From b29f320fd466715d02041a4753223ad4f2105f76 Mon Sep 17 00:00:00 2001 From: Peter Dave Hello Date: Wed, 23 Feb 2022 22:42:03 +0800 Subject: [PATCH 001/110] Simplify Dockerfile Alpine Linux apk usage Remove additional `--update` and manual clean up for apk in Dockerfile --- scripts/make/Dockerfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/make/Dockerfile b/scripts/make/Dockerfile index f5a543a2..a731e3a6 100644 --- a/scripts/make/Dockerfile +++ b/scripts/make/Dockerfile @@ -21,8 +21,7 @@ LABEL\ org.opencontainers.image.version=$VERSION # Update certificates. -RUN apk --no-cache --update add ca-certificates libcap tzdata && \ - rm -rf /var/cache/apk/* && \ +RUN apk --no-cache add ca-certificates libcap tzdata && \ mkdir -p /opt/adguardhome/conf /opt/adguardhome/work && \ chown -R nobody: /opt/adguardhome From 573cbafe3f2f222d7c6413d8fe30c90ae295882d Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Tue, 15 Mar 2022 20:57:46 +0300 Subject: [PATCH 002/110] Pull request: 3597 arpdb Merge in DNS/adguard-home from 3597-wrt-netlink to master Updates #3597. Squashed commit of the following: commit 1709582cd204bb80c84775feabae8723ed3340f6 Merge: 0507b6ed e7b3c996 Author: Eugene Burkov Date: Tue Mar 15 20:25:18 2022 +0300 Merge branch 'master' into 3597-wrt-netlink commit 0507b6ede1162554ca8ac7399d827264aca64f98 Author: Eugene Burkov Date: Tue Mar 15 20:21:29 2022 +0300 all: imp code commit 71f9758d854b3e2cf90cbd3655ae4818cfbcf528 Author: Eugene Burkov Date: Wed Mar 9 18:03:48 2022 +0500 aghnet: imp naming commit c949e765104f130aa3e5ba465bdebc3286bebe44 Author: Eugene Burkov Date: Wed Mar 9 17:26:30 2022 +0500 all: imp code, docs commit cf605ddb401b6e7b0a7a4bb1b175a4dc588d253a Author: Eugene Burkov Date: Tue Mar 8 15:33:52 2022 +0500 all: imp code, docs commit 2960c6549a7e4944cc0072ca47a0cd4e82ec850e Author: Eugene Burkov Date: Sun Mar 6 21:34:58 2022 +0500 all: imp code & docs, fix tests commit 29c049f3aee91a826c3416961686396d562a7066 Author: Eugene Burkov Date: Wed Mar 2 20:45:34 2022 +0300 all: add arpdb --- CHANGELOG.md | 3 + internal/aghnet/arpdb.go | 239 +++++++++++++++++++++++++ internal/aghnet/arpdb_bsd.go | 70 ++++++++ internal/aghnet/arpdb_bsd_test.go | 23 +++ internal/aghnet/arpdb_linux.go | 230 ++++++++++++++++++++++++ internal/aghnet/arpdb_linux_test.go | 84 +++++++++ internal/aghnet/arpdb_openbsd.go | 67 +++++++ internal/aghnet/arpdb_openbsd_test.go | 22 +++ internal/aghnet/arpdb_test.go | 168 +++++++++++++++++ internal/aghnet/arpdb_unix.go | 13 ++ internal/aghnet/arpdb_windows.go | 70 ++++++++ internal/aghnet/arpdb_windows_test.go | 23 +++ internal/aghnet/hostscontainer_test.go | 4 - internal/aghnet/net_test.go | 5 + internal/aghnet/testdata/proc_net_arp | 4 + internal/aghos/os.go | 9 +- internal/home/clients.go | 50 ++---- internal/home/clients_test.go | 8 +- internal/home/home.go | 10 +- 19 files changed, 1058 insertions(+), 44 deletions(-) create mode 100644 internal/aghnet/arpdb.go create mode 100644 internal/aghnet/arpdb_bsd.go create mode 100644 internal/aghnet/arpdb_bsd_test.go create mode 100644 internal/aghnet/arpdb_linux.go create mode 100644 internal/aghnet/arpdb_linux_test.go create mode 100644 internal/aghnet/arpdb_openbsd.go create mode 100644 internal/aghnet/arpdb_openbsd_test.go create mode 100644 internal/aghnet/arpdb_test.go create mode 100644 internal/aghnet/arpdb_unix.go create mode 100644 internal/aghnet/arpdb_windows.go create mode 100644 internal/aghnet/arpdb_windows_test.go create mode 100644 internal/aghnet/testdata/proc_net_arp diff --git a/CHANGELOG.md b/CHANGELOG.md index a5cca836..48aa24d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,8 @@ and this project adheres to ### Changed +- Improved detection of runtime clients through more resilient ARP processing + ([#3597]). - The TTL of responses served from the optimistic cache is now lowered to 10 seconds. - Domain-specific private reverse DNS upstream servers are now validated to @@ -89,6 +91,7 @@ In this release, the schema version has changed from 12 to 13. [#3367]: https://github.com/AdguardTeam/AdGuardHome/issues/3367 [#3381]: https://github.com/AdguardTeam/AdGuardHome/issues/3381 [#3503]: https://github.com/AdguardTeam/AdGuardHome/issues/3503 +[#3597]: https://github.com/AdguardTeam/AdGuardHome/issues/3597 [#3978]: https://github.com/AdguardTeam/AdGuardHome/issues/3978 [#4166]: https://github.com/AdguardTeam/AdGuardHome/issues/4166 [#4213]: https://github.com/AdguardTeam/AdGuardHome/issues/4213 diff --git a/internal/aghnet/arpdb.go b/internal/aghnet/arpdb.go new file mode 100644 index 00000000..759a688a --- /dev/null +++ b/internal/aghnet/arpdb.go @@ -0,0 +1,239 @@ +package aghnet + +import ( + "bufio" + "fmt" + "io" + "net" + "strings" + "sync" + + "github.com/AdguardTeam/AdGuardHome/internal/aghos" + "github.com/AdguardTeam/golibs/errors" + "github.com/AdguardTeam/golibs/netutil" +) + +// ARPDB: The Network Neighborhood Database + +// ARPDB stores and refreshes the network neighborhood reported by ARP (Address +// Resolution Protocol). +type ARPDB interface { + // Refresh updates the stored data. It must be safe for concurrent use. + Refresh() (err error) + + // Neighbors returnes the last set of data reported by ARP. Both the method + // and it's result must be safe for concurrent use. + Neighbors() (ns []Neighbor) +} + +// NewARPDB returns the ARPDB properly initialized for the OS. +func NewARPDB() (arp ARPDB, err error) { + arp = newARPDB() + + err = arp.Refresh() + if err != nil { + return nil, fmt.Errorf("arpdb initial refresh: %w", err) + } + + return arp, nil +} + +// Empty ARPDB implementation + +// EmptyARPDB is the ARPDB implementation that does nothing. +type EmptyARPDB struct{} + +// type check +var _ ARPDB = EmptyARPDB{} + +// Refresh implements the ARPDB interface for EmptyARPContainer. It does +// nothing and always returns nil error. +func (EmptyARPDB) 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 + +// Neighbor is the pair of IP address and MAC address reported by ARP. +type Neighbor struct { + // Name is the hostname of the neighbor. Empty name is valid since not each + // implementation of ARP is able to retrieve that. + Name string + + // IP contains either IPv4 or IPv6. + IP net.IP + + // MAC contains the hardware address. + MAC net.HardwareAddr +} + +// Clone returns the deep copy of n. +func (n Neighbor) Clone() (clone Neighbor) { + return Neighbor{ + Name: n.Name, + IP: netutil.CloneIP(n.IP), + MAC: netutil.CloneMAC(n.MAC), + } +} + +// neighs is the helper type that stores neighbors to avoid copying its methods +// among all the ARPDB implementations. +type neighs struct { + mu *sync.RWMutex + ns []Neighbor +} + +// len returns the length of the neighbors slice. It's safe for concurrent use. +func (ns *neighs) len() (l int) { + ns.mu.RLock() + defer ns.mu.RUnlock() + + return len(ns.ns) +} + +// clone returns a deep copy of the underlying neighbors slice. It's safe for +// concurrent use. +func (ns *neighs) clone() (cloned []Neighbor) { + ns.mu.RLock() + defer ns.mu.RUnlock() + + cloned = make([]Neighbor, len(ns.ns)) + for i, n := range ns.ns { + cloned[i] = n.Clone() + } + + return cloned +} + +// reset replaces the underlying slice with the new one. It's safe for +// concurrent use. +func (ns *neighs) reset(with []Neighbor) { + ns.mu.Lock() + defer ns.mu.Unlock() + + 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) + +// runCmdFunc is the function that runs some command and returns its output +// wrapped to be a io.Reader. +type runCmdFunc func() (r io.Reader, err error) + +// cmdARPDB is the implementation of the ARPDB that uses command line to +// retrieve data. +type cmdARPDB struct { + parse parseNeighsFunc + runcmd runCmdFunc + ns *neighs +} + +// type check +var _ ARPDB = (*cmdARPDB)(nil) + +// runCmd runs the cmd with it's args and returns the result wrapped to be an +// io.Reader. The error is returned either if the exit code retured by command +// not equals 0 or the execution itself failed. +func runCmd(cmd string, args ...string) (r io.Reader, err error) { + var code int + var out string + code, out, err = aghos.RunCommand(cmd, args...) + if err != nil { + return nil, err + } else if code != 0 { + return nil, fmt.Errorf("unexpected exit code %d", code) + } + + return strings.NewReader(out), nil +} + +// Refresh implements the ARPDB interface for *cmdARPDB. +func (arp *cmdARPDB) Refresh() (err error) { + defer func() { err = errors.Annotate(err, "cmd arpdb: %w") }() + + var r io.Reader + r, err = arp.runcmd() + if err != nil { + return fmt.Errorf("running command: %w", err) + } + + sc := bufio.NewScanner(r) + ns := arp.parse(sc, arp.ns.len()) + if err = sc.Err(); err != nil { + return fmt.Errorf("scanning the output: %w", err) + } + + arp.ns.reset(ns) + + return nil +} + +// Neighbors implements the ARPDB 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. +type arpdbs struct { + // arps is the set of ARPDB implementations to range through. + arps []ARPDB + // last is the last succeeded ARPDB index. + last int +} + +// newARPDBs returns a properly initialized *arpdbs. It begins refreshing from +// the first of arps. +func newARPDBs(arps ...ARPDB) (arp *arpdbs) { + return &arpdbs{ + arps: arps, + last: 0, + } +} + +// type check +var _ ARPDB = (*arpdbs)(nil) + +// Refresh implements the ARPDB interface for *arpdbs. +func (arp *arpdbs) Refresh() (err error) { + var errs []error + l := len(arp.arps) + // Start from the last succeeded implementation. + for i := 0; i < l; i++ { + cur := (arp.last + i) % l + err = arp.arps[cur].Refresh() + if err == nil { + // The succeeded implementation found so update the last succeeded + // index. + arp.last = cur + + return nil + } + + errs = append(errs, err) + } + + if len(errs) > 0 { + err = errors.List("each arpdb failed", errs...) + } + + return err +} + +// Neighbors implements the ARPDB interface for *arpdbs. +func (arp *arpdbs) Neighbors() (ns []Neighbor) { + if l := len(arp.arps); l > 0 && arp.last < l { + return arp.arps[arp.last].Neighbors() + } + + return nil +} diff --git a/internal/aghnet/arpdb_bsd.go b/internal/aghnet/arpdb_bsd.go new file mode 100644 index 00000000..fe00418a --- /dev/null +++ b/internal/aghnet/arpdb_bsd.go @@ -0,0 +1,70 @@ +//go:build darwin || freebsd +// +build darwin freebsd + +package aghnet + +import ( + "bufio" + "net" + "strings" + "sync" + + "github.com/AdguardTeam/golibs/log" + "github.com/AdguardTeam/golibs/netutil" +) + +func newARPDB() *cmdARPDB { + return &cmdARPDB{ + parse: parseArpA, + runcmd: rcArpA, + ns: &neighs{ + mu: &sync.RWMutex{}, + ns: make([]Neighbor, 0), + }, + } +} + +// parseArpA parses the output of the "arp -a" command on macOS and FreeBSD. +// The expected input format: +// +// host.name (192.168.0.1) at ff:ff:ff:ff:ff:ff on en0 ifscope [ethernet] +// +func parseArpA(sc *bufio.Scanner, lenHint int) (ns []Neighbor) { + ns = make([]Neighbor, 0, lenHint) + for sc.Scan() { + ln := sc.Text() + + fields := strings.Fields(ln) + if len(fields) < 4 { + continue + } + + n := Neighbor{} + + if ipStr := fields[1]; len(ipStr) < 2 { + continue + } else if ip := net.ParseIP(ipStr[1 : len(ipStr)-1]); ip == nil { + continue + } else { + n.IP = ip + } + + hwStr := fields[3] + if mac, err := net.ParseMAC(hwStr); err != nil { + continue + } else { + n.MAC = mac + } + + host := fields[0] + if err := netutil.ValidateDomainName(host); err != nil { + log.Debug("parsing arp output: %s", err) + } else { + n.Name = host + } + + ns = append(ns, n) + } + + return ns +} diff --git a/internal/aghnet/arpdb_bsd_test.go b/internal/aghnet/arpdb_bsd_test.go new file mode 100644 index 00000000..bbadc600 --- /dev/null +++ b/internal/aghnet/arpdb_bsd_test.go @@ -0,0 +1,23 @@ +//go:build darwin || freebsd +// +build darwin freebsd + +package aghnet + +import ( + "net" +) + +const arpAOutput = ` +hostname.one (192.168.1.2) at ab:cd:ef:ab:cd:ef on en0 ifscope [ethernet] +hostname.two (::ffff:ffff) at ef:cd:ab:ef:cd:ab on em0 expires in 1198 seconds [ethernet] +` + +var wantNeighs = []Neighbor{{ + Name: "hostname.one", + IP: net.IPv4(192, 168, 1, 2), + MAC: net.HardwareAddr{0xAB, 0xCD, 0xEF, 0xAB, 0xCD, 0xEF}, +}, { + Name: "hostname.two", + IP: net.ParseIP("::ffff:ffff"), + MAC: net.HardwareAddr{0xEF, 0xCD, 0xAB, 0xEF, 0xCD, 0xAB}, +}} diff --git a/internal/aghnet/arpdb_linux.go b/internal/aghnet/arpdb_linux.go new file mode 100644 index 00000000..976d8b7a --- /dev/null +++ b/internal/aghnet/arpdb_linux.go @@ -0,0 +1,230 @@ +//go:build linux +// +build linux + +package aghnet + +import ( + "bufio" + "fmt" + "io" + "io/fs" + "net" + "strings" + "sync" + + "github.com/AdguardTeam/AdGuardHome/internal/aghos" + "github.com/AdguardTeam/golibs/log" + "github.com/AdguardTeam/golibs/netutil" + "github.com/AdguardTeam/golibs/stringutil" +) + +func newARPDB() (arp *arpdbs) { + // Use the common storage among the implementations. + ns := &neighs{ + mu: &sync.RWMutex{}, + ns: make([]Neighbor, 0), + } + + var parseF parseNeighsFunc + if aghos.IsOpenWrt() { + parseF = parseArpAWrt + } else { + parseF = parseArpA + } + + return newARPDBs( + // Try /proc/net/arp first. + &fsysARPDB{ns: ns, fsys: aghos.RootDirFS(), filename: "proc/net/arp"}, + // Try "arp -a" then. + &cmdARPDB{parse: parseF, runcmd: rcArpA, ns: ns}, + // Try "ip neigh" finally. + &cmdARPDB{parse: parseIPNeigh, runcmd: rcIPNeigh, ns: ns}, + ) +} + +// fsysARPDB accesses the ARP cache file to update the database. +type fsysARPDB struct { + ns *neighs + fsys fs.FS + filename string +} + +// type check +var _ ARPDB = (*fsysARPDB)(nil) + +// Refresh implements the ARPDB interface for *fsysARPDB. +func (arp *fsysARPDB) Refresh() (err error) { + var f fs.File + f, err = arp.fsys.Open(arp.filename) + if err != nil { + return fmt.Errorf("opening %q: %w", arp.filename, err) + } + + sc := bufio.NewScanner(f) + // Skip the header. + if !sc.Scan() { + return nil + } else if err = sc.Err(); err != nil { + return err + } + + ns := make([]Neighbor, 0, arp.ns.len()) + for sc.Scan() { + ln := sc.Text() + fields := stringutil.SplitTrimmed(ln, " ") + if len(fields) != 6 { + continue + } + + n := Neighbor{} + if n.IP = net.ParseIP(fields[0]); n.IP == 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) + + return nil +} + +// Neighbors implements the ARPDB interface for *fsysARPDB. +func (arp *fsysARPDB) Neighbors() (ns []Neighbor) { + return arp.ns.clone() +} + +// parseArpAWrt parses the output of the "arp -a" command on OpenWrt. The +// expected input format: +// +// IP address HW type Flags HW address Mask Device +// 192.168.11.98 0x1 0x2 5a:92:df:a9:7e:28 * wan +// +func parseArpAWrt(sc *bufio.Scanner, lenHint int) (ns []Neighbor) { + if !sc.Scan() { + // Skip the header. + return + } + + ns = make([]Neighbor, 0, lenHint) + for sc.Scan() { + ln := sc.Text() + + fields := strings.Fields(ln) + if len(fields) < 4 { + continue + } + + n := Neighbor{} + + if ip := net.ParseIP(fields[0]); ip == nil || n.IP.IsUnspecified() { + continue + } else { + n.IP = ip + } + + hwStr := fields[3] + if mac, err := net.ParseMAC(hwStr); err != nil { + log.Debug("parsing arp output: %s", err) + + continue + } else { + n.MAC = mac + } + + ns = append(ns, n) + } + + return ns +} + +// parseArpA parses the output of the "arp -a" command on Linux. The expected +// input format: +// +// hostname (192.168.1.1) at ab:cd:ef:ab:cd:ef [ether] on enp0s3 +// +func parseArpA(sc *bufio.Scanner, lenHint int) (ns []Neighbor) { + ns = make([]Neighbor, 0, lenHint) + for sc.Scan() { + ln := sc.Text() + + fields := strings.Fields(ln) + if len(fields) < 4 { + continue + } + + n := Neighbor{} + + if ipStr := fields[1]; len(ipStr) < 2 { + continue + } else if ip := net.ParseIP(ipStr[1 : len(ipStr)-1]); ip == nil { + continue + } else { + n.IP = ip + } + + hwStr := fields[3] + if mac, err := net.ParseMAC(hwStr); err != nil { + log.Debug("parsing arp output: %s", err) + + continue + } else { + n.MAC = mac + } + + host := fields[0] + if verr := netutil.ValidateDomainName(host); verr != nil { + log.Debug("parsing arp output: %s", verr) + } else { + n.Name = host + } + + ns = append(ns, n) + } + + return ns +} + +// rcIPNeigh runs "ip neigh". +func rcIPNeigh() (r io.Reader, err error) { + return runCmd("ip", "neigh") +} + +// parseIPNeigh parses the output of the "ip neigh" command on Linux. The +// expected input format: +// +// 192.168.1.1 dev enp0s3 lladdr ab:cd:ef:ab:cd:ef REACHABLE +// +func parseIPNeigh(sc *bufio.Scanner, lenHint int) (ns []Neighbor) { + ns = make([]Neighbor, 0, lenHint) + for sc.Scan() { + ln := sc.Text() + + fields := strings.Fields(ln) + if len(fields) < 5 { + continue + } + + n := Neighbor{} + + if ip := net.ParseIP(fields[0]); ip == nil { + continue + } else { + n.IP = ip + } + + if mac, err := net.ParseMAC(fields[4]); err != nil { + log.Debug("parsing arp output: %s", err) + + continue + } else { + n.MAC = mac + } + + ns = append(ns, n) + } + + return ns +} diff --git a/internal/aghnet/arpdb_linux_test.go b/internal/aghnet/arpdb_linux_test.go new file mode 100644 index 00000000..0439c9b5 --- /dev/null +++ b/internal/aghnet/arpdb_linux_test.go @@ -0,0 +1,84 @@ +//go:build linux +// +build linux + +package aghnet + +import ( + "io" + "net" + "strings" + "sync" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const arpAOutputWrt = ` +IP address HW type Flags HW address Mask Device +192.168.1.2 0x1 0x2 ab:cd:ef:ab:cd:ef * wan +::ffff:ffff 0x1 0x2 ef:cd:ab:ef:cd:ab * wan` + +const arpAOutput = ` +? (192.168.1.2) at ab:cd:ef:ab:cd:ef on en0 ifscope [ethernet] +? (::ffff:ffff) at ef:cd:ab:ef:cd:ab on em0 expires in 100 seconds [ethernet]` + +const ipNeighOutput = ` +192.168.1.2 dev enp0s3 lladdr ab:cd:ef:ab:cd:ef DELAY +::ffff:ffff dev enp0s3 lladdr ef:cd:ab:ef:cd:ab router STALE` + +var wantNeighs = []Neighbor{{ + IP: net.IPv4(192, 168, 1, 2), + MAC: net.HardwareAddr{0xAB, 0xCD, 0xEF, 0xAB, 0xCD, 0xEF}, +}, { + IP: net.ParseIP("::ffff:ffff"), + MAC: net.HardwareAddr{0xEF, 0xCD, 0xAB, 0xEF, 0xCD, 0xAB}, +}} + +func TestFSysARPDB(t *testing.T) { + a := &fsysARPDB{ + ns: &neighs{ + mu: &sync.RWMutex{}, + ns: make([]Neighbor, 0), + }, + fsys: testdata, + filename: "proc_net_arp", + } + + err := a.Refresh() + require.NoError(t, err) + + ns := a.Neighbors() + assert.Equal(t, wantNeighs, ns) +} + +func TestCmdARPDB_arpawrt(t *testing.T) { + a := &cmdARPDB{ + parse: parseArpAWrt, + runcmd: func() (r io.Reader, err error) { return strings.NewReader(arpAOutputWrt), nil }, + ns: &neighs{ + mu: &sync.RWMutex{}, + ns: make([]Neighbor, 0), + }, + } + + err := a.Refresh() + require.NoError(t, err) + + assert.Equal(t, wantNeighs, a.Neighbors()) +} + +func TestCmdARPDB_ipneigh(t *testing.T) { + a := &cmdARPDB{ + parse: parseIPNeigh, + runcmd: func() (r io.Reader, err error) { return strings.NewReader(ipNeighOutput), nil }, + ns: &neighs{ + mu: &sync.RWMutex{}, + ns: make([]Neighbor, 0), + }, + } + err := a.Refresh() + require.NoError(t, err) + + assert.Equal(t, wantNeighs, a.Neighbors()) +} diff --git a/internal/aghnet/arpdb_openbsd.go b/internal/aghnet/arpdb_openbsd.go new file mode 100644 index 00000000..805cb459 --- /dev/null +++ b/internal/aghnet/arpdb_openbsd.go @@ -0,0 +1,67 @@ +//go:build openbsd +// +build openbsd + +package aghnet + +import ( + "bufio" + "net" + "strings" + "sync" + + "github.com/AdguardTeam/golibs/log" +) + +func newARPDB() *cmdARPDB { + return &cmdARPDB{ + runcmd: rcArpA, + parse: parseArpA, + ns: &neighs{ + mu: &sync.RWMutex{}, + ns: make([]Neighbor, 0), + }, + } +} + +// parseArpA parses the output of the "arp -a" command on OpenBSD. The expected +// input format: +// +// Host Ethernet Address Netif Expire Flags +// 192.168.1.1 ab:cd:ef:ab:cd:ef em0 19m59s +// +func parseArpA(sc *bufio.Scanner, lenHint int) (ns []Neighbor) { + // Skip the header. + if !sc.Scan() { + return nil + } + + ns = make([]Neighbor, 0, lenHint) + for sc.Scan() { + ln := sc.Text() + + fields := strings.Fields(ln) + if len(fields) < 2 { + continue + } + + n := Neighbor{} + + if ip := net.ParseIP(fields[0]); ip == nil { + continue + } else { + n.IP = ip + } + + if mac, err := net.ParseMAC(fields[1]); err != nil { + log.Debug("parsing arp output: %s", err) + + continue + } else { + n.MAC = mac + } + + ns = append(ns, n) + } + + return ns +} diff --git a/internal/aghnet/arpdb_openbsd_test.go b/internal/aghnet/arpdb_openbsd_test.go new file mode 100644 index 00000000..b1021513 --- /dev/null +++ b/internal/aghnet/arpdb_openbsd_test.go @@ -0,0 +1,22 @@ +//go:build openbsd +// +build openbsd + +package aghnet + +import ( + "net" +) + +const arpAOutput = ` +Host Ethernet Address Netif Expire Flags +192.168.1.2 ab:cd:ef:ab:cd:ef em0 19m56s +::ffff:ffff ef:cd:ab:ef:cd:ab em0 permanent l +` + +var wantNeighs = []Neighbor{{ + IP: net.IPv4(192, 168, 1, 2), + MAC: net.HardwareAddr{0xAB, 0xCD, 0xEF, 0xAB, 0xCD, 0xEF}, +}, { + IP: net.ParseIP("::ffff:ffff"), + MAC: net.HardwareAddr{0xEF, 0xCD, 0xAB, 0xEF, 0xCD, 0xAB}, +}} diff --git a/internal/aghnet/arpdb_test.go b/internal/aghnet/arpdb_test.go new file mode 100644 index 00000000..ce3da4fb --- /dev/null +++ b/internal/aghnet/arpdb_test.go @@ -0,0 +1,168 @@ +package aghnet + +import ( + "io" + "net" + "strings" + "sync" + "testing" + + "github.com/AdguardTeam/golibs/errors" + "github.com/AdguardTeam/golibs/testutil" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestARPDB is the mock implementation of ARPDB to use in tests. +type TestARPDB struct { + OnRefresh func() (err error) + OnNeighbors func() (ns []Neighbor) +} + +// Refresh implements the ARPDB interface for *TestARPDB. +func (arp *TestARPDB) Refresh() (err error) { + return arp.OnRefresh() +} + +// Neighbors implements the ARPDB interface for *TestARPDB. +func (arp *TestARPDB) Neighbors() (ns []Neighbor) { + return arp.OnNeighbors() +} + +func TestARPDBS(t *testing.T) { + knownIP := net.IP{1, 2, 3, 4} + knownMAC := net.HardwareAddr{0xAB, 0xCD, 0xEF, 0xAB, 0xCD, 0xEF} + + succRefrCount, failRefrCount := 0, 0 + clnp := func() { + succRefrCount, failRefrCount = 0, 0 + } + + succDB := &TestARPDB{ + OnRefresh: func() (err error) { succRefrCount++; return nil }, + OnNeighbors: func() (ns []Neighbor) { + return []Neighbor{{Name: "abc", IP: knownIP, MAC: knownMAC}} + }, + } + failDB := &TestARPDB{ + OnRefresh: func() (err error) { failRefrCount++; return errors.Error("refresh failed") }, + OnNeighbors: func() (ns []Neighbor) { return nil }, + } + + t.Run("begin_with_success", func(t *testing.T) { + t.Cleanup(clnp) + + a := newARPDBs(succDB, failDB) + err := a.Refresh() + require.NoError(t, err) + + assert.Equal(t, 1, succRefrCount) + assert.Zero(t, failRefrCount) + assert.NotEmpty(t, a.Neighbors()) + }) + + t.Run("begin_with_fail", func(t *testing.T) { + t.Cleanup(clnp) + + a := newARPDBs(failDB, succDB) + err := a.Refresh() + require.NoError(t, err) + + assert.Equal(t, 1, succRefrCount) + assert.Equal(t, 1, failRefrCount) + assert.NotEmpty(t, a.Neighbors()) + }) + + t.Run("fail_only", func(t *testing.T) { + t.Cleanup(clnp) + + wantMsg := `each arpdb failed: 2 errors: "refresh failed", "refresh failed"` + + a := newARPDBs(failDB, failDB) + err := a.Refresh() + require.Error(t, err) + + testutil.AssertErrorMsg(t, wantMsg, err) + + assert.Equal(t, 2, failRefrCount) + assert.Empty(t, a.Neighbors()) + }) + + t.Run("fail_after_success", func(t *testing.T) { + t.Cleanup(clnp) + + shouldFail := false + unstableDB := &TestARPDB{ + OnRefresh: func() (err error) { + if shouldFail { + err = errors.Error("unstable failed") + } + shouldFail = !shouldFail + + return err + }, + OnNeighbors: func() (ns []Neighbor) { + if !shouldFail { + return failDB.OnNeighbors() + } + + return succDB.OnNeighbors() + }, + } + a := newARPDBs(unstableDB, succDB) + + // Unstable ARPDB should refresh successfully. + err := a.Refresh() + require.NoError(t, err) + + assert.Zero(t, succRefrCount) + assert.NotEmpty(t, a.Neighbors()) + + // Unstable ARPDB should fail and the succDB should be used. + err = a.Refresh() + require.NoError(t, err) + + assert.Equal(t, 1, succRefrCount) + assert.NotEmpty(t, a.Neighbors()) + + // Only the last succeeded ARPDB should be used. + err = a.Refresh() + require.NoError(t, err) + + assert.Equal(t, 2, succRefrCount) + assert.NotEmpty(t, a.Neighbors()) + }) + + t.Run("empty", func(t *testing.T) { + a := newARPDBs() + require.NoError(t, a.Refresh()) + + assert.Empty(t, a.Neighbors()) + }) +} + +func TestCmdARPDB_arpa(t *testing.T) { + a := &cmdARPDB{ + parse: parseArpA, + ns: &neighs{ + mu: &sync.RWMutex{}, + ns: make([]Neighbor, 0), + }, + } + + t.Run("arp_a", func(t *testing.T) { + a.runcmd = func() (r io.Reader, err error) { return strings.NewReader(arpAOutput), nil } + + err := a.Refresh() + require.NoError(t, err) + + assert.Equal(t, wantNeighs, a.Neighbors()) + }) + + t.Run("runcmd_error", func(t *testing.T) { + a.runcmd = func() (r io.Reader, err error) { return nil, errors.Error("can't run") } + + err := a.Refresh() + testutil.AssertErrorMsg(t, "cmd arpdb: running command: can't run", err) + }) +} diff --git a/internal/aghnet/arpdb_unix.go b/internal/aghnet/arpdb_unix.go new file mode 100644 index 00000000..50346f92 --- /dev/null +++ b/internal/aghnet/arpdb_unix.go @@ -0,0 +1,13 @@ +//go:build !windows +// +build !windows + +package aghnet + +import ( + "io" +) + +// rcArpA runs "arp -a". +func rcArpA() (r io.Reader, err error) { + return runCmd("arp", "-a") +} diff --git a/internal/aghnet/arpdb_windows.go b/internal/aghnet/arpdb_windows.go new file mode 100644 index 00000000..5156330b --- /dev/null +++ b/internal/aghnet/arpdb_windows.go @@ -0,0 +1,70 @@ +//go:build windows +// +build windows + +package aghnet + +import ( + "bufio" + "io" + "net" + "strings" + "sync" +) + +func newARPDB() *cmdARPDB { + return &cmdARPDB{ + runcmd: rcArpA, + ns: &neighs{ + mu: &sync.RWMutex{}, + ns: make([]Neighbor, 0), + }, + parse: parseArpA, + } +} + +// rcArpA runs "arp /a". +func rcArpA() (r io.Reader, err error) { + return runCmd("arp", "/a") +} + +// parseArpA parses the output of the "arp /a" command on Windows. The expected +// input format (the first line is empty): +// +// +// Interface: 192.168.56.16 --- 0x7 +// Internet Address Physical Address Type +// 192.168.56.1 0a-00-27-00-00-00 dynamic +// 192.168.56.255 ff-ff-ff-ff-ff-ff static +// +func parseArpA(sc *bufio.Scanner, lenHint int) (ns []Neighbor) { + ns = make([]Neighbor, 0, lenHint) + for sc.Scan() { + ln := sc.Text() + if ln == "" { + continue + } + + fields := strings.Fields(ln) + if len(fields) != 3 { + continue + } + + n := Neighbor{} + + if ip := net.ParseIP(fields[0]); ip == nil { + continue + } else { + n.IP = ip + } + + if mac, err := net.ParseMAC(fields[1]); err != nil { + continue + } else { + n.MAC = mac + } + + ns = append(ns, n) + } + + return ns +} diff --git a/internal/aghnet/arpdb_windows_test.go b/internal/aghnet/arpdb_windows_test.go new file mode 100644 index 00000000..ad88ff8e --- /dev/null +++ b/internal/aghnet/arpdb_windows_test.go @@ -0,0 +1,23 @@ +//go:build windows +// +build windows + +package aghnet + +import ( + "net" +) + +const arpAOutput = ` + +Interface: 192.168.1.1 --- 0x7 + Internet Address Physical Address Type + 192.168.1.2 ab-cd-ef-ab-cd-ef dynamic + ::ffff:ffff ef-cd-ab-ef-cd-ab static` + +var wantNeighs = []Neighbor{{ + IP: net.IPv4(192, 168, 1, 2), + MAC: net.HardwareAddr{0xAB, 0xCD, 0xEF, 0xAB, 0xCD, 0xEF}, +}, { + IP: net.ParseIP("::ffff:ffff"), + MAC: net.HardwareAddr{0xEF, 0xCD, 0xAB, 0xEF, 0xCD, 0xAB}, +}} diff --git a/internal/aghnet/hostscontainer_test.go b/internal/aghnet/hostscontainer_test.go index a141ce00..40bfb34c 100644 --- a/internal/aghnet/hostscontainer_test.go +++ b/internal/aghnet/hostscontainer_test.go @@ -3,7 +3,6 @@ package aghnet import ( "io/fs" "net" - "os" "path" "strings" "sync/atomic" @@ -281,7 +280,6 @@ func TestHostsContainer_PathsToPatterns(t *testing.T) { } func TestHostsContainer_Translate(t *testing.T) { - testdata := os.DirFS("./testdata") stubWatcher := aghtest.FSWatcher{ OnEvents: func() (e <-chan struct{}) { return nil }, OnAdd: func(name string) (err error) { return nil }, @@ -360,8 +358,6 @@ func TestHostsContainer_Translate(t *testing.T) { func TestHostsContainer(t *testing.T) { const listID = 1234 - testdata := os.DirFS("./testdata") - testCases := []struct { want []*rules.DNSRewrite name string diff --git a/internal/aghnet/net_test.go b/internal/aghnet/net_test.go index b5bf2297..34e99faa 100644 --- a/internal/aghnet/net_test.go +++ b/internal/aghnet/net_test.go @@ -1,7 +1,9 @@ package aghnet import ( + "io/fs" "net" + "os" "testing" "github.com/AdguardTeam/AdGuardHome/internal/aghtest" @@ -11,6 +13,9 @@ import ( "github.com/stretchr/testify/require" ) +// testdata is the filesystem containing data for testing the package. +var testdata fs.FS = os.DirFS("./testdata") + func TestMain(m *testing.M) { aghtest.DiscardLogOutput(m) } diff --git a/internal/aghnet/testdata/proc_net_arp b/internal/aghnet/testdata/proc_net_arp new file mode 100644 index 00000000..07d214e1 --- /dev/null +++ b/internal/aghnet/testdata/proc_net_arp @@ -0,0 +1,4 @@ +IP address HW type Flags HW address Mask Device +192.168.1.2 0x1 0x2 ab:cd:ef:ab:cd:ef * wan +::ffff:ffff 0x1 0x0 ef:cd:ab:ef:cd:ab * br-lan +0.0.0.0 0x0 0x0 00:00:00:00:00:00 * unspec \ No newline at end of file diff --git a/internal/aghos/os.go b/internal/aghos/os.go index 29eb1afc..8ac189a1 100644 --- a/internal/aghos/os.go +++ b/internal/aghos/os.go @@ -52,11 +52,12 @@ func HaveAdminRights() (bool, error) { return haveAdminRights() } -// MaxCmdOutputSize is the maximum length of performed shell command output. -const MaxCmdOutputSize = 2 * 1024 +// MaxCmdOutputSize is the maximum length of performed shell command output in +// bytes. +const MaxCmdOutputSize = 64 * 1024 // RunCommand runs shell command. -func RunCommand(command string, arguments ...string) (int, string, error) { +func RunCommand(command string, arguments ...string) (code int, output string, err error) { cmd := exec.Command(command, arguments...) out, err := cmd.Output() if len(out) > MaxCmdOutputSize { @@ -66,7 +67,7 @@ func RunCommand(command string, arguments ...string) (int, string, error) { if errors.As(err, new(*exec.ExitError)) { return cmd.ProcessState.ExitCode(), string(out), nil } else if err != nil { - return 1, "", fmt.Errorf("exec.Command(%s) failed: %w: %s", command, err, string(out)) + return 1, "", fmt.Errorf("command %q failed: %w: %s", command, err, out) } return cmd.ProcessState.ExitCode(), string(out), nil diff --git a/internal/home/clients.go b/internal/home/clients.go index f539adbe..d9aad40e 100644 --- a/internal/home/clients.go +++ b/internal/home/clients.go @@ -4,10 +4,7 @@ import ( "bytes" "fmt" "net" - "os/exec" - "runtime" "sort" - "strings" "sync" "time" @@ -99,6 +96,9 @@ type clientsContainer struct { // hosts database. etcHosts *aghnet.HostsContainer + // arpdb stores the neighbors retrieved from ARP. + arpdb aghnet.ARPDB + testing bool // if TRUE, this object is used for internal tests } @@ -109,6 +109,7 @@ func (clients *clientsContainer) Init( objects []*clientObject, dhcpServer *dhcpd.Server, etcHosts *aghnet.HostsContainer, + arpdb aghnet.ARPDB, ) { if clients.list != nil { log.Fatal("clients.list != nil") @@ -121,6 +122,7 @@ func (clients *clientsContainer) Init( clients.dhcpServer = dhcpServer clients.etcHosts = etcHosts + clients.arpdb = arpdb clients.addFromConfig(objects) if clients.testing { @@ -807,16 +809,18 @@ func (clients *clientsContainer) addFromHostsFile(hosts *netutil.IPMap) { // addFromSystemARP adds the IP-hostname pairings from the output of the arp -a // command. func (clients *clientsContainer) addFromSystemARP() { - if runtime.GOOS == "windows" { + if err := clients.arpdb.Refresh(); err != nil { + log.Error("refreshing arp container: %s", err) + + clients.arpdb = aghnet.EmptyARPDB{} + return } - cmd := exec.Command("arp", "-a") - log.Tracef("executing %q %q", cmd.Path, cmd.Args) - data, err := cmd.Output() - if err != nil || cmd.ProcessState.ExitCode() != 0 { - log.Debug("command %q has failed: %q code:%d", - cmd.Path, err, cmd.ProcessState.ExitCode()) + ns := clients.arpdb.Neighbors() + if len(ns) == 0 { + log.Debug("refreshing arp container: the update is empty") + return } @@ -825,30 +829,14 @@ func (clients *clientsContainer) addFromSystemARP() { clients.rmHostsBySrc(ClientSourceARP) - n := 0 - // TODO(a.garipov): Rewrite to use bufio.Scanner. - lines := strings.Split(string(data), "\n") - for _, ln := range lines { - lparen := strings.Index(ln, " (") - rparen := strings.Index(ln, ") ") - if lparen == -1 || rparen == -1 || lparen >= rparen { - continue - } - - host := ln[:lparen] - ipStr := ln[lparen+2 : rparen] - ip := net.ParseIP(ipStr) - if netutil.ValidateDomainName(host) != nil || ip == nil { - continue - } - - ok := clients.addHostLocked(ip, host, ClientSourceARP) - if ok { - n++ + added := 0 + for _, n := range ns { + if clients.addHostLocked(n.IP, "", ClientSourceARP) { + added++ } } - log.Debug("clients: added %d client aliases from 'arp -a' command output", n) + log.Debug("clients: added %d client aliases from arp neighborhood", added) } // updateFromDHCP adds the clients that have a non-empty hostname from the DHCP diff --git a/internal/home/clients_test.go b/internal/home/clients_test.go index 6cc5d46f..8afd5621 100644 --- a/internal/home/clients_test.go +++ b/internal/home/clients_test.go @@ -18,7 +18,7 @@ func TestClients(t *testing.T) { clients := clientsContainer{} clients.testing = true - clients.Init(nil, nil, nil) + clients.Init(nil, nil, nil, nil) t.Run("add_success", func(t *testing.T) { c := &Client{ @@ -194,7 +194,7 @@ func TestClientsWHOIS(t *testing.T) { clients := clientsContainer{ testing: true, } - clients.Init(nil, nil, nil) + clients.Init(nil, nil, nil, nil) whois := &RuntimeClientWHOISInfo{ Country: "AU", Orgname: "Example Org", @@ -253,7 +253,7 @@ func TestClientsAddExisting(t *testing.T) { clients := clientsContainer{ testing: true, } - clients.Init(nil, nil, nil) + clients.Init(nil, nil, nil, nil) t.Run("simple", func(t *testing.T) { ip := net.IP{1, 1, 1, 1} @@ -332,7 +332,7 @@ func TestClientsCustomUpstream(t *testing.T) { clients := clientsContainer{ testing: true, } - clients.Init(nil, nil, nil) + clients.Init(nil, nil, nil, nil) // Add client with upstreams. ok, err := clients.Add(&Client{ diff --git a/internal/home/home.go b/internal/home/home.go index 021751e8..114ba4b6 100644 --- a/internal/home/home.go +++ b/internal/home/home.go @@ -293,7 +293,15 @@ func setupConfig(args options) (err error) { } } - Context.clients.Init(config.Clients, Context.dhcpServer, Context.etcHosts) + var arpdb aghnet.ARPDB + arpdb, err = aghnet.NewARPDB() + if err != nil { + log.Info("warning: creating arpdb: %s; using stub", err) + + arpdb = aghnet.EmptyARPDB{} + } + + Context.clients.Init(config.Clients, Context.dhcpServer, Context.etcHosts, arpdb) if args.bindPort != 0 { uc := aghalg.UniqChecker{} From 778585865ebd2234596b8acbe5510bcb96de45fc Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Fri, 18 Mar 2022 13:37:27 +0300 Subject: [PATCH 003/110] Pull request: 3142 custom private subnets Merge in DNS/adguard-home from 3142-custom-subnets to master Updates #3142. Squashed commit of the following: commit 11469ade75b9dc32ee6d93e3aa35cf79dbaa28b2 Author: Eugene Burkov Date: Thu Mar 17 19:56:02 2022 +0300 all: upd golibs, use subnet set --- CHANGELOG.md | 3 + go.mod | 2 +- go.sum | 3 +- internal/aghnet/subnetdetector.go | 158 ---------------- internal/aghnet/subnetdetector_test.go | 252 ------------------------- internal/dnsforward/dns.go | 6 +- internal/dnsforward/dns_test.go | 22 ++- internal/dnsforward/dnsforward.go | 20 +- internal/dnsforward/dnsforward_test.go | 66 +++---- internal/dnsforward/filter_test.go | 11 +- internal/dnsforward/http.go | 24 +-- internal/dnsforward/http_test.go | 6 +- internal/home/config.go | 4 + internal/home/dns.go | 43 ++++- internal/home/home.go | 5 - 15 files changed, 105 insertions(+), 520 deletions(-) delete mode 100644 internal/aghnet/subnetdetector.go delete mode 100644 internal/aghnet/subnetdetector_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 48aa24d7..d663d78e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ and this project adheres to ### Added +- The ability to customize the set of networks considered private through the + new `private_networks` setting ([#3142]). - EDNS Client-Subnet information in the request details section of a query log record ([#3978]). - Support for hostnames for plain UDP upstream servers using the `udp://` scheme @@ -88,6 +90,7 @@ In this release, the schema version has changed from 12 to 13. [#1730]: https://github.com/AdguardTeam/AdGuardHome/issues/1730 [#2993]: https://github.com/AdguardTeam/AdGuardHome/issues/2993 [#3057]: https://github.com/AdguardTeam/AdGuardHome/issues/3057 +[#3142]: https://github.com/AdguardTeam/AdGuardHome/issues/3142 [#3367]: https://github.com/AdguardTeam/AdGuardHome/issues/3367 [#3381]: https://github.com/AdguardTeam/AdGuardHome/issues/3381 [#3503]: https://github.com/AdguardTeam/AdGuardHome/issues/3503 diff --git a/go.mod b/go.mod index 1aedfc38..8cfd5475 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.17 require ( github.com/AdguardTeam/dnsproxy v0.41.4 - github.com/AdguardTeam/golibs v0.10.6 + github.com/AdguardTeam/golibs v0.10.8 github.com/AdguardTeam/urlfilter v0.15.2 github.com/NYTimes/gziphandler v1.1.1 github.com/ameshkov/dnscrypt/v2 v2.2.3 diff --git a/go.sum b/go.sum index 716b6955..5e5ef775 100644 --- a/go.sum +++ b/go.sum @@ -12,8 +12,9 @@ github.com/AdguardTeam/dnsproxy v0.41.4/go.mod h1:GCdEbTw683vBqksJIccPSYzBg2yIFb github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4= github.com/AdguardTeam/golibs v0.4.2/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4= github.com/AdguardTeam/golibs v0.10.4/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw= -github.com/AdguardTeam/golibs v0.10.6 h1:6UG6LxWFnG7TfjNzeApw+T68Kqqov0fcDYk9RjhTdhc= github.com/AdguardTeam/golibs v0.10.6/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw= +github.com/AdguardTeam/golibs v0.10.8 h1:diU9gP9qG1qeLbAkzIwfUerpHSqzR6zaBgzvRMR/m6Q= +github.com/AdguardTeam/golibs v0.10.8/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw= github.com/AdguardTeam/gomitmproxy v0.2.0/go.mod h1:Qdv0Mktnzer5zpdpi5rAwixNJzW2FN91LjKJCkVbYGU= github.com/AdguardTeam/urlfilter v0.15.2 h1:LZGgrm4l4Ys9eAqB+UUmZfiC6vHlDlYFhx0WXqo6LtQ= github.com/AdguardTeam/urlfilter v0.15.2/go.mod h1:46YZDOV1+qtdRDuhZKVPSSp7JWWes0KayqHrKAFBdEI= diff --git a/internal/aghnet/subnetdetector.go b/internal/aghnet/subnetdetector.go deleted file mode 100644 index fd338aaa..00000000 --- a/internal/aghnet/subnetdetector.go +++ /dev/null @@ -1,158 +0,0 @@ -package aghnet - -import ( - "net" -) - -// SubnetDetector describes IP address properties. -type SubnetDetector struct { - // spNets is the collection of special-purpose address registries as defined - // by RFC 6890. - spNets []*net.IPNet - - // locServedNets is the collection of locally-served networks as defined by - // RFC 6303. - locServedNets []*net.IPNet -} - -// NewSubnetDetector returns a new IP detector. -// -// TODO(a.garipov): Decide whether an error is actually needed. -func NewSubnetDetector() (snd *SubnetDetector, err error) { - spNets := []string{ - // "This" network. - "0.0.0.0/8", - // Private-Use Networks. - "10.0.0.0/8", - // Shared Address Space. - "100.64.0.0/10", - // Loopback. - "127.0.0.0/8", - // Link Local. - "169.254.0.0/16", - // Private-Use Networks. - "172.16.0.0/12", - // IETF Protocol Assignments. - "192.0.0.0/24", - // DS-Lite. - "192.0.0.0/29", - // TEST-NET-1 - "192.0.2.0/24", - // 6to4 Relay Anycast. - "192.88.99.0/24", - // Private-Use Networks. - "192.168.0.0/16", - // Network Interconnect Device Benchmark Testing. - "198.18.0.0/15", - // TEST-NET-2. - "198.51.100.0/24", - // TEST-NET-3. - "203.0.113.0/24", - // Reserved for Future Use. - "240.0.0.0/4", - // Limited Broadcast. - "255.255.255.255/32", - - // Loopback. - "::1/128", - // Unspecified. - "::/128", - // IPv4-IPv6 Translation Address. - "64:ff9b::/96", - - // IPv4-Mapped Address. Since this network is used for mapping - // IPv4 addresses, we don't include it. - // "::ffff:0:0/96", - - // Discard-Only Prefix. - "100::/64", - // IETF Protocol Assignments. - "2001::/23", - // TEREDO. - "2001::/32", - // Benchmarking. - "2001:2::/48", - // Documentation. - "2001:db8::/32", - // ORCHID. - "2001:10::/28", - // 6to4. - "2002::/16", - // Unique-Local. - "fc00::/7", - // Linked-Scoped Unicast. - "fe80::/10", - } - - // TODO(e.burkov): It's a subslice of the slice above. Should be done - // smarter. - locServedNets := []string{ - // IPv4. - "10.0.0.0/8", - "172.16.0.0/12", - "192.168.0.0/16", - "127.0.0.0/8", - "169.254.0.0/16", - "192.0.2.0/24", - "198.51.100.0/24", - "203.0.113.0/24", - "255.255.255.255/32", - // IPv6. - "::/128", - "::1/128", - "fe80::/10", - "2001:db8::/32", - "fd00::/8", - } - - snd = &SubnetDetector{ - spNets: make([]*net.IPNet, len(spNets)), - locServedNets: make([]*net.IPNet, len(locServedNets)), - } - for i, ipnetStr := range spNets { - var ipnet *net.IPNet - _, ipnet, err = net.ParseCIDR(ipnetStr) - if err != nil { - return nil, err - } - - snd.spNets[i] = ipnet - } - for i, ipnetStr := range locServedNets { - var ipnet *net.IPNet - _, ipnet, err = net.ParseCIDR(ipnetStr) - if err != nil { - return nil, err - } - - snd.locServedNets[i] = ipnet - } - - return snd, nil -} - -// anyNetContains ranges through the given ipnets slice searching for the one -// which contains the ip. For internal use only. -// -// TODO(e.burkov): Think about memoization. -func anyNetContains(ipnets *[]*net.IPNet, ip net.IP) (is bool) { - for _, ipnet := range *ipnets { - if ipnet.Contains(ip) { - return true - } - } - - return false -} - -// IsSpecialNetwork returns true if IP address is contained by any of -// special-purpose IP address registries. It's safe for concurrent use. -func (snd *SubnetDetector) IsSpecialNetwork(ip net.IP) (is bool) { - return anyNetContains(&snd.spNets, ip) -} - -// IsLocallyServedNetwork returns true if IP address is contained by any of -// locally-served IP address registries. It's safe for concurrent use. -func (snd *SubnetDetector) IsLocallyServedNetwork(ip net.IP) (is bool) { - return anyNetContains(&snd.locServedNets, ip) -} diff --git a/internal/aghnet/subnetdetector_test.go b/internal/aghnet/subnetdetector_test.go deleted file mode 100644 index f4b7678c..00000000 --- a/internal/aghnet/subnetdetector_test.go +++ /dev/null @@ -1,252 +0,0 @@ -package aghnet - -import ( - "net" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestSubnetDetector_DetectSpecialNetwork(t *testing.T) { - snd, err := NewSubnetDetector() - require.NoError(t, err) - - testCases := []struct { - name string - ip net.IP - want bool - }{{ - name: "not_specific", - ip: net.ParseIP("8.8.8.8"), - want: false, - }, { - name: "this_host_on_this_network", - ip: net.ParseIP("0.0.0.0"), - want: true, - }, { - name: "private-Use", - ip: net.ParseIP("10.0.0.0"), - want: true, - }, { - name: "shared_address_space", - ip: net.ParseIP("100.64.0.0"), - want: true, - }, { - name: "loopback", - ip: net.ParseIP("127.0.0.0"), - want: true, - }, { - name: "link_local", - ip: net.ParseIP("169.254.0.0"), - want: true, - }, { - name: "private-use", - ip: net.ParseIP("172.16.0.0"), - want: true, - }, { - name: "ietf_protocol_assignments", - ip: net.ParseIP("192.0.0.0"), - want: true, - }, { - name: "ds-lite", - ip: net.ParseIP("192.0.0.0"), - want: true, - }, { - name: "documentation_(test-net-1)", - ip: net.ParseIP("192.0.2.0"), - want: true, - }, { - name: "6to4_relay_anycast", - ip: net.ParseIP("192.88.99.0"), - want: true, - }, { - name: "private-use", - ip: net.ParseIP("192.168.0.0"), - want: true, - }, { - name: "benchmarking", - ip: net.ParseIP("198.18.0.0"), - want: true, - }, { - name: "documentation_(test-net-2)", - ip: net.ParseIP("198.51.100.0"), - want: true, - }, { - name: "documentation_(test-net-3)", - ip: net.ParseIP("203.0.113.0"), - want: true, - }, { - name: "reserved", - ip: net.ParseIP("240.0.0.0"), - want: true, - }, { - name: "limited_broadcast", - ip: net.ParseIP("255.255.255.255"), - want: true, - }, { - name: "loopback_address", - ip: net.ParseIP("::1"), - want: true, - }, { - name: "unspecified_address", - ip: net.ParseIP("::"), - want: true, - }, { - name: "ipv4-ipv6_translation", - ip: net.ParseIP("64:ff9b::"), - want: true, - }, { - name: "discard-only_address_block", - ip: net.ParseIP("100::"), - want: true, - }, { - name: "ietf_protocol_assignments", - ip: net.ParseIP("2001::"), - want: true, - }, { - name: "teredo", - ip: net.ParseIP("2001::"), - want: true, - }, { - name: "benchmarking", - ip: net.ParseIP("2001:2::"), - want: true, - }, { - name: "documentation", - ip: net.ParseIP("2001:db8::"), - want: true, - }, { - name: "orchid", - ip: net.ParseIP("2001:10::"), - want: true, - }, { - name: "6to4", - ip: net.ParseIP("2002::"), - want: true, - }, { - name: "unique-local", - ip: net.ParseIP("fc00::"), - want: true, - }, { - name: "linked-scoped_unicast", - ip: net.ParseIP("fe80::"), - want: true, - }} - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - assert.Equal(t, tc.want, snd.IsSpecialNetwork(tc.ip)) - }) - } -} - -func TestSubnetDetector_DetectLocallyServedNetwork(t *testing.T) { - snd, err := NewSubnetDetector() - require.NoError(t, err) - - testCases := []struct { - name string - ip net.IP - want bool - }{{ - name: "not_specific", - ip: net.ParseIP("8.8.8.8"), - want: false, - }, { - name: "private-Use", - ip: net.ParseIP("10.0.0.0"), - want: true, - }, { - name: "loopback", - ip: net.ParseIP("127.0.0.0"), - want: true, - }, { - name: "link_local", - ip: net.ParseIP("169.254.0.0"), - want: true, - }, { - name: "private-use", - ip: net.ParseIP("172.16.0.0"), - want: true, - }, { - name: "documentation_(test-net-1)", - ip: net.ParseIP("192.0.2.0"), - want: true, - }, { - name: "private-use", - ip: net.ParseIP("192.168.0.0"), - want: true, - }, { - name: "documentation_(test-net-2)", - ip: net.ParseIP("198.51.100.0"), - want: true, - }, { - name: "documentation_(test-net-3)", - ip: net.ParseIP("203.0.113.0"), - want: true, - }, { - name: "limited_broadcast", - ip: net.ParseIP("255.255.255.255"), - want: true, - }, { - name: "loopback_address", - ip: net.ParseIP("::1"), - want: true, - }, { - name: "unspecified_address", - ip: net.ParseIP("::"), - want: true, - }, { - name: "documentation", - ip: net.ParseIP("2001:db8::"), - want: true, - }, { - name: "linked-scoped_unicast", - ip: net.ParseIP("fe80::"), - want: true, - }, { - name: "locally_assigned", - ip: net.ParseIP("fd00::1"), - want: true, - }, { - name: "not_locally_assigned", - ip: net.ParseIP("fc00::1"), - want: false, - }} - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - assert.Equal(t, tc.want, snd.IsLocallyServedNetwork(tc.ip)) - }) - } -} - -func TestSubnetDetector_Detect_parallel(t *testing.T) { - t.Parallel() - - snd, err := NewSubnetDetector() - require.NoError(t, err) - - testFunc := func() { - for _, ip := range []net.IP{ - net.IPv4allrouter, - net.IPv4allsys, - net.IPv4bcast, - net.IPv4zero, - net.IPv6interfacelocalallnodes, - net.IPv6linklocalallnodes, - net.IPv6linklocalallrouters, - net.IPv6loopback, - net.IPv6unspecified, - } { - _ = snd.IsSpecialNetwork(ip) - _ = snd.IsLocallyServedNetwork(ip) - } - } - - const goroutinesNum = 50 - for i := 0; i < goroutinesNum; i++ { - go testFunc() - } -} diff --git a/internal/dnsforward/dns.go b/internal/dnsforward/dns.go index dd5a4dd5..63f694bd 100644 --- a/internal/dnsforward/dns.go +++ b/internal/dnsforward/dns.go @@ -252,7 +252,7 @@ func (s *Server) processDetermineLocal(dctx *dnsContext) (rc resultCode) { return rc } - dctx.isLocalClient = s.subnetDetector.IsLocallyServedNetwork(ip) + dctx.isLocalClient = s.privateNets.Contains(ip) return rc } @@ -374,7 +374,7 @@ func (s *Server) processRestrictLocal(ctx *dnsContext) (rc resultCode) { // Restrict an access to local addresses for external clients. We also // assume that all the DHCP leases we give are locally-served or at least // don't need to be inaccessible externally. - if !s.subnetDetector.IsLocallyServedNetwork(ip) { + if !s.privateNets.Contains(ip) { log.Debug("dns: addr %s is not from locally-served network", ip) return resultCodeSuccess @@ -481,7 +481,7 @@ func (s *Server) processLocalPTR(ctx *dnsContext) (rc resultCode) { s.serverLock.RLock() defer s.serverLock.RUnlock() - if !s.subnetDetector.IsLocallyServedNetwork(ip) { + if !s.privateNets.Contains(ip) { return resultCodeSuccess } diff --git a/internal/dnsforward/dns_test.go b/internal/dnsforward/dns_test.go index 4fc87ccf..54104268 100644 --- a/internal/dnsforward/dns_test.go +++ b/internal/dnsforward/dns_test.go @@ -4,35 +4,41 @@ import ( "net" "testing" - "github.com/AdguardTeam/AdGuardHome/internal/aghnet" "github.com/AdguardTeam/AdGuardHome/internal/aghtest" "github.com/AdguardTeam/AdGuardHome/internal/filtering" "github.com/AdguardTeam/dnsproxy/proxy" "github.com/AdguardTeam/dnsproxy/upstream" + "github.com/AdguardTeam/golibs/netutil" "github.com/miekg/dns" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestServer_ProcessDetermineLocal(t *testing.T) { - snd, err := aghnet.NewSubnetDetector() - require.NoError(t, err) s := &Server{ - subnetDetector: snd, + privateNets: netutil.SubnetSetFunc(netutil.IsLocallyServed), } testCases := []struct { + want assert.BoolAssertionFunc name string cliIP net.IP - want bool }{{ + want: assert.True, name: "local", cliIP: net.IP{192, 168, 0, 1}, - want: true, }, { + want: assert.False, name: "external", cliIP: net.IP{250, 249, 0, 1}, - want: false, + }, { + want: assert.False, + name: "invalid", + cliIP: net.IP{1, 2, 3, 4, 5}, + }, { + want: assert.False, + name: "nil", + cliIP: nil, }} for _, tc := range testCases { @@ -47,7 +53,7 @@ func TestServer_ProcessDetermineLocal(t *testing.T) { } s.processDetermineLocal(dctx) - assert.Equal(t, tc.want, dctx.isLocalClient) + tc.want(t, dctx.isLocalClient) }) } } diff --git a/internal/dnsforward/dnsforward.go b/internal/dnsforward/dnsforward.go index 2d32cfd2..48e344b3 100644 --- a/internal/dnsforward/dnsforward.go +++ b/internal/dnsforward/dnsforward.go @@ -74,7 +74,7 @@ type Server struct { localDomainSuffix string ipset ipsetCtx - subnetDetector *aghnet.SubnetDetector + privateNets netutil.SubnetSet localResolvers *proxy.Proxy sysResolvers aghnet.SystemResolvers recDetector *recursionDetector @@ -111,13 +111,13 @@ const defaultLocalDomainSuffix = ".lan." // DNSCreateParams are parameters to create a new server. type DNSCreateParams struct { - DNSFilter *filtering.DNSFilter - Stats stats.Stats - QueryLog querylog.QueryLog - DHCPServer dhcpd.ServerInterface - SubnetDetector *aghnet.SubnetDetector - Anonymizer *aghnet.IPMut - LocalDomain string + DNSFilter *filtering.DNSFilter + Stats stats.Stats + QueryLog querylog.QueryLog + DHCPServer dhcpd.ServerInterface + PrivateNets netutil.SubnetSet + Anonymizer *aghnet.IPMut + LocalDomain string } // domainNameToSuffix converts a domain name into a local domain suffix. @@ -161,7 +161,7 @@ func NewServer(p DNSCreateParams) (s *Server, err error) { dnsFilter: p.DNSFilter, stats: p.Stats, queryLog: p.QueryLog, - subnetDetector: p.SubnetDetector, + privateNets: p.PrivateNets, localDomainSuffix: localDomainSuffix, recDetector: newRecursionDetector(recursionTTL, cachedRecurrentReqNum), clientIDCache: cache.New(cache.Config{ @@ -315,7 +315,7 @@ func (s *Server) Exchange(ip net.IP) (host string, err error) { } resolver := s.internalProxy - if s.subnetDetector.IsLocallyServedNetwork(ip) { + if s.privateNets.Contains(ip) { if !s.conf.UsePrivateRDNS { return "", nil } diff --git a/internal/dnsforward/dnsforward_test.go b/internal/dnsforward/dnsforward_test.go index bc90d760..36761f41 100644 --- a/internal/dnsforward/dnsforward_test.go +++ b/internal/dnsforward/dnsforward_test.go @@ -24,6 +24,7 @@ import ( "github.com/AdguardTeam/dnsproxy/proxy" "github.com/AdguardTeam/dnsproxy/upstream" "github.com/AdguardTeam/golibs/errors" + "github.com/AdguardTeam/golibs/netutil" "github.com/AdguardTeam/golibs/testutil" "github.com/AdguardTeam/golibs/timeutil" "github.com/miekg/dns" @@ -69,14 +70,11 @@ func createTestServer( f := filtering.New(filterConf, filters) f.SetEnabled(true) - snd, err := aghnet.NewSubnetDetector() - require.NoError(t, err) - require.NotNil(t, snd) - + var err error s, err = NewServer(DNSCreateParams{ - DHCPServer: &testDHCP{}, - DNSFilter: f, - SubnetDetector: snd, + DHCPServer: &testDHCP{}, + DNSFilter: f, + PrivateNets: netutil.SubnetSetFunc(netutil.IsLocallyServed), }) require.NoError(t, err) @@ -770,16 +768,11 @@ func TestBlockedCustomIP(t *testing.T) { Data: []byte(rules), }} - snd, err := aghnet.NewSubnetDetector() - require.NoError(t, err) - require.NotNil(t, snd) - f := filtering.New(&filtering.Config{}, filters) - var s *Server - s, err = NewServer(DNSCreateParams{ - DHCPServer: &testDHCP{}, - DNSFilter: f, - SubnetDetector: snd, + s, err := NewServer(DNSCreateParams{ + DHCPServer: &testDHCP{}, + DNSFilter: f, + PrivateNets: netutil.SubnetSetFunc(netutil.IsLocallyServed), }) require.NoError(t, err) @@ -913,15 +906,10 @@ func TestRewrite(t *testing.T) { f := filtering.New(c, nil) f.SetEnabled(true) - snd, err := aghnet.NewSubnetDetector() - require.NoError(t, err) - require.NotNil(t, snd) - - var s *Server - s, err = NewServer(DNSCreateParams{ - DHCPServer: &testDHCP{}, - DNSFilter: f, - SubnetDetector: snd, + s, err := NewServer(DNSCreateParams{ + DHCPServer: &testDHCP{}, + DNSFilter: f, + PrivateNets: netutil.SubnetSetFunc(netutil.IsLocallyServed), }) require.NoError(t, err) @@ -1028,15 +1016,10 @@ func (d *testDHCP) Leases(flags dhcpd.GetLeasesFlags) (leases []*dhcpd.Lease) { func (d *testDHCP) SetOnLeaseChanged(onLeaseChanged dhcpd.OnLeaseChangedT) {} func TestPTRResponseFromDHCPLeases(t *testing.T) { - snd, err := aghnet.NewSubnetDetector() - require.NoError(t, err) - require.NotNil(t, snd) - - var s *Server - s, err = NewServer(DNSCreateParams{ - DNSFilter: filtering.New(&filtering.Config{}, nil), - DHCPServer: &testDHCP{}, - SubnetDetector: snd, + s, err := NewServer(DNSCreateParams{ + DNSFilter: filtering.New(&filtering.Config{}, nil), + DHCPServer: &testDHCP{}, + PrivateNets: netutil.SubnetSetFunc(netutil.IsLocallyServed), }) require.NoError(t, err) @@ -1105,16 +1088,11 @@ func TestPTRResponseFromHosts(t *testing.T) { }, nil) flt.SetEnabled(true) - var snd *aghnet.SubnetDetector - snd, err = aghnet.NewSubnetDetector() - require.NoError(t, err) - require.NotNil(t, snd) - var s *Server s, err = NewServer(DNSCreateParams{ - DHCPServer: &testDHCP{}, - DNSFilter: flt, - SubnetDetector: snd, + DHCPServer: &testDHCP{}, + DNSFilter: flt, + PrivateNets: netutil.SubnetSetFunc(netutil.IsLocallyServed), }) require.NoError(t, err) @@ -1227,9 +1205,7 @@ func TestServer_Exchange(t *testing.T) { srv.conf.ResolveClients = true srv.conf.UsePrivateRDNS = true - var err error - srv.subnetDetector, err = aghnet.NewSubnetDetector() - require.NoError(t, err) + srv.privateNets = netutil.SubnetSetFunc(netutil.IsLocallyServed) localIP := net.IP{192, 168, 1, 1} testCases := []struct { diff --git a/internal/dnsforward/filter_test.go b/internal/dnsforward/filter_test.go index 84570bce..69dcf8f9 100644 --- a/internal/dnsforward/filter_test.go +++ b/internal/dnsforward/filter_test.go @@ -4,7 +4,6 @@ import ( "net" "testing" - "github.com/AdguardTeam/AdGuardHome/internal/aghnet" "github.com/AdguardTeam/AdGuardHome/internal/aghtest" "github.com/AdguardTeam/AdGuardHome/internal/filtering" "github.com/AdguardTeam/dnsproxy/proxy" @@ -39,14 +38,10 @@ func TestHandleDNSRequest_filterDNSResponse(t *testing.T) { f := filtering.New(&filtering.Config{}, filters) f.SetEnabled(true) - snd, err := aghnet.NewSubnetDetector() - require.NoError(t, err) - require.NotNil(t, snd) - s, err := NewServer(DNSCreateParams{ - DHCPServer: &testDHCP{}, - DNSFilter: f, - SubnetDetector: snd, + DHCPServer: &testDHCP{}, + DNSFilter: f, + PrivateNets: netutil.SubnetSetFunc(netutil.IsLocallyServed), }) require.NoError(t, err) diff --git a/internal/dnsforward/http.go b/internal/dnsforward/http.go index b7fb66a6..2b7cfd13 100644 --- a/internal/dnsforward/http.go +++ b/internal/dnsforward/http.go @@ -10,7 +10,6 @@ import ( "time" "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" - "github.com/AdguardTeam/AdGuardHome/internal/aghnet" "github.com/AdguardTeam/dnsproxy/proxy" "github.com/AdguardTeam/dnsproxy/upstream" "github.com/AdguardTeam/golibs/errors" @@ -167,7 +166,7 @@ func (req *dnsConfig) checkBootstrap() (err error) { } // validate returns an error if any field of req is invalid. -func (req *dnsConfig) validate(snd *aghnet.SubnetDetector) (err error) { +func (req *dnsConfig) validate(privateNets netutil.SubnetSet) (err error) { if req.Upstreams != nil { err = ValidateUpstreams(*req.Upstreams) if err != nil { @@ -176,7 +175,7 @@ func (req *dnsConfig) validate(snd *aghnet.SubnetDetector) (err error) { } if req.LocalPTRUpstreams != nil { - err = ValidateUpstreamsPrivate(*req.LocalPTRUpstreams, snd) + err = ValidateUpstreamsPrivate(*req.LocalPTRUpstreams, privateNets) if err != nil { return fmt.Errorf("validating private upstream servers: %w", err) } @@ -224,7 +223,7 @@ func (s *Server) handleSetConfig(w http.ResponseWriter, r *http.Request) { return } - err = req.validate(s.subnetDetector) + err = req.validate(s.privateNets) if err != nil { aghhttp.Error(r, w, http.StatusBadRequest, "%s", err) @@ -350,17 +349,6 @@ func IsCommentOrEmpty(s string) (ok bool) { return len(s) == 0 || s[0] == '#' } -// LocalNetChecker is used to check if the IP address belongs to a local -// network. -type LocalNetChecker interface { - // IsLocallyServedNetwork returns true if ip is contained in any of address - // registries defined by RFC 6303. - IsLocallyServedNetwork(ip net.IP) (ok bool) -} - -// type check -var _ LocalNetChecker = (*aghnet.SubnetDetector)(nil) - // newUpstreamConfig validates upstreams and returns an appropriate upstream // configuration or nil if it can't be built. // @@ -422,8 +410,8 @@ func stringKeysSorted(m map[string][]upstream.Upstream) (sorted []string) { // ValidateUpstreamsPrivate validates each upstream and returns an error if any // upstream is invalid or if there are no default upstreams specified. It also // checks each domain of domain-specific upstreams for being ARPA pointing to -// a locally-served network. lnc must not be nil. -func ValidateUpstreamsPrivate(upstreams []string, lnc LocalNetChecker) (err error) { +// a locally-served network. privateNets must not be nil. +func ValidateUpstreamsPrivate(upstreams []string, privateNets netutil.SubnetSet) (err error) { conf, err := newUpstreamConfig(upstreams) if err != nil { return err @@ -444,7 +432,7 @@ func ValidateUpstreamsPrivate(upstreams []string, lnc LocalNetChecker) (err erro continue } - if !lnc.IsLocallyServedNetwork(subnet.IP) { + if !privateNets.Contains(subnet.IP) { errs = append( errs, fmt.Errorf("arpa domain %q should point to a locally-served network", domain), diff --git a/internal/dnsforward/http_test.go b/internal/dnsforward/http_test.go index 6e28ab41..f468f7ae 100644 --- a/internal/dnsforward/http_test.go +++ b/internal/dnsforward/http_test.go @@ -14,6 +14,7 @@ import ( "github.com/AdguardTeam/AdGuardHome/internal/aghnet" "github.com/AdguardTeam/AdGuardHome/internal/filtering" + "github.com/AdguardTeam/golibs/netutil" "github.com/AdguardTeam/golibs/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -410,8 +411,7 @@ func TestValidateUpstreams(t *testing.T) { } func TestValidateUpstreamsPrivate(t *testing.T) { - snd, err := aghnet.NewSubnetDetector() - require.NoError(t, err) + ss := netutil.SubnetSetFunc(netutil.IsLocallyServed) testCases := []struct { name string @@ -452,7 +452,7 @@ func TestValidateUpstreamsPrivate(t *testing.T) { set := []string{"192.168.0.1", tc.u} t.Run(tc.name, func(t *testing.T) { - err = ValidateUpstreamsPrivate(set, snd) + err := ValidateUpstreamsPrivate(set, ss) testutil.AssertErrorMsg(t, tc.wantErr, err) }) } diff --git a/internal/home/config.go b/internal/home/config.go index 6ecb4ccb..c018f16e 100644 --- a/internal/home/config.go +++ b/internal/home/config.go @@ -126,6 +126,10 @@ type dnsConfig struct { // ResolveClients enables and disables resolving clients with RDNS. ResolveClients bool `yaml:"resolve_clients"` + // PrivateNets is the set of IP networks for which the private reverse DNS + // resolver should be used. + PrivateNets []string `yaml:"private_networks"` + // UsePrivateRDNS defines if the PTR requests for unknown addresses from // locally-served networks should be resolved via private PTR resolvers. UsePrivateRDNS bool `yaml:"use_private_ptr_resolvers"` diff --git a/internal/home/dns.go b/internal/home/dns.go index 4c27abd9..d676f6af 100644 --- a/internal/home/dns.go +++ b/internal/home/dns.go @@ -77,13 +77,36 @@ func initDNSServer() (err error) { filterConf.HTTPRegister = httpRegister Context.dnsFilter = filtering.New(&filterConf, nil) + var privateNets netutil.SubnetSet + switch len(config.DNS.PrivateNets) { + case 0: + // Use an optimized locally-served matcher. + privateNets = netutil.SubnetSetFunc(netutil.IsLocallyServed) + case 1: + var n *net.IPNet + n, err = netutil.ParseSubnet(config.DNS.PrivateNets[0]) + if err != nil { + return fmt.Errorf("preparing the set of private subnets: %w", err) + } + + privateNets = n + default: + var nets []*net.IPNet + nets, err = netutil.ParseSubnets(config.DNS.PrivateNets...) + if err != nil { + return fmt.Errorf("preparing the set of private subnets: %w", err) + } + + privateNets = netutil.SliceSubnetSet(nets) + } + p := dnsforward.DNSCreateParams{ - DNSFilter: Context.dnsFilter, - Stats: Context.stats, - QueryLog: Context.queryLog, - SubnetDetector: Context.subnetDetector, - Anonymizer: anonymizer, - LocalDomain: config.DHCP.LocalDomainName, + DNSFilter: Context.dnsFilter, + Stats: Context.stats, + QueryLog: Context.queryLog, + PrivateNets: privateNets, + Anonymizer: anonymizer, + LocalDomain: config.DHCP.LocalDomainName, } if Context.dhcpServer != nil { p.DHCPServer = Context.dhcpServer @@ -133,7 +156,7 @@ func onDNSRequest(pctx *proxy.DNSContext) { if config.DNS.ResolveClients && !ip.IsLoopback() { Context.rdns.Begin(ip) } - if !Context.subnetDetector.IsSpecialNetwork(ip) { + if !netutil.IsSpecialPurpose(ip) { Context.whois.Begin(ip) } } @@ -360,10 +383,14 @@ func startDNSServer() error { const topClientsNumber = 100 // the number of clients to get for _, ip := range Context.stats.GetTopClientsIP(topClientsNumber) { + if ip == nil { + continue + } + if config.DNS.ResolveClients && !ip.IsLoopback() { Context.rdns.Begin(ip) } - if !Context.subnetDetector.IsSpecialNetwork(ip) { + if !netutil.IsSpecialPurpose(ip) { Context.whois.Begin(ip) } } diff --git a/internal/home/home.go b/internal/home/home.go index 114ba4b6..7096be78 100644 --- a/internal/home/home.go +++ b/internal/home/home.go @@ -66,8 +66,6 @@ type homeContext struct { updater *updater.Updater - subnetDetector *aghnet.SubnetDetector - // mux is our custom http.ServeMux. mux *http.ServeMux @@ -477,9 +475,6 @@ func run(args options, clientBuildFS fs.FS) { Context.web, err = initWeb(args, clientBuildFS) fatalOnError(err) - Context.subnetDetector, err = aghnet.NewSubnetDetector() - fatalOnError(err) - if !Context.firstRun { err = initDNSServer() fatalOnError(err) From b9790f663a6a0951b684c80989ef35e4b55c5662 Mon Sep 17 00:00:00 2001 From: Ildar Kamalov Date: Mon, 21 Mar 2022 18:57:31 +0300 Subject: [PATCH 004/110] Pull request: 4409 fix icons height Updates #4409 Squashed commit of the following: commit 132073ccf00ba6eb6ddacfc82c8d2e01f3d4b011 Author: Ildar Kamalov Date: Mon Mar 21 15:22:33 2022 +0300 client: remove height commit 29970f33e7af26e406c442510d626fc0cfdae0ce Merge: 96b3abcf 77858586 Author: Ildar Kamalov Date: Mon Mar 21 15:10:49 2022 +0300 Merge branch 'master' into 4409-icon commit 96b3abcfa4561da466cc53331b8f751d55f59351 Author: Ildar Kamalov Date: Mon Mar 21 10:22:55 2022 +0300 client: fix icons height --- client/src/components/ui/Icons.css | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/components/ui/Icons.css b/client/src/components/ui/Icons.css index 73f4c864..929f4725 100644 --- a/client/src/components/ui/Icons.css +++ b/client/src/components/ui/Icons.css @@ -1,7 +1,6 @@ .icons { display: inline-block; vertical-align: middle; - height: 100%; } .icon--24 { From f8e45c13f3c0968b261235c34dc13d309c57de17 Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Tue, 22 Mar 2022 15:21:03 +0300 Subject: [PATCH 005/110] Pull request: 3142 swap arp and rdns priority Merge in DNS/adguard-home from 3142-fix-clients to master Updates #3142. Updates #3597. Squashed commit of the following: commit 4dcabedbfb1a4e4a0aaba588f708e4625442fce8 Author: Eugene Burkov Date: Tue Mar 22 15:13:15 2022 +0300 all: imp log of changes commit 481088d05eecac1109daf378e0b4d5f6b2cf099b Author: Eugene Burkov Date: Tue Mar 22 14:36:44 2022 +0300 all: swap arp and rdns priority --- CHANGELOG.md | 2 ++ internal/dnsforward/dnsforward.go | 4 +++- internal/home/clients.go | 6 ++---- internal/home/rdns.go | 8 +++----- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d663d78e..bc986774 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,8 @@ and this project adheres to ### Changed +- Reverse DNS now has a greater priority as the source of runtime clients' + informmation than ARP neighborhood. - Improved detection of runtime clients through more resilient ARP processing ([#3597]). - The TTL of responses served from the optimistic cache is now lowered to 10 diff --git a/internal/dnsforward/dnsforward.go b/internal/dnsforward/dnsforward.go index 48e344b3..a5b0098a 100644 --- a/internal/dnsforward/dnsforward.go +++ b/internal/dnsforward/dnsforward.go @@ -314,7 +314,7 @@ func (s *Server) Exchange(ip net.IP) (host string, err error) { StartTime: time.Now(), } - resolver := s.internalProxy + var resolver *proxy.Proxy if s.privateNets.Contains(ip) { if !s.conf.UsePrivateRDNS { return "", nil @@ -322,6 +322,8 @@ func (s *Server) Exchange(ip net.IP) (host string, err error) { resolver = s.localResolvers s.recDetector.add(*req) + } else { + resolver = s.internalProxy } if err = resolver.Resolve(ctx); err != nil { diff --git a/internal/home/clients.go b/internal/home/clients.go index d9aad40e..08d70bb9 100644 --- a/internal/home/clients.go +++ b/internal/home/clients.go @@ -53,8 +53,8 @@ type clientSource uint // Client sources. The order determines the priority. const ( ClientSourceWHOIS clientSource = iota - ClientSourceRDNS ClientSourceARP + ClientSourceRDNS ClientSourceDHCP ClientSourceHostsFile ) @@ -723,9 +723,7 @@ func (clients *clientsContainer) AddHost(ip net.IP, host string, src clientSourc clients.lock.Lock() defer clients.lock.Unlock() - ok = clients.addHostLocked(ip, host, src) - - return ok, nil + return clients.addHostLocked(ip, host, src), nil } // addHostLocked adds a new IP-hostname pairing. For internal use only. diff --git a/internal/home/rdns.go b/internal/home/rdns.go index cba748af..7a2d1bcd 100644 --- a/internal/home/rdns.go +++ b/internal/home/rdns.go @@ -125,14 +125,12 @@ func (r *RDNS) workerLoop() { log.Debug("rdns: resolving %q: %s", ip, err) continue - } - - if host == "" { + } else if host == "" { continue } - // Don't handle any errors since AddHost doesn't return non-nil - // errors for now. + // Don't handle any errors since AddHost doesn't return non-nil errors + // for now. _, _ = r.clients.AddHost(ip, host, ClientSourceRDNS) } } From b16b1d1d248db9cd8806f367fb41cdd45a120ccb Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Tue, 22 Mar 2022 18:28:43 +0300 Subject: [PATCH 006/110] Pull request: home: fix adding client Merge in DNS/adguard-home from fix-arp-names to master Updates #3597. Squashed commit of the following: commit b4737a342ab4c3685512bd1271a2dc9fa25256d0 Author: Eugene Burkov Date: Tue Mar 22 16:55:52 2022 +0300 home: fix adding client --- internal/home/clients.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/home/clients.go b/internal/home/clients.go index 08d70bb9..9230e565 100644 --- a/internal/home/clients.go +++ b/internal/home/clients.go @@ -735,6 +735,7 @@ func (clients *clientsContainer) addHostLocked(ip net.IP, host string, src clien return false } + rc.Host = host rc.Source = src } else { rc = &RuntimeClient{ @@ -829,7 +830,7 @@ func (clients *clientsContainer) addFromSystemARP() { added := 0 for _, n := range ns { - if clients.addHostLocked(n.IP, "", ClientSourceARP) { + if clients.addHostLocked(n.IP, n.Name, ClientSourceARP) { added++ } } From beb674ecbc0cf47510e62064fb03497650f58e42 Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Wed, 23 Mar 2022 14:19:45 +0300 Subject: [PATCH 007/110] Pull request: filtering: fix qq regex legacy Merge in DNS/adguard-home from qq-rule to master Updates #3717. Squashed commit of the following: commit 1e2d50077067e5f95da645091686349ce9c8a6bc Merge: 7290a1c4 b16b1d1d Author: Eugene Burkov Date: Wed Mar 23 14:14:10 2022 +0300 Merge branch 'master' into qq-rule commit 7290a1c456a7f47e91cc9485f5e112b92cb595ba Author: Eugene Burkov Date: Fri Mar 18 20:36:17 2022 +0300 filtering: fix qq regex legacy --- internal/filtering/blocked.go | 213 +++++++++++++++++++++------------- 1 file changed, 132 insertions(+), 81 deletions(-) diff --git a/internal/filtering/blocked.go b/internal/filtering/blocked.go index 3ecc2619..1d165cf4 100644 --- a/internal/filtering/blocked.go +++ b/internal/filtering/blocked.go @@ -19,9 +19,12 @@ type svc struct { // Keep in sync with: // client/src/helpers/constants.js // client/src/components/ui/Icons.js -var serviceRulesArray = []svc{ - {"whatsapp", []string{"||whatsapp.net^", "||whatsapp.com^"}}, - {"facebook", []string{ +var serviceRulesArray = []svc{{ + name: "whatsapp", + rules: []string{"||whatsapp.net^", "||whatsapp.com^"}, +}, { + name: "facebook", + rules: []string{ "||facebook.com^", "||facebook.net^", "||fbcdn.net^", @@ -33,9 +36,13 @@ var serviceRulesArray = []svc{ "||facebookcorewwwi.onion^", "||fbcdn.com^", "||fb.watch^", - }}, - {"twitter", []string{"||twitter.com^", "||twttr.com^", "||t.co^", "||twimg.com^"}}, - {"youtube", []string{ + }, +}, { + name: "twitter", + rules: []string{"||twitter.com^", "||twttr.com^", "||t.co^", "||twimg.com^"}, +}, { + name: "youtube", + rules: []string{ "||youtube.com^", "||ytimg.com^", "||youtu.be^", @@ -43,35 +50,75 @@ var serviceRulesArray = []svc{ "||youtubei.googleapis.com^", "||youtube-nocookie.com^", "||youtube", - }}, - {"twitch", []string{"||twitch.tv^", "||ttvnw.net^", "||jtvnw.net^", "||twitchcdn.net^"}}, - {"netflix", []string{"||nflxext.com^", "||netflix.com^", "||nflximg.net^", "||nflxvideo.net^", "||nflxso.net^"}}, - {"instagram", []string{"||instagram.com^", "||cdninstagram.com^"}}, - {"snapchat", []string{ + }, +}, { + name: "twitch", + rules: []string{"||twitch.tv^", "||ttvnw.net^", "||jtvnw.net^", "||twitchcdn.net^"}, +}, { + name: "netflix", + rules: []string{ + "||nflxext.com^", + "||netflix.com^", + "||nflximg.net^", + "||nflxvideo.net^", + "||nflxso.net^", + }, +}, { + name: "instagram", + rules: []string{"||instagram.com^", "||cdninstagram.com^"}, +}, { + name: "snapchat", + rules: []string{ "||snapchat.com^", "||sc-cdn.net^", "||snap-dev.net^", "||snapkit.co", "||snapads.com^", "||impala-media-production.s3.amazonaws.com^", - }}, - {"discord", []string{"||discord.gg^", "||discordapp.net^", "||discordapp.com^", "||discord.com^", "||discord.media^"}}, - {"ok", []string{"||ok.ru^"}}, - {"skype", []string{"||skype.com^", "||skypeassets.com^"}}, - {"vk", []string{"||vk.com^", "||userapi.com^", "||vk-cdn.net^", "||vkuservideo.net^"}}, - {"origin", []string{"||origin.com^", "||signin.ea.com^", "||accounts.ea.com^"}}, - {"steam", []string{ + }, +}, { + name: "discord", + rules: []string{ + "||discord.gg^", + "||discordapp.net^", + "||discordapp.com^", + "||discord.com^", + "||discord.media^", + }, +}, { + name: "ok", + rules: []string{"||ok.ru^"}, +}, { + name: "skype", + rules: []string{"||skype.com^", "||skypeassets.com^"}, +}, { + name: "vk", + rules: []string{"||vk.com^", "||userapi.com^", "||vk-cdn.net^", "||vkuservideo.net^"}, +}, { + name: "origin", + rules: []string{"||origin.com^", "||signin.ea.com^", "||accounts.ea.com^"}, +}, { + name: "steam", + rules: []string{ "||steam.com^", "||steampowered.com^", "||steamcommunity.com^", "||steamstatic.com^", "||steamstore-a.akamaihd.net^", "||steamcdn-a.akamaihd.net^", - }}, - {"epic_games", []string{"||epicgames.com^", "||easyanticheat.net^", "||easy.ac^", "||eac-cdn.com^"}}, - {"reddit", []string{"||reddit.com^", "||redditstatic.com^", "||redditmedia.com^", "||redd.it^"}}, - {"mail_ru", []string{"||mail.ru^"}}, - {"cloudflare", []string{ + }, +}, { + name: "epic_games", + rules: []string{"||epicgames.com^", "||easyanticheat.net^", "||easy.ac^", "||eac-cdn.com^"}, +}, { + name: "reddit", + rules: []string{"||reddit.com^", "||redditstatic.com^", "||redditmedia.com^", "||redd.it^"}, +}, { + name: "mail_ru", + rules: []string{"||mail.ru^"}, +}, { + name: "cloudflare", + rules: []string{ "||cloudflare.com^", "||cloudflare-dns.com^", "||cloudflare.net^", @@ -86,8 +133,10 @@ var serviceRulesArray = []svc{ "||warp.plus^", "||1.1.1.1^", "||dns4torpnlfs2ifuz2s2yf3fc7rdmsbhm6rw75euj35pac6ap25zgqad.onion^", - }}, - {"amazon", []string{ + }, +}, { + name: "amazon", + rules: []string{ "||amazon.com^", "||media-amazon.com^", "||primevideo.com^", @@ -114,8 +163,10 @@ var serviceRulesArray = []svc{ "||amazon.co.uk^", "||createspace.com^", "||aws", - }}, - {"ebay", []string{ + }, +}, { + name: "ebay", + rules: []string{ "||ebay.com^", "||ebayimg.com^", "||ebaystatic.com^", @@ -141,8 +192,10 @@ var serviceRulesArray = []svc{ "||ebay.com.my^", "||ebay.com.sg^", "||ebay.co.uk^", - }}, - {"tiktok", []string{ + }, +}, { + name: "tiktok", + rules: []string{ "||tiktok.com^", "||tiktokcdn.com^", "||musical.ly^", @@ -162,59 +215,55 @@ var serviceRulesArray = []svc{ "||bytedance.map.fastly.net^", "||douyin.com^", "||tiktokv.com^", - }}, - {"vimeo", []string{ - "||vimeo.com^", - "||vimeocdn.com^", - "*vod-adaptive.akamaized.net^", - }}, - {"pinterest", []string{ - "||pinterest.*^", - "||pinimg.com^", - }}, - {"imgur", []string{ - "||imgur.com^", - }}, - {"dailymotion", []string{ - "||dailymotion.com^", - "||dm-event.net^", - "||dmcdn.net^", - }}, - {"qq", []string{ - // block qq.com and subdomains excluding WeChat domains - "||qq.com^$denyallow=wx*.qq.com|weixin.qq.com", + }, +}, { + name: "vimeo", + rules: []string{"||vimeo.com^", "||vimeocdn.com^", "*vod-adaptive.akamaized.net^"}, +}, { + name: "pinterest", + rules: []string{"||pinterest.*^", "||pinimg.com^"}, +}, { + name: "imgur", + rules: []string{"||imgur.com^"}, +}, { + name: "dailymotion", + rules: []string{"||dailymotion.com^", "||dm-event.net^", "||dmcdn.net^"}, +}, { + name: "qq", + rules: []string{ + // Block qq.com and subdomains excluding WeChat's domains. + "||qq.com^$denyallow=wx.qq.com|weixin.qq.com", "||qqzaixian.com^", - }}, - {"wechat", []string{ - "||wechat.com^", - "||weixin.qq.com^", - "||wx.qq.com^", - }}, - {"viber", []string{ - "||viber.com^", - }}, - {"weibo", []string{ - "||weibo.com^", - }}, - {"9gag", []string{ - "||9cache.com^", - "||9gag.com^", - }}, - {"telegram", []string{ - "||t.me^", - "||telegram.me^", - "||telegram.org^", - }}, - {"disneyplus", []string{ + }, +}, { + name: "wechat", + rules: []string{"||wechat.com^", "||weixin.qq.com^", "||wx.qq.com^"}, +}, { + name: "viber", + rules: []string{"||viber.com^"}, +}, { + name: "weibo", + rules: []string{"||weibo.com^"}, +}, { + name: "9gag", + rules: []string{"||9cache.com^", "||9gag.com^"}, +}, { + name: "telegram", + rules: []string{"||t.me^", "||telegram.me^", "||telegram.org^"}, +}, { + name: "disneyplus", + rules: []string{ "||disney-plus.net^", "||disneyplus.com^", "||disney.playback.edge.bamgrid.com^", "||media.dssott.com^", - }}, - {"hulu", []string{ - "||hulu.com^", - }}, - {"spotify", []string{ + }, +}, { + name: "hulu", + rules: []string{"||hulu.com^"}, +}, { + name: "spotify", + rules: []string{ "/_spotify-connect._tcp.local/", "||spotify.com^", "||scdn.co^", @@ -226,13 +275,15 @@ var serviceRulesArray = []svc{ "||audio4-ak-spotify-com.akamaized.net^", "||heads-ak-spotify-com.akamaized.net^", "||heads4-ak-spotify-com.akamaized.net^", - }}, - {"tinder", []string{ + }, +}, { + name: "tinder", + rules: []string{ "||gotinder.com^", "||tinder.com^", "||tindersparks.com^", - }}, -} + }, +}} // convert array to map func initBlockedServices() { From 2c33ab6a92c7066a26e68b6fff0fa04d8218f054 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Wed, 23 Mar 2022 14:36:17 +0300 Subject: [PATCH 008/110] Pull request: client: upd i18n Merge in DNS/adguard-home from upd-i18n to master Squashed commit of the following: commit 0de5987fbc8da3d609a2d0f5ab34c07959ceb818 Merge: cea47b73 beb674ec Author: Ainar Garipov Date: Wed Mar 23 14:19:57 2022 +0300 Merge branch 'master' into upd-i18n commit cea47b733dc32a3c63c2598dc8f20367b5a9753f Author: Ainar Garipov Date: Wed Mar 23 14:17:48 2022 +0300 client: upd i18n --- client/src/__locales/be.json | 113 ++++++++++---------- client/src/__locales/cs.json | 89 ++++++++-------- client/src/__locales/da.json | 53 +++++----- client/src/__locales/de.json | 95 ++++++++--------- client/src/__locales/es.json | 89 ++++++++-------- client/src/__locales/fi.json | 79 +++++++------- client/src/__locales/fr.json | 83 ++++++++------- client/src/__locales/hr.json | 97 ++++++++--------- client/src/__locales/hu.json | 89 ++++++++-------- client/src/__locales/id.json | 91 ++++++++-------- client/src/__locales/it.json | 95 ++++++++--------- client/src/__locales/ja.json | 35 ++++--- client/src/__locales/ko.json | 87 ++++++++-------- client/src/__locales/nl.json | 91 ++++++++-------- client/src/__locales/pl.json | 91 ++++++++-------- client/src/__locales/pt-br.json | 87 ++++++++-------- client/src/__locales/pt-pt.json | 87 ++++++++-------- client/src/__locales/ro.json | 91 ++++++++-------- client/src/__locales/ru.json | 93 +++++++++-------- client/src/__locales/si-lk.json | 162 +++++++++++++++++------------ client/src/__locales/sk.json | 81 ++++++++------- client/src/__locales/sl.json | 83 ++++++++------- client/src/__locales/sr-cs.json | 178 +++++++++++++++++++++++--------- client/src/__locales/sv.json | 44 ++++---- client/src/__locales/tr.json | 125 +++++++++++----------- client/src/__locales/uk.json | 104 ++++++++++--------- client/src/__locales/vi.json | 108 +++++++++++-------- client/src/__locales/zh-cn.json | 87 ++++++++-------- client/src/__locales/zh-hk.json | 6 ++ client/src/__locales/zh-tw.json | 89 ++++++++-------- 30 files changed, 1462 insertions(+), 1240 deletions(-) diff --git a/client/src/__locales/be.json b/client/src/__locales/be.json index db3d9e85..c01cbaa4 100644 --- a/client/src/__locales/be.json +++ b/client/src/__locales/be.json @@ -1,7 +1,7 @@ { "client_settings": "Налады кліентаў", - "example_upstream_reserved": "Вы можаце паказаць DNS-сервер <0>для канкрэтнага дамена(аў)", - "example_upstream_comment": "Вы можаце паказаць каментар", + "example_upstream_reserved": "upstream <0>для канкрэтных даменаў;", + "example_upstream_comment": "каментар.", "upstream_parallel": "Ужыць адначасныя запыты да ўсіх сервераў для паскарэння апрацоўкі запыту", "parallel_requests": "Паралельныя запыты", "load_balancing": "Размеркаванне нагрузкі", @@ -36,14 +36,14 @@ "dhcp_ipv4_settings": "Налады DHCP IPv4", "dhcp_ipv6_settings": "Налады DHCP IPv6", "form_error_required": "Абавязковае поле", - "form_error_ip4_format": "Няслушны фармат IPv4", + "form_error_ip4_format": "Няслушны IPv4-адрас", "form_error_ip4_range_start_format": "Няслушны IPv4-адрас пачатку дыяпазону", "form_error_ip4_range_end_format": "Няслушны IPv4-адрас канца дыяпазону", "form_error_ip4_gateway_format": "Няслушны IPv4-адрас шлюза", - "form_error_ip6_format": "Няслушны фармат IPv6", - "form_error_ip_format": "Няслушны фармат IP-адраса", - "form_error_mac_format": "Некарэктны фармат MAC", - "form_error_client_id_format": "Няслушны фармат ID кліента", + "form_error_ip6_format": "Няслушны IPv6-адрас", + "form_error_ip_format": "Няслушны IP-адрас", + "form_error_mac_format": "Некарэктны MAC-адрас", + "form_error_client_id_format": "ClientID павінен утрымліваць толькі лічбы, малыя літары і злучкі", "form_error_server_name": "Няслушнае імя сервера", "form_error_subnet": "Падсетка «{{cidr}}» не ўтрымвае IP-адраса «{{ip}}»", "form_error_positive": "Павінна быць больш 0", @@ -67,7 +67,7 @@ "dhcp_table_hostname": "Імя хаста", "dhcp_table_expires": "Мінае", "dhcp_warning": "Калі вы ўсё адно хочаце ўключыць DHCP-сервер, пераканайцеся, што ў сеціве больш няма актыўных DHCP-сервераў. Інакш гэта можа зламаць доступ у сеціва для падлучаных прылад!", - "dhcp_error": "Мы не змаглі вызначыць наяўнасць іншых DHCP-сервераў у сеціве.", + "dhcp_error": "AdGuard Home не можа вызначыць, ці ёсць у сетцы іншы актыўны DHCP-сервер", "dhcp_static_ip_error": "Для таго, каб выкарыстоўваць DHCP-сервер, павінен быць усталяваны статычны IP-адрас. Мы не змаглі вызначыць, ці выкарыстоўвае гэты інтэрфейс сеціва статычны IP-адрас. Калі ласка, усталюйце яго ручна.", "dhcp_dynamic_ip_found": "Ваша сістэма выкарыстоўвае дынамічны IP-адрас для інтэрфейсу <0>{{interfaceName}}. Каб выкарыстоўваць DHCP-сервер трэба ўсталяваць статычны IP-адрас. Ваш бягучы IP-адрас – <0>{{ipAddress}}. Мы аўтаматычна ўсталюем яго як статычны, калі вы націснеце кнопку Ўключыць DHCP.", "dhcp_lease_added": "Статычная арэнда \"{{key}}\" паспяхова дададзена", @@ -165,10 +165,10 @@ "enabled_filtering_toast": "Фільтрацыя ўкл.", "disabled_safe_browsing_toast": "Бяспечная навігацыя выключана", "enabled_safe_browsing_toast": "Бяспечная навігацыя ўключана", - "disabled_parental_toast": "Бацькоўскі кантроль выкл.", - "enabled_parental_toast": "Бацькоўскі кантроль укл.", - "disabled_safe_search_toast": "Бяспечны пошук выкл.", - "enabled_save_search_toast": "Бяспечны пошук укл.", + "disabled_parental_toast": "Адключаны бацькоўскі кантроль", + "enabled_parental_toast": "Уключаны бацькоўскі кантроль", + "disabled_safe_search_toast": "Адключаны бяспечны пошук", + "enabled_save_search_toast": "Уключаны бяспечны пошук", "enabled_table_header": "УКЛ.", "name_table_header": "Імя", "list_url_table_header": "URL-адрас спіса", @@ -202,19 +202,21 @@ "custom_filter_rules_hint": "Уводзьце па адным правіле на радок. Вы можаце выкарыстоўваць правілы блакавання ці сінтаксіс файлаў hosts.", "system_host_files": "Сістэмныя hosts-файлы", "examples_title": "Прыклады", - "example_meaning_filter_block": "заблакаваць доступ да дамена example.org і ўсім яго паддаменам", - "example_meaning_filter_whitelist": "адблакаваць доступ да дамена example.org і ўсім яго паддаменам", - "example_meaning_host_block": "Зараз AdGuard Home верне 127.0.0.1 для дамена example.org (але не для яго паддаменаў).", - "example_comment": "! Так можна дадаваць апісанне", - "example_comment_meaning": "каментар", - "example_comment_hash": "# І вось так таксама", - "example_regex_meaning": "блакуе доступ да даменаў, што адпавядаюць <0>зададзенаму рэгулярнаму выразу", - "example_upstream_regular": "звычайны DNS (наўзверх UDP)", - "example_upstream_dot": "зашыфраваны DNS-па-над-TLS", - "example_upstream_doh": "зашыфраваны DNS-over-HTTPS", - "example_upstream_doq": "зашыфраваны <0>DNS-over-QUIC", - "example_upstream_sdns": "вы можаце выкарыстоўваць DNS Stamps для DNSCrypt ці DNS-over-HTTPS рэзалвераў", - "example_upstream_tcp": "звычайны DNS (наўзверх TCP)", + "example_meaning_filter_block": "заблакаваць доступ да example.org і ўсім яго паддаменам;", + "example_meaning_filter_whitelist": "адблакаваць доступ да example.org і ўсім яго паддаменам;", + "example_meaning_host_block": "адказаць 127.0.0.1 для example.org (але не для яго паддаменаў);", + "example_comment": "! Так можна дадаваць апісанне.", + "example_comment_meaning": "каментар;", + "example_comment_hash": "# І вось так таксама.", + "example_regex_meaning": "блакаваць доступ да даменаў, якія адпавядаюць зададзенаму рэгулярнаму выразу.", + "example_upstream_regular": "звычайны DNS (наўзверх UDP);", + "example_upstream_udp": "звычайны DNS (праз UDP, імя хаста);", + "example_upstream_dot": "зашыфраваны <0>DNS-over-TLS;", + "example_upstream_doh": "зашыфраваны <0>DNS-over-HTTPS;", + "example_upstream_doq": "зашыфраваны <0>DNS-over-QUIC (эксперыментальны);", + "example_upstream_sdns": "<0>DNS Stamps для <1>DNSCrypt ці <2>DNS-over-HTTPS рэзалвераў;", + "example_upstream_tcp": "звычайны DNS (наўзверх TCP);", + "example_upstream_tcp_hostname": "звычайны DNS (праз TCP, імя хаста);", "all_lists_up_to_date_toast": "Усе спісы ўжо абноўлены", "updated_upstream_dns_toast": "Upstream DNS-серверы абноўлены", "dns_test_ok_toast": "Паказаныя серверы DNS працуюць карэктна", @@ -259,7 +261,7 @@ "query_log_strict_search": "Ужывайце падвойныя двукоссі для строгага пошуку", "query_log_retention_confirm": "Вы ўпэўнены, што хочаце змяніць тэрмін захоўвання запытаў? Пры скарачэнні інтэрвалу дадзеныя могуць быць згублены", "anonymize_client_ip": "Ананімізацыя IP-адрасы кліента", - "anonymize_client_ip_desc": "Не захоўвайце поўны IP-адрас кліента ў часопісах і статыстыцы", + "anonymize_client_ip_desc": "Не захоўвайце поўныя IP-адрасы гэтых удзельнікаў у часопісах або статыстыцы", "dns_config": "Налады DNS-сервера", "dns_cache_config": "Налада кэша DNS", "dns_cache_config_desc": "Тут можна наладзіць кэш DNS", @@ -275,9 +277,9 @@ "dns_over_https": "DNS-over-HTTPS", "dns_over_tls": "DNS-over-TLS", "dns_over_quic": "DNS-over-QUIC", - "client_id": "Ідэнтыфікатар кліента", - "client_id_placeholder": "Увядзіце ідэнтыфікатар кліента", - "client_id_desc": "Розныя кліенты могуць ідэнтыфікавацца па адмысловым ідэнтыфікатары кліента. Тут вы можаце даведацца больш пра ідэнтыфікацыю кліентаў.", + "client_id": "ClientID", + "client_id_placeholder": "Увядзіце ClientID", + "client_id_desc": "Кліенты могуць ідэнтыфікавацца па ClientID. Тут вы можаце даведацца больш пра ідэнтыфікацыю кліентаў.", "download_mobileconfig_doh": "Спампаваць .mobileconfig для DNS-over-HTTPS", "download_mobileconfig_dot": "Спампаваць .mobileconfig для DNS-over-TLS", "download_mobileconfig": "Загрузіць файл канфігурацыі", @@ -285,7 +287,7 @@ "form_enter_rate_limit": "Увядзіце rate limit", "rate_limit": "Ограничение скорости", "edns_enable": "Уключыць адпраўленне EDNS Client Subnet", - "edns_cs_desc": "Калі ўключыць гэту опцыю, AdGuard Home будзе адпраўляць падсеціва кліентаў на DNS-сервера.", + "edns_cs_desc": "Дадайце опцыю кліенцкай падсеткі EDNS (ECS) да запытаў вышэй па плыні і запісвайце значэнні, адпраўленыя кліентамі, у журнал запытаў.", "rate_limit_desc": "Абмежаванне на колькасць запытаў у секунду для кожнага кліента (0 — неабмежавана)", "blocking_ipv4_desc": "IP-адрас, што вяртаецца пры блакаванню A-запыту", "blocking_ipv6_desc": "IP-адрас, што вяртаецца пры блакаванню AAAA-запыту", @@ -309,7 +311,7 @@ "install_settings_listen": "Інтэрфейс сеціва", "install_settings_port": "Порт", "install_settings_interface_link": "Ваш ўэб-інтэрфейс адміністравання AdGuard Home будзе даступны па наступных адрасах:", - "form_error_port": "Увядзіце карэктны порт", + "form_error_port": "Увядзіце карэктны нумар порта", "install_settings_dns": "DNS-сервер", "install_settings_dns_desc": "Вам будзе трэба наладзіць свае прылады ці роўтар на выкарыстанне DNS-сервера на адным з наступных адрасоў:", "install_settings_all_interfaces": "Усе інтэрфейсы", @@ -334,12 +336,12 @@ "install_devices_router_list_4": "Вы не можаце ўсталяваць уласны DNS-сервер на некаторых тыпах маршрутызатараў. У гэтым выпадку можа дапамагчы налада AdGuard Home у якасці DHCP-сервера. У адваротным выпадку вам трэба звярнуцца да кіраўніцтва па наладзе DNS-сервераў для вашай пэўнай мадэлі маршрутызатара.", "install_devices_windows_list_1": "Адкрыйце Панэль кіравання праз меню \"Пуск\" ці праз пошук Windows.", "install_devices_windows_list_2": "Перайдзіце ў \"Сеціва і інтэрнэт\", а потым у \"Цэнтр кіравання сеціва і агульным доступам\"", - "install_devices_windows_list_3": "У левым боку экрана знайдзіце \"Змена параметраў адаптара\" і клікніце па ім.", - "install_devices_windows_list_4": "Вылучыце ваша актыўнае падлучэнне, потым клікніце па ім правай клавішай мышы і выберыце \"Уласцівасці\".", + "install_devices_windows_list_3": "У левым боку экрана клікніце «Змена параметраў адаптара».", + "install_devices_windows_list_4": "Пстрыкніце правай кнопкай мышы ваша актыўнае злучэнне і абярыце Уласцівасці.", "install_devices_windows_list_5": "Знайдзіце ў спісе пункт \"IP версіі 4 (TCP/IPv4)\", вылучыце яго і потым ізноў націсніце \"Уласцівасці\".", "install_devices_windows_list_6": "Абярыце \"Выкарыстаць наступныя адрасы DNS-сервераў\" і ўвядзіце адрас AdGuard Home.", - "install_devices_macos_list_1": "Клікніце па абразку Apple і перайдзіце ў «Сістэмныя налады».", - "install_devices_macos_list_2": "Клікніце па іконцы «Сеціва».", + "install_devices_macos_list_1": "Клікніце па абразку Apple і перайдзіце ў Сістэмныя налады.", + "install_devices_macos_list_2": "Клікніце па іконцы Сеціва.", "install_devices_macos_list_3": "Абярыце першае падлучэнне ў спісе і націсніце кнопку «Дадаткова».", "install_devices_macos_list_4": "Абярыце ўкладку «DNS» і дадайце адрасы AdGuard Home.", "install_devices_android_list_1": "У меню кіравання націсніце абразок «Налады».", @@ -356,7 +358,7 @@ "open_dashboard": "Адкрыць Панэль кіравання", "install_saved": "Паспяхова захавана", "encryption_title": "Шыфраванне", - "encryption_desc": "Падтрымка шыфравання (HTTPS/TLS) для DNS і ўэб-інтэрфейсу адміністравання", + "encryption_desc": "Падтрымка шыфравання (HTTPS/QUIC/TLS) для DNS і ўэб-інтэрфейсу адміністравання", "encryption_config_saved": "Налады шыфравання захаваны", "encryption_server": "Імя сервера", "encryption_server_enter": "Увядзіце ваша даменавае імя", @@ -367,7 +369,7 @@ "encryption_https_desc": "Калі порт HTTPS наладжаны, ўэб-інтэрфейс адміністравання AdGuard Home будзе даступны праз HTTPS, а таксама DNS-over-HTTPS сервер будзе даступны па шляху '/dns-query'.", "encryption_dot": "Порт DNS-over-TLS", "encryption_dot_desc": "Калі гэты порт наладжаны, AdGuard Home запусціць DNS-over-TLS-сервер на гэтаму порту.", - "encryption_doq": "Порт DNS-over-QUIC", + "encryption_doq": "Порт DNS-over-QUIC (эксперыментальны)", "encryption_doq_desc": "Калі гэты порт наладжаны, AdGuard Home запусціць сервер DNS-over-QUIC на гэтым порце. Гэта эксперыментальна і можа быць ненадзейна. Апроч таго, не так шмат кліентаў падтрымвае гэты спосаб цяпер.", "encryption_certificates": "Сертыфікаты", "encryption_certificates_desc": "Для выкарыстання шыфравання вам трэба падаць валідны ланцужок SSL-сертыфікатаў для вашага дамена. Вы можаце атрымаць дармовы сертыфікат на <0>{{link}} ці вы можаце купіць яго ў аднаго з давераных Цэнтраў Сертыфікацыі.", @@ -388,8 +390,8 @@ "encryption_reset": "Вы ўпэўнены, што хочаце скінуць налады шыфравання?", "topline_expiring_certificate": "Ваш SSL-сертыфікат хутка мінае. Абновіце <0>Налады шыфравання.", "topline_expired_certificate": "Ваш SSL-сертыфікат мінуў. Абновіце <0>Налады шыфравання.", - "form_error_port_range": "Увядзіце значэнне порта з інтэрвалу 80-65535", - "form_error_port_unsafe": "Гэта небяспечны порт", + "form_error_port_range": "Увядзіце нумар порта з інтэрвалу 80-65535", + "form_error_port_unsafe": "Небяспечны порт", "form_error_equal": "Не павінны быць роўныя", "form_error_password": "Паролі не супадаюць", "reset_settings": "Скінуць налады", @@ -397,15 +399,16 @@ "setup_guide": "Інструкцыя па наладзе", "dns_addresses": "Адрасы DNS", "dns_start": "DNS-сервер запускаецца", - "dns_status_error": "Памылка пры атрыманні стану DNS-сервера", + "dns_status_error": "Памылка праверкі стану DNS-сервера", "down": "Уніз", "fix": "Выправіць", "dns_providers": "<0>Спіс вядомых DNS-правайдараў на выбар.", "update_now": "Абнавіць цяпер", "update_failed": "Памылка аўто-абнаўлення. Калі ласка, кіруйцеся інструкцыі для абнаўлення ручна.", + "manual_update": "Калі ласка, кіруйцеся інструкцыі для абнаўлення ручна.", "processing_update": "Калі ласка, пачакайце, AdGuard Home абнаўляецца", - "clients_title": "Кліенты", - "clients_desc": "Наладзьце прылады, што выкарыстоўваюць AdGuard Home", + "clients_title": "Пастаянныя кліенты", + "clients_desc": "Наладзьце пастаянныя запісы кліентаў для прылад, падлучаных да AdGuard Home", "settings_global": "Глабальныя", "settings_custom": "Свае", "table_client": "Кліент", @@ -416,7 +419,7 @@ "client_edit": "Рэдагаваць кліента", "client_identifier": "Ідэнтыфікатар", "ip_address": "IP-адрас", - "client_identifier_desc": "Кліенты могуць быць ідэнтыфікаваны па IP-адрасе, CIDR ці MAC-адрасу. Звярніце ўвагу, што выкарыстанне MAC як ідэнтыфікатара магчыма, толькі калі AdGuard Home таксама з'яўляецца і <0>DHCP-серверам", + "client_identifier_desc": "Кліентаў можна ідэнтыфікаваць па іх IP-адрасе, CIDR, MAC-адрасе або ClientID (можна выкарыстоўваць для DoT/DoH/DoQ). Даведайцеся больш пра тое, як ідэнтыфікаваць кліентаў <0>тут.", "form_enter_ip": "Увядзіце IP", "form_enter_subnet_ip": "Увядзіце IP-адрас у падсеткі «{{cidr}}»", "form_enter_mac": "Увядзіце MAC", @@ -432,13 +435,13 @@ "client_confirm_delete": "Вы ўпэўнены, што хочаце выдаліць кліента \"{{key}}\"?", "list_confirm_delete": "Вы ўпэўнены, што хочаце выдаліць гэты спіс?", "auto_clients_title": "Кліенты (runtime)", - "auto_clients_desc": "Дадзеныя пра кліентаў, якія скарыстаюць AdGuard Home, але не захоўваюцца ў наладах", + "auto_clients_desc": "Прылады, якіх няма ў спісе пастаянных кліентаў, якія ўсё яшчэ могуць выкарыстоўваць AdGuard Home", "access_title": "Налады доступу", - "access_desc": "Тут вы можаце наладзіць правілы доступу да DNS-серверу AdGuard Home.", + "access_desc": "Тут вы можаце наладзіць правілы доступу да DNS-серверу AdGuard Home", "access_allowed_title": "Дазволеныя кліенты", - "access_allowed_desc": "Спіс CIDR- ці IP-адрасоў. Калі ён наладжаны, AdGuard Home будзе прымаць запыты толькі з гэтых IP-адрасоў.", + "access_allowed_desc": "Спіс CIDR, IP-адрасоў або ClientID. Калі ў гэтым спісе ёсць запісы, AdGuard Home будзе прымаць запыты толькі ад гэтых кліентаў.", "access_disallowed_title": "Забароненыя кліенты", - "access_disallowed_desc": "Спіс CIDR- ці IP-адрасоў. Калі ён наладжаны, AdGuard Home будзе ігнараваць запыты з гэтых IP-адрасоў.", + "access_disallowed_desc": "Спіс CIDR, IP-адрасоў або ClientID. Калі ў гэтым спісе ёсць запісы, AdGuard Home выдаліць запыты ад гэтых кліентаў. Гэта поле ігнаруецца, калі ёсць запісы ў Дазволеныя кліенты.", "access_blocked_title": "Заблакаваныя дамены", "access_blocked_desc": "Не блытайце гэта з фільтрамі. AdGuard Home будзе ігнараваць DNS-запыты з гэтымі даменамі.", "access_settings_saved": "Налады доступу паспяхова захаваны", @@ -499,6 +502,7 @@ "interval_days": "{{count}} дзень", "interval_days_plural": "{{count}} дзён", "domain": "Дамен", + "ecs": "ECS", "punycode": "Punycode", "answer": "Адказ", "filter_added_successfully": "Спіс паспяхова дададзены", @@ -531,7 +535,7 @@ "netname": "Назва сеціва", "network": "Сеціва", "descr": "Апісанне", - "whois": "Хто", + "whois": "WHOIS", "filtering_rules_learn_more": "<0>Даведайцеся больш пра стварэнне ўласных спісаў блакавання хастоў.", "blocked_by_response": "Заблакавана па CNAME ці IP у адказе", "blocked_by_cname_or_ip": "Заблакавана з дапамогай CNAME ці IP", @@ -551,7 +555,7 @@ "autofix_warning_list": "Будуць выконвацца наступныя заданні: <0>Дэактываваць сістэмны DNSStubListener <0>Усталяваць адрас сервера DNS на 127.0.0.1 <0>Стварыць сімвалічную спасылку /etc/resolv.conf на /run/systemd/resolve/resolv.conf <0>Спыніць DNSStubListener (перазагрузіць сістэмную службу).", "autofix_warning_result": "У выніку ўсе DNS-запыты ад вашай сістэмы будуць па змаўчанні апрацоўвацца AdGuard Home.\n", "tags_title": "Тэгі", - "tags_desc": "Вы можаце выбраць тэгі, якія адпавядаюць кліенту. Тэгі могуць быць улучаны ў правілы фільтрацыі і дазволяць вам ужываць іх больш дакладна. <0>Даведацца больш.", + "tags_desc": "Вы можаце выбраць тэгі, якія адпавядаюць кліенту. Уключыце тэгі ў правілы фільтрацыі, каб прымяняць іх больш дакладна. <0>Даведацца больш.", "form_select_tags": "Выбраць тэгі кліента", "check_title": "Праверыць фільтрацыю", "check_desc": "Праверыць фільтрацыю імя хаста", @@ -593,18 +597,18 @@ "allowed": "Дазволены", "filtered": "Адфільтраваныя", "rewritten": "Перапісаныя", - "safe_search": "Уключыць Бяспечны пошук", + "safe_search": "Бяспечны пошук", "blocklist": "Чорны спіс", "milliseconds_abbreviation": "мс", "cache_size": "Памер кэша", - "cache_size_desc": "Памер кэша DNS (у байтах)", + "cache_size_desc": "Памер кэша DNS (у байтах).", "cache_ttl_min_override": "Перавызначыць мінімальны TTL", "cache_ttl_max_override": "Перавызначыць максімальны TTL", "enter_cache_size": "Увядзіце памер кэша (байты)", "enter_cache_ttl_min_override": "Увядзіце мінімальны TTL (секунды)", "enter_cache_ttl_max_override": "Увядзіце максімальны TTL (секунды)", - "cache_ttl_min_override_desc": "Перавызначыць TTL-значэнне (мінімальнае), атрыманае з upstream-сервера", - "cache_ttl_max_override_desc": "Усталюйце максімальнае TTL-значэнне (секунды) для запісаў у кэшы DNS", + "cache_ttl_min_override_desc": "Пашырыць кароткія значэнні часу жыцця (секунды), атрыманыя ад сервера вышэй па плыні пры кэшаванні адказаў DNS.", + "cache_ttl_max_override_desc": "Усталюйце максімальнае TTL-значэнне (секунды) для запісаў у кэшы DNS.", "ttl_cache_validation": "Мінімальнае значэнне TTL кэша павінна быць менш ці роўна максімальнаму значэнню", "cache_optimistic": "Аптымістычнае кэшаванне", "cache_optimistic_desc": "Прымусьце AdGuard Home адказваць з кэша, нават калі тэрмін дзеяння запісаў скончыўся, а таксама паспрабуйце абнавіць іх.", @@ -626,5 +630,6 @@ "use_saved_key": "Скарыстаць захаваны раней ключ", "parental_control": "Бацькоўскі кантроль", "safe_browsing": "Бяспечны інтэрнэт", - "served_from_cache": "{{value}} (атрымана з кэша)" + "served_from_cache": "{{value}} (атрымана з кэша)", + "form_error_password_length": "Пароль павінен быць не менш за {{value}} сімвалаў" } diff --git a/client/src/__locales/cs.json b/client/src/__locales/cs.json index 8d89f204..26759394 100644 --- a/client/src/__locales/cs.json +++ b/client/src/__locales/cs.json @@ -35,24 +35,24 @@ "dhcp_config_saved": "Konfigurace DHCP byla úspěšně uložena", "dhcp_ipv4_settings": "Nastavení DHCP IPv4", "dhcp_ipv6_settings": "Nastavení DHCP IPv6", - "form_error_required": "Povinné pole.", - "form_error_ip4_format": "Neplatná adresa IPv4.", - "form_error_ip4_range_start_format": "Neplatná adresa IPv4 na začátku rozsahu.", - "form_error_ip4_range_end_format": "Neplatná adresa IPv4 na konci rozsahu.", - "form_error_ip4_gateway_format": "Neplatná adresa IPv4 brány.", - "form_error_ip6_format": "Neplatná adresa IPv6.", - "form_error_ip_format": "Neplatná IP adresa.", - "form_error_mac_format": "Neplatná adresa MAC.", - "form_error_client_id_format": "ID klienta musí obsahovat pouze čísla, malá písmena a spojovníky.", - "form_error_server_name": "Neplatný název serveru.", - "form_error_subnet": "Podsíť \"{{cidr}}\" neobsahuje IP adresu \"{{ip}}\".", - "form_error_positive": "Musí být větší než 0.", - "out_of_range_error": "Musí být mimo rozsah \"{{start}}\"-\"{{end}}\".", - "lower_range_start_error": "Musí být menší než začátek rozsahu.", - "greater_range_start_error": "Musí být větší než začátek rozsahu.", - "greater_range_end_error": "Musí být větší než konec rozsahu.", - "subnet_error": "Adresy musí být v jedné podsíti.", - "gateway_or_subnet_invalid": "Neplatná maska podsítě.", + "form_error_required": "Povinné pole", + "form_error_ip4_format": "Neplatná adresa IPv4", + "form_error_ip4_range_start_format": "Neplatná adresa IPv4 na začátku rozsahu", + "form_error_ip4_range_end_format": "Neplatná adresa IPv4 na konci rozsahu", + "form_error_ip4_gateway_format": "Neplatná adresa IPv4 brány", + "form_error_ip6_format": "Neplatná adresa IPv6", + "form_error_ip_format": "Neplatná IP adresa", + "form_error_mac_format": "Neplatná adresa MAC", + "form_error_client_id_format": "ID klienta musí obsahovat pouze čísla, malá písmena a spojovníky", + "form_error_server_name": "Neplatný název serveru", + "form_error_subnet": "Podsíť \"{{cidr}}\" neobsahuje IP adresu \"{{ip}}\"", + "form_error_positive": "Musí být větší než 0", + "out_of_range_error": "Musí být mimo rozsah \"{{start}}\"-\"{{end}}\"", + "lower_range_start_error": "Musí být menší než začátek rozsahu", + "greater_range_start_error": "Musí být větší než začátek rozsahu", + "greater_range_end_error": "Musí být větší než konec rozsahu", + "subnet_error": "Adresy musí být v jedné podsíti", + "gateway_or_subnet_invalid": "Neplatná maska podsítě", "dhcp_form_gateway_input": "IP brána", "dhcp_form_subnet_input": "Maska podsítě", "dhcp_form_range_title": "Rozsah IP adres", @@ -67,7 +67,7 @@ "dhcp_table_hostname": "Název hostitele", "dhcp_table_expires": "Vyprší", "dhcp_warning": "Pokud přesto chcete server DHCP povolit, ujistěte se, že ve Vaší síti není žádný jiný aktivní server DHCP, protože by to mohlo narušit připojení k Internetu pro zařízení v síti!", - "dhcp_error": "AdGuard Home nemohl určit, zda je v síti jiný aktivní server DHCP.", + "dhcp_error": "AdGuard Home nemohl určit, zda je v síti jiný aktivní server DHCP", "dhcp_static_ip_error": "Pro použití serveru DHCP musí být nastavena statická IP adresa. AdGuard Home nemohl zjistit, zda je toto síťové rozhraní nakonfigurováno pomocí statické adresy IP. Nastavte prosím statickou IP adresu ručně.", "dhcp_dynamic_ip_found": "Váš systém používá konfiguraci dynamické IP adresy pro rozhraní <0>{{interfaceName}}. Pro použití serveru DHCP musí být nastavena statická IP adresa. Vaše aktuální IP adresa je <0>{{ipAddress}}. AdGuard Home automaticky nastaví tuto IP adresu jako statickou, pokud stisknete tlačítko \"Zapnout DHCP server\".", "dhcp_lease_added": "Statický pronájem \"{{key}}\" byl úspěšně přidán", @@ -196,8 +196,8 @@ "choose_allowlist": "Vyberte seznamy povolených", "enter_valid_blocklist": "Zadejte platnou adresu URL na seznam blokovaných.", "enter_valid_allowlist": "Zadejte platnou adresu URL na seznam povolených.", - "form_error_url_format": "Neplatný formát URL.", - "form_error_url_or_path_format": "Neplatná URL nebo úplná cesta k seznamu.", + "form_error_url_format": "Neplatný formát URL", + "form_error_url_or_path_format": "Neplatná URL nebo úplná cesta k seznamu", "custom_filter_rules": "Vlastní pravidla filtrování", "custom_filter_rules_hint": "Na každý řádek vložte jedno pravidlo. Můžete použít buď pravidla blokování reklam nebo syntaxe hostitelských souborů.", "system_host_files": "Systémové soubory hostitelů", @@ -210,11 +210,13 @@ "example_comment_hash": "# Také komentář.", "example_regex_meaning": "blokuje přístup doménám, které vyhovují regulárnímu výrazu.", "example_upstream_regular": "obvyklý DNS (přes UDP);", + "example_upstream_udp": "obvyklý DNS (skrze UDP, název hostitele);", "example_upstream_dot": "šifrovaný <0>DNS skrze TLS;", "example_upstream_doh": "šifrovaný <0>DNS skrze HTTPS;", "example_upstream_doq": "šifrovaný <0>DNS skrze QUIC (experimentální);", "example_upstream_sdns": "<0>DNS razítka pro <1>DNSCrypt nebo <2>DNS skrze HTTPS řešitele;", "example_upstream_tcp": "obvyklý DNS (přes TCP);", + "example_upstream_tcp_hostname": "obvyklý DNS (skrze TCP, název hostitele);", "all_lists_up_to_date_toast": "Všechny seznamy jsou již aktuální", "updated_upstream_dns_toast": "Odchozí servery byly úspěšně uloženy", "dns_test_ok_toast": "Specifikované DNS servery pracují správně", @@ -259,10 +261,10 @@ "query_log_strict_search": "Pro striktní vyhledávání použijte dvojité uvozovky", "query_log_retention_confirm": "Opravdu chcete změnit uchovávání protokolu dotazů? Pokud snížíte hodnotu intervalu, některá data budou ztracena", "anonymize_client_ip": "Anonymizovat IP klienta", - "anonymize_client_ip_desc": "Neukládat úplnou IP adresu klienta do protokolů a statistik.", + "anonymize_client_ip_desc": "Neukládat úplnou IP adresu klienta do protokolů a statistik", "dns_config": "Konfigurace DNS serveru", "dns_cache_config": "Konfigurace mezipaměti DNS", - "dns_cache_config_desc": "Zde můžete konfigurovat mezipaměť DNS.", + "dns_cache_config_desc": "Zde můžete konfigurovat mezipaměť DNS", "blocking_mode": "Režim blokování", "default": "Výchozí", "nxdomain": "NXDOMAIN", @@ -285,7 +287,7 @@ "form_enter_rate_limit": "Zadejte rychlostní limit", "rate_limit": "Rychlostní limit", "edns_enable": "Povolit klientskou podsíť EDNS", - "edns_cs_desc": "Odeslat podsítě klientů na servery DNS.", + "edns_cs_desc": "Přidá možnost podsítě klienta EDNS (ECS) do odchozích požadavků a zaznamá hodnoty odeslané klienty do protokolu dotazů.", "rate_limit_desc": "Počet požadavků za sekundu, které smí jeden klient provádět (0: neomezeno)", "blocking_ipv4_desc": "IP adresa, která se má vrátit v případě blokovaného požadavku typu A", "blocking_ipv6_desc": "IP adresa, která se má vrátit v případě blokovaného požadavku typu AAAA", @@ -309,7 +311,7 @@ "install_settings_listen": "Síťové rozhraní", "install_settings_port": "Port", "install_settings_interface_link": "Vaše administrátorské webové rozhraní AdGuard Home bude k dispozici na těchto adresách:", - "form_error_port": "Zadejte platné číslo portu.", + "form_error_port": "Zadejte platné číslo portu", "install_settings_dns": "DNS server", "install_settings_dns_desc": "Budete muset nakonfigurovat Vaše zařízení nebo router, aby používali DNS server na následujících adresách:", "install_settings_all_interfaces": "Všechna rozhraní", @@ -356,7 +358,7 @@ "open_dashboard": "Otevřít hlavní panel", "install_saved": "Úspěšně uloženo", "encryption_title": "Šifrování", - "encryption_desc": "Podpora šifrování (HTTPS/TLS) pro webové rozhraní DNS i administrátora.", + "encryption_desc": "Podpora šifrování (HTTPS/TLS) pro webové rozhraní DNS i administrátora", "encryption_config_saved": "Konfigurace šifrování byla uložena", "encryption_server": "Název serveru", "encryption_server_enter": "Zadejte název domény", @@ -378,26 +380,26 @@ "encryption_key_input": "Zde můžete nakopírovat/vložit soukromý klíč k certifikátu PEM.", "encryption_enable": "Povolit šifrování (HTTPS, DNS skrze HTTPS a DNS skrze TLS)", "encryption_enable_desc": "Pokud je šifrování zapnuto, administrátorské rozhraní AdGuard Home bude pracovat skrze HTTPS a DNS server bude naslouchat požadavky přes DNS skrze HTTPS a DNS skrze TLS.", - "encryption_chain_valid": "Certifikační řetězec je platný.", - "encryption_chain_invalid": "Certifikační řetězec je neplatný.", - "encryption_key_valid": "Toto je platný {{type}} osobní klíč.", - "encryption_key_invalid": "Toto je neplatný {{type}} osobní klíč.", + "encryption_chain_valid": "Certifikační řetězec je platný", + "encryption_chain_invalid": "Certifikační řetězec je neplatný", + "encryption_key_valid": "Toto je platný {{type}} osobní klíč", + "encryption_key_invalid": "Toto je neplatný {{type}} osobní klíč", "encryption_subject": "Subjekt", "encryption_issuer": "Vydavatel", "encryption_hostnames": "Názvy hostitelů", "encryption_reset": "Opravdu chcete obnovit nastavení šifrování?", "topline_expiring_certificate": "Váš SSL certifikát brzy vyprší. Aktualizujte <0>Nastavení šifrování.", "topline_expired_certificate": "Váš SSL certifikát vypršel. Aktualizujte <0>Nastavení šifrování.", - "form_error_port_range": "Zadejte číslo portu v rozmezí 80-65535.", - "form_error_port_unsafe": "Toto není bezpečný port.", - "form_error_equal": "Nesmí se shodovat.", - "form_error_password": "Heslo se neshoduje.", + "form_error_port_range": "Zadejte číslo portu v rozmezí 80-65535", + "form_error_port_unsafe": "Nezabezpečený port", + "form_error_equal": "Nesmí se shodovat", + "form_error_password": "Heslo se neshoduje", "reset_settings": "Resetovat nastavení", "update_announcement": "AdGuard Home {{version}} je nyní k dispozici! <0>Klikněte zde<0> pro více informací.", "setup_guide": "Průvodce nastavením", "dns_addresses": "Adresy DNS", "dns_start": "Spouští se DNS server", - "dns_status_error": "Chyba při kontrole stavu DNS serveru.", + "dns_status_error": "Chyba při kontrole stavu DNS serveru", "down": "Dolů", "fix": "Opravit", "dns_providers": "Zde je <0>seznam známých poskytovatelů DNS, z nichž si můžete vybrat.", @@ -406,7 +408,7 @@ "manual_update": "Prosím následujte tyto kroky a aktualizujte ručně.", "processing_update": "Čekejte prosím, AdGuard Home se aktualizuje", "clients_title": "Stálí klienti", - "clients_desc": "Konfigurace stálých klientských záznamů pro zařízení připojená k AdGuard Home.", + "clients_desc": "Konfigurace stálých klientských záznamů pro zařízení připojená k AdGuard Home", "settings_global": "Globální", "settings_custom": "Vlastní", "table_client": "Klient", @@ -433,9 +435,9 @@ "client_confirm_delete": "Opravdu chcete odstranit klienta \"{{key}}\"?", "list_confirm_delete": "Opravdu chcete smazat tento seznam?", "auto_clients_title": "Spuštění klienti", - "auto_clients_desc": "Zařízení, která nejsou na seznamu stálých klientů, a mohou nadále používat AdGuard Home.", + "auto_clients_desc": "Zařízení, která nejsou na seznamu stálých klientů, a mohou nadále používat AdGuard Home", "access_title": "Nastavení přístupu", - "access_desc": "Zde můžete konfigurovat pravidla přístupu pro server DNS AdGuard Home.", + "access_desc": "Zde můžete konfigurovat pravidla přístupu pro server DNS AdGuard Home", "access_allowed_title": "Povolení klienti", "access_allowed_desc": "Seznam CIDR, IP adres nebo ID klientů. Pokud tento seznam obsahuje položky, AdGuard Home bude přijímat požadavky pouze od těchto klientů.", "access_disallowed_title": "Blokovaní klienti", @@ -475,8 +477,8 @@ "dns_rewrites": "Přesměrování DNS", "form_domain": "Zadejte doménu", "form_answer": "Zadejte IP adresu nebo název domény", - "form_error_domain_format": "Neplatný formát domény.", - "form_error_answer_format": "Neplatný formát odpovědi.", + "form_error_domain_format": "Neplatný formát domény", + "form_error_answer_format": "Neplatný formát odpovědi", "configure": "Konfigurovat", "main_settings": "Hlavní nastavení", "block_services": "Blokovat specifické služby", @@ -500,6 +502,7 @@ "interval_days": "Dny: {{count}}", "interval_days_plural": "Dny: {{count}}", "domain": "Doména", + "ecs": "ECS", "punycode": "Punycode", "answer": "Odpověď", "filter_added_successfully": "Seznam byl úspěšně přidán", @@ -507,7 +510,7 @@ "filter_updated": "Seznam byl úspěšně aktualizován", "statistics_configuration": "Konfigurace statistik", "statistics_retention": "Uchovávání statistik", - "statistics_retention_desc": "Pokud hodnotu intervalu snížíte, některá data budou ztracena.", + "statistics_retention_desc": "Pokud hodnotu intervalu snížíte, některá data budou ztracena", "statistics_clear": " Vyčistit statistiky", "statistics_clear_confirm": "Opravdu chcete vyčistit statistiky?", "statistics_retention_confirm": "Opravdu chcete změnit uchovávání statistik? Pokud snížíte hodnotu intervalu, některá data budou ztracena", @@ -606,7 +609,7 @@ "enter_cache_ttl_max_override": "Zadejte maximální hodnotu TTL (v sekundách)", "cache_ttl_min_override_desc": "Prodlužte nejkratší hodnotu TTL (v sekundách) obdrženou z odchozího serveru při ukládání DNS odpovědí do mezipaměti.", "cache_ttl_max_override_desc": "Nastavte maximální hodnotu TTL (v sekundách) pro položky v mezipaměti DNS.", - "ttl_cache_validation": "Minimální přepis TTL mezipaměti musí být menší nebo roven maximální hodnotě.", + "ttl_cache_validation": "Minimální přepis TTL mezipaměti musí být menší nebo roven maximální hodnotě", "cache_optimistic": "Optimistické ukládání do mezipaměti", "cache_optimistic_desc": "Nechte AdGuard Home odpovědět z mezipaměti, i když už platnost položek skončila. Také se je pokuste obnovit.", "filter_category_general": "Obecné", @@ -628,5 +631,5 @@ "parental_control": "Rodičovská ochrana", "safe_browsing": "Bezpečné prohlížení", "served_from_cache": "{{value}} (převzato z mezipaměti)", - "form_error_password_length": "Heslo musí být alespoň {{value}} znaků dlouhé." + "form_error_password_length": "Heslo musí být alespoň {{value}} znaků dlouhé" } diff --git a/client/src/__locales/da.json b/client/src/__locales/da.json index fb67607d..1b12ad06 100644 --- a/client/src/__locales/da.json +++ b/client/src/__locales/da.json @@ -37,21 +37,21 @@ "dhcp_ipv6_settings": "DHCP IPv6-indstillinger", "form_error_required": "Obligatorisk felt", "form_error_ip4_format": "Ugyldig IPv4-adresse", - "form_error_ip4_range_start_format": "Ugyldig IPv4-startadresse for området.", - "form_error_ip4_range_end_format": "Ugyldig IPv4-slutadresse for området.", - "form_error_ip4_gateway_format": "Ugyldig IPv4 gateway-adresse.", - "form_error_ip6_format": "Ugyldig IPv6-adresse.", - "form_error_ip_format": "Ugyldig IP-adresse.", - "form_error_mac_format": "Ugyldig MAC-adresse.", - "form_error_client_id_format": "KlientID må kun indeholde cifre, minuskler og bindestreger.", - "form_error_server_name": "Ugyldigt servernavn.", - "form_error_subnet": "Undernet \"{{cidr}}\" indeholder ikke IP-adressen \"{{ip}}\".", - "form_error_positive": "Skal være større end 0.", - "out_of_range_error": "Skal være uden for området \"{{start}}\"-\"{{end}}\".", - "lower_range_start_error": "Skal være mindre end starten på området.", - "greater_range_start_error": "Skal være større end starten på ​​området.", - "greater_range_end_error": "Skal være større end områdeslutning.", - "subnet_error": "Adresser ska være i ét undernet.", + "form_error_ip4_range_start_format": "Ugyldig IPv4-startadresse for området", + "form_error_ip4_range_end_format": "Ugyldig IPv4-slutadresse for området", + "form_error_ip4_gateway_format": "Ugyldig IPv4 gateway-adresse", + "form_error_ip6_format": "Ugyldig IPv6-adresse", + "form_error_ip_format": "Ugyldig IP-adresse", + "form_error_mac_format": "Ugyldig MAC-adresse", + "form_error_client_id_format": "KlientID må kun indeholde cifre, minuskler og bindestreger", + "form_error_server_name": "Ugyldigt servernavn", + "form_error_subnet": "Undernet \"{{cidr}}\" indeholder ikke IP-adressen \"{{ip}}\"", + "form_error_positive": "Skal være større end 0", + "out_of_range_error": "Skal være uden for området \"{{start}}\"-\"{{end}}\"", + "lower_range_start_error": "Skal være mindre end starten på området", + "greater_range_start_error": "Skal være større end starten på ​​området", + "greater_range_end_error": "Skal være større end områdeslutning", + "subnet_error": "Adresser ska være i ét undernet", "gateway_or_subnet_invalid": "Undernetmaske ugyldig", "dhcp_form_gateway_input": "Gateway IP", "dhcp_form_subnet_input": "Undernetmaske", @@ -67,7 +67,7 @@ "dhcp_table_hostname": "Værtsnavn", "dhcp_table_expires": "Udløber", "dhcp_warning": "Vil du alligevel aktivere DHCP-serveren, så sørg for at der ikke er nogen anden aktiv DHCP-server på dit netværk, da dette kan ødelægge Internetkonnektiviteten for netværksenhederne!", - "dhcp_error": "AdGuard Home kunne ikke afgøres, om der findes en anden DHCP-server på netværket.", + "dhcp_error": "AdGuard Home kunne ikke afgøres, om der findes en anden DHCP-server på netværket", "dhcp_static_ip_error": "For at kunne bruge DHCP-serveren skal der opsættes en statisk IP-adresse. Da det ikke kunne afgøres, om denne netværksinterface er opsat vha. en statisk IP-adresse, bedes du opsætte en manuelt.", "dhcp_dynamic_ip_found": "Dit system bruger en dynamisk IP-adresseopsætning til interface <0>{{interfaceName}}. For at kunne bruge DHCP-serveren skal en statisk IP-adresse indstilles. Din aktuelle IP-adresse er <0>{{ipAddress}}. AdGuard Home vil automatisk indstille denne IP-adresse som din statiske hvis du trykker på knappen \"Aktivér DHCP-server\".", "dhcp_lease_added": "Statisk lease \"{{key}}\" tilføjet", @@ -210,11 +210,13 @@ "example_comment_hash": "# Også en kommentar.", "example_regex_meaning": "blokér adgang til domæner matchernde det angivne regulære udtryk", "example_upstream_regular": "almindelig DNS (over UDP)", + "example_upstream_udp": "almindelig DNS (over UDP, værtsnavn);", "example_upstream_dot": "krypteret <0>DNS-over-TLS", "example_upstream_doh": "krypteret <0>DNS-over-HTTPS", "example_upstream_doq": "krypteret <0>DNS-over-QUIC(eksperimentel);", "example_upstream_sdns": "<0>DNS Stamps til <1>DNSCrypt eller <2>DNS-over-HTTPS-opløsere;", "example_upstream_tcp": "almindelig DNS (over TCP)", + "example_upstream_tcp_hostname": "almindelig DNS (over TCP, værtsnavn);", "all_lists_up_to_date_toast": "Alle lister er allerede opdaterede", "updated_upstream_dns_toast": "Upstream-servere er gemt", "dns_test_ok_toast": "Angivne DNS-servere fungerer korrekt", @@ -259,7 +261,7 @@ "query_log_strict_search": "Brug dobbelt anførselstegn til stringent søgning", "query_log_retention_confirm": "Sikker på, at du vil ændre forespørgselsloggens opbevaringperiode? Mindskes intervalværdien, mistes data", "anonymize_client_ip": "Anonymisér klient-IP", - "anonymize_client_ip_desc": "Gem ikke klientens fulde IP-adresse i logfiler og statistikker", + "anonymize_client_ip_desc": "Gem ikke fuld klient IP-adresse i logfiler eller statistikker", "dns_config": "DNS-serveropsætning", "dns_cache_config": "DNS-cacheopsætning", "dns_cache_config_desc": "Hér kan DNS-cache opsættes.", @@ -285,7 +287,7 @@ "form_enter_rate_limit": "Angiv hyppighedsgrænse", "rate_limit": "Hyppighedsgrænse", "edns_enable": "Aktivér EDNS-klientundernet", - "edns_cs_desc": "Send klienters undernet til DNS-serverne.", + "edns_cs_desc": "Tilføj indstillingen EDNS Client Subnet (ECS) til upstream-forespørgsler og log de af klienterne sendte værdier i forespørgselsloggen.", "rate_limit_desc": "Antallet af forespørgsler pr. sekund tilladt pr. klient (værdien 0 = ubegrænset)", "blocking_ipv4_desc": "Returneret IP-adresse for en blokeret A-forespørgsel", "blocking_ipv6_desc": "Returneret IP-adresse for en blokeret AAAA-forespørgsel", @@ -309,7 +311,7 @@ "install_settings_listen": "Overvågningsgrænseflade", "install_settings_port": "Port", "install_settings_interface_link": "Din AdGuard Home admin webgrænseflade vil være tilgængelig på flg. adresser:", - "form_error_port": "Angiv gyldig portnummer", + "form_error_port": "Angiv gyldigt portnummer", "install_settings_dns": "DNS-server", "install_settings_dns_desc": "Du skal opsætte dine enheder eller router til at bruge DNS-serveren på flg. adresser:", "install_settings_all_interfaces": "Alle grænseflader", @@ -356,7 +358,7 @@ "open_dashboard": "Åbn Dashboard", "install_saved": "Gemt", "encryption_title": "Kryptering", - "encryption_desc": "Krypteringsunderstøttelse (HTTPS/TLS) til både DNS og admin-webgrænseflade.", + "encryption_desc": "Krypteringsunderstøttelse (HTTPS/TLS) til både DNS og admin-webgrænseflade", "encryption_config_saved": "Krypteringsopsætning gemt", "encryption_server": "Servernavn", "encryption_server_enter": "Angiv dit domænenavn", @@ -389,7 +391,7 @@ "topline_expiring_certificate": "Dit SSL-certifikat er ved at udløbe. Opdatér <0>Krypteringsindstillinger.", "topline_expired_certificate": "Dit SSL-certifikat er udløbet. Opdatér <0>Krypteringsindstillinger.", "form_error_port_range": "Angiv portnummer i intervallet 80-65535", - "form_error_port_unsafe": "Dette er en usikker port", + "form_error_port_unsafe": "Ikke-sikker port", "form_error_equal": "Må ikke svare til.", "form_error_password": "Adgangskoder matcher ikke.", "reset_settings": "Nulstil indstillinger", @@ -406,7 +408,7 @@ "manual_update": "Følg disse trin for at opdatere manuelt.", "processing_update": "Vent venligst, AdGuard Home bliver opdateret", "clients_title": "Blivende klienter", - "clients_desc": "Opsæt blivende klientposter for enheder tilsluttet AdGuard Home.", + "clients_desc": "Opsæt permanente klientposter for enheder tilsluttet AdGuard Home", "settings_global": "Global", "settings_custom": "Tilpasset", "table_client": "Klient", @@ -433,9 +435,9 @@ "client_confirm_delete": "Sikker på, at du vil slette klient \"{{key}}\"?", "list_confirm_delete": "Sikker på, at du vil slette denne liste?", "auto_clients_title": "Klienter (runtime)", - "auto_clients_desc": "Enheder, som ikke er på listen over Blivende klienter, som stadig kan bruge AdGuard Home.", + "auto_clients_desc": "Enheder, som ikke er på listen over Permanente klienter, kan stadig bruge AdGuard Home", "access_title": "Adgangsindstillinger", - "access_desc": "Her kan du opsætte adgangsregler for AdGuard Home DNS-serveren.", + "access_desc": "Her kan adgangsregler for AdGuard Home DNS-serveren opsættes", "access_allowed_title": "Tilladte klienter", "access_allowed_desc": "En liste over CIDR'er, IP-adresser eller KlientID'er. Har listen poster, accepterer AdGuard Home kun forespørgsler fra disse klienter.", "access_disallowed_title": "Ikke tilladte klienter", @@ -500,6 +502,7 @@ "interval_days": "{{count}} dag", "interval_days_plural": "{{count}} dage", "domain": "Domæne", + "ecs": "ECS", "punycode": "Punycode", "answer": "Svar", "filter_added_successfully": "Listen er tilføjet", @@ -517,7 +520,7 @@ "interval_hours_plural": "{{count}} timer", "filters_configuration": "Filteropsætninger", "filters_enable": "Aktivér filtre", - "filters_interval": "Filtrenes opdateringsinterval", + "filters_interval": "Filteropdateringsinterval", "disabled": "Deaktiveret", "username_label": "Brugernavn", "username_placeholder": "Angiv brugernavn", diff --git a/client/src/__locales/de.json b/client/src/__locales/de.json index fc9f5878..6f8ff803 100644 --- a/client/src/__locales/de.json +++ b/client/src/__locales/de.json @@ -35,24 +35,24 @@ "dhcp_config_saved": "DHCP-Konfiguration erfolgreich gespeichert", "dhcp_ipv4_settings": "DHCP-IPv4-Einstellungen", "dhcp_ipv6_settings": "DHCP-IPv6-Einstellungen", - "form_error_required": "Pflichtfeld.", - "form_error_ip4_format": "Ungültige IPv4-Adresse.", - "form_error_ip4_range_start_format": "Ungültige IPv4-Adresse des Bereichsbeginns.", - "form_error_ip4_range_end_format": "Ungültige IPv4-Adresse des Bereichsendes.", - "form_error_ip4_gateway_format": "Ungültige IPv4-Adresse des Gateways.", - "form_error_ip6_format": "Ungültige IPv6-Adresse.", - "form_error_ip_format": "Ungültige IP-Adresse.", - "form_error_mac_format": "Ungültige MAC-Adresse.", - "form_error_client_id_format": "Client-ID muss nur Zahlen, Kleinbuchstaben und Bindestriche enthalten.", - "form_error_server_name": "Ungültiger Servername.", - "form_error_subnet": "Subnetz „{{cidr}}“ enthält nicht die IP-Adresse „{{ip}}“.", - "form_error_positive": "Muss größer als 0 sein.", - "out_of_range_error": "Muss außerhalb des Bereichs „{{start}}“-„{{end}}“ liegen.", - "lower_range_start_error": "Muss niedriger als der Bereichsbeginn sein.", - "greater_range_start_error": "Muss größer als der Bereichsbeginn sein.", - "greater_range_end_error": "Muss größer als das Bereichsende sein.", - "subnet_error": "Die Adressen müssen innerhalb eines Subnetzes liegen.", - "gateway_or_subnet_invalid": "Ungültige Subnetzmaske.", + "form_error_required": "Pflichtfeld", + "form_error_ip4_format": "Ungültige IPv4-Adresse", + "form_error_ip4_range_start_format": "Ungültiger Bereichsbeginn der IPv4-Adresse", + "form_error_ip4_range_end_format": "Ungültiges Bereichsende der IPv4-Adresse", + "form_error_ip4_gateway_format": "Ungültige IPv4-Adresse des Gateways", + "form_error_ip6_format": "Ungültige IPv6-Adresse", + "form_error_ip_format": "Ungültige IP-Adresse", + "form_error_mac_format": "Ungültige MAC-Adresse", + "form_error_client_id_format": "Client-ID muss nur Zahlen, Kleinbuchstaben und Bindestriche enthalten", + "form_error_server_name": "Ungültiger Servername", + "form_error_subnet": "Subnetz „{{cidr}}“ enthält nicht die IP-Adresse „{{ip}}“", + "form_error_positive": "Muss größer als 0 sein", + "out_of_range_error": "Muss außerhalb des Bereichs „{{start}}“-„{{end}}“ liegen", + "lower_range_start_error": "Muss niedriger als der Bereichsbeginn sein", + "greater_range_start_error": "Muss größer als der Bereichsbeginn sein", + "greater_range_end_error": "Muss größer als das Bereichsende sein", + "subnet_error": "Die Adressen müssen innerhalb eines Subnetzes liegen", + "gateway_or_subnet_invalid": "Ungültige Subnetzmaske", "dhcp_form_gateway_input": "Gateway-IP", "dhcp_form_subnet_input": "Subnetz-Maske", "dhcp_form_range_title": "Bereich von IP-Adressen", @@ -67,7 +67,7 @@ "dhcp_table_hostname": "Hostname", "dhcp_table_expires": "Gültig bis", "dhcp_warning": "Wenn Sie den DHCP-Server trotzdem aktivieren möchten, stellen Sie sicher, dass sich in Ihrem Netzwerk kein anderer aktiver DHCP-Server befindet. Andernfalls kann es bei angeschlossenen Geräten zu einem Ausfall des Internets kommen!", - "dhcp_error": "AdGuard Home konnte nicht ermitteln, ob es einen anderen aktiven DHCP-Server im Netzwerk gibt.", + "dhcp_error": "AdGuard Home konnte keinen anderen aktiven DHCP-Server im Netzwerk feststellen", "dhcp_static_ip_error": "Um den DHCP-Server nutzen zu können, muss eine statische IP-Adresse festgelegt werden. Es konnte nicht ermittelt werden, ob diese Netzwerkschnittstelle mit statischer IP-Adresse konfiguriert ist. Bitte legen Sie eine statische IP-Adresse manuell fest.", "dhcp_dynamic_ip_found": "Ihr System verwendet die dynamische Konfiguration der IP-Adresse für die Schnittstelle <0>{{interfaceName}}. Um den DHCP-Server nutzen zu können, muss eine statische IP-Adresse festgelegt werden. Ihre aktuelle IP-Adresse ist <0>{{ipAddress}}. Diese IP-Adresse wird automatisch als statisch festgelegt, sobald Sie auf die Schaltfläche „DHCP-Server aktivieren“ klicken.", "dhcp_lease_added": "Statische Zuweisung „{{key}}“ erfolgreich hinzugefügt", @@ -196,7 +196,7 @@ "choose_allowlist": "Freigabeliste wählen", "enter_valid_blocklist": "Gültige Webadresse zur Sperrliste eingeben.", "enter_valid_allowlist": "Gültige Webadresse zur Freigabeliste eingeben.", - "form_error_url_format": "Ungültiges URL-Format.", + "form_error_url_format": "Ungültiges URL-Format", "form_error_url_or_path_format": "Ungültige URL oder absoluter Pfad der Liste", "custom_filter_rules": "Benutzerdefinierte Filterregeln", "custom_filter_rules_hint": "Geben Sie pro Zeile eine Regel ein. Sie können entweder Werbefilterregeln oder Host-Datei-Syntax verwenden.", @@ -210,11 +210,13 @@ "example_comment_hash": "# Auch ein Kommentar.", "example_regex_meaning": "Zugriff auf die Domains sperren, die dem angegebenen regulären Ausdruck entsprechen.", "example_upstream_regular": "reguläres DNS (over UDP);", + "example_upstream_udp": "normales DNS (über UDP, Hostname);", "example_upstream_dot": "verschlüsseltes <0>DNS-over-TLS;", "example_upstream_doh": "verschlüsseltes <0>DNS-over-HTTPS;", "example_upstream_doq": "verschlüsseltes <0>DNS-over-QUIC (experimentell);", "example_upstream_sdns": "<0>DNS-Stempel für <1>DNSCrypt oder <2>DNS-over-HTTPS Resolver;", "example_upstream_tcp": "reguläres DNS (over TCP);", + "example_upstream_tcp_hostname": "normales DNS (über TCP, Hostname);", "all_lists_up_to_date_toast": "Alle Listen sind bereits auf dem neuesten Stand", "updated_upstream_dns_toast": "Upstream-Server erfolgreich gespeichert", "dns_test_ok_toast": "Angegebene DNS-Server arbeiten ordnungsgemäß", @@ -259,10 +261,10 @@ "query_log_strict_search": "Doppelte Anführungszeichen für die strikte Suche verwenden", "query_log_retention_confirm": "Möchten Sie die Aufbewahrung des Abfrageprotokolls wirklich ändern? Wenn Sie den Zeitabstand verringern, gehen einige Daten verloren.", "anonymize_client_ip": "Client-IP anonymisieren", - "anonymize_client_ip_desc": "Vollständige IP-Adresse des Clients nicht in Protokollen und Statistiken speichern.", + "anonymize_client_ip_desc": "Vollständige IP-Adresse des Clients nicht in Protokollen und Statistiken speichern", "dns_config": "DNS-Serverkonfiguration", "dns_cache_config": "Konfiguration des DNS-Cache", - "dns_cache_config_desc": "Hier können Sie den DNS-Cache konfigurieren.", + "dns_cache_config_desc": "Hier können Sie den DNS-Cache konfigurieren", "blocking_mode": "Sperrmodus", "default": "Standard", "nxdomain": "NXDomain", @@ -285,7 +287,7 @@ "form_enter_rate_limit": "Begrenzungswert eingeben", "rate_limit": "Begrenzungswert", "edns_enable": "EDNS Client Subnetz aktivieren", - "edns_cs_desc": "Senden Sie die Subnetze der Clients an die DNS-Server.", + "edns_cs_desc": "Die Option EDNS Client Subnetz (ECS) zu Upstream-Anfragen hinzufügen und die von Clients gesendeten Werte protokollieren.", "rate_limit_desc": "Die Anzahl der Anfragen pro Sekunde, die ein einzelner Client stellen darf. Das Setzen auf 0 bedeutet keine Begrenzung.", "blocking_ipv4_desc": "IP-Adresse, die für eine gesperrte A-Anfrage zurückgegeben werden soll", "blocking_ipv6_desc": "IP-Adresse, die für eine gesperrte AAAA-Anfrage zurückgegeben werden soll", @@ -309,7 +311,7 @@ "install_settings_listen": "Netzwerk-Schnittstelle\n", "install_settings_port": "Port", "install_settings_interface_link": "Ihre AdGuard Home Admin-Weboberfläche ist unter den folgenden Adressen verfügbar:", - "form_error_port": "Geben Sie eine gültige Portnummer ein.", + "form_error_port": "Geben Sie eine gültige Portnummer ein", "install_settings_dns": "DNS-Server", "install_settings_dns_desc": "Sie müssen Ihre Geräte oder Ihren Router so konfigurieren, dass er den DNS-Server unter den folgenden Adressen verwendet:", "install_settings_all_interfaces": "Alle Schnittstellen", @@ -356,7 +358,7 @@ "open_dashboard": "Übersicht öffnen", "install_saved": "Erfolgreich gespeichert", "encryption_title": "Verschlüsselung", - "encryption_desc": "Verschlüsselungsunterstützung (HTTPS/TLS) für DNS- und Admin-Weboberfläche.", + "encryption_desc": "Unterstützung von Verschlüsselung (HTTPS/QUIC/TLS) für DNS- und Admin-Weboberfläche", "encryption_config_saved": "Verschlüsselungskonfiguration gespeichert", "encryption_server": "Servername", "encryption_server_enter": "Domain-Namen eingeben", @@ -378,26 +380,26 @@ "encryption_key_input": "Kopieren Sie Ihren PEM-codierten privaten Schlüssel für Ihr Zertifikat und fügen Sie ihn hier ein.", "encryption_enable": "Verschlüsselung aktivieren (HTTPS, DNS-over-HTTPS und DNS-over-TLS)", "encryption_enable_desc": "Wenn die Verschlüsselung aktiviert ist, funktioniert die AdGuard Home Admin-Oberfläche über HTTPS, und der DNS-Server wartet auf Anfragen über DNS-over-HTTPS und DNS-over-TLS.", - "encryption_chain_valid": "Zertifikatskette ist gültig.", - "encryption_chain_invalid": "Zertifikatskette ist ungültig.", - "encryption_key_valid": "Dies ist ein gültiger {{type}} privater Schlüssel.", - "encryption_key_invalid": "Dies ist ein ungültiger {{type}} privater Schlüssel.", + "encryption_chain_valid": "Zertifikatskette ist gültig", + "encryption_chain_invalid": "Zertifikatskette ist ungültig", + "encryption_key_valid": "Das ist ein gültiger {{type}} privater Schlüssel", + "encryption_key_invalid": "Das ist ein ungültiger {{type}} privater Schlüssel", "encryption_subject": "Ausgestellt für", "encryption_issuer": "Ausgestellt von", "encryption_hostnames": "Hostnamen", "encryption_reset": "Möchten Sie die Verschlüsselungseinstellungen wirklich zurücksetzen?", "topline_expiring_certificate": "Ihr SSL-Zertifikat läuft demnächst ab. Aktualisieren Sie Ihre <0>Verschlüsselungseinstellungen.", "topline_expired_certificate": "Ihr SSL-Zertifikat ist abgelaufen. Aktualisieren Sie Ihre <0>Verschlüsselungseinstellungen.", - "form_error_port_range": "Geben Sie die Portnummer zwischen 80 und 65535 ein.", - "form_error_port_unsafe": "Dies ist ein unsicherer Port.", - "form_error_equal": "Sollten nicht übereinstimmen.", - "form_error_password": "Passwörter stimmen nicht überein.", + "form_error_port_range": "Geben Sie die Portnummer zwischen 80 und 65535 ein", + "form_error_port_unsafe": "Unsicherer Port", + "form_error_equal": "Sollten nicht übereinstimmen", + "form_error_password": "Passwörter stimmen nicht überein", "reset_settings": "Einstellungen zurücksetzen", "update_announcement": "AdGuard Home {{version}} ist jetzt verfügbar! <0>Klicken Sie hier für weitere Informationen.", "setup_guide": "Einrichtungsassistent", "dns_addresses": "DNS-Adressen", "dns_start": "DNS-Server wird gestartet", - "dns_status_error": "Fehler bei Statusabfrage des DNS-Server.", + "dns_status_error": "Fehler bei Statusabfrage des DNS-Server", "down": "Nicht erreichbar", "fix": "Beheben", "dns_providers": "Hier finden Sie eine <0>Liste der bekannten DNS-Anbieter zur Auswahl.", @@ -406,7 +408,7 @@ "manual_update": "Bitte befolgen Sie diese Schritte, um manuell zu aktualisieren.", "processing_update": "Bitte warten Sie, AdGuard Home wird aktualisiert …", "clients_title": "Persistente Clients", - "clients_desc": "Datensätze persistenter Clients für Geräte konfigurieren, die mit AdGuard Home verbunden sind.", + "clients_desc": "Datensätze persistenter Clients für Geräte konfigurieren, die mit AdGuard Home verbunden sind", "settings_global": "Allgemein", "settings_custom": "Benutzerdefiniert", "table_client": "Client", @@ -433,9 +435,9 @@ "client_confirm_delete": "Möchten Sie den Client „{{key}}“ wirklich löschen?", "list_confirm_delete": "Möchten Sie diese Liste wirklich löschen?", "auto_clients_title": "Laufzeit-Clients", - "auto_clients_desc": "Geräte, die nicht auf der Liste der persistenten Clients stehen und trotzdem AdGuard Home verwenden dürfen.", + "auto_clients_desc": "Geräte, die nicht auf der Liste der persistenten Clients stehen und trotzdem AdGuard Home verwenden dürfen", "access_title": "Zugriffsrechte", - "access_desc": "Hier können Sie die Zugriffsregeln für den AdGuard Home DNS-Server konfigurieren.", + "access_desc": "Hier können Sie die Zugriffsregeln für den DNS-Server von AdGuard Home konfigurieren", "access_allowed_title": "Zugelassene Clients", "access_allowed_desc": "Eine Liste von CIDRs, IP-Adressen oder Client-IDs. Wenn diese Liste gefüllt ist, akzeptiert AdGuard Home nur Anfragen von diesen Clients.", "access_disallowed_title": "Nicht zugelassene Clients", @@ -475,8 +477,8 @@ "dns_rewrites": "DNS-Umschreibungen", "form_domain": "Domain eingeben", "form_answer": "IP-Adresse oder Domainname eingeben", - "form_error_domain_format": "Ungültiges Domainformat.", - "form_error_answer_format": "Ungültiges Antwortformat.", + "form_error_domain_format": "Ungültiges Domainformat", + "form_error_answer_format": "Ungültiges Antwortformat", "configure": "Konfigurieren", "main_settings": "Grundeinstellungen", "block_services": "Bestimmte Dienste sperren", @@ -500,6 +502,7 @@ "interval_days": "{{count}} Tag", "interval_days_plural": "{{count}} Tage", "domain": "Domain", + "ecs": "ECS", "punycode": "Punycode", "answer": "Antwort", "filter_added_successfully": "Der Filter wurde erfolgreich hinzugefügt", @@ -507,7 +510,7 @@ "filter_updated": "Der Filter wurde erfolgreich aktualisiert", "statistics_configuration": "Statistikkonfiguration", "statistics_retention": "Statistiken speichern", - "statistics_retention_desc": "Wenn Sie den Intervallwert verringern, gehen einige Daten verloren.", + "statistics_retention_desc": "Wenn Sie den Intervallwert verringern, gehen einige Daten verloren", "statistics_clear": "Statistiken leeren", "statistics_clear_confirm": "Möchten Sie die Statistiken wirklich löschen?", "statistics_retention_confirm": "Möchten Sie wirklich die Aufbewahrung der Statistiken ändern? Wenn Sie den Zeitabstand verringern, gehen einige Daten verloren.", @@ -599,14 +602,14 @@ "milliseconds_abbreviation": "ms", "cache_size": "Größe des Cache", "cache_size_desc": "Größe des DNS-Zwischenspeichers (in Bytes).", - "cache_ttl_min_override": "TTL-Minimalwert überschreiben (in Sekunden)", - "cache_ttl_max_override": "TTL-Höchstwert überschreiben (in Sekunden)", + "cache_ttl_min_override": "TTL-Minimalwert überschreiben", + "cache_ttl_max_override": "TTL-Höchstwert überschreiben", "enter_cache_size": "Größe des Cache (Bytes) eingeben", - "enter_cache_ttl_min_override": "TTL-Minimalwert eingeben", - "enter_cache_ttl_max_override": "TTL-Höchstwert eingeben", + "enter_cache_ttl_min_override": "TTL-Minimalwert eingeben (in Sekunden)", + "enter_cache_ttl_max_override": "TTL-Höchstwert eingeben (in Sekunden)", "cache_ttl_min_override_desc": "Kurze Time-to-Live-Werte (Sekunden) verlängern, die vom Upstream-Server beim Caching von DNS-Antworten empfangen werden.", "cache_ttl_max_override_desc": "Maximalen Time-to-Live-Wert (Sekunden) für Einträge im DNS-Cache festlegen.", - "ttl_cache_validation": "Der minimale Cache-TTL-Override muss kleiner oder gleich dem maximalen Wert sein.", + "ttl_cache_validation": "Der Überschreibungswert für die minimale TTL muss kleiner oder gleich dem für die maximale TTL sein", "cache_optimistic": "Optimistisches Caching", "cache_optimistic_desc": "Sorgt dafür, dass AdGuard Home auch dann aus dem Cache antwortet, wenn die Einträge abgelaufen sind, und versucht zudem, diese zu aktualisieren.", "filter_category_general": "Allgemein", @@ -628,5 +631,5 @@ "parental_control": "Kindersicherung", "safe_browsing": "Internetsicherheit", "served_from_cache": "{{value}} (aus dem Cache abgerufen)", - "form_error_password_length": "Das Passwort muss mindestens {{value}} Zeichen enthalten." + "form_error_password_length": "Das Passwort muss mindestens {{value}} Zeichen enthalten" } diff --git a/client/src/__locales/es.json b/client/src/__locales/es.json index 76eedb0f..a83527ed 100644 --- a/client/src/__locales/es.json +++ b/client/src/__locales/es.json @@ -35,24 +35,24 @@ "dhcp_config_saved": "Configuración DHCP guardado correctamente", "dhcp_ipv4_settings": "Configuración DHCP IPv4", "dhcp_ipv6_settings": "Configuración DHCP IPv6", - "form_error_required": "Campo obligatorio.", - "form_error_ip4_format": "Dirección IPv4 no válida.", - "form_error_ip4_range_start_format": "Dirección IPv4 no válida del inicio de rango.", - "form_error_ip4_range_end_format": "Dirección IPv4 no válida del final de rango.", - "form_error_ip4_gateway_format": "Dirección IPv4 no válida de la puerta de enlace.", - "form_error_ip6_format": "Dirección IPv6 no válida.", - "form_error_ip_format": "Dirección IP no válida.", - "form_error_mac_format": "Dirección MAC no válida.", - "form_error_client_id_format": "El ID de cliente debe contener solo números, letras minúsculas y guiones.", - "form_error_server_name": "Nombre de servidor no válido.", - "form_error_subnet": "La subred \"{{cidr}}\" no contiene la dirección IP \"{{ip}}\".", - "form_error_positive": "Debe ser mayor que 0.", - "out_of_range_error": "Debe estar fuera del rango \"{{start}}\"-\"{{end}}\".", - "lower_range_start_error": "Debe ser inferior que el inicio de rango.", - "greater_range_start_error": "Debe ser mayor que el inicio de rango.", - "greater_range_end_error": "Debe ser mayor que el final de rango.", - "subnet_error": "Las direcciones deben estar en una subred.", - "gateway_or_subnet_invalid": "Máscara de subred no válida.", + "form_error_required": "Campo obligatorio", + "form_error_ip4_format": "Dirección IPv4 no válida", + "form_error_ip4_range_start_format": "Dirección IPv4 no válida del inicio de rango", + "form_error_ip4_range_end_format": "Dirección IPv4 no válida del final de rango", + "form_error_ip4_gateway_format": "Dirección IPv4 no válida de la puerta de enlace", + "form_error_ip6_format": "Dirección IPv6 no válida", + "form_error_ip_format": "Dirección IP no válida", + "form_error_mac_format": "Dirección MAC no válida", + "form_error_client_id_format": "El ID de cliente debe contener solo números, letras minúsculas y guiones", + "form_error_server_name": "Nombre de servidor no válido", + "form_error_subnet": "La subred \"{{cidr}}\" no contiene la dirección IP \"{{ip}}\"", + "form_error_positive": "Debe ser mayor que 0", + "out_of_range_error": "Debe estar fuera del rango \"{{start}}\"-\"{{end}}\"", + "lower_range_start_error": "Debe ser inferior que el inicio de rango", + "greater_range_start_error": "Debe ser mayor que el inicio de rango", + "greater_range_end_error": "Debe ser mayor que el final de rango", + "subnet_error": "Las direcciones deben estar en una subred", + "gateway_or_subnet_invalid": "Máscara de subred no válida", "dhcp_form_gateway_input": "IP de puerta de enlace", "dhcp_form_subnet_input": "Máscara de subred", "dhcp_form_range_title": "Rango de direcciones IP", @@ -67,7 +67,7 @@ "dhcp_table_hostname": "Nombre del host", "dhcp_table_expires": "Expira", "dhcp_warning": "Si de todos modos deseas habilitar el servidor DHCP, asegúrate de que no hay otro servidor DHCP activo en tu red. ¡De lo contrario, puedes dejar sin conexión a Internet a los dispositivos conectados!", - "dhcp_error": "AdGuard Home no pudo determinar si hay otro servidor DHCP activo en la red.", + "dhcp_error": "AdGuard Home no pudo determinar si hay otro servidor DHCP activo en la red", "dhcp_static_ip_error": "Para poder utilizar el servidor DHCP se debe establecer una dirección IP estática. AdGuard Home no pudo determinar si esta interfaz de red está configurada utilizando una dirección IP estática. Por favor establece una dirección IP estática manualmente.", "dhcp_dynamic_ip_found": "Tu sistema utiliza la configuración de dirección IP dinámica para la interfaz <0>{{interfaceName}}. Para poder utilizar el servidor DHCP se debe establecer una dirección IP estática. Tu dirección IP actual es <0>{{ipAddress}}. AdGuard Home establecerá automáticamente esta dirección IP como estática si presionas el botón \"Habilitar servidor DHCP\".", "dhcp_lease_added": "Asignación estática \"{{key}}\" añadido correctamente", @@ -196,8 +196,8 @@ "choose_allowlist": "Elegir listas de permitido", "enter_valid_blocklist": "Ingresa una URL válida para la lista de bloqueo.", "enter_valid_allowlist": "Ingresa una URL válida para la lista de permitido.", - "form_error_url_format": "Formato de URL no válido.", - "form_error_url_or_path_format": "URL o ruta absoluta no válida para la lista.", + "form_error_url_format": "Formato de URL no válido", + "form_error_url_or_path_format": "URL o ruta absoluta no válida para la lista", "custom_filter_rules": "Reglas de filtrado personalizado", "custom_filter_rules_hint": "Ingresa una regla por línea. Puedes utilizar reglas de bloqueo o la sintaxis de los archivos hosts.", "system_host_files": "Archivos hosts del sistema", @@ -210,11 +210,13 @@ "example_comment_hash": "# También un comentario.", "example_regex_meaning": "bloquea el acceso a los dominios que coincidan con la expresión regular especificada.", "example_upstream_regular": "DNS regular (mediante UDP).", + "example_upstream_udp": "DNS regular (mediante UDP, nombre del host).", "example_upstream_dot": "cifrado <0>DNS mediante TLS.", "example_upstream_doh": "cifrado <0>DNS mediante HTTPS.", "example_upstream_doq": "cifrado <0>DNS mediante QUIC (experimental).", "example_upstream_sdns": "<0>DNS Stamps para <1>DNSCrypt o resolutores <2>DNS mediante HTTPS.", "example_upstream_tcp": "DNS regular (mediante TCP).", + "example_upstream_tcp_hostname": "DNS regular (mediante TCP, nombre del host).", "all_lists_up_to_date_toast": "Todas las listas ya están actualizadas", "updated_upstream_dns_toast": "Servidores DNS de subida guardados correctamente", "dns_test_ok_toast": "Los servidores DNS especificados funcionan correctamente", @@ -259,10 +261,10 @@ "query_log_strict_search": "Usar comillas dobles para una búsqueda estricta", "query_log_retention_confirm": "¿Estás seguro de que deseas cambiar la retención del registro de consultas? Si disminuye el valor del intervalo, se perderán algunos datos", "anonymize_client_ip": "Anonimizar IP del cliente", - "anonymize_client_ip_desc": "No guarda la dirección IP completa del cliente en registros o estadísticas.", + "anonymize_client_ip_desc": "No guarda la dirección IP completa del cliente en registros o estadísticas", "dns_config": "Configuración del servidor DNS", "dns_cache_config": "Configuración de la caché DNS", - "dns_cache_config_desc": "Aquí puedes configurar la caché DNS.", + "dns_cache_config_desc": "Aquí puedes configurar la caché DNS", "blocking_mode": "Modo de bloqueo", "default": "Predeterminado", "nxdomain": "NXDOMAIN", @@ -285,7 +287,7 @@ "form_enter_rate_limit": "Ingresa el límite de cantidad", "rate_limit": "Límite de cantidad", "edns_enable": "Habilitar subred de cliente EDNS", - "edns_cs_desc": "Envía las subredes de los clientes a los servidores DNS.", + "edns_cs_desc": "Añade la opción subred de cliente EDNS (ECS) a las peticiones del DNS de subida y registra los valores enviados por los clientes en el registro de consultas.", "rate_limit_desc": "Número de peticiones por segundo permitidas por cliente. Establecerlo en 0 significa que no hay límite.", "blocking_ipv4_desc": "Dirección IP devolverá una petición A bloqueada", "blocking_ipv6_desc": "Dirección IP devolverá una petición AAAA bloqueada", @@ -309,7 +311,7 @@ "install_settings_listen": "Interfaz de escucha", "install_settings_port": "Puerto", "install_settings_interface_link": "La interfaz web de administración de AdGuard Home estará disponible en las siguientes direcciones:", - "form_error_port": "Ingresa un número de puerto válido.", + "form_error_port": "Ingresa un número de puerto válido", "install_settings_dns": "Servidor DNS", "install_settings_dns_desc": "Deberás configurar tus dispositivos o router para usar el servidor DNS en las siguientes direcciones:", "install_settings_all_interfaces": "Todas las interfaces", @@ -356,7 +358,7 @@ "open_dashboard": "Abrir panel de control", "install_saved": "Guardado correctamente", "encryption_title": "Cifrado", - "encryption_desc": "Soporte de cifrado (HTTPS/TLS) tanto para DNS como para la interfaz web de administración.", + "encryption_desc": "Soporte de cifrado (HTTPS/QUIC/TLS) tanto para DNS como para la interfaz web de administración", "encryption_config_saved": "Configuración de cifrado guardado", "encryption_server": "Nombre del servidor", "encryption_server_enter": "Ingresa el nombre del dominio", @@ -378,26 +380,26 @@ "encryption_key_input": "Copia/pega aquí tu clave privada codificada PEM para tu certificado.", "encryption_enable": "Habilitar cifrado (HTTPS, DNS mediante HTTPS y DNS mediante TLS)", "encryption_enable_desc": "Si el cifrado está habilitado, la interfaz de administración de AdGuard Home funcionará a través de HTTPS, y el servidor DNS escuchará las peticiones DNS mediante HTTPS y DNS mediante TLS.", - "encryption_chain_valid": "La cadena de certificado es válida.", - "encryption_chain_invalid": "La cadena de certificado no es válida.", - "encryption_key_valid": "Esta es una clave privada {{type}} válida.", - "encryption_key_invalid": "Esta es una clave privada {{type}} no válida.", + "encryption_chain_valid": "La cadena de certificado es válida", + "encryption_chain_invalid": "La cadena de certificado no es válida", + "encryption_key_valid": "Esta es una clave privada {{type}} válida", + "encryption_key_invalid": "Esta es una clave privada {{type}} no válida", "encryption_subject": "Asunto", "encryption_issuer": "Emisor", "encryption_hostnames": "Nombres de hosts", "encryption_reset": "¿Estás seguro de que deseas restablecer la configuración de cifrado?", "topline_expiring_certificate": "Tu certificado SSL está a punto de expirar. Actualiza la <0>configuración de cifrado.", "topline_expired_certificate": "Tu certificado SSL ha expirado. Actualiza la <0>configuración de cifrado.", - "form_error_port_range": "Ingresa el número del puerto en el rango de 80 a 65535.", - "form_error_port_unsafe": "Este es un puerto inseguro.", - "form_error_equal": "No debe ser igual.", - "form_error_password": "La contraseña no coincide.", + "form_error_port_range": "Ingresa el número del puerto en el rango de 80 a 65535", + "form_error_port_unsafe": "Puerto inseguro", + "form_error_equal": "No debe ser igual", + "form_error_password": "La contraseña no coincide", "reset_settings": "Restablecer configuración", "update_announcement": "¡AdGuard Home {{version}} ya está disponible! <0>Haz clic aquí para más información.", "setup_guide": "Guía de configuración", "dns_addresses": "Direcciones DNS", "dns_start": "El servidor DNS está iniciando", - "dns_status_error": "Error al obtener el estado del servidor DNS.", + "dns_status_error": "Error al obtener el estado del servidor DNS", "down": "Abajo", "fix": "Corregir", "dns_providers": "Aquí hay una <0>lista de proveedores DNS conocidos para elegir.", @@ -406,7 +408,7 @@ "manual_update": "Por favor sigue estos pasos para actualizar manualmente.", "processing_update": "Por favor espera, AdGuard Home se está actualizando", "clients_title": "Clientes persistentes", - "clients_desc": "Configurar registros de clientes persistentes para dispositivos conectados a AdGuard Home.", + "clients_desc": "Configurar registros de clientes persistentes para dispositivos conectados a AdGuard Home", "settings_global": "Global", "settings_custom": "Personalizado", "table_client": "Cliente", @@ -433,9 +435,9 @@ "client_confirm_delete": "¿Estás seguro de que deseas eliminar el cliente \"{{key}}\"?", "list_confirm_delete": "¿Estás seguro de que deseas eliminar esta lista?", "auto_clients_title": "Clientes activos", - "auto_clients_desc": "Dispositivos que no están en la lista de clientes persistentes que aún pueden utilizar AdGuard Home.", + "auto_clients_desc": "Dispositivos que no están en la lista de clientes persistentes que aún pueden utilizar AdGuard Home", "access_title": "Configuración de acceso", - "access_desc": "Aquí puedes configurar las reglas de acceso para el servidor DNS de AdGuard Home.", + "access_desc": "Aquí puedes configurar las reglas de acceso para el servidor DNS de AdGuard Home", "access_allowed_title": "Clientes permitidos", "access_allowed_desc": "Lista de CIDR, direcciones IP o ID de clientes. Si esta lista tiene entradas, AdGuard Home aceptará peticiones solo de estos clientes.", "access_disallowed_title": "Clientes no permitidos", @@ -475,8 +477,8 @@ "dns_rewrites": "Reescrituras DNS", "form_domain": "Ingresa el nombre del dominio o comodín", "form_answer": "Ingresa la dirección IP o el nombre del dominio", - "form_error_domain_format": "Formato de dominio no válido.", - "form_error_answer_format": "Formato de respuesta no válido.", + "form_error_domain_format": "Formato de dominio no válido", + "form_error_answer_format": "Formato de respuesta no válido", "configure": "Configurar", "main_settings": "Configuración principal", "block_services": "Bloquear servicios específicos", @@ -500,6 +502,7 @@ "interval_days": "{{count}} día", "interval_days_plural": "{{count}} días", "domain": "Dominio", + "ecs": "ECS", "punycode": "Punycode", "answer": "Respuesta", "filter_added_successfully": "La lista ha sido añadida correctamente", @@ -507,7 +510,7 @@ "filter_updated": "La lista ha sido actualizada correctamente", "statistics_configuration": "Configuración de estadísticas", "statistics_retention": "Retención de estadísticas", - "statistics_retention_desc": "Si disminuye el valor del intervalo, se perderán algunos datos.", + "statistics_retention_desc": "Si disminuye el valor del intervalo, se perderán algunos datos", "statistics_clear": "Borrar estadísticas", "statistics_clear_confirm": "¿Estás seguro de que deseas borrar las estadísticas?", "statistics_retention_confirm": "¿Estás seguro de que deseas cambiar la retención de estadísticas? Si disminuye el valor del intervalo, se perderán algunos datos", @@ -606,7 +609,7 @@ "enter_cache_ttl_max_override": "Ingresa el TTL máximo (en segundos)", "cache_ttl_min_override_desc": "Amplía el corto tiempo de vida (segundos) de los valores recibidos del servidor DNS de subida al almacenar en caché las respuestas DNS.", "cache_ttl_max_override_desc": "Establece un valor de tiempo de vida (segundos) máximo para las entradas en la caché DNS.", - "ttl_cache_validation": "La anulación TTL mínimo de la caché debe ser menor o igual al máximo.", + "ttl_cache_validation": "La anulación TTL mínimo de la caché debe ser menor o igual al máximo", "cache_optimistic": "Caché optimista", "cache_optimistic_desc": "Haz que AdGuard Home responda desde la caché incluso cuando las entradas estén expiradas y también intente actualizarlas.", "filter_category_general": "General", @@ -628,5 +631,5 @@ "parental_control": "Control parental", "safe_browsing": "Navegación segura", "served_from_cache": "{{value}} (servido desde la caché)", - "form_error_password_length": "La contraseña debe tener al menos {{value}} caracteres." + "form_error_password_length": "La contraseña debe tener al menos {{value}} caracteres" } diff --git a/client/src/__locales/fi.json b/client/src/__locales/fi.json index 899748a7..5e6c8089 100644 --- a/client/src/__locales/fi.json +++ b/client/src/__locales/fi.json @@ -35,24 +35,24 @@ "dhcp_config_saved": "DHCP-asetukset tallennettiin", "dhcp_ipv4_settings": "DHCP:n IPv4-asetukset", "dhcp_ipv6_settings": "DHCP:n IPv6-asetukset", - "form_error_required": "Pakollinen kenttä.", - "form_error_ip4_format": "Virheellinen IPv4-osoite.", - "form_error_ip4_range_start_format": "Virheellinen IPv4-osoitealueen aloitusosoite.", - "form_error_ip4_range_end_format": "Virheellinen IPv4-osoitealueen päätösosoite.", - "form_error_ip4_gateway_format": "Virheellinen yhdyskäytävän IPv4-osoite.", - "form_error_ip6_format": "Virheellinen IPv6-osoite.", - "form_error_ip_format": "Virheellinen IP-osoite.", - "form_error_mac_format": "Virheellinen MAC-osoite.", - "form_error_client_id_format": "Päätelaitteen ID voi sisältää ainoastaan numeroita, pieniä kirjaimia sekä yhdysviivoja.", - "form_error_server_name": "Virheellinen palvelimen nimi.", - "form_error_subnet": "Aliverkko \"{{cidr}}\" ei sisällä IP-osoitetta \"{{ip}}\".", - "form_error_positive": "Oltava suurempi kuin 0.", - "out_of_range_error": "Oltava alueen \"{{start}}\" - \"{{end}}\" ulkopuolella.", - "lower_range_start_error": "Oltava alueen aloitusarvoa pienempi.", - "greater_range_start_error": "Oltava alueen aloitusarvoa suurempi.", - "greater_range_end_error": "Oltava alueen päätösarvoa pienempi.", - "subnet_error": "Osoitteiden tulee olla yhdessä aliverkossa.", - "gateway_or_subnet_invalid": "Virheellinen aliverkon peite.", + "form_error_required": "Pakollinen kenttä", + "form_error_ip4_format": "Virheellinen IPv4-osoite", + "form_error_ip4_range_start_format": "Virheellinen IPv4-osoitealueen aloitusosoite", + "form_error_ip4_range_end_format": "Virheellinen IPv4-osoitealueen päätösosoite", + "form_error_ip4_gateway_format": "Virheellinen yhdyskäytävän IPv4-osoite", + "form_error_ip6_format": "Virheellinen IPv6-osoite", + "form_error_ip_format": "Virheellinen IP-osoite", + "form_error_mac_format": "Virheellinen MAC-osoite", + "form_error_client_id_format": "Päätelaitteen ID voi sisältää ainoastaan numeroita, pieniä kirjaimia sekä yhdysviivoja", + "form_error_server_name": "Virheellinen palvelimen nimi", + "form_error_subnet": "Aliverkko \"{{cidr}}\" ei sisällä IP-osoitetta \"{{ip}}\"", + "form_error_positive": "Oltava suurempi kuin 0", + "out_of_range_error": "Oltava alueen \"{{start}}\" - \"{{end}}\" ulkopuolella", + "lower_range_start_error": "Oltava alueen aloitusarvoa pienempi", + "greater_range_start_error": "Oltava alueen aloitusarvoa suurempi", + "greater_range_end_error": "Oltava alueen päätösarvoa pienempi", + "subnet_error": "Osoitteiden tulee olla yhdessä aliverkossa", + "gateway_or_subnet_invalid": "Virheellinen aliverkon peite", "dhcp_form_gateway_input": "Yhdyskäytävän IP-osoite", "dhcp_form_subnet_input": "Aliverkon peite", "dhcp_form_range_title": "IP-osoitealue", @@ -67,7 +67,7 @@ "dhcp_table_hostname": "Isäntänimi", "dhcp_table_expires": "Erääntyy", "dhcp_warning": "Jos tahdot kuitenkin ottaa DHCP-palvelimen käyttöön, varmista, ettei verkossasi ole muita aktiivisia DHCP-palvelimia, koska tämä voi rikkoa Internet-yhteyden muilta verkon laitteilta!", - "dhcp_error": "AdGuard Home ei voinut tunnistaa, onko verkossa toista aktiivista DHCP-palvelinta.", + "dhcp_error": "AdGuard Home ei voinut tunnistaa, onko verkossa toista aktiivista DHCP-palvelinta", "dhcp_static_ip_error": "Jotta DHCP-palvelinta voidaan käyttää, on määritettävä kiinteä IP-osoite. AdGuard Home ei voinut tunnistaa, onko tälle verkkosovittimelle määritetty IP-osoite kiinteä. Määritä kiinteä IP-osoite itse.", "dhcp_dynamic_ip_found": "Järjestelmäsi käyttää verkkosovittimelle <0>{{interfaceName}} dynaamista IP-osoitetta. Jotta voit käyttää DHCP-palvelinta, on sovittimelle määritettävä kiinteä IP-osoite. Nykyinen IP-osoitteesi on <0>{{ipAddress}}. Tämä osoite määritetään automaattisesti kiinteäksi, jos painat \"Ota DHCP-palvelin käyttöön\" -painiketta.", "dhcp_lease_added": "Kiinteä laina \"{{key}}\" on lisätty", @@ -117,7 +117,7 @@ "stats_adult": "Estetyt aikuisille tarkoitetut sivustot", "stats_query_domain": "Kysytyimmät verkkotunnukset", "for_last_24_hours": "viimeisten 24 tunnin ajalta", - "for_last_days": "viimeisen {{count}} päivän ajalta", + "for_last_days": "viimeisten {{count}} päivän ajalta", "for_last_days_plural": "viimeisten {{count}} päivän ajalta", "stats_disabled": "Tilastointi ei ole käytössä. Voit ottaa sen käyttöön <0>asetuksista.", "stats_disabled_short": "Tilastointi ei ole käytössä", @@ -127,7 +127,7 @@ "top_clients": "Käytetyimmät päätelaitteet", "no_clients_found": "Päätelaitteita ei löytynyt", "general_statistics": "Yleiset tilastot", - "number_of_dns_query_days": "Käsiteltyjen DNS-pyyntöjen määrä viimeisen {{count}} päivän ajalta", + "number_of_dns_query_days": "Käsiteltyjen DNS-pyyntöjen määrä viimeisten {{count}} päivän ajalta", "number_of_dns_query_days_plural": "Käsiteltyjen DNS-pyyntöjen määrä viimeisten {{count}} päivän ajalta", "number_of_dns_query_24_hours": "Käsiteltyjen DNS-pyyntöjen määrä viimeisten 24 tunnin ajalta", "number_of_dns_query_blocked_24_hours": "Mainoseston suodattimien ja hosts-estolistojen estämien DNS-pyyntöjen määrä", @@ -196,8 +196,8 @@ "choose_allowlist": "Valitse sallittujen listat", "enter_valid_blocklist": "Syötä estolistan URL-osoite.", "enter_valid_allowlist": "Syötä sallittujen listan URL-osoite.", - "form_error_url_format": "Virheellinen URL-osoitteen muoto.", - "form_error_url_or_path_format": "Syötä listan URL-osoite tai tarkka tiedostosijainti.", + "form_error_url_format": "Virheellinen URL-osoitteen muoto", + "form_error_url_or_path_format": "Syötä listan URL-osoite tai tarkka tiedostosijainti", "custom_filter_rules": "Omat suodatussäännöt", "custom_filter_rules_hint": "Syötä yksi sääntö per rivi. Voit käyttää mainoseston sääntöjen tai hosts-tiedostojen syntakseja.", "system_host_files": "Järjestelmän hosts-tiedostot", @@ -210,11 +210,13 @@ "example_comment_hash": "# Tämäkin on kommentti.", "example_regex_meaning": "estä pääsy määritettyä säännöllistä lauseketta vastaaviin verkkotunnuksiin.", "example_upstream_regular": "tavallinen DNS (UDP:n välityksellä);", + "example_upstream_udp": "tavallinen DNS (UDP, isäntänimi);", "example_upstream_dot": "salattu <0>DNS-over-TLS;", "example_upstream_doh": "salattu <0>DNS-over-HTTPS;", "example_upstream_doq": "salattu <0>DNS-over-QUIC (kokeellinen);", "example_upstream_sdns": "<0>DNS Stamp -merkinnät <1>DNSCrypt tai <2>DNS-over-HTTPS -resolvereille;", "example_upstream_tcp": "tavallinen DNS (TCP:n välityksellä);", + "example_upstream_tcp_hostname": "tavallinen DNS (TCP, isäntänimi);", "all_lists_up_to_date_toast": "Kaikki listat ovat ajan tasalla", "updated_upstream_dns_toast": "Ylävirtojen palvelimet tallennettiin", "dns_test_ok_toast": "Määritetyt DNS-palvelimet toimivat oikein", @@ -309,7 +311,7 @@ "install_settings_listen": "Käytettävä verkkosovitin", "install_settings_port": "Portti", "install_settings_interface_link": "AdGuard Home -asennuksesi hallintapaneeli on käytettävissä seuraavilla osoitteilla:", - "form_error_port": "Syötä oikea portin numero.", + "form_error_port": "Syötä kelvollinen portti", "install_settings_dns": "DNS-palvelin", "install_settings_dns_desc": "Sinun on määritettävä laitteesi tai reitittimesi käyttämään DNS-palvelinta seuraavissa osoitteissa:", "install_settings_all_interfaces": "Kaikki verkkosovittimet", @@ -378,26 +380,26 @@ "encryption_key_input": "Kopioi/liitä tähän varmenteesi PEM-koodattu yksityinen avain.", "encryption_enable": "Käytä salausta (HTTPS, DNS-over-HTTPS ja DNS-over-TLS)", "encryption_enable_desc": "Jos salaus on käytössä, AdGuard Homen hallinta on käytettävissä HTTPS-yhteydellä ja DNS-palvelin kuuntelee pyyntöjä DNS-over-HTTPS ja DNS-over-TLS -yhteyksillä.", - "encryption_chain_valid": "Varmenneketju on kelvollinen.", - "encryption_chain_invalid": "Varmenneketju ei kelpaa.", - "encryption_key_valid": "Tämä yksityinen {{type}}-avain on kelvollinen.", - "encryption_key_invalid": "Tämä yksityinen {{type}}-avain ei kelpaa.", + "encryption_chain_valid": "Varmenneketju on kelvollinen", + "encryption_chain_invalid": "Varmenneketju ei kelpaa", + "encryption_key_valid": "Tämä yksityinen {{type}}-avain on kelvollinen", + "encryption_key_invalid": "Tämä yksityinen {{type}}-avain ei kelpaa", "encryption_subject": "Aihe", "encryption_issuer": "Toimittaja", "encryption_hostnames": "Isäntänimet", "encryption_reset": "Haluatko varmasti palauttaa salausasetukset?", "topline_expiring_certificate": "SSL-varmenteesi on erääntymässä. Päivitä <0>Salausasetukset.", "topline_expired_certificate": "SSL-varmenteesi on erääntynyt. Päivitä <0>Salausasetukset.", - "form_error_port_range": "Syötä portti väliltä 80-65535.", - "form_error_port_unsafe": "Tämä portti ei ole turvallinen.", - "form_error_equal": "Ei voi olla sama.", - "form_error_password": "Salasanat eivät täsmää.", + "form_error_port_range": "Syötä portti väliltä 80-65535", + "form_error_port_unsafe": "Portti ei ole turvallinen", + "form_error_equal": "Ei voi olla sama", + "form_error_password": "Salasanat eivät täsmää", "reset_settings": "Tyhjennä asetukset", "update_announcement": "AdGuard Home {{version}} on nyt saatavilla! <0>Paina tästä saadaksesi lisätietoja.", "setup_guide": "Asennusopas", "dns_addresses": "DNS-osoitteet", "dns_start": "DNS-palvelin käynnistyy", - "dns_status_error": "Virhe tarkistettaessa DNS-palvelimen tilaa.", + "dns_status_error": "Virhe tarkistettaessa DNS-palvelimen tilaa", "down": "yhteydetön", "fix": "Korjaa", "dns_providers": "Katso <0>luettelo tunnetuista DNS-palveluista, joista valita.", @@ -406,7 +408,7 @@ "manual_update": "Seuraa näitä ohjeita päivittääksesi manuaalisesti.", "processing_update": "Odota kun AdGuard Home päivittyy", "clients_title": "Pysyvät päätelaitteet", - "clients_desc": "Määritä pysyvät AdGuard Homeen yhdistetyt päätelaittetiedot.", + "clients_desc": "Määritä pysyvät AdGuard Homeen yhdistetyt päätelaitetiedot.", "settings_global": "Yleinen", "settings_custom": "Oma", "table_client": "Päätelaite", @@ -475,8 +477,8 @@ "dns_rewrites": "DNS-uudelleenohjaukset", "form_domain": "Syötä verkkotunnus tai jokerimerkki", "form_answer": "Syötä IP-osoite tai verkkotunnus", - "form_error_domain_format": "Virheellinen verkkotunnuksen muoto.", - "form_error_answer_format": "Virheellinen vastauksen muoto.", + "form_error_domain_format": "Virheellinen verkkotunnuksen muoto", + "form_error_answer_format": "Virheellinen vastauksen muoto", "configure": "Määritä", "main_settings": "Pääasetukset", "block_services": "Estä tietyt palvelut", @@ -500,6 +502,7 @@ "interval_days": "{{count}} päivä", "interval_days_plural": "{{count}} päivää", "domain": "Verkkotunnus", + "ecs": "ECS", "punycode": "Punycode", "answer": "Vastaus", "filter_added_successfully": "Lista lisättiin", @@ -606,7 +609,7 @@ "enter_cache_ttl_max_override": "Syötä enimmäis-TTL (sekunteina)", "cache_ttl_min_override_desc": "Pidennä ylävirran palvelimelta vastaanotettuja, lyhyitä elinaika-arvoja (sekunteina) tallennettaessa DNS-vastauksia välimuistiin.", "cache_ttl_max_override_desc": "Määritä DNS-välimuistin kohteiden enimmäiselinaika (sekunteina).", - "ttl_cache_validation": "Välimuistin vähimmäiselinajan tulee olla pienempi tai sama kuin enimmäiselinajan.", + "ttl_cache_validation": "Välimuistin vähimmäiselinajan on oltava pienempi tai sama kuin enimmäiselinajan", "cache_optimistic": "Optimistinen välimuisti", "cache_optimistic_desc": "Pakota AdGuard Home vastaamaan välimuistista vaikka sen tiedot olisivat vanhentuneet. Pyri samalla myös päivittämään tiedot.", "filter_category_general": "Yleiset", @@ -628,5 +631,5 @@ "parental_control": "Lapsilukko", "safe_browsing": "Turvallinen selaus", "served_from_cache": "{{value}} (jaettu välimuistista)", - "form_error_password_length": "Salasanan on oltava ainakin {{value}} merkkiä." + "form_error_password_length": "Salasanan on oltava ainakin {{value}} merkkiä" } diff --git a/client/src/__locales/fr.json b/client/src/__locales/fr.json index b10433ae..afbe91cd 100644 --- a/client/src/__locales/fr.json +++ b/client/src/__locales/fr.json @@ -35,24 +35,24 @@ "dhcp_config_saved": "Configuration du serveur DHCP sauvegardée", "dhcp_ipv4_settings": "Paramètres IPv4 du DHCP", "dhcp_ipv6_settings": "Paramètres IPv6 du DHCP", - "form_error_required": "Champ requis.", - "form_error_ip4_format": "Adresse IPv4 invalide.", - "form_error_ip4_range_start_format": "Adresse de début de plage IPv4 incorrecte.", - "form_error_ip4_range_end_format": "Adresse de fin de plage IPv4 incorrecte.", - "form_error_ip4_gateway_format": "Adresse de passerelle IPv4 invalide.", - "form_error_ip6_format": "Adresse IPv6 invalide.", - "form_error_ip_format": "Adresse IP invalide.", - "form_error_mac_format": "Format MAC invalide.", - "form_error_client_id_format": "ClientID ne doit contenir que des chiffres, des lettres minuscules et des traits d'union.", - "form_error_server_name": "Nom de serveur invalide.", - "form_error_subnet": "Le sous-réseau « {{cidr}} » ne contient pas l'adresse IP « {{ip}} ».", - "form_error_positive": "Doit être supérieur à 0.", - "out_of_range_error": "Doit être hors plage « {{start}} » - « {{end}} ».", - "lower_range_start_error": "Doit être inférieur au début de plage.", - "greater_range_start_error": "Doit être supérieur au début de plage.", - "greater_range_end_error": "Doit être supérieur à la fin de plage.", - "subnet_error": "Les adresses doivent être dans le même sous-réseau.", - "gateway_or_subnet_invalid": "Masque de sous-réseau invalide.", + "form_error_required": "Champ requis", + "form_error_ip4_format": "Adresse IPv4 invalide", + "form_error_ip4_range_start_format": "Adresse de début de plage IPv4 incorrecte", + "form_error_ip4_range_end_format": "Adresse de fin de plage IPv4 incorrecte", + "form_error_ip4_gateway_format": "Adresse de passerelle IPv4 invalide", + "form_error_ip6_format": "Adresse IPv6 invalide", + "form_error_ip_format": "Adresse IP invalide", + "form_error_mac_format": "Adresse MAC invalide", + "form_error_client_id_format": "L'ID du client ne doit contenir que des chiffres, des lettres minuscules et des traits d'union", + "form_error_server_name": "Nom de serveur invalide", + "form_error_subnet": "Le sous-réseau « {{cidr}} » ne contient pas l'adresse IP « {{ip}} »", + "form_error_positive": "Doit être supérieur à 0", + "out_of_range_error": "Doit être hors plage « {{start}} » - « {{end}} »", + "lower_range_start_error": "Doit être inférieur au début de plage", + "greater_range_start_error": "Doit être supérieur au début de plage", + "greater_range_end_error": "Doit être supérieur à la fin de plage", + "subnet_error": "Les adresses doivent être dans le même sous-réseau", + "gateway_or_subnet_invalid": "Masque de sous-réseau invalide", "dhcp_form_gateway_input": "IP de la passerelle", "dhcp_form_subnet_input": "Masque de sous-réseau", "dhcp_form_range_title": "Rangée des adresses IP", @@ -196,8 +196,8 @@ "choose_allowlist": "Choisir des listes d’autorisation", "enter_valid_blocklist": "Saisissez une URL valide vers la liste de blocage.", "enter_valid_allowlist": "Saisissez une URL valide vers la liste d’autorisation.", - "form_error_url_format": "Format d’URL incorrect.", - "form_error_url_or_path_format": "Entrez une URL ou le chemin absolu de la liste.", + "form_error_url_format": "Format d’URL incorrect", + "form_error_url_or_path_format": "Lien URL soit chemin absolu de la liste invalide", "custom_filter_rules": "Règles de filtrage d'utilisateur", "custom_filter_rules_hint": "Saisissez la règle en une ligne. C'est possible d'utiliser les règles de blocage ou la syntaxe des fichiers hosts.", "system_host_files": "Fichier d'hôtes système", @@ -210,11 +210,13 @@ "example_comment_hash": "# Aussi un commentaire.", "example_regex_meaning": "bloque l’accès aux domaines correspondants à l'expression régulière spécifiée .", "example_upstream_regular": "DNS classique (au-dessus de UDP) ;", + "example_upstream_udp": "DNS normal (sur UDP, nom d’hôte) ;", "example_upstream_dot": "<0>DNS-over-TLS chiffré ;", "example_upstream_doh": "<0>DNS-over-HTTPS chiffré ;", "example_upstream_doq": "<0>DNS-over-QUIC chiffré (expérimental) ;", "example_upstream_sdns": "vous pouvez utiliser <0>DNS Stamps pour <1>DNSCrypt ou les résolveurs <2>DNS_over_HTTPS ;", "example_upstream_tcp": "DNS classique (au-dessus de TCP) ;", + "example_upstream_tcp_hostname": "DNS normal (sur TCP, nom d’hôte) ;", "all_lists_up_to_date_toast": "Toutes les listes sont déjà à jour", "updated_upstream_dns_toast": "Serveurs en amont enregistrés", "dns_test_ok_toast": "Les serveurs DNS spécifiés fonctionnent correctement", @@ -259,10 +261,10 @@ "query_log_strict_search": "Utilisez les doubles guillemets pour une recherche stricte", "query_log_retention_confirm": "Êtes-vous sûr de vouloir modifier la rétention des journaux de requêtes ? Si vous diminuez la valeur de l'intervalle, certaines données seront perdues", "anonymize_client_ip": "Anonymiser l’IP du client", - "anonymize_client_ip_desc": "Ne pas enregistrer l’adresse IP complète du client dans les journaux et statistiques .", + "anonymize_client_ip_desc": "Ne pas enregistrer l’adresse IP complète du client dans les journaux et statistiques", "dns_config": "Configuration du serveur DNS", "dns_cache_config": "Configuration du cache DNS", - "dns_cache_config_desc": "Ici, vous pouvez configurer le cache DNS .", + "dns_cache_config_desc": "Ici, vous pouvez configurer le cache DNS", "blocking_mode": "Mode du blocage", "default": "Par défaut", "nxdomain": "NXDOMAIN", @@ -285,7 +287,7 @@ "form_enter_rate_limit": "Entrez la limite de taux", "rate_limit": "Limite de taux", "edns_enable": "Activer le sous-réseau du client EDNS", - "edns_cs_desc": "Envoyer les sous-réseaux des clients aux serveurs DNS.", + "edns_cs_desc": "Ajouter l'option du sous-réseau Client EDNS (ECS) au requêtes en amont et enregistrer les valeurs envoyées par les clients dans le journal des requêtes.", "rate_limit_desc": "Le nombre de requêtes par seconde qu’un seul client est autorisé à faire. Le réglage 0 fait illimité.", "blocking_ipv4_desc": "Adresse IP à renvoyer pour une demande A bloquée", "blocking_ipv6_desc": "Adresse IP à renvoyer pour une demande AAAA bloquée", @@ -309,7 +311,7 @@ "install_settings_listen": "Interface d'écoute", "install_settings_port": "Port", "install_settings_interface_link": "Votre interface web administrateur AdGuard Home sera disponible sur les adresses suivantes :", - "form_error_port": "Entrez un port valide.", + "form_error_port": "Saisissez un numéro de port valide", "install_settings_dns": "Serveur DNS", "install_settings_dns_desc": "Vous devrez configurer vos appareils et votre routeur pour utiliser le serveur DNS sur les adresses suivantes :", "install_settings_all_interfaces": "Toutes les interfaces", @@ -356,7 +358,7 @@ "open_dashboard": "Ouvrir le Tableau de bord", "install_saved": "Enregistré avec succès", "encryption_title": "Chiffrement", - "encryption_desc": "Le support du chiffrement (HTTPS/TLS) pour les DNS et l'interface web administrateur", + "encryption_desc": "Le support du chiffrement (HTTPS/QUIC/TLS) pour les DNS et l'interface web administrateur", "encryption_config_saved": "Configuration de chiffrement enregistrée", "encryption_server": "Nom du serveur", "encryption_server_enter": "Entrez votre nom de domaine", @@ -379,25 +381,25 @@ "encryption_enable": "Activer le chiffrement (HTTPS, DNS-over-HTTPS et DNS-over-TLS)", "encryption_enable_desc": "Si le chiffrement est activé, l'interface administrateur AdGuard Home fonctionnera via HTTPS et le serveur DNS écoutera les requêtes via DNS-over-HTTPS et DNS-over-TLS.", "encryption_chain_valid": "Chaîne de certificat valide.", - "encryption_chain_invalid": "Chaîne de certificat invalide.", - "encryption_key_valid": "Ceci est une clé privée {{type}} valide.", - "encryption_key_invalid": "Ceci est une clé privée {{type}} invalide.", + "encryption_chain_invalid": "Chaîne de certificat invalide", + "encryption_key_valid": "Ceci est une clé privée {{type}} valide", + "encryption_key_invalid": "Ceci est une clé privée {{type}} invalide", "encryption_subject": "Objet", "encryption_issuer": "Émetteur", "encryption_hostnames": "Noms d'hôte", "encryption_reset": "Voulez-vous vraiment réinitialiser les paramètres de chiffrement ?", "topline_expiring_certificate": "Votre certificat SSL est sur le point d'expirer. Mettez à jour vos <0>Paramètres de chiffrement.", "topline_expired_certificate": "Votre certificat SSL a expiré. Mettez à jour vos <0>Paramètres de chiffrement.", - "form_error_port_range": "Saisissez une valeur de port entre 80 et 65535.", - "form_error_port_unsafe": "C'est un port non fiable.", - "form_error_equal": "Ne doit pas être égal .", - "form_error_password": "Mots de passe différents.", + "form_error_port_range": "Saisissez une valeur de port entre 80 et 65535", + "form_error_port_unsafe": "Port non fiable", + "form_error_equal": "Ne doit pas être égal", + "form_error_password": "Mots de passe différents", "reset_settings": "Réinitialiser les paramètres", "update_announcement": "AdGuard Home {{version}} est disponible ! <0>Cliquez ici pour plus d'informations.", "setup_guide": "Guide d'installation", "dns_addresses": "Adresses DNS", "dns_start": "Démarrage du serveur DNS", - "dns_status_error": "Erreur lors de la récupération du statut du serveur DNS .", + "dns_status_error": "Erreur lors de la vérification du statut du serveur DNS", "down": "Descendant", "fix": "Corriger", "dns_providers": "Voici une <0>liste de fournisseurs DNS connus.", @@ -406,7 +408,7 @@ "manual_update": "Veuillez suivre ces étapes pour mettre à jour manuellement.", "processing_update": "Veuillez patienter, AdGuard Home est en cours de mise à jour", "clients_title": "Clients persistants", - "clients_desc": "Configurez des enregistrements clients persistants pour les appareils connectés à AdGuard Home.", + "clients_desc": "Configurer des dossiers de clients persistants pour les appareils connectés à AdGuard Home", "settings_global": "Général", "settings_custom": "Personnalisé", "table_client": "Client", @@ -435,7 +437,7 @@ "auto_clients_title": "Clients d'exécution", "auto_clients_desc": "Appareils ne figurant pas sur la liste des clients persistants qui peuvent encore utiliser AdGuard Home.", "access_title": "Paramètres d'accès", - "access_desc": "Ici vous pouvez configurer les règles d'accès au serveur DNS AdGuard Home.", + "access_desc": "Ici vous pouvez configurer les règles d'accès au serveur DNS AdGuard Home", "access_allowed_title": "Clients autorisés", "access_allowed_desc": "Une liste de CIDRs, d'adresses IP, ou de ClientIDs. Si cette liste comporte des entrées, AdGuard Home n'acceptera que les demandes provenant de ces clients.", "access_disallowed_title": "Clients non autorisés", @@ -475,8 +477,8 @@ "dns_rewrites": "Réécritures DNS", "form_domain": "Saisissez un domaine ou caracrtère générique", "form_answer": "Saisissez une adresse IP ou un nom de domaine", - "form_error_domain_format": "Nom de domaine invalide.", - "form_error_answer_format": "Format de réponse invalide.", + "form_error_domain_format": "Format de domaine invalide", + "form_error_answer_format": "Format de réponse invalide", "configure": "Configurer", "main_settings": "Paramètres principaux", "block_services": "Bloquer des services spécifiques", @@ -500,6 +502,7 @@ "interval_days": "{{count}} jour", "interval_days_plural": "{{count}} jours", "domain": "Domaine", + "ecs": "ECS", "punycode": "Punycode", "answer": "Réponse", "filter_added_successfully": "Le filtre a été ajouté avec succès", @@ -507,7 +510,7 @@ "filter_updated": "Le filtre a été mis à jour avec succès", "statistics_configuration": "Configuration des statistiques", "statistics_retention": "Maintien des statistiques", - "statistics_retention_desc": "Si vous baissez la valeur de l'intervalle, des données seront perdues .", + "statistics_retention_desc": "Si vous baissez la valeur de l'intervalle, des données seront perdues", "statistics_clear": " Effacer les statistiques", "statistics_clear_confirm": "Voulez-vous vraiment effacer les statistiques ?", "statistics_retention_confirm": "Êtes-vous sûr de vouloir modifier le maintien des statistiques ? Si vous diminuez la valeur de l'intervalle, certaines données seront perdues", @@ -606,7 +609,7 @@ "enter_cache_ttl_max_override": "Entrez le TTL maximum (secondes)", "cache_ttl_min_override_desc": "Prolonger les valeurs courtes de durée de vie (en secondes) reçues du serveur en amont lors de la mise en cache des réponses DNS .", "cache_ttl_max_override_desc": "Établir la valeur de durée de vie TTL maximale (en secondes) pour les saisies dans le cache du DNS .", - "ttl_cache_validation": "La valeur TTL minimale du cache doit être inférieure ou égale à la valeur maximale .", + "ttl_cache_validation": "La valeur TTL minimale du cache doit être inférieure ou égale à la valeur maximale", "cache_optimistic": "Caching optimiste", "cache_optimistic_desc": "Faites en sorte qu'AdGuard Home réponde à partir du cache même lorsque les entrées ont expiré et essayez également de les actualiser.", "filter_category_general": "Général", @@ -628,5 +631,5 @@ "parental_control": "Contrôle parental", "safe_browsing": "Navigation sécurisée", "served_from_cache": "{{value}} (depuis le cache)", - "form_error_password_length": "Le mot de passe doit comporter au moins {{value}} caractères." + "form_error_password_length": "Le mot de passe doit comporter au moins {{value}} caractères" } diff --git a/client/src/__locales/hr.json b/client/src/__locales/hr.json index 5b0dc1dc..47f2296c 100644 --- a/client/src/__locales/hr.json +++ b/client/src/__locales/hr.json @@ -1,7 +1,7 @@ { "client_settings": "Postavke klijenta", - "example_upstream_reserved": "VI možete odrediti DNS upstream-ove <0>za određene domene", - "example_upstream_comment": "Možete odrediti komentar", + "example_upstream_reserved": "upstream <0>za određene domene;", + "example_upstream_comment": "komentar.", "upstream_parallel": "Koristi paralelne upite kako bi ubrzali rješavanje istovremenim ispitavanjem svih upstream poslužitelja.", "parallel_requests": "Paralelni zahtjevi", "load_balancing": "Load-balancing", @@ -36,13 +36,13 @@ "dhcp_ipv4_settings": "DHCP IPv4 postavke", "dhcp_ipv6_settings": "DHCP IPv6 postavke", "form_error_required": "Obavezno polje", - "form_error_ip4_format": "Nevažeći IPv4 format", + "form_error_ip4_format": "Nevažeća IPv4 adresa", "form_error_ip4_range_start_format": "Nepravilan početak ranga IPv4 adresa", "form_error_ip4_range_end_format": "Nepravilan kraj ranga IPv4 adresa", "form_error_ip4_gateway_format": "Nepravilna IPV4 adresa čvora", - "form_error_ip6_format": "Nevažeći IPv6 format", - "form_error_ip_format": "Nevažeći format IP adrese", - "form_error_mac_format": "Nevažeći MAC format", + "form_error_ip6_format": "Nevažeći IPv6 adresa", + "form_error_ip_format": "Nepravilna IP adresa", + "form_error_mac_format": "Nevažeći MAC adresa", "form_error_client_id_format": "ID klijenta može sadržavati samo brojeve, mala slova i crtice", "form_error_server_name": "Nevažeće ime poslužitelja", "form_error_subnet": "Podmrežu \"{{cidr}}\" ne sadrži IP adresu \"{{ip}}\"", @@ -67,7 +67,7 @@ "dhcp_table_hostname": "Naziv računala", "dhcp_table_expires": "Istječe", "dhcp_warning": "Ako svejedno želite omogućiti DHCP poslužitelj, provjerite da nema drugog aktivnog DHCP poslužitelja na vašoj mreži. Inače može pokvariti Internet za ostale povezane uređaje!", - "dhcp_error": "AdGuard Home nije mogao utvrditi postoji li drugi aktivni DHCP poslužitelj na mreži.", + "dhcp_error": "AdGuard Home nije mogao utvrditi postoji li drugi aktivni DHCP poslužitelj na mreži", "dhcp_static_ip_error": "Da bi se koristio DHCP poslužitelj mora se postaviti statička IP adresa. AdGuard Home nije uspio utvrditi je li ovo mrežno sučelje konfigurirano pomoću statičke IP adrese. Ručno postavite statičku IP adresu.", "dhcp_dynamic_ip_found": "Vaš sustav koristi postavke dinamičke IP adrese za sučelje <0>{{interfaceName}}. Za korištenje DHCP poslužitelja mora se postaviti statička IP adresa. Vaša trenutna IP adresa je <0>{{ipAddress}}. AdGuard Home automatski će postaviti ovu IP adresu kao statičnu ako pritisnete gumb \"Omogući DHCP\".", "dhcp_lease_added": "Statični lease \"{{key}}\" je uspješno dodan", @@ -202,19 +202,21 @@ "custom_filter_rules_hint": "Unesite jedno pravilo po liniji. Možete koristiti sintaksu za pravila blokiranja oglasa ili za hosts datoteke.", "system_host_files": "Datoteke host sustava", "examples_title": "Primjeri", - "example_meaning_filter_block": "blokira pristup domeni example.org kao i svim njenim poddomenama", - "example_meaning_filter_whitelist": "odblokira pristup domeni example.org kao i svim njenim poddomenama", - "example_meaning_host_block": "AdGuard Home će sada vratiti 127.0.0.1 adresu na example.org domenu (ali ne i poddomene).", - "example_comment": "! Ovdje ide komentar", - "example_comment_meaning": "samo komentar", - "example_comment_hash": "# Također komentar", - "example_regex_meaning": "blokira pristup domenama koje se podudaraju s regularnim izrazom", - "example_upstream_regular": "zadani DNS (putem UDP)", - "example_upstream_dot": "šifrirano <0>DNS-over-TLS", - "example_upstream_doh": "šifrirano <0>DNS-over-HTTPS", - "example_upstream_doq": "šifrirano <0>DNS-over-QUIC", - "example_upstream_sdns": "možete koristiti <0>DNS Stamps za <1>DNSCrypt ili <2>DNS-over-HTTPS rezolvere", - "example_upstream_tcp": "zadani DNS (putem TCP)", + "example_meaning_filter_block": "blokira pristup example.org i svim njenim poddomenama;", + "example_meaning_filter_whitelist": "odblokira pristup example.org i svim njenim poddomenama;", + "example_meaning_host_block": "vratiti 127.0.0.1 adresu na example.org domenu (ali ne i poddomene);", + "example_comment": "! Ovdje ide komentar.", + "example_comment_meaning": "samo komentar;", + "example_comment_hash": "# Također komentar.", + "example_regex_meaning": "blokira pristup domenama koje se podudaraju s regularnim izrazom.", + "example_upstream_regular": "zadani DNS (putem UDP);", + "example_upstream_udp": "obični DNS (preko UDP-a, ime hosta);", + "example_upstream_dot": "šifrirano <0>DNS-over-TLS;", + "example_upstream_doh": "šifrirano <0>DNS-over-HTTPS;", + "example_upstream_doq": "šifrirano <0>DNS-over-QUIC (eksperimentalno);", + "example_upstream_sdns": "<0>DNS Stamps za <1>DNSCrypt ili <2>DNS-over-HTTPS rezolvere;", + "example_upstream_tcp": "zadani DNS (putem TCP);", + "example_upstream_tcp_hostname": "obični DNS (preko TCP-a, ime hosta);", "all_lists_up_to_date_toast": "Svi popisi su ažurirani", "updated_upstream_dns_toast": "Uzvodni poslužitelji uspješno su spremljeni", "dns_test_ok_toast": "Odabrani DNS poslužitelji su trenutno aktivni", @@ -275,9 +277,9 @@ "dns_over_https": "DNS-over-HTTPS", "dns_over_tls": "DNS-over-TLS", "dns_over_quic": "DNS-over-QUIC", - "client_id": "ID klijenta", - "client_id_placeholder": "Unesite ID klijenta", - "client_id_desc": "Različiti klijenti mogu se prepoznati pomoću posebnog ID-a klijenta. Ovdje možete saznati više o tome kako prepoznati klijente.", + "client_id": "ClientID", + "client_id_placeholder": "Unesite ClientID", + "client_id_desc": "Različiti klijenti mogu se prepoznati pomoću posebnog ClientID. Ovdje možete saznati više o tome kako prepoznati klijente.", "download_mobileconfig_doh": "Preuzmi .mobileconfig za DNS-over-HTTPS", "download_mobileconfig_dot": "Preuzmi .mobileconfig za DNS-over-TLS", "download_mobileconfig": "Preuzmite konfiguracijsku datoteku", @@ -285,7 +287,7 @@ "form_enter_rate_limit": "Unesite ograničenje", "rate_limit": "Ograničenje", "edns_enable": "Omogući podmrežu klijenta EDNS-a", - "edns_cs_desc": "Pošaljite podmreže klijenata DNS poslužiteljima.", + "edns_cs_desc": "Dodajte opciju EDNS klijentske podmreže (ECS) uzvodnim zahtjevima i zabilježite vrijednosti koje su klijenti poslali u dnevnik upita.", "rate_limit_desc": "Broj zahtjeva u sekundi koji su dopušteni po jednom klijentu. Postavljanje na 0 znači neograničeno.", "blocking_ipv4_desc": "Povratna IP adresa za blokirane A zahtjeve", "blocking_ipv6_desc": "Povratna IP adresa za blokirane AAAA zahtjeve", @@ -334,8 +336,8 @@ "install_devices_router_list_4": "Na nekim se vrstama usmjerivača ne može postaviti prilagođeni DNS poslužitelj. U ovom slučaju, može vam pomoći ako postavite AdGuard Home kao <0>DHCP poslužitelj. U suprotnom, trebali biste potražiti priručnik o tome kako prilagoditi DNS poslužitelje za vaš određeni model routera.", "install_devices_windows_list_1": "Otvorite Upravljačku ploču putem Start izbornika ili Windows pretrage.", "install_devices_windows_list_2": "Idite na kategoriju Mreža i Internet i odaberite Centar za mreže i zajedničko korištenje.", - "install_devices_windows_list_3": "Na lijevoj strani zaslona pronađite \"Promjena postavki prilagodnika\" i kliknite na nju.", - "install_devices_windows_list_4": "Odaberite aktivnu vezu, pritisnite desni klik na nju i odaberite Svojstva.", + "install_devices_windows_list_3": "Na lijevoj strani zaslona kliknite \"Promjena postavki prilagodnika\".", + "install_devices_windows_list_4": "Desnom tipkom miša kliknite svoju aktivnu vezu i odaberite Svojstva.", "install_devices_windows_list_5": "Na popisu pronađite \"Internet Protocol Version 4 (TCP/IPv4)\" (ili, za IPv6, \"Internet Protocol Version 6 (TCP/IPv6)\"), odaberite ga i zatim ponovno kliknite svojstva.", "install_devices_windows_list_6": "Odaberite \"Koristi sljedeće adrese DNS poslužitelja\" i unesite adrese AdGuard Home poslužitelja.", "install_devices_macos_list_1": "Pritisnite na Apple ikonu i idite u Postavke sustava.", @@ -356,7 +358,7 @@ "open_dashboard": "Otvori upravljačku ploču", "install_saved": "Uspješno spremljeno", "encryption_title": "Šifriranje", - "encryption_desc": "Podrška šifriranja (HTTPS/TLS) za DNS i administratorsko web sučelje", + "encryption_desc": "Podrška šifriranja (HTTPS/QUIC/TLS) za DNS i administratorsko web sučelje", "encryption_config_saved": "Konfiguracija šifriranja spremljena", "encryption_server": "Naziv poslužitelja", "encryption_server_enter": "Unesite naziv domene", @@ -367,7 +369,7 @@ "encryption_https_desc": "Ako je HTTPS port postavljen, AdGuard Home administracijsko sučelje biti će dostupno putem HTTPS-a, a također će pružiti DNS-over-HTTPS na '/dns-query' lokaciji.", "encryption_dot": "DNS-over-TLS port", "encryption_dot_desc": "Ako je ovaj port postavljen, AdGuard Home će pokrenuti DNS-over-TLS poslužitelj na ovom portu.", - "encryption_doq": "DNS-over-QUIC port", + "encryption_doq": "DNS-over-QUIC port (eksperimentalno)", "encryption_doq_desc": "Ako je ovaj port postavljen, AdGuard Home će na ovom portu pokrenuti DNS-over-QUIC poslužitelj. Eksperimentalno je i možda nije pouzdano. Također, trenutno nema previše klijenata koji to podržavaju.", "encryption_certificates": "Certifikati", "encryption_certificates_desc": "Da biste koristili šifriranje, za svoju domenu morate osigurati važeći lanac SSL certifikata. Besplatan certifikat možete dobiti na <0>{{link}} ili ga možete kupiti od jednog od pouzdanih izdavatelja certifikata.", @@ -389,7 +391,7 @@ "topline_expiring_certificate": "Vaš SSL certifikat uskoro ističe. Ažurirajte <0>Postavke šifriranja.", "topline_expired_certificate": "Vaš SSL certifikat je istekao. Ažurirajte <0>Postavke šifriranja.", "form_error_port_range": "Unesite broj porta od 80 do 65536", - "form_error_port_unsafe": "Ovo je nesigurna port", + "form_error_port_unsafe": "Nesigurna port", "form_error_equal": "Ne bi trebalo biti jednako", "form_error_password": "Lozinka se ne podudara", "reset_settings": "Poništi postavke", @@ -397,15 +399,16 @@ "setup_guide": "Vodič za postavljanje", "dns_addresses": "DNS adrese", "dns_start": "Pokreće se DNS poslužitelj", - "dns_status_error": "Pogreška pri dohvatu statusa DNS poslužitelja", + "dns_status_error": "Pogreška pri provjeravanju statusa DNS poslužitelja", "down": "Ne radi", "fix": "Popravi", "dns_providers": "Ovo je <0>popis poznatih DNS poslužitelja za izbor.", "update_now": "Ažuriraj sada", "update_failed": "Neuspješno automatsko ažuriranje. Molimo pratite ove korake za ručno ažuriranje.", + "manual_update": "Molimo pratite ove korake za ručno ažuriranje.", "processing_update": "Molimo pričekajte, AdGuard Home se ažurira", - "clients_title": "Klijenti", - "clients_desc": "Postavite uređaje povezane na AdGuard Home", + "clients_title": "Uporni klijenti", + "clients_desc": "Konfigurirajte trajne zapise klijenata za uređaje povezane s AdGuard Home", "settings_global": "Globalno", "settings_custom": "Prilagođeno", "table_client": "Klijent", @@ -416,7 +419,7 @@ "client_edit": "Uredi klijenta", "client_identifier": "Identifikator", "ip_address": "IP adresa", - "client_identifier_desc": "Klijenti se mogu identificirati putem IP adrese, CIDR-a, MAC adrese ili posebnog ID-a klijenta (može se koristiti za DoT/DoH/DoQ). <0>Ovdje možete saznati više o tome kako prepoznati klijente.", + "client_identifier_desc": "Klijenti se mogu identificirati putem IP adrese, CIDR-a, MAC adrese ili posebnog ClientID (može se koristiti za DoT/DoH/DoQ). <0>Ovdje možete saznati više o tome kako prepoznati klijente.", "form_enter_ip": "Unesite IP adresu", "form_enter_subnet_ip": "Unesite IP adresu u podmrežu \"{{cidr}}\"", "form_enter_mac": "Unesite MAC adresu", @@ -431,14 +434,14 @@ "clients_not_found": "Nema pronađenih klijenata", "client_confirm_delete": "Jeste li sigurni da želite ukloniti \"{{key}}\" klijenta?", "list_confirm_delete": "Jeste li sigurni da želite ukloniti ovaj popis?", - "auto_clients_title": "Klijenti (runtime)", - "auto_clients_desc": "Podaci na klijentu koji koriste AdGuard Home, ali se ne spremaju u postavke", + "auto_clients_title": "Runtime klijenti", + "auto_clients_desc": "Podaci na klijentu koji koriste AdGuard Home, ali se ne mijenjaju u postavkama", "access_title": "Postavke pristupa", - "access_desc": "Postavite pravila pristupa za AdGuard Home DNS poslužitelj.", + "access_desc": "Ovdje možete konfigurirati pravila pristupa za AdGuard Home DNS poslužitelj", "access_allowed_title": "Dopušteni klijenti", - "access_allowed_desc": "Popis CIDR-ova, IP adresa ili ID-ova klijenata. Ako je konfiguriran, AdGuard Home prihvatit će zahtjeve samo tih klijenata.", + "access_allowed_desc": "Popis CIDR-ova, IP adresa ili ClientIDs. Ako ovaj popis ima unose, AdGuard Home prihvatit će zahtjeve samo tih klijenata.", "access_disallowed_title": "Nedopušteni klijenti", - "access_disallowed_desc": "Popis CIDR-ova, IP adresa ili ID-ova klijenata. Ako je konfiguriran, AdGuard Home će odbaciti zahtjeve tih klijenata. Ako su konfigurirani dopušteni klijenti, ovo se polje zanemaruje.", + "access_disallowed_desc": "Popis CIDR-ova, IP adresa ili ClientIDs. Ako ovaj popis ima unose, AdGuard Home će odbaciti zahtjeve tih klijenata. Ovo polje se zanemaruje ako postoje unosi u Dopušteni klijenti.", "access_blocked_title": "Nedopuštene domene", "access_blocked_desc": "Ne smije se miješati s filterima. AdGuard Home ispušta DNS upite koji odgovaraju tim domenama, a ti se upiti čak i ne pojavljuju u zapisniku upita. Možete navesti točne nazive domena, zamjenske znakove ili pravila filtriranja URL-a, npr || example.org example.org. example.org^\" u skladu s tim.", "access_settings_saved": "Postavke pristupa su uspješno spremljene", @@ -499,6 +502,7 @@ "interval_days": "{{count}} dan", "interval_days_plural": "{{count}} dana", "domain": "Domena", + "ecs": "ECS", "punycode": "Punycode", "answer": "Odgovor", "filter_added_successfully": "Popis je uspješno dodan", @@ -531,7 +535,7 @@ "netname": "Naziv mreže", "network": "Mreža", "descr": "Opis", - "whois": "Whois", + "whois": "WHOIS", "filtering_rules_learn_more": "<0>Saznajte više o stvaranju vlastitog popisa poslužitelja.", "blocked_by_response": "Blokirano od strane CNAME-a ili IP-a u odgovoru", "blocked_by_cname_or_ip": "Blokirao CNAME ili IP", @@ -551,10 +555,10 @@ "autofix_warning_list": "Izvodi sljedeće radnje: <0>Deaktiviraj DNSStubListener sustav <0>Postavi adresu DNS poslužitelja na 127.0.0.1 <0>Zamijeni simbolički cilj veze iz /etc/resolv.conf u /run/systemd/resolve/resolv.conf <0>Zaustavi DNSStubListener (ponovno pokreni systemd-resolved uslugu)", "autofix_warning_result": "Kao rezultat toga, sve DNS zahtjeve iz vašeg sustava će AdGuard Home obraditi prema zadanim postavkama.", "tags_title": "Oznake", - "tags_desc": "Možete odabrati oznake koje odgovaraju klijentu. Oznake se mogu uključiti u pravila filtriranja i omogućuju vam da ih točnije primijenite. <0>Saznajte više", + "tags_desc": "Možete odabrati oznake koje odgovaraju klijentu. Uključite oznake u pravila filtriranja kako biste ih preciznije primijenili. <0>Saznajte više.", "form_select_tags": "Odaberite oznake klijenta", "check_title": "Provjerite filtriranje", - "check_desc": "Provjerite je li naziv računala filtriran", + "check_desc": "Provjerite je li naziv hosta filtriran.", "check": "Provjeri", "form_enter_host": "Unesite naziv računala", "filtered_custom_rules": "Filtrirano prilagođenim pravilima filtriranja", @@ -597,15 +601,15 @@ "blocklist": "Popis nedopuštenih", "milliseconds_abbreviation": "ms", "cache_size": "Veličina predmemorije", - "cache_size_desc": "Veličina DNS predmemorije (u bajtovima)", + "cache_size_desc": "Veličina DNS predmemorije (u bajtovima).", "cache_ttl_min_override": "Nadjačaj minimum TTL-a", "cache_ttl_max_override": "Nadjačaj maksimum TTL-a", "enter_cache_size": "Unesite veličinu predmemorije (u bajtovima)", "enter_cache_ttl_min_override": "Unesite minimalni TTL (u sekundama)", "enter_cache_ttl_max_override": "Unesite maksimalni TTL (u sekundama)", - "cache_ttl_min_override_desc": "Povećajte kratke vrijednosti TTL-a (u sekundama) primljene od upstream poslužitelja prilikom predmemoriranja DNS odgovora", - "cache_ttl_max_override_desc": "Postavite maksimalnu vrijednost TTL-a (u sekundama) za zapise u DNS predmemoriju", - "ttl_cache_validation": "Minimalna vrijednost TTL predmemorije mora biti manja ili jednaka maksimalnoj vrijednosti", + "cache_ttl_min_override_desc": "Povećajte kratke vrijednosti TTL-a (u sekundama) primljene od upstream poslužitelja prilikom predmemoriranja DNS odgovora.", + "cache_ttl_max_override_desc": "Postavite maksimalnu vrijednost TTL-a (u sekundama) za zapise u DNS predmemoriju.", + "ttl_cache_validation": "Minimalno nadjačavanje TTL-a predmemorije mora biti manje ili jednako maksimalnom", "cache_optimistic": "Optimistično predmemoriranje", "cache_optimistic_desc": "Učinite da AdGuard Home reagira iz predmemorije čak i kada su unosi istekli i pokušajte ih osvježiti.", "filter_category_general": "Općenito", @@ -626,5 +630,6 @@ "use_saved_key": "Korištenje prethodno spremljenog ključa", "parental_control": "Roditeljska zaštita", "safe_browsing": "Sigurno surfanje", - "served_from_cache": "{{value}} (dohvaćeno iz predmemorije)" + "served_from_cache": "{{value}} (dohvaćeno iz predmemorije)", + "form_error_password_length": "Lozinka mora imati najmanje {{value}} znakova" } diff --git a/client/src/__locales/hu.json b/client/src/__locales/hu.json index 5ffa9d15..a47d069c 100644 --- a/client/src/__locales/hu.json +++ b/client/src/__locales/hu.json @@ -35,24 +35,24 @@ "dhcp_config_saved": "DHCP beállítások sikeresen el lettek mentve", "dhcp_ipv4_settings": "DHCP IPv4 Beállítások", "dhcp_ipv6_settings": "DHCP IPv6 Beállítások", - "form_error_required": "Kötelező mező.", - "form_error_ip4_format": "Érvénytelen IPv4 cím.", - "form_error_ip4_range_start_format": "Érvénytelen IPv4-cím a tartomány kezdetéhez.", - "form_error_ip4_range_end_format": "Érvénytelen IPv4-cím a tartomány végén.", - "form_error_ip4_gateway_format": "Az átjáróhoz (gateway) érvénytelen IPv4 cím lett megadva.", - "form_error_ip6_format": "Érvénytelen IPv6 cím.", - "form_error_ip_format": "Érvénytelen IP-cím.", - "form_error_mac_format": "Érvénytelen MAC cím.", - "form_error_client_id_format": "A ClientID (kliens azonosító) csak számokat, kisbetűket és kötőjeleket tartalmazhat.", - "form_error_server_name": "Érvénytelen szervernév.", - "form_error_subnet": "A(z) \"{{cidr}}\" alhálózat nem tartalmazza a(z) \"{{ip}}\" IP címet.", - "form_error_positive": "0-nál nagyobbnak kell lennie.", - "out_of_range_error": "A következő tartományon kívül legyen: \"{{start}}\"-\"{{end}}\".", - "lower_range_start_error": "Kisebb legyen, mint a tartomány kezdete.", - "greater_range_start_error": "Nagyobbnak kell lennie, mint a tartomány kezdete.", - "greater_range_end_error": "Nagyobb legyen, mint a tartomány vége.", - "subnet_error": "A címeknek egy alhálózatban kell lenniük.", - "gateway_or_subnet_invalid": "Az alhálózati maszk érvénytelen.", + "form_error_required": "Kötelező mező", + "form_error_ip4_format": "Érvénytelen IPv4 cím", + "form_error_ip4_range_start_format": "Érvénytelen IPv4-cím a tartomány kezdetéhez", + "form_error_ip4_range_end_format": "Érvénytelen IPv4-cím a tartomány végén", + "form_error_ip4_gateway_format": "Az átjáróhoz (gateway) érvénytelen IPv4 cím lett megadva", + "form_error_ip6_format": "Érvénytelen IPv6 cím", + "form_error_ip_format": "Érvénytelen IP-cím", + "form_error_mac_format": "Érvénytelen MAC cím", + "form_error_client_id_format": "A ClientID (kliens azonosító) csak számokat, kisbetűket és kötőjeleket tartalmazhat", + "form_error_server_name": "Érvénytelen szervernév", + "form_error_subnet": "A(z) \"{{cidr}}\" alhálózat nem tartalmazza a(z) \"{{ip}}\" IP címet", + "form_error_positive": "0-nál nagyobbnak kell lennie", + "out_of_range_error": "A következő tartományon kívül legyen: \"{{start}}\"-\"{{end}}\"", + "lower_range_start_error": "Kisebb legyen, mint a tartomány kezdete", + "greater_range_start_error": "Nagyobbnak kell lennie, mint a tartomány kezdete", + "greater_range_end_error": "Nagyobb legyen, mint a tartomány vége", + "subnet_error": "A címeknek egy alhálózatban kell lenniük", + "gateway_or_subnet_invalid": "Az alhálózati maszk érvénytelen", "dhcp_form_gateway_input": "Átjáró IP", "dhcp_form_subnet_input": "Alhálózati maszk", "dhcp_form_range_title": "IP-címek tartománya", @@ -67,7 +67,7 @@ "dhcp_table_hostname": "Hosztnév", "dhcp_table_expires": "Lejár", "dhcp_warning": "Ha engedélyezni szeretné a DHCP-kiszolgálót, ellenőrizze, hogy nincs-e más aktív DHCP-kiszolgáló a hálózaton, mert ez megszakíthatja a hálózati eszközök internetkapcsolatát.", - "dhcp_error": "Az AdGuard Home nem tudta megállapítani, hogy van-e másik aktív DHCP-szerver a hálózaton.", + "dhcp_error": "Az AdGuard Home nem tudta megállapítani, hogy van-e másik aktív DHCP-szerver a hálózaton", "dhcp_static_ip_error": "A DHCP szerver használatához statikus IP-címet kell beállítani. Nem sikerült meghatározni, hogy ez a hálózati interfész statikus IP-cím használatával van-e beállítva. Állítson be kézzel egy statikus IP-címet.", "dhcp_dynamic_ip_found": "A rendszer dinamikus IP-cím konfigurációt használ az <0>{{interfaceName}} interfészhez. A DHCP szerver használatához statikus IP-címet kell beállítani. Jelenlegi IP-címe: <0>{{ipAddress}}. Automatikusan beállítjuk ezt az IP címet statikusnak, ha rányom a DHCP engedélyezése gombra.", "dhcp_lease_added": "Statikus bérlet \"{{key}}\" sikeresen hozzáadva", @@ -196,8 +196,8 @@ "choose_allowlist": "Engedélyezési lista választás", "enter_valid_blocklist": "Adjon meg egy érvényes URL-t a blokkolási listához.", "enter_valid_allowlist": "Adjon meg egy érvényes URL-t az engedélyezési listához.", - "form_error_url_format": "Érvénytelen URL formátum.", - "form_error_url_or_path_format": "Helytelen URL vagy abszolút elérési útvonal a listához.", + "form_error_url_format": "Érvénytelen URL formátum", + "form_error_url_or_path_format": "Helytelen URL vagy abszolút elérési útvonal a listához", "custom_filter_rules": "Egyéni szűrési szabályok", "custom_filter_rules_hint": "Adjon meg egy szabályt egy sorban. Használhat egyszerű hirdetésblokkolási szabályokat vagy hosztfájl szintaxist.", "system_host_files": "Rendszer hosztfájlok", @@ -210,11 +210,13 @@ "example_comment_hash": "# Ez is egy megjegyzés.", "example_regex_meaning": "blokkolja a hozzáférést azokhoz a domainekhez, amik illeszkednek a megadott reguláris kifejezésre.", "example_upstream_regular": "hagyományos DNS (UDP felett);", + "example_upstream_udp": "normál DNS (UDP felett, hostnév);", "example_upstream_dot": "titkosított <0>DNS-over-TLS;", "example_upstream_doh": "titkosított <0>DNS-over-HTTPS;", "example_upstream_doq": "titkosított <0>DNS-over-QUIC (kísérleti);", "example_upstream_sdns": "<0>DNS Stamps a <1>DNSCrypt vagy <2>DNS-over-HTTPS feloldókhoz;", "example_upstream_tcp": "hagyományos DNS (TCP felett);", + "example_upstream_tcp_hostname": "normál DNS (TCP felett, hostnév);", "all_lists_up_to_date_toast": "Már minden lista naprakész", "updated_upstream_dns_toast": "Upstream szerverek sikeresen mentve", "dns_test_ok_toast": "A megadott DNS-kiszolgálók megfelelően működnek", @@ -259,10 +261,10 @@ "query_log_strict_search": "Használjon \"dupla idézőjelet\" a pontos kereséshez", "query_log_retention_confirm": "Biztos benne, hogy megváltoztatja a kérések naplójának megőrzési idejét? Ha csökkentette az értéket, a megadottnál korábbi adatok elvesznek", "anonymize_client_ip": "Kliens IP-címének anonimizálása", - "anonymize_client_ip_desc": "Ne mentse el a kliens teljes IP-címét a naplókban és a statisztikákban.", + "anonymize_client_ip_desc": "Ne mentse el a kliens teljes IP-címét a naplókban és a statisztikákban", "dns_config": "DNS szerver beállításai", "dns_cache_config": "DNS gyorsítótár beállításai", - "dns_cache_config_desc": "Itt tudja konfigurálni a DNS gyorsítótárat.", + "dns_cache_config_desc": "Itt tudja konfigurálni a DNS gyorsítótárat", "blocking_mode": "Blokkolás módja", "default": "Alapértelmezett", "nxdomain": "NXDOMAIN", @@ -285,7 +287,7 @@ "form_enter_rate_limit": "Adja meg a kérések maximális számát", "rate_limit": "Kérések korlátozása", "edns_enable": "EDNS kliens alhálózat engedélyezése", - "edns_cs_desc": "Ha engedélyezve van, az AdGuard Home a kliensek alhálózatait küldi el a DNS-kiszolgálóknak.", + "edns_cs_desc": "Adja hozzá az EDNS Client Subnet beállítást (ECS) a felfelé irányuló kérésekhez, és naplózza a kliensek által küldött értékeket a lekérdezési naplóban.", "rate_limit_desc": "Maximálisan hány kérést küldhet egy kliens másodpercenkén. Ha 0-ra állítja, akkor nincs korlátozás.", "blocking_ipv4_desc": "A blokkolt A kéréshez visszaadandó IP-cím", "blocking_ipv6_desc": "A blokkolt AAAA kéréshez visszaadandó IP-cím", @@ -309,7 +311,7 @@ "install_settings_listen": "Figyelő felület", "install_settings_port": "Port", "install_settings_interface_link": "Az AdGuard Home webes admin felülete elérhető a következő címe(ke)n:", - "form_error_port": "Adjon meg egy érvényes portot.", + "form_error_port": "Adjon meg egy érvényes portot", "install_settings_dns": "DNS szerver", "install_settings_dns_desc": "Be kell állítania az eszközeit vagy a routerét, hogy használni tudja a DNS szervert a következő címeken:", "install_settings_all_interfaces": "Minden felület", @@ -356,7 +358,7 @@ "open_dashboard": "Irányítópult megnyitása", "install_saved": "Sikeres mentés", "encryption_title": "Titkosítás", - "encryption_desc": "Titkosítás (HTTPS/TLS) támogatása mind a DNS, mind pedig a webes admin felület számára.", + "encryption_desc": "Titkosítás (HTTPS/QUIC/TLS) támogatása mind a DNS, mind pedig a webes admin felület számára", "encryption_config_saved": "Titkosítási beállítások mentve", "encryption_server": "Szerver neve", "encryption_server_enter": "Adja meg az Ön domain címét", @@ -378,26 +380,26 @@ "encryption_key_input": "Másolja ki és illessze be ide a tanúsítványa PEM-kódolt privát kulcsát.", "encryption_enable": "Titkosítás engedélyezése (HTTPS, DNS-over-HTTPS, és DNS-over-TLS)", "encryption_enable_desc": "Ha a titkosítás engedélyezve van, az AdGuard Home admin felülete működik HTTPS-en keresztül, és a DNS szerver is várja a kéréseket DNS-over-HTTPS-en, valamint DNS-over-TLS-en keresztül.", - "encryption_chain_valid": "A tanúsítványlánc érvényes.", - "encryption_chain_invalid": "A tanúsítványlánc érvénytelen.", - "encryption_key_valid": "Ez egy érvényes {{type}} privát kulcs.", - "encryption_key_invalid": "Ez egy érvénytelen {{type}} privát kulcs.", + "encryption_chain_valid": "A tanúsítványlánc érvényes", + "encryption_chain_invalid": "A tanúsítványlánc érvénytelen", + "encryption_key_valid": "Ez egy érvényes {{type}} privát kulcs", + "encryption_key_invalid": "Ez egy érvénytelen {{type}} privát kulcs", "encryption_subject": "Tárgy", "encryption_issuer": "Kibocsátó", "encryption_hostnames": "Hosztnevek", "encryption_reset": "Biztosan visszaállítja a titkosítási beállításokat?", "topline_expiring_certificate": "Az SSL-tanúsítványa hamarosan lejár. Frissítse a <0>Titkosítási beállításokat.", "topline_expired_certificate": "Az SSL-tanúsítványa lejárt. Frissítse a <0>Titkosítási beállításokat.", - "form_error_port_range": "Adjon meg egy portszámot a 80-65535 tartományon belül.", - "form_error_port_unsafe": "Ez a port nem biztonságos.", - "form_error_equal": "Nem egyezhetnek.", - "form_error_password": "A jelszavak nem egyeznek.", + "form_error_port_range": "Adjon meg egy portszámot a 80-65535 tartományon belül", + "form_error_port_unsafe": "Ez a port nem biztonságos", + "form_error_equal": "Nem egyezhetnek", + "form_error_password": "A jelszavak nem egyeznek", "reset_settings": "Beállítások visszaállítása", "update_announcement": "Az AdGuard Home {{version}} verziója elérhető! <0>Kattintson ide további információkért.", "setup_guide": "Beállítási útmutató", "dns_addresses": "DNS címek", "dns_start": "A DNS szerver indul", - "dns_status_error": "Hiba történt a DNS szerver állapotának ellenőrzésekor.", + "dns_status_error": "Hiba történt a DNS szerver állapotának ellenőrzésekor", "down": "Nem elérhető", "fix": "Állandó", "dns_providers": "Itt van az <0>ismert DNS szolgáltatók listája, amelyekből választhat.", @@ -406,7 +408,7 @@ "manual_update": "Kérjük, hogy kövesse ezeket a lépéseket a manuális frissítéshez.", "processing_update": "Kérjük várjon, az AdGuard Home frissítése folyamatban van", "clients_title": "Fenntartott kliensek", - "clients_desc": "Állítsa be az AdGuard Home-ban fenntartott kliens rekordokat az egyes eszközeihez.", + "clients_desc": "Állítsa be az AdGuard Home-ban fenntartott kliens rekordokat az egyes eszközeihez", "settings_global": "Globális", "settings_custom": "Egyéni", "table_client": "Kliens", @@ -433,9 +435,9 @@ "client_confirm_delete": "Biztosan törölni szeretné a(z) \"{{key}}\" klienst?", "list_confirm_delete": "Biztosan törölni kívánja ezt a listát?", "auto_clients_title": "Futási idejű kliensek", - "auto_clients_desc": "Ezek az eszközök nem szerepelnek a fenntartott kliensek listáján, de használják az AdGuard Home-ot.", + "auto_clients_desc": "Ezek az eszközök nem szerepelnek a fenntartott kliensek listáján, de használják az AdGuard Home-ot", "access_title": "Hozzáférési beállítások", - "access_desc": "Itt konfigurálhatja az AdGuard Home DNS-kiszolgáló hozzáférési szabályait.", + "access_desc": "Itt konfigurálhatja az AdGuard Home DNS-kiszolgáló hozzáférési szabályait", "access_allowed_title": "Engedélyezett kliensek", "access_allowed_desc": "CIDR-ek, IP-címek vagy ClientID-k listája. Ha be van állítva, akkor az AdGuard Home csak azokat a lekérdezéseket engedélyezi, amelyek ezektől a kliensektől érkeznek.", "access_disallowed_title": "Nem engedélyezett kliensek", @@ -475,8 +477,8 @@ "dns_rewrites": "DNS átírások", "form_domain": "Adja meg a domain nevet vagy a helyettesítő karaktert", "form_answer": "Adjon meg egy IP-címet vagy egy domain nevet", - "form_error_domain_format": "Érvénytelen domain formátum.", - "form_error_answer_format": "Érvénytelen válasz formátum.", + "form_error_domain_format": "Érvénytelen domain formátum", + "form_error_answer_format": "Érvénytelen válasz formátum", "configure": "Beállítás", "main_settings": "Fő beállítások", "block_services": "Speciális szolgáltatások blokkolása", @@ -500,6 +502,7 @@ "interval_days": "{{count}} nap", "interval_days_plural": "{{count}} nap", "domain": "Domain", + "ecs": "ECS", "punycode": "Punycode", "answer": "Válasz", "filter_added_successfully": "A lista sikeresen hozzá lett adva", @@ -507,7 +510,7 @@ "filter_updated": "A lista sikeresen frissítve lett", "statistics_configuration": "Statisztikai beállítások", "statistics_retention": "Statisztika megőrzése", - "statistics_retention_desc": "Ha csökkenti az intervallum értékét, az előtte levő adatok elvesznek.", + "statistics_retention_desc": "Ha csökkenti az intervallum értékét, az előtte levő adatok elvesznek", "statistics_clear": "Statisztikák visszaállítása", "statistics_clear_confirm": "Biztosan vissza akarja állítani a statisztikákat?", "statistics_retention_confirm": "Biztos benne, hogy megváltoztatja a statisztika megőrzési idejét? Ha csökkentette az értéket, a megadottnál korábbi adatok elvesznek", @@ -606,7 +609,7 @@ "enter_cache_ttl_max_override": "Adja meg a maximális TTL-t (másodpercben)", "cache_ttl_min_override_desc": "Megnöveli a DNS kiszolgálótól kapott rövid TTL értékeket (másodpercben), ha gyorsítótárazza a DNS kéréseket.", "cache_ttl_max_override_desc": "Állítson be egy maximális TTL értéket (másodpercben) a DNS gyorsítótár bejegyzéseihez.", - "ttl_cache_validation": "A minimális gyorsítótár TTL értéknek kisebbnek vagy egyenlőnek kell lennie a maximum értékkel.", + "ttl_cache_validation": "A minimális gyorsítótár TTL értéknek kisebbnek vagy egyenlőnek kell lennie a maximum értékkel", "cache_optimistic": "Optimista gyorsítótár", "cache_optimistic_desc": "Lehetővé teszi, hogy az AdGuard Home a gyorsítótárból válaszoljon, még abban az esetben is, ha az ott lévő bejegyzések lejértak, és próbálja meg frissíteni őket.", "filter_category_general": "Általános", @@ -628,5 +631,5 @@ "parental_control": "Szülői felügyelet", "safe_browsing": "Biztonságos böngészés", "served_from_cache": "{{value}} (gyorsítótárból kiszolgálva)", - "form_error_password_length": "A jelszó legalább {{value}} karakter hosszú kell, hogy legyen." + "form_error_password_length": "A jelszó legalább {{value}} karakter hosszú kell, hogy legyen" } diff --git a/client/src/__locales/id.json b/client/src/__locales/id.json index 58148123..75e87b0d 100644 --- a/client/src/__locales/id.json +++ b/client/src/__locales/id.json @@ -1,7 +1,7 @@ { "client_settings": "Pengaturan klien", - "example_upstream_reserved": "Anda dapat menetapkan DNS upstream <0>untuk domain spesifik", - "example_upstream_comment": "Anda dapat menentukan komentar", + "example_upstream_reserved": "upstream <0>untuk domain spesifik;", + "example_upstream_comment": "komentar.", "upstream_parallel": "Gunakan kueri paralel untuk mempercepat resoluasi dengan menanyakan semua server upstream secara bersamaan", "parallel_requests": "Permintaan paralel", "load_balancing": "Penyeimbang beban", @@ -43,7 +43,7 @@ "form_error_ip6_format": "Alamat IPv6 tidak valid", "form_error_ip_format": "Alamat IP tidak valid", "form_error_mac_format": "Alamat MAC tidak valid", - "form_error_client_id_format": "ID Klien hanya boleh berisi angka, huruf kecil, dan tanda hubung", + "form_error_client_id_format": "ClientID hanya boleh berisi angka, huruf kecil, dan tanda hubung", "form_error_server_name": "Nama server tidak valid", "form_error_subnet": "Subnet \"{{cidr}}\" tidak berisi alamat IP \"{{ip}}\"", "form_error_positive": "Harus lebih dari 0", @@ -67,7 +67,7 @@ "dhcp_table_hostname": "Nama host", "dhcp_table_expires": "Kadaluwarsa", "dhcp_warning": "Jika anda ingin mengaktifkan server DHCP bawaan, pastikan tidak ada server DHCP lain yang aktif. Jika tidak, akan memutus koneksi internet pada perangkat yang telah terhubung!", - "dhcp_error": "AdGuard Home tidak dapat menentukan apakah ada server DHCP aktif lain pada jaringan.", + "dhcp_error": "AdGuard Home tidak dapat menentukan apakah ada server DHCP aktif lain pada jaringan", "dhcp_static_ip_error": "Jika ingin menggunakan server DHCP, alamat IP statis harus diatur. AdGuard Home gagal menentukan jika antarmuka jaringan ini dikonfigurasi menggunakan alamat IP statis. Silakan atur alamat IP statis secara manual.", "dhcp_dynamic_ip_found": "Sistem Anda menggunakan konfigurasi alamat IP dinamis untuk antarmuka <0>{{interfaceName}}. Untuk menggunakan server DHCP, alamat IP statis harus ditetapkan. Alamat IP Anda saat ini adalah <0>{{ipAddress}}. AdGuard Home akan secara otomatis menetapkan alamat IP ini sebagai statis jika Anda menekan tombol Aktifkan DHCP.", "dhcp_lease_added": "Static lease \"{{key}}\" berhasil ditambahkan", @@ -202,19 +202,21 @@ "custom_filter_rules_hint": "Masukkan satu aturan dalam sebuah baris. Anda dapat menggunakan baik aturan adblock maupun sintaks file hosts.", "system_host_files": "File host sistem", "examples_title": "Contoh", - "example_meaning_filter_block": "Blokir akses ke example.org dan seluruh subdomainnya", - "example_meaning_filter_whitelist": "Buka blokir akses ke domain example.orf dan seluruh subdomainnya", - "example_meaning_host_block": "AdGuard Home sekarang akan mengembalikan alamat 127.0.0.1 untuk domain example.org (namun tidak subdomainnya)", - "example_comment": "! Komentar di sini", - "example_comment_meaning": "hanya sebuah komentar", - "example_comment_hash": "Juga sebuah komentar", - "example_regex_meaning": "blokir akses ke domain yang cocok dengan <0>ekspresi reguler yang ditentukan", - "example_upstream_regular": "DNS reguler (melalui UDP)", - "example_upstream_dot": "terenkripsi <0>DNS-over-TLS", - "example_upstream_doh": "terenkripsi <0>DNS-over-HTTPS", - "example_upstream_doq": "terenkripsi <0>DNS-over-QUIC", - "example_upstream_sdns": "anda bisa menggunakan <0>Stempel DNS untuk <1>DNSCrypt atau pengarah <2>DNS-over-HTTPS", - "example_upstream_tcp": "DNS reguler (melalui TCP)", + "example_meaning_filter_block": "blokir akses ke example.org dan seluruh subdomainnya;", + "example_meaning_filter_whitelist": "buka blokir akses ke domain example.orf dan seluruh subdomainnya;", + "example_meaning_host_block": "merespons dengan 127.0.0.1 untuk example.org (tetapi tidak untuk subdomainnya);", + "example_comment": "! Komentar di sini.", + "example_comment_meaning": "hanya sebuah komentar;", + "example_comment_hash": "# Juga sebuah komentar.", + "example_regex_meaning": "blokir akses ke domain yang cocok dengan ekspresi reguler yang ditentukan.", + "example_upstream_regular": "DNS reguler (melalui UDP);", + "example_upstream_udp": "DNS biasa (lebih dari UDP, nama host);", + "example_upstream_dot": "terenkripsi <0>DNS-over-TLS;", + "example_upstream_doh": "terenkripsi <0>DNS-over-HTTPS;", + "example_upstream_doq": "terenkripsi <0>DNS-over-QUIC (eksperimental);", + "example_upstream_sdns": "<0>Stempel DNS untuk <1>DNSCrypt atau pengarah <2>DNS-over-HTTPS;", + "example_upstream_tcp": "DNS reguler (melalui TCP);", + "example_upstream_tcp_hostname": "DNS biasa (lebih dari TCP, nama host);", "all_lists_up_to_date_toast": "Semua daftar sudah diperbarui", "updated_upstream_dns_toast": "Server upstream berhasil disimpan", "dns_test_ok_toast": "Server DNS yang ditentukan bekerja dengan benar", @@ -275,9 +277,9 @@ "dns_over_https": "DNS-over-HTTPS", "dns_over_tls": "DNS-over-TLS", "dns_over_quic": "DNS-over-QUIC", - "client_id": "ID Klien", - "client_id_placeholder": "Masukkan ID klien", - "client_id_desc": "Klien yang berbeda dapat diidentifikasi dengan ID klien khusus. Di sini Anda dapat mempelajari lebih lanjut tentang cara mengidentifikasi klien.", + "client_id": "ClientID", + "client_id_placeholder": "Masukkan ClientID", + "client_id_desc": "Klien dapat diidentifikasi oleh ClientID. Pelajari lebih lanjut tentang cara mengidentifikasi klien di sini.", "download_mobileconfig_doh": "Unduh .mobileconfig untuk DNS-over-HTTPS", "download_mobileconfig_dot": "Unduh .mobileconfig untuk DNS-over-TLS", "download_mobileconfig": "Unduh berkas konfigurasi", @@ -285,7 +287,7 @@ "form_enter_rate_limit": "Masukkan batas nilai", "rate_limit": "Batas nilai", "edns_enable": "Aktifkan EDNS Klien Subnet", - "edns_cs_desc": "Kirim subnet klien ke server DNS.", + "edns_cs_desc": "Tambahkan opsi EDNS Client Subnet (ECS) ke permintaan upstream dan catat nilai yang dikirim oleh klien di log kueri.", "rate_limit_desc": "Jumlah permintaan per detik yang diperbolehkan untuk satu klien. Atur ke 0 untuk tidak terbatas.", "blocking_ipv4_desc": "Alamat IP akan dikembalikan untuk permintaan A yang diblokir", "blocking_ipv6_desc": "Alamat IP akan dipulihkan untuk permintaan AAAA yang diblokir", @@ -334,12 +336,12 @@ "install_devices_router_list_4": "Anda tidak dapat menyetel server DNS kustom pada beberapa tipe router. Dalam hal ini mungkin membantu jika Anda mengatur AdGuard Home sebagai <0>server DHCP. Jika tidak, Anda harus mencari petunjuk tentang cara mengkustomisasi server DNS untuk model router khusus Anda.", "install_devices_windows_list_1": "Buka Panel Kontrol melalui menu Start atau pencarian Windows.", "install_devices_windows_list_2": "Masuk ke kategori Jaringan dan Internet (Network and Internet) dan kemudian ke Pusat Jaringan dan Berbagi (Network and Sharing Center).", - "install_devices_windows_list_3": "Di sisi kiri layar temukan \"Ubah pengaturan adaptor\" dan klik di atasnya.", - "install_devices_windows_list_4": "Pilih koneksi aktif Anda, klik kanan padanya dan pilih Properties.", + "install_devices_windows_list_3": "Di panel kiri, klik \"Ubah pengaturan adaptor\".", + "install_devices_windows_list_4": "Klik kanan koneksi aktif Anda dan pilih Properties.", "install_devices_windows_list_5": "Temukan \"Internet Protocol Version 4 (TCP/IPv4)\" (atau, untuk IPv6, \"Internet Protocol Version 6 (TCP/IPv6)\") dalam daftar, pilih dan kemudian klik Properties lagi.", "install_devices_windows_list_6": "Pilih \"Gunakan alamat server DNS berikut\" dan masukkan alamat server Beranda AdGuard Anda.", - "install_devices_macos_list_1": "Klik pada ikon Apple dan pergi ke System Preferences.", - "install_devices_macos_list_2": "Klik pada Jaringan (Network)", + "install_devices_macos_list_1": "Klik ikon Apple dan pergi ke System Preferences.", + "install_devices_macos_list_2": "Klik Network.", "install_devices_macos_list_3": "Pilih koneksi pertama dalam daftar dan klik Advanced.", "install_devices_macos_list_4": "Pilih tab DNS dan masukkan alamat server AdGuard Anda.", "install_devices_android_list_1": "Dari layar beranda Menu Android, ketuk Pengaturan.", @@ -356,7 +358,7 @@ "open_dashboard": "Buka Beranda", "install_saved": "Berhasil disimpan", "encryption_title": "Enkripsi", - "encryption_desc": "Enkripsi (HTTPS / TLS) untuk DNS dan antarmuka admin", + "encryption_desc": "Enkripsi (HTTPS/QUIC/TLS) untuk DNS dan antarmuka admin", "encryption_config_saved": "Pengaturan enkripsi telah tersimpan", "encryption_server": "Nama server", "encryption_server_enter": "Masukkan nama domain anda", @@ -367,7 +369,7 @@ "encryption_https_desc": "Jika port HTTPS dikonfigurasi, antarmuka admin Home AdGuard akan dapat diakses melalui HTTPS, dan itu juga akan memberikan DNS-over-HTTPS di lokasi '/ dns-query'.", "encryption_dot": "Port DNS-over-TLS", "encryption_dot_desc": "Jika port ini terkonfigurasi, AdGuard Home akan menjalankan server DNS-over-TLS dalam port ini", - "encryption_doq": "Port DNS-lewat-QUIC", + "encryption_doq": "Port DNS-over-QUIC (eksperimental)", "encryption_doq_desc": "Jika port ini diatur secara sepesifik, AdGuard Home akan menjalankan server DNS-lewat-QUIC pada port ini. Ini adalah eksperimental dan mungkin tidak dapat diandalkan. Juga, tidak banyak klien yang mendukungnya saat ini.", "encryption_certificates": "Sertifikat", "encryption_certificates_desc": "Untuk menggunakan enkripsi, Anda perlu memberikan rantai sertifikat SSL yang valid untuk domain Anda. Anda bisa mendapatkan sertifikat gratis di <0>{{link}} atau Anda dapat membelinya dari salah satu Otoritas Sertifikat tepercaya.", @@ -403,9 +405,10 @@ "dns_providers": "Berikut adalah <0>daftar penyedia DNS yang dikenal untuk dipilih.", "update_now": "Perbarui sekarang", "update_failed": "Pembaruan otomatis gagal. Silahkan ikuti petunjuk ini untuk perbarui secara manual.", + "manual_update": "Silakan mengikuti langkah berikut untuk memperbarui secara manual.", "processing_update": "Silahkan tunggu, AdGuard Home sedang diperbarui", - "clients_title": "Klien", - "clients_desc": "Atur perangkat yang terhubung ke AdGuard Home", + "clients_title": "Klien yang gigih", + "clients_desc": "Konfigurasikan catatan klien persisten untuk perangkat yang terhubung ke AdGuard Home", "settings_global": "Global", "settings_custom": "Kustom", "table_client": "Klien", @@ -416,7 +419,7 @@ "client_edit": "Ubah Klien", "client_identifier": "Identifikasi", "ip_address": "Alamat IP", - "client_identifier_desc": "Klien dapat diidentifikasi oleh alamat IP, CIDR, alamat MAC atau ID klien khusus (dapat digunakan untuk DoT/DoH/DoQ). <0>Di sini Anda dapat mempelajari lebih lanjut tentang cara mengidentifikasi klien.", + "client_identifier_desc": "Klien dapat diidentifikasi oleh alamat IP, CIDR, alamat MAC atau ClientID (dapat digunakan untuk DoT/DoH/DoQ). <0>Di sini Anda dapat mempelajari lebih lanjut tentang cara mengidentifikasi klien.", "form_enter_ip": "Masukkan IP", "form_enter_subnet_ip": "Masukkan alamat IP di subnet \"{{cidr}}\"", "form_enter_mac": "Masukkan MAC", @@ -432,13 +435,13 @@ "client_confirm_delete": "Apakah anda yakin ingin menghapus klien \"{{key}}\"?", "list_confirm_delete": "Anda yakin ingin menghapus daftar ini?", "auto_clients_title": "Klien (waktu berjalan)", - "auto_clients_desc": "Data pada klien yang menggunakan AdGuard Home, tetapi tidak disimpan dalam konfigurasi", + "auto_clients_desc": "Perangkat yang tidak ada dalam daftar klien Persisten yang mungkin masih menggunakan AdGuard Home", "access_title": "Pengaturan akses", - "access_desc": "Disini anda dapat mengatur aturan akses untuk server AdGuard Home DNS.", + "access_desc": "Disini anda dapat mengatur aturan akses untuk server AdGuard Home DNS", "access_allowed_title": "Klien yang diizinkan", - "access_allowed_desc": "Daftar CIDR, alamat IP, atau ID klien. Jika dikonfigurasi, AdGuard Home hanya akan menerima permintaan dari klien ini.", + "access_allowed_desc": "Daftar CIDR, alamat IP, atau ClientID. Jika daftar ini memiliki entri, AdGuard Home hanya akan menerima permintaan dari klien ini.", "access_disallowed_title": "Klien yang tidak diizinkan", - "access_disallowed_desc": "Daftar CIDR, alamat IP, atau ID klien. Jika dikonfigurasi, AdGuard Home akan menghapus permintaan dari klien ini. Jika klien yang diizinkan dikonfigurasi, bidang ini diabaikan.", + "access_disallowed_desc": "Daftar CIDR, alamat IP, atau ClientID. Jika daftar ini memiliki entri, AdGuard Home akan membatalkan permintaan dari klien ini. Bidang ini diabaikan jika ada entri di klien yang diizinkan.", "access_blocked_title": "Domain yang diblokir", "access_blocked_desc": "Jangan bingung dengan filter. AdGuard Home menghapus kueri DNS yang cocok dengan domain ini, dan kueri ini bahkan tidak muncul di log kueri. Anda dapat menentukan nama domain, karakter pengganti, atau aturan filter URL yang tepat, mis. \"example.org\", \"*.example.org\", atau \"||example.org^\" yang sesuai.", "access_settings_saved": "Pengaturan akses berhasil disimpan", @@ -474,7 +477,7 @@ "dns_rewrites": "DNS rewrite", "form_domain": "Masukkan nama domain", "form_answer": "Masaukan alamat IP atau nama domain", - "form_error_domain_format": "Nama domain tidak valid", + "form_error_domain_format": "Format domain tidak valid", "form_error_answer_format": "Format jawaban tidak valid", "configure": "Konfigurasi", "main_settings": "Pengaturan utama", @@ -499,6 +502,7 @@ "interval_days": "{{count}} hari", "interval_days_plural": "{{count}} hari", "domain": "Domain", + "ecs": "ECS", "punycode": "Kode kecil", "answer": "Jawab", "filter_added_successfully": "Filter telah berhasil ditambahkan", @@ -531,7 +535,7 @@ "netname": "Nama jaringan", "network": "Jaringan", "descr": "Deskripsi", - "whois": "Whois", + "whois": "WHOIS", "filtering_rules_learn_more": "<0>Pelajari lebih lanjut tentang membuat daftar hitam host Anda sendiri.", "blocked_by_response": "Diblokir oleh CNAME atau IP sebagai respon", "blocked_by_cname_or_ip": "Diblokir oleh CNAME atau IP", @@ -551,10 +555,10 @@ "autofix_warning_list": "Ini akan melakukan tugas berikut: <0>Nonaktifkan sistem DNSStubListener <0> Atur alamat server DNS ke 127.0.0.1 <0>Ganti target tautan simbolis /etc/resolv.conf pakai /run/systemd/resolve/resolv.conf <0>Hentikan DNSStubListener (muat ulang layanan sistemd-resolve service)", "autofix_warning_result": "Hasilnya, semua permintaan DNS dari sistem anda akan diproses oleh AdGuardHome secara standar.", "tags_title": "Tag", - "tags_desc": "Anda dapat memilih tag sesuai dengan klien. Tag dapat dimasukkan dalam aturan pemfilteran dan memungkinkan Anda untuk menerapkannya lebih akurat. <0>Pelajari lebih", + "tags_desc": "Anda dapat memilih tag sesuai dengan klien. Tag dapat dimasukkan dalam aturan pemfilteran dan memungkinkan Anda untuk menerapkannya lebih akurat. <0>Pelajari lebih.", "form_select_tags": "Pilih tag klien", "check_title": "Periksa penyaringan", - "check_desc": "Periksa apakah nama host telah tersaring", + "check_desc": "Periksa apakah nama host telah tersaring.", "check": "Periksa", "form_enter_host": "Masukkan nama host", "filtered_custom_rules": "Tersaring oleh aturan penyaring Buatan", @@ -593,18 +597,18 @@ "allowed": "Dibolehkan", "filtered": "Tersaring", "rewritten": "Tulis ulang", - "safe_search": "Aktifkan Pencarian Aman", + "safe_search": "Pencarian aman", "blocklist": "Daftar blokir", "milliseconds_abbreviation": "ms", "cache_size": "Ukuran cache", - "cache_size_desc": "Ukuran DNS cache (dalam bit)", + "cache_size_desc": "Ukuran DNS cache (dalam bit).", "cache_ttl_min_override": "Tumpuk TTL minimum", "cache_ttl_max_override": "Tumpuk TTL maksimum", "enter_cache_size": "Masukkan ukuran cache (bytes)", "enter_cache_ttl_min_override": "Masukkan TTL minimum (detik)", "enter_cache_ttl_max_override": "Masukkan TTL maksimum (detik)", - "cache_ttl_min_override_desc": "Perpanjang nilai waktu-online singkat (detik) yang diterima dari server upstream saat menyimpan respons DNS", - "cache_ttl_max_override_desc": "Tetapkan nilai waktu-online maksimum (detik) untuk entri di cache DNS", + "cache_ttl_min_override_desc": "Perpanjang nilai waktu-online singkat (detik) yang diterima dari server upstream saat menyimpan respons DNS.", + "cache_ttl_max_override_desc": "Tetapkan nilai waktu-online maksimum (detik) untuk entri di cache DNS.", "ttl_cache_validation": "Nilai TTL cache minimum harus kurang dari atau sama dengan nilai maksimum", "cache_optimistic": "Caching yang optimis", "cache_optimistic_desc": "Buat AdGuard Home merespons dari cache bahkan ketika entri telah kedaluwarsa dan juga mencoba untuk menyegarkannya.", @@ -626,5 +630,6 @@ "use_saved_key": "Gunakan kunci yang disimpan sebelumnya", "parental_control": "Kontrol Orang Tua", "safe_browsing": "Penjelajahan Aman", - "served_from_cache": "{{value}} (disajikan dari cache)" + "served_from_cache": "{{value}} (disajikan dari cache)", + "form_error_password_length": "Kata sandi harus minimal {{value}} karakter" } diff --git a/client/src/__locales/it.json b/client/src/__locales/it.json index fd560562..cd499740 100644 --- a/client/src/__locales/it.json +++ b/client/src/__locales/it.json @@ -35,24 +35,24 @@ "dhcp_config_saved": "Salvataggio configurazione server DHCP riuscito", "dhcp_ipv4_settings": "Impostazioni DHCP IPv4", "dhcp_ipv6_settings": "Impostazioni DHCP IPv6", - "form_error_required": "Campo richiesto.", - "form_error_ip4_format": "Indirizzo IPv4 non valido.", - "form_error_ip4_range_start_format": "Indirizzo IPV4 non valido dell'intervallo iniziale.", - "form_error_ip4_range_end_format": "Indirizzo IPV4 non valido dell'intervallo finale.", - "form_error_ip4_gateway_format": "Indirizzo gateway IPv4 non valido.", - "form_error_ip6_format": "Indirizzo IPv6 non valido.", - "form_error_ip_format": "Indirizzo IP non valido.", - "form_error_mac_format": "Indirizzo MAC non valido.", - "form_error_client_id_format": "Il ClientID deve contenere solo numeri, lettere minuscole, e trattini.", - "form_error_server_name": "Nome server non valido.", - "form_error_subnet": "Il subnet \"{{cidr}}\" non contiene l'indirizzo IP \"{{ip}}\".", - "form_error_positive": "Deve essere maggiore di 0.", - "out_of_range_error": "Deve essere fuori intervallo \"{{start}}\"-\"{{end}}\".", - "lower_range_start_error": "Deve essere inferiore dell'intervallo di inizio.", - "greater_range_start_error": "Deve essere maggiore dell'intervallo di inizio.", - "greater_range_end_error": "Deve essere maggiore dell'intervallo di fine.", - "subnet_error": "Gli indirizzi devono trovarsi in una sottorete.", - "gateway_or_subnet_invalid": "Maschera di sottorete non valida.", + "form_error_required": "Campo richiesto", + "form_error_ip4_format": "Indirizzo IPv4 non valido", + "form_error_ip4_range_start_format": "Indirizzo IPV4 non valido dell'intervallo iniziale", + "form_error_ip4_range_end_format": "Indirizzo IPV4 non valido dell'intervallo finale", + "form_error_ip4_gateway_format": "Indirizzo gateway IPv4 non valido", + "form_error_ip6_format": "Indirizzo IPv6 non valido", + "form_error_ip_format": "Indirizzo IP non valido", + "form_error_mac_format": "Indirizzo MAC non valido", + "form_error_client_id_format": "Il ClientID deve contenere solo numeri, lettere minuscole, e trattini", + "form_error_server_name": "Nome server non valido", + "form_error_subnet": "Il subnet \"{{cidr}}\" non contiene l'indirizzo IP \"{{ip}}\"", + "form_error_positive": "Deve essere maggiore di 0", + "out_of_range_error": "Deve essere fuori intervallo \"{{start}}\"-\"{{end}}\"", + "lower_range_start_error": "Deve essere inferiore dell'intervallo di inizio", + "greater_range_start_error": "Deve essere maggiore dell'intervallo di inizio", + "greater_range_end_error": "Deve essere maggiore dell'intervallo di fine", + "subnet_error": "Gli indirizzi devono trovarsi in una sottorete", + "gateway_or_subnet_invalid": "Maschera di sottorete non valida", "dhcp_form_gateway_input": "IP Gateway", "dhcp_form_subnet_input": "Maschera di sottorete", "dhcp_form_range_title": "Intervallo di indirizzi IP", @@ -67,7 +67,7 @@ "dhcp_table_hostname": "Nome host", "dhcp_table_expires": "Scaduto", "dhcp_warning": "Se desideri attivare il server DHCP integrato, assicurati che non vi siano altri server DHCP attivi, ciò potrebbe causare problemi di connessione alla rete per i dispositivi collegati!", - "dhcp_error": "AdGuard Home non può determinare se è presente un altro server DHCP attivo nella rete.", + "dhcp_error": "AdGuard Home non può determinare se è presente un altro server DHCP attivo nella rete", "dhcp_static_ip_error": "Per utilizzare il server DHCP è necessario impostare un indirizzo IP statico. AdGuard Home non è riuscito a determinare se questa interfaccia di rete è configurata utilizzando un indirizzo IP statico. Ti preghiamo di impostare manualmente un indirizzo IP statico.", "dhcp_dynamic_ip_found": "Il tuo sistema utilizza una configurazione di indirizzi IP dinamici per l'interfaccia <0>{{interfaceName}}. Per poter utilizzare un server DHCP, è necessario impostare un indirizzo IP statico. Il tuo indirizzo IP attuale è <0>{{ipAddress}}. AdGuard Home imposterà automaticamente questo indirizzo come statico quando cliccherai il pulsante \"Attiva server DHCP\".", "dhcp_lease_added": "Lease statici \"{{key}}\" aggiunti correttamente", @@ -196,8 +196,8 @@ "choose_allowlist": "Scegli liste bianche", "enter_valid_blocklist": "Inserisci un URL valido alla lista nera.", "enter_valid_allowlist": "Inserisci un URL valido alla lista bianca.", - "form_error_url_format": "Formato URL non valido.", - "form_error_url_or_path_format": "URL o percorso assoluto dell'elenco non validi.", + "form_error_url_format": "Formato URL non valido", + "form_error_url_or_path_format": "URL o percorso assoluto dell'elenco non validi", "custom_filter_rules": "Regole filtri personalizzate", "custom_filter_rules_hint": "Inserisci una regola per riga. Puoi utilizzare la sintassi delle regole blocca-annunci o quelle dei file hosts.", "system_host_files": "File host di sistema", @@ -209,12 +209,14 @@ "example_comment_meaning": "solo un commento;", "example_comment_hash": "# Anche un commento.", "example_regex_meaning": "blocca l'accesso ai domini corrispondenti alla specifica espressione regolare.", - "example_upstream_regular": "DNS regolari (tramite UDP);", + "example_upstream_regular": "DNS regolare (over UDP);", + "example_upstream_udp": "DNS regolare (over UDP, nome host);", "example_upstream_dot": "<0>DNS su TLS crittografato;", "example_upstream_doh": "<0>DNS su HTTPS crittografato;", "example_upstream_doq": "<0>DNS su QUIC crittografato (sperimentale);", "example_upstream_sdns": "<0>DNS Stamps per <1>DNSCrypt oppure i risolutori <2>DNS su HTTPS;", - "example_upstream_tcp": "DNS regolari (tramite TCP);", + "example_upstream_tcp": "DNS regolare (over TCP);", + "example_upstream_tcp_hostname": "DNS regolare (over TCP, nome host);", "all_lists_up_to_date_toast": "Tutti gli elenchi sono aggiornati", "updated_upstream_dns_toast": "I server upstream sono stati salvati correttamente", "dns_test_ok_toast": "I server DNS specificati funzionano correttamente", @@ -259,10 +261,10 @@ "query_log_strict_search": "Utilizzare le doppie virgolette per una ricerca precisa", "query_log_retention_confirm": "Sei sicuro di voler modificare il registro delle richieste? Se il valore di intervallo dovesse diminuire, alcuni dati andranno persi", "anonymize_client_ip": "Anonimizza client IP", - "anonymize_client_ip_desc": "Non salvare l'indirizzo IP completo del client nel registro o nelle statistiche.", + "anonymize_client_ip_desc": "Non salvare l'indirizzo IP completo del client nel registro o nelle statistiche", "dns_config": "Configurazione server DNS", "dns_cache_config": "Configurazione cache DNS", - "dns_cache_config_desc": "Qui puoi configurare la cache DNS.", + "dns_cache_config_desc": "Qui puoi configurare la cache DNS", "blocking_mode": "Modalità di blocco", "default": "Predefinito", "nxdomain": "NXDOMAIN", @@ -285,7 +287,7 @@ "form_enter_rate_limit": "Imposta limite delle richieste", "rate_limit": "Limite delle richieste", "edns_enable": "Attiva client di sottorete EDNS", - "edns_cs_desc": "Invia le sottoreti dei client ai server DNS.", + "edns_cs_desc": "Aggiunge l'opzione EDNS Client Subnet (ECS) alle richieste upstream e registra i valori inviati dai client nel registro delle richieste.", "rate_limit_desc": "Il numero di richieste al secondo consentite da un singolo client. Impostare questo valore a 0 rimuove le limitazioni.", "blocking_ipv4_desc": "Indirizzo IP per una richiesta DNS IPv4 bloccata", "blocking_ipv6_desc": "Indirizzo IP restituito per una richiesta DNS IPv6 bloccata", @@ -309,7 +311,7 @@ "install_settings_listen": "Interfaccia d'ascolto", "install_settings_port": "Porta", "install_settings_interface_link": "La tua interfaccia web di amministrazione di AdGuard Home sarà disponibile ai seguenti indirizzi:", - "form_error_port": "Immettere un valore di porta valido.", + "form_error_port": "Immettere un valore di porta valido", "install_settings_dns": "Server DNS", "install_settings_dns_desc": "Sarà necessario configurare i dispositivi o il router per utilizzare il server DNS nei seguenti indirizzi:", "install_settings_all_interfaces": "Tutte le interfacce", @@ -356,7 +358,7 @@ "open_dashboard": "Apri pannello di controllo", "install_saved": "Salvataggio riuscito", "encryption_title": "crittografia", - "encryption_desc": "Supporto alla crittografia (HTTPS / TLS) per DNS ed interfaccia web amministrazione.", + "encryption_desc": "Supporto alla crittografia (HTTPS/QUIC/TLS) per DNS ed interfaccia web di amministrazione", "encryption_config_saved": "Configurazione crittografia salvata", "encryption_server": "Nome server", "encryption_server_enter": "Inserisci il tuo nome di dominio", @@ -378,26 +380,26 @@ "encryption_key_input": "Copia/Incolla qui la tua chiave privata codificata PEM per il tuo certificato.", "encryption_enable": "Attiva crittografia (HTTPS, DNS su HTTPS e DNS su TLS)", "encryption_enable_desc": "Se la crittografia è attiva, l'interfaccia di amministrazione di AdGuard Home funzionerà su HTTPS e il server DNS ascolterà le richieste su DNS su HTTPS e DNS su TLS.", - "encryption_chain_valid": "La catena di certificati è valida.", - "encryption_chain_invalid": "La catena di certificati non è valida.", - "encryption_key_valid": "Questa è una chiave privata {{type}} valida.", - "encryption_key_invalid": "Questa è una chiave privata {{type}} non valida.", + "encryption_chain_valid": "La catena di certificati è valida", + "encryption_chain_invalid": "La catena di certificati non è valida", + "encryption_key_valid": "Questa è una chiave privata {{type}} valida", + "encryption_key_invalid": "Questa è una chiave privata {{type}} non valida", "encryption_subject": "Soggetto", "encryption_issuer": "Emittente", "encryption_hostnames": "Nomi host", "encryption_reset": "Sei sicuro di voler ripristinare le impostazioni di crittografia?", "topline_expiring_certificate": "Il tuo certificato SSL sta per scadere. Aggiorna le<0> Impostazioni di crittografia .", "topline_expired_certificate": "Il tuo certificato SSL è scaduto. Aggiorna le <0> Impostazioni di crittografia .", - "form_error_port_range": "Immettere il valore della porta nell'intervallo 80-65535.", - "form_error_port_unsafe": "Questa è una porta non sicura.", - "form_error_equal": "Non deve essere uguale.", - "form_error_password": "Password non corrispondente.", + "form_error_port_range": "Immettere il valore della porta nell'intervallo 80-65535", + "form_error_port_unsafe": "Questa porta non è sicura", + "form_error_equal": "Non deve essere uguale", + "form_error_password": "Password non corrispondente", "reset_settings": "Reimposta impostazioni", "update_announcement": "AdGuard Home {{version}} è ora disponibile! <0>Clicca qui per più informazioni.", "setup_guide": "Configurazione guidata", "dns_addresses": "Indirizzo DNS", "dns_start": "Il server DNS si sta avviando", - "dns_status_error": "Errore nel recupero dello stato del server DNS.", + "dns_status_error": "Errore nel recupero dello stato del server DNS", "down": "Spenta", "fix": "Risolvi", "dns_providers": "Qui c'è un <0>elenco di fornitori DNS noti da cui scegliere.", @@ -406,7 +408,7 @@ "manual_update": "Ti invitiamo a seguire questi passaggi per aggiornare manualmente.", "processing_update": "Perfavore aspetta, AdGuard Home si sta aggiornando", "clients_title": "Client persistenti", - "clients_desc": "Configura le registrazioni dei client persistenti per i dispositivi connessi ad AdGuard Home.", + "clients_desc": "Configura le registrazioni dei client persistenti per i dispositivi connessi ad AdGuard Home", "settings_global": "Globale", "settings_custom": "Personalizzato", "table_client": "Client", @@ -433,9 +435,9 @@ "client_confirm_delete": "Sei sicuro di voler eliminare il client \"{{key}}\"?", "list_confirm_delete": "Sei sicuro di voler eliminare questo elenco?", "auto_clients_title": "Client in tempo reale", - "auto_clients_desc": "Dispositivi non presenti nell'elenco dei client Persistenti che possono ancora utilizzare AdGuard Home.", + "auto_clients_desc": "Dispositivi non presenti nell'elenco dei client Persistenti che possono ancora utilizzare AdGuard Home", "access_title": "Impostazioni di accesso", - "access_desc": "Qui puoi configurare le regole d'accesso per il server DNS di AdGuard Home.", + "access_desc": "Qui puoi configurare le regole d'accesso per il server DNS di AdGuard Home", "access_allowed_title": "Client permessi", "access_allowed_desc": "Un elenco di CIDR, indirizzi IP, o ClientID. Se l'elenco conterrà elementi, AdGuard Home accetterà richieste solo da questi client.", "access_disallowed_title": "Client non permessi", @@ -475,8 +477,8 @@ "dns_rewrites": "Riscrittura DNS", "form_domain": "Inserisci il dominio", "form_answer": "Inserisci l'indirizzo IP o il nome del dominio", - "form_error_domain_format": "Formato del dominio non valido.", - "form_error_answer_format": "Formato di risposta non valido.", + "form_error_domain_format": "Formato del dominio non valido", + "form_error_answer_format": "Formato di risposta non valido", "configure": "Configura", "main_settings": "Impostazioni principali", "block_services": "Blocca servizi specifici", @@ -500,6 +502,7 @@ "interval_days": "{{count}} giorni", "interval_days_plural": "{{count}} giorni", "domain": "Dominio", + "ecs": "ECS", "punycode": "Punycode", "answer": "Risposta", "filter_added_successfully": "L'elenco è stato aggiunto correttamente", @@ -507,7 +510,7 @@ "filter_updated": "L'elenco è stato aggiornato correttamente", "statistics_configuration": "Configurazione delle statistiche", "statistics_retention": "Conservazione delle statistiche", - "statistics_retention_desc": "Se dovessi diminuire il valore di intervallo, alcuni dati andranno persi.", + "statistics_retention_desc": "Se dovessi diminuire il valore di intervallo, alcuni dati andranno persi", "statistics_clear": "Azzera statistiche", "statistics_clear_confirm": "Sei sicuro di voler azzerare le statistiche?", "statistics_retention_confirm": "Sei sicuro di voler modificare la conservazione delle statistiche? Se il valore di intervallo dovesse diminuire, alcuni dati andranno persi", @@ -517,7 +520,7 @@ "interval_hours_plural": "{{count}} ore", "filters_configuration": "Configurazione filtri", "filters_enable": "Attiva i filtri", - "filters_interval": "Intervallo aggiornamento filtri", + "filters_interval": "Intervallo aggiornamento filtro", "disabled": "Disattivato", "username_label": "Nome utente", "username_placeholder": "Inserisci nome utente", @@ -606,7 +609,7 @@ "enter_cache_ttl_max_override": "Immetti TTL massimo (in secondi)", "cache_ttl_min_override_desc": "Estende i valori di breve durata (in secondi) ricevuti dal server upstream durante la memorizzazione nella cache delle risposte DNS.", "cache_ttl_max_override_desc": "Imposta un valore di durata massima (secondi) per le voci nella cache DNS.", - "ttl_cache_validation": "La sovrascrittura del valore TTL minimo della cache deve essere inferiore o uguale a quello massimo.", + "ttl_cache_validation": "La sovrascrittura del valore TTL minimo della cache deve essere inferiore o uguale a quello massimo", "cache_optimistic": "Optimistic caching", "cache_optimistic_desc": "Fai in modo che AdGuard Home risponda dalla cache anche quando le voci risultano scadute e prova anche ad aggiornarle.", "filter_category_general": "Generali", @@ -628,5 +631,5 @@ "parental_control": "Controllo Parentale", "safe_browsing": "Navigazione Sicura", "served_from_cache": "{{value}} (fornito dalla cache)", - "form_error_password_length": "La password deve essere lunga almeno {{value}} caratteri." + "form_error_password_length": "La password deve contenere almeno {{value}} caratteri" } diff --git a/client/src/__locales/ja.json b/client/src/__locales/ja.json index 7c2f8ba1..0cd45548 100644 --- a/client/src/__locales/ja.json +++ b/client/src/__locales/ja.json @@ -45,13 +45,13 @@ "form_error_mac_format": "MACアドレスが無効です", "form_error_client_id_format": "ClientIDには、数字、小文字、ハイフン以外は使用できません", "form_error_server_name": "サーバー名が無効です", - "form_error_subnet": "IPアドレス「{{ip}}」はサブネット「{{cidr}}」に含まれていません", + "form_error_subnet": "IPアドレス「{{ip}}」がサブネット「{{cidr}}」に含まれていません", "form_error_positive": "0より大きい値でなければなりません", - "out_of_range_error": "\"{{start}}\"-\"{{end}}\" の範囲外である必要があります", + "out_of_range_error": "\"{{start}}\"〜\"{{end}}\" の範囲外である必要があります", "lower_range_start_error": "範囲開始よりも低い値である必要があります", "greater_range_start_error": "範囲開始値より大きい値でなければなりません", "greater_range_end_error": "範囲終了値より大きい値でなければなりません", - "subnet_error": "アドレスは1つのサブネット内にある必要があります", + "subnet_error": "両アドレスが同じサブネット内にある必要があります", "gateway_or_subnet_invalid": "サブネットマスクが無効です", "dhcp_form_gateway_input": "ゲートウェイIP", "dhcp_form_subnet_input": "サブネットマスク", @@ -67,7 +67,7 @@ "dhcp_table_hostname": "ホスト名", "dhcp_table_expires": "有効期限", "dhcp_warning": "ともかくDHCPサーバを有効にしたい場合は、ネットワーク内で他に稼働中のDHCPサーバがないことを確認してください。そうでなければ、ネットワーク上デバイスでインターネット接続を壊してしまう可能性があります!", - "dhcp_error": "ネットワーク上に別の稼働中DHCPサーバがあるかどうか、AdGuard Homeは判断できませんでした。", + "dhcp_error": "ネットワーク上に別の稼働中DHCPサーバがあるかどうか、AdGuard Homeは判断できませんでした", "dhcp_static_ip_error": "DHCPサーバーを使用するには、静的IPアドレスを設定する必要があります。このネットワークインターフェースが静的IPアドレスを使用するように設定されているかどうかを、AdGuard Homeは判断できませんでした。手動で静的IPアドレスを設定してください。", "dhcp_dynamic_ip_found": "お使いのシステムは、インターフェース<0>{{interfaceName}}用に動的IPアドレス構成を使用しています。DHCPサーバを使用するには、静的IPアドレスで設定する必要があります。あなたの現在のIPアドレスは<0>{{ipAddress}}です。「DHCPサーバを有効にする」ボタンを押すと、AdGuard Homeは自動的にこのIPアドレスを静的IPアドレスとして設定します。", "dhcp_lease_added": "静的割り当て \"{{key}}\" の追加に成功しました", @@ -210,11 +210,13 @@ "example_comment_hash": "# これもコメントです", "example_regex_meaning": "指定の正規表現に一致するドメインへのアクセスをブロックします。", "example_upstream_regular": "通常のDNS(over UDP)。", + "example_upstream_udp": "通常のDNS(over UDP, ホスト名)。", "example_upstream_dot": "暗号化されている <0>DNS-over-TLS。", "example_upstream_doh": "暗号化されている <0>DNS-over-HTTPS。", "example_upstream_doq": "暗号化 <0>DNS-over-QUIC(実験的)。", "example_upstream_sdns": "<1>DNSCrypt または <2>DNS-over-HTTPS リゾルバのための <0>DNS Stamps。", "example_upstream_tcp": "通常のDNS(over TCP)。", + "example_upstream_tcp_hostname": "通常のDNS(over TCP, ホスト名)。", "all_lists_up_to_date_toast": "すべてのリストは既に最新です", "updated_upstream_dns_toast": "上流DNSサーバを保存しました。", "dns_test_ok_toast": "指定されたDNSサーバは正しく動作しています", @@ -259,10 +261,10 @@ "query_log_strict_search": "完全一致検索には二重引用符を使用します", "query_log_retention_confirm": "クエリ・ログの保持を変更してもよろしいですか? 期間を短くすると、一部のデータが失われます", "anonymize_client_ip": "クライアントIPを匿名化する", - "anonymize_client_ip_desc": "ログと統計にクライアントのフルPアドレスを保存しません。", + "anonymize_client_ip_desc": "ログと統計にクライアントのフルIPアドレスを保存しないようにします。", "dns_config": "DNSサーバ設定", "dns_cache_config": "DNSキャッシュ設定", - "dns_cache_config_desc": "ここでDNSキャッシュを設定できます。", + "dns_cache_config_desc": "こちらではDNSキャッシュを設定できます。", "blocking_mode": "ブロックモード", "default": "デフォルト", "nxdomain": "NXDOMAIN", @@ -285,7 +287,7 @@ "form_enter_rate_limit": "頻度制限を入力してください", "rate_limit": "頻度制限", "edns_enable": "EDNSクライアントサブネットを有効にする", - "edns_cs_desc": "有効にすると、AdGuard HomeはクライアントのサブネットをDNSサーバへ送信します。", + "edns_cs_desc": "アップストリームリクエストにEDNSクライアントサブネットオプション(ECS)を追加し、クライアントから送信された値をクエリログに記録します。", "rate_limit_desc": "一つのクライアントに対して許可される1秒あたりのリクエスト数(「0」に設定すると、制限なしになります)", "blocking_ipv4_desc": "ブロックされたAリクエストに対して応答されるIPアドレス", "blocking_ipv6_desc": "ブロックされたAAAAリクエストに対して応答されるIPアドレス", @@ -356,7 +358,7 @@ "open_dashboard": "ダッシュボードを開きます", "install_saved": "保存に成功しました", "encryption_title": "暗号化", - "encryption_desc": "DNSと管理者ウェブインターフェースの両方に対する暗号化(HTTPS/TLS)サポート。", + "encryption_desc": "DNSと管理者ウェブインターフェースの両方に対する暗号化(HTTPS/QUIC/TLS)サポート。", "encryption_config_saved": "暗号化構成が保存されました。", "encryption_server": "サーバ名", "encryption_server_enter": "ドメイン名を入力してください", @@ -379,7 +381,7 @@ "encryption_enable": "暗号化を有効にする(HTTPS、DNS-over-HTTPS、DNS-over-TLS)", "encryption_enable_desc": "暗号化が有効になっていると、AdGuard Home 管理インターフェースはHTTPS経由で動作し、DNSサーバはDNS-over-HTTPSおよびDNS-over-TLS経由で要求を待ち受けます。", "encryption_chain_valid": "証明書チェーンは有効です。", - "encryption_chain_invalid": "証明書チェーンは無効です", + "encryption_chain_invalid": "証明書チェーンが無効です", "encryption_key_valid": "これは有効な{{type}}プライベートキーです。", "encryption_key_invalid": "これは無効な{{type}}プライベートキーです", "encryption_subject": "件名", @@ -388,7 +390,7 @@ "encryption_reset": "暗号化設定をリセットして良いですか?", "topline_expiring_certificate": "SSL証明書は期限切れになります。<0>暗号化設定を更新します。", "topline_expired_certificate": "SSL証明書は期限切れです。<0>暗号化設定を更新します。", - "form_error_port_range": "80〜65535 の範囲でポート番号を入力してください", + "form_error_port_range": "80〜65535 の範囲内でポート番号を入力してください", "form_error_port_unsafe": "これは不安全なポートです", "form_error_equal": "同じ値であってはなりません", "form_error_password": "パスワードが一致しません", @@ -397,7 +399,7 @@ "setup_guide": "セットアップガイド", "dns_addresses": "DNSアドレス", "dns_start": "DNSサーバが起動処理中です", - "dns_status_error": "DNSサーバ・ステータスの確認エラー", + "dns_status_error": "DNSサーバーステータスの確認エラー", "down": "ダウン", "fix": "改善", "dns_providers": "こちらは、選択可能な<0>既知のDNSプロバイダの一覧です。", @@ -435,7 +437,7 @@ "auto_clients_title": "ランタイムクライアント", "auto_clients_desc": "永続的クライアントのリストに未登録で、AdGuard Homeを使用する場合があるデバイスのリスト。", "access_title": "アクセス設定", - "access_desc": "ここで、AdGuard Home DNSサーバのアクセスルールを設定できます。", + "access_desc": "こちらでは、AdGuard Home DNSサーバーのアクセスルールを設定できます。", "access_allowed_title": "許可されたクライアント", "access_allowed_desc": "CIDR、IPアドレス、またはClientIDのリスト。このリストに入力がある場合、AdGuard Homeはリストに入っているクライアントからのみリクエストを受け入れます。", "access_disallowed_title": "拒否するクライアント", @@ -500,6 +502,7 @@ "interval_days": "{{count}}日", "interval_days_plural": "{{count}}日", "domain": "ドメイン", + "ecs": "ECS", "punycode": "Punycode", "answer": "応答", "filter_added_successfully": "フィルタの追加に成功しました", @@ -507,7 +510,7 @@ "filter_updated": "フィルタの更新に成功しました", "statistics_configuration": "統計設定", "statistics_retention": "統計保持", - "statistics_retention_desc": "※保持期間を短くすると、一部のデータが失われます。", + "statistics_retention_desc": "※保持期間を短くすると、一部のデータは失われます。", "statistics_clear": "統計を消去する", "statistics_clear_confirm": "統計を消去してもよろしいですか?", "statistics_retention_confirm": "統計の保持を変更してもよろしいですか? 期間を短くすると、一部のデータが失われます", @@ -517,7 +520,7 @@ "interval_hours_plural": "{{count}}時間", "filters_configuration": "フィルタ設定", "filters_enable": "フィルタを有効にする", - "filters_interval": "フィルタの更新間隔", + "filters_interval": "フィルタの更新頻度", "disabled": "無効", "username_label": "ユーザ名", "username_placeholder": "ユーザ名を入力してください", @@ -606,7 +609,7 @@ "enter_cache_ttl_max_override": "最大TTL(秒単位)を入力してください", "cache_ttl_min_override_desc": "DNS応答をキャッシュするとき、上流サーバから受信した短いTTL(秒単位)を延長します。", "cache_ttl_max_override_desc": "DNSキャッシュ内のエントリの最大TTL(秒単位)を設定します。", - "ttl_cache_validation": "最小キャッシュTTL上書きは最大値以下にする必要があります", + "ttl_cache_validation": "最小キャッシュTTL上書き値は最大値以下にする必要があります", "cache_optimistic": "Optimistic cashing (オプティミスティック・キャッシュ)", "cache_optimistic_desc": "エントリの有効期限が切れた場合でも、AdGuard Homeがキャッシュから応答するようにし、エントリの更新も試みます。", "filter_category_general": "一般", @@ -628,5 +631,5 @@ "parental_control": "ペアレンタルコントロール", "safe_browsing": "セーフブラウジング", "served_from_cache": "{{value}} (キャッシュから応答)", - "form_error_password_length": "パスワードは{{value}}文字以上にしてください。" + "form_error_password_length": "パスワードは{{value}}文字以上にしてください" } diff --git a/client/src/__locales/ko.json b/client/src/__locales/ko.json index ff52d178..19440d13 100644 --- a/client/src/__locales/ko.json +++ b/client/src/__locales/ko.json @@ -35,24 +35,24 @@ "dhcp_config_saved": "DHCP 구성이 성공적으로 저장되었습니다", "dhcp_ipv4_settings": "DHCP IPv4 설정", "dhcp_ipv6_settings": "DHCP IPv6 설정", - "form_error_required": "필수 필드.", - "form_error_ip4_format": "잘못된 IPv4 주소.", - "form_error_ip4_range_start_format": "잘못된 범위 시작 IPv4 주소.", - "form_error_ip4_range_end_format": "잘못된 범위 종료 IPv4 주소.", - "form_error_ip4_gateway_format": "잘못된 게이트웨이 IPv4 주소.", - "form_error_ip6_format": "잘못된 IPv6 주소.", - "form_error_ip_format": "잘못된 IP 주소.", - "form_error_mac_format": "잘못된 MAC 주소.", - "form_error_client_id_format": "ClientID는 숫자, 소문자 및 하이픈만 포함해야 합니다.", - "form_error_server_name": "유효하지 않은 서버 이름입니다.", - "form_error_subnet": "서브넷 '{{cidr}}'에 '{{ip}}' IP 주소가 없습니다.", - "form_error_positive": "0보다 커야 합니다.", - "out_of_range_error": "'{{start}}'-'{{end}}' 범위 밖이어야 합니다.", - "lower_range_start_error": "범위 시작보다 작은 값이어야 합니다.", - "greater_range_start_error": "범위 시작보다 큰 값이어야 합니다.", - "greater_range_end_error": "범위 종료보다 큰 값이어야 합니다.", - "subnet_error": "주소는 하나의 서브넷에 있어야 합니다.", - "gateway_or_subnet_invalid": "잘못된 서브넷 마스크.", + "form_error_required": "필수 영역", + "form_error_ip4_format": "잘못된 IPv4 형식", + "form_error_ip4_range_start_format": "잘못된 범위 시작 IPv4 형식", + "form_error_ip4_range_end_format": "잘못된 범위 종료 IPv4 형식", + "form_error_ip4_gateway_format": "잘못된 게이트웨이 IPv4 형식", + "form_error_ip6_format": "잘못된 IPv6 주소", + "form_error_ip_format": "잘못된 IP 주소", + "form_error_mac_format": "잘못된 MAC 주소", + "form_error_client_id_format": "ClientID는 숫자, 소문자 및 붙임표(-)만 포함해야 합니다", + "form_error_server_name": "유효하지 않은 서버 이름", + "form_error_subnet": "서브넷 \"{{cidr}}\"에 \"{{ip}}\" IP 주소가 없습니다", + "form_error_positive": "0보다 커야 합니다", + "out_of_range_error": "\"{{start}}\"-\"{{end}}\" 범위 밖이어야 합니다", + "lower_range_start_error": "범위 시작보다 작은 값이어야 합니다", + "greater_range_start_error": "범위 시작보다 큰 값이어야 합니다", + "greater_range_end_error": "범위 종료보다 큰 값이어야 합니다", + "subnet_error": "주소는 하나의 서브넷에 있어야 합니다", + "gateway_or_subnet_invalid": "잘못된 서브넷 마스크", "dhcp_form_gateway_input": "게이트웨이 IP", "dhcp_form_subnet_input": "서브넷 마스크", "dhcp_form_range_title": "IP 주소 범위", @@ -67,7 +67,7 @@ "dhcp_table_hostname": "호스트 이름", "dhcp_table_expires": "만료", "dhcp_warning": "DHCP 서버를 사용하려면 네트워크에 다른 활성화된 DHCP 서버가 없는지 확인해 주세요. 다른 활성 DHCP 서버가 있다면, 연결된 장치의 인터넷이 끊길 수 있습니다.", - "dhcp_error": "AdGuard Home이 네트워크에 다른 활성 DHCP 서버가 있는지 확인할 수 없습니다.", + "dhcp_error": "AdGuard Home이 네트워크에 다른 활성 DHCP 서버가 있는지 확인할 수 없습니다", "dhcp_static_ip_error": "DHCP 서버를 사용하려면 고정 IP 주소를 설정해야 합니다. AdGuard Home이 이 네트워크 인터페이스가 고정 IP 주소를 사용하는지 확인할 수 없습니다. 고정 IP 주소를 수동으로 설정하십시오.", "dhcp_dynamic_ip_found": "시스템은 <0>{{interfaceName}} 인터페이스에 동적 IP 주소를 사용합니다. DHCP 서버를 사용하려면 고정 IP 주소를 설정해야 합니다. 현재 IP 주소는 <0>{{ipAddress}}입니다. 'DHCP 서버 활성화' 버튼을 누르면 AdGuard Home이 이 IP 주소를 고정 IP 주소로 자동 설정합니다.", "dhcp_lease_added": "\"{{key}}\" 고정 임대 정상적으로 추가되었습니다", @@ -196,8 +196,8 @@ "choose_allowlist": "허용 목록 선택", "enter_valid_blocklist": "차단 목록에 유효한 URL을 입력해주세요.", "enter_valid_allowlist": "허용 목록에 유효한 URL을 입력해주세요.", - "form_error_url_format": "잘못된 URL 형식.", - "form_error_url_or_path_format": "목록의 URL 또는 절대 경로가 잘못되었습니다.", + "form_error_url_format": "잘못된 URL 형식", + "form_error_url_or_path_format": "목록의 URL 또는 절대 경로가 잘못되었습니다", "custom_filter_rules": "커스텀 필터링 규칙", "custom_filter_rules_hint": "한 라인에 한 규칙만 입력하세요. 광고 차단 규칙과 호스트 파일 문법 중 하나를 사용할 수 있습니다", "system_host_files": "시스템 호스트 파일", @@ -210,11 +210,13 @@ "example_comment_hash": "# 이것 또한 댓글입니다.", "example_regex_meaning": "특정 정규 표현식에 맞는 도메인 접근을 차단합니다.", "example_upstream_regular": "일반 DNS (UDP을 통한 접속);", + "example_upstream_udp": "일반 DNS (UDP를 통한, 호스트명);", "example_upstream_dot": "암호화된 <0>DNS-over-TLS;", "example_upstream_doh": "암호화된 <0>DNS-over-HTTPS;", "example_upstream_doq": "암호화된 <0>DNS-over-QUIC (실험);", "example_upstream_sdns": "<1>DNSCrypt 또는 <2>DNS-over-HTTPS 리졸버를 위한 <0>DNS 스탬프;", "example_upstream_tcp": "일반 DNS (TCP를 통한 접속);", + "example_upstream_tcp_hostname": "일반 DNS (TCP를 통한, 호스트명);", "all_lists_up_to_date_toast": "모든 리스트가 이미 최신입니다", "updated_upstream_dns_toast": "업스트림 서버가 성공적으로 저장되었습니다", "dns_test_ok_toast": "특정 DNS 서버들은 정상적으로 동작 중입니다", @@ -259,10 +261,10 @@ "query_log_strict_search": "검색을 제한하려면 쌍따옴표를 사용해주세요", "query_log_retention_confirm": "정말로 쿼리 로그 저장 기간을 변경하시겠습니까? 저장 주기를 낮출 경우, 일부 데이터가 손실됩니다", "anonymize_client_ip": "클라이언트 IP 익명화", - "anonymize_client_ip_desc": "클라이언트의 전체 IP 주소를 로그와 통계에 저장하지 않습니다.", + "anonymize_client_ip_desc": "클라이언트의 전체 IP 주소를 로그와 통계에 저장하저장하지 마세요", "dns_config": "DNS 서버 설정", "dns_cache_config": "DNS 캐시 구성", - "dns_cache_config_desc": "여기에서 DNS 캐시를 구성할 수 있습니다.", + "dns_cache_config_desc": "여기에서 DNS 캐시를 구성 할 수 있습니다", "blocking_mode": "차단 모드", "default": "기본", "nxdomain": "NXDOMAIN", @@ -285,7 +287,7 @@ "form_enter_rate_limit": "한도 제한 입력하기", "rate_limit": "한도 제한", "edns_enable": "EDNS 클라이언트 서브넷 활성화", - "edns_cs_desc": "클라이언트의 서브넷을 DNS 서버에 전달합니다.", + "edns_cs_desc": "업스트림 요청에 EDNS 클라이언트 서브넷 옵션(ECS)을 추가하고 쿼리 로그에 클라이언트가 보낸 값을 기록합니다.", "rate_limit_desc": "단일 클라이언트에서 허용 가능한 초 당 요청 생성 숫자 (0: 무제한)", "blocking_ipv4_desc": "차단된 A 요청에 대해서 반환할 IP 주소", "blocking_ipv6_desc": "차단된 AAAA 요청에 대해서 반환할 IP 주소", @@ -309,7 +311,7 @@ "install_settings_listen": "네트워크 인터페이스", "install_settings_port": "포트", "install_settings_interface_link": "AdGuard Home 관리자 웹 인터페이스는 다음 주소로 제공됨:", - "form_error_port": "유효한 포트 번호를 입력하세요.", + "form_error_port": "유효한 포트 번호를 입력하세요", "install_settings_dns": "DNS 서버", "install_settings_dns_desc": "다음 주소의 DNS 서버를 사용하도록 장치 또는 라우터를 구성해야 합니다.", "install_settings_all_interfaces": "모든 인터페이스", @@ -356,7 +358,7 @@ "open_dashboard": "대시보드 열기", "install_saved": "성공적으로 저장되었습니다", "encryption_title": "암호화", - "encryption_desc": "DNS 및 관리 웹 인터페이스에 대한 암호화(HTTPS/TLS)를 지원합니다.", + "encryption_desc": "DNS 및 관리 웹 인터페이스에 대한 암호화(HTTPS/TLS)를 지원합니다", "encryption_config_saved": "암호화 구성이 저장되었습니다", "encryption_server": "서버 이름", "encryption_server_enter": "도메인 이름을 입력하세요.", @@ -378,26 +380,26 @@ "encryption_key_input": "PEM으로 인코딩된 개인 키를 여기에 복사/붙여넣기하세요.", "encryption_enable": "암호화 활성화 (HTTPS, DNS-over-HTTPS 및 DNS-over-TLS)", "encryption_enable_desc": "암호화가 활성화 된 경우 AdGuard Home 관리자 인터페이스는 HTTPS를 통해 작동하고 DNS 서버는 DNS-over-HTTPS 및 DNS-over-TLS를 통해 요청을 수신합니다.", - "encryption_chain_valid": "인증서 체인이 유효합니다.", - "encryption_chain_invalid": "인증서 체인이 유효하지 않습니다.", - "encryption_key_valid": "유효한 {{type}} 개인 키입니다.", - "encryption_key_invalid": "유효하지 않는 {{type}} 개인 키입니다.", + "encryption_chain_valid": "인증서 체인이 유효합니다", + "encryption_chain_invalid": "인증서 체인이 유효하지 않습니다", + "encryption_key_valid": "유효한 {{type}} 개인 키입니다", + "encryption_key_invalid": "유효하지 않는 {{type}} 개인 키입니다", "encryption_subject": "대상", "encryption_issuer": "발행자", "encryption_hostnames": "호스트 이름", "encryption_reset": "암호화 설정을 재설정하시겠습니까?", "topline_expiring_certificate": "SSL 인증서가 곧 만료됩니다. 업데이트<0> 암호화 설정.", "topline_expired_certificate": "SSL 인증서가 만료되었습니다. 업데이트<0> 암호화 설정.", - "form_error_port_range": "80-65535 범위의 포트 번호를 입력하세요.", - "form_error_port_unsafe": "안전하지 않은 포트입니다.", - "form_error_equal": "동일하지 않아야 함.", - "form_error_password": "비밀번호 불일치.", + "form_error_port_range": "80-65535 범위의 포트 번호를 입력하세요", + "form_error_port_unsafe": "안전하지 않은 포트입니다", + "form_error_equal": "동일하지 않아야 합니다", + "form_error_password": "비밀번호 불일치", "reset_settings": "설정 초기화", "update_announcement": "AdGuard Home {{version}} 사용 가능합니다! <0>이곳을 클릭하여 더 많은 정보를 확인하세요.", "setup_guide": "설치 안내", "dns_addresses": "DNS 주소", "dns_start": "DNS 서버를 시작하고 있습니다", - "dns_status_error": "DNS 서버 상태를 확인하는 동안 오류가 발생했습니다.", + "dns_status_error": "DNS 서버 상태를 확인하는 동안 오류가 발생했습니다", "down": "다운로드", "fix": "수정", "dns_providers": "다음은 선택할 수 있는 <0>알려진 DNS 공급자 목록입니다.", @@ -406,7 +408,7 @@ "manual_update": "절차를 따라 수동으로 업데이트하십시오.", "processing_update": "잠시만 기다려주세요, AdGuard Home가 업데이트 중입니다.", "clients_title": "영구 클라이언트", - "clients_desc": "AdGuard Home에 연결된 기기에 대한 영구 클라이언트 레코드를 설정합니다.", + "clients_desc": "AdGuard Home에 연결된 기기에 대한 영구 클라이언트 레코드를 설정합니다", "settings_global": "글로벌", "settings_custom": "사용자", "table_client": "클라이언트", @@ -433,9 +435,9 @@ "client_confirm_delete": "정말 클라이언트 \"{{key}}\" 삭제하시겠습니까?", "list_confirm_delete": "정말로 이 목록을 제거하시겠습니까?", "auto_clients_title": "런타임 클라이언트", - "auto_clients_desc": "AdGuard Home을 계속 사용할 수 있는 영구 클라이언트 목록에 없는 디바이스입니다.", + "auto_clients_desc": "AdGuard Home을 계속 사용할 수 있는 영구 클라이언트 목록에 없는 디바이스입니다", "access_title": "접근 설정", - "access_desc": "여기에서 AdGuard Home DNS 서버에 대한 액세스 규칙을 구성할 수 있습니다.", + "access_desc": "여기에서 AdGuard Home DNS 서버에 대한 액세스 규칙을 설정할 수 있습니다", "access_allowed_title": "허용된 클라이언트", "access_allowed_desc": "CIDR, IP 주소 또는 ClientID 목록입니다. 이 목록에 항목이 있는 경우, AdGuard Home은 이러한 클라이언트의 요청만 수락합니다.", "access_disallowed_title": "차단된 클라이언트", @@ -475,8 +477,8 @@ "dns_rewrites": "DNS 변경", "form_domain": "도메인 이름 또는 와일드카드를 입력합니다", "form_answer": "IP 주소 또는 도메인 이름을 입력하세요", - "form_error_domain_format": "도메인 형식이 잘못되었습니다.", - "form_error_answer_format": "답변 형식이 잘못되었습니다. ", + "form_error_domain_format": "도메인 형식이 잘못되었습니다", + "form_error_answer_format": "답변 형식이 잘못되었습니다", "configure": "설정하기", "main_settings": "기본 설정", "block_services": "특정 서비스 차단", @@ -500,6 +502,7 @@ "interval_days": "{{count}} 일", "interval_days_plural": "{{count}} 일", "domain": "도메인", + "ecs": "ECS", "punycode": "Punycode", "answer": "응답", "filter_added_successfully": "목록이 성공적으로 추가됨", @@ -507,7 +510,7 @@ "filter_updated": "필터가 성공적으로 업데이트됨", "statistics_configuration": "통계 구성", "statistics_retention": "통계 저장 기간", - "statistics_retention_desc": "간격 값을 줄이면 일부 데이터가 손실됩니다.", + "statistics_retention_desc": "주기를 줄이면, 일부 데이터가 손실됩니다", "statistics_clear": "통계 초기화", "statistics_clear_confirm": "통계를 정말로 초기화하시겠습니까?", "statistics_retention_confirm": "정말로 통계 저장 기간을 변경하시겠습니까? 저장 주기를 낮출 경우, 일부 데이터가 손실됩니다", @@ -628,5 +631,5 @@ "parental_control": "자녀 보호", "safe_browsing": "세이프 브라우징", "served_from_cache": "{{value}} (캐시에서 제공)", - "form_error_password_length": "비밀번호는 {{value}}자 이상이어야 합니다." + "form_error_password_length": "비밀번호는 {{value}}자 이상이어야 합니다" } diff --git a/client/src/__locales/nl.json b/client/src/__locales/nl.json index 36478928..990f4b09 100644 --- a/client/src/__locales/nl.json +++ b/client/src/__locales/nl.json @@ -35,24 +35,24 @@ "dhcp_config_saved": "DHCP configuratie succesvol opgeslagen", "dhcp_ipv4_settings": "DHCP IPv4 instellingen", "dhcp_ipv6_settings": "DHCP IPv6 instellingen", - "form_error_required": "Vereist veld.", - "form_error_ip4_format": "Ongeldig IPv4-adres.", - "form_error_ip4_range_start_format": "Ongeldig IPv4-adres start bereik.", - "form_error_ip4_range_end_format": "Ongeldig IPv4-adres einde bereik.", - "form_error_ip4_gateway_format": "Ongeldig IPv4-adres van de gateway.", - "form_error_ip6_format": "Ongeldig IPv6-adres.", - "form_error_ip_format": "Ongeldig IP-adres.", - "form_error_mac_format": "Ongeldig MAC-adres.", - "form_error_client_id_format": "Client-ID mag alleen cijfers, kleine letters en koppeltekens bevatten.", - "form_error_server_name": "Ongeldige servernaam.", - "form_error_subnet": "Subnet “{{cidr}}” bevat niet het IP-adres “{{ip}}”.", - "form_error_positive": "Moet groter zijn dan 0.", - "out_of_range_error": "Moet buiten bereik zijn \"{{start}}\"-\"{{end}}\".", - "lower_range_start_error": "Moet lager zijn dan begin reeks.", - "greater_range_start_error": "Moet groter zijn dan begin reeks.", - "greater_range_end_error": "Moet groter zijn dan einde reeks.", - "subnet_error": "Adressen moeten in één subnet vallen.", - "gateway_or_subnet_invalid": "Subnetmasker ongeldig.", + "form_error_required": "Vereist veld", + "form_error_ip4_format": "Ongeldig IPv4-adres", + "form_error_ip4_range_start_format": "Ongeldig IPv4-adres start bereik", + "form_error_ip4_range_end_format": "Ongeldig IPv4-adres einde bereik", + "form_error_ip4_gateway_format": "Ongeldig IPv4-adres van de gateway", + "form_error_ip6_format": "Ongeldig IPv6-adres", + "form_error_ip_format": "Ongeldig IP-adres", + "form_error_mac_format": "Ongeldig MAC-adres", + "form_error_client_id_format": "Client-ID mag alleen cijfers, kleine letters en koppeltekens bevatten", + "form_error_server_name": "Ongeldige servernaam", + "form_error_subnet": "Subnet “{{cidr}}” bevat niet het IP-adres “{{ip}}”", + "form_error_positive": "Moet groter zijn dan 0", + "out_of_range_error": "Moet buiten bereik zijn \"{{start}}\"-\"{{end}}\"", + "lower_range_start_error": "Moet lager zijn dan begin reeks", + "greater_range_start_error": "Moet groter zijn dan begin reeks", + "greater_range_end_error": "Moet groter zijn dan einde reeks", + "subnet_error": "Adressen moeten in één subnet vallen", + "gateway_or_subnet_invalid": "Subnetmasker ongeldig", "dhcp_form_gateway_input": "Gateway IP", "dhcp_form_subnet_input": "Subnet mask", "dhcp_form_range_title": "Bereik van IP adressen", @@ -67,7 +67,7 @@ "dhcp_table_hostname": "Host naam", "dhcp_table_expires": "Verloopt op", "dhcp_warning": "Indien je de ingebouwde DHCP server wilt inschakelen, let dan op dat er geen andere actieve DHCP server aanwezig is in je netwerk. Dit kan de internetverbinding instabiel maken voor sommige apparaten in je netwerk!", - "dhcp_error": "AdGuard Home kon niet bepalen of er een andere actieve DHCP server in je netwerk aanwezig is.", + "dhcp_error": "AdGuard Home kon niet bepalen of er een andere actieve DHCP server op het netwerk aanwezig is", "dhcp_static_ip_error": "Om de DHCP server te gebruiken, moet een statisch IP-adres worden ingesteld. AdGuard Home heeft niet kunnen vaststellen of de netwerkinterface is geconfigureerd met een statisch IP-adres. Stel handmatig een statisch IP-adres in.", "dhcp_dynamic_ip_found": "Je systeem gebruikt dynamische IP-adres configuratie voor interface <0>{{interfaceName}}. Om de DHCP server te gebruiken moet er een statisch IP-adres worden ingesteld. Je huidige IP-adres is <0>{{ipAddress}}. AdGuard Home zal automatisch dit IP-adres als statisch IP-adres instellen wanneer je op de knop \"DHCP inschakelen\" drukt.", "dhcp_lease_added": "Statische uitgifte \"{{key}}\" met succes toegevoegd", @@ -196,8 +196,8 @@ "choose_allowlist": "Toestemmingslijsten selecteren", "enter_valid_blocklist": "Voer een geldige URL in voor de blokkeerlijst.", "enter_valid_allowlist": "Voer een geldige URL in voor de toestemmingslijst.", - "form_error_url_format": "Ongeldig URL-opmaak.", - "form_error_url_or_path_format": "Ongeldig URL of pad van de lijst.", + "form_error_url_format": "Ongeldig URL-opmaak", + "form_error_url_or_path_format": "Ongeldig URL of pad van de lijst", "custom_filter_rules": "Aangepaste filterregels", "custom_filter_rules_hint": "Voer één regel op een regel in. U kunt adblock-regels gebruiken of de syntaxis van hosts-bestanden gebruiken.", "system_host_files": "Systeem host-bestanden", @@ -210,11 +210,13 @@ "example_comment_hash": "# Ook een opmerking.", "example_regex_meaning": "toegang blokkeren tot de domeinen die overeenkomen met de opgegeven reguliere expressie.", "example_upstream_regular": "standaard DNS (over UDP);", + "example_upstream_udp": "standaard DNS (via UDP, hostnaam);", "example_upstream_dot": "versleutelde <0>DNS-via-TLS;", "example_upstream_doh": "versleutelde <0>DNS-via-HTTPS;", "example_upstream_doq": "versleutelde <0>DNS-via-QUIC (experimenteel);", "example_upstream_sdns": "<0>DNS Stamps voor <1>DNSCrypt of <2>DNS-via-HTTPS oplossingen;", "example_upstream_tcp": "standaard DNS (over TCP);", + "example_upstream_tcp_hostname": "standaard DNS (via TCP, hostnaam);", "all_lists_up_to_date_toast": "Alle lijsten zijn reeds actueel", "updated_upstream_dns_toast": "Upstream-servers succesvol opgeslagen", "dns_test_ok_toast": "Opgegeven DNS-servers werken correct", @@ -259,10 +261,10 @@ "query_log_strict_search": "Gebruik dubbele aanhalingstekens voor strikt zoeken", "query_log_retention_confirm": "Weet u zeker dat u de bewaartermijn van het query logboek wilt wijzigen? Als u de intervalwaarde verlaagt, gaan sommige gegevens verloren", "anonymize_client_ip": "Cliënt IP anonimiseren", - "anonymize_client_ip_desc": "Het volledige IP-adres van de cliënt niet opnemen in logboeken en statistiekbestanden.", + "anonymize_client_ip_desc": "Het volledige IP-adres van de cliënt niet opnemen in logboeken en statistiekbestanden", "dns_config": "DNS-server configuratie", "dns_cache_config": "DNS cache configuratie", - "dns_cache_config_desc": "Hier kan de DNS cache geconfigureerd worden.", + "dns_cache_config_desc": "Hier kan de DNS cache geconfigureerd worden", "blocking_mode": "Blocking modus", "default": "Standaard", "nxdomain": "NXDOMAIN", @@ -285,7 +287,7 @@ "form_enter_rate_limit": "Voer ratio limiet in", "rate_limit": "Ratio limiet", "edns_enable": "EDNS client subnet inschakelen", - "edns_cs_desc": "Indien ingeschakeld stuurt AdGuard Home het subnet van de client naar de DNS-servers.", + "edns_cs_desc": "De EDNS Client Subnet-optie (ECS) toevoegen aan upstream-verzoeken en de waarden die door de clients zijn verzonden registreren in het querylogboek.", "rate_limit_desc": "Het aantal verzoeken per seconde toegelaten per toestel. 0 betekent onbeperkt.", "blocking_ipv4_desc": "IP-adres dat moet worden teruggegeven voor een geblokkeerd A-verzoek", "blocking_ipv6_desc": "IP-adres dat moet worden teruggegeven voor een geblokkeerd A-verzoek", @@ -309,7 +311,7 @@ "install_settings_listen": "Luister interface", "install_settings_port": "Poort", "install_settings_interface_link": "De webinterface van AdGuard Home admin is beschikbaar op de volgende adressen:", - "form_error_port": "Geldig poortnummer invoeren.", + "form_error_port": "Geldig poortnummer invoeren", "install_settings_dns": "DNS-server", "install_settings_dns_desc": "Je moet jouw apparaten of router configureren om de DNS-server te gebruiken op de volgende adressen:", "install_settings_all_interfaces": "Alle interfaces", @@ -356,7 +358,7 @@ "open_dashboard": "Open Dashboard", "install_saved": "Succesvol opgeslagen", "encryption_title": "Encryptie", - "encryption_desc": "Encryptie (HTTPS/TLS) ondersteuning voor DNS en admin web interface.", + "encryption_desc": "Encryptie (HTTPS/TLS) ondersteuning voor DNS en admin web interface", "encryption_config_saved": "Versleuteling configuratie opgeslagen", "encryption_server": "Server naam", "encryption_server_enter": "Voer domein naam in", @@ -378,26 +380,26 @@ "encryption_key_input": "Kopieër en plak je PEM-gecodeerde prive sleutel voor je certificaat hier.", "encryption_enable": "Activeer encryptie (HTTPS, DNS-via-HTTPS, en DNS-via-TLS)", "encryption_enable_desc": "Als encryptie is geactiveerd, is de AdGuard Home beheerders interface toegankelijk via HTTPS en de DNS-server zal luisteren naar aanvragen via DNS-via-HTTPS en DNS-via-TLS.", - "encryption_chain_valid": "Certificaatketen is geldig.", - "encryption_chain_invalid": "Certificaatketen is ongeldig.", - "encryption_key_valid": "Dit is een geldige {{type}} privésleutel.", - "encryption_key_invalid": "Dit is een ongeldige {{type}} privésleutel.", + "encryption_chain_valid": "Certificaatketen is geldig", + "encryption_chain_invalid": "Certificaatketen is ongeldig", + "encryption_key_valid": "Dit is een geldige {{type}} privésleutel", + "encryption_key_invalid": "Dit is een ongeldige {{type}} privésleutel", "encryption_subject": "Onderwerp", "encryption_issuer": "Uitgever", "encryption_hostnames": "Hostnamen", "encryption_reset": "Ben je zeker dat je de encryptie instellingen wil resetten?", "topline_expiring_certificate": "Jouw SSL-certificaat vervalt binnenkort. Werk de <0>encryptie-instellingen bij.", "topline_expired_certificate": "Jouw SSL-certificaat is vervallen. Werk de <0>encryptie-instellingen bij.", - "form_error_port_range": "Poortnummer invoeren tussen 80 en 65535.", - "form_error_port_unsafe": "Dit is een onveilige poort.", - "form_error_equal": "Mag niet gelijk zijn.", - "form_error_password": "Wachtwoord komt niet overeen.", + "form_error_port_range": "Poortnummer invoeren tussen 80 en 65535", + "form_error_port_unsafe": "Onveilige poort", + "form_error_equal": "Mag niet gelijk zijn", + "form_error_password": "Wachtwoord komt niet overeen", "reset_settings": "Reset Instellingen", "update_announcement": "AdGuard Home{{version}} is nu beschikbaar! <0>klik hier voor meer info.", "setup_guide": "Installatie gids", "dns_addresses": "DNS adressen", "dns_start": "DNS-server aan het opstarten", - "dns_status_error": "Fout bij het controleren van de DNS-server status.", + "dns_status_error": "Fout bij het controleren van de DNS-server status", "down": "Uitgeschakeld", "fix": "Los op", "dns_providers": "hier is een <0>lijst of gekende DNS providers waarvan je kan kiezen.", @@ -406,7 +408,7 @@ "manual_update": "Volg deze stappen om handmatig bij te werken.", "processing_update": "Even geduld, AdGuard Home wordt bijgewerkt", "clients_title": "Permanente clients", - "clients_desc": "Permanente client-records configureren voor apparaten verboden met AdGuard Home.", + "clients_desc": "Permanente client-records configureren voor apparaten verboden met AdGuard Home", "settings_global": "Globaal", "settings_custom": "Aangepast", "table_client": "Gebruiker", @@ -433,9 +435,9 @@ "client_confirm_delete": "Ben je zeker dat je deze gebruiker \"{{key}}\" wilt verwijderen?", "list_confirm_delete": "Ben je zeker om deze lijst te verwijderen?", "auto_clients_title": "Runtime-clients", - "auto_clients_desc": "Apparaten die niet op de lijst van permanente clients staan die mogelijk nog steeds AdGuard Home gebruiken.", + "auto_clients_desc": "Apparaten die niet op de lijst van permanente clients staan die mogelijk nog steeds AdGuard Home gebruiken", "access_title": "Toegangs instellingen", - "access_desc": "Hier kan je toegangsregels voor de AdGuard Home DNS-server instellen.", + "access_desc": "Hier kan je toegangsregels voor de AdGuard Home DNS-server instellen", "access_allowed_title": "Toegestane gebruikers", "access_allowed_desc": "Een lijst met CIDR's, IP-adressen of Client-ID's. Indien geconfigureerd, accepteert AdGuard Home alleen verzoeken van deze cliënts.", "access_disallowed_title": "Verworpen gebruikers", @@ -475,8 +477,8 @@ "dns_rewrites": "DNS herschrijvingen", "form_domain": "Vul domein of wildcard in", "form_answer": "Vul IP adres of domeinnaam in", - "form_error_domain_format": "Ongeldige opmaak domein.", - "form_error_answer_format": "Ongeldig opmaak antwoord.", + "form_error_domain_format": "Ongeldige opmaak domein", + "form_error_answer_format": "Ongeldige opmaak antwoord", "configure": "Bewerk", "main_settings": "Algemene instellingen", "block_services": "Specifieke services blokkeren", @@ -500,6 +502,7 @@ "interval_days": "{{count}} dagen", "interval_days_plural": "{{count}} dagen", "domain": "Domein", + "ecs": "ECS", "punycode": "Punycode", "answer": "Antwoord", "filter_added_successfully": "De lijst is succesvol toegevoegd", @@ -507,7 +510,7 @@ "filter_updated": "De lijst is succesvol geüpdatet", "statistics_configuration": "Statistieken configuratie", "statistics_retention": "Statistieken retentie", - "statistics_retention_desc": "Als je de intervalwaarde vermindert, zullen sommige gegevens verloren gaan.", + "statistics_retention_desc": "Als je de intervalwaarde vermindert, zullen sommige gegevens verloren gaan", "statistics_clear": "Statistieken wissen", "statistics_clear_confirm": "Alle statistieken werkelijk wissen?", "statistics_retention_confirm": "Weet u zeker dat u de bewaartermijn van de statistieken wilt wijzigen? Als u de intervalwaarde verlaagt, gaan sommige gegevens verloren", @@ -517,7 +520,7 @@ "interval_hours_plural": "{{count}} uren", "filters_configuration": "Filters instellingen", "filters_enable": "Filters inschakelen", - "filters_interval": "Filters update frequentie", + "filters_interval": "Filter update frequentie", "disabled": "Uitgeschakeld", "username_label": "Gebruikersnaam", "username_placeholder": "Voer gebruikersnaam in", @@ -606,7 +609,7 @@ "enter_cache_ttl_max_override": "Maximum TTL invoeren (seconden)", "cache_ttl_min_override_desc": "Uitbreiden van korte Time-To-Live waardes (seconden) ontvangen van de upstream server bij het cachen van DNS antwoorden.", "cache_ttl_max_override_desc": "Instellen van maximum time-to-live waarde (seconden) voor opslag in de DNS cache.", - "ttl_cache_validation": "Minimale waarde TTL-cache moet kleiner dan of gelijk zijn aan de maximale waarde.", + "ttl_cache_validation": "Minimale waarde TTL-cache moet kleiner dan of gelijk zijn aan de maximale waarde", "cache_optimistic": "Optimistisch cachen", "cache_optimistic_desc": "Laat AdGuard Home reageren vanuit de cache, zelfs als de vermeldingen zijn verlopen en probeer deze ook te vernieuwen.", "filter_category_general": "Algemeen", @@ -628,5 +631,5 @@ "parental_control": "Ouderlijk toezicht", "safe_browsing": "Veilig browsen", "served_from_cache": "{{value}} (geleverd vanuit cache)", - "form_error_password_length": "Wachtwoord moet minimaal {{value}} tekens lang zijn." + "form_error_password_length": "Wachtwoord moet minimaal {{value}} tekens lang zijn" } diff --git a/client/src/__locales/pl.json b/client/src/__locales/pl.json index 253a8cac..1d1f5f18 100644 --- a/client/src/__locales/pl.json +++ b/client/src/__locales/pl.json @@ -35,24 +35,24 @@ "dhcp_config_saved": "Konfiguracja DHCP została pomyślnie zapisana", "dhcp_ipv4_settings": "Ustawienia serwera DHCP IPv4", "dhcp_ipv6_settings": "Ustawienia serwera DHCP IPv6", - "form_error_required": "Pole wymagane.", - "form_error_ip4_format": "Nieprawidłowy adres IPv4.", - "form_error_ip4_range_start_format": "Nieprawidłowy adres IPv4 początku zakresu.", - "form_error_ip4_range_end_format": "Nieprawidłowy adres IPv4 końca zakresu.", - "form_error_ip4_gateway_format": "Nieprawidłowy adres IPv4 bramy.", - "form_error_ip6_format": "Nieprawidłowy adres IPv6.", - "form_error_ip_format": "Nieprawidłowy adres IP.", - "form_error_mac_format": "Nieprawidłowy adres MAC.", - "form_error_client_id_format": "ClientID musi zawierać tylko cyfry, małe litery i myślniki.", - "form_error_server_name": "Nieprawidłowa nazwa serwera.", - "form_error_subnet": "Podsieć \"{{cidr}}\" nie zawiera adresu IP \"{{ip}}\".", - "form_error_positive": "Musi być większa niż 0.", - "out_of_range_error": "Musi być spoza zakresu \"{{start}}\"-\"{{end}}\".", - "lower_range_start_error": "Musi być niższy niż początek zakresu.", - "greater_range_start_error": "Musi być większy niż początek zakresu.", - "greater_range_end_error": "Musi być większy niż koniec zakresu.", - "subnet_error": "Adresy muszą należeć do jednej podsieci.", - "gateway_or_subnet_invalid": "Nieprawidłowa maska podsieci.", + "form_error_required": "Pole wymagane", + "form_error_ip4_format": "Nieprawidłowy adres IPv4", + "form_error_ip4_range_start_format": "Nieprawidłowy adres IPv4 początku zakresu", + "form_error_ip4_range_end_format": "Nieprawidłowy adres IPv4 końca zakresu", + "form_error_ip4_gateway_format": "Nieprawidłowy adres IPv4 bramy", + "form_error_ip6_format": "Nieprawidłowy adres IPv6", + "form_error_ip_format": "Nieprawidłowy adres IP", + "form_error_mac_format": "Nieprawidłowy adres MAC", + "form_error_client_id_format": "ClientID musi zawierać tylko cyfry, małe litery i myślniki", + "form_error_server_name": "Nieprawidłowa nazwa serwera", + "form_error_subnet": "Podsieć \"{{cidr}}\" nie zawiera adresu IP \"{{ip}}\"", + "form_error_positive": "Musi być większa niż 0", + "out_of_range_error": "Musi być spoza zakresu \"{{start}}\"-\"{{end}}\"", + "lower_range_start_error": "Musi być niższy niż początek zakresu", + "greater_range_start_error": "Musi być większy niż początek zakresu", + "greater_range_end_error": "Musi być większy niż koniec zakresu", + "subnet_error": "Adresy muszą należeć do jednej podsieci", + "gateway_or_subnet_invalid": "Nieprawidłowa maska podsieci", "dhcp_form_gateway_input": "Adres IP bramy", "dhcp_form_subnet_input": "Maska podsieci", "dhcp_form_range_title": "Zakres adresów IP", @@ -67,7 +67,7 @@ "dhcp_table_hostname": "Nazwa hosta", "dhcp_table_expires": "Wygasa", "dhcp_warning": "Jeśli mimo wszystko chcesz włączyć serwer DHCP, upewnij się, że w Twojej sieci nie ma innego aktywnego serwera DHCP, ponieważ może to spowodować przerwanie łączności z Internetem dla urządzeń w sieci!", - "dhcp_error": "AdGuard Home nie mógł określić, czy w sieci jest inny aktywny serwer DHCP.", + "dhcp_error": "AdGuard Home nie mógł określić, czy w sieci jest inny aktywny serwer DHCP", "dhcp_static_ip_error": "Aby korzystać z serwera DHCP musi być ustawiony statyczny adres IP. AdGuard Home nie udało się ustalić, czy ten interfejs sieciowy jest skonfigurowany przy użyciu statycznego adresu IP. Proszę ustawić statyczny adres IP ręcznie.", "dhcp_dynamic_ip_found": "Twój system używa dynamicznej konfiguracji adresu IP dla interfejsu <0>{{interfaceName}}. Aby można było korzystać z serwera DHCP, należy ustawić statyczny adres IP. Twój obecny adres IP to <0>{{ipAddress}}. AdGuard Home automatycznie ustawi ten adres IP jako statyczny, jeśli naciśniesz przycisk \"Włącz serwer DHCP\".", "dhcp_lease_added": "Dzierżawa statyczna \"{{key}}\" pomyślnie dodana", @@ -196,8 +196,8 @@ "choose_allowlist": "Wybierz listy dozwolonych", "enter_valid_blocklist": "Wpisz prawidłowy adres URL do listy zablokowanych.", "enter_valid_allowlist": "Wpisz prawidłowy adres URL do listy dozwolonych.", - "form_error_url_format": "Nieprawidłowy format URL.", - "form_error_url_or_path_format": "Nieprawidłowy adres URL lub bezwzględna ścieżka listy.", + "form_error_url_format": "Nieprawidłowy format URL", + "form_error_url_or_path_format": "Nieprawidłowy adres URL lub bezwzględna ścieżka listy", "custom_filter_rules": "Niestandardowe reguły filtrowania", "custom_filter_rules_hint": "Wpisz jedną regułę w jednej linii. Możesz użyć reguł adblock lub składni plików hostów.", "system_host_files": "Pliki hosts systemu", @@ -210,11 +210,13 @@ "example_comment_hash": "# Również komentarz.", "example_regex_meaning": "zablokuj dostęp do domen pasujących do określonego wyrażenia regularnego.", "example_upstream_regular": "normalny DNS (przez UDP);", + "example_upstream_udp": "zwykły DNS (przez UDP, nazwa hosta);", "example_upstream_dot": "zaszyfrowany <0>DNS-over-TLS;", "example_upstream_doh": "zaszyfrowany <0>DNS-over-HTTPS;", "example_upstream_doq": "zaszyfrowany <0>DNS-over-QUIC (eksperymentalny);", "example_upstream_sdns": "<0>Stempel DNS dla resolwerów <1>DNSCrypt lub <2>DNS-over-HTTPS;", "example_upstream_tcp": "zwykły DNS (przez TCP);", + "example_upstream_tcp_hostname": "zwykły DNS (przez TCP, nazwa hosta);", "all_lists_up_to_date_toast": "Wszystkie listy są już aktualne", "updated_upstream_dns_toast": "Serwery nadrzędne zostały pomyślnie zapisane", "dns_test_ok_toast": "Określone serwery DNS działają poprawnie", @@ -259,10 +261,10 @@ "query_log_strict_search": "Używaj podwójnych cudzysłowów do ścisłego wyszukiwania", "query_log_retention_confirm": "Czy na pewno chcesz zmienić sposób przechowywania dziennika zapytań? Jeśli zmniejszysz wartość interwału, niektóre dane zostaną utracone", "anonymize_client_ip": "Anonimizuj adres IP klienta", - "anonymize_client_ip_desc": "Nie zapisuj pełnego adresu IP w dziennikach i statystykach.", + "anonymize_client_ip_desc": "Nie zapisuj pełnego adresu IP w dziennikach i statystykach", "dns_config": "Konfiguracja serwera DNS", "dns_cache_config": "Konfiguracja pamięci podręcznej DNS", - "dns_cache_config_desc": "Tutaj możesz skonfigurować pamięć podręczną DNS.", + "dns_cache_config_desc": "Tutaj możesz skonfigurować pamięć podręczną DNS", "blocking_mode": "Tryb blokowania", "default": "Domyślny", "nxdomain": "NXDOMAIN", @@ -285,7 +287,7 @@ "form_enter_rate_limit": "Wpisz limit ilościowy", "rate_limit": "Limit ilościowy", "edns_enable": "Włącz podsieć klienta EDNS", - "edns_cs_desc": "Wyślij podsieci klientów do serwerów DNS.", + "edns_cs_desc": "Dodaj opcję podsieci klienta EDNS (ECS) do żądań nadrzędnych i rejestruj wartości wysyłane przez klientów w dzienniku zapytań.", "rate_limit_desc": "Liczba żądań na sekundę dozwolona na klienta. Ustawienie wartości 0 oznacza brak ograniczeń.", "blocking_ipv4_desc": "Adres IP, który ma zostać zwrócony w przypadku zablokowanego żądania A", "blocking_ipv6_desc": "Adres IP, który ma zostać zwrócony w przypadku zablokowanego żądania AAAA", @@ -309,7 +311,7 @@ "install_settings_listen": "Interfejs sieciowy", "install_settings_port": "Port", "install_settings_interface_link": "Twój interfejs www AdGuard Home Admin będzie dostępny pod następującymi adresami:", - "form_error_port": "Wprowadź prawidłowy numer portu.", + "form_error_port": "Wprowadź prawidłowy numer portu", "install_settings_dns": "Serwer DNS", "install_settings_dns_desc": "Konieczne będzie skonfigurowanie urządzenia lub routera do korzystania z serwera DNS pod następującymi adresami:", "install_settings_all_interfaces": "Wszystkie interfejsy", @@ -356,7 +358,7 @@ "open_dashboard": "Otwórz panel sterowania", "install_saved": "Pomyślnie zapisany", "encryption_title": "Szyfrowanie", - "encryption_desc": "Obsługa szyfrowania (HTTPS/TLS) dla interfejsu sieciowego DNS i administratora.", + "encryption_desc": "Obsługa szyfrowania (HTTPS/TLS) dla interfejsu sieciowego DNS i administratora", "encryption_config_saved": "Konfiguracja szyfrowania została zapisana", "encryption_server": "Nazwa serwera", "encryption_server_enter": "Wpisz swoją nazwę domeny", @@ -378,26 +380,26 @@ "encryption_key_input": "Tutaj kopiuj/wklej klucze prywatne zakodowane w PEM do swojego certyfikatu.", "encryption_enable": "Włącz szyfrowanie (HTTPS, DNS-over-HTTPS i DNS-over-TLS)", "encryption_enable_desc": "Jeśli szyfrowanie jest włączone, interfejs administracyjny AdGuard Home będzie działał przez HTTPS, a serwer DNS będzie nasłuchiwał żądań przez DNS-over-HTTPS i DNS-over-TLS.", - "encryption_chain_valid": "Łańcuch certyfikatów jest prawidłowy.", - "encryption_chain_invalid": "Łańcuch certyfikatu jest nieprawidłowy.", - "encryption_key_valid": "Poprawny {{type}} klucz prywatny.", - "encryption_key_invalid": "Nieprawidłowy {{type}} klucz prywatny.", + "encryption_chain_valid": "Łańcuch certyfikatów jest prawidłowy", + "encryption_chain_invalid": "Łańcuch certyfikatu jest nieprawidłowy", + "encryption_key_valid": "Poprawny {{type}} klucz prywatny", + "encryption_key_invalid": "Nieprawidłowy {{type}} klucz prywatny", "encryption_subject": "Temat", "encryption_issuer": "Zgłaszający", "encryption_hostnames": "Nazwy hostów", "encryption_reset": "Czy na pewno chcesz zresetować ustawienia szyfrowania?", "topline_expiring_certificate": "Twój certyfikat SSL wkrótce wygaśnie. Zaktualizuj <0>Ustawienia szyfrowania.", "topline_expired_certificate": "Twój certyfikat SSL wygasł. Zaktualizuj <0>Ustawienia szyfrowania.", - "form_error_port_range": "Wpisz numer portu z zakresu 80-65535.", - "form_error_port_unsafe": "To jest niebezpieczny port.", - "form_error_equal": "Nie mogą być równe.", - "form_error_password": "Niezgodne hasło.", + "form_error_port_range": "Wpisz numer portu z zakresu 80-65535", + "form_error_port_unsafe": "Niebezpieczny port", + "form_error_equal": "Nie mogą być równe", + "form_error_password": "Niezgodne hasło", "reset_settings": "Resetowanie ustawień", "update_announcement": "AdGuard Home {{version}} jest już dostępny! <0>Kliknij tutaj aby uzyskać więcej informacji.", "setup_guide": "Przewodnik instalacji", "dns_addresses": "Adresy DNS", "dns_start": "Serwer DNS uruchamia się", - "dns_status_error": "Błąd podczas sprawdzania stanu serwera DNS.", + "dns_status_error": "Błąd podczas sprawdzania stanu serwera DNS", "down": "Utrata połączenia", "fix": "Napraw", "dns_providers": "Oto lista <0>znanych dostawców DNS do wyboru.", @@ -406,7 +408,7 @@ "manual_update": "Proszę wykonać te czynności, aby zaktualizować ręcznie.", "processing_update": "Poczekaj, trwa aktualizacja AdGuard Home", "clients_title": "Trwali klienci", - "clients_desc": "Skonfiguruj trwałe rekordy klienta dla urządzeń podłączonych do AdGuard Home.", + "clients_desc": "Skonfiguruj trwałe rekordy klienta dla urządzeń podłączonych do AdGuard Home", "settings_global": "Globalny", "settings_custom": "Własne", "table_client": "Klient", @@ -433,9 +435,9 @@ "client_confirm_delete": "Czy na pewno chcesz usunąć klienta \"{{key}}\"?", "list_confirm_delete": "Czy na pewno chcesz usunąć tę listę?", "auto_clients_title": "Uruchomieni klienci", - "auto_clients_desc": "Urządzenia, których nie ma na liście stałych klientów, które mogą nadal korzystać z AdGuard Home.", + "auto_clients_desc": "Urządzenia, których nie ma na liście stałych klientów, które mogą nadal korzystać z AdGuard Home", "access_title": "Ustawienia dostępu", - "access_desc": "Tutaj możesz skonfigurować reguły dostępu dla serwera DNS AdGuard Home.", + "access_desc": "Tutaj możesz skonfigurować reguły dostępu dla serwera DNS AdGuard Home", "access_allowed_title": "Dozwoleni klienci", "access_allowed_desc": "Lista identyfikatorów CIDR, adresów IP lub identyfikatorów klienta. Jeśli ta lista zawiera wpisy, AdGuard Home zaakceptuje żądania tylko od tych klientów.", "access_disallowed_title": "Niedozwoleni klienci", @@ -475,8 +477,8 @@ "dns_rewrites": "Przepisywanie DNS", "form_domain": "Wpisz nazwę domeny lub symbol wieloznaczny", "form_answer": "Wpisz adres IP lub nazwę domeny", - "form_error_domain_format": "Niepoprawny format domeny.", - "form_error_answer_format": "Nieprawidłowy format odpowiedzi.", + "form_error_domain_format": "Niepoprawny format domeny", + "form_error_answer_format": "Nieprawidłowy format odpowiedzi", "configure": "Skonfiguruj", "main_settings": "Ustawienia główne", "block_services": "Zablokuj określone usługi", @@ -500,6 +502,7 @@ "interval_days": "{{count}} dni", "interval_days_plural": "{{count}} dni", "domain": "Domena", + "ecs": "ECS", "punycode": "Punycode", "answer": "Odpowiedź", "filter_added_successfully": "Lista została pomyślnie dodana", @@ -507,7 +510,7 @@ "filter_updated": "Filtr został pomyślnie zaktualizowany", "statistics_configuration": "Konfiguracja statystyk", "statistics_retention": "Przechowywanie statystyk", - "statistics_retention_desc": "Jeśli zmniejszysz wartość interwału, niektóre dane zostaną utracone.", + "statistics_retention_desc": "Jeśli zmniejszysz wartość interwału, niektóre dane zostaną utracone", "statistics_clear": "Wyczyść statystyki", "statistics_clear_confirm": "Czy na pewno chcesz wyczyścić statystyki?", "statistics_retention_confirm": "Czy chcesz zmienić sposób przechowania statystyk? Jeżeli obniżysz wartość interwału, niektóre dane będą utracone", @@ -517,7 +520,7 @@ "interval_hours_plural": "{{count}} godziny", "filters_configuration": "Konfiguracja filtrów", "filters_enable": "Włącz filtry", - "filters_interval": "Częstotliwość aktualizacji filtrów", + "filters_interval": "Aktualizuj filtry co", "disabled": "Wyłączone", "username_label": "Nazwa użytkownika", "username_placeholder": "Wpisz nazwę użytkownika", @@ -606,7 +609,7 @@ "enter_cache_ttl_max_override": "Wpisz maksymalną wartość TTL (w sekundach)", "cache_ttl_min_override_desc": "Przedłuż najkrótszą wartość TTL (w sekundach) otrzymaną od serwera wychodzącego podczas buforowania odpowiedzi DNS.", "cache_ttl_max_override_desc": "Ustaw maksymalną wartość czasu życia (w sekundach) dla wpisów w pamięci podręcznej DNS.", - "ttl_cache_validation": "Minimalne nadpisanie pamięci podręcznej TTL musi być mniejsze lub równe maksimum.", + "ttl_cache_validation": "Minimalne nadpisanie pamięci podręcznej TTL musi być mniejsze lub równe maksimum", "cache_optimistic": "Optymistyczne buforowanie", "cache_optimistic_desc": "Spraw, aby AdGuard Home odpowiadał z pamięci podręcznej, nawet gdy wpisy wygasły, a także spróbuj je odświeżyć.", "filter_category_general": "Ogólne", @@ -628,5 +631,5 @@ "parental_control": "Kontrola rodzicielska", "safe_browsing": "Bezpieczne przeglądanie", "served_from_cache": "{{value}} (podawane z pamięci podręcznej)", - "form_error_password_length": "Hasło musi mieć przynajmniej {{value}} znaków." + "form_error_password_length": "Hasło musi mieć co najmniej {{value}} znaków" } diff --git a/client/src/__locales/pt-br.json b/client/src/__locales/pt-br.json index 56c91880..48d82e0d 100644 --- a/client/src/__locales/pt-br.json +++ b/client/src/__locales/pt-br.json @@ -35,24 +35,24 @@ "dhcp_config_saved": "Configurações DHCP salvas com sucesso", "dhcp_ipv4_settings": "Configurações DHCP IPv4", "dhcp_ipv6_settings": "Configurações DHCP IPv6", - "form_error_required": "Campo obrigatório.", - "form_error_ip4_format": "Endereço de IPv4 inválido.", - "form_error_ip4_range_start_format": "Endereço IPv4 de início de intervalo inválido.", + "form_error_required": "Campo obrigatório", + "form_error_ip4_format": "Endereço de IPv4 inválido", + "form_error_ip4_range_start_format": "Endereço IPv4 de início de intervalo inválido", "form_error_ip4_range_end_format": "Endereço IPv4 de fim de intervalo inválido.", - "form_error_ip4_gateway_format": "Endereço IPv4 de gateway inválido.", - "form_error_ip6_format": "Endereço de IPv6 inválido.", - "form_error_ip_format": "Endereço de IP inválido.", - "form_error_mac_format": "Endereço de MAC inválido.", + "form_error_ip4_gateway_format": "Endereço IPv4 de gateway inválido", + "form_error_ip6_format": "Endereço de IPv6 inválido", + "form_error_ip_format": "Endereço de IP inválido", + "form_error_mac_format": "Endereço de MAC inválido", "form_error_client_id_format": "O ID do cliente deve conter apenas números, letras minúsculas e hifens", - "form_error_server_name": "Nome de servidor inválido.", - "form_error_subnet": "A sub-rede \"{{cidr}}\" não contém o endereço IP \"{{ip}}\".", - "form_error_positive": "Deve ser maior que 0.", - "out_of_range_error": "Deve estar fora do intervalo \"{{start}}\"-\"{{end}}\".", - "lower_range_start_error": "Deve ser inferior ao início do intervalo.", - "greater_range_start_error": "Deve ser maior que o início do intervalo.", - "greater_range_end_error": "Deve ser maior que o fim do intervalo.", - "subnet_error": "Endereços devem estar em uma sub-rede.", - "gateway_or_subnet_invalid": "Máscara de sub-rede inválida.", + "form_error_server_name": "Nome de servidor inválido", + "form_error_subnet": "A sub-rede \"{{cidr}}\" não contém o endereço IP \"{{ip}}\"", + "form_error_positive": "Deve ser maior que 0", + "out_of_range_error": "Deve estar fora do intervalo \"{{start}}\"-\"{{end}}\"", + "lower_range_start_error": "Deve ser inferior ao início do intervalo", + "greater_range_start_error": "Deve ser maior que o início do intervalo", + "greater_range_end_error": "Deve ser maior que o fim do intervalo", + "subnet_error": "Endereços devem estar em uma sub-rede", + "gateway_or_subnet_invalid": "Máscara de sub-rede inválida", "dhcp_form_gateway_input": "IP do gateway", "dhcp_form_subnet_input": "Máscara de sub-rede", "dhcp_form_range_title": "Faixa de endereços IP", @@ -67,7 +67,7 @@ "dhcp_table_hostname": "Nome do servidor", "dhcp_table_expires": "Expira", "dhcp_warning": "Se você quiser ativar o servidor DHCP de qualquer maneira, certifique-se de que não haja outro servidor DHCP ativo em sua rede, pois isso pode quebrar a conectividade com a Internet para dispositivos na rede!", - "dhcp_error": "O AdGuard Home não conseguiu determinar se há outro servidor DHCP ativo na rede.", + "dhcp_error": "O AdGuard Home não conseguiu determinar se há outro servidor DHCP ativo na rede", "dhcp_static_ip_error": "Para usar o servidor DHCP, você deve definir um endereço IP estático. AdGuard Home não conseguiu determinar se essa interface de rede está configurada usando o endereço de IP estático. Por favor, defina um endereço IP estático manualmente.", "dhcp_dynamic_ip_found": "Seu sistema usa a configuração de endereço IP dinâmico para a interface <0>{{interfaceName}}. Para usar o servidor DHCP, você deve definir um endereço de IP estático. Seu endereço IP atual é <0> {{ipAddress}} . AdGuard Home irá definir automaticamente este endereço IP como estático se você pressionar o botão \"Ativar servidor DHCP\".", "dhcp_lease_added": "Concessão estática \"{{key}}\" adicionada com sucesso", @@ -196,8 +196,8 @@ "choose_allowlist": "Escolher as listas de permissões", "enter_valid_blocklist": "Digite um URL válido para a lista de bloqueio.", "enter_valid_allowlist": "Digite uma URL válida para a lista de permissões.", - "form_error_url_format": "Formato da URL inválida.", - "form_error_url_or_path_format": "URL ou local da lista inválida.", + "form_error_url_format": "Formato da URL inválida", + "form_error_url_or_path_format": "URL ou local da lista inválida", "custom_filter_rules": "Regras de filtragem personalizadas", "custom_filter_rules_hint": "Digite uma regra por linha. Você pode usar regras de bloqueio de anúncios ou a sintaxe de arquivos de hosts.", "system_host_files": "Arquivos hosts do sistema", @@ -210,11 +210,13 @@ "example_comment_hash": "# Também um comentário.", "example_regex_meaning": "bloqueia o acesso aos domínios que correspondem à expressão regular especificada.", "example_upstream_regular": "dNS regular (através do UDP);", + "example_upstream_udp": "DNS normal (através do UDP, nome do servidor);", "example_upstream_dot": "<0>DNS-sobre-TLS criptografado;", "example_upstream_doh": "<0>DNS-sobre-HTTPS criptografado;", "example_upstream_doq": "<0>DNS-sobre-QUIC criptografado (experimental);", "example_upstream_sdns": "<0>DNS Stamps para o <1>DNSCrypt ou usar os resolvedores <2>DNS-sobre-HTTPS;", "example_upstream_tcp": "DNS regular (através do TCP);", + "example_upstream_tcp_hostname": "DNS normal (através do TCP, nome do servidor);", "all_lists_up_to_date_toast": "Todas as listas já estão atualizadas", "updated_upstream_dns_toast": "Servidores DNS primário salvos com sucesso", "dns_test_ok_toast": "Os servidores DNS especificados estão funcionando corretamente", @@ -259,10 +261,10 @@ "query_log_strict_search": "Use aspas duplas para uma pesquisa mais criteriosa", "query_log_retention_confirm": "Você tem certeza de que deseja alterar o arquivamento do registro de consulta? Se diminuir o valor de intervalo, alguns dados serão perdidos", "anonymize_client_ip": "Tornar anônimo o IP do cliente", - "anonymize_client_ip_desc": "Não salva o endereço de IP completo do cliente em registros ou estatísticas.", + "anonymize_client_ip_desc": "Não salva o endereço de IP completo do cliente em registros ou estatísticas", "dns_config": "Configuração do servidor DNS", "dns_cache_config": "Configuração de cache DNS", - "dns_cache_config_desc": "Aqui você pode configurar o cache do DNS.", + "dns_cache_config_desc": "Aqui você pode configurar o cache do DNS", "blocking_mode": "Modo de bloqueio", "default": "Padrão", "nxdomain": "NXDOMAIN", @@ -285,7 +287,7 @@ "form_enter_rate_limit": "Insira a taxa limite", "rate_limit": "Taxa limite", "edns_enable": "Ativar a sub-rede do cliente EDNS", - "edns_cs_desc": "Envia as sub-redes dos clientes para os servidores DNS.", + "edns_cs_desc": "Adicione a opção de sub-rede de cliente EDNS (ECS) às solicitações de servidor DNS primário e registre os valores enviados pelos clientes no registro de consulta.", "rate_limit_desc": "O número de solicitações por segundo permitidas por cliente. Definir como 0 significa que não há limite.", "blocking_ipv4_desc": "Endereço de IP a ser retornado para uma solicitação bloqueada", "blocking_ipv6_desc": "Endereço de IP a ser retornado para uma solicitação AAAA bloqueada", @@ -309,7 +311,7 @@ "install_settings_listen": "Interface de escuta", "install_settings_port": "Porta", "install_settings_interface_link": "A interface web de administrador do AdGuard estará disponível nos seguintes endereços:", - "form_error_port": "Digite um numero de porta válida.", + "form_error_port": "Digite um numero de porta válida", "install_settings_dns": "Servidor DNS", "install_settings_dns_desc": "Você precisa configurar seu dispositivo ou roteador para usar o servidor DNS nos seguintes endereços:", "install_settings_all_interfaces": "Todas interfaces", @@ -356,7 +358,7 @@ "open_dashboard": "Abrir painel", "install_saved": "Salvo com sucesso", "encryption_title": "Criptografia", - "encryption_desc": "Suporte a criptografia (HTTPS/TLS) para DNS e interface de administração web.", + "encryption_desc": "Suporte a criptografia (HTTPS/QUIC/TLS) para DNS e interface de administração web", "encryption_config_saved": "Configuração de criptografia salva", "encryption_server": "Nome do servidor", "encryption_server_enter": "Digite seu nome de domínio", @@ -378,26 +380,26 @@ "encryption_key_input": "Copie/cole aqui a chave privada codificada em PEM para seu certificado.", "encryption_enable": "Ativar criptografia (HTTPS, DNS-sobre-HTTPS e DNS-sobre-TLS)", "encryption_enable_desc": "Se a criptografia estiver ativada, a interface administrativa do AdGuard Home funcionará em HTTPS, o servidor DNS irá capturar as solicitações por meio do DNS-sobre-HTTPS e DNS-sobre-TLS.", - "encryption_chain_valid": "Cadeia de chave válida.", - "encryption_chain_invalid": "A cadeia de certificado é inválida.", - "encryption_key_valid": "Esta é uma chave privada {{type}} válida.", - "encryption_key_invalid": "Esta é uma chave privada {{type}} inválida.", + "encryption_chain_valid": "Cadeia de chave válida", + "encryption_chain_invalid": "A cadeia de certificado é inválida", + "encryption_key_valid": "Esta é uma chave privada {{type}} válida", + "encryption_key_invalid": "Esta é uma chave privada {{type}} inválida", "encryption_subject": "Assunto", "encryption_issuer": "Emissor", "encryption_hostnames": "Nomes dos servidores", "encryption_reset": "Você tem certeza de que deseja redefinir a configuração de criptografia?", "topline_expiring_certificate": "Seu certificado SSL está prestes a expirar. Atualize suas <0>configurações de criptografia", "topline_expired_certificate": "Seu certificado SSL está expirado. Atualize suas <0>configurações de criptografia", - "form_error_port_range": "Digite um número de porta entre 80 e 65535.", - "form_error_port_unsafe": "Esta porta não é segura.", - "form_error_equal": "Não deve ser igual.", - "form_error_password": "Senhas não coincidem.", + "form_error_port_range": "Digite um número de porta entre 80 e 65535", + "form_error_port_unsafe": "Porta não é segura", + "form_error_equal": "Não deve ser igual", + "form_error_password": "Senhas não coincidem", "reset_settings": "Redefinir configurações", "update_announcement": "AdGuard Home {{version}} está disponível!<0>Clique aqui para mais informações.", "setup_guide": "Guia de configuração", "dns_addresses": "Endereços DNS", "dns_start": "O servidor DNS está iniciando", - "dns_status_error": "Ocorreu um erro ao verificar o status do servidor DNS.", + "dns_status_error": "Ocorreu um erro ao verificar o status do servidor DNS", "down": "Caiu", "fix": "Corrigido", "dns_providers": "Aqui está uma <0>lista de provedores de DNS conhecidos para escolher.", @@ -406,7 +408,7 @@ "manual_update": "Por favor, siga estes passos para atualizar manualmente.", "processing_update": "Por favor, aguarde enquanto o AdGuard Home está sendo atualizado", "clients_title": "Clientes persistentes", - "clients_desc": "Configure registros de cliente persistentes para dispositivos conectados ao AdGuard Home.", + "clients_desc": "Configure registros de cliente persistentes para dispositivos conectados ao AdGuard Home", "settings_global": "Global", "settings_custom": "Personalizado", "table_client": "Cliente", @@ -433,9 +435,9 @@ "client_confirm_delete": "Você tem certeza de que deseja excluir o cliente \"{{key}}\"?", "list_confirm_delete": "Você tem certeza de que deseja excluir essa lista?", "auto_clients_title": "Clientes ativos", - "auto_clients_desc": "Dispositivo não está na lista de dispositivos persistentes que podem ser utilizados no AdGuard Home.", + "auto_clients_desc": "Dispositivo não está na lista de dispositivos persistentes que podem ser utilizados no AdGuard Home", "access_title": "Configurações de acessos", - "access_desc": "Aqui você pode configurar as regras de acesso para o servidores de DNS do AdGuard Home.", + "access_desc": "Aqui você pode configurar as regras de acesso para o servidores de DNS do AdGuard Home", "access_allowed_title": "Clientes permitidos", "access_allowed_desc": "Uma lista de CIDRs, endereços IP ou IDs de cliente. Se esta lista tiver entradas, o AdGuard Home do aceitará solicitações apenas desses clientes.", "access_disallowed_title": "Clientes não permitidos", @@ -475,8 +477,8 @@ "dns_rewrites": "Reescritas de DNS", "form_domain": "Digite o nome do domínio ou wildcard", "form_answer": "Digite o endereço de IP ou nome de domínio", - "form_error_domain_format": "Formato de domínio inválido.", - "form_error_answer_format": "Formato de resposta inválido.", + "form_error_domain_format": "Formato de domínio inválido", + "form_error_answer_format": "Formato de resposta inválido", "configure": "Configurar", "main_settings": "Configurações principais", "block_services": "Bloquear serviços específicos", @@ -500,6 +502,7 @@ "interval_days": "{{count}} dias", "interval_days_plural": "{{count}} dias", "domain": "Domínio", + "ecs": "ECS", "punycode": "Punycode", "answer": "Resposta", "filter_added_successfully": "O filtro foi adicionado com sucesso", @@ -507,7 +510,7 @@ "filter_updated": "O filtro atualizado com sucesso", "statistics_configuration": "Configurações de estatísticas", "statistics_retention": "Permanência das estatísticas", - "statistics_retention_desc": "Se você diminuir o valor do intervalo, alguns dados serão perdidos.", + "statistics_retention_desc": "Se você diminuir o valor do intervalo, alguns dados serão perdidos", "statistics_clear": " Limpar estatísticas", "statistics_clear_confirm": "Você tem certeza de que deseja limpar as estatísticas?", "statistics_retention_confirm": "Você tem certeza que quer alterar o arquivamento das estatísticas? Se diminuir o valor do intervalo, alguns dados serão perdidos", @@ -517,7 +520,7 @@ "interval_hours_plural": "{{count}} horas", "filters_configuration": "Configuração de filtros", "filters_enable": "Ativar filtros", - "filters_interval": "Intervalo de atualização de filtros", + "filters_interval": "Intervalo de atualização de filtro", "disabled": "Desativado", "username_label": "Nome de usuário", "username_placeholder": "Digite o nome de usuário", @@ -606,7 +609,7 @@ "enter_cache_ttl_max_override": "Digite o TTL máximo (segundos)", "cache_ttl_min_override_desc": "Prolongue os valores de curta duração (segundos) recebidos do servidor primário ao armazenar em cache as respostas DNS.", "cache_ttl_max_override_desc": "Defina um valor máximo de tempo de vida (segundos) para entradas no cache DNS.", - "ttl_cache_validation": "O substituto mínimo de cache TTL deve ser menor ou igual ao máximo.", + "ttl_cache_validation": "O substituto mínimo de cache TTL deve ser menor ou igual ao máximo", "cache_optimistic": "Cache otimista", "cache_optimistic_desc": "Faz o AdGuard Home responder a partir do cache mesmo quando as entradas expirarem e também tenta atualizá-las.", "filter_category_general": "Geral", @@ -628,5 +631,5 @@ "parental_control": "Controle parental", "safe_browsing": "Navegação segura", "served_from_cache": "{{value}} (servido do cache)", - "form_error_password_length": "A senha deve ter pelo menos {{value}} caracteres." + "form_error_password_length": "A senha deve ter pelo menos {{value}} caracteres" } diff --git a/client/src/__locales/pt-pt.json b/client/src/__locales/pt-pt.json index 068ebc03..1a2d5c7c 100644 --- a/client/src/__locales/pt-pt.json +++ b/client/src/__locales/pt-pt.json @@ -35,24 +35,24 @@ "dhcp_config_saved": "Definições DHCP guardadas com sucesso", "dhcp_ipv4_settings": "Definições DHCP IPv4", "dhcp_ipv6_settings": "Definições DHCP IPv6", - "form_error_required": "Campo obrigatório.", - "form_error_ip4_format": "Endereço de IPv4 inválido.", - "form_error_ip4_range_start_format": "Endereço IPv4 de início de intervalo inválido.", - "form_error_ip4_range_end_format": "Endereço IPv4 de fim de intervalo inválido.", - "form_error_ip4_gateway_format": "Endereço IPv4 de gateway inválido.", - "form_error_ip6_format": "Endereço de IPv6 inválido.", - "form_error_ip_format": "Endereço de IP inválido.", - "form_error_mac_format": "Endereço de MAC inválido.", + "form_error_required": "Campo obrigatório", + "form_error_ip4_format": "Endereço de IPv4 inválido", + "form_error_ip4_range_start_format": "Endereço IPv4 de início de intervalo inválido", + "form_error_ip4_range_end_format": "Endereço IPv4 de fim de intervalo inválido", + "form_error_ip4_gateway_format": "Endereço IPv4 de gateway inválido", + "form_error_ip6_format": "Endereço de IPv6 inválido", + "form_error_ip_format": "Endereço de email inválido", + "form_error_mac_format": "Endereço de MAC inválido", "form_error_client_id_format": "O ID do cliente deve conter apenas números, letras minúsculas e hifens", - "form_error_server_name": "Nome de servidor inválido.", - "form_error_subnet": "A sub-rede \"{{cidr}}\" não contém o endereço IP \"{{ip}}\".", - "form_error_positive": "Deve ser maior que 0.", - "out_of_range_error": "Deve estar fora do intervalo \"{{start}}\"-\"{{end}}\".", - "lower_range_start_error": "Deve ser inferior ao início do intervalo.", - "greater_range_start_error": "Deve ser maior que o início do intervalo.", - "greater_range_end_error": "Deve ser maior que o fim do intervalo.", - "subnet_error": "Os endereços devem estar em uma sub-rede.", - "gateway_or_subnet_invalid": "Máscara de sub-rede inválida.", + "form_error_server_name": "Nome de servidor inválido", + "form_error_subnet": "A sub-rede \"{{cidr}}\" não contém o endereço IP \"{{ip}}\"", + "form_error_positive": "Deve ser maior que 0", + "out_of_range_error": "Deve estar fora do intervalo \"{{start}}\"-\"{{end}}\"", + "lower_range_start_error": "Deve ser inferior ao início do intervalo", + "greater_range_start_error": "Deve ser maior que o início do intervalo", + "greater_range_end_error": "Deve ser maior que o fim do intervalo", + "subnet_error": "Os endereços devem estar em uma sub-rede", + "gateway_or_subnet_invalid": "Máscara de sub-rede inválida", "dhcp_form_gateway_input": "IP do gateway", "dhcp_form_subnet_input": "Máscara de sub-rede", "dhcp_form_range_title": "Faixa de endereços IP", @@ -67,7 +67,7 @@ "dhcp_table_hostname": "Nome do servidor", "dhcp_table_expires": "Expira", "dhcp_warning": "Se tu quiser ativar o servidor DHCP de qualquer maneira, certifique-se de que não haja outro servidor DHCP ativo em tua rede, pois isso pode quebrar a conectividade com a Internet para dispositivos na rede!", - "dhcp_error": "O AdGuard Home não conseguiu determinar se há noutro servidor DHCP ativo na rede.", + "dhcp_error": "O AdGuard Home não conseguiu determinar se há noutro servidor DHCP ativo na rede", "dhcp_static_ip_error": "Para usar o servidor DHCP, deve definir um endereço IP estático. AdGuard Home não conseguiu determinar se essa interface de rede está configurada usando o endereço de IP estático. Por favor, defina um endereço IP estático manualmente.", "dhcp_dynamic_ip_found": "O seu sistema usa a configuração de endereço IP dinâmico para a interface <0>{{interfaceName}}. Para usar o servidor DHCP, deve definir um endereço de IP estático. O seu endereço IP atual é <0> {{ipAddress}} . AdGuard Home irá definir automaticamente este endereço IP como estático se pressionar o botão \"Ativar servidor DHCP\".", "dhcp_lease_added": "Concessão estática \"{{key}}\" adicionada com sucesso", @@ -196,8 +196,8 @@ "choose_allowlist": "Escolher as listas de permissões", "enter_valid_blocklist": "Digite uma URL válida para a lista de bloqueio.", "enter_valid_allowlist": "Digite uma URL válida para a lista de permissões.", - "form_error_url_format": "Formato da URL inválida.", - "form_error_url_or_path_format": "URL ou local da lista inválida.", + "form_error_url_format": "Formato da URL inválida", + "form_error_url_or_path_format": "URL ou local da lista inválida", "custom_filter_rules": "Regras de filtragem personalizadas", "custom_filter_rules_hint": "Insira uma regra por linha. Pode usar regras de bloqueio de anúncios ou a sintaxe de ficheiros de hosts.", "system_host_files": "Arquivos hosts do sistema", @@ -210,11 +210,13 @@ "example_comment_hash": "# Também um comentário.", "example_regex_meaning": "bloquear o acesso aos domínios que correspondam à expressão regular especificada.", "example_upstream_regular": "DNS regular (através do UDP)", + "example_upstream_udp": "DNS normal (através do UDP, nome do servidor);", "example_upstream_dot": "<0>DNS-sobre-TLS criptografado;", "example_upstream_doh": "<0>DNS-sobre-HTTPS criptografado;", "example_upstream_doq": "<0>DNS-sobre-QUIC criptografado (experimental);", "example_upstream_sdns": "<0>DNS Stamps para o <1>DNSCrypt ou usar os resolvedores <2>DNS-sobre-HTTPS;", "example_upstream_tcp": "DNS regular (através do TCP);", + "example_upstream_tcp_hostname": "DNS normal (através do TCP, nome do servidor);", "all_lists_up_to_date_toast": "Todas as listas já estão atualizadas", "updated_upstream_dns_toast": "Servidores DNS primário guardados com sucesso", "dns_test_ok_toast": "Os servidores DNS especificados estão a funcionar corretamente", @@ -259,10 +261,10 @@ "query_log_strict_search": "Usar aspas duplas para uma pesquisa rigorosa", "query_log_retention_confirm": "Tem a certeza de que deseja alterar a retenção do registo de consulta? Se diminuir o valor do intervalo, alguns dados serão perdidos", "anonymize_client_ip": "Tornar anónimo o IP do cliente", - "anonymize_client_ip_desc": "Não gurda o endereço de IP completo do cliente em registros ou estatísticas.", + "anonymize_client_ip_desc": "Não gurda o endereço de IP completo do cliente em registros ou estatísticas", "dns_config": "Definição do servidor DNS", "dns_cache_config": "Definição de cache DNS", - "dns_cache_config_desc": "Aqui você pode configurar o cache do DNS.", + "dns_cache_config_desc": "Aqui você pode configurar o cache do DNS", "blocking_mode": "Modo de bloqueio", "default": "Predefinido", "nxdomain": "NXDOMAIN", @@ -285,7 +287,7 @@ "form_enter_rate_limit": "Insira o limite de taxa", "rate_limit": "Limite de taxa", "edns_enable": "Ativar a sub-rede do cliente EDNS", - "edns_cs_desc": "Envia as sub-redes dos clientes para os servidores DNS.", + "edns_cs_desc": "Adicione a opção de sub-rede de cliente EDNS (ECS) às solicitações de servidor DNS primário e registre os valores enviados pelos clientes no registro de consulta.", "rate_limit_desc": "O número de solicitações por segundo permitido por cliente. Configurando para 0 significa sem limite.", "blocking_ipv4_desc": "Endereço IP a ser devolvido para uma solicitação A bloqueada", "blocking_ipv6_desc": "Endereço IP a ser devolvido para uma solicitação AAAA bloqueada", @@ -356,7 +358,7 @@ "open_dashboard": "Abrir Painel", "install_saved": "Guardado com sucesso", "encryption_title": "Encriptação", - "encryption_desc": "Suporta a criptografia (HTTPS/TLS) para DNS e interface de administração web.", + "encryption_desc": "Suporta a criptografia (HTTPS/QUIC/TLS) para DNS e interface de administração web", "encryption_config_saved": "Definição de criptografia guardada", "encryption_server": "Nome do servidor", "encryption_server_enter": "Insira o seu nome de domínio", @@ -378,26 +380,26 @@ "encryption_key_input": "Copie/cole aqui a chave privada codificada em PEM para o seu certificado.", "encryption_enable": "Ativar criptografia (HTTPS, DNS-sobre-HTTPS e DNS-sobre-TLS)", "encryption_enable_desc": "Se a criptografia estiver ativada, a interface administrativa do AdGuard Home funcionará em HTTPS, o servidor DNS irá capturar as solicitações por meio do DNS-sobre-HTTPS e DNS-sobre-TLS.", - "encryption_chain_valid": "Cadeia de certificado válida.", - "encryption_chain_invalid": "A cadeia de certificado é inválida.", - "encryption_key_valid": "Esta é uma chave privada {{type}} válida.", - "encryption_key_invalid": "Esta é uma chave privada {{type}} inválida.", + "encryption_chain_valid": "Cadeia de certificado válida", + "encryption_chain_invalid": "A cadeia de certificado é inválida", + "encryption_key_valid": "Esta é uma chave privada {{type}} válida", + "encryption_key_invalid": "Esta é uma chave privada {{type}} inválida", "encryption_subject": "Assunto", "encryption_issuer": "Emissor", "encryption_hostnames": "Nomes dos servidores", "encryption_reset": "Tem a certeza de que deseja repor a definição de criptografia?", "topline_expiring_certificate": "O seu certificado SSL está prestes a expirar. Atualize as suas <0>definições de criptografia.", "topline_expired_certificate": "O seu certificado SSL está expirado. Atualize as suas <0>definições de criptografia.", - "form_error_port_range": "Digite um numero de porta entre 80 e 65535.", - "form_error_port_unsafe": "Esta porta não é segura.", - "form_error_equal": "Não deve ser igual.", - "form_error_password": "As palavras-passe não coincidem.", + "form_error_port_range": "Digite um numero de porta entre 80 e 65535", + "form_error_port_unsafe": "Porta não é segura", + "form_error_equal": "Não deve ser igual", + "form_error_password": "As palavras-passe não coincidem", "reset_settings": "Repor definições", "update_announcement": "AdGuard Home {{version}} está disponível!<0>Clique aqui para mais informações.", "setup_guide": "Guia de instalação", "dns_addresses": "Endereços DNS", "dns_start": "O servidor DNS está a iniciar", - "dns_status_error": "Ocorreu um erro ao verificar o estado do servidor DNS.", + "dns_status_error": "Ocorreu um erro ao verificar o estado do servidor DNS", "down": "Caiu", "fix": "Corrigido", "dns_providers": "Aqui está uma <0>lista de provedores de DNS conhecidos para escolher.", @@ -406,7 +408,7 @@ "manual_update": "Por favor, siga estes passos para atualizar manualmente.", "processing_update": "Por favor espere, o AdGuard Home está a atualizar-se", "clients_title": "Clientes persistentes", - "clients_desc": "Configure registros de cliente persistentes para dispositivos conectados ao AdGuard Home.", + "clients_desc": "Configure registros de cliente persistentes para dispositivos conectados ao AdGuard Home", "settings_global": "Global", "settings_custom": "Personalizar", "table_client": "Cliente", @@ -433,9 +435,9 @@ "client_confirm_delete": "Tem a certeza de que deseja excluir o cliente \"{{key}}\"?", "list_confirm_delete": "Você tem certeza de que deseja excluir essa lista?", "auto_clients_title": "Clientes ativos", - "auto_clients_desc": "Dispositivo não está na lista de dispositivos persistentes que podem ser utilizados no AdGuard Home.", + "auto_clients_desc": "Dispositivo não está na lista de dispositivos persistentes que podem ser utilizados no AdGuard Home", "access_title": "Definições de acesso", - "access_desc": "Aqui pode configurar as regras de acesso para o servidores de DNS do AdGuard Home.", + "access_desc": "Aqui pode configurar as regras de acesso para o servidores de DNS do AdGuard Home", "access_allowed_title": "Clientes permitidos", "access_allowed_desc": "Uma lista de CIDRs, endereços IP ou IDs de cliente. Se esta lista tiver entradas, o AdGuard Home do aceitará solicitações apenas desses clientes.", "access_disallowed_title": "Clientes não permitidos", @@ -475,8 +477,8 @@ "dns_rewrites": "Reescritas de DNS", "form_domain": "Inserir domínio", "form_answer": "Insira o endereço de IP ou nome de domínio", - "form_error_domain_format": "Formato de domínio inválido.", - "form_error_answer_format": "Formato de resposta inválido.", + "form_error_domain_format": "Formato de domínio inválido", + "form_error_answer_format": "Formato de resposta inválido", "configure": "Configurar", "main_settings": "Definições principais", "block_services": "Bloquear serviços específicos", @@ -500,6 +502,7 @@ "interval_days": "{{count}} dias", "interval_days_plural": "{{count}} dias", "domain": "Domínio", + "ecs": "ECS", "punycode": "Punycode", "answer": "Resposta", "filter_added_successfully": "O filtro foi adicionado com sucesso", @@ -507,7 +510,7 @@ "filter_updated": "O filtro atualizado com sucesso", "statistics_configuration": "Definição das estatísticas", "statistics_retention": "Retenção de estatísticas", - "statistics_retention_desc": "Se diminuir o valor do intervalo, alguns dados serão perdidos.", + "statistics_retention_desc": "Se diminuir o valor do intervalo, alguns dados serão perdidos", "statistics_clear": "Limpar estatísticas", "statistics_clear_confirm": "Tem a certeza de que deseja limpar as estatísticas?", "statistics_retention_confirm": "Tem a certeza que quer alterar a retenção de estatísticas? Se diminuir o valor do intervalo, alguns dados serão perdidos", @@ -517,7 +520,7 @@ "interval_hours_plural": "{{count}} horas", "filters_configuration": "Definição dos filtros", "filters_enable": "Ativar filtros", - "filters_interval": "Intervalo de atualização de filtros", + "filters_interval": "Intervalo de atualização de filtro", "disabled": "Desativado", "username_label": "Nome do utilizador", "username_placeholder": "Insira o nome de utilizador", @@ -606,7 +609,7 @@ "enter_cache_ttl_max_override": "Digite o TTL máximo (segundos)", "cache_ttl_min_override_desc": "Prolongue os valores de curta duração (segundos) recebidos do servidor primário ao armazenar em cache as respostas DNS.", "cache_ttl_max_override_desc": "Defina um valor máximo de tempo de vida (segundos) para entradas no cache DNS.", - "ttl_cache_validation": "O substituto mínimo de cache TTL deve ser menor ou igual ao máximo.", + "ttl_cache_validation": "O substituto mínimo de cache TTL deve ser menor ou igual ao máximo", "cache_optimistic": "Cache otimista", "cache_optimistic_desc": "Faz o AdGuard Home responder a partir do cache mesmo quando as entradas expirarem e também tenta atualizá-las.", "filter_category_general": "Geral", @@ -628,5 +631,5 @@ "parental_control": "Controlo parental", "safe_browsing": "Navegação segura", "served_from_cache": "{{value}} (servido do cache)", - "form_error_password_length": "A palavra-passe deve ter pelo menos {{value}} caracteres." + "form_error_password_length": "A palavra-passe deve ter pelo menos {{value}} caracteres" } diff --git a/client/src/__locales/ro.json b/client/src/__locales/ro.json index c4b304b2..b19b8576 100644 --- a/client/src/__locales/ro.json +++ b/client/src/__locales/ro.json @@ -35,24 +35,24 @@ "dhcp_config_saved": "Configurare DHCP salvată cu succes", "dhcp_ipv4_settings": "Setări DHCP IPv4", "dhcp_ipv6_settings": "Setări DHCP IPv6", - "form_error_required": "Câmp obligatoriu.", - "form_error_ip4_format": "Adresă IPv4 nevalidă.", - "form_error_ip4_range_start_format": "Adresă IPv4 nevalidă pentru începutul intervalului.", - "form_error_ip4_range_end_format": "Adresă IPv4 nevalidă a sfârșitului intervalului.", - "form_error_ip4_gateway_format": "Adresă IPv4 nevalidă a gateway-ului.", - "form_error_ip6_format": "Adresa IPv6 nevalidă.", - "form_error_ip_format": "Adresă IP nevalidă.", - "form_error_mac_format": "Adresă MAC nevalidă.", - "form_error_client_id_format": "ClientID-ul trebuie să conțină numai numere, litere minuscule și cratime.", - "form_error_server_name": "Nume de server nevalid.", - "form_error_subnet": "Subrețeaua „{{cidr}}” nu conține adresa IP „{{ip}}”.", - "form_error_positive": "Trebuie să fie mai mare de 0.", - "out_of_range_error": "Trebuie să fie în afara intervalului „{{start}}”-„{{end}}”.", - "lower_range_start_error": "Trebuie să fie mai mică decât începutul intervalului.", - "greater_range_start_error": "Trebuie să fie mai mare decât începutul intervalului.", - "greater_range_end_error": "Trebuie să fie mai mare decât sfârșitul intervalului.", - "subnet_error": "Adresele trebuie să fie în aceeași subrețea.", - "gateway_or_subnet_invalid": "Mască de subrețea nevalidă.", + "form_error_required": "Câmp obligatoriu", + "form_error_ip4_format": "Adresă IPv4 nevalidă", + "form_error_ip4_range_start_format": "Adresă IPv4 nevalidă pentru începutul intervalului", + "form_error_ip4_range_end_format": "Adresă IPv4 nevalidă a sfârșitului intervalului", + "form_error_ip4_gateway_format": "Adresă IPv4 nevalidă a gateway-ului", + "form_error_ip6_format": "Adresa IPv6 nevalidă", + "form_error_ip_format": "Adresă IP nevalidă", + "form_error_mac_format": "Adresă MAC nevalidă", + "form_error_client_id_format": "ClientID-ul trebuie să conțină numai numere, litere minuscule și cratime", + "form_error_server_name": "Nume de server nevalid", + "form_error_subnet": "Subrețeaua „{{cidr}}” nu conține adresa IP „{{ip}}”", + "form_error_positive": "Trebuie să fie mai mare de 0", + "out_of_range_error": "Trebuie să fie în afara intervalului „{{start}}”-„{{end}}”", + "lower_range_start_error": "Trebuie să fie mai mică decât începutul intervalului", + "greater_range_start_error": "Trebuie să fie mai mare decât începutul intervalului", + "greater_range_end_error": "Trebuie să fie mai mare decât sfârșitul intervalului", + "subnet_error": "Adresele trebuie să fie în aceeași subrețea", + "gateway_or_subnet_invalid": "Mască de subrețea nevalidă", "dhcp_form_gateway_input": "IP Gateway", "dhcp_form_subnet_input": "Mască subnet", "dhcp_form_range_title": "Interval de adrese IP", @@ -67,7 +67,7 @@ "dhcp_table_hostname": "Hostname", "dhcp_table_expires": "Expiră", "dhcp_warning": "Dacă doriți să activați serverul DHCP oricum, asigurați-vă că nu există nici un alt server DHCP activ în rețeaua dvs., deoarece acest lucru poate rupe conectivitatea la Internet a dispozitivelor din rețea!", - "dhcp_error": "AdGuard Home nu a putut determina dacă există un alt server DHCP activ în rețea.", + "dhcp_error": "AdGuard Home nu a putut determina dacă există un alt server DHCP activ în rețea", "dhcp_static_ip_error": "Pentru a utiliza serverul DHCP, trebuie setată o adresă IP statică. AdGuard Home nu a reușit să determine dacă această interfață de rețea este configurată utilizând o adresă IP statică. Setați manual o adresă IP statică.", "dhcp_dynamic_ip_found": "Sistemul dvs. folosește configurația dinamică a adreselor IP pentru interfața <0>{{interfaceName}}. Pentru a utiliza serverul DHCP, trebuie setată o adresă IP statică. Adresa IP curentă este <0>{{ipAddress}}. AdGuard Home o va configura automat ca adresă IP statică, dacă apăsați butonul \"Activați serverul DHCP\".", "dhcp_lease_added": "\"{{key}}\" statică închiriată adăugată cu succes", @@ -196,8 +196,8 @@ "choose_allowlist": "Selectați liste de autorizări", "enter_valid_blocklist": "Introduceți un URL valid pentru blocare.", "enter_valid_allowlist": "Introduceți un URL valid pentru autorizare.", - "form_error_url_format": "Format URL nevalid.", - "form_error_url_or_path_format": "URL nevalabil sau calea absolută a listei.", + "form_error_url_format": "Format URL nevalid", + "form_error_url_or_path_format": "URL nevalabil sau calea absolută a listei", "custom_filter_rules": "Reguli de filtrare personalizate", "custom_filter_rules_hint": "Introduceți o regulă pe linie. Puteți utiliza reguli de blocare sau sintaxa de fișiere hosts.", "system_host_files": "Fișiere de sistem hosts", @@ -210,11 +210,13 @@ "example_comment_hash": "# De asemenea, un comentariu.", "example_regex_meaning": "blochează accesul la domeniile care corespund expresiei regulate specificate.", "example_upstream_regular": "DNS clasic (over UDP);", + "example_upstream_udp": "DNS obișnuit (over UDP, nume de gazdă);", "example_upstream_dot": "<0>DNS-over-TLS criptat;", "example_upstream_doh": "<0>DNS-over-HTTPS criptat;", "example_upstream_doq": "<0>DNS-over-QUIC criptat (experimental);", "example_upstream_sdns": "<0>DNS Stamps pentru <1>DNSCrypt sau rezolvere <2>DNS-over-HTTPS;", "example_upstream_tcp": "DNS clasic (over TCP);", + "example_upstream_tcp_hostname": "DNS obișnuit (over TCP, nume de gazdă);", "all_lists_up_to_date_toast": "Toate listele sunt deja la zi", "updated_upstream_dns_toast": "Serverele din amonte au fost salvate cu succes", "dns_test_ok_toast": "Serverele DNS specificate funcționează corect", @@ -259,10 +261,10 @@ "query_log_strict_search": "Utilizați ghilimele duble pentru căutare strictă", "query_log_retention_confirm": "Sunteți sigur că doriți să schimbați retenția jurnalului de interogare? Reducând valoarea intervalului, unele date vor fi pierdute", "anonymize_client_ip": "Anonimizare client IP", - "anonymize_client_ip_desc": "Nu salvați adresa IP completă a clientului în jurnale și statistici.", + "anonymize_client_ip_desc": "Nu salvați adresa IP completă a clientului în jurnale și statistici", "dns_config": "Configurația serverului DNS", "dns_cache_config": "Configurare cache DNS", - "dns_cache_config_desc": "Aici puteți configura cache-ul DNS.", + "dns_cache_config_desc": "Aici puteți configura cache-ul DNS", "blocking_mode": "Modul de blocare", "default": "Implicit", "nxdomain": "NXDOMAIN", @@ -285,7 +287,7 @@ "form_enter_rate_limit": "Introduceți limita ratei", "rate_limit": "Limita ratei", "edns_enable": "Activați subrețeaua de clienți EDNS", - "edns_cs_desc": "Trimite subrețelele clienților la serverele DNS.", + "edns_cs_desc": "Adaugă opțiunea EDNS Client Subnet (ECS) la solicitările în amonte și înregistrează valorile trimise de clienți în jurnalul de interogare.", "rate_limit_desc": "Numărul de interogări pe secundă permise pe client. Setarea la 0 înseamnă că nu există limită.", "blocking_ipv4_desc": "Adresa IP de returnat pentru o cerere A de blocare", "blocking_ipv6_desc": "Adresa IP de returnat pentru o cerere AAAA de blocare", @@ -309,7 +311,7 @@ "install_settings_listen": "Interfață de ascultare", "install_settings_port": "Port", "install_settings_interface_link": "Interfața dvs. de administrare AdGuard Home va fi disponibilă pe următoarele adrese:", - "form_error_port": "Introduceți un număr de port valid.", + "form_error_port": "Introduceți un număr de port valid", "install_settings_dns": "Server DNS", "install_settings_dns_desc": "Va trebui să configurați aparatele sau routerul pentru a utiliza serverul DNS pe următoarele adrese:", "install_settings_all_interfaces": "Toate interfețele", @@ -356,7 +358,7 @@ "open_dashboard": "Deschideți Tabloul de bord", "install_saved": "Salvat cu succes", "encryption_title": "Criptare", - "encryption_desc": "Suport pentru criptare (HTTPS/TLS) atât pentru DNS, cât și pentru interfața web de administrare.", + "encryption_desc": "Suport pentru criptare (HTTPS/TLS) atât pentru DNS, cât și pentru interfața web de administrare", "encryption_config_saved": "Configurația de criptare salvată", "encryption_server": "Nume de server", "encryption_server_enter": "Introduceți numele domeniului", @@ -378,26 +380,26 @@ "encryption_key_input": "Copiați/lipiți cheia dvs. privată PEM-codată pentru certificatul dvs. aici.", "encryption_enable": "Activați criptarea (HTTPS, DNS-over-HTTPS, și DNS-over-TLS)", "encryption_enable_desc": "Dacă este activată criptarea, interfața administrator AdGuard Home va lucra peste HTTPS, și serverul DNS va asculta pentru cereri peste DNS-over-HTTPS și DNS-over-TLS.", - "encryption_chain_valid": "Lanț de certificate valid.", - "encryption_chain_invalid": "Lanț de certificate invalid.", - "encryption_key_valid": "Aceasta este o cheie privată {{type}} validă.", - "encryption_key_invalid": "Aceasta este o cheie privată {{type}} invalidă.", + "encryption_chain_valid": "Lanț de certificate valid", + "encryption_chain_invalid": "Lanț de certificate invalid", + "encryption_key_valid": "Aceasta este o cheie privată {{type}} validă", + "encryption_key_invalid": "Aceasta este o cheie privată {{type}} invalidă", "encryption_subject": "Obiect", "encryption_issuer": "Emitent", "encryption_hostnames": "Nume de host", "encryption_reset": "Sunteți sigur că doriți să resetați setările de criptare?", "topline_expiring_certificate": "Certificatul dvs. SSL este pe cale să expire. Actualizați <0>Setările de criptare.", "topline_expired_certificate": "Certificatul dvs. SSL a expirat. Actualizați <0>Setările de criptare.", - "form_error_port_range": "Introduceți valoarea portului între 80-65535.", - "form_error_port_unsafe": "Acesta este un port nesigur.", - "form_error_equal": "Nu trebuie să fie egale.", - "form_error_password": "Parolele nu corespund.", + "form_error_port_range": "Introduceți valoarea portului între 80-65535", + "form_error_port_unsafe": "Port nesigur", + "form_error_equal": "Nu trebuie să fie egale", + "form_error_password": "Parolele nu corespund", "reset_settings": "Resetare setări", "update_announcement": "AdGuard Home {{version}} este disponibil! <0>Clicați aici pentru mai multe informații.", "setup_guide": "Ghid de instalare", "dns_addresses": "Adrese DNS", "dns_start": "Serverul DNS demarează", - "dns_status_error": "Eroare la verificare statut server DNS.", + "dns_status_error": "Eroare la verificarea stării serverului DNS", "down": "Down", "fix": "Fix", "dns_providers": "Iată o <0>listă de furnizori DNS cunoscuți ce pot fi aleși.", @@ -406,7 +408,7 @@ "manual_update": "Vă rugăm să urmați etapele următoare pentru a actualiza manual.", "processing_update": "Vă rugăm să așteptați, AdGuard Home se actualizează...", "clients_title": "Clienți persistenți", - "clients_desc": "Configură înregistrările clientului permanent pentru dispozitivele conectate la AdGuard Home.", + "clients_desc": "Configurează înregistrările persistente ale clienților pentru dispozitivele conectate la AdGuard Home", "settings_global": "General", "settings_custom": "Personalizat", "table_client": "Client", @@ -433,9 +435,9 @@ "client_confirm_delete": "Sunteți sigur că doriți să ștergeți clientul \"{{key}}\"?", "list_confirm_delete": "Sigur doriți să ștergeți această listă?", "auto_clients_title": "Clienți runtime", - "auto_clients_desc": "Dispozitivele care nu se află pe lista de clienți Persistent care pot utiliza în continuare AdGuard Home.", + "auto_clients_desc": "Dispozitivele care nu se află pe lista de clienți Persistent care pot utiliza în continuare AdGuard Home", "access_title": "Setări de acces", - "access_desc": "Aici puteți configura regulile de acces pentru serverul DNS AdGuard Home.", + "access_desc": "Aici puteți configura regulile de acces pentru serverul DNS AdGuard Home", "access_allowed_title": "Clienți autorizați", "access_allowed_desc": "O listă de CIDR-uri, adrese IP sau ClientID-uri. Dacă această listă are intrări, AdGuard Home va accepta cereri numai de la acești clienți.", "access_disallowed_title": "Clienți neautorizați", @@ -475,8 +477,8 @@ "dns_rewrites": "Rescrieri DNS", "form_domain": "Introduceți un nume de domeniu sau wildcard", "form_answer": "Introduceți adresa IP sau numele de domeniu", - "form_error_domain_format": "Format de domeniu invalid.", - "form_error_answer_format": "Format de răspuns invalid.", + "form_error_domain_format": "Format de domeniu invalid", + "form_error_answer_format": "Format de răspuns invalid", "configure": "Configurați", "main_settings": "Setări principale", "block_services": "Blochează anumite servicii", @@ -500,6 +502,7 @@ "interval_days": "{{count}} zi", "interval_days_plural": "{{count}} zile", "domain": "Domeniu", + "ecs": "ECS", "punycode": "Punycode", "answer": "Răspuns", "filter_added_successfully": "Filtrul a fost adăugat cu succes", @@ -507,7 +510,7 @@ "filter_updated": "Filtrul a fost actualizat cu succes", "statistics_configuration": "Configurația statisticilor", "statistics_retention": "Păstrarea statisticilor", - "statistics_retention_desc": "Dacă reduceți valoarea intervalului, unele date vor fi pierdute.", + "statistics_retention_desc": "Dacă reduceți valoarea intervalului, unele date vor fi pierdute", "statistics_clear": " Șterge statisticile", "statistics_clear_confirm": "Sunteți sigur că doriți să ștergeți statisticile?", "statistics_retention_confirm": "Sunteți sigur că doriți să schimbați păstrarea statisticilor? Dacă reduceți valoarea intervalului, unele date vor fi pierdute", @@ -517,7 +520,7 @@ "interval_hours_plural": "{{count}} ore", "filters_configuration": "Configurația filtrelor", "filters_enable": "Activați filtrele", - "filters_interval": "Interval de actualizare filtre", + "filters_interval": "Intervalul de actualizare a filtrului", "disabled": "Dezactivat", "username_label": "Nume utilizator", "username_placeholder": "Introduceți nume utilizator", @@ -606,7 +609,7 @@ "enter_cache_ttl_max_override": "Introduceți maximum TTL (secunde)", "cache_ttl_min_override_desc": "Extinde valorile timp-de-viață scurte (secunde) primite de la serverul din amonte la stocarea în cache a răspunsurilor DNS.", "cache_ttl_max_override_desc": "Setează o valoare maximă a timpului-de-viață (secunde) pentru intrările din memoria cache DNS.", - "ttl_cache_validation": "Valoarea TTL cache minimă trebuie să fie mai mică sau egală cu valoarea maximă.", + "ttl_cache_validation": "Valoarea TTL cache minimă trebuie să fie mai mică sau egală cu valoarea maximă", "cache_optimistic": "Caching optimistic", "cache_optimistic_desc": "Face ca AdGuard Home să răspundă din cache chiar și atunci când intrările au expirate și de asemenea, încearcă să le reîmprospăteze.", "filter_category_general": "General", @@ -628,5 +631,5 @@ "parental_control": "Control Parental", "safe_browsing": "Navigare în siguranță", "served_from_cache": "{{value}} (furnizat din cache)", - "form_error_password_length": "Parola trebuie să aibă cel puțin {{value}} caractere." + "form_error_password_length": "Parola trebuie să aibă cel puțin {{value}} caractere" } diff --git a/client/src/__locales/ru.json b/client/src/__locales/ru.json index dc73fded..214169fd 100644 --- a/client/src/__locales/ru.json +++ b/client/src/__locales/ru.json @@ -35,24 +35,24 @@ "dhcp_config_saved": "Конфигурация DHCP-сервера успешно сохранена", "dhcp_ipv4_settings": "Настройки DHCP IPv4", "dhcp_ipv6_settings": "Настройки DHCP IPv6", - "form_error_required": "Обязательное поле.", - "form_error_ip4_format": "Некорректный IPv4-адрес.", - "form_error_ip4_range_start_format": "Некорректный IPv4-адрес начала диапазона.", - "form_error_ip4_range_end_format": "Некорректный IPv4-адрес конца диапазона.", - "form_error_ip4_gateway_format": "Некорректный IPv4-адрес шлюза.", - "form_error_ip6_format": "Некорректный IPv6-адрес.", - "form_error_ip_format": "Некорректный IP-адрес.", - "form_error_mac_format": "Некорректный MAC-адрес.", - "form_error_client_id_format": "ClientID может содержать только цифры, строчные латинские буквы и дефисы.", - "form_error_server_name": "Некорректное имя сервера.", - "form_error_subnet": "Подсеть «{{cidr}}» не содержит IP-адрес «{{ip}}».", - "form_error_positive": "Должно быть больше 0.", - "out_of_range_error": "Должно быть вне диапазона «{{start}}»-«{{end}}».", - "lower_range_start_error": "Должно быть меньше начала диапазона.", - "greater_range_start_error": "Должно быть больше начала диапазона.", - "greater_range_end_error": "Должно быть больше конца диапазона.", - "subnet_error": "Адреса должны быть внутри одной подсети.", - "gateway_or_subnet_invalid": "Некорректная маска подсети.", + "form_error_required": "Обязательное поле", + "form_error_ip4_format": "Некорректный IPv4-адрес", + "form_error_ip4_range_start_format": "Некорректный IPv4-адрес начала диапазона", + "form_error_ip4_range_end_format": "Некорректный IPv4-адрес конца диапазона", + "form_error_ip4_gateway_format": "Некорректный IPv4-адрес шлюза", + "form_error_ip6_format": "Некорректный IPv6-адрес", + "form_error_ip_format": "Некорректный IP-адрес", + "form_error_mac_format": "Некорректный MAC-адрес", + "form_error_client_id_format": "ClientID может содержать только цифры, строчные латинские буквы и дефисы", + "form_error_server_name": "Некорректное имя сервера", + "form_error_subnet": "Подсеть «{{cidr}}» не содержит IP-адрес «{{ip}}»", + "form_error_positive": "Должно быть больше 0", + "out_of_range_error": "Должно быть вне диапазона «{{start}}»-«{{end}}»", + "lower_range_start_error": "Должно быть меньше начала диапазона", + "greater_range_start_error": "Должно быть больше начала диапазона", + "greater_range_end_error": "Должно быть больше конца диапазона", + "subnet_error": "Адреса должны быть внутри одной подсети", + "gateway_or_subnet_invalid": "Некорректная маска подсети", "dhcp_form_gateway_input": "IP-адрес шлюза", "dhcp_form_subnet_input": "Маска подсети", "dhcp_form_range_title": "Диапазон IP-адресов", @@ -67,7 +67,7 @@ "dhcp_table_hostname": "Имя хоста", "dhcp_table_expires": "Истекает", "dhcp_warning": "Если вы все равно хотите включить DHCP-сервер, убедитесь, что в сети больше нет активных DHCP-серверов. Иначе это может сломать доступ в сеть для подключённых устройств!", - "dhcp_error": "AdGuard Home не смог определить присутствие других DHCP-серверов в сети.", + "dhcp_error": "AdGuard Home не смог определить присутствие других DHCP-серверов в сети", "dhcp_static_ip_error": "Чтобы использовать DHCP-сервер, должен быть установлен статический IP-адрес. AdGuard Home не смог определить, использует ли этот сетевой интерфейс статический IP-адрес. Пожалуйста, установите его вручную.", "dhcp_dynamic_ip_found": "Ваша система использует динамический IP-адрес для интерфейса <0>{{interfaceName}}. Чтобы использовать DHCP-сервер, необходимо установить статический IP-адрес. Ваш текущий IP-адрес – <0>{{ipAddress}}. Мы автоматически установим его как статический, если вы нажмёте кнопку «Включить DHCP-сервер».", "dhcp_lease_added": "Статическая аренда «{{key}}» успешно добавлена", @@ -196,8 +196,8 @@ "choose_allowlist": "Выберите списки разрешённых", "enter_valid_blocklist": "Добавьте действующий URL-адрес в чёрный список.", "enter_valid_allowlist": "Добавьте действующий URL-адрес в белый список.", - "form_error_url_format": "Неверный формат URL.", - "form_error_url_or_path_format": "Неверный URL или абсолютный путь к списку.", + "form_error_url_format": "Неверный формат URL", + "form_error_url_or_path_format": "Неверный URL или абсолютный путь к списку", "custom_filter_rules": "Пользовательское правило фильтрации", "custom_filter_rules_hint": "Вводите по одному правилу на строчку. Вы можете использовать правила блокировки или синтаксис файлов hosts.", "system_host_files": "Системные hosts-файлы", @@ -210,11 +210,13 @@ "example_comment_hash": "# И вот так тоже.", "example_regex_meaning": "блокировать доступ к доменам, соответствующим заданному регулярному выражению.", "example_upstream_regular": "обычный DNS (поверх UDP);", + "example_upstream_udp": "обычный DNS (поверх UDP, с именем хоста);", "example_upstream_dot": "зашифрованный <0>DNS-over-TLS;", "example_upstream_doh": "зашифрованный <0>DNS-over-HTTPS;", "example_upstream_doq": "зашифрованный <0>DNS-over-QUIC (эксперементальный);", "example_upstream_sdns": "<0>DNS Stamps для <1>DNSCrypt или <2>DNS-over-HTTPS серверов;", "example_upstream_tcp": "обычный DNS (поверх TCP);", + "example_upstream_tcp_hostname": "обычный DNS (поверх TCP, с именем хоста);", "all_lists_up_to_date_toast": "Все списки уже обновлены", "updated_upstream_dns_toast": "DNS-серверы успешно обновлены", "dns_test_ok_toast": "Указанные серверы DNS работают корректно", @@ -259,10 +261,10 @@ "query_log_strict_search": "Используйте двойные кавычки для строгого поиска", "query_log_retention_confirm": "Вы уверены, что хотите изменить срок хранения запросов? При сокращении интервала данные могут быть утеряны", "anonymize_client_ip": "Анонимизировать IP-адрес клиента", - "anonymize_client_ip_desc": "Не сохранять полный IP-адрес клиента в журналах и статистике.", + "anonymize_client_ip_desc": "Не сохранять полный IP-адрес клиента в журналах и статистике", "dns_config": "Настройки DNS-сервера", "dns_cache_config": "Настройка кеша DNS", - "dns_cache_config_desc": "Здесь можно настроить кеш DNS.", + "dns_cache_config_desc": "Здесь можно настроить кеш DNS", "blocking_mode": "Режим блокировки", "default": "Стандартный", "nxdomain": "NXDOMAIN", @@ -285,7 +287,7 @@ "form_enter_rate_limit": "Введите rate limit", "rate_limit": "Rate limit", "edns_enable": "Включить отправку EDNS Client Subnet", - "edns_cs_desc": "Отправлять подсети клиентов на DNS-серверы.", + "edns_cs_desc": "Добавлять опцию EDNS Client Subnet (ECS) к запросам к upstream-серверам, а также записывать присланные клиентами значения в журнал.", "rate_limit_desc": "Ограничение на количество запросов в секунду для каждого клиента (0 — неограниченно).", "blocking_ipv4_desc": "IP-адрес, возвращаемый при блокировке A-запроса", "blocking_ipv6_desc": "IP-адрес, возвращаемый при блокировке AAAA-запроса", @@ -309,7 +311,7 @@ "install_settings_listen": "Сетевой интерфейс", "install_settings_port": "Порт", "install_settings_interface_link": "Ваш веб-интерфейс администрирования AdGuard Home будет доступен по следующим адресам:", - "form_error_port": "Введите корректный порт.", + "form_error_port": "Введите корректный порт", "install_settings_dns": "DNS-сервер", "install_settings_dns_desc": "Вам будет нужно настроить свои устройства или роутер на использование DNS-сервера на одном из следующих адресов:", "install_settings_all_interfaces": "Все интерфейсы", @@ -356,7 +358,7 @@ "open_dashboard": "Открыть Панель управления", "install_saved": "Успешно сохранено", "encryption_title": "Шифрование", - "encryption_desc": "Поддержка шифрования (HTTPS/TLS) для DNS и веб-интерфейса администрирования.", + "encryption_desc": "Поддержка шифрования (HTTPS/QUIC/TLS) для DNS и веб-интерфейса администрирования", "encryption_config_saved": "Настройки шифрования сохранены", "encryption_server": "Имя сервера", "encryption_server_enter": "Введите ваше доменное имя", @@ -378,26 +380,26 @@ "encryption_key_input": "Скопируйте сюда приватный ключ в PEM-кодировке.", "encryption_enable": "Включить шифрование (HTTPS, DNS-over-HTTPS и DNS-over-TLS)", "encryption_enable_desc": "Если шифрование включено, веб-интерфейс AdGuard Home будет работать по HTTPS, а DNS-сервер будет также работать по DNS-over-HTTPS и DNS-over-TLS.", - "encryption_chain_valid": "Цепочка сертификатов прошла проверку.", - "encryption_chain_invalid": "Цепочка сертификатов не прошла проверку.", - "encryption_key_valid": "Корректный {{type}} приватный ключ.", - "encryption_key_invalid": "Некорректный {{type}} приватный ключ.", + "encryption_chain_valid": "Цепочка сертификатов прошла проверку", + "encryption_chain_invalid": "Цепочка сертификатов не прошла проверку", + "encryption_key_valid": "Корректный {{type}} приватный ключ", + "encryption_key_invalid": "Некорректный {{type}} приватный ключ", "encryption_subject": "Субъект", "encryption_issuer": "Издатель", "encryption_hostnames": "Имена хостов", "encryption_reset": "Вы уверены, что хотите сбросить настройки шифрования?", "topline_expiring_certificate": "Ваш SSL-сертификат скоро истекает. Обновите <0>Настройки шифрования.", "topline_expired_certificate": "Ваш SSL-сертификат истёк. Обновите <0>Настройки шифрования.", - "form_error_port_range": "Введите номер порта из интервала 80-65535.", - "form_error_port_unsafe": "Это небезопасный порт.", - "form_error_equal": "Не должны быть равны.", - "form_error_password": "Пароли не совпадают.", + "form_error_port_range": "Введите номер порта из интервала 80-65535", + "form_error_port_unsafe": "Небезопасный порт", + "form_error_equal": "Не должны быть равны", + "form_error_password": "Пароли не совпадают", "reset_settings": "Сбросить настройки", "update_announcement": "AdGuard Home {{version}} уже доступна! <0>Нажмите сюда, чтобы узнать больше.", "setup_guide": "Инструкция по настройке", "dns_addresses": "Адреса DNS", "dns_start": "DNS-сервер запускается", - "dns_status_error": "Ошибка при получении состояния DNS-сервера.", + "dns_status_error": "Ошибка при получении состояния DNS-сервера", "down": "Вниз", "fix": "Исправить", "dns_providers": "<0>Список известных DNS-провайдеров на выбор.", @@ -406,7 +408,7 @@ "manual_update": "Пожалуйста, следуйте инструкции для обновления вручную.", "processing_update": "Пожалуйста, подождите, AdGuard Home обновляется", "clients_title": "Сохранённые клиенты", - "clients_desc": "Настройте устройства, использующие AdGuard Home.", + "clients_desc": "Настройте устройства, использующие AdGuard Home", "settings_global": "Глобальные", "settings_custom": "Свои", "table_client": "Клиент", @@ -433,9 +435,9 @@ "client_confirm_delete": "Вы уверены, что хотите удалить клиента «{{key}}»?", "list_confirm_delete": "Вы уверены, что хотите удалить этот список?", "auto_clients_title": "Клиенты (runtime)", - "auto_clients_desc": "Несохранённые клиенты, которые могут пользоваться AdGuard Home.", + "auto_clients_desc": "Несохранённые клиенты, которые могут пользоваться AdGuard Home", "access_title": "Настройки доступа", - "access_desc": "Здесь вы можете настроить правила доступа к DNS-серверу AdGuard Home.", + "access_desc": "Здесь вы можете настроить правила доступа к DNS-серверу AdGuard Home", "access_allowed_title": "Разрешённые клиенты", "access_allowed_desc": "Список CIDR, IP-адресов или ClientID. Если в списке есть записи, AdGuard Home будет принимать запросы только от этих клиентов.", "access_disallowed_title": "Запрещённые клиенты", @@ -475,8 +477,8 @@ "dns_rewrites": "Перезапись DNS-запросов", "form_domain": "Введите домен", "form_answer": "Введите IP адрес или домен", - "form_error_domain_format": "Некорректный домен.", - "form_error_answer_format": "Некорректный ответ.", + "form_error_domain_format": "Некорректный домен", + "form_error_answer_format": "Некорректный ответ", "configure": "Настроить", "main_settings": "Основные настройки", "block_services": "Выбрать заблокированные сервисы", @@ -500,6 +502,7 @@ "interval_days": "{{count}} день", "interval_days_plural": "{{count}} дней", "domain": "Домен", + "ecs": "ECS", "punycode": "Punycode", "answer": "Ответ", "filter_added_successfully": "Список успешно добавлен", @@ -507,7 +510,7 @@ "filter_updated": "Список успешно обновлён", "statistics_configuration": "Конфигурация статистики", "statistics_retention": "Сохранение статистики", - "statistics_retention_desc": "Если вы уменьшите значение интервала, некоторые данные могут быть потеряны.", + "statistics_retention_desc": "Если вы уменьшите значение интервала, некоторые данные могут быть потеряны", "statistics_clear": "Очистить статистику", "statistics_clear_confirm": "Вы уверены, что хотите очистить статистику?", "statistics_retention_confirm": "Вы уверены, что хотите изменить срок хранения статистики? При сокращении интервала данные могут быть утеряны", @@ -599,14 +602,14 @@ "milliseconds_abbreviation": "мс", "cache_size": "Размер кеша", "cache_size_desc": "Размера кеша DNS (в байтах).", - "cache_ttl_min_override": "Переопределить минимальный TTL (в секундах)", - "cache_ttl_max_override": "Переопределить максимальный TTL (в секундах)", + "cache_ttl_min_override": "Переопределить минимальный TTL", + "cache_ttl_max_override": "Переопределить максимальный TTL", "enter_cache_size": "Введите размер кеша (в байтах)", "enter_cache_ttl_min_override": "Введите минимальный TTL (в секундах)", "enter_cache_ttl_max_override": "Введите максимальный TTL (в секундах)", "cache_ttl_min_override_desc": "Расширить короткие TTL-значения (в секундах), полученные с upstream-сервера при кешировании DNS-ответов.", "cache_ttl_max_override_desc": "Установить максимальное TTL-значение (в секундах) для записей в DNS-кеше.", - "ttl_cache_validation": "Минимальное значение TTL-кеша должно быть меньше или равно максимальному значению.", + "ttl_cache_validation": "Значение для переопределения минимального TTL должно быть меньше или равно значению для переопределения максимального", "cache_optimistic": "Оптимистическое кеширование", "cache_optimistic_desc": "AdGuard Home будет отвечать из кеша, даже если ответы в нём неактуальны, и попытается обновить их.", "filter_category_general": "Общие", @@ -628,5 +631,5 @@ "parental_control": "Родительский контроль", "safe_browsing": "Безопасный интернет", "served_from_cache": "{{value}} (получено из кеша)", - "form_error_password_length": "Пароль должен быть длиной не меньше {{value}} символов." + "form_error_password_length": "Пароль должен быть длиной не меньше {{value}} символов" } diff --git a/client/src/__locales/si-lk.json b/client/src/__locales/si-lk.json index d2a4f5b9..ea6d29b1 100644 --- a/client/src/__locales/si-lk.json +++ b/client/src/__locales/si-lk.json @@ -1,15 +1,19 @@ { - "client_settings": "අනුග්‍රාහක සැකසුම්", - "example_upstream_comment": "ඔබට අදහසක් සඳහන් කළ හැකිය", + "client_settings": "අනුග්‍රාහකයේ සැකසුම්", + "example_upstream_comment": "අදහසක්.", "parallel_requests": "සමාන්තර ඉල්ලීම්", "load_balancing": "ධාරිතාව තුලනය", "local_ptr_title": "පෞද්ගලික ප්‍රතිවර්ත ව.නා.ප. සේවාදායක", + "local_ptr_desc": "ස්ථානීය PTR විමසුම් සඳහා ඇඩ්ගාර්ඩ් හෝම් භාවිතා කරන ව.නා.ප. සේවාදායක. මෙම සේවාදායක පුද්ගලික අ.ජා.කෙ. ලිපින සහිත අනුග්‍රාහකවල සත්කාරක නාම විසඳීමට භාවිතා කරයි, උදාහරණයක් ලෙස ප්‍රතිවර්ත ව.නා.ප. භාවිතයෙන් \"192.168.12.34\". නැති නම්, ඇඩ්ගාර්ඩ් හෝම් හි ලිපින සඳහා හැරුනු විට ඔබගේ මෙහෙයුම් පද්ධතියේ පෙරනිමි ව.නා.ප. විසදුම්වල ලිපින භාවිතා කරයි.", + "local_ptr_default_resolver": "පෙරනිමි ලෙස, ඇඩ්ගාර්ඩ් හෝම් පහත ප්‍රතිවර්තත ව.නා.ප. විසඳුම් භාවිතා කරයි: {{ip}}.", + "local_ptr_no_default_resolver": "ඇඩ්ගාර්ඩ් හෝම් හට මෙම පද්ධතිය සඳහා සුදුසු පුද්ගලික ප්‍රතිවර්ත ව.නා.ප. විසඳුම් නිශ්චය කරගත නොහැකි විය.", "local_ptr_placeholder": "පේළියකට එක් සේවාදායක ලිපිනය බැගින් යොදන්න", "resolve_clients_title": "අනුග්‍රාහකවල අ.ජා.කෙ. ලිපින ප්‍රතිවර්ත විසඳීම සබල කරන්න", "check_dhcp_servers": "ග.ධා.වි.කෙ. සේවාදායක සඳහා පරීක්‍ෂා කරන්න", "save_config": "වින්‍යාසය සුරකින්න", "enabled_dhcp": "ග.ධා.වි.කෙ. සේවාදායකය සබල කෙරිණි", "disabled_dhcp": "ග.ධා.වි.කෙ. සේවාදායකය අබල කෙරිණි", + "unavailable_dhcp": "ග.ධා.වි.කෙ. නැත", "unavailable_dhcp_desc": "ඇඩ්ගාර්ඩ් හෝම් හට ඔබගේ මෙහෙයුම් පද්ධතියේ ග.ධා.වි.කෙ. සේවාදායකයක් ධාවනය කිරීමට නොහැකිය", "dhcp_title": "ග.ධා.වි.කෙ. සේවාදායකය (පර්යේෂණාත්මක!)", "dhcp_description": "ඔබගේ මාර්ගකාරකය ග.ධා.වි.කෙ. (DHCP) සැකසුම් ලබා නොදෙන්නේ නම්, ඔබට ඇඩ්ගාර්ඩ් හි ඇති ග.ධා.වි.කෙ. සේවාදායකය භාවිතා කළ හැකිය.", @@ -18,16 +22,21 @@ "dhcp_config_saved": "ග.ධා.වි.කෙ. වින්‍යාසය සාර්ථකව සුරකින ලදි", "dhcp_ipv4_settings": "ග.ධා.වි.කෙ. අ.ජා.කෙ. 4 සැකසුම්", "dhcp_ipv6_settings": "ග.ධා.වි.කෙ. අ.ජා.කෙ. 6 සැකසුම්", - "form_error_required": "අවශ්‍ය ක්ෂේත්‍රයකි", - "form_error_ip4_format": "වලංගු නොවන IPv4 ලිපිනයකි", - "form_error_ip4_range_start_format": "පරාසය ආරම්භයේ අ.ජා.කෙ.4 ලිපිනය වලංගු නොවේ", - "form_error_ip4_range_end_format": "පරාසය අවසානයේ අ.ජා.කෙ.4 ලිපිනය වලංගු නොවේ", + "form_error_required": "ඇවැසි ක්‍ෂේත්‍රයකි", + "form_error_ip4_format": "IPv4 ලිපිනය වලංගු නොවේ", + "form_error_ip4_range_start_format": "පරාසය ආරම්භයේ වලංගු නොවන අ.ජා.කෙ.4 ලිපිනයකි", + "form_error_ip4_range_end_format": "පරාසය අවසානයේ වලංගු නොවන අ.ජා.කෙ.4 ලිපිනයකි", "form_error_ip6_format": "වලංගු නොවන අ.ජා.කෙ.6 ලිපිනයකි", "form_error_ip_format": "අ.ජා.කෙ. (IP) ලිපිනය වලංගු නොවේ", "form_error_mac_format": "මා.ප්‍ර.පා. ලිපිනය වලංගු නොවේ", "form_error_client_id_format": "අනුග්‍රාහකයේ හැඳු. වලංගු නොවේ", - "form_error_server_name": "වලංගු නොවන සේවාදායක නාමයකි", + "form_error_server_name": "සේවාදායකයේ නම වලංගු නොවේ", "form_error_positive": "0 ට වඩා වැඩි විය යුතුය", + "out_of_range_error": "\"{{start}}\"-\"{{end}}\" පරාසයෙන් පිට විය යුතුය", + "lower_range_start_error": "පරාසය ආරම්භයට වඩා අඩු විය යුතුය", + "greater_range_start_error": "පරාසය ආරම්භයට වඩා වැඩි විය යුතුය", + "greater_range_end_error": "පරාසය අවසානයට වඩා වැඩි විය යුතුය", + "subnet_error": "ලිපින එක් අනුජාලයක තිබිය යුතුය", "dhcp_form_range_title": "අ.ජා. කෙ. (IP) ලිපින පරාසය", "dhcp_form_range_start": "පරාසය ආරම්භය", "dhcp_form_range_end": "පරාසය අවසානය", @@ -38,7 +47,7 @@ "dhcp_table_hostname": "ධාරක නාමය", "dhcp_table_expires": "කල් ඉකුත් වීම", "dhcp_warning": "ඔබට කෙසේ හෝ ග.ධා.වි.කෙ. සේවාදායකය සබල කිරීමට අවශ්‍ය නම්, ඔබගේ ජාලයේ වෙනත් ක්‍රියාකාරී ග.ධා.වි.කෙ. සේවාදායකයක් නැති බව තහවුරු කරගන්න. මෙය සම්බන්ධිත උපාංග සඳහා අන්තර්ජාලය බිඳ දැමිය හැකිය!", - "dhcp_error": "ජාලයේ තවත් ග.ධා.වි.කෙ. සේවාදායකයක් තිබේද යන්න නිශ්චය කළ නොහැකි විය.", + "dhcp_error": "ජාලයේ තවත් ක්‍රියාත්මක ග.ධා.වි.කෙ. සේවාදායකයක් තිබේද යන්න නිශ්චය කළ නොහැකි විය", "dhcp_static_ip_error": "ග.ධා.වි.කෙ. සේවාදායකය භාවිතා කිරීම සඳහා ස්ථිතික අන්තර්ජාල කෙටුම්පත් (IP) ලිපිනයක් සැකසිය යුතුය. මෙම ජාල අතුරුමුහුණත ස්ථිතික අ.ජා. කෙ. ලිපිනයක් භාවිතයෙන් වින්‍යාසගත කර තිබේද යන්න තීරණය කිරීමට ඇඩ්ගාර්ඩ් හෝම් අසමත් විය. කරුණාකර ස්ථිතික අ.ජා. කෙ. ලිපිනයක් අතින් සකසන්න.", "dhcp_dynamic_ip_found": "ඔබගේ පද්ධතිය <0>{{interfaceName}} අතුරු මුහුණත සඳහා ගතික අන්තර්ජාල කෙටුම්පත් (IP) ලිපින වින්‍යාසය භාවිතා කරයි. ග.ධා.වි.කෙ. සේවාදායකය භාවිතා කිරීම සඳහා ස්ථිතික අ.ජා. කෙ. ලිපිනයක් සැකසිය යුතුය. ඔබගේ වර්තමාන අ.ජා. කෙ. ලිපිනය <0>{{ipAddress}} වේ. ඔබ \"ග.ධා.වි.කෙ. සබල කරන්න\" බොත්තම එබුවහොත් ඇඩ්ගාර්ඩ් හෝම් ස්වයංක්‍රීයව මෙම අ.ජා. කෙ. ලිපිනය ස්ථිතික ලෙස සකසනු ඇත.", "dhcp_reset": "ග.ධා.වි.කෙ. වින්‍යාසය යළි පිහිටුවීමට අවශ්‍ය බව ඔබට විශ්වාස ද?", @@ -56,7 +65,7 @@ "settings": "සැකසුම්", "filters": "පෙරහන්", "filter": "පෙරහන", - "query_log": "විමසුම් ලොගය", + "query_log": "විමසුම් සටහන", "compact": "සංක්ෂිප්ත", "nothing_found": "කිසිවක් හමු නොවිණි", "faq": "නිති පැණ", @@ -78,7 +87,7 @@ "blocked_by": "<0>පෙරහන් මගින් අවහිර කළ", "stats_malware_phishing": "අවහිර කළ ද්වේශාංග/තතුබෑම්", "stats_adult": "අවහිර කළ වැඩිහිටි වියමන අඩවි", - "stats_query_domain": "ජනප්‍රිය විමසන ලද වසම්", + "stats_query_domain": "ප්‍රචලිත විමසන ලද වසම්", "for_last_24_hours": "පසුගිය පැය 24 සඳහා", "for_last_days": "පසුගිය දවස් {{count}} සඳහා", "for_last_days_plural": "පසුගිය දවස් {{count}} සඳහා", @@ -86,8 +95,8 @@ "stats_disabled_short": "සංඛ්‍යාලේඛන අබල කර ඇත", "no_domains_found": "වසම් කිසිවක් හමු නොවිණි", "requests_count": "ඉල්ලීම් ගණන", - "top_blocked_domains": "ජනප්‍රිය අවහිර කළ වසම්", - "top_clients": "ජනප්‍රිය අනුග්‍රාහක", + "top_blocked_domains": "ප්‍රචලිත අවහිර කළ වසම්", + "top_clients": "ප්‍රචලිත අනුග්‍රාහක", "no_clients_found": "අනුග්‍රාහක හමු නොවිණි", "general_statistics": "පොදු සංඛ්‍යාලේඛන", "number_of_dns_query_days": "පසුගිය දවස් {{count}} සඳහා සැකසූ ව.නා.ප. විමසුම් ගණන", @@ -157,23 +166,26 @@ "enter_valid_blocklist": "අවහිර කිරී‌‌‌‌‌මේ ලැයිස්තුවට වලංගු ඒ.ස.නි.(URL) ලිපිනයක් ඇතුල් කරන්න.", "enter_valid_allowlist": "ඉඩ දීමේ ලැයිස්තුවට වලංගු ඒ.ස.නි.(URL) ලිපිනයක් ඇතුල් කරන්න.", "form_error_url_format": "වලංගු නොවන ඒ.ස.නි.(URL) ආකෘතියකි", - "form_error_url_or_path_format": "ලැයිස්තුවක වලංගු නොවන ඒ.ස.නි.(URL) හෝ ස්ථීර මාර්ගයකි", + "form_error_url_or_path_format": "වලංගු නොවන ඒ.ස.නි.(URL) හෝ ස්ථීර මාර්ගයකි", "custom_filter_rules": "අභිරුචි පෙරීමේ නීති", "custom_filter_rules_hint": "පේළියකට එක් නීතියක් බැගින් ඇතුල් කරන්න. ඔබට දැන්වීම් අවහිර කිරීමේ නීති හෝ ධාරක ගොනු පද ගැලපුම් භාවිතා කළ හැකිය.", "system_host_files": "පද්ධතියේ සත්කාරක ගොනු", "examples_title": "උදාහරණ", - "example_meaning_filter_block": "උදාහරණය.ලංකා වසමට සහ එහි සියළුම උප වසම් වලට ප්‍රවේශය අවහිර කරයි", - "example_meaning_filter_whitelist": "උදාහරණය.ලංකා වසමට සහ එහි සියළුම උප වසම් වලට ප්‍රවේශය අනවහිර කරයි", - "example_meaning_host_block": "ඇඩ්ගාර්ඩ් හෝම් දැන් උදාහරණය.ලංකා වසම සඳහා 127.0.0.1 ලිපිනය ලබා දෙනු ඇත (නමුත් එහි උප ලිපින නොවේ).", - "example_comment": "! මෙතැන අදහස් දැක්වීමක්", - "example_comment_meaning": "අදහසක්", - "example_comment_hash": "# එසේම අදහස් දැක්වීමක්", - "example_regex_meaning": "නිශ්චිතව දක්වා ඇති නිත්‍ය වාක්‍යවිධියට ගැලපෙන වසම් වෙත ප්‍රවේශය අවහිර කරයි", - "example_upstream_regular": "සාමාන්‍ය ව.නා.ප. (UDP හරහා)", + "example_meaning_filter_block": "උදාහරණය.ලංකා වසමට සහ එහි සියළු උප වසම් වලට ප්‍රවේශය අවහිර කරයි;", + "example_meaning_filter_whitelist": "උදාහරණය.ලංකා වසමට සහ එහි සියළු උප වසම් වලට ප්‍රවේශය අනවහිර කරයි;", + "example_meaning_host_block": "උදාහරණය.ලංකා වසම සඳහා 127.0.0.1 සමඟ ප්‍රතිචාර දක්වයි (නමුත් එහි උප ලිපින සඳහා නොවේ);", + "example_comment": "! මෙතැන අදහස් දැක්වීමක්.", + "example_comment_meaning": "අදහසක්;", + "example_comment_hash": "# එසේම අදහස් දැක්වීමක්.", + "example_regex_meaning": "නිශ්චිතව දක්වා ඇති නිත්‍ය වාක්‍යවිධියට ගැළපෙන වසම් වෙත ප්‍රවේශය අවහිර කරයි.", + "example_upstream_regular": "සාමාන්‍ය ව.නා.ප. (UDP හරහා);", + "example_upstream_udp": "සාමාන්‍ය ව.නා.ප. (UDP, සත්කාරක නම හරහා);", "example_upstream_dot": "සංකේතිත <0>DNS-over-TLS", "example_upstream_doh": "සංකේතිත <0>DNS-over-HTTPS", - "example_upstream_doq": "සංකේතිත <0>DNS-over-QUIC", - "example_upstream_tcp": "සාමාන්‍ය ව.නා.ප. (TCP/ස.පා.කෙ. හරහා) ", + "example_upstream_doq": "සංකේතිත <0>DNS-over-QUIC;", + "example_upstream_sdns": "<1>DNSCrypt හෝ <2>HTTPS-හරහා-ව.නා.ප. විසඳුම් සඳහා <0>ව.නා.ප. මුද්දර;", + "example_upstream_tcp": "සාමාන්‍ය ව.නා.ප. (TCP/ස.පා.කෙ. හරහා);", + "example_upstream_tcp_hostname": "සාමාන්‍ය ව.නා.ප. (ස.පා.කෙ., සත්කාරක නම හරහා);", "all_lists_up_to_date_toast": "සියළුම ලැයිස්තු දැනටමත් යාවත්කාලීනයි", "dns_test_ok_toast": "සඳහන් කළ ව.නා.ප. සේවාදායක නිවැරදිව ක්‍රියා කරයි", "dns_test_not_ok_toast": "\"{{key}}\" සේවාදායක(ය): භාවිතා කිරීමට නොහැකි විය, ඔබ එය නිවැරදිව ලියා ඇතිදැයි පරීක්‍ෂා කරන්න", @@ -194,6 +206,7 @@ "empty_response_status": "හිස්", "show_all_filter_type": "සියල්ල පෙන්වන්න", "show_filtered_type": "පෙරූ දෑ පෙන්වන්න", + "no_logs_found": "සටහන් හමු නොවිණි", "refresh_btn": "නැවුම් කරන්න", "previous_btn": "පෙර", "next_btn": "ඊළඟ", @@ -205,20 +218,21 @@ "rule_added_to_custom_filtering_toast": "අභිරුචි පෙරීමේ නීති තුළට මෙම නීතිය එකතු කෙරිණි: {{rule}}", "query_log_response_status": "තත්වය: {{value}}", "query_log_filtered": "{{filter}} මගින් පෙරිණි", - "query_log_confirm_clear": "සම්පූර්ණ විමසුම් ලොගය ඉවත් කිරීමට අවශ්‍ය යැයි ඔබට විශ්වාසද?", - "query_log_updated": "විමසුම් ලොගය සාර්ථකව යාවත්කාලීන කරන ලදි", - "query_log_clear": "විමසුම් ලොග ඉවත් කරන්න", - "query_log_retention": "විමසුම් ලොග රඳවා තබා ගැනීම", - "query_log_enable": "ලොගය සබල කරන්න", - "query_log_configuration": "ලොග වින්‍යාසය", - "query_log_disabled": "විමසුම් ලොගය අබල කර ඇති අතර එය <0>සැකසුම් තුළ වින්‍යාසගත කළ හැකිය", + "query_log_confirm_clear": "සමස්ථ විමසුම් සටහන හිස් කිරීමට ඇවැසි බව ඔබට විශ්වාසද?", + "query_log_cleared": "විමසුම් සටහන සාර්ථකව හිස් කර ඇත", + "query_log_updated": "විමසුම් සටහන සාර්ථකව යාවත්කාල කෙරිණි", + "query_log_clear": "විමසුම් සටහන් හිස් කරන්න", + "query_log_retention": "විමසුම් සටහන් රඳවා තබා ගැනීම", + "query_log_enable": "සටහන සබල කරන්න", + "query_log_configuration": "සටහන් වින්‍යාසය", + "query_log_disabled": "විමසුම් සටහන අබල කර ඇති අතර එය <0>සැකසුම් තුළ වින්‍යාසගත කළ හැකිය", "query_log_strict_search": "ඉතා නිවැරදිව සෙවීමට ද්විත්ව උද්ධෘතය භාවිතා කරන්න", - "query_log_retention_confirm": "විමසුම් ලොගය රඳවා තබා ගැනීම වෙනස් කිරීමට අවශ්‍ය බව ඔබට විශ්වාසද? ඔබ කාල පරතරයෙහි අගය අඩු කළහොත් සමහර දත්ත නැති වී යනු ඇත", + "query_log_retention_confirm": "විමසුම් සටහන රඳවා තබා ගැනීම වෙනස් කිරීමට ඇවැසි බව ඔබට විශ්වාසද? ඔබ කාල පරතරයෙහි අගය අඩු කළහොත් සමහර දත්ත නැති වී යනු ඇත", "anonymize_client_ip": "අනුග්‍රාහකයෙහි අ.ජා.කෙ. (IP) නිර්නාමික කරන්න", - "anonymize_client_ip_desc": "ලොග සහ සංඛ්‍යාලේඛන තුළ අනුග්‍රාහකයේ සම්පූර්ණ අ.ජා.කෙ. ලිපිනය සුරැකීමෙන් වලකින්න", + "anonymize_client_ip_desc": "සටහන් සහ සංඛ්‍යාලේඛන තුළ අනුග්‍රාහකයේ පූර්ණ අ.ජා.කෙ. ලිපිනය සුරකින්න එපා", "dns_config": "ව.නා.ප. සේවාදායක වින්‍යාසය", "dns_cache_config": "ව.නා.ප. නිහිත වින්‍යාසය", - "dns_cache_config_desc": "මෙහිදී ඔබට ව.නා.ප. නිහිතය වින්‍යාසගත කළ හැකිය", + "dns_cache_config_desc": "මෙතැන ඔබට ව.නා.ප. නිහිතය වින්‍යාසගත කළ හැකිය", "blocking_mode": "අවහිර කරන ආකාරය", "default": "සුපුරුදු", "nxdomain": "නොපවතින වසම", @@ -227,8 +241,15 @@ "custom_ip": "අභිරුචි අ.ජා.කෙ.", "blocking_ipv4": "අ.ජා.කෙ.4 අවහිර කිරීම", "blocking_ipv6": "අ.ජා.කෙ.6 අවහිර කිරීම", - "client_id": "අනුග්‍රාහකයේ හැඳුනුම", - "client_id_placeholder": "අනුග්‍රාහකයේ හැඳුනුම යොදන්න", + "dnscrypt": "DNSCrypt", + "dns_over_https": "HTTPS-හරහා-ව.නා.ප.", + "dns_over_tls": "TLS-හරහා-ව.නා.ප.", + "dns_over_quic": "QUIC-හරහා-ව.නා.ප.", + "client_id": "අනුග්‍රාහකයේ හැඳු.", + "client_id_placeholder": "අනුග්‍රාහකයක හැඳු. යොදන්න", + "client_id_desc": "අනුග්‍රාහක හැඳු. මගින් අනුග්‍රාහක හඳුනාගත හැකිය. කෙසේදැයි මෙතැනින් දැන ගන්න.", + "download_mobileconfig_doh": "HTTPS-හරහා-ව.නා.ප. සඳහා .ජංගමවින්‍යාසය බාගන්න", + "download_mobileconfig_dot": "TLS-හරහා-ව.නා.ප. සඳහා .ජංගමවින්‍යාසය බාගන්න", "download_mobileconfig": "වින්‍යාසගත ගොනුව බාගන්න", "plain_dns": "සරල ව.නා.ප.", "form_enter_rate_limit": "අනුපාත සීමාව ඇතුල් කරන්න", @@ -255,12 +276,12 @@ "install_welcome_desc": "ඇඩ්ගාර්ඩ් හෝම් යනු ජාලය පුරා ඇති දැන්වීම් සහ ලුහුබැඳීම අවහිර කරන ව.නා.ප. සේවාදායකයකි. ඔබගේ මුළු ජාලය සහ සියළුම උපාංග පාලනය කිරීමට ඉඩ සලසා දීම එහි පරමාර්ථය යි, එයට අනුග්‍රාහක පාර්ශවීය වැඩසටහනක් භාවිතා කිරීම අවශ්‍ය නොවේ.", "install_settings_title": "පරිපාලක වියමන අතුරු මුහුණත", "install_settings_listen": "සවන් දෙන අතුරු මුහුණත", - "install_settings_port": "කෙවෙනිය", + "install_settings_port": "තොට", "install_settings_interface_link": "ඔබගේ ඇඩ්ගාර්ඩ් හෝම් පරිපාලක වියමන අතුරු මුහුණතට පහත ලිපින වලින් ප්‍රවේශ වීමට හැකිය:", - "form_error_port": "වලංගු කෙවෙනියක අගයක් යොදන්න", + "form_error_port": "වලංගු තොටක අගයක් යොදන්න", "install_settings_dns": "ව.නා.ප. සේවාදායකය", "install_settings_dns_desc": "පහත ලිපිනයන්හි ව.නා.ප. සේවාදායකය භාවිතා කිරීම සඳහා ඔබගේ උපාංග හෝ මාර්ගකාරකය වින්‍යාසගත කිරීමට අවශ්‍ය වනු ඇත:", - "install_settings_all_interfaces": "සියලුම අතුරුමුහුණත්", + "install_settings_all_interfaces": "සියළු අතුරුමුහුණත්", "install_auth_title": "සත්‍යාපනය", "install_auth_desc": "ඔබගේ ඇඩ්ගාර්ඩ් හෝම් පරිපාලන වියමන අතුරු මුහුණතට මුරපද සත්‍යාපනය වින්‍යාසගත කළ යුතුය. එය ඔබගේ ස්ථානීය ජාල‌යෙන් පමණක් ප්‍රවේශ විය හැකි වුවද, එය තව දුරටත් සීමා රහිත ප්‍රවේශයකින් ආරක්ෂා කර ගැනීම වැදගත් ය.", "install_auth_username": "පරිශීලක නාමය", @@ -274,14 +295,15 @@ "install_submit_title": "සුභ පැතුම්!", "install_submit_desc": "පිහිටුවීමේ ක්‍රියා පටිපාටිය අවසන් වී ඇති අතර ඔබ දැන් ඇඩ්ගාර්ඩ් හෝම් භාවිතය ආරම්භ කිරීමට සූදානම්ය.", "install_devices_router": "මාර්ගකාරකය", - "install_devices_router_desc": "මෙම පිහිටුම ඔබගේ නිවසේ මාර්ගකාරකයට සම්බන්ධ සියලුම උපාංග ස්වයංක්‍රීයව ආවරණය කරන අතර ඔබට ඒ සෑම එකක්ම අතින් වින්‍යාසගත කිරීමට අවශ්‍ය නොවේ.", + "install_devices_router_desc": "මෙම පිහිටුම ඔබගේ නිවසේ මාර්ගකාරකයට සම්බන්ධ සියළුම උපාංග ස්වයංක්‍රීයව ආවරණය කරන අතර ඔබට ඒ සෑම එකක්ම අතින් වින්‍යාසගත කිරීමට අවශ්‍ය නොවේ.", "install_devices_address": "ඇඩ්ගාර්ඩ් හෝම් ව.නා.ප. සේවාදායකය පහත ලිපිනයන්ට සවන් දෙමින් පවතී", + "install_devices_router_list_1": "ඔබගේ මාර්ගකාරකය සඳහා වූ මනාපයන් විවෘත කරන්න. සාමාන්‍යයෙන්, එය ඔබගේ අතිරික්සුවෙන් ඒ.ස.නි.(URL) ක් හරහා (http://192.168.0.1/ හෝ http://192.168.1.1/ වැනි) ප්‍රවේශ විය හැකිය. මුරපදය ඇතුල් කිරීමට සිදු විය හැකි නමුත් එය මතක නැතිනම් බොහෝ විට මාර්ගකාරකයේ බොත්තමක් එබීමෙන් මුරපදය නැවත සැකසිය හැකිය. නමුත් මෙම ක්‍රියා පටිපාටිය තෝරා ගන්නේ නම්, බොහෝ විට ඔබගේ මාර්ගකාරකයේ සමස්ථ වින්‍යාසය අහිමි වනු ඇති බව මතක තබා ගන්න.එය පිහිටුවීමට ඔබගේ මාර්ගකාරකයට යෙදුමක් ඇවැසි නම්, කරුණාකර එය ඔබගේ පරිගණකයේ හෝ දුරකථනයේ ස්ථාපනය කර මාර්ගකාරකයේ සැකසුම් වෙත ප්‍රවේශ වීමට භාවිතා කරන්න.", "install_devices_router_list_2": "ග.ධා.වි.කෙ. (DHCP)/ ව.නා.ප. (DNS) සැකසුම් සොයා ගන්න. අංක කට්ටල දෙකකට හෝ තුනකට ඉඩ දෙන ක්ෂේත්‍රයක් අසල ඇති ව.නා.ප. අකුරු බලන්න, සෑම එකක්ම ඉලක්කම් එකේ සිට තුන දක්වා කාණ්ඩ හතරකට බෙදා ඇත.", "install_devices_router_list_3": "ඔබගේ ඇඩ්ගාර්ඩ් හෝම් සේවාදායක ලිපින එහි ඇතුල් කරන්න.", "install_devices_router_list_4": "සමහර වර්ගයේ මාර්ගකාරක වල අභිරුචි ව.නා.ප. සේවාදායකයක් සැකසීමට නොහැකිය. මෙම අවස්ථාවේදී ඇඩ්ගාර්ඩ් හෝම් <0>ග.ධා.වි.කෙ. සේවාදායකයක් ලෙස පිහිටුවන්නේ නම් එය උපකාර වනු ඇත. එසේ නැතිනම්, ඔබගේ විශේෂිත මාර්ගකාරකය සඳහා වූ ව.නා.ප. සේවාදායක රිසිකරණය කරන්නේ කෙසේද යන්න පිළිබඳ අත්පොත පරීක්‍ෂා කළ යුතුය.", "install_devices_windows_list_2": "ජාල සහ අන්තර්ජාල ප්‍රවර්ගයට ගොස් පසුව ජාල සහ බෙදාගැනීමේ මධ්‍යස්ථානය වෙත යන්න.", - "install_devices_windows_list_3": "\"උපයුක්තක‌‌‌යෙහි සැකසුම් වෙනස් කිරීම\" තිරයේ වම් පසින් සොයාගෙන එය මත ඔබන්න.", - "install_devices_windows_list_4": "ඔබගේ ක්‍රියාකාරී සම්බන්ධතාවය තෝරන්න, එය මත දකුණු-ක්ලික් කර ගුණාංග තෝරන්න.", + "install_devices_windows_list_3": "වම් තීරුවෙහි \"උපයුක්තක‌‌‌යෙහි සැකසුම් වෙනස් කිරීම\" ඔබන්න.", + "install_devices_windows_list_4": "ඔබගේ ක්‍රියාකාරී සම්බන්ධතාවය මත දකුණු-ක්ලික් කර ගුණාංග තෝරන්න.", "install_devices_windows_list_5": "ලැයිස්තුවෙන් \"අන්තර්ජාල කෙටුම්පත් අනුවාදය 4 (TCP/IPv4)\" (හෝ, IPv6 සඳහා, \"අන්තර්ජාල කෙටුම්පත් අනුවාදය 6 (TCP/IPv6)\") සොයාගෙන එය තෝරා ඉන්පසු ගුණාංග මත නැවත ඔබන්න.", "install_devices_windows_list_6": "'පහත සඳහන් ව.නා.ප. සේවාදායක ලිපින භාවිතා කරන්න' යන්න තෝරා ඔබගේ ඇඩ්ගාර්ඩ් හෝම් සේවාදායක ලිපින ඇතුල් කරන්න.", "install_devices_macos_list_1": "ඇපල් නිරූපකය එබීමෙන් පසු පද්ධතියේ මනාප වෙත යන්න.", @@ -302,18 +324,18 @@ "open_dashboard": "උපකරණ පුවරුව විවෘත කරන්න", "install_saved": "සාර්ථකව සුරකින ලදි", "encryption_title": "සංකේතනය", - "encryption_desc": "ගුප්තකේතනය (HTTPS/TLS) සඳහා ව.නා.ප. සහ පරිපාලක වියමන අතුරු මුහුණත සහය දක්වයි", + "encryption_desc": "ගුප්තකේතනය (HTTPS/QUIC/TLS) සඳහා ව.නා.ප. සහ පරිපාලක වියමන අතුරු මුහුණත සහය දක්වයි", "encryption_config_saved": "සංකේතන වින්‍යාසය සුරකින ලදි", "encryption_server": "සේවාදායක‌‌‌‌යේ නම", "encryption_server_enter": "ඔබගේ වසම් නාමය ඇතුල් කරන්න", "encryption_redirect": "ස්වයංක්‍රීයව HTTPS වෙත හරවා යවන්න", "encryption_redirect_desc": "සබල කර ඇත්නම්, ඇඩ්ගාර්ඩ් හෝම් ඔබව ස්වයංක්‍රීයව HTTP සිට HTTPS ලිපින වෙත හරවා යවනු ඇත.", - "encryption_https": "HTTPS කෙවෙනිය", - "encryption_https_desc": "HTTPS කෙවෙනිය වින්‍යාසගත කර ඇත්නම්, ඇඩ්ගාර්ඩ් හෝම් පරිපාලක අතුරුමුහුණත HTTPS හරහා ප්‍රවේශ විය හැකි අතර එය '/dns-query' ස්ථානයේ DNS-over-HTTPS ද ලබා දෙනු ඇත.", - "encryption_dot": "DNS-over-TLS කෙවෙනිය", - "encryption_dot_desc": "මෙම කෙවෙනිය වින්‍යාසගත කර ඇත්නම්, ඇඩ්ගාර්ඩ් හෝම් විසින් මෙම කවුළුව හරහා DNS-over-TLS සේවාදායකයක් ධාවනය කරනු ඇත.", - "encryption_doq": "DNS-over-QUIC කෙවෙනිය", - "encryption_doq_desc": "මෙම කෙවෙනිය වින්‍යාසගත කර ඇත්නම්, ඇඩ්ගාර්ඩ් හෝම් විසින් මෙම කෙවෙනිය හරහා DNS-over-QUIC සේවාදායකයක් ධාවනය කරනු ඇත. එය පර්යේෂණාත්මක වන අතර විශ්වාසදායක නොවිය හැකිය. එසේම, මේ වන විට එයට සහාය දක්වන බොහෝ අනුග්‍රාහකයින් නැත.", + "encryption_https": "HTTPS තොට", + "encryption_https_desc": "HTTPS තොට වින්‍යාසගත කර ඇත්නම්, ඇඩ්ගාර්ඩ් හෝම් පරිපාලක අතුරුමුහුණත HTTPS හරහා ප්‍රවේශ විය හැකි අතර එය '/dns-query' ස්ථානයේ HTTPS-හරහා-ව.නා.ප. ද ලබා දෙනු ඇත.", + "encryption_dot": "TLS-හරහා-ව.නා.ප. තොට", + "encryption_dot_desc": "මෙම තොට වින්‍යාසගත කර ඇත්නම්, ඇඩ්ගාර්ඩ් හෝම් විසින් මෙම කවුළුව හරහා TLS-හරහා-ව.නා.ප. සේවාදායකයක් ධාවනය කරනු ඇත.", + "encryption_doq": "QUIC-හරහා-ව.නා.ප. තොට", + "encryption_doq_desc": "මෙම තොට වින්‍යාසගත කර ඇත්නම්, ඇඩ්ගාර්ඩ් හෝම් විසින් මෙම තොට හරහා QUIC-හරහා-ව.නා.ප. සේවාදායකයක් ධාවනය කරනු ඇත. එය පරීක්‍ෂාත්මක වන අතර විශ්වාසදායක නොවිය හැකිය. එසේම, මේ වන විට එයට සහාය දක්වන බොහෝ අනුග්‍රාහක නැත.", "encryption_certificates": "සහතික", "encryption_certificates_input": "ඔබගේ PEM-කේතනය කළ සහතික පිටපත් කර මෙහි අලවන්න.", "encryption_status": "තත්වය", @@ -332,24 +354,25 @@ "encryption_reset": "සංකේතාංකන සැකසුම් යළි පිහිටුවීමට අවශ්‍ය බව ඔබට විශ්වාස ද?", "topline_expiring_certificate": "ඔබගේ SSL සහතිකය කල් ඉකුත්වීමට ආසන්න වී ඇත. <0>සංකේතන සැකසුම් යාවත්කාල කරන්න.", "topline_expired_certificate": "ඔබගේ SSL සහතිකය කල් ඉකුත් වී ඇත. <0>සංකේතන සැකසුම් යාවත්කාල කරන්න.", - "form_error_port_range": "80-65535 පරාසය හි කෙවෙනියක අගයක් ඇතුල් කරන්න", - "form_error_port_unsafe": "මෙය අනාරක්ෂිත කෙවෙනියකි", + "form_error_port_range": "80-65535 පරාසය හි තොටක අගයක් ඇතුල් කරන්න", + "form_error_port_unsafe": "මෙය අනාරක්‍ෂිත තොටකි", "form_error_equal": "සමාන නොවිය යුතුය", - "form_error_password": "මුරපදය නොගැලපුණි", + "form_error_password": "මුරපදය නොගැළපේ", "reset_settings": "සැකසුම් යළි පිහිටුවන්න", "update_announcement": "ඇඩ්ගාර්ඩ් හෝම් {{version}} දැන් ලබා ගත හැකිය! වැඩි විස්තර සඳහා <0>මෙය ඔබන්න.", "setup_guide": "පිහිටුවීමේ මාර්ගෝපදේශය", "dns_addresses": "ව.නා.ප. ලිපින", "dns_start": "ව.නා.ප. සේවාදායකය ආරම්භ වෙමින්", - "dns_status_error": "ව.නා.ප. සේවාදායකයේ තත්වය පරීක්‍ෂා කිරීමේදී දෝෂයකි", + "dns_status_error": "ව.නා.ප. සේවාදායකයේ තත්‍වය පරීක්‍ෂා කිරීමේ දෝෂයකි", "down": "බිඳ වැටී", "fix": "නිරාකරණය", "dns_providers": "මෙහි තෝරා ගැනීමට <0>දැනුවත් ව.නා.ප. සපයන්නන්ගේ ලැයිස්තුවක් ඇත.", "update_now": "යාවත්කාල කරන්න", "update_failed": "ස්වයං යාවත්කාලය අසමත් විය. අතින් යාවත්කාල කිරීමට කරුණාකර පියවර අනුගමනය කරන්න.", + "manual_update": "අතින් යාවත්කාල කිරීමට මෙම පියවර අනුගමනය කරන්න.", "processing_update": "රැඳී සිටින්න, ඇඩ්ගාර්ඩ් හෝම් යාවත්කාල වෙමින්", - "clients_title": "අනුග්‍රාහක", - "clients_desc": "ඇඩ්ගාර්ඩ් හෝම් වෙත සම්බන්ධිත උපාංග වින්‍යාසගත කරන්න", + "clients_title": "නිබැඳි අනුග්‍රාහක", + "clients_desc": "ඇඩ්ගාර්ඩ් හෝම් වෙත සම්බන්ධිත උපාංග සඳහා නිබැඳි අනුග්‍රාහක වාර්තා වින්‍යාසගත කරන්න", "settings_global": "ගෝලීය", "settings_custom": "අභිරුචි", "table_client": "අනුග්‍රාහකය", @@ -374,9 +397,9 @@ "clients_not_found": "අනුග්‍රාහක හමු නොවිණි", "client_confirm_delete": "\"{{key}}\" අනුග්‍රාහකය ඉවත් කිරීමට අවශ්‍ය බව ඔබට විශ්වාසද?", "list_confirm_delete": "මෙම ලැයිස්තුව ඉවත් කිරීමට අවශ්‍ය බව ඔබට විශ්වාස ද?", - "auto_clients_desc": "ඇඩ්ගාර්ඩ් හෝම් භාවිතා කරන අනුග්‍රාහක දත්ත, නමුත් වින්‍යාසය තුළ ගබඩා කර නැති", + "auto_clients_desc": "ඇඩ්ගාර්ඩ් හෝම් භාවිතා කරන නිබැඳි අනුග්‍රාහක තුළ නැති උපාංග", "access_title": "ප්‍රවේශවීමට සැකසුම්", - "access_desc": "මෙහිදී ඔබට ඇඩ්ගාර්ඩ් හෝම් ව.නා.ප. සේවාදායකය සඳහා ප්‍රවේශ වී‌‌‌‌මේ නීති වින්‍යාසගත කළ හැකිය.", + "access_desc": "මෙහිදී ඔබට ඇඩ්ගාර්ඩ් හෝම් ව.නා.ප. සේවාදායකයට ප්‍රවේශ වී‌‌‌‌මේ නීති වින්‍යාසගත කළ හැකිය", "access_allowed_title": "ඉඩ ලත් අනුග්‍රාහකයින්", "access_allowed_desc": "CIDR හෝ අ.ජා. කෙ. ලිපින ලැයිස්තුවක් වින්‍යාසගත කර ඇත්නම්, ඇඩ්ගාර්ඩ් හෝම් විසින් එම අ.ජා. කෙ. ලිපින වලින් පමණක් ඉල්ලීම් පිළිගනු ඇත.", "access_disallowed_title": "නොඉඩ ලත් අනුග්‍රාහකයින්", @@ -388,6 +411,7 @@ "check_updates_now": "දැන් යාවත්කාල පරීක්‍ෂා කරන්න", "dns_privacy": "ව.නා.ප. රහස්‍යතා", "setup_dns_privacy_3": "<0>මෙහි ඔබට භාවිතා කළ හැකි මෘදුකාංග ලැයිස්තුවක් ඇත.", + "setup_dns_privacy_android_2": "<1>HTTPS-හරහා-ව.නා.ප. සහ <1>TLS-හරහා-ව.නා.ප. සඳහා <0>ඇන්ඩ්‍රොයිඩ් සඳහා ඇඩ්ගාර්ඩ් සහාය දක්වයි.", "setup_dns_privacy_other_title": "වෙනත් ක්‍රියාවට නැංවූ දෑ", "setup_dns_privacy_other_2": "<0>ඩීඑන්එස්ප්‍රොක්සි දන්නා සියලුම ආරක්‍ෂිත ව.නා.ප. කෙටුම්පත් සඳහා සහාය දක්වයි.", "setup_dns_privacy_other_3": "<1>DNS-over-HTTPS සඳහා <0>dnscrypt-පෙරකලාසිය සහාය දක්වයි.", @@ -429,6 +453,7 @@ "interval_days": "දවස් {{count}}", "interval_days_plural": "දවස් {{count}}", "domain": "වසම", + "ecs": "ECS", "answer": "උත්තරය", "filter_added_successfully": "පෙරහන සාර්ථකව එකතු කෙරිණි", "filter_removed_successfully": "ලැයිස්තුව සාර්ථකව ඉවත් කෙරිණි", @@ -436,7 +461,7 @@ "statistics_configuration": "සංඛ්‍යාලේඛන වින්‍යාසය", "statistics_retention": "සංඛ්‍යාලේඛන රඳවා තබා ගැනීම", "statistics_retention_desc": "ඔබ කාල පරතරය අඩු කළහොත් සමහර දත්ත නැති වනු ඇත", - "statistics_clear": " සංඛ්‍යාලේඛන ඉවත් කරන්න", + "statistics_clear": "සංඛ්‍යාලේඛන හිස් කරන්න", "statistics_clear_confirm": "සංඛ්‍යාලේඛන ඉවත් කිරීමට අවශ්‍ය බව ඔබට විශ්වාස ද?", "statistics_retention_confirm": "සංඛ්‍යාලේඛන රඳවා තබා ගැනීම වෙනස් කිරීමට අවශ්‍ය බව ඔබට විශ්වාසද? ඔබ කාල පරතරයෙහි අගය අඩු කළහොත් සමහර දත්ත නැති වී යනු ඇත", "statistics_cleared": "සංඛ්‍යාලේඛන සාර්ථකව ඉවත් කෙරිණි", @@ -475,11 +500,11 @@ "fastest_addr_desc": "සියළුම ව.නා.ප. සේවාදායක වලින් විමසා සියළු ප්‍රතිචාර අතරින් වේගවත්ම අ.ජා.කෙ. ලිපිනය ලබා දෙයි. සියළුම ව.නා.ප. ප්‍රතිචාර සඳහා ඇඩ්ගාර්ඩ් හෝම් රැඳී සිටිය යුතු බැවින් මෙය ව.නා.ප. විමසුම් මන්දගාමී කරන නමුත් සමස්ත සම්බන්ධතාවය වැඩි දියුණු කරයි.", "autofix_warning_text": "ඔබ \"නිරාකරණය\" යන්න එබුවහොත්, ඔබගේ පද්ධතිය ඇඩ්ගාර්ඩ් හෝම් ව.නා.ප. සේවාදායකය භාවිතයට වින්‍යාසගත කෙරෙනු ඇත.", "autofix_warning_result": "ප්‍රතිඵලයක් ලෙස ඔබගේ පද්ධතියෙන් ලැබෙන සියළුම ව.නා.ප. ඉල්ලීම් මූලිකවම ඇඩ්ගාර්ඩ් හෝම් විසින් සකසනු ඇත.", - "tags_title": "හැඳුනුම් සංකේත", - "tags_desc": "අනුග්‍රාහකයට අනුරූප වන හැඳුනුම් සංකේත ඔබට තෝරා ගත හැකිය. පෙරහන් නීති වලට හැඳුනුම් සංකේත ඇතුළත් කළ හැකි අතර ඒවා වඩාත් නිවැරදිව යෙදීමට ඔබට ඉඩ සලසයි. <0>තව දැන ගන්න", - "form_select_tags": "අනුග්‍රාහක හැඳුනුම් සංකේත", + "tags_title": "අනන්‍යන", + "tags_desc": "අනුග්‍රාහකයට අනුරූපව අනන්‍යන ඔබට තෝරා ගත හැකිය. ඒවා වඩාත් නිවැරදිව යෙදීමට \nඅනන්‍යන පෙරහන් නීති වලට ඇතුළත් කරන්න. <0>තව දැන ගන්න.", + "form_select_tags": "අනුග්‍රාහක අනන්‍යන තෝරන්න", "check_title": "පෙරීම පරීක්‍ෂා කරන්න", - "check_desc": "ධාරක නාමය පෙරහන් වේ දැයි පරීක්‍ෂා කරන්න", + "check_desc": "සත්කාරක නාමය පෙරෙනවා දැයි පරීක්‍ෂා කරන්න.", "check": "පරීක්‍ෂාව", "form_enter_host": "ධාරක නාමයක් ඇතුල් කරන්න", "filtered_custom_rules": "අභිරුචි පෙරීමේ නීති මගින් පෙරහන් කරන ලදි", @@ -505,6 +530,7 @@ "confirm_static_ip": "ඇඩ්ගාර්ඩ් හෝම් ඔබගේ ස්ථිතික අ.ජා.කෙ. (IP) ලිපිනය ලෙස {{ip}} වින්‍යාසගත කරනු ඇත. ඔබට ඉදිරියට යාමට අවශ්‍යද?", "list_updated": "ලැයිස්තු {{count}} ක් යාවත්කාල කෙරිණි", "list_updated_plural": "ලැයිස්තු {{count}} ක් යාවත්කාල කෙරිණි", + "dnssec_enable": "DNSSEC සබල කරන්න", "all_queries": "සියළුම විමසුම්", "show_blocked_responses": "අවහිර කර ඇත", "show_whitelisted_responses": "ඉඩ දී ඇත", @@ -519,14 +545,15 @@ "blocklist": "අවහිර කිරී‌‌‌‌‌මේ ලැයිස්තුව", "milliseconds_abbreviation": "මිලි තත්.", "cache_size": "නිහිතයෙහි ප්‍රමාණය", - "cache_size_desc": "ව.නා.ප. නිහිතයෙහි ප්‍රමාණය (බයිට වලින්)", + "cache_size_desc": "ව.නා.ප. නිහිතයෙහි ප්‍රමාණය (බයිට)", "cache_ttl_min_override": "අවම පව. කා. අභිබවන්න", "cache_ttl_max_override": "උපරිම පව. කා. අභිබවන්න", "enter_cache_size": "ව.නා.ප. නිහිතයෙහි ප්‍රමාණය යොදන්න (බයිට)", "enter_cache_ttl_min_override": "අවම පව. කා. (TTL) ඇතුල් කරන්න", "enter_cache_ttl_max_override": "උපරිම පව. කා. (TTL) ඇතුල් කරන්න", - "cache_ttl_max_override_desc": "ව.නා.ප. නිහිතයෙහි නිවේශිත සඳහා ඉතා වැඩි පවත්නා කාලයක අගයක් (තත්.) සකසන්න", - "ttl_cache_validation": "නිහිතයෙහි අවම පව. කා. (TTL) අගය උපරිම අගයට වඩා අඩු හෝ සමාන විය යුතුය", + "cache_ttl_max_override_desc": "ව.නා.ප. නිහිතයෙහි නිවේශිත සඳහා උපරිම පවත්නා කාලයක අගයක් (තත්.) සකසන්න.", + "ttl_cache_validation": "නිහිතයෙහි පාගාගෙන යන අවම පව. කා. (TTL) උපරිමයට වඩා අඩු හෝ සමාන විය යුතුය", + "cache_optimistic": "සර්වශුභවාදී නිහිතගතය", "cache_optimistic_desc": "නිවේශිත කල් ඉකුත් වූ විට පවා ඇඩ්ගාර්ඩ් හෝම් ට නිහිතයෙන් ප්‍රතිචාර දැක්වීමට සලස්වයි එමෙන්ම ඒවා නැවත නැවුම් කිරීමට ද උත්සාහ කරයි.", "filter_category_general": "පොදු", "filter_category_security": "ආරක්‍ෂණ", @@ -539,10 +566,13 @@ "setup_config_to_enable_dhcp_server": "ග.ධා.වි.කෙ. සේවාදායකය සබල කිරීමට වින්‍යාසය පිහිටුවන්න", "original_response": "මුල් ප්‍රතිචාරය", "click_to_view_queries": "විමසුම් බැලීමට ඔබන්න", - "port_53_faq_link": "53 වන කෙවෙනිය බොහෝ විට \"DNSStubListener\" හෝ \"systemd-resolved\" සේවා භාවිතයට ගනු ලැබේ. කරුණාකර මෙය විසඳන්නේ කෙසේද යන්න පිළිබඳ <0>මෙම උපදෙස් කියවන්න.", + "port_53_faq_link": "53 වන තොට බොහෝ විට \"DNSStubListener\" හෝ \"systemd-resolved\" සේවා භාවිතයට ගනු ලැබේ. කරුණාකර මෙය විසඳන්නේ කෙසේද යන්න පිළිබඳ <0>මෙම උපදෙස් කියවන්න.", "adg_will_drop_dns_queries": "ඇඩ්ගාර්ඩ් හෝම් මෙම අනුග්‍රාහකයේ සියළුම ව.නා.ප. විමසුම් අතහැර දමනු ඇත.", + "filter_allowlist": "අවවාදයයි: මෙම ක්‍රියාමාර්ගය ඉඩලත් අනුග්‍රාහක ලේඛන වලින්ද \"{{disallowed_rule}}\" නීතිය බැහැර කරයි.", + "last_rule_in_allowlist": "\"{{disallowed_rule}}\" නීතිය බැහැර කිරීම \"ඉඩලත් අනුග්‍රාහක\" ලේඛනය අබල කරන බැවින් මෙම අනුග්‍රාහකය ඉඩ නොදීමට නොහැකිය.", "use_saved_key": "පෙර සුරැකි යතුර භාවිතා කරන්න", "parental_control": "දෙමාපිය පාලනය", "safe_browsing": "ආරක්‍ෂිත පිරික්සුම", - "served_from_cache": "{{value}} (නිහිතයෙන් ගැනිණි)" + "served_from_cache": "{{value}} (නිහිතයෙන් ගැනිණි)", + "form_error_password_length": "මුරපදය අවම වශයෙන් අකුරු {{value}} ක් දිගු විය යුතුමයි" } diff --git a/client/src/__locales/sk.json b/client/src/__locales/sk.json index 118a0578..52048c04 100644 --- a/client/src/__locales/sk.json +++ b/client/src/__locales/sk.json @@ -36,23 +36,23 @@ "dhcp_ipv4_settings": "Nastavenia DHCP IPv4", "dhcp_ipv6_settings": "Nastavenia DHCP IPv6", "form_error_required": "Povinná položka.", - "form_error_ip4_format": "Neplatná IPv4 adresa.", - "form_error_ip4_range_start_format": "Neplatný začiatok rozsahu IPv4 formátu.", - "form_error_ip4_range_end_format": "Neplatná IPv4 adresa konca rozsahu.", - "form_error_ip4_gateway_format": "Neplatná IPv4 adresa brány.", - "form_error_ip6_format": "Neplatná IPv6 adresa.", - "form_error_ip_format": "Neplatná IP adresa.", - "form_error_mac_format": "Neplatná MAC adresa.", - "form_error_client_id_format": "Id klienta musí obsahovať iba čísla, malé písmená a spojovníky.", + "form_error_ip4_format": "Neplatná IPv4 adresa", + "form_error_ip4_range_start_format": "Neplatný začiatok rozsahu IPv4 formátu", + "form_error_ip4_range_end_format": "Neplatný koniec rozsahu IPv4 formátu", + "form_error_ip4_gateway_format": "Neplatná IPv4 adresa brány", + "form_error_ip6_format": "Neplatná IPv6 adresa", + "form_error_ip_format": "Neplatná IP adresa", + "form_error_mac_format": "Neplatná MAC adresa", + "form_error_client_id_format": "ID klienta musí obsahovať iba čísla, malé písmená a spojovníky", "form_error_server_name": "Neplatné meno servera", - "form_error_subnet": "Podsieť \"{{cidr}}\" neobsahuje IP adresu \"{{ip}}\".", - "form_error_positive": "Musí byť väčšie ako 0.", - "out_of_range_error": "Musí byť mimo rozsahu \"{{start}}\"-\"{{end}}\".", - "lower_range_start_error": "Musí byť nižšie ako začiatok rozsahu.", - "greater_range_start_error": "Musí byť väčšie ako začiatok rozsahu.", - "greater_range_end_error": "Musí byť väčšie ako koniec rozsahu.", - "subnet_error": "Adresy musia byť v spoločnej podsieti.", - "gateway_or_subnet_invalid": "Maska podsiete je neplatná.", + "form_error_subnet": "Podsieť \"{{cidr}}\" neobsahuje IP adresu \"{{ip}}\"", + "form_error_positive": "Musí byť väčšie ako 0", + "out_of_range_error": "Musí byť mimo rozsahu \"{{start}}\"-\"{{end}}\"", + "lower_range_start_error": "Musí byť nižšie ako začiatok rozsahu", + "greater_range_start_error": "Musí byť väčšie ako začiatok rozsahu", + "greater_range_end_error": "Musí byť väčšie ako koniec rozsahu", + "subnet_error": "Adresy musia byť v spoločnej podsieti", + "gateway_or_subnet_invalid": "Maska podsiete je neplatná", "dhcp_form_gateway_input": "IP brána", "dhcp_form_subnet_input": "Maska podsiete", "dhcp_form_range_title": "Rozsah IP adries", @@ -67,7 +67,7 @@ "dhcp_table_hostname": "Meno hostiteľa", "dhcp_table_expires": "Vyprší", "dhcp_warning": "Ak chcete server DHCP napriek tomu zapnúť, uistite sa, že v sieti nie je žiadny iný aktívny DHCP server. V opačnom prípade sa môže prerušiť internet pre už pripojené zariadenia!", - "dhcp_error": "AdGuard Home nevie určiť, či je v sieti iný aktívny DHCP server.", + "dhcp_error": "AdGuard Home nevie určiť, či je v sieti iný aktívny DHCP server", "dhcp_static_ip_error": "Aby bolo možné používať DHCP server, musí byť nastavená statická IP adresa. AdGuard Home nedokázal určiť, či je toto sieťové rozhranie nakonfigurované pomocou statickej adresy IP. Nastavte statickú IP adresu manuálne.", "dhcp_dynamic_ip_found": "Váš systém používa pre rozhranie <0>{{interfaceName}} dynamickú konfiguráciu IP adresy. Aby bolo možné používať DHCP server, musí byť nastavená statická IP adresa. Vaša aktuálna IP adresa je <0>{{ipAddress}}. ak Ak stlačíte tlačidlo \"Povoliť DHCP server\", AdGuard Home automaticky nastaví túto IP adresu ako statickú.", "dhcp_lease_added": "Statický \"{{key}}\" prenájmu bol úspešne pridaný", @@ -196,8 +196,8 @@ "choose_allowlist": "Vybrať povolený zoznam", "enter_valid_blocklist": "Zadajte platnú URL adresu do zoznamu blokovaných DNS.", "enter_valid_allowlist": "Zadajte platnú URL adresu do zoznamu povolených DNS.", - "form_error_url_format": "Neplatný URL formát.", - "form_error_url_or_path_format": "Neplatná URL adresa alebo absolútna adresa zoznamu.", + "form_error_url_format": "Neplatný URL formát", + "form_error_url_or_path_format": "Neplatná URL adresa alebo absolútna adresa zoznamu", "custom_filter_rules": "Vlastné filtračné pravidlá", "custom_filter_rules_hint": "Zadajte na každý riadok jedno pravidlo. Môžete použiť buď adblock pravidlá alebo syntax host súborov.", "system_host_files": "Systémové súbory hosts", @@ -210,11 +210,13 @@ "example_comment_hash": "# Tiež komentár.", "example_regex_meaning": "zablokovať prístup k doménam zodpovedajúcim zadanému regulárnemu výrazu.", "example_upstream_regular": "obyčajná DNS (cez UDP);", + "example_upstream_udp": "štandardné DNS (cez UDP, hostname);", "example_upstream_dot": "šifrované <0>DNS-over-TLS;", "example_upstream_doh": "šifrované <0>DNS-over-HTTPS;", "example_upstream_doq": "šifrované <0>DNS-over-QUIC (experimentálne);", "example_upstream_sdns": "<0>DNS pečiatky pre <1>DNSCrypt alebo <2>DNS-over-HTTPS rezolvery;", "example_upstream_tcp": "obyčajná DNS (cez TCP);", + "example_upstream_tcp_hostname": "štandardné DNS (cez TCP, hostname);", "all_lists_up_to_date_toast": "Všetky zoznamy sú už aktuálne", "updated_upstream_dns_toast": "Upstream servery boli úspešne uložené", "dns_test_ok_toast": "Špecifikované DNS servery pracujú korektne", @@ -259,10 +261,10 @@ "query_log_strict_search": "Na prísne vyhľadávanie použite dvojité úvodzovky", "query_log_retention_confirm": "Naozaj chcete zmeniť uchovávanie denníku dopytov? Ak znížite hodnotu intervalu, niektoré údaje sa stratia", "anonymize_client_ip": "Anonymizujte IP klienta", - "anonymize_client_ip_desc": "Neukladať úplnú IP adresu klienta do protokolov a štatistík.", + "anonymize_client_ip_desc": "Neukladať úplnú IP adresu klienta do protokolov a štatistík", "dns_config": "Konfigurácia DNS servera", "dns_cache_config": "Konfigurácia DNS cache", - "dns_cache_config_desc": "Tu môžete nakonfigurovať DNS cache.", + "dns_cache_config_desc": "Tu môžete nakonfigurovať DNS cache", "blocking_mode": "Spôsob blokovania", "default": "Predvolené", "nxdomain": "NXDOMAIN", @@ -285,7 +287,7 @@ "form_enter_rate_limit": "Zadajte rýchlostný limit", "rate_limit": "Rýchlostný limit", "edns_enable": "Povoliť klientsku podsiete EDNS", - "edns_cs_desc": "Posiela podsiete klientov na DNS servery.", + "edns_cs_desc": "Pridáva možnosť EDNS Client Subnet (ECS) do upstream požiadaviek a zapíše hodnoty odoslané klientmi do denníka dopytov.", "rate_limit_desc": "Počet požiadaviek za sekundu, ktoré môže jeden klient vykonať. Nastavenie na hodnotu 0 znamená neobmedzene.", "blocking_ipv4_desc": "IP adresa, ktorá sa má vrátiť v prípade blokovanej žiadosti A", "blocking_ipv6_desc": "IP adresa, ktorá sa má vrátiť v prípade blokovanej žiadosti AAAA", @@ -356,7 +358,7 @@ "open_dashboard": "Otvoriť riadiaci panel", "install_saved": "Úspešne uložené", "encryption_title": "Šifrovanie", - "encryption_desc": "Podpora šifrovania (HTTPS/TLS) pre webové rozhranie DNS aj administrátora.", + "encryption_desc": "Podpora šifrovania (HTTPS/TLS) pre webové rozhranie DNS aj administrátora", "encryption_config_saved": "Konfigurácia šifrovania uložená", "encryption_server": "Meno servera", "encryption_server_enter": "Zadajte meno Vašej domény", @@ -378,26 +380,26 @@ "encryption_key_input": "Skopírujte a prilepte sem svoj súkromný kľúč vo formáte PEM pre Váš certifikát.", "encryption_enable": "Zapnite šifrovanie (HTTPS, DNS-cez-HTTPS a DNS-cez-TLS)", "encryption_enable_desc": "Ak je šifrovanie zapnuté, AdGuard Home administrátorské rozhranie bude pracovať cez HTTPS a DNS server bude počúvať požiadavky cez DNS-cez-HTTPS a DNS-cez-TLS.", - "encryption_chain_valid": "Certifikačný reťazec je platný.", - "encryption_chain_invalid": "Certifikačný reťazec je neplatný.", - "encryption_key_valid": "Toto je platný {{type}} súkromný kľúč.", - "encryption_key_invalid": "Toto je neplatný {{type}} súkromný kľúč.", + "encryption_chain_valid": "Certifikačný reťazec je platný", + "encryption_chain_invalid": "Certifikačný reťazec je neplatný", + "encryption_key_valid": "Toto je platný {{type}} súkromný kľúč", + "encryption_key_invalid": "Toto je neplatný {{type}} súkromný kľúč", "encryption_subject": "Predmet", "encryption_issuer": "Vydavateľ", "encryption_hostnames": "Názvy hostiteľov", "encryption_reset": "Naozaj chcete obnoviť nastavenia šifrovania?", "topline_expiring_certificate": "Váš SSL certifikát čoskoro vyprší. Aktualizujte <0>Nastavenia šifrovania.", "topline_expired_certificate": "Váš SSL certifikát vypršal. Aktualizujte <0>Nastavenia šifrovania.", - "form_error_port_range": "Zadajte číslo portu v rozsahu 80-65535.", - "form_error_port_unsafe": "Toto nie je bezpečný port.", - "form_error_equal": "Nesmie byť rovnaká.", - "form_error_password": "Heslo sa nezhoduje.", + "form_error_port_range": "Zadajte číslo portu v rozsahu 80-65535", + "form_error_port_unsafe": "Nezabezpečený port", + "form_error_equal": "Nesmie byť rovnaká", + "form_error_password": "Heslo sa nezhoduje", "reset_settings": "Obnoviť nastavenia", "update_announcement": "AdGuard Home {{version}} je teraz k dispozícii! <0>Viac informácií nájdete tu.", "setup_guide": "Sprievodca nastavením", "dns_addresses": "DNS adresy", "dns_start": "Spúšťa sa DNS server", - "dns_status_error": "Chyba pri zisťovaní stavu DNS servera.", + "dns_status_error": "Chyba pri zisťovaní stavu DNS servera", "down": "Nadol", "fix": "Opraviť", "dns_providers": "Tu je <0>zoznam známych poskytovateľov DNS, z ktorého si vyberiete.", @@ -406,7 +408,7 @@ "manual_update": "Pre manuálnu aktualizáciu prosím sledujte tento postup.", "processing_update": "Čakajte prosím, AdGuard Home sa aktualizuje", "clients_title": "Permanentní klienti", - "clients_desc": "Nakonfigurujte trvalé záznamy klientov pre zariadenia pripojené k domovskej stránke AdGuard.", + "clients_desc": "Nakonfigurujte trvalé záznamy klientov pre zariadenia pripojené k AdGuard Home", "settings_global": "Globálne", "settings_custom": "Vlastné", "table_client": "Klient", @@ -433,7 +435,7 @@ "client_confirm_delete": "Naozaj chcete vymazať \"{{key}}\" klienta?", "list_confirm_delete": "Naozaj chcete vymazať tento zoznam?", "auto_clients_title": "Runtime klienti", - "auto_clients_desc": "Zariadenia, ktoré nie sú na zozname trvalých klientov, ktorí môžu stále používať AdGuard Home.", + "auto_clients_desc": "Zariadenia, ktoré nie sú na zozname trvalých klientov, ktorí môžu stále používať AdGuard Home", "access_title": "Nastavenia prístupu", "access_desc": "Tu môžete konfigurovať pravidlá prístupu pre server DNS AdGuard Home.", "access_allowed_title": "Povolení klienti", @@ -475,8 +477,8 @@ "dns_rewrites": "DNS prepisovanie", "form_domain": "Zadajte meno domény alebo zástupný znak", "form_answer": "Zadajte IP adresu alebo meno domény", - "form_error_domain_format": "Neplatný formát domény.", - "form_error_answer_format": "Neplatný formát odpovede.", + "form_error_domain_format": "Neplatný formát domény", + "form_error_answer_format": "Neplatný formát odpovede", "configure": "Konfigurovať", "main_settings": "Hlavné nastavenia", "block_services": "Blokovať vybrané služby", @@ -500,6 +502,7 @@ "interval_days": "{{count}} deň", "interval_days_plural": "{{count}} dní", "domain": "Doména", + "ecs": "ECS", "punycode": "Punycode", "answer": "Odpoveď", "filter_added_successfully": "Filter bol úspešne pridaný", @@ -507,7 +510,7 @@ "filter_updated": "Filter bol úspešne aktualizovaný", "statistics_configuration": "Konfigurácia štatistiky", "statistics_retention": "Štatistika za obdobie", - "statistics_retention_desc": "Ak znížite hodnotu intervalu, niektoré údaje sa stratia.", + "statistics_retention_desc": "Ak znížite hodnotu intervalu, niektoré údaje sa stratia", "statistics_clear": "Vynulovať štatistiku", "statistics_clear_confirm": "Naozaj chcete vynulovať štatistiku?", "statistics_retention_confirm": "Naozaj chcete zmeniť uchovávanie štatistík? Ak znížite hodnotu intervalu, niektoré údaje sa stratia", @@ -606,7 +609,7 @@ "enter_cache_ttl_max_override": "Zadať maximálne TTL (v sekundách)", "cache_ttl_min_override_desc": "Predĺži krátke hodnoty TTL (v sekundách) prijaté od servera typu upstream pri ukladaní odpovedí DNS do cache pamäte.", "cache_ttl_max_override_desc": "Nastaví maximálnu hodnotu TTL (v sekundách) pre záznamy v DNS cache pamäti.", - "ttl_cache_validation": "Minimálna hodnota TTL cache musí byť menšia alebo rovná maximálnej hodnote.", + "ttl_cache_validation": "Minimálna hodnota TTL cache musí byť menšia alebo rovná maximálnej hodnote", "cache_optimistic": "Optimistické nastavenie", "cache_optimistic_desc": "Nechajte AdGuard Home odpovedať z vyrovnávacej pamäte, aj keď už platnosť položiek skončila, a tiež sa pokúste ich obnoviť.", "filter_category_general": "Všeobecné", @@ -628,5 +631,5 @@ "parental_control": "Rodičovská kontrola", "safe_browsing": "Bezpečné prehliadanie", "served_from_cache": "{{value}} (prevzatá z cache pamäte)", - "form_error_password_length": "Heslo musí mať dĺžku aspoň {{value}} znakov." + "form_error_password_length": "Heslo musí mať dĺžku aspoň {{value}} znakov" } diff --git a/client/src/__locales/sl.json b/client/src/__locales/sl.json index 8df19766..8dffefc7 100644 --- a/client/src/__locales/sl.json +++ b/client/src/__locales/sl.json @@ -37,22 +37,22 @@ "dhcp_ipv6_settings": "Nastavitve DHCP IPv6", "form_error_required": "Zahtevano polje.", "form_error_ip4_format": "Neveljaven naslov IPv4.", - "form_error_ip4_range_start_format": "Neveljaven naslov IPv4 začetka razpona.", - "form_error_ip4_range_end_format": "Neveljaven naslov IPv4 konca razpona.", - "form_error_ip4_gateway_format": "Neveljaven naslov IPv4 prehoda.", - "form_error_ip6_format": "Neveljaven naslov IPv6.", - "form_error_ip_format": "Neveljaven naslov IP.", - "form_error_mac_format": "Neveljaven naslov MAC.", - "form_error_client_id_format": "ID odjemalca mora vsebovati samo številke, male črke in vezaje.", - "form_error_server_name": "Neveljavno ime strežnika.", - "form_error_subnet": "Podomrežje \"{{cidr}}\" ne vsebuje naslova IP \"{{ip}}\".", - "form_error_positive": "Mora biti večja od 0.", - "out_of_range_error": "Mora biti izven razpona \"{{start}}\"-\"{{end}}\".", - "lower_range_start_error": "Mora biti manjši od začetka razpona.", - "greater_range_start_error": "Mora biti večji od začetka razpona.", - "greater_range_end_error": "Mora biti večji od konca razpona.", - "subnet_error": "Naslovi morajo biti v enem podomrežju.", - "gateway_or_subnet_invalid": "Maska podomrežja ni veljavna.", + "form_error_ip4_range_start_format": "Neveljaven začetek razpona naslova IPv4", + "form_error_ip4_range_end_format": "Neveljaven konec razpona naslova IPv4", + "form_error_ip4_gateway_format": "Neveljaven naslov IPv4 prehoda", + "form_error_ip6_format": "Neveljaven naslov IPv6", + "form_error_ip_format": "Neveljaven naslov IP", + "form_error_mac_format": "Neveljaven naslov MAC", + "form_error_client_id_format": "ID odjemalca mora vsebovati samo številke, male črke in vezaje", + "form_error_server_name": "Neveljavno ime strežnika", + "form_error_subnet": "Podomrežje \"{{cidr}}\" ne vsebuje naslova IP \"{{ip}}\"", + "form_error_positive": "Mora biti večja od 0", + "out_of_range_error": "Mora biti izven razpona \"{{start}}\"-\"{{end}}\"", + "lower_range_start_error": "Mora biti manjši od začetka razpona", + "greater_range_start_error": "Mora biti večji od začetka razpona", + "greater_range_end_error": "Mora biti večji od konca razpona", + "subnet_error": "Naslovi morajo biti v enem podomrežju", + "gateway_or_subnet_invalid": "Maska podomrežja ni veljavna", "dhcp_form_gateway_input": "IP prehoda", "dhcp_form_subnet_input": "Maska podomrežja", "dhcp_form_range_title": "Razpon naslovov IP", @@ -67,7 +67,7 @@ "dhcp_table_hostname": "Ime gostitelja", "dhcp_table_expires": "Poteče", "dhcp_warning": "Če želite vseeno omogočiti strežnik DHCP, se prepričajte, da v vašem omrežju ni nobenega drugega aktivnega strežnika DHCP, saj lahko to prekine internetno povezljivost naprav v omrežju!", - "dhcp_error": "AdGuard Home ni mogel ugotoviti, ali je v omrežju še en aktivni strežnik DHCP.", + "dhcp_error": "AdGuard Home ni mogel ugotoviti, ali je v omrežju še en aktivni strežnik DHCP", "dhcp_static_ip_error": "Za uporabo strežnika DHCP mora biti nastavljen statični naslov IP. AdGuard Home ni uspel ugotoviti, ali je ta omrežni vmesnik nastavljen s statičnim naslovom IP. Prosimo, nastavite statični naslov IP ročno.", "dhcp_dynamic_ip_found": "Vaš sistem uporablja dinamično nastavitev naslova IP kartice <0>{{interfaceName}}. Za uporabo strežnika DHCP morate nastaviti statični naslov IP. Vaš trenutni naslov IP je<0>{{ipAddress}}. AdGuard Home bo samodejno nastavil ta naslov IP kot statičen, če pritisnete gumb 'Omogoči strežnik DHCP'.", "dhcp_lease_added": "Statičen najem \"{{key}}\" je uspešno dodan", @@ -196,7 +196,7 @@ "choose_allowlist": "Izberite sezname dovoljenih", "enter_valid_blocklist": "Vnesite veljaven URL naslov seznama nedovoljenih.", "enter_valid_allowlist": "Vnesite veljaven URL naslov seznama dovoljenih.", - "form_error_url_format": "Neveljaven format URL naslova.", + "form_error_url_format": "Neveljavna oblika URL naslova", "form_error_url_or_path_format": "Neveljaven URL ali absolutna pot seznama", "custom_filter_rules": "Pravila filtriranja po meri", "custom_filter_rules_hint": "V vrstico vnesite eno pravilo. Uporabite lahko pravila zaviranja oglasov ali sintakso gostiteljskih datotek.", @@ -210,11 +210,13 @@ "example_comment_hash": "# Tudi komentar.", "example_regex_meaning": "onemogoča dostop do domen, ki se ujemajo z določenim regularnim izrazom.", "example_upstream_regular": "redni DNS (nad UDP);", + "example_upstream_udp": "redni DNS (nad UDP, ime gostitelja);", "example_upstream_dot": "šifriran <0>DNS-prek-TLS;", "example_upstream_doh": "šifriran <0>DNS-prek-HTTPS;", "example_upstream_doq": "šifriran <0>DNS-prek-QUIC (eksperimentalno);", "example_upstream_sdns": "lahko uporabite <0>DNS Žige za reševalce <1>DNSCrypt ali <2>DNS-prek-HTTPS;", "example_upstream_tcp": "redni DNS (nad TCP);", + "example_upstream_tcp_hostname": "redni DNS (nad TCP, ime gostitelja);", "all_lists_up_to_date_toast": "Vsi seznami so že posodobljeni", "updated_upstream_dns_toast": "Gorvodni trežniki so uspešno shranjeni", "dns_test_ok_toast": "Navedeni strežniki DNS delujejo pravilno", @@ -259,10 +261,10 @@ "query_log_strict_search": "Za strogo iskanje uporabite dvojne narekovaje", "query_log_retention_confirm": "Ali ste prepričani, da želite spremeniti zadrževanje dnevnika poizvedb? Če zmanjšate vrednost intervala, bodo nekateri podatki izgubljeni", "anonymize_client_ip": "Anonimiziraj odjemalca IP", - "anonymize_client_ip_desc": "Ne shrani celotnega naslova IP odjemalca v dnevnikih ali statistiki.", + "anonymize_client_ip_desc": "Ne shrani celotnega naslova IP odjemalca v dnevnikih ali statistiki", "dns_config": "Konfiguracija strežnika DNS", "dns_cache_config": "Konfiguracija strežnika DNS", - "dns_cache_config_desc": "Tu lahko nastavite predpomnilnik DNS.", + "dns_cache_config_desc": "Tu lahko nastavite predpomnilnik DNS", "blocking_mode": "Način zaviranja", "default": "Privzeto", "nxdomain": "NXDOMAIN", @@ -285,7 +287,7 @@ "form_enter_rate_limit": "Vnesite omejitev hitrosti", "rate_limit": "Omejitev hitrosti", "edns_enable": "Omogoči odjemalsko podomrežje EDNS", - "edns_cs_desc": "Pošlji podomrežja odjemalcev strežnikom DNS.", + "edns_cs_desc": "Dodaj možnost podomrežja odjemalca EDNS (ECS) zahtevam v gorvodnem toku in zabeleži vrednosti, ki jih pošljejo odjemalci, v dnevnik poizvedb.", "rate_limit_desc": "Dovoljeno število zahtev na sekundo na odjemalca. Nastavitev na 0 pomeni brez omejitve.", "blocking_ipv4_desc": "IP naslov, ki mora biti vrnjen za onemogočeno zahtevo A", "blocking_ipv6_desc": "IP naslov, ki mora biti vrnjen za onemogočeno zahtevo AAAA", @@ -309,7 +311,7 @@ "install_settings_listen": "Poslušaj vmesnik", "install_settings_port": "Vrata", "install_settings_interface_link": "Vaš AdGuard Home Skrbniški spletni vmesnik bo na voljo na naslednjih naslovih:", - "form_error_port": "Vnesite veljavno številko vrat.", + "form_error_port": "Vnesite veljavno številko vrat", "install_settings_dns": "DNS strežnik", "install_settings_dns_desc": "Vaše naprave ali usmerjevalnik boste morali konfigurirati za uporabo strežnika DNS na naslednjih naslovih:", "install_settings_all_interfaces": "Vsi vmesniki", @@ -356,7 +358,7 @@ "open_dashboard": "Odpri nadzorno ploščo", "install_saved": "Shranjeno uspešno", "encryption_title": "Šifriranje", - "encryption_desc": "Podpora za šifriranje (HTTPS/TLS) za DNS in skrbniški spletni vmesnik.", + "encryption_desc": "Podpora za šifriranje (HTTPS/TLS) za DNS in skrbniški spletni vmesnik", "encryption_config_saved": "Nastavitve šifriranja so shranjene", "encryption_server": "Ime strežnika", "encryption_server_enter": "Vnesite ime vaše domene", @@ -378,26 +380,26 @@ "encryption_key_input": "Tukaj kopirajte/prilepite PEM-kodiran zasebni ključ za vaše digitalno potrdilo.", "encryption_enable": "Omogoči šifriranje (HTTPS, DNS-prek-HTTPS in DNS-prek-TLS)", "encryption_enable_desc": "Če je omogočeno šifriranje, bo skrbniški vmesnik AdGuard Home deloval prek HTTPS, strežnik DNS pa bo poslušal zahteve prek DNS-prek-HTTPS in DNS-prek-TLS.", - "encryption_chain_valid": "Veriga digitalih potrdil je veljavna.", - "encryption_chain_invalid": "Veriga digitalih potrdil ni veljavna.", - "encryption_key_valid": "To je veljaven zasebni ključ {{type}}.", - "encryption_key_invalid": "To je neveljaven zasebni ključ {{type}}.", + "encryption_chain_valid": "Veriga digitalih potrdil je veljavna", + "encryption_chain_invalid": "Veriga digitalih potrdil ni veljavna", + "encryption_key_valid": "To je veljaven zasebni ključ {{type}}", + "encryption_key_invalid": "To je neveljaven zasebni ključ {{type}}", "encryption_subject": "Predmet", "encryption_issuer": "Izdajatelj", "encryption_hostnames": "Imena gostiteljev", "encryption_reset": "Ali ste prepričani, da želite ponastaviti nastavitve šifriranja?", "topline_expiring_certificate": "Vaš e digitalno potrdilo SSL bo kmalu poteklol. Posodobite <0>Nastavitve šifriranja.", "topline_expired_certificate": "Vaše digitalno potrdilo SSL je poteklo. Posodobi <0>Nastavitve šifriranja.", - "form_error_port_range": "Vnesite številko vrat v razponu med 80-65535.", - "form_error_port_unsafe": "To so nevarna vrata.", - "form_error_equal": "Ne sme biti enako.", - "form_error_password": "Geslo se ne ujema.", + "form_error_port_range": "Vnesite številko vrat v razponu med 80-65535", + "form_error_port_unsafe": "Nevarna vrata", + "form_error_equal": "Ne sme biti enako", + "form_error_password": "Geslo se ne ujema", "reset_settings": "Ponastavi nastavitve", "update_announcement": "Zdaj je na voljo AdGuard Home {{version}}! <0>Klinite tukaj za več informacij.", "setup_guide": "Navodila za nastavitev", "dns_addresses": "DNS naslovi", "dns_start": "Zaganja se strežnik DNS", - "dns_status_error": "Napaka pri preverjanju stanja strežnika DNS.", + "dns_status_error": "Napaka pri preverjanju stanja strežnika DNS", "down": "Navzdol", "fix": "Popravi", "dns_providers": "Tukaj je <0>seznam znanih ponudnikov DNS, med katerimi lahko izbirate.", @@ -406,7 +408,7 @@ "manual_update": "Za ročno posodobitev sledite tem korakom.", "processing_update": "Prosimo, počakajte. AdGuard Home se posodablja!", "clients_title": "Trajni odjemalci", - "clients_desc": "Nastavite trajne zapise odjemalca za povezane naprave z AdGuard Home.", + "clients_desc": "Nastavite trajne zapise odjemalca za povezane naprave z AdGuard Home", "settings_global": "Splošno", "settings_custom": "Po meri", "table_client": "Odjemalec", @@ -433,9 +435,9 @@ "client_confirm_delete": "Ali ste prepričani, da želite izbrisati odjemalca \"{{key}}\"?", "list_confirm_delete": "Ali ste prepričani, da želite izbrisati ta seznam?", "auto_clients_title": "Odjemalci izvajanja", - "auto_clients_desc": "Naprave, ki niso na seznamu trajnih odjemalcev, ki morda še vedno uporabljajo AdGuard Home.", + "auto_clients_desc": "Naprave, ki niso na seznamu trajnih odjemalcev, ki morda še vedno uporabljajo AdGuard Home", "access_title": "Nastavitve dostopa", - "access_desc": "Tukaj lahko nastavite pravila dostopa strežnika DNS AdGuard Home.", + "access_desc": "Tukaj lahko nastavite pravila dostopa strežnika DNS AdGuard Home", "access_allowed_title": "Dovoljeni odjemalci", "access_allowed_desc": "Seznam CIDR-jev, naslovov IP ali ID-jev odjemalcev. Če ta seznam vsebuje vnose, bo AdGuard Home sprejel zahteve samo teh odjemalcev.", "access_disallowed_title": "Zavrnjeni odjemalci", @@ -475,8 +477,8 @@ "dns_rewrites": "Prepisovanja NDS", "form_domain": "Vnesite domeno ali nadomestni znak", "form_answer": "Vnesite IP naslov ali ime domene", - "form_error_domain_format": "Neveljavna oblika domene.", - "form_error_answer_format": "Neveljavna oblika odgovora.", + "form_error_domain_format": "Neveljavna oblika domene", + "form_error_answer_format": "Neveljavna oblika odgovora", "configure": "Konfiguriraj", "main_settings": "Glavne nastavitve", "block_services": "Onemogoči določene storitve", @@ -500,6 +502,7 @@ "interval_days": "{{count}} dan", "interval_days_plural": "{{count}} dni", "domain": "Domena", + "ecs": "ECS", "punycode": "Slaba koda", "answer": "Odgovor", "filter_added_successfully": "Seznam je bil uspešno dodan", @@ -507,7 +510,7 @@ "filter_updated": "Filter je bil uspešno posodobljen", "statistics_configuration": "Nastavitve statistike", "statistics_retention": "Statistika zadrževanja", - "statistics_retention_desc": "Če zmanjšate vrednost intervala, bodo nekateri podatki izgubljeni.", + "statistics_retention_desc": "Če zmanjšate vrednost intervala, bodo nekateri podatki izgubljeni", "statistics_clear": " Počisti statistiko", "statistics_clear_confirm": "Ali ste prepričani, da želite počistiti statistiko?", "statistics_retention_confirm": "Ali ste prepričani, da želite spremeniti zadrževanje statistike? Če zmanjšate vrednost intervala, bodo nekateri podatki izgubljeni", @@ -606,7 +609,7 @@ "enter_cache_ttl_max_override": "Vnesite največji TTL (v sekundah)", "cache_ttl_min_override_desc": "Podaljšajte kratke življenjske vrednosti (sekunde), prejete od gorvodnega strežnika pri predpomnjenju odgovorov DNS.", "cache_ttl_max_override_desc": "Nastavite največjo vrednost življenjske dobe (sekunde) za vnose v predpomnilniku DNS.", - "ttl_cache_validation": "Najmanjša preglasitev TTL predpomnilnika mora biti manjša ali enaka najvišji.", + "ttl_cache_validation": "Najmanjša preglasitev TTL predpomnilnika mora biti manjša ali enaka najvišji", "cache_optimistic": "Optimistično predpomnjenje", "cache_optimistic_desc": "Poskrbi, da se AdGuard Home odzove iz predpomnilnika, tudi ko vnosi potečejo, in jih tudi poskusi osvežiti.", "filter_category_general": "Splošno", @@ -628,5 +631,5 @@ "parental_control": "Starševski nadzor", "safe_browsing": "Varno brskanje", "served_from_cache": "{{value}} (postreženo iz predpomnilnika)", - "form_error_password_length": "Geslo mora vsebovati najmanj {{value}} znakov." + "form_error_password_length": "Geslo mora vsebovati najmanj {{value}} znakov" } diff --git a/client/src/__locales/sr-cs.json b/client/src/__locales/sr-cs.json index 3c6a19f2..1fff431a 100644 --- a/client/src/__locales/sr-cs.json +++ b/client/src/__locales/sr-cs.json @@ -1,10 +1,24 @@ { "client_settings": "Postavke klijenta", + "example_upstream_reserved": "upstream <0>za određene domene;", + "example_upstream_comment": "komentar.", + "upstream_parallel": "Koristite paralelne upite da biste ubrzali rešavanje tako što ćete istovremeno ispitati sve uzvodne servere.", "parallel_requests": "Paralelni zahtevi", "load_balancing": "Load-balancing", + "load_balancing_desc": "Koristi jedan upstream server. AdGuard Home koristi najnoviji nasumični algoritam da izabere server tako da se najbrži server češće koristi.", "bootstrap_dns": "Bootstrap DNS serveri", "bootstrap_dns_desc": "Bootstrap DNS serveri se koriste da reše IP adrese od DoH/DoT razrešivača koje ste odredili kao upstream.", + "local_ptr_title": "Private reverse DNS serveri", + "local_ptr_desc": "DNS serveri koje AdGuard Home koristi za lokalne PTR upite. Ovi serveri se koriste za rešavanje imena domaćina klijenata sa privatnim IP adresama, na primer \"192.168.12.34\", koristeći obrnuti DNS. Ako nije podešen, AdGuard Home koristi adrese podrazumevanih DNS razrešivača vašeg OS-a osim adresa samog AdGuard Home-a.", + "local_ptr_default_resolver": "Podrazumevano, AdGuard Home koristi sledeće obrnute DNS razrešivače: {{ip}}.", + "local_ptr_no_default_resolver": "AdGuard Home ne može da odredi pogodne privatne obrnute DNS razrešivače za ovaj sistem.", + "local_ptr_placeholder": "Unesite jednu adresu servera po redu", + "resolve_clients_title": "Uključi obrnuto razrešavanje klijentskih IP adresa", + "resolve_clients_desc": "Obrnuto razrešite IP adrese klijenata u njihova imena domaćina slanjem PTR upita odgovarajućim razrešivačima (privatni DNS serveri za lokalne klijente, uzvodni serveri za klijente sa javnim IP adresama).", + "use_private_ptr_resolvers_title": "Koristi privatne obrnute razrešivače", + "use_private_ptr_resolvers_desc": "Izvršavanje obrnutih DNS izgleda za lokalno servirane adrese pomoću ovih uzvodnih servera. Ako je onemogućen, AdGuard Home odgovara sa NXDOMAIN na sve takve PTR zahteve osim klijenata poznatih iz DHCP- a, /etc/hosts itd.", "check_dhcp_servers": "Proveri DHCP servere", + "save_config": "Sačuvaj konfiguraciju", "enabled_dhcp": "DHCP server uključen", "disabled_dhcp": "DHCP server isključen", "unavailable_dhcp": "DHCP nije dostupan", @@ -13,19 +27,32 @@ "dhcp_description": "Ako vaš ruter nema DHCP postavke, možete koristiti AdGuard' ugrađen DHCP server.", "dhcp_enable": "Uključi DHCP server", "dhcp_disable": "Isključi DHCP server", + "dhcp_not_found": "Bezbedno je da uključite ugrađeni DHCP server. Nismo pronašli nijedan aktivan DHCP server na mreži. međutim, ohrabrujemo vas da to ponovo proverite ručno, jer naš automatski test trenutno nije 100% pouzdan.", "dhcp_found": "Pronađen je aktivan DHCP server na mreži. Nije bezbedno da uključite ugrađeni DHCP server.", "dhcp_leases": "DHCP pozajmljivanja", "dhcp_static_leases": "DHCP statička pozajmljivanja", "dhcp_leases_not_found": "DHCP pozajmljivanja nisu pronađena", + "dhcp_config_saved": "Sačuvaj DHCP konfiguraciju servera", "dhcp_ipv4_settings": "DHCP IPv4 postavke", "dhcp_ipv6_settings": "DHCP IPv6 postavke", "form_error_required": "Obavezno polje", - "form_error_ip4_format": "Nevažeći IPv4 format", - "form_error_ip6_format": "Nevažeći IPv6 format", - "form_error_ip_format": "Pogrešna IP adresa", - "form_error_mac_format": "Nevažeći MAC format", - "form_error_client_id_format": "Nevažeći format klijenta", + "form_error_ip4_format": "Nevažeća IPv4 adresa", + "form_error_ip4_range_start_format": "Nevažeća IPv4 addresa početnog opsega", + "form_error_ip4_range_end_format": "Nevažeća IPv4 addresa završnog opsega", + "form_error_ip4_gateway_format": "Nevažeća IPv4 addresa prozala", + "form_error_ip6_format": "Nevažeća IPv6 adresa", + "form_error_ip_format": "Nevažeća IP adresa", + "form_error_mac_format": "Nevažeća MAC adresa", + "form_error_client_id_format": "ClientID mora da sadrži samo brojeve, malim slovima i crticama", + "form_error_server_name": "Nevažeće ime servera", + "form_error_subnet": "Subnet \"{{cidr}}\" ne sadrži IP adresu \"{{ip}}\"", "form_error_positive": "Mora biti veće od 0", + "out_of_range_error": "Mora biti izvan opsega \"{{start}}\"-\"{{end}}\"", + "lower_range_start_error": "Mora biti manje od početnog opsega", + "greater_range_start_error": "Mora biti veće od početnog opsega", + "greater_range_end_error": "Mora biti veće od završnog opsega", + "subnet_error": "Asrese moraju biti u jednoj subnet", + "gateway_or_subnet_invalid": "Subnet mask nevažeća", "dhcp_form_gateway_input": "IP mrežnog prolaza", "dhcp_form_subnet_input": "Subnet mask", "dhcp_form_range_title": "Opseg IP adresa", @@ -39,11 +66,19 @@ "ip": "IP", "dhcp_table_hostname": "Ime hosta", "dhcp_table_expires": "Ističe", + "dhcp_warning": "Ako ipak želite da omogućite DHCP server, uverite se da u mreži ne postoji drugi aktivni DHCP server, jer to može da prekine Internet vezu za uređaje na mreži!", + "dhcp_error": "AdGuard Home nije mogao da utvrdi da li postoji još jedan aktivni DHCP server na mreži", + "dhcp_static_ip_error": "Da biste koristili DHCP server, morate postaviti statičnu IP adresu. AdGuard Home nije uspeo da utvrdi da li je ovaj mrežni interfejs konfigurisan pomoću statične IP adrese. Postavite statičnu IP adresu ručno.", + "dhcp_dynamic_ip_found": "Vaš sistem koristi dinamičku IP adresu za okruženje <0>{{interfaceName}}. Kako biste koristili DHCP server, morate podesiti statičku IP adresu. Vaša trenutna IP adresa je <0>{{ipAddress}}. Automatski ćemo podesiti ovu IP adresu kao statičku ako pritisnete Uključi DHCP dugme.", "dhcp_lease_added": "Statičko iznajmljivanje \"{{key}}\" uspešno dodato", "dhcp_lease_deleted": "Statičko iznajmljivanje lease \"{{key}}\" uspešno izbrisano", "dhcp_new_static_lease": "Novo statičko iznajmljivanje", "dhcp_static_leases_not_found": "Nisu pronađena statička DHCP iznajmljivanja", "dhcp_add_static_lease": "Dodaj statičko iznajmljivanje", + "dhcp_reset_leases": "Resetuj sva unajmljivanja", + "dhcp_reset_leases_confirm": "Jeste li sigurni da želite da resetujete sva pozajmljivanja?", + "dhcp_reset_leases_success": "DHCP unajmljivanja uspešno resetovana", + "dhcp_reset": "Jeste li sigurni da želite da resetujete DHCP konfiguraciju?", "country": "Zemlja", "city": "Grad", "delete_confirm": "Jeste li sigurni da želite da izbrišete \"{{key}}\"?", @@ -84,13 +119,22 @@ "for_last_24_hours": "u poslednja 24 časa", "for_last_days": "u poslednjih {{count}} dana", "for_last_days_plural": "u poslednjih {{count}} dana", + "stats_disabled": "Statistika je isključena. Možete ga uključiti sa stranice <0>sa postavkama.", + "stats_disabled_short": "Statistika je isključena", "no_domains_found": "Domeni nisu pronađeni", "requests_count": "Broj zahteva", "top_blocked_domains": "Najčešće blokirani domeni", "top_clients": "Najčešći klijenti", "no_clients_found": "Nema pronađenih klijenata", "general_statistics": "Opšte statistike", + "number_of_dns_query_days": "Broj obrađenih DNS unosa u poslednjih {{count}} dan", + "number_of_dns_query_days_plural": "Broj obrađenih DNS unosa u poslednjih {{count}} dana", + "number_of_dns_query_24_hours": "Broj obrađenih DNS unosa u poslednja 24 časa", + "number_of_dns_query_blocked_24_hours": "Broj DNS zahteva blokiranih od filtera blokatora reklama i blok liste hostova", + "number_of_dns_query_blocked_24_hours_by_sec": "Broj DNS zahteva blokiranih od AdGuard-ovog podprograma za bezbedno pregledanje", + "number_of_dns_query_blocked_24_hours_adult": "Broj blokiranih sajtova za odrasle", "enforced_save_search": "Nametni sigurno pretraživanje", + "number_of_dns_query_to_safe_search": "Broj DNS zahteva ka pretraživačima za koje je nametnuto sigurno pretraživanje", "average_processing_time": "Prosečno vreme obrade", "average_processing_time_hint": "Prosečno vreme u milisekundama za obradu DNS zahteva", "block_domain_use_filters_and_hosts": "Blokiraj domene koristeći filtere i hosts datoteke", @@ -100,6 +144,7 @@ "use_adguard_parental": "Koristi AdGuard-ovu uslugu roditeljske kontrole", "use_adguard_parental_hint": "AdGuard Home će proveriti da li domen sadrži sadržaj za odrasle. Koristi se isti privatni prijateljski API kao i kod usluge bezbednog pregledanja.", "enforce_safe_search": "Nametni sigurno pretraživanje", + "enforce_save_search_hint": "AdGuard Home može nametnuti sigurno pretraživanje u sledećim pretraživačima: Google, Youtube, Bing, DuckDuckGo i Yandex.", "no_servers_specified": "Serveri nisu određeni", "general_settings": "Opšte postavke", "dns_settings": "DNS postavke", @@ -111,6 +156,7 @@ "encryption_settings": "Postavke šifrovanja", "dhcp_settings": "DHCP postavke", "upstream_dns": "Upstream DNS serveri", + "upstream_dns_help": "Unesite adrese servera, jednu po redu. Saznajte više o konfigurisanju upstream DNS servera.", "upstream_dns_configured_in_file": "Konfiguriši u {{path}}", "test_upstream_btn": "Testiraj upstreams", "upstreams": "Upstreams", @@ -150,25 +196,29 @@ "choose_allowlist": "Izaberite liste dozvoljenih", "enter_valid_blocklist": "Unesite važeći URL do blok liste.", "enter_valid_allowlist": "Unesite važeći URL do liste dozvoljenih.", - "form_error_url_format": "Nevažeći format Url-a", + "form_error_url_format": "Nevažeći format URL-a", "form_error_url_or_path_format": "URL ili apsolutna putanja do liste nije valjana", "custom_filter_rules": "Prilagođena pravila filtriranja", "custom_filter_rules_hint": "Unesite jedno pravilo po redu. Možete koristiti pravila blokatora reklama ili sintaksu hosts datoteke.", + "system_host_files": "System hosts datoteke", "examples_title": "Primeri", - "example_meaning_filter_block": "blokirajte pristup ka domenu primer.org i svim njegovim poddomenima", - "example_meaning_filter_whitelist": "dozvolite pristup ka domenu primer.org i svim njegovim poddomenima", - "example_meaning_host_block": "AdGuard Home će sada vratiti adresu 127.0.0.1 za domen primer.org (ali ne i za njegove poddomene).", - "example_comment": "! Ovde ide komentar", - "example_comment_meaning": "samo komentar", - "example_comment_hash": "# Takođe komentar", - "example_regex_meaning": "blokiranje pristupa domenima koji odgovaraju određenom uobičajenom izrazu", - "example_upstream_regular": "uobičajeno DNS (preko UDP)", - "example_upstream_dot": "šifrovano <0>DNS-over-TLS", - "example_upstream_doh": "šifrovano <0>DNS-over-HTTPS", - "example_upstream_doq": "šifrovano <0>DNS-over-QUIC", - "example_upstream_sdns": "možete koristiti <0>DNS brojeve za <1>DNSCrypt ili <2>DNS-over-HTTPS", - "example_upstream_tcp": "uobičajeni DNS (preko TCP)", + "example_meaning_filter_block": "blokirajte pristup ka primer.org i svim njegovim poddomenima;", + "example_meaning_filter_whitelist": "dozvolite pristup ka primer.org i svim njegovim poddomenima;", + "example_meaning_host_block": "vratiti adresu 127.0.0.1 za primer.org (ali ne i za njegove poddomene);", + "example_comment": "! Ovde ide komentar.", + "example_comment_meaning": "samo komentar;", + "example_comment_hash": "# Takođe komentar.", + "example_regex_meaning": "blokiranje pristupa domenima koji odgovaraju određenom uobičajenom izrazu.", + "example_upstream_regular": "uobičajeno DNS (preko UDP);", + "example_upstream_udp": "uobičajen DNS (preko UDP, imena domaćina);", + "example_upstream_dot": "šifrovano <0>DNS-over-TLS;", + "example_upstream_doh": "šifrovano <0>DNS-over-HTTPS;", + "example_upstream_doq": "šifrovano <0>DNS-over-QUIC (eksperimentalno);", + "example_upstream_sdns": "<0>DNS brojeve za <1>DNSCrypt ili <2>DNS-over-HTTPS razrešivače;", + "example_upstream_tcp": "uobičajeni DNS (preko TCP);", + "example_upstream_tcp_hostname": "uobičajen DNS (preko TCP, imena domaćina);", "all_lists_up_to_date_toast": "Sve liste su već ažurirane", + "updated_upstream_dns_toast": "Upstream serveri su uspešno sačuvani", "dns_test_ok_toast": "Dati DNS serveri rade ispravno", "dns_test_not_ok_toast": "Server \"{{key}}\": se ne može koristiti. Proverite da li ste ga ispravno uneli", "unblock": "Odblokiraj", @@ -195,7 +245,7 @@ "loading_table_status": "Učitavanje...", "page_table_footer_text": "Stranica", "rows_table_footer_text": "redovi", - "updated_custom_filtering_toast": "Ažurirana prilagođena pravila filtriranja", + "updated_custom_filtering_toast": "Prilagođena pravila su uspešno sačuvana", "rule_removed_from_custom_filtering_toast": "Pravilo uklonjeno iz prilagođenih pravila filtriranja: {{rule}}", "rule_added_to_custom_filtering_toast": "Pravilo dodato u prilagođena pravila filtriranja: {{rule}}", "query_log_response_status": "Stanje: {{value}}", @@ -227,13 +277,18 @@ "dns_over_https": "DNS-over-HTTPS", "dns_over_tls": "DNS-over-TLS", "dns_over_quic": "DNS-over-QUIC", + "client_id": "ClientID", + "client_id_placeholder": "Unesite ClientID", + "client_id_desc": "Različiti klijenti mogu biti prepoznati posebnim ClientID. Ovde možete saznati više o tome kako da prepoznate klijente.", "download_mobileconfig_doh": "Preuzimanja", "download_mobileconfig_dot": "Preuzmi .mobileconfig za DNS-over-TLS", + "download_mobileconfig": "Preuzmi konfiguracionu datoteku", "plain_dns": "Plain DNS", "form_enter_rate_limit": "Unesite ograničenje brzine", "rate_limit": "Ograničenje brzine", "edns_enable": "Uključi EDNS Client Subnet", - "edns_cs_desc": "Ako je uključeno, AdGuard Home će slati klijente na DNS servere.", + "edns_cs_desc": "Dodajte opciju podmreži EDNS klijenta (ECS) uzvodnim zahtevima i evidentirajte vrednosti koje klijenti šalju u evidenciji upita.", + "rate_limit_desc": "Broj zahteva u sekundi dozvoljen po klijentu. Postavljanje na 0 znači da nema ograničenja.", "blocking_ipv4_desc": "IP adresa koja će biti vraćena za blokirane zahteve", "blocking_ipv6_desc": "IP adresa koja će biti vraćena za blokirane AAAA zahteve", "blocking_mode_default": "Podrazumevano: Odgovara sa REFUSED kada je blokirano od Adblock-style pravila; odgovara sa IP adresom koja je određena u pravilu kada je blokiran od /etc/hosts-style pravila", @@ -256,6 +311,7 @@ "install_settings_listen": "Okruženje slušanja", "install_settings_port": "Port", "install_settings_interface_link": "Vaše AdGuard Home administratorsko web okruženje će biti dostupno na sledećim adresama:", + "form_error_port": "Unesite važeći broj porta", "install_settings_dns": "DNS server", "install_settings_dns_desc": "Potrebno je da konfigurišete vaše uređaje ili ruter da koristi DNS server sa sledećim adresama:", "install_settings_all_interfaces": "Sva okruženja", @@ -274,14 +330,16 @@ "install_devices_router": "Ruter", "install_devices_router_desc": "Ovo postavljanje će automatski pokriti sve uređaje koji su povezani na vaš kućni ruter pa nećete morati da konfigurišete svaki uređaj posebno.", "install_devices_address": "AdGuard Home DNS server sluša na sledećim adresama", + "install_devices_router_list_1": "Otvorite željene postavke mrežne skretnice. Obično mu možete pristupiti iz pregledača putem URL adrese, kao što su http://192.168.0.1/ ili http://192.168.1.1/. Od vas će možda biti zatraženo da unesete lozinku. Ako je se ne sećate, često možete da poništite lozinku pritiskom na dugme na samoj mrežnoj skretnici, ali imajte na umu da ćete, ako se ova procedura izabere, verovatno izgubiti celu konfiguraciju rutera. Ako ruter zahteva aplikaciju za podešavanje, instalirajte aplikaciju na telefonu ili računaru i koristite je za pristup postavkama rutera.", "install_devices_router_list_2": "Pronađite DHCP ili DNS postavke. Potražite DNS slova pored polja koje dozvoljava dve ili tri skupine brojeva, a svaka može da sadrži četiri grupe od jedne do tri cifre.", "install_devices_router_list_3": "Tamo unesite adrese AdGuard home servera.", + "install_devices_router_list_4": "Na nekim tipovima mrežnih skretnica nije moguće podesiti prilagođeni DNS server. U tom slučaju, podešavanje AdGuard Home-a kao <0>DHCP servera može da pomogne. U suprotnom, trebalo bi da proverite uputstvo mrežne skretnice o prilagođavanju DNS servera na određenom modelu rutera.", "install_devices_windows_list_1": "Otvorite kontrolnu tablu iz startnog menija ili kroz Windows pretragu.", "install_devices_windows_list_2": "Otvorite kategoriju mreža i internet a onda otiđite u centar za mrežu i deljenje.", - "install_devices_windows_list_3": "Na levoj strani ekrana pronađite Promena postavke adaptera i kliknite tu.", - "install_devices_windows_list_4": "Izaberite vašu aktivnu vezu, desnim tasterom kliknite na nju i izaberite Svojstva.", - "install_devices_windows_list_5": "Na listi pronađite Internet Protokol verzija 4 (TCP/IP), izaberite ga pa kliknite ponovo na Svojstva.", - "install_devices_windows_list_6": "Izaberite Koristi sledeće adrese DNS servera pa unesite vaše adrese AdGuard Home servera.", + "install_devices_windows_list_3": "Na levoj tabli kliknite na dugme \"Promeni postavke adaptera\".", + "install_devices_windows_list_4": "Kliknite desnim tasterom miša na aktivnu vezu i izaberite stavku Svojstva.", + "install_devices_windows_list_5": "Na listi pronađite Internet Protokol verzija 4 (TCP/IP) (ili, za IPv6, \"Internet Protocol Version 6 (TCP/IPv6)\"), izaberite ga pa kliknite ponovo na Svojstva.", + "install_devices_windows_list_6": "Izaberite \"Koristi sledeće adrese DNS servera\" pa unesite vaše adrese AdGuard Home servera.", "install_devices_macos_list_1": "Kliknite na ikonicu jabuke pa otiđite na postavke sistema.", "install_devices_macos_list_2": "Kliknite na mrežu.", "install_devices_macos_list_3": "Izaberite prvu vezu sa liste pa kliknite na više opcija.", @@ -300,16 +358,18 @@ "open_dashboard": "Otvori kontrolnu tablu", "install_saved": "Uspešno sačuvano", "encryption_title": "Šifrovanje", - "encryption_desc": "Šifrovanje (HTTPS/TLS) podrška za oba DNS i administratorsko okruženje", + "encryption_desc": "Šifrovanje (HTTPS/QUIC/TLS) podrška za oba DNS i administratorsko okruženje", + "encryption_config_saved": "Konfiguracija šifrovanja je sačuvana", "encryption_server": "Ime servera", "encryption_server_enter": "Unesite vaše ime domena", + "encryption_server_desc": "Da biste koristili HTTPS, potrebno je da unesete ime servera koje se podudara sa SSL certifikatom ili džoker certifikatom. Ako polje nije postavljeno, prihvatiće TLS veze za bilo koji domen.", "encryption_redirect": "Automatski preusmeri na HTTPS", "encryption_redirect_desc": "Ako je označeno, AdGuard Home će vas automatski preusmeravati sa HTTP na HTTPS adrese.", "encryption_https": "HTTPS port", "encryption_https_desc": "Ako je HTTPS port konfigurisan, AdGuard Home administratorskom okruženju će se moći pristupati preko HTTPS, a to će takođe omogućiti DNS-over-HTTPS na '/dns-query' lokaciji.", "encryption_dot": "DNS-over-TLS port", "encryption_dot_desc": "Ako je ovaj port konfigurisan, AdGuard Home će pokretati DNS-over-TLS server na ovom portu.", - "encryption_doq": "DNS-over-QUIC port", + "encryption_doq": "DNS-over-QUIC port (eksperimentalno)", "encryption_doq_desc": "Ako je ovaj port konfigurisan, AdGuard Home će pokrenuti DNS-over-QUIC server na tom portu. To je eksperiment i možda neće biti stabilno. Takođe, u ovom trenutku ne postoji puno klijenata koji ovo podržavaju.", "encryption_certificates": "Sertifikati", "encryption_certificates_desc": "Da biste koristili šifrovanje, morate obezbediti važeći lanac SSL sertifikata za vaš domen. Besplatan sertifikat možete nabaviti na <0>{{link}} ili ga možete kupiti od nekog od pouzdanih izdavalaca sertifikata.", @@ -330,21 +390,25 @@ "encryption_reset": "Jeste li sigurni da želite dda resetujete postavke šifrovanja?", "topline_expiring_certificate": "Vaš SSL sertifikat uskoro ističe. Ažurirajte <0>postavke šifrovanja.", "topline_expired_certificate": "Vaš SSL sertifikat je istekao. Ažurirajte <0>postavke šifrovanja.", - "form_error_port_unsafe": "Ovo nije siguran port", + "form_error_port_range": "Unesite vrednost porta u opsegu od 80-65535", + "form_error_port_unsafe": "Nije siguran port", + "form_error_equal": "Ne smije biti jednako", "form_error_password": "Lozinke se ne podudaraju", "reset_settings": "Vrati postavke na podrazumevano", "update_announcement": "AdGuard Home {{version}} je sada dostupan! <0>Kliknite ovde za više informacija.", + "setup_guide": "Uputstvo za podešavanje", "dns_addresses": "DNS adrese", "dns_start": "DNS server se pokreće", - "dns_status_error": "Greška prilikom pribavljanja stanja DNS servera", + "dns_status_error": "Greška pri proveri statusa DNS servera", "down": "Dole", "fix": "Popravi", "dns_providers": "Ovo je a <0>lista poznatih DNS dobavljača sa koje možete da izaberete.", "update_now": "Ažuriraj sada", "update_failed": "Automatsko ažuriranje nije uspelo. Molimo vas pratite korake za ručno ažuriranje.", + "manual_update": "Molimo vas pratite korake za ručno ažuriranje.", "processing_update": "Molimo sačekajte. AdGuard Home se ažurira", - "clients_title": "Klijenti", - "clients_desc": "Konfigurišite uređaje koji su povezani na AdGuard Home", + "clients_title": "Uporni klijenti", + "clients_desc": "Konfigurisanje stalnih klijenata za uređaje povezane sa AdGuard Home", "settings_global": "Globalno", "settings_custom": "Prilagođeno", "table_client": "Klijent", @@ -355,7 +419,9 @@ "client_edit": "Izmeni klijent", "client_identifier": "Identifikator", "ip_address": "IP adresa", + "client_identifier_desc": "Klijenti se mogu identifikovati po IP adresi, CIDR-u, MAC adresi ili ClientID (može se koristiti za DoT/DoH/DoQ). Saznajte više o tome kako <0>da identifikujete klijente.", "form_enter_ip": "Unesite IP", + "form_enter_subnet_ip": "Unesite IP adresu subnet \"{{cidr}}\"", "form_enter_mac": "Unesite MAC", "form_enter_id": "Unesite identifikator", "form_add_id": "Dodaj identifikator", @@ -369,14 +435,15 @@ "client_confirm_delete": "Jeste li sigurni da želite da izbrišete klijenta \"{{key}}\"?", "list_confirm_delete": "Jeste li sigurni da želite da izbrišete ovu listu?", "auto_clients_title": "Klijenti (runtime)", - "auto_clients_desc": "Podaci o klijentima koji koriste AdGuard Home, ali nisu sačuvani u konfiguraciji", + "auto_clients_desc": "Uređaji koji nisu na listi upornih klijenata koji i dalje mogu da koriste AdGuard Home", "access_title": "Postavke pristupa", - "access_desc": "Ovde možete konfigurisati pravila pristupa za AdGuard home DNS server.", + "access_desc": "Ovde možete konfigurisati pravila pristupa za AdGuard Home DNS server", "access_allowed_title": "Dozvoljeni klijenti", - "access_allowed_desc": "Spisak CIDR ili IP adresa. Ako je podešeno, AdGuard Home će prihvatiti zahteve samo od ovih IP adresa.", + "access_allowed_desc": "Spisak CIDR, IP adresa ili ClientIDs. Ako ova lista ima stavke, AdGuard Home će prihvatiti zahteve samo ovih klijenata.", "access_disallowed_title": "Zabranjeni klijenti", - "access_disallowed_desc": "Lista CIDR ili IP adresa.. Ako je podešeno, AdGuard Home će odbijati zahteve od ovih IP adresa.", + "access_disallowed_desc": "Spisak CIDR, IP adresa ili ClientIDs. Ako ova lista ima stavke, AdGuard Home će otpustiti zahteve ovih klijenata. Ovo polje se zanemaruje ako postoje stavke u dozvoljenim klijentima.", "access_blocked_title": "Blokirani domeni", + "access_blocked_desc": "Da ne bude zabune sa filterima. AdGuard Home odustaje od DNS upita koji se podudaraju sa ovim domenima, a ovi upiti se čak i ne pojavljuju u evidenciji upita. Možete da navedete tačna imena domena, džoker znakove ili pravila URL filtera, npr. \"example.org\", \"*.example.org\" ili \"|| example.org^\" dopisno.", "access_settings_saved": "Postavke pristupa su uspešno sačuvane", "updates_checked": "Ažuriranja su uspešno proverena", "updates_version_equal": "AdGuard Home je ažuriran na najnoviju verziju", @@ -397,6 +464,7 @@ "setup_dns_privacy_other_3": "<0>dnscrypt-proxy podržava <1>DNS-over-HTTPS.", "setup_dns_privacy_other_4": "<0>Mozilla Firefox podržava <1>DNS-over-HTTPS.", "setup_dns_privacy_other_5": "Više implementacija ćete pronaći <0>ovde i <1>ovde.", + "setup_dns_privacy_ioc_mac": "iOS i macOS konfiguracija", "setup_dns_notice": "Kako biste koristili <1>DNS-over-HTTPS ili <1>DNS-over-TLS, potrebno je da <0>konfigurišete šifrovanje u AdGuard Home postavkama.", "rewrite_added": "DNS prepisivanje za \"{{key}}\" je uspešno dodato", "rewrite_deleted": "DNS prepisivanje za \"{{key}}\" uspešno izbrisano", @@ -429,11 +497,13 @@ "encryption_key_source_content": "Nalepi sadržaj privatnog ključa", "stats_params": "Konfiguracija statistike", "config_successfully_saved": "Konfiguracija je uspešno sačuvana", - "interval_6_hour": "6 sati", + "interval_6_hour": "6 časa", "interval_24_hour": "24 časa", "interval_days": "{{count}} dan", "interval_days_plural": "{{count}} dana", "domain": "Domen", + "ecs": "ECS", + "punycode": "Punycode", "answer": "Odgovor", "filter_added_successfully": "Filter je uspešno dodat", "filter_removed_successfully": "Lista je uspešno uklonjena", @@ -445,6 +515,7 @@ "statistics_clear_confirm": "Jeste li sigurni da želite da očistite statistiku?", "statistics_retention_confirm": "Jeste li sigurni da želite da promenite zadržavanje statistike? Ako smanjite vrednost intervala, neki podaci će biti izgubljeni", "statistics_cleared": "Statistika je uspešno očišćena", + "statistics_enable": "Uključi statistiku", "interval_hours": "{{count}} čas", "interval_hours_plural": "{{count}} časova", "filters_configuration": "Konfiguracija filtera", @@ -464,7 +535,7 @@ "netname": "Ime mreže", "network": "Mreža", "descr": "Opis", - "whois": "Whois", + "whois": "WHOIS", "filtering_rules_learn_more": "<0>Saznajte više o stvaranju vaše lične blokliste hostova.", "blocked_by_response": "Blokirano od CNAME ili IP u odgovoru", "blocked_by_cname_or_ip": "Blokirano od CNAME ili IP", @@ -476,17 +547,18 @@ "rewrite_domain_name": "Ime domena: dodajte CNAME zapis", "rewrite_A": "<0>A: posebna vrednost, zadrži <0>A records iz apstrima", "rewrite_AAAA": "<0>AAAA: posebna vrednost, zadržite <0>AAAA records iz apstrima", - "disable_ipv6": "Isključi IPv6", - "disable_ipv6_desc": "Ako je ovo uključeno, svi DNS unosi za IPv6 adrese (type AAAA) će biti odbačeni.", + "disable_ipv6": "Onemogući rešavanje IPv6 adresa", + "disable_ipv6_desc": "Otpustite sve DNS upite za IPv6 adrese (otkucajte AAAA).", "fastest_addr": "Najbrža IP adresa", + "fastest_addr_desc": "Pretražuje sve DNS servere i vraća najbržu IP adresu među svim odgovorima. Ovo će usporiti DNS pretragu jer moramo da čekamo na odgovore od svih DNS servera, ali će poboljšati sveukupnu povezanost.", "autofix_warning_text": "Ako kliknete \"Popravi\", AdGuardHome će konfigurisati vaš sistem da koristi AdGuardHome DNS server.", "autofix_warning_list": "To će izvršiti sledeće zadatke: <0>Deaktiviranje system DNSStubListener <0>Set DNS server address to 127.0.0.1 <0>Replace symbolic link target of /etc/resolv.conf to /run/systemd/resolve/resolv.conf <0>Stop DNSStubListener (reload systemd-resolved service)", "autofix_warning_result": "Kao rezultat, svi DNS zahtevi sa vašeg sistema će biti obrađeni od AdGuardHome.", "tags_title": "Oznake", - "tags_desc": "Možete izabrati oznake koje odgovaraju klijentu. Oznake mogu biti uključene u pravila filtriranja i dozvoljavaju vam da ih preciznije primenite. <0>Saznajte više", + "tags_desc": "Možete izabrati oznake koje odgovaraju klijentu. Uključite oznake u pravila filtriranja da biste ih preciznije primenili. <0>Saznajte više.", "form_select_tags": "Izaberite oznake klijenta", "check_title": "Proverite filtriranje", - "check_desc": "Proverite da li je host filtriran", + "check_desc": "Proverite da li je host filtriran.", "check": "Proveri", "form_enter_host": "Unesite host", "filtered_custom_rules": "Filtrirano od strane prilagođenog pravila", @@ -508,35 +580,38 @@ "set_static_ip": "Postavite statičku IP adresu", "install_static_ok": "Dobre vesti! Statička IP adresa je već konfigurisana", "install_static_error": "AdGuard Home se ne može automatski konfigurisati za ovo mrežno okruženje. Pogledajte uputstvo kako da to ručno uradite.", + "install_static_configure": "Otkrili smo da se koristi dinamička IP adresa — <0>{{ip}}. Želite li da je koristite kao vašu statičku adresu?", "confirm_static_ip": "AdGuard Home će konfigurisati {{ip}} da bude vaša statička IP adresa. Želite li da nastavite?", "list_updated": "{{count}} lista ažurirana", "list_updated_plural": "{{count}} lista ažurirano", "dnssec_enable": "Uključi DNSSEC", - "dnssec_enable_desc": "Postavlja DNSSEC zastavicu u odlaznim DNS zahtevima i proverava rezultat (DNSSEC rešavač je potreban)", + "dnssec_enable_desc": "Postavlja DNSSEC zastavicu u odlaznim DNS zahtevima i proverava rezultat (DNSSEC rešavač je potreban).", "validated_with_dnssec": "Potvrđeno sa DNSSEC", "all_queries": "Svi zahtevi", "show_blocked_responses": "Blokirano", "show_whitelisted_responses": "Na beloj listi", "show_processed_responses": "Obrađeno", "blocked_safebrowsing": "Blokiralo bezbedno pregledanje", - "blocked_adult_websites": "Blokirala roditeljska kontrola", + "blocked_adult_websites": "Blokiraj sajtove za odrasle", "blocked_threats": "Blokiranih pretnji", "allowed": "Dozvoljeno", "filtered": "Filtrirano", "rewritten": "Prepisano", - "safe_search": "uključi sigurno pretraživanje", + "safe_search": "Sigurna pretraga", "blocklist": "Lista blokiranih", "milliseconds_abbreviation": "ms", "cache_size": "Veličina predmemorije", - "cache_size_desc": "Veličina DNS predmemorije (u bitovima)", + "cache_size_desc": "Veličina DNS predmemorije (u bitovima).", "cache_ttl_min_override": "Prepiši najmanji TTL", "cache_ttl_max_override": "Prepiši najveći TTL", "enter_cache_size": "Unesite veličinu predmemorije", "enter_cache_ttl_min_override": "Unesite najmanji TTL", "enter_cache_ttl_max_override": "Unesite najveći TTL", - "cache_ttl_min_override_desc": "Prepiši TTL vrednost (minimum) dobijen od apstrim servera. Ova vrednost ne može biti veća od 3600 (1 sat)", - "cache_ttl_max_override_desc": "Prepiši TTL vrednost (maksimum) dobijen od apstrim servera", + "cache_ttl_min_override_desc": "Proširivanje kratkih vrednosti vremena na život (sekundi) primljenih sa uzvodnog servera prilikom keširanje DNS odgovora.", + "cache_ttl_max_override_desc": "Prepiši TTL vrednost (maksimum) dobijen od apstrim servera.", "ttl_cache_validation": "Minimalna TTL vrednost mora biti manja ili jednaka najvišij vrednosti", + "cache_optimistic": "Optimistično keširanje", + "cache_optimistic_desc": "Neka AdGuard Home odgovara iz predmemorije čak i kada su unosi istekli pa pokušaj da ih osvežiš.", "filter_category_general": "Opšte", "filter_category_security": "Bezbednost", "filter_category_regional": "Region", @@ -545,9 +620,16 @@ "filter_category_security_desc": "Lista specijalizovana za blokiranje štetnog softvera, štetnih i fišing domena", "filter_category_regional_desc": "Lista koja se usredsređuje na regionalne reklame i servere praćenja", "filter_category_other_desc": "Ostale liste blokiranja", + "setup_config_to_enable_dhcp_server": "Podesite konfiguraciju kako biste omogućili DHCP server", "original_response": "Izvorni odgovor", "click_to_view_queries": "Kliknite da pogledate zahteve", "port_53_faq_link": "Port 53 je najčešće zauzet od \"DNSStubListener\" ili \"systemd-resolved\" usluga. Pročitajte <0>ovo uputstvo kako da to rešite.", "adg_will_drop_dns_queries": "AdGuard Home će odbacivati sve DNS unose od ovog klijenta.", - "parental_control": "Roditeljska kontrola" + "filter_allowlist": "UPOZORENJE: Ova radnja će takođe izuzeti pravilo \"{{disallowed_rule}}\" sa the spiska dozvoljenih klijenata.", + "last_rule_in_allowlist": "Ne mogu da zabranim ovog klijenta zato što će izuzimanje pravila \"{{disallowed_rule}}\" onemogućiti \"dozvoljene klijente\".", + "use_saved_key": "Koristi prethodno sačuvan ključ", + "parental_control": "Roditeljska kontrola", + "safe_browsing": "Sigurno pregledanje", + "served_from_cache": "{{value}} (posluženo iz predmemorije)", + "form_error_password_length": "Lozinka mora imati najmanje {{value}} znakova" } diff --git a/client/src/__locales/sv.json b/client/src/__locales/sv.json index 8ab55d81..90ddd608 100644 --- a/client/src/__locales/sv.json +++ b/client/src/__locales/sv.json @@ -36,15 +36,15 @@ "dhcp_ipv4_settings": "DHCP IPv4 inställningar", "dhcp_ipv6_settings": "DHCP IPv6 inställningar", "form_error_required": "Obligatoriskt fält", - "form_error_ip4_format": "Ogiltig IPv4-adress.", + "form_error_ip4_format": "Ogiltig IPv4-adress", "form_error_ip4_range_start_format": "Ogiltig IPv4-adress för starten av intervallet", "form_error_ip4_range_end_format": "Ogiltig IPv4-adress för slutet av intervallet", "form_error_ip4_gateway_format": "Ogiltig IPv4 adress för gatewayen", - "form_error_ip6_format": "Ogiltig IPv6-adress.", - "form_error_ip_format": "Ogiltig IP-adress.", - "form_error_mac_format": "Ogiltig MAC-adress.", + "form_error_ip6_format": "Ogiltig IPv6-adress", + "form_error_ip_format": "Ogiltig IP-adress", + "form_error_mac_format": "Ogiltig MAC-adress", "form_error_client_id_format": "Ogiltigt klient-ID", - "form_error_server_name": "Ogiltigt servernamn.", + "form_error_server_name": "Ogiltigt servernamn", "form_error_subnet": "Subnätet \"{{cidr}}\" innehåller inte IP-adressen \"{{ip}}\"", "form_error_positive": "Måste vara större än noll", "out_of_range_error": "Måste vara utanför intervallet \"{{start}}\"-\"{{end}}\"", @@ -95,7 +95,7 @@ "filter": "Filter", "query_log": "Förfrågningslogg", "compact": "Kompakt", - "nothing_found": "Inget hittades", + "nothing_found": "Ingenting hittades", "faq": "FAQ", "version": "version", "address": "Adress", @@ -367,7 +367,7 @@ "encryption_https_desc": "Om en HTTPS-port är inställd kommer gränssnittet till AdGuard Home administrering att kunna nås via HTTPS och kommer också att erbjuda DNS-over-HTTPS på '/dns-query' plats.", "encryption_dot": "DNS-över-TLS port", "encryption_dot_desc": "Om den här porten ställs in kommer AdGuard Home att använda DNS-over-TLS-server på porten.", - "encryption_doq": "DNS-over-QUIC port", + "encryption_doq": "DNS-over-QUIC port (experimentell)", "encryption_doq_desc": "Om denna port är konfigurerad kommer AdGuard Home att köra en DNS-over-QUIC-server på denna port. Det är experimentellt och kanske inte är tillförlitligt. Dessutom finns det inte så många klienter som stödjer det för tillfället.", "encryption_certificates": "Certifikat", "encryption_certificates_desc": "För att använda kryptering måste du ange ett giltigt SSL-certifikat för din domän. Du kan skaffa ett certifikat gratis på <0>{{link}} eller köpa ett från någon av de godkända certifikatutfärdare.", @@ -389,7 +389,7 @@ "topline_expiring_certificate": "Ditt SSL-certifikat håller på att gå ut. <0>Krypteringsinställningar.", "topline_expired_certificate": "Ditt SSL-certifikat har gått ut. Uppdatera <0>Krypteringsinställningar-", "form_error_port_range": "Ange ett portnummer inom värdena 80-65535", - "form_error_port_unsafe": "Det här är en osäker port", + "form_error_port_unsafe": "Osäker port", "form_error_equal": "Får inte vara samma", "form_error_password": "Lösenorden överensstämmer inte", "reset_settings": "Återställ inställningar", @@ -405,8 +405,8 @@ "update_failed": "Automatisk uppdatering misslyckad. Var god följ stegen för att uppdatera manuellt.", "manual_update": "Vänligen följ dessa steg för att uppdatera manuellt.", "processing_update": "Vänta, AdGuard Home uppdateras", - "clients_title": "Klienter", - "clients_desc": "Konfigurera enheter uppkopplade mot AdGuard Home", + "clients_title": "Uthålliga klienter", + "clients_desc": "Konfigurera beständiga klientposter för enheter som är anslutna till AdGuard Home", "settings_global": "Global", "settings_custom": "Anpassade", "table_client": "Klient", @@ -417,7 +417,7 @@ "client_edit": "Redigera klient", "client_identifier": "Identifikator", "ip_address": "IP-adress", - "client_identifier_desc": "Klienter kan identifieras med IP-adressen, CIDR, MAC-adressen eller ett speciellt klient-ID (kan användas för DoT/DoH/DoQ). <0>Här kan du lära dig mer om hur du identifierar klienter.", + "client_identifier_desc": "Klienter kan identifieras med IP-adressen, CIDR, MAC-adressen eller ett ClientID (kan användas för DoT/DoH/DoQ). <0>Här kan du lära dig mer om hur du identifierar klienter.", "form_enter_ip": "Skriv in IP", "form_enter_subnet_ip": "Ange en IP adress i subnätet \"{{cidr}}\"", "form_enter_mac": "Skriv in MAC", @@ -433,13 +433,13 @@ "client_confirm_delete": "Är du säker på att du vill ta bort klient \"{{key}}\"?", "list_confirm_delete": "Är du säker på att du vill ta bort den här listan?", "auto_clients_title": "Klienter (körtid)", - "auto_clients_desc": "Data från klienter som använder AdGuard Home, men inte är sparade i konfigurationen", + "auto_clients_desc": "Enheter som inte finns på listan över beständiga klienter som fortfarande kan använda AdGuard Home", "access_title": "Åtkomstinställningar", - "access_desc": "Här kan du konfigurera åtkomstregler för AdGuard Homes DNS-server.", + "access_desc": "Här kan du konfigurera åtkomstregler för AdGuard Homes DNS-server", "access_allowed_title": "Tillåtna klienter", - "access_allowed_desc": "En lista över CIDR, IP-adresser eller klient-ID. Om det är konfigurerat accepterar AdGuard Home endast förfrågningar från dessa klienter.", + "access_allowed_desc": "En lista över CIDR, IP-adresser eller ClientID. Om den här listan har poster accepterar AdGuard Home endast förfrågningar från dessa clienter.", "access_disallowed_title": "Otillåtna klienter", - "access_disallowed_desc": "En lista över CIDR, IP-adresser eller klient-ID. Om det är konfigurerat kommer AdGuard Home att kasta förfrågningar från dessa klienter. Om tillåtna klienter är konfigurerade ignoreras detta fält.", + "access_disallowed_desc": "En lista över CIDR, IP-adresser eller ClientID. Om den här listan har poster kommer AdGuard Home att ta bort förfrågningar från dessa klienter. Detta fält ignoreras om det finns poster i Tillåtna klienter.", "access_blocked_title": "Blockerade domäner", "access_blocked_desc": "Ej att förväxla med filter. AdGuard Home kastar DNS-frågor som matchar dessa domäner, och dessa frågor visas inte ens i frågeloggen. Du kan ange exakta domännamn, jokertecken eller URL-filterregler, t.ex. \"example.org\", \"*.example.org\" eller \"||example.org^\" på motsvarande sätt.", "access_settings_saved": "Åtkomstinställningar sparade", @@ -500,6 +500,7 @@ "interval_days": "{{count}} dag", "interval_days_plural": "{{count}} dagar", "domain": "Domän", + "ecs": "ECS", "punycode": "Punycode", "answer": "Svar", "filter_added_successfully": "Listan har lagts till", @@ -552,10 +553,10 @@ "autofix_warning_list": "Den kommer att utföra följande uppgifter: <0>Avaktivera system DNSStubListener <0>Sätt DNS serveradress till 127.0.0.1 <0>Ersätt symboliskt länkmål för /etc/resolv.conf med /run/systemd /resolve/resolv.conf <0>Stoppa DNSStubListener (ladda om systemd-resolved tjänst)", "autofix_warning_result": "Som ett resultat kommer alla DNS-förfrågningar från ditt system att behandlas av AdGuard Home som standard.", "tags_title": "Taggar", - "tags_desc": "Du kan välja de taggar som motsvarar klienten. Taggar kan inkluderas i filtreringsreglerna och låter dig tillämpa dem mer exakt. <0>Läs mer", + "tags_desc": "Du kan välja de taggar som motsvarar klienten. Inkludera taggar i filtreringsregler för att tillämpa dem mer exakt. <0>Läs mer.", "form_select_tags": "Välj klienttaggar", "check_title": "Kontrollera filtreringen", - "check_desc": "Kontrollera om värdnamnet är filtrerat", + "check_desc": "Kontrollera om värdnamnet är filtrerat.", "check": "Kontrollera", "form_enter_host": "Ange ett värdnamn", "filtered_custom_rules": "Filtrerat efter anpassade filtreringsregler", @@ -598,14 +599,14 @@ "blocklist": "Blocklista", "milliseconds_abbreviation": "ms", "cache_size": "Cachestorlek", - "cache_size_desc": "DNS cachestorlek (i byte)", + "cache_size_desc": "DNS cachestorlek (i byte).", "cache_ttl_min_override": "Åsidosätt minsta TTL", "cache_ttl_max_override": "Åsidosätt maximal TTL", "enter_cache_size": "Ange cachestorlek (byte)", "enter_cache_ttl_min_override": "Ange minsta TTL (sekunder)", "enter_cache_ttl_max_override": "Ange maximal TTL (sekunder)", - "cache_ttl_min_override_desc": "Förläng värden för korta time-to-live värden (sekunder) som tas emot från uppströms server när DNS svar cachelagras", - "cache_ttl_max_override_desc": "Ställ in ett maximalt värde för time-to-live (sekunder) för poster i DNS cachen", + "cache_ttl_min_override_desc": "Förläng värden för korta time-to-live värden (sekunder) som tas emot från uppströms server när DNS svar cachelagras.", + "cache_ttl_max_override_desc": "Ställ in ett maximalt värde för time-to-live (sekunder) för poster i DNS cachen.", "ttl_cache_validation": "Minsta cache TTL-värde måste vara mindre än eller lika med maxvärdet", "cache_optimistic": "Optimistisk cachning", "cache_optimistic_desc": "Få AdGuard Home att svara från cachen även när posterna har gått ut och försök även uppdatera dem.", @@ -627,5 +628,6 @@ "use_saved_key": "Använd den tidigare sparade nyckeln", "parental_control": "Föräldrakontroll", "safe_browsing": "Säker surfning", - "served_from_cache": "{{value}} (levereras från cache)" + "served_from_cache": "{{value}} (levereras från cache)", + "form_error_password_length": "Lösenordet måste vara minst {{value}} tecken långt" } diff --git a/client/src/__locales/tr.json b/client/src/__locales/tr.json index 86683857..5aa53ec1 100644 --- a/client/src/__locales/tr.json +++ b/client/src/__locales/tr.json @@ -9,12 +9,12 @@ "bootstrap_dns": "DNS Önyükleme sunucuları", "bootstrap_dns_desc": "DNS Önyükleme sunucuları, belirttiğiniz üst sunucuların DoH/DoT çözümleyicilerine ait IP adreslerinin çözümlemek için kullanılır.", "local_ptr_title": "Özel ters DNS sunucuları", - "local_ptr_desc": "AdGuard Home'un yerel PTR sorguları için kullandığı DNS sunucuları. Bu sunucular, rDNS kullanarak \"192.168.12.34\" gibi özel IP adreslerine sahip istemcilerin ana bilgisayar adlarını çözmek için kullanılır. Ayarlanmadığı durumda AdGuard Home, işletim sisteminizin varsayılan DNS çözümleme adreslerini kullanır.", + "local_ptr_desc": "AdGuard Home'un yerel PTR sorguları için kullandığı DNS sunucuları. Bu sunucular, rDNS kullanarak \"192.168.12.34\" gibi özel IP adreslerine sahip istemcilerin ana makine adlarını çözmek için kullanılır. Ayarlanmadığı durumda AdGuard Home, işletim sisteminizin varsayılan DNS çözümleme adreslerini kullanır.", "local_ptr_default_resolver": "AdGuard Home, varsayılan olarak aşağıdaki ters DNS çözümleyicilerini kullanır: {{ip}}.", "local_ptr_no_default_resolver": "AdGuard Home, bu sistem için uygun olan özel ters DNS çözümleyicilerini belirleyemedi.", "local_ptr_placeholder": "Her satıra bir sunucu adresi girin", "resolve_clients_title": "İstemcilerin IP adreslerinin ters çözümlenmesini etkinleştir", - "resolve_clients_desc": "Karşılık gelen çözümleyicilere (yerel istemciler için özel DNS sunucuları, genel IP adresleri olan istemciler için üst sunucuları) PTR sorguları göndererek istemcilerin IP adreslerini ana bilgisayar adlarının tersine çözün.", + "resolve_clients_desc": "Karşılık gelen çözümleyicilere (yerel istemciler için özel DNS sunucuları, genel IP adresleri olan istemciler için üst sunucuları) PTR sorguları göndererek istemcilerin IP adreslerini ana makine adlarının tersine çözün.", "use_private_ptr_resolvers_title": "Özel ters DNS çözümleyicileri kullan", "use_private_ptr_resolvers_desc": "Bu üst kaynak sunucularını kullanarak yerel olarak sunulan adresler için ters DNS aramaları yapın. Devre dışı bırakılırsa, AdGuard Home, DHCP, /etc/hosts, vb. tarafından bilinen istemciler dışında bu tür tüm PTR isteklerine NXDOMAIN ile yanıt verir.", "check_dhcp_servers": "DHCP sunucularını denetle", @@ -35,23 +35,23 @@ "dhcp_config_saved": "DHCP yapılandırması başarıyla kaydedildi", "dhcp_ipv4_settings": "DHCP IPv4 Ayarları", "dhcp_ipv6_settings": "DHCP IPv6 Ayarları", - "form_error_required": "Gerekli alan.", - "form_error_ip4_format": "IPv4 adresi geçersiz.", - "form_error_ip4_range_start_format": "Başlangıç aralığı IPv4 adresi geçersiz.", - "form_error_ip4_range_end_format": "Bitiş aralığı IPv4 adresi geçersiz.", - "form_error_ip4_gateway_format": "Ağ geçidi IPv4 adresi geçersiz.", - "form_error_ip6_format": "IPv6 adresi geçersiz.", - "form_error_ip_format": "IP adresi geçersiz.", - "form_error_mac_format": "MAC adresi geçersiz.", - "form_error_client_id_format": "İstemci Kimliği yalnızca sayılar, küçük harfler ve kısa çizgiler içermelidir.", - "form_error_server_name": "Sunucu adı geçersiz.", - "form_error_subnet": "\"{{cidr}}\" alt ağı, \"{{ip}}\" IP adresini içermiyor.", - "form_error_positive": "0'dan büyük olmalıdır.", - "out_of_range_error": "\"{{start}}\"-\"{{end}}\" aralığının dışında olmalıdır.", - "lower_range_start_error": "Başlangıç aralığından daha düşük olmalıdır.", - "greater_range_start_error": "Başlangıç aralığından daha büyük olmalıdır.", - "greater_range_end_error": "Bitiş aralığından daha büyük olmalıdır.", - "subnet_error": "Adresler bir alt ağda olmalıdır.", + "form_error_required": "Gerekli alan", + "form_error_ip4_format": "Geçersiz IPv4 adresi", + "form_error_ip4_range_start_format": "Geçersiz başlangıç aralığı IPv4 biçimi", + "form_error_ip4_range_end_format": "Geçersiz bitiş aralığı IPv4 adresi", + "form_error_ip4_gateway_format": "Geçersiz ağ geçidi IPv4 adresi", + "form_error_ip6_format": "Geçersiz IPv6 adresi", + "form_error_ip_format": "Geçersiz IP adresi", + "form_error_mac_format": "Geçersiz MAC adresi", + "form_error_client_id_format": "İstemci Kimliği yalnızca sayılar, küçük harfler ve kısa çizgiler içermelidir", + "form_error_server_name": "Geçersiz sunucu adı", + "form_error_subnet": "\"{{cidr}}\" alt ağı, \"{{ip}}\" IP adresini içermiyor", + "form_error_positive": "0'dan büyük olmalıdır", + "out_of_range_error": "\"{{start}}\"-\"{{end}}\" aralığının dışında olmalıdır", + "lower_range_start_error": "Başlangıç aralığından daha düşük olmalıdır", + "greater_range_start_error": "Başlangıç aralığından daha büyük olmalıdır", + "greater_range_end_error": "Bitiş aralığından daha büyük olmalıdır", + "subnet_error": "Adresler bir alt ağda olmalıdır", "gateway_or_subnet_invalid": "Alt ağ maskesi geçersiz.", "dhcp_form_gateway_input": "Ağ geçidi IP", "dhcp_form_subnet_input": "Alt ağ maskesi", @@ -64,10 +64,10 @@ "dhcp_hardware_address": "Donanım adresi", "dhcp_ip_addresses": "IP adresleri", "ip": "IP", - "dhcp_table_hostname": "Bilgisayar Adı", + "dhcp_table_hostname": "Ana makine Adı", "dhcp_table_expires": "Bitiş tarihi", "dhcp_warning": "DHCP sunucusunu yine de etkinleştirmek istiyorsanız, ağınızda başka aktif DHCP sunucusu olmadığından emin olun, aksi takdirde ağa bağlı cihazların İnternet bağlantısı kesilebilir!", - "dhcp_error": "AdGuard Home, ağda başka bir etkin DHCP sunucusu olup olmadığını belirleyemedi.", + "dhcp_error": "AdGuard Home, ağda başka bir etkin DHCP sunucusu olup olmadığını belirleyemedi", "dhcp_static_ip_error": "DHCP sunucusunu kullanmak için sabit bir IP adresi ayarlanmalıdır. AdGuard Home, bu ağ arayüzünün sabit bir IP adresi kullanılarak yapılandırılıp yapılandırılmadığını belirleyemedi. Lütfen sabit IP adresini elle ayarlayın.", "dhcp_dynamic_ip_found": "Sisteminiz, <0>{{interfaceName}} arayüzü için dinamik IP adresi yapılandırması kullanıyor. DHCP sunucusunu kullanmak için sabit bir IP adresi ayarlanmalıdır. Geçerli olan IP adresiniz <0>{{ipAddress}}. \"DHCP sunucusunu etkinleştir\" düğmesine basarsanız, AdGuard Home bu IP adresini otomatik bir şekilde sabit olarak ayarlayacaktır.", "dhcp_lease_added": "Sabit kiralama \"{{key}}\" başarıyla eklendi", @@ -82,7 +82,7 @@ "country": "Ülke", "city": "Şehir", "delete_confirm": "\"{{key}}\" öğesini silmek istediğinizden emin misiniz?", - "form_enter_hostname": "Ana bilgisayar adı girin", + "form_enter_hostname": "Ana makine adı girin", "error_details": "Hata ayrıntıları", "response_details": "Yanıt ayrıntıları", "request_details": "İstek ayrıntıları", @@ -130,14 +130,14 @@ "number_of_dns_query_days": "Son {{count}} gün boyunca işlenen DNS sorgularının sayısı", "number_of_dns_query_days_plural": "Son {{count}} gün boyunca işlenen DNS sorgularının sayısı", "number_of_dns_query_24_hours": "Son 24 saat içinde işlenen DNS sorgularının sayısı", - "number_of_dns_query_blocked_24_hours": "Reklam engelleme filtreleri ve engel listeleri tarafından engellenen DNS isteklerinin sayısı", + "number_of_dns_query_blocked_24_hours": "Reklam engelleme filtreleri ve ana makine engel listeleri tarafından engellenen DNS isteklerinin sayısı", "number_of_dns_query_blocked_24_hours_by_sec": "AdGuard gezinti koruması modülü tarafından engellenen DNS isteklerinin sayısı", "number_of_dns_query_blocked_24_hours_adult": "Engellenen yetişkin içerikli sitelerin sayısı", "enforced_save_search": "Uygulanan güvenli arama", "number_of_dns_query_to_safe_search": "Güvenli Aramanın uygulandığı arama motorlarına gönderilen DNS isteklerinin sayısı", "average_processing_time": "Ortalama işlem süresi", "average_processing_time_hint": "Bir DNS isteğinin milisaniye cinsinden ortalama işlem süresi", - "block_domain_use_filters_and_hosts": "Filtre ve ana bilgisayar listelerini kullanarak alan adlarını engelle", + "block_domain_use_filters_and_hosts": "Filtre ve ana makine listelerini kullanarak alan adlarını engelle", "filters_block_toggle_hint": "Filtreler ayarlarında engelleme kuralları oluşturabilirsiniz.", "use_adguard_browsing_sec": "AdGuard gezinti koruması web hizmetini kullan", "use_adguard_browsing_sec_hint": "AdGuard Home, alan adının gezinti koruması web hizmeti tarafından engellenip engellenmediğini kontrol eder. Kontrolü gerçekleştirmek için gizlilik dostu arama API'sini kullanır: sunucuya yalnızca SHA256 karma alan adının kısa bir ön eki gönderilir.", @@ -151,7 +151,7 @@ "dns_blocklists": "DNS engel listeleri", "dns_allowlists": "DNS izin listeleri", "dns_blocklists_desc": "AdGuard Home, engel listeleriyle eşleşen alan adlarını engeller.", - "dns_allowlists_desc": "DNS izin listesindeki alan adlarına, engel listesinde olsa bile izin verilir.", + "dns_allowlists_desc": "DNS izin listesindeki alan adlarına, engel listesinde olsa bile izin verilecektir.", "custom_filtering_rules": "Özel filtreleme kuralları", "encryption_settings": "Şifreleme ayarları", "dhcp_settings": "DHCP ayarları", @@ -179,14 +179,14 @@ "edit_table_action": "Düzenle", "delete_table_action": "Sil", "elapsed": "Geçen süre", - "filters_and_hosts_hint": "AdGuard Home, temel reklam engelleme kurallarını ve ana bilgisayar engelleme dosyalarının söz dizimini anlar.", + "filters_and_hosts_hint": "AdGuard Home, temel reklam engelleme kurallarını ve ana makine engelleme dosyalarının söz dizimini anlar.", "no_blocklist_added": "Engel listesi eklenmedi", "no_whitelist_added": "İzin listesi eklenmedi", "add_blocklist": "Engel listesi ekle", "add_allowlist": "İzin listesi ekle", "cancel_btn": "İptal", "enter_name_hint": "İsim girin", - "enter_url_or_path_hint": "Listenin URL adresini veya dosya konumunu girin", + "enter_url_or_path_hint": "Listenin URL adresini veya dosya yolunu girin", "check_updates_btn": "Güncellemeleri denetle", "new_blocklist": "Yeni engel listesi", "new_allowlist": "Yeni izin listesi", @@ -196,11 +196,11 @@ "choose_allowlist": "İzin listelerini seçin", "enter_valid_blocklist": "Engel listesine geçerli bir URL girin.", "enter_valid_allowlist": "İzin listesine geçerli bir URL girin.", - "form_error_url_format": "URL biçimi geçersiz.", - "form_error_url_or_path_format": "Listenin URL adresi veya dosya konumu geçersiz.", + "form_error_url_format": "Geçersiz URL biçimi", + "form_error_url_or_path_format": "Geçersiz URL adresi veya dosya yolu", "custom_filter_rules": "Özel filtreleme kuralları", - "custom_filter_rules_hint": "Her satıra bir kural girin. Reklam engelleme kuralı veya ana bilgisayar dosyası söz dizimi kullanabilirsiniz.", - "system_host_files": "Sistem ana bilgisayar dosyaları", + "custom_filter_rules_hint": "Her satıra bir kural girin. Reklam engelleme kuralı veya ana makine dosyası söz dizimi kullanabilirsiniz.", + "system_host_files": "Sistem ana makine dosyaları", "examples_title": "Örnekler", "example_meaning_filter_block": "example.org'a ve tüm alt alanlarına erişimi engeller;", "example_meaning_filter_whitelist": "example.org'a ve tüm alt alanlarına erişimin engelini kaldırır;", @@ -210,11 +210,13 @@ "example_comment_hash": "# Ayrıca bir yorum.", "example_regex_meaning": "belirtilen düzenli ifadelerle eşleşen alan adlarına erişimi engelle.", "example_upstream_regular": "normal DNS (UDP üzerinden);", + "example_upstream_udp": "normal DNS (UDP üzerinden, ana makine adı);", "example_upstream_dot": "şifrelenmiş <0>DNS-over-TLS;", "example_upstream_doh": "şifrelenmiş <0>DNS-over-HTTPS;", "example_upstream_doq": "şifrelenmiş <0>DNS-over-QUIC (deneysel);", "example_upstream_sdns": "<1>DNSCrypt veya <2>DNS-over-HTTPS çözümleyicileri için <0>DNS Damgaları;", "example_upstream_tcp": "normal DNS (TCP üzerinden);", + "example_upstream_tcp_hostname": "normal DNS (TCP üzerinden, ana makine adı);", "all_lists_up_to_date_toast": "Tüm listeler güncel durumda", "updated_upstream_dns_toast": "Üst sunucular başarıyla kaydedildi", "dns_test_ok_toast": "Belirtilen DNS sunucuları düzgün çalışıyor", @@ -259,10 +261,10 @@ "query_log_strict_search": "Tam arama için çift tırnak işareti kullanın", "query_log_retention_confirm": "Sorgu günlüğü saklama süresini değiştirmek istediğinize emin misiniz? Aralık değerini azaltırsanız, bazı veriler kaybolacaktır", "anonymize_client_ip": "İstemcinin IP adresini gizle", - "anonymize_client_ip_desc": "İstemcinin tam IP adresini günlüklere veya istatistiklere kaydetmeyin.", + "anonymize_client_ip_desc": "İstemcinin tam IP adresini günlüklere veya istatistiklere kaydetmeyin", "dns_config": "DNS sunucu yapılandırması", "dns_cache_config": "DNS önbellek yapılandırması", - "dns_cache_config_desc": "Burada DNS önbelleğini yapılandırabilirsiniz.", + "dns_cache_config_desc": "Burada DNS önbelleğini yapılandırabilirsiniz", "blocking_mode": "Engelleme modu", "default": "Varsayılan", "nxdomain": "NXDOMAIN", @@ -285,7 +287,7 @@ "form_enter_rate_limit": "Sıklık limitini girin", "rate_limit": "Sıklık limiti", "edns_enable": "EDNS istemci alt ağını etkinleştir", - "edns_cs_desc": "İstemcilerin alt ağlarını DNS sunucularına gönderin.", + "edns_cs_desc": "Kaynak yönü isteklerine EDNS İstemci Alt Ağı seçeneğini (ECS) ekleyin ve istemciler tarafından gönderilen değerleri sorgu günlüğüne kaydedin.", "rate_limit_desc": "İstemci başına izin verilen saniyedeki istek sayısı. 0 olarak ayarlamak, sınır olmadığı anlamına gelir.", "blocking_ipv4_desc": "Engellenen bir A isteği için geri döndürülecek IP adresi", "blocking_ipv6_desc": "Engellenen bir AAAA isteği için geri döndürülecek IP adresi", @@ -308,8 +310,8 @@ "install_settings_title": "Yönetici Web Arayüzü", "install_settings_listen": "Dinleme arayüzü", "install_settings_port": "Bağlantı noktası", - "install_settings_interface_link": "AdGuard Home yönetici web arayüzü sayfanız şu adresten erişilebilir olacaktır:", - "form_error_port": "Geçerli bir bağlantı noktası değeri girin.", + "install_settings_interface_link": "AdGuard Home yönetici web arayüzünüz aşağıdaki adreslerde bulunacaktır:", + "form_error_port": "Geçerli bir bağlantı noktası değeri girin", "install_settings_dns": "DNS sunucusu", "install_settings_dns_desc": "Cihazlarınızı veya yönlendiricinizi şu adresteki DNS sunucusunu kullanması için ayarlamanız gerekecek:", "install_settings_all_interfaces": "Tüm arayüzler", @@ -334,7 +336,7 @@ "install_devices_router_list_4": "Bazı yönlendirici türlerinde özel bir DNS sunucusu ayarlanamaz. Bu durumda, AdGuard Home'u <0>DHCP sunucusu olarak ayarlamak yardımcı olabilir. Aksi takdirde, yönlendirici modeliniz için DNS sunucularını nasıl ayarlayacağınız konusunda yönlendirici kılavuzuna bakmalısınız.", "install_devices_windows_list_1": "Başlat menüsünden veya Windows araması aracılığıyla Denetim Masası'nı açın.", "install_devices_windows_list_2": "Ağ ve İnternet kategorisine girin ve ardından Ağ ve Paylaşım Merkezi'ne girin.", - "install_devices_windows_list_3": "Ekranın sol tarafında bulunan \"Adaptör ayarlarını değiştir\" öğesini bulun ve tıklayın.", + "install_devices_windows_list_3": "Sol panelde \"Bağdaştırıcı ayarlarını değiştirin'e\" tıklayın.", "install_devices_windows_list_4": "Kullandığınız aktif bağlantının üzerine sağ tıklayın ve Özellikler öğesine tıklayın.", "install_devices_windows_list_5": "Listede \"İnternet Protokolü Sürüm 4 (TCP/IPv4)\" (veya IPv6 için \"İnternet Protokolü Sürüm 6 (TCP/IPv6)\") öğesini bulun, seçin ve ardından tekrar Özellikler'e tıklayın.", "install_devices_windows_list_6": "\"Aşağıdaki DNS sunucu adreslerini kullan\"ı seçin ve AdGuard Home sunucu adreslerinizi girin.", @@ -356,7 +358,7 @@ "open_dashboard": "Ana Sayfayı Aç", "install_saved": "Başarıyla kaydedildi", "encryption_title": "Şifreleme", - "encryption_desc": "DNS ve yönetici web arayüzü için şifreleme (HTTPS/TLS) desteği.", + "encryption_desc": "DNS ve yönetici web arayüzü için şifreleme (HTTPS/TLS) desteği", "encryption_config_saved": "Şifreleme yapılandırması kaydedildi", "encryption_server": "Sunucu adı", "encryption_server_enter": "Alan adınızı girin", @@ -364,7 +366,7 @@ "encryption_redirect": "Otomatik olarak HTTPS'e yönlendir", "encryption_redirect_desc": "Etkinleştirirseniz, AdGuard Home sizi HTTP adresi yerine HTTPS adresine yönlendirir.", "encryption_https": "HTTPS bağlantı noktası", - "encryption_https_desc": "HTTPS bağlantı noktası yapılandırılırsa, AdGuard Home yönetici arayüzüne HTTPS aracılığıyla erişilebilir olacak ve ayrıca '/dns-query' üzerinden DNS-over-HTTPS bağlantısı sağlanır.", + "encryption_https_desc": "HTTPS bağlantı noktası yapılandırılırsa, AdGuard Home yönetici arayüzüne HTTPS aracılığıyla erişilebilir olacak ve ayrıca '/dns-query' üzerinden DNS-over-HTTPS bağlantısı sağlayacaktır.", "encryption_dot": "DNS-over-TLS bağlantı noktası", "encryption_dot_desc": "Bu bağlantı noktası yapılandırılırsa, AdGuard Home, DNS-over-TLS sunucusunu bu bağlantı noktası üzerinden çalıştıracaktır.", "encryption_doq": "DNS-over-QUIC bağlantı noktası (deneysel)", @@ -378,26 +380,26 @@ "encryption_key_input": "Sertifikanızın PEM biçimli özel anahtarını kopyalayıp buraya yapıştırın.", "encryption_enable": "Şifrelemeyi etkinleştir (HTTPS, DNS-over-HTTPS ve DNS-over-TLS)", "encryption_enable_desc": "Şifrelemeyi etkinleştirirseniz, AdGuard Home yönetici arayüzü HTTPS üzerinden çalışır ve DNS sunucusu, DNS-over-HTTPS ve DNS-over-TLS üzerinden gelen istekleri dinler.", - "encryption_chain_valid": "Sertifika zinciri geçerli.", + "encryption_chain_valid": "Sertifika zinciri geçerli", "encryption_chain_invalid": "Sertifika zinciri geçersiz.", "encryption_key_valid": "Bu geçerli bir {{type}} özel anahtar.", "encryption_key_invalid": "Bu geçersiz bir {{type}} özel anahtar.", "encryption_subject": "Konu", "encryption_issuer": "Sağlayan", - "encryption_hostnames": "Ana bilgisayar adları", + "encryption_hostnames": "Ana makine adları", "encryption_reset": "Şifreleme ayarlarını sıfırlamak istediğinizden emin misiniz?", "topline_expiring_certificate": "SSL sertifikanızın süresi sona erdi. <0>Şifreleme ayarlarını güncelleyin.", "topline_expired_certificate": "SSL sertifikanızın süresi sona erdi. <0>Şifreleme ayarlarını güncelleyin.", - "form_error_port_range": "80-65535 aralığında geçerli bir bağlantı noktası değeri girin.", - "form_error_port_unsafe": "Bu bağlantı noktası güvenli değil.", - "form_error_equal": "Aynı olmamalı.", - "form_error_password": "Parolalar uyuşmuyor.", + "form_error_port_range": "80-65535 aralığında geçerli bir bağlantı noktası değeri girin", + "form_error_port_unsafe": "Güvenli olmayan bağlantı noktası", + "form_error_equal": "Aynı olmamalıdır", + "form_error_password": "Parolalar uyuşmuyor", "reset_settings": "Ayarları sıfırla", "update_announcement": "AdGuard Home {{version}} sürümü mevcut! Daha fazla bilgi için <0>buraya tıklayın.", "setup_guide": "Kurulum Rehberi", "dns_addresses": "DNS adresleri", "dns_start": "DNS sunucusu başlatılıyor", - "dns_status_error": "DNS sunucusunun durumu denetlenirken bir hata oluştu.", + "dns_status_error": "DNS sunucusunun durumu denetlenirken bir hata oluştu", "down": "Kapalı", "fix": "Düzelt", "dns_providers": "Aralarından seçim yapabileceğiniz, bilinen <0>DNS sağlayıcıların listesi.", @@ -406,7 +408,7 @@ "manual_update": "Elle güncellemek için lütfen bu adımları uygulayın.", "processing_update": "Lütfen bekleyin, AdGuard Home güncelleniyor", "clients_title": "Kalıcı istemciler", - "clients_desc": "AdGuard Home'a bağlı cihazlar için kalıcı istemci kayıtlarını yapılandırın.", + "clients_desc": "AdGuard Home'a bağlı cihazlar için kalıcı istemci kayıtlarını yapılandırın", "settings_global": "Genel", "settings_custom": "Özel", "table_client": "İstemci", @@ -433,9 +435,9 @@ "client_confirm_delete": "\"{{key}}\" istemcisini silmek istediğinizden emin misiniz?", "list_confirm_delete": "Bu listeyi silmek istediğinizden emin misiniz?", "auto_clients_title": "Çalışma zamanı istemcileri", - "auto_clients_desc": "Henüz AdGuard Home'u kullanabilecek Kalıcı istemciler listesinde olmayan cihazlar.", + "auto_clients_desc": "Henüz AdGuard Home'u kullanabilecek Kalıcı istemciler listesinde olmayan cihazlar", "access_title": "Erişim ayarları", - "access_desc": "AdGuard Home DNS sunucusu için erişim kurallarını buradan yapılandırabilirsiniz.", + "access_desc": "AdGuard Home DNS sunucusu için erişim kurallarını buradan yapılandırabilirsiniz", "access_allowed_title": "İzin verilen istemciler", "access_allowed_desc": "CIDR'lerin, IP adreslerinin veya İstemci Kimliklerin listesi. Bu listede girişler varsa, AdGuard Home yalnızca bu istemcilerden gelen istekleri kabul eder.", "access_disallowed_title": "İzin verilmeyen istemciler", @@ -471,12 +473,12 @@ "rewrite_confirm_delete": "\"{{key}}\" için DNS yeniden yazımını silmek istediğinize emin misiniz?", "rewrite_desc": "Belirli bir alan adı için özel DNS yanıtını kolayca yapılandırmanızı sağlar.", "rewrite_applied": "Yeniden yazım kuralı uygulandı", - "rewrite_hosts_applied": "Ana bilgisayar dosyası kuralı tarafından yeniden yazıldı", + "rewrite_hosts_applied": "Ana makine dosyası kuralı tarafından yeniden yazıldı", "dns_rewrites": "DNS yeniden yazımları", "form_domain": "Alan adı veya joker karakter girin", "form_answer": "IP adresi veya alan adı girin", - "form_error_domain_format": "Alan adı biçimi geçersiz.", - "form_error_answer_format": "Yanıt biçimi geçersiz.", + "form_error_domain_format": "Geçersiz alan adı biçimi", + "form_error_answer_format": "Geçersiz yanıt biçimi", "configure": "Yapılandır", "main_settings": "Ana ayarlar", "block_services": "Belirli hizmetleri engelle", @@ -500,6 +502,7 @@ "interval_days": "{{count}} gün", "interval_days_plural": "{{count}} gün", "domain": "Alan adı", + "ecs": "ECS", "punycode": "Punycode", "answer": "Yanıt", "filter_added_successfully": "Liste başarıyla eklendi", @@ -507,7 +510,7 @@ "filter_updated": "Liste başarıyla güncellendi", "statistics_configuration": "İstatistik yapılandırması", "statistics_retention": "İstatistikleri sakla", - "statistics_retention_desc": "Zaman değerini azaltırsanız, bazı veriler kaybolacaktır.", + "statistics_retention_desc": "Zaman değerini azaltırsanız, bazı veriler kaybolacaktır", "statistics_clear": " İstatistikleri temizle", "statistics_clear_confirm": "İstatistikleri temizlemek istediğinizden emin misiniz?", "statistics_retention_confirm": "İstatistik saklama süresini değiştirmek istediğinizden emin misiniz? Aralık değerini azaltırsanız, bazı veriler kaybolacaktır", @@ -524,7 +527,7 @@ "password_label": "Parola", "password_placeholder": "Parolayı girin", "sign_in": "Giriş yap", - "sign_out": "Oturumu kapat", + "sign_out": "Çıkış yap", "forgot_password": "Parolanızı mı unuttunuz?", "forgot_password_desc": "Kullanıcı hesabınız için yeni bir parola oluşturmak istiyorsanız lütfen <0>bu adımları uygulayın.", "location": "Konum", @@ -533,7 +536,7 @@ "network": "Ağ", "descr": "Açıklama", "whois": "WHOIS", - "filtering_rules_learn_more": "Kendi ana bilgisayar listelerinizi oluşturma hakkında <0>daha fazla bilgi edinin.", + "filtering_rules_learn_more": "Kendi ana makine listelerinizi oluşturma hakkında <0>daha fazla bilgi edinin.", "blocked_by_response": "Yanıt olarak CNAME veya IP tarafından engellendi", "blocked_by_cname_or_ip": "CNAME veya IP tarafından engellendi", "try_again": "Tekrar dene", @@ -555,13 +558,13 @@ "tags_desc": "İstemciye karşılık gelen etiketleri seçebilirsiniz. Etiketleri daha kesin olarak uygulamak için filtreleme kurallarına dahil edin. <0>Daha fazla bilgi edinin.", "form_select_tags": "İstemci etiketlerini seçin", "check_title": "Filtrelemeyi denetleyin", - "check_desc": "Ana bilgisayar adının filtreleme durumunu kontrol edin.", + "check_desc": "Ana makine adının filtreleme durumunu kontrol edin.", "check": "Denetle", - "form_enter_host": "Ana bilgisayar adı girin", + "form_enter_host": "Ana makine adı girin", "filtered_custom_rules": "Özel filtreleme kurallarına göre filtrelendi", "choose_from_list": "Listeden seç", "add_custom_list": "Özel liste ekle", - "host_whitelisted": "Ana bilgisayara izin verildi", + "host_whitelisted": "Ana makineye izin verildi", "check_ip": "IP adresleri: {{ip}}", "check_cname": "CNAME: {{cname}}", "check_reason": "Sebep: {{reason}}", @@ -606,7 +609,7 @@ "enter_cache_ttl_max_override": "Maksimum TTL değerini girin (saniye olarak)", "cache_ttl_min_override_desc": "DNS yanıtlarını önbelleğe alırken üst sunucudan alınan kullanım süresi değerini uzatın (saniye olarak).", "cache_ttl_max_override_desc": "DNS önbelleğindeki girişler için maksimum kullanım süresi değerini ayarlayın (saniye olarak).", - "ttl_cache_validation": "Minimum önbellek TTL geçersiz kılma, maksimuma eşit veya bundan küçük olmalıdır.", + "ttl_cache_validation": "Minimum önbellek TTL geçersiz kılma, maksimuma eşit veya bundan küçük olmalıdır", "cache_optimistic": "İyimser önbelleğe alma", "cache_optimistic_desc": "Girişlerin süresi dolduğunda bile AdGuard Home'un önbellekten yanıt vermesini sağlayın ve bunları yenilemeye çalışın.", "filter_category_general": "Genel", @@ -621,12 +624,12 @@ "original_response": "Gerçek yanıt", "click_to_view_queries": "Sorguları görmek için tıklayın", "port_53_faq_link": "53 numaralı bağlantı noktası genellikle \"DNSStubListener\" veya \"systemd-resolved\" hizmetleri tarafından kullanılır. Lütfen bu sorunun nasıl çözüleceğine ilişkin <0>bu talimatı okuyun.", - "adg_will_drop_dns_queries": "AdGuard Home, bu istemciden gelen tüm DNS sorgularını yok sayar.", + "adg_will_drop_dns_queries": "AdGuard Home, bu istemciden gelen tüm DNS sorgularını yok sayacaktır.", "filter_allowlist": "UYARI: Bu işlem ayrıca \"{{disallowed_rule}}\" kuralını izin verilen istemciler listesinden hariç tutacaktır.", "last_rule_in_allowlist": "\"{{disallowed_rule}}\" kuralı hariç tutulduğunda \"İzin verilen istemciler\" listesi DEVRE DIŞI bırakılacağı için bu istemciye izin verilemez.", "use_saved_key": "Önceden kaydedilmiş anahtarı kullan", "parental_control": "Ebeveyn Denetimi", "safe_browsing": "Güvenli Gezinti", "served_from_cache": "{{value}} (önbellekten kullanıldı)", - "form_error_password_length": "Parola en az {{value}} karakter uzunluğunda olmalı." + "form_error_password_length": "Parola en az {{value}} karakter uzunluğunda olmalıdır" } diff --git a/client/src/__locales/uk.json b/client/src/__locales/uk.json index 716d784c..5d349618 100644 --- a/client/src/__locales/uk.json +++ b/client/src/__locales/uk.json @@ -35,24 +35,24 @@ "dhcp_config_saved": "Конфігурацію DHCP-сервера успішно збережено", "dhcp_ipv4_settings": "Налаштування DHCP IPv4", "dhcp_ipv6_settings": "Налаштування DHCP IPv6", - "form_error_required": "Обов'язкове поле.", - "form_error_ip4_format": "Неправильна IPv4-адреса.", - "form_error_ip4_range_start_format": "Неправильна IPv4-адреса початку діапазону.", - "form_error_ip4_range_end_format": "Неправильна IPv4-адреса кінця діапазону.", - "form_error_ip4_gateway_format": "Неправильна IPv4-адреса шлюзу.", - "form_error_ip6_format": "Неправильна IPv6-адреса.", - "form_error_ip_format": "Неправильна IP-адреса.", - "form_error_mac_format": "Неправильна MAC-адреса.", - "form_error_client_id_format": "ClientID має містити лише цифри, малі латинські букви та дефіси.", - "form_error_server_name": "Неправильна назва сервера.", - "form_error_subnet": "Підмережа «{{cidr}}» не містить IP-адресу «{{ip}}».", - "form_error_positive": "Повинно бути більше ніж 0.", - "out_of_range_error": "Не повинна бути в діапазоні «{{start}}»−«{{end}}».", - "lower_range_start_error": "Має бути меншим за початкову адресу.", - "greater_range_start_error": "Має бути більшим за початкову адресу.", - "greater_range_end_error": "Має бути більшим за кінцеву адресу.", - "subnet_error": "Адреси повинні бути в одній підмережі.", - "gateway_or_subnet_invalid": "Неправильна маска підмережі.", + "form_error_required": "Обов'язкове поле", + "form_error_ip4_format": "Неправильна IPv4-адреса", + "form_error_ip4_range_start_format": "Неправильна IPv4-адреса початку діапазону", + "form_error_ip4_range_end_format": "Неправильна IPv4-адреса кінця діапазону", + "form_error_ip4_gateway_format": "Неправильна IPv4-адреса шлюзу", + "form_error_ip6_format": "Неправильна IPv6-адреса", + "form_error_ip_format": "Неправильна IP-адреса", + "form_error_mac_format": "Неправильна MAC-адреса", + "form_error_client_id_format": "ID клієнта має містити лише цифри, малі букви та дефіси", + "form_error_server_name": "Неправильна назва сервера", + "form_error_subnet": "Підмережа «{{cidr}}» не містить IP-адресу «{{ip}}»", + "form_error_positive": "Повинно бути більше за 0", + "out_of_range_error": "Не повинна бути в діапазоні «{{start}}»−«{{end}}»", + "lower_range_start_error": "Має бути меншим за початкову адресу", + "greater_range_start_error": "Має бути більшим за початкову адресу", + "greater_range_end_error": "Має бути більшим за кінцеву адресу", + "subnet_error": "Адреси повинні бути в одній підмережі", + "gateway_or_subnet_invalid": "Неправильна маска підмережі", "dhcp_form_gateway_input": "IP-адреса шлюзу", "dhcp_form_subnet_input": "Маска підмережі", "dhcp_form_range_title": "Діапазон IP-адрес", @@ -67,7 +67,7 @@ "dhcp_table_hostname": "Назва вузла", "dhcp_table_expires": "Термін дії", "dhcp_warning": "Якщо ви однаково хочете увімкнути DHCP-сервер, переконайтеся, що у вашій мережі немає інших активних DHCP-серверів. Інакше, це може порушити роботу інтернету на під'єднаних пристроях!", - "dhcp_error": "Не вдалося визначити, чи є в мережі інший DHCP-сервер.", + "dhcp_error": "AdGuard Home не зміг визначити, чи є в мережі інший DHCP-сервер", "dhcp_static_ip_error": "Для використання DHCP-сервера необхідно встановити статичну IP-адресу. Нам не вдалося визначити, чи цей мережевий інтерфейс налаштовано для використання статичної IP-адреси. Встановіть статичну IP-адресу вручну.", "dhcp_dynamic_ip_found": "Ваша система використовує конфігурацію з динамічною IP-адресою для інтерфейсу <0>{{interfaceName}}. Для використання DHCP-сервера необхідно встановити статичну IP-адресу. Ваша поточна IP-адреса <0>{{ipAddress}}. Ми автоматично встановимо цю IP-адресу як статичну, якщо ви натиснете кнопку «Увімкнути DHCP-сервер».", "dhcp_lease_added": "Статичну оренду «{{key}}» успішно додано", @@ -196,8 +196,8 @@ "choose_allowlist": "Обрати списки дозволених сайтів", "enter_valid_blocklist": "Введіть дійсну URL-адресу в список блокування.", "enter_valid_allowlist": "Введіть дійсну URL-адресу в список дозволів.", - "form_error_url_format": "Неправильний формат URL.", - "form_error_url_or_path_format": "Неправильна URL-адреса або абсолютний шлях до списку.", + "form_error_url_format": "Неправильний формат URL", + "form_error_url_or_path_format": "Неправильна URL-адреса або абсолютний шлях до списку", "custom_filter_rules": "Власні правила фільтрування", "custom_filter_rules_hint": "Вводьте одне правило на рядок. Ви можете використовувати правила блокування чи синтаксис файлів hosts.", "system_host_files": "Системні hosts-файли", @@ -210,11 +210,13 @@ "example_comment_hash": "# Також коментар.", "example_regex_meaning": "блокувати доступ до доменів, що відповідають вказаному регулярному виразу.", "example_upstream_regular": "звичайний DNS (через UDP);", + "example_upstream_udp": "звичайний DNS (поверх UDP, з назвою вузла);", "example_upstream_dot": "зашифрований <0>DNS-over-TLS;", "example_upstream_doh": "зашифрований <0>DNS-over-HTTPS;", "example_upstream_doq": "зашифрований <0>DNS-over-QUIC (експериментальний);", "example_upstream_sdns": "<0>DNS Stamps для <1>DNSCrypt або <2>DNS-over-HTTPS серверів;", "example_upstream_tcp": "звичайний DNS (через TCP);", + "example_upstream_tcp_hostname": "звичайний DNS (поверх TCP, з назвою вузла);", "all_lists_up_to_date_toast": "Всі списки вже оновлені", "updated_upstream_dns_toast": "DNS-сервери оновлено", "dns_test_ok_toast": "Вказані DNS сервери працюють правильно", @@ -259,10 +261,10 @@ "query_log_strict_search": "Використовуйте подвійні лапки для точного пошуку", "query_log_retention_confirm": "Ви дійсно хочете змінити час зберігання журналу? Якщо ви зменшите значення, деякі дані будуть втрачені", "anonymize_client_ip": "Анонімізація IP-адреси клієнта", - "anonymize_client_ip_desc": "Не зберігати повну IP-адресу клієнта в журналах і статистиці.", + "anonymize_client_ip_desc": "Не зберігати повну IP-адресу клієнта в журналах і статистиці", "dns_config": "Конфігурація DNS-сервера", "dns_cache_config": "Конфігурація кешу DNS", - "dns_cache_config_desc": "Тут ви можете налаштувати кеш DNS.", + "dns_cache_config_desc": "Тут ви можете налаштувати DNS-кеш", "blocking_mode": "Режим блокування", "default": "Типовий", "nxdomain": "NXDOMAIN", @@ -285,7 +287,7 @@ "form_enter_rate_limit": "Уведіть обмеження швидкості", "rate_limit": "Обмеження швидкості", "edns_enable": "Увімкнути відправку EDNS Client Subnet", - "edns_cs_desc": "Надсилати підмережі клієнтів на DNS-сервери.", + "edns_cs_desc": "Додавати параметр EDNS Client Subnet (ECS) до запитів до upstream-серверів, а також записувати в журнал значення, що надсилаються клієнтами.", "rate_limit_desc": "Кількість запитів в секунду, які може робити один клієнт. Встановлене значення «0» означатиме необмежену кількість.", "blocking_ipv4_desc": "IP-адреса, яку потрібно видати для заблокованого A запиту", "blocking_ipv6_desc": "IP-адреса, яку потрібно видати для заблокованого АААА запиту", @@ -309,7 +311,7 @@ "install_settings_listen": "Мережевий інтерфейс", "install_settings_port": "Порт", "install_settings_interface_link": "Веб-інтерфейс адміністратора AdGuard Home буде доступний за такими адресами:", - "form_error_port": "Уведіть правильне значення порту.", + "form_error_port": "Уведіть правильне значення порту", "install_settings_dns": "DNS-сервер", "install_settings_dns_desc": "Вам потрібно буде налаштувати свої пристрої або маршрутизатор для використання DNS-сервера за такими адресами:", "install_settings_all_interfaces": "Усі інтерфейси", @@ -356,7 +358,7 @@ "open_dashboard": "Відкрити інформаційну панель", "install_saved": "Збережено успішно", "encryption_title": "Шифрування", - "encryption_desc": "Підтримка шифрування (HTTPS/TLS) як для DNS, так і для вебінтерфейсу адміністратора.", + "encryption_desc": "Підтримка шифрування (HTTPS/TLS) як для DNS, так і для вебінтерфейсу адміністратора", "encryption_config_saved": "Конфігурацію шифрування збережено", "encryption_server": "Назва сервера", "encryption_server_enter": "Введіть ваше доменне ім'я", @@ -378,33 +380,34 @@ "encryption_key_input": "Скопіюйте/вставте сюди свій приватний ключ кодований PEM для вашого сертифіката.", "encryption_enable": "Увімкнути шифрування (HTTPS, DNS-over-HTTPS і DNS-over-TLS)", "encryption_enable_desc": "Якщо ввімкнено шифрування, інтерфейс адміністратора AdGuard Home буде працювати через HTTPS, а DNS-сервер буде прослуховувати запити через DNS-over-HTTPS і DNS-over-TLS.", - "encryption_chain_valid": "Ланцюжок довіри сертифікатів дійсний.", - "encryption_chain_invalid": "Ланцюжок довіри сертифікатів не дійсний.", - "encryption_key_valid": "Дійсний {{type}} приватний ключ.", - "encryption_key_invalid": "Недійсний {{type}} приватний ключ.", + "encryption_chain_valid": "Ланцюжок довіри сертифікатів дійсний", + "encryption_chain_invalid": "Ланцюжок довіри сертифікатів не дійсний", + "encryption_key_valid": "Дійсний {{type}} приватний ключ", + "encryption_key_invalid": "Недійсний {{type}} приватний ключ", "encryption_subject": "Обє'кт", "encryption_issuer": "Видавець", "encryption_hostnames": "Назви вузлів", "encryption_reset": "Ви впевнені, що хочете скинути налаштування шифрування?", "topline_expiring_certificate": "Ваш сертифікат SSL скоро закінчиться. Оновіть <0>Налаштування шифрування.", "topline_expired_certificate": "Термін дії вашого сертифіката SSL закінчився. Оновіть <0>Налаштування шифрування.", - "form_error_port_range": "Введіть значення порту в діапазоні 80−65535.", - "form_error_port_unsafe": "Це небезпечний порт.", - "form_error_equal": "Мають бути різні значення.", - "form_error_password": "Паролі не збігаються.", + "form_error_port_range": "Введіть значення порту в діапазоні 80−65535", + "form_error_port_unsafe": "Небезпечний порт", + "form_error_equal": "Мають бути різні значення", + "form_error_password": "Паролі не збігаються", "reset_settings": "Скинути налаштування", "update_announcement": "AdGuard Home {{version}} тепер доступний! <0>Докладніше.", "setup_guide": "Посібник з налаштування", "dns_addresses": "DNS-адреси", "dns_start": "DNS-сервер запускається", - "dns_status_error": "Помилка перевірки стану сервера DNS", + "dns_status_error": "Помилка перевірки стану DNS-сервера", "down": "Недоступний", "fix": "Виправити", "dns_providers": "<0>Список відомих DNS-провайдерів на вибір.", "update_now": "Оновити зараз", "update_failed": "Помилка автоматичного оновлення. Будь ласка, виконайте ці кроки аби оновити вручну.", + "manual_update": "Щоб оновити самостійно, виконайте ці кроки.", "processing_update": "Зачекайте будь ласка, AdGuard Home оновлюється", - "clients_title": "Клієнти", + "clients_title": "Постійні клієнти", "clients_desc": "Налаштуйте пристрої, під'єднані до AdGuard Home", "settings_global": "Загальні", "settings_custom": "Власні", @@ -416,7 +419,7 @@ "client_edit": "Редагувати Клієнта", "client_identifier": "Ідентифікатор", "ip_address": "IP-адреса", - "client_identifier_desc": "Клієнтів можна ідентифікувати за IP-, CIDR-, MAC-адресами або ж за спеціальним клієнтським ідентифікатором (можливий для DoT, DoH та DoQ). <0>Докладніше про ідентифікацію клієнтів.", + "client_identifier_desc": "Клієнтів можна ідентифікувати за IP- чи MAC-адресами, CIDR або ж за спеціальним клієнтським ідентифікатором ClientID (можливий для DoT, DoH та DoQ). <0>Докладніше про ідентифікацію клієнтів.", "form_enter_ip": "Введіть IP", "form_enter_subnet_ip": "Введіть IP-адресу в підмережі «{{cidr}}»", "form_enter_mac": "Введіть MAC", @@ -432,13 +435,13 @@ "client_confirm_delete": "Ви впевнені, що хочете видалити клієнта «{{key}}»?", "list_confirm_delete": "Ви впевнені, що хочете видалити цей список?", "auto_clients_title": "Runtime-клієнти", - "auto_clients_desc": "Дані про клієнтів, які використовують AdGuard Home, але не зберігаються в конфігурації", + "auto_clients_desc": "Клієнти, які використовують AdGuard Home, незалежно від того, чи збережені вони в списку постійних", "access_title": "Налаштування доступу", - "access_desc": "Тут ви можете налаштувати правила доступу для DNS-сервера AdGuard Home.", + "access_desc": "Тут ви можете налаштувати правила доступу для DNS-сервера AdGuard Home", "access_allowed_title": "Дозволені клієнти", - "access_allowed_desc": "Перелік CIDR-, IP-адрес та клієнтських ідентифікаторів. Якщо налаштовано, AdGuard Home прийматиме запити лише від цих клієнтів.", + "access_allowed_desc": "Перелік CIDR, IP-адрес та ClientIDs. Якщо налаштовано, AdGuard Home прийматиме запити лише від цих клієнтів.", "access_disallowed_title": "Заборонені клієнти", - "access_disallowed_desc": "Перелік CIDR-, IP-адрес та клієнтських ідентифікаторів. Якщо налаштовано, AdGuard Home буде скасовувати запити від цих клієнтів. Проте якщо налаштовано список дозволених клієнтів, то це поле проігнорується.", + "access_disallowed_desc": "Перелік CIDR, IP-адрес та ClientIDs. Якщо налаштовано, AdGuard Home буде скасовувати запити від цих клієнтів. Проте якщо налаштовано список Дозволених клієнтів, то це поле проігнорується.", "access_blocked_title": "Заборонені домени", "access_blocked_desc": "Не плутайте з фільтрами. AdGuard Home буде ігнорувати DNS-запити з цими доменами, такі запити навіть не будуть записані до журналу. Ви можете вказати точні доменні імена, замінні знаки та правила фільтрування URL-адрес, наприклад, 'example.org', '*.example.org' або '||example.org^' відповідно.", "access_settings_saved": "Налаштування доступу успішно збережено", @@ -475,7 +478,7 @@ "form_domain": "Введіть доменне ім’я або підстановний знак", "form_answer": "Введіть IP-адресу або доменне ім'я", "form_error_domain_format": "Неправильний формат домену", - "form_error_answer_format": "Неправильний формат відопвіді", + "form_error_answer_format": "Неправильний формат відповіді", "configure": "Налаштувати", "main_settings": "Головні налаштування", "block_services": "Блокувати конкретні сервіси", @@ -499,6 +502,7 @@ "interval_days": "{{count}} день", "interval_days_plural": "{{count}} дні(в)", "domain": "Домен", + "ecs": "ECS", "punycode": "Punycode", "answer": "Відповідь", "filter_added_successfully": "Фільтр успішно додано", @@ -598,14 +602,14 @@ "milliseconds_abbreviation": "мс", "cache_size": "Розмір кешу", "cache_size_desc": "Розмір кешу DNS (у байтах).", - "cache_ttl_min_override": "Замінити мінімальний TTL", - "cache_ttl_max_override": "Замінити максимальний TTL", + "cache_ttl_min_override": "Змінити мінімальний TTL", + "cache_ttl_max_override": "Змінити максимальний TTL", "enter_cache_size": "Введіть розмір кешу (байт)", - "enter_cache_ttl_min_override": "Введіть мінімальний TTL (секунди)", - "enter_cache_ttl_max_override": "Введіть максимальний TTL (секунди)", - "cache_ttl_min_override_desc": "Розширити короткі значення time-to-live (секунди) отримані від основного сервера під час кешування відповідей DNS", - "cache_ttl_max_override_desc": "Встановіть максимальне значення time-to-live (секунди) для записів у кеші DNS", - "ttl_cache_validation": "Мінімальне значення TTL кеш-пам'яті має бути меншим або рівним максимальному значенню", + "enter_cache_ttl_min_override": "Введіть мінімальний TTL (в секундах)", + "enter_cache_ttl_max_override": "Введіть максимальний TTL (в секундах)", + "cache_ttl_min_override_desc": "Збільшити малі TTL-значення (в секундах), отримані від основного сервера під час кешування DNS-відповідей.", + "cache_ttl_max_override_desc": "Встановіть максимальне TTL-значення (в секундах) для записів у DNS-кеші.", + "ttl_cache_validation": "Мінімальне TTL-значення має бути меншим або рівним максимальному значенню", "cache_optimistic": "Оптимістичне кешування", "cache_optimistic_desc": "AdGuard Home буде відповідати з кешу, навіть якщо відповіді в ньому застарілі, а також спробує оновити їх.", "filter_category_general": "Загальні", @@ -627,5 +631,5 @@ "parental_control": "Батьківський контроль", "safe_browsing": "Безпечний перегляд", "served_from_cache": "{{value}} (отримано з кешу)", - "form_error_password_length": "Пароль мусить мати принаймні {{value}} символів." + "form_error_password_length": "Пароль мусить мати принаймні {{value}} символів" } diff --git a/client/src/__locales/vi.json b/client/src/__locales/vi.json index 28ec3b1b..7c9c2fd4 100644 --- a/client/src/__locales/vi.json +++ b/client/src/__locales/vi.json @@ -1,7 +1,7 @@ { "client_settings": "Cài đặt máy khách", - "example_upstream_reserved": "bạn có thể chỉ định DNS ngược tuyến <0>cho một tên miền cụ thể(hoặc nhiều)", - "example_upstream_comment": "Bạn có thể thêm chú thích cụ thể", + "example_upstream_reserved": "ngược dòng <0>cho các miền cụ thể;", + "example_upstream_comment": "một lời bình luận.", "upstream_parallel": "Sử dụng truy vấn song song để tăng tốc độ giải quyết bằng cách truy vấn đồng thời tất cả các máy chủ ngược tuyến", "parallel_requests": "Yêu cầu song song", "load_balancing": "Cân bằng tải", @@ -36,14 +36,23 @@ "dhcp_ipv4_settings": "Cài đặt DHCP IPv4", "dhcp_ipv6_settings": "Cài đặt DHCP IPv6", "form_error_required": "Trường bắt buộc", - "form_error_ip4_format": "Định dạng IPv4 không hợp lệ", - "form_error_ip6_format": "Định dạng IPv6 không hợp lệ", + "form_error_ip4_format": "Địa chỉ IPv4 không hợp lệ", + "form_error_ip4_range_start_format": "Địa chỉ IPv4 không hợp lệ của phạm vi bắt đầu", + "form_error_ip4_range_end_format": "Địa chỉ IPv4 không hợp lệ của cuối phạm vi", + "form_error_ip4_gateway_format": "Địa chỉ IPv4 không hợp lệ của cổng kết nối", + "form_error_ip6_format": "Địa chỉ IPv6 không hợp lệ", "form_error_ip_format": "Địa chỉ IP không hợp lệ", - "form_error_mac_format": "Định dạng MAC không hợp lệ", - "form_error_client_id_format": "Định dạng client ID không hợp lệ", + "form_error_mac_format": "Địa chỉ MAC không hợp lệ", + "form_error_client_id_format": "ClientID chỉ được chứa số, chữ thường và dấu gạch nối", "form_error_server_name": "Tên máy chủ không hợp lệ", "form_error_subnet": "Mạng con \"{{cidr}}\" không chứa địa chỉ IP \"{{ip}}\"", "form_error_positive": "Phải lớn hơn 0", + "out_of_range_error": "Phải nằm ngoài phạm vi \"{{start}}\"-\"{{end}}\"", + "lower_range_start_error": "Phải thấp hơn khởi động phạm vi", + "greater_range_start_error": "Phải lớn hơn khoảng bắt đầu", + "greater_range_end_error": "Phải lớn hơn phạm vi kết thúc", + "subnet_error": "Địa chỉ phải nằm trong một mạng con", + "gateway_or_subnet_invalid": "Mặt nạ mạng con không hợp lệ", "dhcp_form_gateway_input": "Cổng IP", "dhcp_form_subnet_input": "Mặt nạ mạng con", "dhcp_form_range_title": "Phạm vi của địa chỉ IP", @@ -58,7 +67,7 @@ "dhcp_table_hostname": "Tên máy chủ", "dhcp_table_expires": "Hết hạn", "dhcp_warning": "Nếu bạn vẫn muốn bật máy chủ DHCP, hãy đảm bảo rằng không có máy chủ DHCP hoạt động nào khác trong mạng của bạn. Nếu không, nó có thể phá vỡ Internet cho các thiết bị được kết nối!", - "dhcp_error": "Chúng tôi không thể xác định liệu có một máy chủ DHCP khác trong mạng hay không.", + "dhcp_error": "Chúng tôi không thể xác định liệu có một máy chủ DHCP khác trong mạng hay không", "dhcp_static_ip_error": "Để sử dụng máy chủ DHCP, phải đặt địa chỉ IP tĩnh. Chúng tôi không thể xác định xem giao diện mạng này có được cấu hình bằng địa chỉ IP tĩnh hay không. Vui lòng đặt địa chỉ IP tĩnh theo cách thủ công.", "dhcp_dynamic_ip_found": "Hệ thống của bạn sử dụng cấu hình địa chỉ IP động cho giao diện <0>{{interfaceName}}. Để sử dụng máy chủ DHCP, phải đặt địa chỉ IP tĩnh. Địa chỉ IP hiện tại của bạn là <0>{{ipAddress}}. Chúng tôi sẽ tự động đặt địa chỉ IP này thành tĩnh nếu bạn nhấn nút Bật DHCP.", "dhcp_lease_added": "Cho thuê tĩnh \"{{key}}\" đã được thêm thành công", @@ -191,20 +200,23 @@ "form_error_url_or_path_format": "Định dạng URL hoặc đường dẫn tới danh sách không hợp lệ", "custom_filter_rules": "Quy tắc lọc tuỳ chỉnh", "custom_filter_rules_hint": "Nhập mỗi quy tắc 1 dòng. Có thể sử dụng quy tắc chặn quảng cáo hoặc cú pháp file host", + "system_host_files": "Hệ thống lưu trữ tệp", "examples_title": "Ví dụ", - "example_meaning_filter_block": "Chặn truy cập tới tên miền example.org và tất cả tên miền con", - "example_meaning_filter_whitelist": "Không chặn truy cập tới tên miền example.org và tất cả tên miền con", - "example_meaning_host_block": "AdGuard Home sẽ phản hồi địa chỉ IP 127.0.0.1 cho tên miền example.org (không áp dụng tên miền con)", - "example_comment": "! Đây là một chú thích", - "example_comment_meaning": "Chỉ là một chú thích", - "example_comment_hash": "# Cũng là một chú thích", - "example_regex_meaning": "chặn quyền truy cập vào các miền khớp với <0>biểu thức chính được quy định", - "example_upstream_regular": "DNS thông thường (dùng UDP)", - "example_upstream_dot": "được mã hoá <0>DNS-over-TLS", - "example_upstream_doh": "được mã hoá <0>DNS-over-HTTPS", - "example_upstream_doq": "được mã hoá <0>DNS-over-QUIC", + "example_meaning_filter_block": "chặn truy cập tới tên miền example.org và tất cả tên miền con;", + "example_meaning_filter_whitelist": "không chặn truy cập tới tên miền example.org và tất cả tên miền con;", + "example_meaning_host_block": "hồi địa chỉ IP 127.0.0.1 cho tên miền example.org (không áp dụng tên miền con);", + "example_comment": "! Đây là một chú thích.", + "example_comment_meaning": "chỉ là một chú thích;", + "example_comment_hash": "# Cũng là một chú thích.", + "example_regex_meaning": "chặn quyền truy cập vào các miền khớp với biểu thức chính được quy định.", + "example_upstream_regular": "DNS thông thường (dùng UDP);", + "example_upstream_udp": "DNS thông thường (qua UDP, tên máy chủ);", + "example_upstream_dot": "được mã hoá <0>DNS-over-TLS;", + "example_upstream_doh": "được mã hoá <0>DNS-over-HTTPS;", + "example_upstream_doq": "được mã hoá <0>DNS-over-QUIC (thử nghiệm);", "example_upstream_sdns": "bạn có thể sử dụng <0>DNS Stamps for <1>DNSCrypt hoặc <2>DNS-over-HTTPS ", - "example_upstream_tcp": "DNS thông thường(dùng TCP)", + "example_upstream_tcp": "DNS thông thường(dùng TCP);", + "example_upstream_tcp_hostname": "DNS thông thường (qua TCP, tên máy chủ);", "all_lists_up_to_date_toast": "Tất cả danh sách đã ở phiên bản mới nhất", "updated_upstream_dns_toast": "Các máy chủ thượng nguồn đã được lưu thành công", "dns_test_ok_toast": "Máy chủ DNS có thể sử dụng", @@ -265,9 +277,9 @@ "dns_over_https": "DNS-over-HTTPS", "dns_over_tls": "DNS-over-TLS", "dns_over_quic": "DNS-over-QUIC", - "client_id": "ID khách hàng", - "client_id_placeholder": "Nhập ID khách hàng", - "client_id_desc": "Các khách hàng khác nhau có thể được xác định bằng một ID khách hàng đặc biệt. Tại đây bạn có thể tìm hiểu thêm về cách xác định khách hàng.", + "client_id": "ClientID", + "client_id_placeholder": "Nhập một ClientID", + "client_id_desc": "Khách hàng có thể được xác định bằng ClientID. Tìm hiểu thêm về cách xác định khách hàng tại đây .", "download_mobileconfig_doh": "Tải xuống .mobileconfig cho DNS-over-HTTPS", "download_mobileconfig_dot": "Tải xuống .mobileconfig cho DNS-over-TLS", "download_mobileconfig": "Tải xuống tệp cấu hình", @@ -275,7 +287,7 @@ "form_enter_rate_limit": "Nhập giới hạn yêu cầu", "rate_limit": "Giới hạn yêu cầu", "edns_enable": "Bật mạng con EDNS Client", - "edns_cs_desc": "Nếu được bật, AdGuard Home sẽ gửi các mạng con của khách hàng đến các máy chủ DNS.", + "edns_cs_desc": "Thêm tùy chọn EDNS Client Subnet (ECS) vào các yêu cầu ngược dòng và ghi lại các giá trị được gửi bởi các máy khách trong nhật ký truy vấn.", "rate_limit_desc": "Số lượng yêu cầu mỗi giây mà một khách hàng được phép thực hiện (0: không giới hạn)", "blocking_ipv4_desc": "Địa chỉ IP được trả lại cho một yêu cầu A bị chặn", "blocking_ipv6_desc": "Địa chỉ IP được trả lại cho một yêu cầu AAA bị chặn", @@ -299,12 +311,12 @@ "install_settings_listen": "Giao diện nghe", "install_settings_port": "Cổng", "install_settings_interface_link": "Giao diện web quản trị viên AdGuard Home của bạn sẽ có sẵn trên các địa chỉ sau:", - "form_error_port": "Nhập giá trị cổng hợp lệ", + "form_error_port": "Nhập số cổng hợp lệ", "install_settings_dns": "Máy chủ DNS", "install_settings_dns_desc": "Bạn sẽ cần định cấu hình thiết bị hoặc bộ định tuyến của mình để sử dụng máy chủ DNS trên các địa chỉ sau:", "install_settings_all_interfaces": "Tất cả các giao diện", "install_auth_title": "Xác thực", - "install_auth_desc": "Rất khuyến khích cấu hình xác thực mật khẩu cho giao diện web quản trị viên AdGuard Home của bạn. Ngay cả khi nó chỉ có thể truy cập được trong mạng cục bộ của bạn, điều quan trọng là phải bảo vệ nó khỏi sự truy cập không hạn chế.", + "install_auth_desc": "Xác thực mật khẩu cho giao diện web quản trị AdGuard Home của bạn phải được định cấu hình. Ngay cả khi AdGuard Home chỉ có thể truy cập được trong mạng cục bộ của bạn, điều quan trọng vẫn là bảo vệ nó khỏi quyền truy cập không hạn chế.", "install_auth_username": "Tên đăng nhập", "install_auth_password": "Mật khẩu", "install_auth_confirm": "Xác nhận mật khẩu", @@ -346,7 +358,7 @@ "open_dashboard": "Mở bảng điều khiển", "install_saved": "Lưu thành công", "encryption_title": "Mã hóa", - "encryption_desc": "Hỗ trợ mã hóa (HTTPS/TLS) cho cả giao diện web quản trị viên và DNS", + "encryption_desc": "Hỗ trợ mã hóa (HTTPS/QUIC/TLS) cho cả giao diện web quản trị viên và DNS", "encryption_config_saved": "Đã lưu cấu hình mã hóa", "encryption_server": "Tên máy chủ", "encryption_server_enter": "Nhập tên miền của bạn", @@ -357,7 +369,7 @@ "encryption_https_desc": "Nếu cổng HTTPS được định cấu hình, giao diện quản trị viên AdGuard Home sẽ có thể truy cập thông qua HTTPS và nó cũng sẽ cung cấp DNS-over-HTTPS trên vị trí '/dns-query'.", "encryption_dot": "Cổng DNS-over-TLS", "encryption_dot_desc": "Nếu cổng này được định cấu hình, AdGuard Home sẽ chạy máy chủ DNS-over-TLS trên cổng này.", - "encryption_doq": "Cổng DNS-over-QUIC", + "encryption_doq": "Cổng DNS-over-QUIC (thử nghiệm)", "encryption_doq_desc": "Nếu cổng này được định cấu hình, AdGuard Home sẽ chạy máy chủ DNS qua QUIC trên cổng này. Đó là thử nghiệm và có thể không đáng tin cậy. Ngoài ra, không có quá nhiều khách hàng hỗ trợ nó vào lúc này.", "encryption_certificates": "Chứng chỉ", "encryption_certificates_desc": "Để sử dụng mã hóa, bạn cần cung cấp chuỗi chứng chỉ SSL hợp lệ cho miền của mình. Bạn có thể nhận chứng chỉ miễn phí trên <0>{{link}} hoặc bạn có thể mua chứng chỉ từ một trong các Cơ Quan Chứng Nhận tin cậy.", @@ -370,8 +382,8 @@ "encryption_enable_desc": "Nếu mã hóa được bật, giao diện quản trị viên AdGuard Home sẽ hoạt động trên HTTPS và máy chủ DNS sẽ lắng nghe các yêu cầu qua DNS-over-HTTPS và DNS-over-TLS.", "encryption_chain_valid": "Chứng chỉ hợp lệ", "encryption_chain_invalid": "Chứng chỉ không hợp lệ", - "encryption_key_valid": "Đây là khóa riêng {{type}} hợp lệ", - "encryption_key_invalid": "Đây là khóa riêng {{type}} không hợp lệ", + "encryption_key_valid": "Khóa riêng {{type}} hợp lệ", + "encryption_key_invalid": "Khóa riêng {{type}} không hợp lệ", "encryption_subject": "Chủ đề", "encryption_issuer": "Phát hành", "encryption_hostnames": "Tên máy chủ", @@ -393,9 +405,10 @@ "dns_providers": "Dưới đây là một <0>danh sách của các nhà cung cấp DNS đã biết để lựa chọn.", "update_now": "Cập nhật ngay", "update_failed": "Tự động cập nhật thất bại. Vui lòng làm theo các bước để cập nhật thủ công.", + "manual_update": "Vui lòng làm theo các bước này để cập nhật thủ công.", "processing_update": "Xin vui lòng chờ, AdGuard Home đang được cập nhật", - "clients_title": "Máy khách", - "clients_desc": "Định cấu hình thiết bị được kết nối với AdGuard Home", + "clients_title": "Khách hàng lâu dài", + "clients_desc": "Định cấu hình hồ sơ khách hàng liên tục cho các thiết bị được kết nối với AdGuard Home", "settings_global": "Toàn cầu", "settings_custom": "Tùy chỉnh", "table_client": "Máy khách", @@ -406,7 +419,7 @@ "client_edit": "Chỉnh Sửa Máy Khách", "client_identifier": "Định danh", "ip_address": "Địa chỉ IP", - "client_identifier_desc": "Các máy khách có thể được xác định bằng địa chỉ IP, CIDR, địa chỉ MAC hoặc một ID khách đặc biệt(có thể được dùng cho DoT/DoH/DoQ). Xem thêm cách xác định máy khách tại <0>đây.", + "client_identifier_desc": "Khách hàng có thể được xác định bằng địa chỉ IP, CIDR, địa chỉ MAC hoặc ClientID (có thể được sử dụng cho DoT / DoH / DoQ). Tìm hiểu thêm về cách xác định khách hàng <0>tại đây.", "form_enter_ip": "Nhập IP", "form_enter_subnet_ip": "Nhập địa chỉ IP vào mạng con \"{{cidr}}\"", "form_enter_mac": "Nhập MAC", @@ -422,13 +435,13 @@ "client_confirm_delete": "Bạn có chắc chắn muốn xóa máy khách \"{{key}}\" không?", "list_confirm_delete": "Bạn có muốn xóa bộ lọc này?", "auto_clients_title": "Máy khách (thời gian chạy)", - "auto_clients_desc": "Dữ liệu trên các máy khách sử dụng AdGuard Home, nhưng không được lưu trong cấu hình", + "auto_clients_desc": "Các thiết bị không có trong danh sách khách hàng ổn định vẫn có thể sử dụng AdGuard Home", "access_title": "Cài đặt truy cập", - "access_desc": "Tại đây bạn có thể định cấu hình quy tắc truy cập cho máy chủ AdGuard Home DNS.", + "access_desc": "Tại đây bạn có thể định cấu hình quy tắc truy cập cho máy chủ AdGuard Home DNS", "access_allowed_title": "Máy chủ được phép", - "access_allowed_desc": "Một danh sách các địa chỉ CIDR hoặc IP. Nếu được định cấu hình, AdGuard Home sẽ chỉ chấp nhận các yêu cầu từ các địa chỉ IP này.", + "access_allowed_desc": "Danh sách CIDR, địa chỉ IP hoặc ClientID. Nếu danh sách này có các mục nhập, AdGuard Home sẽ chỉ chấp nhận yêu cầu từ những khách hàng này.", "access_disallowed_title": "Máy chủ không được phép", - "access_disallowed_desc": "Một danh sách các địa chỉ CIDR hoặc IP. Nếu được định cấu hình, AdGuard Home sẽ bỏ yêu cầu từ các địa chỉ IP này.", + "access_disallowed_desc": "Danh sách CIDR, địa chỉ IP hoặc ClientID. Nếu danh sách này có các mục nhập, AdGuard Home sẽ loại bỏ các yêu cầu từ những khách hàng này. Trường này bị bỏ qua nếu có các mục nhập trong máy khách Được phép.", "access_blocked_title": "Tên miền bị chặn", "access_blocked_desc": "Đừng nhầm lẫn điều này với các bộ lọc. AdGuard Home sẽ bỏ các truy vấn DNS với các tên miền này trong câu hỏi của truy vấn.", "access_settings_saved": "Cài đặt truy cập đã lưu thành công", @@ -489,6 +502,7 @@ "interval_days": "{{count}} ngày", "interval_days_plural": "{{count}} ngày", "domain": "Tên miền", + "ecs": "ECS", "punycode": "Punycode", "answer": "Trả lời", "filter_added_successfully": "Thêm bộ lọc thành công", @@ -521,7 +535,7 @@ "netname": "Tên mạng", "network": "Mạng", "descr": "Mô tả", - "whois": "Whois", + "whois": "WHOIS", "filtering_rules_learn_more": "<0>Tìm hiểu thêm về việc tạo danh sách chặn máy chủ của riêng bạn.", "blocked_by_response": "Chặn bởi CNAME hoặc địa IP ở phản hồi", "blocked_by_cname_or_ip": "Đã bị chặn bởi CNAME hoặc IP", @@ -541,10 +555,10 @@ "autofix_warning_list": "Nó sẽ thực hiện các tác vụ sau: <0> Hủy kích hoạt hệ thống DNSStubListener <0> Đặt địa chỉ máy chủ DNS thành 127.0.0.1 <0> Thay thế mục tiêu liên kết tượng trưng của /etc/resolv.conf bằng / run / systemd /resolve/resolv.conf <0> Dừng DNSStubListener (tải lại dịch vụ do hệ thống phân giải) ", "autofix_warning_result": "Do đó, tất cả các yêu cầu DNS từ hệ thống của bạn sẽ được AdGuard Home xử lý theo mặc định.", "tags_title": "Thẻ", - "tags_desc": "Bạn có thể chọn các thẻ tương ứng với khách hàng. Thẻ có thể được bao gồm trong các quy tắc lọc và cho phép bạn áp dụng chúng chính xác hơn. <0>Tìm hiểu thêm", + "tags_desc": "Bạn có thể chọn các thẻ tương ứng với máy khách. Bao gồm các thẻ trong các quy tắc lọc để áp dụng chúng chính xác hơn. <0>Tìm hiểu thêm.", "form_select_tags": "Chọn thẻ khách hàng", "check_title": "Kiểm tra bộ lọc", - "check_desc": "Kiểm tra xem tên miền có tồn tại trong các bộ lọc không", + "check_desc": "Kiểm tra xem tên miền có tồn tại trong các bộ lọc không.", "check": "Kiểm tra", "form_enter_host": "Nhập tên máy chủ", "filtered_custom_rules": "Được lọc bởi các quy tắc lọc tùy chỉnh", @@ -583,19 +597,21 @@ "allowed": "Được phép", "filtered": "Đã lọc", "rewritten": "Đã viết lại", - "safe_search": "Kích hoạt Tìm kiếm An toàn", + "safe_search": "Tìm kiếm an toàn", "blocklist": "Danh sách chặn", "milliseconds_abbreviation": "ms", "cache_size": "Kích thước cache", - "cache_size_desc": "Kích thước cache DNS (bytes)", + "cache_size_desc": "Kích thước cache DNS (bytes).", "cache_ttl_min_override": "Ghi đè TTL tối thiểu", "cache_ttl_max_override": "Ghi đè TTL tối đa", "enter_cache_size": "Nhập kích thước bộ nhớ cache (byte)", "enter_cache_ttl_min_override": "Nhập TTL tối thiểu (giây)", "enter_cache_ttl_max_override": "Nhập TTL tối đa (giây)", - "cache_ttl_min_override_desc": "Mở rộng giá trị thời gian tồn tại ngắn (giây) nhận được từ máy chủ ngược dòng khi phản hồi DNS vào bộ nhớ đệm", - "cache_ttl_max_override_desc": "Đặt giá trị thời gian tồn tại tối đa (giây) cho các mục nhập trong bộ nhớ cache DNS", + "cache_ttl_min_override_desc": "Mở rộng giá trị thời gian tồn tại ngắn (giây) nhận được từ máy chủ ngược dòng khi phản hồi DNS vào bộ nhớ đệm.", + "cache_ttl_max_override_desc": "Đặt giá trị thời gian tồn tại tối đa (giây) cho các mục nhập trong bộ nhớ cache DNS.", "ttl_cache_validation": "Giá trị TTL trong bộ nhớ cache tối thiểu phải nhỏ hơn hoặc bằng giá trị lớn nhất", + "cache_optimistic": "Bộ nhớ đệm lạc quan", + "cache_optimistic_desc": "Làm cho AdGuard Home phản hồi từ bộ nhớ cache ngay cả khi các mục nhập đã hết hạn và cố gắng làm mới chúng.", "filter_category_general": "Chung", "filter_category_security": "Bảo mật", "filter_category_regional": "Khu vực", @@ -611,5 +627,9 @@ "adg_will_drop_dns_queries": "AdGuard Home sẽ loại bỏ tất cả các truy vấn DNS từ ứng dụng khách này.", "filter_allowlist": "CẢNH BÁO: Hành động này cũng sẽ loại trừ quy tắc \"{{disallowed_rule}}\" khỏi danh sách các ứng dụng khách được phép.", "last_rule_in_allowlist": "Không thể không cho phép ứng dụng khách này vì việc loại trừ quy tắc \"{{disallowed_rule}}\" sẽ TẮT danh sách \"Ứng dụng khách được phép\".", - "parental_control": "Quản lý của phụ huynh" + "use_saved_key": "Sử dụng khóa đã lưu trước đó", + "parental_control": "Quản lý của phụ huynh", + "safe_browsing": "Duyệt web an toàn", + "served_from_cache": "{{value}} (được phục vụ từ bộ nhớ cache)", + "form_error_password_length": "Mật khẩu phải có ít nhất {{value}} ký tự" } diff --git a/client/src/__locales/zh-cn.json b/client/src/__locales/zh-cn.json index dce4be31..69d5b8b0 100644 --- a/client/src/__locales/zh-cn.json +++ b/client/src/__locales/zh-cn.json @@ -35,24 +35,24 @@ "dhcp_config_saved": "已成功保存 DHCP 服务器配置", "dhcp_ipv4_settings": "DHCP IPv4设置", "dhcp_ipv6_settings": "DHCP IPv6设置", - "form_error_required": "必填字段。", - "form_error_ip4_format": "无效的 IPv4 地址。", - "form_error_ip4_range_start_format": "范围起始值的 IPv4 地址无效。", - "form_error_ip4_range_end_format": "范围终值的 IPv4 地址无效。", - "form_error_ip4_gateway_format": "网关 IPv4 格式无效。", - "form_error_ip6_format": "无效的 IPv6 地址。", - "form_error_ip_format": "无效的 IP 地址。", - "form_error_mac_format": "无效的 MAC 地址。", - "form_error_client_id_format": "客户端 ID 必须只包含数字、小写字母和连字符。", - "form_error_server_name": "无效的服务器名。", - "form_error_subnet": "子网 \"{{cidr}}\" 不包含 IP 地址 \"{{ip}}\"。", - "form_error_positive": "必须大于 0。", - "out_of_range_error": "必定超出了范围 \"{{start}}\"-\"{{end}}\"。", - "lower_range_start_error": "必须小于范围起始值。", - "greater_range_start_error": "必须大于范围起始值。", - "greater_range_end_error": "必须大于范围终值。", - "subnet_error": "地址必须在一个子网内。", - "gateway_or_subnet_invalid": "子网掩码无效。", + "form_error_required": "必填字段", + "form_error_ip4_format": "无效的 IPv4 地址", + "form_error_ip4_range_start_format": "范围起始值的 IPv4 地址无效", + "form_error_ip4_range_end_format": "范围终值的 IPv4 地址无效", + "form_error_ip4_gateway_format": "网关 IPv4 地址无效", + "form_error_ip6_format": "无效的 IPv6 地址", + "form_error_ip_format": "无效的 IP 地址", + "form_error_mac_format": "无效的 MAC 地址", + "form_error_client_id_format": "客户端 ID 必须只包含数字、小写字母和连字符", + "form_error_server_name": "无效的服务器名", + "form_error_subnet": "子网 \"{{cidr}}\" 不包含 IP 地址 \"{{ip}}\"", + "form_error_positive": "必须大于 0", + "out_of_range_error": "必定超出了范围 \"{{start}}\"-\"{{end}}\"", + "lower_range_start_error": "必须小于范围起始值", + "greater_range_start_error": "必须大于范围起始值", + "greater_range_end_error": "必须大于范围终值", + "subnet_error": "地址必须在一个子网内", + "gateway_or_subnet_invalid": "子网掩码无效", "dhcp_form_gateway_input": "网关 IP", "dhcp_form_subnet_input": "子网掩码", "dhcp_form_range_title": "IP 地址范围", @@ -67,7 +67,7 @@ "dhcp_table_hostname": "主机名", "dhcp_table_expires": "到期", "dhcp_warning": "如果你想要启用内置的 DHCP 服务器,请确保在当前网络中没有其它起作用的 DHCP 服务器。否则,此操作可能会破坏已连接设备的网络连接!", - "dhcp_error": "AdGuard Home 无法确定在当前网络中是否存在其它 DHCP 服务器。", + "dhcp_error": "AdGuard Home 无法确定在当前网络中是否存在其它 DHCP 服务器", "dhcp_static_ip_error": "要使用 DHCP 服务器,则必须设置静态 IP 地址。AdGuard Home 无法确定此网络接口是否已被配置为使用静态 IP 地址。请手动为此网络接口设置静态 IP 地址。", "dhcp_dynamic_ip_found": "您的系统对网络接口 <0>{{interfaceName}} 使用了动态 IP 地址配置。要使用 DHCP 服务器,则必须对此网络接口使用静态 IP 地址配置。此网络接口当前的 IP 地址为 <0>{{ipAddress}}。如您点击“启用 DHCP 服务器” 按钮,AdGuard Home 将自动修改此网络接口以使用静态 IP 地址。", "dhcp_lease_added": "静态租约 \"{{key}}\" 已成功添加", @@ -196,8 +196,8 @@ "choose_allowlist": "选择允许列表", "enter_valid_blocklist": "输入有效的阻止列表URL", "enter_valid_allowlist": "输入有效的允许列表URL", - "form_error_url_format": "无效的 URL 格式。", - "form_error_url_or_path_format": "无效的 URL 或列表的绝对路径。", + "form_error_url_format": "无效的 URL 格式", + "form_error_url_or_path_format": "无效的 URL 或列表的绝对路径", "custom_filter_rules": "自定义过滤器规则", "custom_filter_rules_hint": "请确保每行只输入一条规则。你可以输入符合 adblock 语法或 Hosts 语法的规则。", "system_host_files": "系统主机文件", @@ -210,11 +210,13 @@ "example_comment_hash": "# 这也是一行注释。", "example_regex_meaning": "阻止访问与指定的正则表达式匹配的域名。", "example_upstream_regular": "常规 DNS(基于 UDP);", + "example_upstream_udp": "常规 DNS(通过 UDP、主机名);", "example_upstream_dot": "加密 <0>DNS-over-TLS;", "example_upstream_doh": "加密 <0>DNS-over-HTTPS;", "example_upstream_doq": "加密 <0>DNS-over-QUIC(实验性的);", "example_upstream_sdns": "<1>DNSCrypt 的 <0>DNS Stamps 或者 <2>DNS-over-HTTPS 解析器;", "example_upstream_tcp": "常规 DNS(基于 TCP );", + "example_upstream_tcp_hostname": "常规 DNS(通过 TCP、主机名);", "all_lists_up_to_date_toast": "所有列表都是最新的", "updated_upstream_dns_toast": "上游服务器保存成功", "dns_test_ok_toast": "指定的 DNS 服务器现已正常运行", @@ -259,10 +261,10 @@ "query_log_strict_search": "使用双引号进行严谨搜索", "query_log_retention_confirm": "您确定要更改查询记录保留时间吗? 如果您减少间隔时间的值, 某些数据可能会丢失。", "anonymize_client_ip": "匿名化客户端IP", - "anonymize_client_ip_desc": "不要在日志和统计信息中保存客户端的完整 IP 地址。", + "anonymize_client_ip_desc": "不要在日志和统计信息中保存客户端的完整 IP 地址", "dns_config": "DNS 服务配置", "dns_cache_config": "DNS缓存配置", - "dns_cache_config_desc": "您可以在此处配置 DNS 缓存。", + "dns_cache_config_desc": "您可以在此处配置 DNS 缓存", "blocking_mode": "拦截模式", "default": "默认", "nxdomain": "无效域名", @@ -285,7 +287,7 @@ "form_enter_rate_limit": "输入限制速率", "rate_limit": "速度限制", "edns_enable": "启用 EDNS 客户端子网", - "edns_cs_desc": "将客户端子网发送至 DNS 服务器。", + "edns_cs_desc": "在上游请求中加入 EDNS 客户端子网(“EDNS Client Subnet”,即 ECS)选项,并在查询日志中记录客户端发送的数值。", "rate_limit_desc": "每个客户端每秒钟查询次数的限制。设置为 0 意味着不限制。", "blocking_ipv4_desc": "拦截 A 记录请求返回的 IP 地址", "blocking_ipv6_desc": "拦截 AAAA 记录请求返回的 IP 地址", @@ -309,7 +311,7 @@ "install_settings_listen": "监听接口", "install_settings_port": "端口", "install_settings_interface_link": "您可以通过以下地址访问您的 AdGuard Home 网页管理界面:", - "form_error_port": "输入有效的端口值。", + "form_error_port": "输入有效的端口值", "install_settings_dns": "DNS 服务器", "install_settings_dns_desc": "您将需要使用以下地址来设置您的设备或路由器的 DNS 服务器:", "install_settings_all_interfaces": "所有接口", @@ -356,7 +358,7 @@ "open_dashboard": "打开仪表盘", "install_saved": "保存成功", "encryption_title": "加密", - "encryption_desc": "为 DNS 与网页管理界面启用加密(HTTPS/TLS)。", + "encryption_desc": "为 DNS 与网页管理界面启用加密(HTTPS/QUIC/TLS)", "encryption_config_saved": "加密配置已保存", "encryption_server": "服务器名称", "encryption_server_enter": "输入您的域名", @@ -378,26 +380,26 @@ "encryption_key_input": "将您以 PEM 格式编码的证书私钥复制粘贴到此处。", "encryption_enable": "启用加密(HTTPS、DNS-over-HTTPS、DNS-over-TLS)", "encryption_enable_desc": "如果启用加密选项,AdGuard Home 的网页管理界面将通过 HTTPS 连接访问,同时 DNS 服务器将监听通过 DNS-over-HTTPS 与 DNS-over-TLS 发送的请求。", - "encryption_chain_valid": "证书链有效。", - "encryption_chain_invalid": "证书链无效。", - "encryption_key_valid": "该 {{type}} 私钥有效。", - "encryption_key_invalid": "该 {{type}} 私钥无效。", + "encryption_chain_valid": "证书链有效", + "encryption_chain_invalid": "证书链无效", + "encryption_key_valid": "该 {{type}} 私钥有效", + "encryption_key_invalid": "该 {{type}} 私钥无效", "encryption_subject": "使用者", "encryption_issuer": "颁发者", "encryption_hostnames": "主机名", "encryption_reset": "您确定想要重置加密设置?", "topline_expiring_certificate": "您的 SSL 证书即将过期。请更新 <0>加密设置 。", "topline_expired_certificate": "您的 SSL 证书已过期。请更新 <0>加密设置 。", - "form_error_port_range": "输入 80 - 65535 范围内的端口值。", - "form_error_port_unsafe": "这是一个不安全的端口。", - "form_error_equal": "不可相同。", - "form_error_password": "密码不匹配。", + "form_error_port_range": "输入 80 - 65535 范围内的端口值", + "form_error_port_unsafe": "这是一个不安全的端口", + "form_error_equal": "不可相同", + "form_error_password": "密码不匹配", "reset_settings": "重置设置", "update_announcement": "AdGuard Home {{version}} 现已发布! <0>点击此处 以获取详细信息。", "setup_guide": "设置指导", "dns_addresses": "DNS 地址", "dns_start": "正在启动DNS服务", - "dns_status_error": "检查 DNS 服务器状态时出错。", + "dns_status_error": "检查 DNS 服务器状态时出错", "down": "下移", "fix": "修复", "dns_providers": "此为可从中选择的<0>已知 DNS 提供商列表。", @@ -406,7 +408,7 @@ "manual_update": "请跟随此步骤以进行手动更新。", "processing_update": "正在更新 AdGuard Home,请稍侯", "clients_title": "持久客户端", - "clients_desc": "配置已连接到 AdGuard Home 的设备的持久客户端记录。", + "clients_desc": "配置已连接到 AdGuard Home 的设备的持久客户端记录", "settings_global": "全局", "settings_custom": "自定义", "table_client": "客户端", @@ -435,7 +437,7 @@ "auto_clients_title": "客户端(运行时间)", "auto_clients_desc": "不在可继续使用 AdGuard Home 的持久客户端列表中的设备。", "access_title": "访问设置", - "access_desc": "您可在此处配置 AdGuard Home DNS 服务器的访问规则。", + "access_desc": "您可以在此处配置 AdGuard Home 的 DNS 服务器的访问规则", "access_allowed_title": "允许的客户端", "access_allowed_desc": "CIDR、IP 地址或客户端 ID 的列表。如已配置,则 AdGuard Home 将仅接受来自这些客户端的请求。", "access_disallowed_title": "不允许的客户端", @@ -475,8 +477,8 @@ "dns_rewrites": "DNS 重写", "form_domain": "输入域", "form_answer": "输入 IP 地址或域名", - "form_error_domain_format": "无效的网域格式。", - "form_error_answer_format": "无效的响应格式。", + "form_error_domain_format": "无效的域格式", + "form_error_answer_format": "无效的响应格式", "configure": "配置", "main_settings": "主要设置", "block_services": "阻止特定服务", @@ -500,6 +502,7 @@ "interval_days": "{{count}} 天", "interval_days_plural": "{{count}} 天", "domain": "域名", + "ecs": "ECS", "punycode": "Punycode", "answer": "应答", "filter_added_successfully": "已成功添加过滤器", @@ -507,7 +510,7 @@ "filter_updated": "成功更新过滤器", "statistics_configuration": "统计配置", "statistics_retention": "统计保留", - "statistics_retention_desc": "如果您减少该间隔的数值, 某些数据可能会丢失。", + "statistics_retention_desc": "如果您减少该间隔的数值, 某些数据可能会丢失", "statistics_clear": " 清除统计数据", "statistics_clear_confirm": "您确定要清除统计数据?", "statistics_retention_confirm": "您确定要更改统计记录保留时间吗? 如果您减少间隔时间的值, 某些数据可能会丢失。", @@ -606,7 +609,7 @@ "enter_cache_ttl_max_override": "输入最大 TTL 值(秒)", "cache_ttl_min_override_desc": "缓存 DNS 响应时,延长从上游服务器接收到的 TTL 值 (秒)。", "cache_ttl_max_override_desc": "设定 DNS 缓存条目的最大 TTL 值(秒)。", - "ttl_cache_validation": "最小缓存 TTL 值必须小于或等于最大值。", + "ttl_cache_validation": "最小缓存 TTL 值必须小于或等于最大值", "cache_optimistic": "乐观缓存", "cache_optimistic_desc": "即使条目已过期,也让 AdGuard Home 从缓存中响应,并尝试刷新它们。", "filter_category_general": "常规", @@ -628,5 +631,5 @@ "parental_control": "家长控制", "safe_browsing": "安全浏览", "served_from_cache": "{{value}}(由缓存提供)", - "form_error_password_length": "密码必须至少有 {{value}} 个字符。" + "form_error_password_length": "密码必须至少有 {{value}} 个字符" } diff --git a/client/src/__locales/zh-hk.json b/client/src/__locales/zh-hk.json index cae94b69..99028a59 100644 --- a/client/src/__locales/zh-hk.json +++ b/client/src/__locales/zh-hk.json @@ -38,12 +38,18 @@ "form_error_required": "必要欄位", "form_error_ip4_format": "無效的 IPv4 格式", "form_error_ip6_format": "無效的 IPv6 格式", + "form_error_ip4_range_start_format": "無效的 IPv4 範圍起始位址", + "form_error_ip4_range_end_format": "無效的 IPv4 範圍結束位址", + "form_error_ip4_gateway_format": "閘道的 IPv4 位址無效", "form_error_ip_format": "無效的 IP 位址", "form_error_mac_format": "無效的 「MAC 位址」格式", "form_error_client_id_format": "無效的「客戶端 ID」格式", "form_error_server_name": "無效伺服器名稱", "form_error_subnet": "子網路 \"{{cidr}}\" 不包含 IP 位址 \"{{ip}}\"", "form_error_positive": "數值必須大於 0", + "out_of_range_error": "必須介於 \"{{start}}\" - \"{{end}}\" 範圍之外", + "lower_range_start_error": "必須小於起始值", + "greater_range_start_error": "必須大於起始值", "dhcp_form_gateway_input": "閘道 IP 位址", "dhcp_form_subnet_input": "子網路遮罩", "dhcp_form_range_title": "IP 位址範圍", diff --git a/client/src/__locales/zh-tw.json b/client/src/__locales/zh-tw.json index 52bbc4e0..8b1fab72 100644 --- a/client/src/__locales/zh-tw.json +++ b/client/src/__locales/zh-tw.json @@ -35,24 +35,24 @@ "dhcp_config_saved": "動態主機設定協定(DHCP)配置被成功地儲存", "dhcp_ipv4_settings": "DHCP IPv4 設定", "dhcp_ipv6_settings": "DHCP IPv6 設定", - "form_error_required": "必填的欄位。", - "form_error_ip4_format": "無效的 IPv4 位址。", - "form_error_ip4_range_start_format": "無效起始範圍的 IPv4 位址。", - "form_error_ip4_range_end_format": "無效結束範圍的 IPv4 位址。", - "form_error_ip4_gateway_format": "無效閘道的 IPv4 位址。", - "form_error_ip6_format": "無效的 IPv6 位址。", - "form_error_ip_format": "無效的 IP 位址。", - "form_error_mac_format": "無效的媒體存取控制(MAC)位址。", - "form_error_client_id_format": "用戶端 ID 必須只包含數字、小寫字母和連字號。", - "form_error_server_name": "無效的伺服器名稱。", - "form_error_subnet": "子網路 \"{{cidr}}\" 不包含該 IP 位址 \"{{ip}}\"。", - "form_error_positive": "必須大於 0。", - "out_of_range_error": "必須在\"{{start}}\"-\"{{end}}\"範圍之外。", - "lower_range_start_error": "必須低於起始範圍。", - "greater_range_start_error": "必須大於起始範圍。", - "greater_range_end_error": "必須大於結束範圍。", - "subnet_error": "位址必須在子網路中。", - "gateway_or_subnet_invalid": "無效的子網路遮罩。", + "form_error_required": "必填的欄位", + "form_error_ip4_format": "無效的 IPv4 位址", + "form_error_ip4_range_start_format": "無效起始範圍的 IPv4 位址", + "form_error_ip4_range_end_format": "無效結束範圍的 IPv4 位址", + "form_error_ip4_gateway_format": "無效閘道的 IPv4 位址", + "form_error_ip6_format": "無效的 IPv6 位址", + "form_error_ip_format": "無效的 IP 位址", + "form_error_mac_format": "無效的媒體存取控制(MAC)位址", + "form_error_client_id_format": "用戶端 ID 必須只包含數字、小寫字母和連字號", + "form_error_server_name": "無效的伺服器名稱", + "form_error_subnet": "子網路 \"{{cidr}}\" 不包含該 IP 位址 \"{{ip}}\"", + "form_error_positive": "必須大於 0", + "out_of_range_error": "必須在\"{{start}}\"-\"{{end}}\"範圍之外", + "lower_range_start_error": "必須低於起始範圍", + "greater_range_start_error": "必須大於起始範圍", + "greater_range_end_error": "必須大於結束範圍", + "subnet_error": "位址必須在子網路中", + "gateway_or_subnet_invalid": "無效的子網路遮罩", "dhcp_form_gateway_input": "閘道 IP", "dhcp_form_subnet_input": "子網路遮罩", "dhcp_form_range_title": "IP 位址範圍", @@ -67,7 +67,7 @@ "dhcp_table_hostname": "主機名稱", "dhcp_table_expires": "到期", "dhcp_warning": "如果您無論如何想要啟用動態主機設定協定(DHCP)伺服器,確保在您的網路中無其它現行的 DHCP 伺服器,因為對於該網路上的裝置,這可能破壞其網際網路連線!", - "dhcp_error": "AdGuard Home 無法確定於該網路上是否有另外現行的動態主機設定協定(DHCP)伺服器。", + "dhcp_error": "AdGuard Home 無法確定於該網路上是否有另外現行的動態主機設定協定(DHCP)伺服器", "dhcp_static_ip_error": "為了使用動態主機設定協定(DHCP)伺服器,靜態 IP 位址必須被設定。AdGuard Home 未能確定此網路介面是否被配置使用靜態 IP 位址。請手動地設定靜態 IP 位址。", "dhcp_dynamic_ip_found": "您的系統使用動態 IP 位址配置供介面 <0>{{interfaceName}}。為了使用動態主機設定協定(DHCP)伺服器,靜態 IP 位址必須被設定。您現行的 IP 位址為 <0>{{ipAddress}}。如果您按\"啟用 DHCP 伺服器\" 按鈕,AdGuard Home 將自動地設定此 IP 位址作為靜態。", "dhcp_lease_added": "靜態租約 \"{{key}}\" 被成功地加入", @@ -196,8 +196,8 @@ "choose_allowlist": "選擇允許清單", "enter_valid_blocklist": "輸入一個到該封鎖清單之有效的網址。", "enter_valid_allowlist": "輸入一個到該允許清單之有效的網址。", - "form_error_url_format": "無效的網址格式。", - "form_error_url_or_path_format": "該清單之無效的網址或絕對的路徑。", + "form_error_url_format": "無效的網址格式", + "form_error_url_or_path_format": "該清單之無效的網址或絕對的路徑", "custom_filter_rules": "自訂的過濾規則", "custom_filter_rules_hint": "於一行上輸入一項規則。您可使用廣告封鎖規則或主機檔案語法。", "system_host_files": "系統主機檔案", @@ -210,11 +210,13 @@ "example_comment_hash": "# 也是一個註解。", "example_regex_meaning": "封鎖至與該已明確指定的規則運算式(Regular Expression)相符的網域之存取。", "example_upstream_regular": "常規 DNS(透過 UDP);", + "example_upstream_udp": "常規 DNS(透過 UDP,主機名稱);", "example_upstream_dot": "加密的 <0>DNS-over-TLS;", "example_upstream_doh": "加密的 <0>DNS-over-HTTPS;", "example_upstream_doq": "加密的 <0>DNS-over-QUIC(實驗性的);", "example_upstream_sdns": "關於 <1>DNSCrypt 或 <2>DNS-over-HTTPS 解析器之 <0>DNS 戳記;", "example_upstream_tcp": "常規 DNS(透過 TCP);", + "example_upstream_tcp_hostname": "常規 DNS(透過 TCP,主機名稱);", "all_lists_up_to_date_toast": "所有的清單已是最新的", "updated_upstream_dns_toast": "上游的伺服器被成功地儲存", "dns_test_ok_toast": "已明確指定的 DNS 伺服器正在正確地運作", @@ -259,10 +261,10 @@ "query_log_strict_search": "使用雙引號於嚴謹的搜尋", "query_log_retention_confirm": "您確定您想要更改查詢記錄保留嗎?如果您減少該間隔值,某些資料將被丟失", "anonymize_client_ip": "將用戶端 IP 匿名", - "anonymize_client_ip_desc": "不要儲存用戶端之完整的 IP 位址到記錄或統計資料裡。", + "anonymize_client_ip_desc": "不要儲存用戶端之完整的 IP 位址到記錄或統計資料裡", "dns_config": "DNS 伺服器配置", "dns_cache_config": "DNS 快取配置", - "dns_cache_config_desc": "於此您可配置 DNS 快取。", + "dns_cache_config_desc": "於此您可配置 DNS 快取", "blocking_mode": "封鎖模式", "default": "預設", "nxdomain": "不存在的網域(NXDOMAIN)", @@ -285,7 +287,7 @@ "form_enter_rate_limit": "輸入速率限制", "rate_limit": "速率限制", "edns_enable": "啟用對於 DNS 的擴充機制(EDNS)用戶端子網路", - "edns_cs_desc": "傳送用戶端的子網路到該 DNS 伺服器。", + "edns_cs_desc": "新增對於 DNS 的擴充機制(EDNS)用戶端子網路選項到上游的請求,並在查詢記錄中記錄由用戶端傳送的數值。", "rate_limit_desc": "每個用戶端被允許的每秒請求之數量。設定它為 0 表示無限制。", "blocking_ipv4_desc": "要被返回給已封鎖的 A 請求之 IP 位址", "blocking_ipv6_desc": "要被返回給已封鎖的 AAAA 請求之 IP 位址", @@ -309,7 +311,7 @@ "install_settings_listen": "監聽介面", "install_settings_port": "連接埠", "install_settings_interface_link": "您的 AdGuard Home 管理員網路介面將於下列的位址上為可用的:", - "form_error_port": "輸入有效的連接埠號碼。", + "form_error_port": "輸入有效的連接埠號碼", "install_settings_dns": "DNS 伺服器", "install_settings_dns_desc": "您將需要配置您的裝置或路由器以使用於下列的位址上之 DNS 伺服器:", "install_settings_all_interfaces": "所有的介面", @@ -356,7 +358,7 @@ "open_dashboard": "開啟儀表板", "install_saved": "被成功地儲存", "encryption_title": "加密", - "encryption_desc": "供 DNS 和管理員網路介面兩者之加密(HTTPS/TLS)支援。", + "encryption_desc": "供 DNS 和管理員網路介面兩者之加密(HTTPS/TLS)支援", "encryption_config_saved": "加密配置被儲存", "encryption_server": "伺服器名稱", "encryption_server_enter": "輸入您的域名", @@ -378,26 +380,26 @@ "encryption_key_input": "於此複製/貼上您的隱私增強郵件編碼之(PEM-encoded)私密金鑰供您的憑證。", "encryption_enable": "啟用加密(HTTPS、DNS-over-HTTPS 和 DNS-over-TLS)", "encryption_enable_desc": "如果加密被啟用,AdGuard Home 管理員介面透過 HTTPS 將運作,且該 DNS 伺服器將留心監聽透過 DNS-over-HTTPS 和 DNS-over-TLS 之請求。", - "encryption_chain_valid": "憑證鏈結為有效的。", - "encryption_chain_invalid": "憑證鏈結為無效的。", - "encryption_key_valid": "此為有效的 {{type}} 私密金鑰。", - "encryption_key_invalid": "此為無效的 {{type}} 私密金鑰。", + "encryption_chain_valid": "憑證鏈結為有效的", + "encryption_chain_invalid": "憑證鏈結為無效的", + "encryption_key_valid": "此為有效的 {{type}} 私密金鑰", + "encryption_key_invalid": "此為無效的 {{type}} 私密金鑰", "encryption_subject": "物件", "encryption_issuer": "簽發者", "encryption_hostnames": "主機名稱", "encryption_reset": "您確定您想要重置加密設定嗎?", "topline_expiring_certificate": "您的安全通訊端層(SSL)憑證即將到期。更新<0>加密設定。", "topline_expired_certificate": "您的安全通訊端層(SSL)憑證為已到期的。更新<0>加密設定。", - "form_error_port_range": "輸入在 80-65535 之範圍內的連接埠號碼。", - "form_error_port_unsafe": "此為不安全的連接埠。", - "form_error_equal": "必須不為相等的。", - "form_error_password": "不相符的密碼。", + "form_error_port_range": "輸入在 80-65535 之範圍內的連接埠號碼", + "form_error_port_unsafe": "不安全的連接埠", + "form_error_equal": "必須為不相等的", + "form_error_password": "不相符的密碼", "reset_settings": "重置設定", "update_announcement": "AdGuard Home {{version}} 現為可用的!關於更多的資訊,<0>點擊這裡。", "setup_guide": "設置指南", "dns_addresses": "DNS 位址", "dns_start": "DNS 伺服器正在啟動", - "dns_status_error": "檢查 DNS 伺服器狀態出錯。", + "dns_status_error": "檢查 DNS 伺服器狀態出錯", "down": "停止運作的", "fix": "修復", "dns_providers": "這裡是一個從中選擇之<0>已知的 DNS 供應商之清單。", @@ -406,7 +408,7 @@ "manual_update": "請遵循這些步驟以手動地更新。", "processing_update": "請稍候,AdGuard Home 正被更新", "clients_title": "持續性用戶端", - "clients_desc": "配置關於被連線到 AdGuard Home 的裝置之持續性用戶端記錄。", + "clients_desc": "配置關於被連線到 AdGuard Home 的裝置之持續性用戶端記錄", "settings_global": "全域的", "settings_custom": "自訂的", "table_client": "用戶端", @@ -433,9 +435,9 @@ "client_confirm_delete": "您確定您想要刪除用戶端 \"{{key}}\" 嗎?", "list_confirm_delete": "您確定您想要刪除該清單嗎?", "auto_clients_title": "執行時期用戶端", - "auto_clients_desc": "未於可能仍然使用 AdGuard Home 的持續性用戶端之清單上的裝置。", + "auto_clients_desc": "未於可能仍然使用 AdGuard Home 的持續性用戶端之清單上的裝置", "access_title": "存取設定", - "access_desc": "於此您可配置用於 AdGuard Home DNS 伺服器之存取規則。", + "access_desc": "於此您可配置用於 AdGuard Home DNS 伺服器之存取規則", "access_allowed_title": "已允許的用戶端", "access_allowed_desc": "無類別網域間路由(CIDRs)、IP 位址或用戶端 IDs 之清單。如果此清單有項目,AdGuard Home 將接受僅來自這些用戶端的請求。", "access_disallowed_title": "未被允許的用戶端", @@ -475,8 +477,8 @@ "dns_rewrites": "DNS 改寫", "form_domain": "輸入域名或萬用字元(wildcard)", "form_answer": "輸入 IP 位址或域名", - "form_error_domain_format": "無效的網域格式。", - "form_error_answer_format": "無效的回應格式。", + "form_error_domain_format": "無效的網域格式", + "form_error_answer_format": "無效的回應格式", "configure": "配置", "main_settings": "主設定", "block_services": "封鎖特定的服務", @@ -500,6 +502,7 @@ "interval_days": "{{count}} 日", "interval_days_plural": "{{count}} 日", "domain": "網域", + "ecs": "對於 DNS 的擴充機制(EDNS)用戶端子網路", "punycode": "國際化域名代碼(Punycode)", "answer": "回應", "filter_added_successfully": "該清單已被成功地加入", @@ -507,7 +510,7 @@ "filter_updated": "該清單已被成功地更新", "statistics_configuration": "統計資料配置", "statistics_retention": "統計資料保留", - "statistics_retention_desc": "如果您減少該間隔值,某些資料將被丟失。", + "statistics_retention_desc": "如果您減少該間隔值,某些資料將被丟失", "statistics_clear": " 清除統計資料", "statistics_clear_confirm": "您確定您想要清除統計資料嗎?", "statistics_retention_confirm": "您確定您想要更改統計資料保留嗎?如果您減少該間隔值,某些資料將被丟失", @@ -606,7 +609,7 @@ "enter_cache_ttl_max_override": "輸入最大的存活時間(秒)", "cache_ttl_min_override_desc": "當快取 DNS 回應時,延長從上游的伺服器收到的短存活時間數值(秒)。", "cache_ttl_max_override_desc": "設定最大的存活時間數值(秒)供在 DNS 快取中的項目。", - "ttl_cache_validation": "最小的快取存活時間(TTL)覆寫必須小於或等於最大的。", + "ttl_cache_validation": "最小的快取存活時間(TTL)覆寫必須小於或等於最大的", "cache_optimistic": "樂觀快取", "cache_optimistic_desc": "即使當項目為已到期的,從快取使 AdGuard Home 回覆,並還嘗試重新整理它們。", "filter_category_general": "一般的", @@ -628,5 +631,5 @@ "parental_control": "家長控制", "safe_browsing": "安全瀏覽", "served_from_cache": "{{value}} (由快取提供)", - "form_error_password_length": "密碼必須為至少長 {{value}} 個字元。" + "form_error_password_length": "密碼必須為至少長 {{value}} 個字元" } From 5cba78a8d5ca35e33c35ff68ef0b668d78826c7f Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Wed, 23 Mar 2022 16:00:32 +0300 Subject: [PATCH 009/110] Pull request: 4276 upd quic port Merge in DNS/adguard-home from 4276-doq-port to master Closes #4276. Squashed commit of the following: commit cbdde622b54d0d5d11d1b4809f95a41ace990a1b Merge: d32c13e9 2c33ab6a Author: Eugene Burkov Date: Wed Mar 23 15:47:43 2022 +0300 Merge branch 'master' into 4276-doq-port commit d32c13e98f0fed2c863160e4e2de02ae3038e3df Author: Eugene Burkov Date: Mon Mar 21 21:55:09 2022 +0300 all: fix link commit 0afd702f5192d727927df2f8d95b9317811a1be0 Author: Eugene Burkov Date: Mon Mar 21 21:47:38 2022 +0300 all: imp docs, log changes commit 9a77fc3daf78d32c577f1bc49aa1f8bc352d44e3 Author: Eugene Burkov Date: Mon Mar 21 21:41:30 2022 +0300 home: upd quic port --- CHANGELOG.md | 9 +++++++-- internal/home/config.go | 36 +++++++++++++++++++++++---------- internal/home/controlinstall.go | 4 ++-- internal/home/dns.go | 2 +- internal/home/home.go | 14 ++++++------- internal/home/tls.go | 28 ++++++++++++------------- 6 files changed, 56 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc986774..0a29640a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,8 @@ and this project adheres to ### Changed +- The default DNS-over-QUIC port number is now `853` instead of `754` in + accoradance with the latest [RFC draft][doq-draft-10] ([#4276]). - Reverse DNS now has a greater priority as the source of runtime clients' informmation than ARP neighborhood. - Improved detection of runtime clients through more resilient ARP processing @@ -103,8 +105,10 @@ In this release, the schema version has changed from 12 to 13. [#4216]: https://github.com/AdguardTeam/AdGuardHome/issues/4216 [#4221]: https://github.com/AdguardTeam/AdGuardHome/issues/4221 [#4238]: https://github.com/AdguardTeam/AdGuardHome/issues/4238 +[#4276]: https://github.com/AdguardTeam/AdGuardHome/issues/4276 -[repr]: https://reproducible-builds.org/docs/source-date-epoch/ +[repr]: https://reproducible-builds.org/docs/source-date-epoch/ +[doq-draft-10]: https://datatracker.ietf.org/doc/html/draft-ietf-dprive-dnsoquic-10#section-10.2 @@ -234,7 +238,7 @@ See also the [v0.107.0 GitHub milestone][ms-v0.107.0]. - New possible value of `6h` for `querylog_interval` setting ([#2504]). - Blocking access using ClientIDs ([#2624], [#3162]). - `source` directives support in `/etc/network/interfaces` on Linux ([#3257]). -- RFC 9000 support in DNS-over-QUIC. +- [RFC 9000][rfc-9000] support in QUIC. - Completely disabling statistics by setting the statistics interval to zero ([#2141]). - The ability to completely purge DHCP leases ([#1691]). @@ -459,6 +463,7 @@ In this release, the schema version has changed from 10 to 12. [#3933]: https://github.com/AdguardTeam/AdGuardHome/pull/3933 [ms-v0.107.0]: https://github.com/AdguardTeam/AdGuardHome/milestone/23?closed=1 +[rfc-9000]: https://datatracker.ietf.org/doc/html/rfc9000 diff --git a/internal/home/config.go b/internal/home/config.go index c018f16e..c81de19e 100644 --- a/internal/home/config.go +++ b/internal/home/config.go @@ -292,18 +292,20 @@ func parseConfig() (err error) { uc := aghalg.UniqChecker{} addPorts( uc, - config.BindPort, - config.BetaBindPort, - config.DNS.Port, + tcpPort(config.BindPort), + tcpPort(config.BetaBindPort), + udpPort(config.DNS.Port), ) if config.TLS.Enabled { addPorts( uc, - config.TLS.PortHTTPS, - config.TLS.PortDNSOverTLS, - config.TLS.PortDNSOverQUIC, - config.TLS.PortDNSCrypt, + // TODO(e.burkov): Consider adding a udpPort with the same value if + // we ever support the HTTP/3 for web admin interface. + tcpPort(config.TLS.PortHTTPS), + tcpPort(config.TLS.PortDNSOverTLS), + udpPort(config.TLS.PortDNSOverQUIC), + tcpPort(config.TLS.PortDNSCrypt), ) } if err = uc.Validate(aghalg.IntIsBefore); err != nil { @@ -321,11 +323,23 @@ func parseConfig() (err error) { return nil } -// addPorts is a helper for ports validation. It skips zero ports. -func addPorts(uc aghalg.UniqChecker, ports ...int) { +// udpPort is the port number for UDP protocol. +type udpPort int + +// tcpPort is the port number for TCP protocol. +type tcpPort int + +// addPorts is a helper for ports validation. It skips zero ports. Each of +// ports should be either a udpPort or a tcpPort. +func addPorts(uc aghalg.UniqChecker, ports ...interface{}) { for _, p := range ports { - if p != 0 { - uc.Add(p) + switch p := p.(type) { + case tcpPort, udpPort: + if p != 0 { + uc.Add(p) + } + default: + // Go on. } } } diff --git a/internal/home/controlinstall.go b/internal/home/controlinstall.go index 98cbf31a..0435651b 100644 --- a/internal/home/controlinstall.go +++ b/internal/home/controlinstall.go @@ -109,7 +109,7 @@ func (req *checkConfReq) validateWeb(uc aghalg.UniqChecker) (err error) { defer func() { err = errors.Annotate(err, "validating ports: %w") }() port := req.Web.Port - addPorts(uc, config.BetaBindPort, port) + addPorts(uc, tcpPort(config.BetaBindPort), tcpPort(port)) if err = uc.Validate(aghalg.IntIsBefore); err != nil { // Avoid duplicating the error into the status of DNS. uc[port] = 1 @@ -135,7 +135,7 @@ func (req *checkConfReq) validateDNS(uc aghalg.UniqChecker) (canAutofix bool, er defer func() { err = errors.Annotate(err, "validating ports: %w") }() port := req.DNS.Port - addPorts(uc, port) + addPorts(uc, udpPort(port)) if err = uc.Validate(aghalg.IntIsBefore); err != nil { return false, err } diff --git a/internal/home/dns.go b/internal/home/dns.go index d676f6af..c30e12ec 100644 --- a/internal/home/dns.go +++ b/internal/home/dns.go @@ -25,7 +25,7 @@ const ( defaultPortDNS = 53 defaultPortHTTP = 80 defaultPortHTTPS = 443 - defaultPortQUIC = 784 + defaultPortQUIC = 853 defaultPortTLS = 853 ) diff --git a/internal/home/home.go b/internal/home/home.go index 7096be78..4e4d3aee 100644 --- a/internal/home/home.go +++ b/internal/home/home.go @@ -305,17 +305,17 @@ func setupConfig(args options) (err error) { uc := aghalg.UniqChecker{} addPorts( uc, - args.bindPort, - config.BetaBindPort, - config.DNS.Port, + tcpPort(args.bindPort), + tcpPort(config.BetaBindPort), + udpPort(config.DNS.Port), ) if config.TLS.Enabled { addPorts( uc, - config.TLS.PortHTTPS, - config.TLS.PortDNSOverTLS, - config.TLS.PortDNSOverQUIC, - config.TLS.PortDNSCrypt, + tcpPort(config.TLS.PortHTTPS), + tcpPort(config.TLS.PortDNSOverTLS), + udpPort(config.TLS.PortDNSOverQUIC), + tcpPort(config.TLS.PortDNSCrypt), ) } if err = uc.Validate(aghalg.IntIsBefore); err != nil { diff --git a/internal/home/tls.go b/internal/home/tls.go index eeffe3b6..fe595e98 100644 --- a/internal/home/tls.go +++ b/internal/home/tls.go @@ -253,13 +253,13 @@ func (t *TLSMod) handleTLSValidate(w http.ResponseWriter, r *http.Request) { uc := aghalg.UniqChecker{} addPorts( uc, - config.BindPort, - config.BetaBindPort, - config.DNS.Port, - setts.PortHTTPS, - setts.PortDNSOverTLS, - setts.PortDNSOverQUIC, - setts.PortDNSCrypt, + tcpPort(config.BindPort), + tcpPort(config.BetaBindPort), + udpPort(config.DNS.Port), + tcpPort(setts.PortHTTPS), + tcpPort(setts.PortDNSOverTLS), + udpPort(setts.PortDNSOverQUIC), + tcpPort(setts.PortDNSCrypt), ) err = uc.Validate(aghalg.IntIsBefore) @@ -346,13 +346,13 @@ func (t *TLSMod) handleTLSConfigure(w http.ResponseWriter, r *http.Request) { uc := aghalg.UniqChecker{} addPorts( uc, - config.BindPort, - config.BetaBindPort, - config.DNS.Port, - data.PortHTTPS, - data.PortDNSOverTLS, - data.PortDNSOverQUIC, - data.PortDNSCrypt, + tcpPort(config.BindPort), + tcpPort(config.BetaBindPort), + udpPort(config.DNS.Port), + tcpPort(data.PortHTTPS), + tcpPort(data.PortDNSOverTLS), + udpPort(data.PortDNSOverQUIC), + tcpPort(data.PortDNSCrypt), ) err = uc.Validate(aghalg.IntIsBefore) From 9ce2a0fb341c89b1e047649f97f80cbcc088c8e0 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Wed, 23 Mar 2022 16:13:28 +0300 Subject: [PATCH 010/110] Pull request: all: upd chlog Merge in DNS/adguard-home from upd-chlog to master Squashed commit of the following: commit 02b33e764d540868df19cd7359f114f98c9a66ca Merge: 999a5f27 5cba78a8 Author: Ainar Garipov Date: Wed Mar 23 16:09:39 2022 +0300 Merge branch 'master' into upd-chlog commit 999a5f2718f5577e13ec59619652cc60ff7a7416 Author: Ainar Garipov Date: Wed Mar 23 16:04:35 2022 +0300 all: fix chlog commit 2fe68c5665ea63c3b3f73b8a6ace88de45f2aec1 Author: Ainar Garipov Date: Wed Mar 23 15:59:36 2022 +0300 all: imp chlog commit d5af9db6365430cc7e96d7681231db24e57aa6a5 Author: Ainar Garipov Date: Wed Mar 23 15:39:27 2022 +0300 all: upd chlog --- CHANGELOG.md | 72 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a29640a..65e8a64b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,8 +17,9 @@ and this project adheres to ### Added -- The ability to customize the set of networks considered private through the - new `private_networks` setting ([#3142]). +- The ability to customize the set of networks that are considered private + through the new `dns.private_networks` property in the configuration file + ([#3142]). - EDNS Client-Subnet information in the request details section of a query log record ([#3978]). - Support for hostnames for plain UDP upstream servers using the `udp://` scheme @@ -32,7 +33,7 @@ and this project adheres to - The default DNS-over-QUIC port number is now `853` instead of `754` in accoradance with the latest [RFC draft][doq-draft-10] ([#4276]). - Reverse DNS now has a greater priority as the source of runtime clients' - informmation than ARP neighborhood. + information than ARP neighborhood. - Improved detection of runtime clients through more resilient ARP processing ([#3597]). - The TTL of responses served from the optimistic cache is now lowered to 10 @@ -49,16 +50,16 @@ and this project adheres to of the commit from which the binary was built ([#4221]). This should simplify reproducible builds for package maintainers and those who compile their own AdGuard Home. -- The setting `local_domain_name` is now in the `dhcp` block in the +- The property `local_domain_name` is now in the `dhcp` object in the configuration file to avoid confusion ([#3367]). -- The `dns.bogus_nxdomain` configuration file parameter now supports CIDR +- The `dns.bogus_nxdomain` property in the configuration file now supports CIDR notation alongside IP addresses ([#1730]). #### Configuration Changes In this release, the schema version has changed from 12 to 13. -- Parameter `local_domain_name`, which in schema versions 12 and earlier used to +- Property `local_domain_name`, which in schema versions 12 and earlier used to be a part of the `dns` object, is now a part of the `dhcp` object: ```yaml @@ -73,8 +74,8 @@ In this release, the schema version has changed from 12 to 13. 'local_domain_name': 'lan' ``` - To rollback this change, move the parameter back into `dns` and change the - `schema_version` back to `12`. + To rollback this change, move the property back into the `dns` object and + change the `schema_version` back to `12`. ### Deprecated @@ -86,7 +87,7 @@ In this release, the schema version has changed from 12 to 13. ### Security -- `User-Agent` HTTP header removed from outcoming DNS-over-HTTPS requests. +- `User-Agent` HTTP header removed from outgoing DNS-over-HTTPS requests. - Enforced password strength policy ([#3503]). - Weaker cipher suites that use the CBC (cipher block chaining) mode of operation have been disabled ([#2993]). @@ -113,15 +114,29 @@ In this release, the schema version has changed from 12 to 13. +## [v0.107.5] - 2022-03-04 + +This is a security update. There is no GitHub milestone, since no GitHub issues +were resolved. + +### Security + +- Go version was updated to prevent the possibility of exploiting the + [CVE-2022-24921] vulnerability. + +[CVE-2022-24921]: https://www.cvedetails.com/cve/CVE-2022-24921 + + + ## [v0.107.4] - 2022-03-01 See also the [v0.107.4 GitHub milestone][ms-v0.107.4]. @@ -135,8 +150,8 @@ See also the [v0.107.4 GitHub milestone][ms-v0.107.4]. ### Security -- Go version was updated to prevent the possibility of exploiting - [CVE-2022-23806], [CVE-2022-23772], and [CVE-2022-23773]. +- Go version was updated to prevent the possibility of exploiting the + [CVE-2022-23806], [CVE-2022-23772], and [CVE-2022-23773] vulnerabilities. [#4216]: https://github.com/AdguardTeam/AdGuardHome/issues/4216 [#4254]: https://github.com/AdguardTeam/AdGuardHome/issues/4254 @@ -235,7 +250,7 @@ See also the [v0.107.0 GitHub milestone][ms-v0.107.0]. through the new `fastest_timeout` field in the configuration file ([#1992]). - Static IP address detection on FreeBSD ([#3289]). - Optimistic cache ([#2145]). -- New possible value of `6h` for `querylog_interval` setting ([#2504]). +- New possible value of `6h` for `querylog_interval` property ([#2504]). - Blocking access using ClientIDs ([#2624], [#3162]). - `source` directives support in `/etc/network/interfaces` on Linux ([#3257]). - [RFC 9000][rfc-9000] support in QUIC. @@ -286,22 +301,22 @@ See also the [v0.107.0 GitHub milestone][ms-v0.107.0]. proxy ([#2799]). - Clients who are blocked by access settings now receive a `REFUSED` response when a protocol other than DNS-over-UDP and DNSCrypt is used. -- `querylog_interval` setting is now formatted in hours. +- `dns.querylog_interval` property is now formatted in hours. - Query log search now supports internationalized domains ([#3012]). - Internationalized domains are now shown decoded in the query log with the original encoded version shown in request details ([#3013]). - When /etc/hosts-type rules have several IPs for one host, all IPs are now returned instead of only the first one ([#1381]). -- The setting `rlimit_nofile` is now in the `os` block of the configuration - file, together with the new `group` and `user` settings ([#2763]). +- Property `rlimit_nofile` is now in the `os` object of the configuration file, + together with the new `group` and `user` properties ([#2763]). - Permissions on filter files are now `0o644` instead of `0o600` ([#3198]). #### Configuration Changes In this release, the schema version has changed from 10 to 12. -- Parameter `dns.querylog_interval`, which in schema versions 11 and earlier - used to be an integer number of days, is now a string with a human-readable +- Property `dns.querylog_interval`, which in schema versions 11 and earlier used + to be an integer number of days, is now a string with a human-readable duration: ```yaml @@ -316,10 +331,10 @@ In this release, the schema version has changed from 10 to 12. 'querylog_interval': '2160h' ``` - To rollback this change, convert the parameter back into days and change the + To rollback this change, convert the property back into days and change the `schema_version` back to `11`. -- Parameter `rlimit_nofile`, which in schema versions 10 and earlier used to be +- Property `rlimit_nofile`, which in schema versions 10 and earlier used to be on the top level, is now moved to the new `os` object: ```yaml @@ -333,7 +348,7 @@ In this release, the schema version has changed from 10 to 12. 'user': '' ``` - To rollback this change, move the parameter on the top level and change the + To rollback this change, move the property on the top level and change the `schema_version` back to `10`. ### Deprecated @@ -686,8 +701,8 @@ See also the [v0.105.1 GitHub milestone][ms-v0.105.1]. - Occasional crashes during startup. - The field `"range_start"` in the `GET /control/dhcp/status` HTTP API response is now correctly named again ([#2678]). -- DHCPv6 server's `ra_slaac_only` and `ra_allow_slaac` settings aren't reset to - `false` on update anymore ([#2653]). +- DHCPv6 server's `ra_slaac_only` and `ra_allow_slaac` properties aren't reset + to `false` on update anymore ([#2653]). - The `Vary` header is now added along with `Access-Control-Allow-Origin` to prevent cache-related and other issues in browsers ([#2658]). - The request body size limit is now set for HTTPS requests as well. @@ -864,11 +879,12 @@ See also the [v0.104.2 GitHub milestone][ms-v0.104.2]. -[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.4...HEAD +[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.5...HEAD +[v0.107.5]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.4...v0.107.5 [v0.107.4]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.3...v0.107.4 [v0.107.3]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.2...v0.107.3 [v0.107.2]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.1...v0.107.2 From 82505566f87fe10b80b2961456ed0150baed716c Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Wed, 23 Mar 2022 20:47:45 +0300 Subject: [PATCH 011/110] Pull request: 2846 cover aghnet vol.2 Merge in DNS/adguard-home from 2846-cover-aghnet-vol.2 to master Updates #2846. Closes #4408. Squashed commit of the following: commit 8d62b29d5b5be875cb71e518e479e321d853eb1a Author: Eugene Burkov Date: Wed Mar 23 20:42:04 2022 +0300 home: recover panic commit 1d98109e910830bec712c7aecbbbcb8f659d823d Merge: ac11d751 9ce2a0fb Author: Eugene Burkov Date: Wed Mar 23 20:32:05 2022 +0300 Merge branch 'master' into 2846-cover-aghnet-vol.2 commit ac11d751fb7951e3dd0940bf425a893223c32789 Author: Eugene Burkov Date: Wed Mar 23 20:29:41 2022 +0300 aghnet: use iotest commit 7c923df7bafd5d4b91c4b4a01e75ab161944f949 Author: Eugene Burkov Date: Wed Mar 23 20:17:19 2022 +0300 aghnet: cover more commit 3bfd4d587e4b887b5527d60c0eb6027da15c7e37 Author: Eugene Burkov Date: Wed Mar 23 14:13:59 2022 +0300 aghnet: cover arpdb more commit cd5cf7bbdecceeab6d3abee10a5572e1e907cc67 Author: Eugene Burkov Date: Wed Mar 23 13:05:35 2022 +0300 all: rm arpdb initial refresh commit 0fb8d9e44a4d130ca4e8fc2ea5d595ec08555302 Author: Eugene Burkov Date: Tue Mar 22 21:13:16 2022 +0300 aghnet: cover arpdb --- internal/aghnet/arpdb.go | 11 +--- internal/aghnet/arpdb_bsd_test.go | 8 +++ internal/aghnet/arpdb_linux_test.go | 7 +++ internal/aghnet/arpdb_openbsd_test.go | 2 + internal/aghnet/arpdb_test.go | 53 +++++++++++++++++++ internal/aghnet/hostscontainer.go | 4 +- internal/aghnet/net.go | 3 +- internal/aghnet/net_test.go | 25 +++++++++ internal/aghnet/systemresolvers.go | 40 ++------------ internal/aghnet/systemresolvers_others.go | 23 ++++---- .../aghnet/systemresolvers_others_test.go | 21 +++----- internal/aghnet/systemresolvers_test.go | 14 +++-- internal/aghnet/systemresolvers_windows.go | 3 +- internal/aghnet/testdata/proc_net_arp | 4 +- internal/dnsforward/dnsforward.go | 2 +- internal/home/clients.go | 2 + internal/home/home.go | 9 +--- 17 files changed, 143 insertions(+), 88 deletions(-) diff --git a/internal/aghnet/arpdb.go b/internal/aghnet/arpdb.go index 759a688a..afb880c3 100644 --- a/internal/aghnet/arpdb.go +++ b/internal/aghnet/arpdb.go @@ -27,15 +27,8 @@ type ARPDB interface { } // NewARPDB returns the ARPDB properly initialized for the OS. -func NewARPDB() (arp ARPDB, err error) { - arp = newARPDB() - - err = arp.Refresh() - if err != nil { - return nil, fmt.Errorf("arpdb initial refresh: %w", err) - } - - return arp, nil +func NewARPDB() (arp ARPDB) { + return newARPDB() } // Empty ARPDB implementation diff --git a/internal/aghnet/arpdb_bsd_test.go b/internal/aghnet/arpdb_bsd_test.go index bbadc600..3404af69 100644 --- a/internal/aghnet/arpdb_bsd_test.go +++ b/internal/aghnet/arpdb_bsd_test.go @@ -8,8 +8,12 @@ import ( ) const arpAOutput = ` +invalid.mac (1.2.3.4) at 12:34:56:78:910 on el0 ifscope [ethernet] +invalid.ip (1.2.3.4.5) at ab:cd:ef:ab:cd:12 on ek0 ifscope [ethernet] +invalid.fmt 1 at 12:cd:ef:ab:cd:ef on er0 ifscope [ethernet] hostname.one (192.168.1.2) at ab:cd:ef:ab:cd:ef on en0 ifscope [ethernet] hostname.two (::ffff:ffff) at ef:cd:ab:ef:cd:ab on em0 expires in 1198 seconds [ethernet] +? (::1234) at aa:bb:cc:dd:ee:ff on ej0 expires in 1918 seconds [ethernet] ` var wantNeighs = []Neighbor{{ @@ -20,4 +24,8 @@ var wantNeighs = []Neighbor{{ Name: "hostname.two", IP: net.ParseIP("::ffff:ffff"), MAC: net.HardwareAddr{0xEF, 0xCD, 0xAB, 0xEF, 0xCD, 0xAB}, +}, { + Name: "", + IP: net.ParseIP("::1234"), + MAC: net.HardwareAddr{0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}, }} diff --git a/internal/aghnet/arpdb_linux_test.go b/internal/aghnet/arpdb_linux_test.go index 0439c9b5..b9ed859f 100644 --- a/internal/aghnet/arpdb_linux_test.go +++ b/internal/aghnet/arpdb_linux_test.go @@ -16,14 +16,21 @@ import ( const arpAOutputWrt = ` IP address HW type Flags HW address Mask Device +1.2.3.4.5 0x1 0x2 aa:bb:cc:dd:ee:ff * wan +1.2.3.4 0x1 0x2 12:34:56:78:910 * wan 192.168.1.2 0x1 0x2 ab:cd:ef:ab:cd:ef * wan ::ffff:ffff 0x1 0x2 ef:cd:ab:ef:cd:ab * wan` const arpAOutput = ` +invalid.mac (1.2.3.4) at 12:34:56:78:910 on el0 ifscope [ethernet] +invalid.ip (1.2.3.4.5) at ab:cd:ef:ab:cd:12 on ek0 ifscope [ethernet] +invalid.fmt 1 at 12:cd:ef:ab:cd:ef on er0 ifscope [ethernet] ? (192.168.1.2) at ab:cd:ef:ab:cd:ef on en0 ifscope [ethernet] ? (::ffff:ffff) at ef:cd:ab:ef:cd:ab on em0 expires in 100 seconds [ethernet]` const ipNeighOutput = ` +1.2.3.4.5 dev enp0s3 lladdr aa:bb:cc:dd:ee:ff DELAY +1.2.3.4 dev enp0s3 lladdr 12:34:56:78:910 DELAY 192.168.1.2 dev enp0s3 lladdr ab:cd:ef:ab:cd:ef DELAY ::ffff:ffff dev enp0s3 lladdr ef:cd:ab:ef:cd:ab router STALE` diff --git a/internal/aghnet/arpdb_openbsd_test.go b/internal/aghnet/arpdb_openbsd_test.go index b1021513..915c17ff 100644 --- a/internal/aghnet/arpdb_openbsd_test.go +++ b/internal/aghnet/arpdb_openbsd_test.go @@ -9,6 +9,8 @@ import ( const arpAOutput = ` Host Ethernet Address Netif Expire Flags +1.2.3.4.5 aa:bb:cc:dd:ee:ff em0 permanent +1.2.3.4 12:34:56:78:910 em0 permanent 192.168.1.2 ab:cd:ef:ab:cd:ef em0 19m56s ::ffff:ffff ef:cd:ab:ef:cd:ab em0 permanent l ` diff --git a/internal/aghnet/arpdb_test.go b/internal/aghnet/arpdb_test.go index ce3da4fb..aa5c821a 100644 --- a/internal/aghnet/arpdb_test.go +++ b/internal/aghnet/arpdb_test.go @@ -6,6 +6,7 @@ import ( "strings" "sync" "testing" + "testing/iotest" "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/testutil" @@ -13,6 +14,15 @@ import ( "github.com/stretchr/testify/require" ) +func TestNewARPDB(t *testing.T) { + var a ARPDB + require.NotPanics(t, func() { + a = NewARPDB() + }) + + assert.NotNil(t, a) +} + // TestARPDB is the mock implementation of ARPDB to use in tests. type TestARPDB struct { OnRefresh func() (err error) @@ -166,3 +176,46 @@ func TestCmdARPDB_arpa(t *testing.T) { testutil.AssertErrorMsg(t, "cmd arpdb: running command: can't run", err) }) } + +func TestCmdARPDB_errors(t *testing.T) { + const errRead errors.Error = "can't read" + + badReaderRunCmd := runCmdFunc(func() (r io.Reader, err error) { + return iotest.ErrReader(errRead), nil + }) + + a := &cmdARPDB{ + runcmd: badReaderRunCmd, + parse: parseArpA, + ns: &neighs{ + mu: &sync.RWMutex{}, + ns: make([]Neighbor, 0), + }, + } + + const wantErrMsg string = "cmd arpdb: scanning the output: " + string(errRead) + + testutil.AssertErrorMsg(t, wantErrMsg, a.Refresh()) +} + +func TestEmptyARPDB(t *testing.T) { + a := EmptyARPDB{} + + t.Run("refresh", func(t *testing.T) { + var err error + require.NotPanics(t, func() { + err = a.Refresh() + }) + + assert.NoError(t, err) + }) + + t.Run("neighbors", func(t *testing.T) { + var ns []Neighbor + require.NotPanics(t, func() { + ns = a.Neighbors() + }) + + assert.Empty(t, ns) + }) +} diff --git a/internal/aghnet/hostscontainer.go b/internal/aghnet/hostscontainer.go index 198d4c78..290dc1c0 100644 --- a/internal/aghnet/hostscontainer.go +++ b/internal/aghnet/hostscontainer.go @@ -368,8 +368,8 @@ func (hp *hostsParser) addPairs(ip net.IP, hosts []string) { } } -// writeRules writes the actual rule for the qtype and the PTR for the -// host-ip pair into internal builders. +// 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 net.IP) (rule, rulePtr string) { arpa, err := netutil.IPToReversedAddr(ip) if err != nil { diff --git a/internal/aghnet/net.go b/internal/aghnet/net.go index ecb70fa8..2d791c03 100644 --- a/internal/aghnet/net.go +++ b/internal/aghnet/net.go @@ -105,8 +105,7 @@ func GetValidNetInterfacesForWeb() ([]*NetInterface, error) { ifaces, err := net.Interfaces() if err != nil { return nil, fmt.Errorf("couldn't get interfaces: %w", err) - } - if len(ifaces) == 0 { + } else if len(ifaces) == 0 { return nil, errors.Error("couldn't find any legible interface") } diff --git a/internal/aghnet/net_test.go b/internal/aghnet/net_test.go index 34e99faa..b461cb44 100644 --- a/internal/aghnet/net_test.go +++ b/internal/aghnet/net_test.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/AdguardTeam/AdGuardHome/internal/aghtest" + "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/netutil" "github.com/AdguardTeam/golibs/testutil" "github.com/stretchr/testify/assert" @@ -130,3 +131,27 @@ func TestCheckPort(t *testing.T) { assert.NoError(t, err) }) } + +func TestCollectAllIfacesAddrs(t *testing.T) { + addrs, err := CollectAllIfacesAddrs() + require.NoError(t, err) + + assert.NotEmpty(t, addrs) +} + +func TestIsAddrInUse(t *testing.T) { + t.Run("addr_in_use", func(t *testing.T) { + l, err := net.Listen("tcp", "0.0.0.0:0") + require.NoError(t, err) + testutil.CleanupAndRequireSuccess(t, l.Close) + + _, err = net.Listen(l.Addr().Network(), l.Addr().String()) + assert.True(t, IsAddrInUse(err)) + }) + + t.Run("another", func(t *testing.T) { + const anotherErr errors.Error = "not addr in use" + + assert.False(t, IsAddrInUse(anotherErr)) + }) +} diff --git a/internal/aghnet/systemresolvers.go b/internal/aghnet/systemresolvers.go index 777127a3..13fbeb32 100644 --- a/internal/aghnet/systemresolvers.go +++ b/internal/aghnet/systemresolvers.go @@ -1,11 +1,5 @@ package aghnet -import ( - "time" - - "github.com/AdguardTeam/golibs/log" -) - // DefaultRefreshIvl is the default period of time between refreshing cached // addresses. // const DefaultRefreshIvl = 5 * time.Minute @@ -16,39 +10,21 @@ type HostGenFunc func() (host string) // SystemResolvers helps to work with local resolvers' addresses provided by OS. type SystemResolvers interface { - // Get returns the slice of local resolvers' addresses. It should be - // safe for concurrent use. + // Get returns the slice of local resolvers' addresses. It must be safe for + // concurrent use. Get() (rs []string) - // refresh refreshes the local resolvers' addresses cache. It should be - // safe for concurrent use. + // refresh refreshes the local resolvers' addresses cache. It must be safe + // for concurrent use. refresh() (err error) } -// refreshWithTicker refreshes the cache of sr after each tick form tickCh. -func refreshWithTicker(sr SystemResolvers, tickCh <-chan time.Time) { - defer log.OnPanic("systemResolvers") - - // TODO(e.burkov): Implement a functionality to stop ticker. - for range tickCh { - err := sr.refresh() - if err != nil { - log.Error("systemResolvers: error in refreshing goroutine: %s", err) - - continue - } - - log.Debug("systemResolvers: local addresses cache is refreshed") - } -} - // NewSystemResolvers returns a SystemResolvers with the cache refresh rate // defined by refreshIvl. It disables auto-resfreshing if refreshIvl is 0. If // nil is passed for hostGenFunc, the default generator will be used. func NewSystemResolvers( - refreshIvl time.Duration, hostGenFunc HostGenFunc, ) (sr SystemResolvers, err error) { - sr = newSystemResolvers(refreshIvl, hostGenFunc) + sr = newSystemResolvers(hostGenFunc) // Fill cache. err = sr.refresh() @@ -56,11 +32,5 @@ func NewSystemResolvers( return nil, err } - if refreshIvl > 0 { - ticker := time.NewTicker(refreshIvl) - - go refreshWithTicker(sr, ticker.C) - } - return sr, nil } diff --git a/internal/aghnet/systemresolvers_others.go b/internal/aghnet/systemresolvers_others.go index 8acdb6c7..f8afa286 100644 --- a/internal/aghnet/systemresolvers_others.go +++ b/internal/aghnet/systemresolvers_others.go @@ -24,12 +24,15 @@ func defaultHostGen() (host string) { // systemResolvers is a default implementation of SystemResolvers interface. type systemResolvers struct { - resolver *net.Resolver - hostGenFunc HostGenFunc - - // addrs is the set that contains cached local resolvers' addresses. - addrs *stringutil.Set + // addrsLock protects addrs. addrsLock sync.RWMutex + // addrs is the set that contains cached local resolvers' addresses. + addrs *stringutil.Set + + // resolver is used to fetch the resolvers' addresses. + resolver *net.Resolver + // hostGenFunc generates hosts to resolve. + hostGenFunc HostGenFunc } const ( @@ -44,6 +47,7 @@ const ( errUnexpectedHostFormat errors.Error = "unexpected host format" ) +// refresh implements the SystemResolvers interface for *systemResolvers. func (sr *systemResolvers) refresh() (err error) { defer func() { err = errors.Annotate(err, "systemResolvers: %w") }() @@ -56,7 +60,7 @@ func (sr *systemResolvers) refresh() (err error) { return err } -func newSystemResolvers(refreshIvl time.Duration, hostGenFunc HostGenFunc) (sr SystemResolvers) { +func newSystemResolvers(hostGenFunc HostGenFunc) (sr SystemResolvers) { if hostGenFunc == nil { hostGenFunc = defaultHostGen } @@ -76,19 +80,18 @@ func newSystemResolvers(refreshIvl time.Duration, hostGenFunc HostGenFunc) (sr S func validateDialedHost(host string) (err error) { defer func() { err = errors.Annotate(err, "parsing %q: %w", host) }() - var ipStr string parts := strings.Split(host, "%") switch len(parts) { case 1: - ipStr = host + // host case 2: // Remove the zone and check the IP address part. - ipStr = parts[0] + host = parts[0] default: return errUnexpectedHostFormat } - if net.ParseIP(ipStr) == nil { + if _, err = netutil.ParseIP(host); err != nil { return errBadAddrPassed } diff --git a/internal/aghnet/systemresolvers_others_test.go b/internal/aghnet/systemresolvers_others_test.go index 79abeca2..f7cf9ef0 100644 --- a/internal/aghnet/systemresolvers_others_test.go +++ b/internal/aghnet/systemresolvers_others_test.go @@ -6,37 +6,32 @@ package aghnet import ( "context" "testing" - "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -func createTestSystemResolversImp( +func createTestSystemResolversImpl( t *testing.T, - refreshDur time.Duration, hostGenFunc HostGenFunc, ) (imp *systemResolvers) { t.Helper() - sr := createTestSystemResolvers(t, refreshDur, hostGenFunc) + sr := createTestSystemResolvers(t, hostGenFunc) + require.IsType(t, (*systemResolvers)(nil), sr) - var ok bool - imp, ok = sr.(*systemResolvers) - require.True(t, ok) - - return imp + return sr.(*systemResolvers) } func TestSystemResolvers_Refresh(t *testing.T) { t.Run("expected_error", func(t *testing.T) { - sr := createTestSystemResolvers(t, 0, nil) + sr := createTestSystemResolvers(t, nil) assert.NoError(t, sr.refresh()) }) t.Run("unexpected_error", func(t *testing.T) { - _, err := NewSystemResolvers(0, func() string { + _, err := NewSystemResolvers(func() string { return "127.0.0.1::123" }) assert.Error(t, err) @@ -44,7 +39,7 @@ func TestSystemResolvers_Refresh(t *testing.T) { } func TestSystemResolvers_DialFunc(t *testing.T) { - imp := createTestSystemResolversImp(t, 0, nil) + imp := createTestSystemResolversImpl(t, nil) testCases := []struct { want error @@ -52,7 +47,7 @@ func TestSystemResolvers_DialFunc(t *testing.T) { address string }{{ want: errFakeDial, - name: "valid", + name: "valid_ipv4", address: "127.0.0.1", }, { want: errFakeDial, diff --git a/internal/aghnet/systemresolvers_test.go b/internal/aghnet/systemresolvers_test.go index 13145817..0a19490d 100644 --- a/internal/aghnet/systemresolvers_test.go +++ b/internal/aghnet/systemresolvers_test.go @@ -2,7 +2,6 @@ package aghnet import ( "testing" - "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -10,13 +9,12 @@ import ( func createTestSystemResolvers( t *testing.T, - refreshDur time.Duration, hostGenFunc HostGenFunc, ) (sr SystemResolvers) { t.Helper() var err error - sr, err = NewSystemResolvers(refreshDur, hostGenFunc) + sr, err = NewSystemResolvers(hostGenFunc) require.NoError(t, err) require.NotNil(t, sr) @@ -24,8 +22,14 @@ func createTestSystemResolvers( } func TestSystemResolvers_Get(t *testing.T) { - sr := createTestSystemResolvers(t, 0, nil) - assert.NotEmpty(t, sr.Get()) + sr := createTestSystemResolvers(t, nil) + + var rs []string + require.NotPanics(t, func() { + rs = sr.Get() + }) + + assert.NotEmpty(t, rs) } // TODO(e.burkov): Write tests for refreshWithTicker. diff --git a/internal/aghnet/systemresolvers_windows.go b/internal/aghnet/systemresolvers_windows.go index 5acdfa85..f82d6e7e 100644 --- a/internal/aghnet/systemresolvers_windows.go +++ b/internal/aghnet/systemresolvers_windows.go @@ -11,7 +11,6 @@ import ( "os/exec" "strings" "sync" - "time" "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/log" @@ -27,7 +26,7 @@ type systemResolvers struct { addrsLock sync.RWMutex } -func newSystemResolvers(refreshIvl time.Duration, _ HostGenFunc) (sr SystemResolvers) { +func newSystemResolvers(_ HostGenFunc) (sr SystemResolvers) { return &systemResolvers{} } diff --git a/internal/aghnet/testdata/proc_net_arp b/internal/aghnet/testdata/proc_net_arp index 07d214e1..8460c8bb 100644 --- a/internal/aghnet/testdata/proc_net_arp +++ b/internal/aghnet/testdata/proc_net_arp @@ -1,4 +1,6 @@ IP address HW type Flags HW address Mask Device 192.168.1.2 0x1 0x2 ab:cd:ef:ab:cd:ef * wan ::ffff:ffff 0x1 0x0 ef:cd:ab:ef:cd:ab * br-lan -0.0.0.0 0x0 0x0 00:00:00:00:00:00 * unspec \ No newline at end of file +0.0.0.0 0x0 0x0 00:00:00:00:00:00 * unspec +1.2.3.4.5 0x1 0x2 aa:bb:cc:dd:ee:ff * wan +1.2.3.4 0x1 0x2 12:34:56:78:910 * wan \ No newline at end of file diff --git a/internal/dnsforward/dnsforward.go b/internal/dnsforward/dnsforward.go index a5b0098a..c0cd0e55 100644 --- a/internal/dnsforward/dnsforward.go +++ b/internal/dnsforward/dnsforward.go @@ -173,7 +173,7 @@ func NewServer(p DNSCreateParams) (s *Server, err error) { // TODO(e.burkov): Enable the refresher after the actual implementation // passes the public testing. - s.sysResolvers, err = aghnet.NewSystemResolvers(0, nil) + s.sysResolvers, err = aghnet.NewSystemResolvers(nil) if err != nil { return nil, fmt.Errorf("initializing system resolvers: %w", err) } diff --git a/internal/home/clients.go b/internal/home/clients.go index 9230e565..fe15e514 100644 --- a/internal/home/clients.go +++ b/internal/home/clients.go @@ -257,6 +257,8 @@ func (clients *clientsContainer) forConfig() (objs []*clientObject) { } func (clients *clientsContainer) periodicUpdate() { + defer log.OnPanic("clients container") + for { clients.Reload() time.Sleep(clientsUpdatePeriod) diff --git a/internal/home/home.go b/internal/home/home.go index 4e4d3aee..5fae42c8 100644 --- a/internal/home/home.go +++ b/internal/home/home.go @@ -291,14 +291,7 @@ func setupConfig(args options) (err error) { } } - var arpdb aghnet.ARPDB - arpdb, err = aghnet.NewARPDB() - if err != nil { - log.Info("warning: creating arpdb: %s; using stub", err) - - arpdb = aghnet.EmptyARPDB{} - } - + arpdb := aghnet.NewARPDB() Context.clients.Init(config.Clients, Context.dhcpServer, Context.etcHosts, arpdb) if args.bindPort != 0 { From 3603b1fcab3a39cbc6402ae0334133f58624e335 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Thu, 24 Mar 2022 17:12:41 +0300 Subject: [PATCH 012/110] Pull request: home: fix types Updates #4424. Squashed commit of the following: commit 784b4940d46ce74edbfbbde6e5b24f95dcb4bc70 Author: Ainar Garipov Date: Thu Mar 24 17:07:41 2022 +0300 home: fix types --- internal/home/config.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/internal/home/config.go b/internal/home/config.go index c81de19e..aa8450be 100644 --- a/internal/home/config.go +++ b/internal/home/config.go @@ -333,8 +333,14 @@ type tcpPort int // ports should be either a udpPort or a tcpPort. func addPorts(uc aghalg.UniqChecker, ports ...interface{}) { for _, p := range ports { + // Use separate cases for tcpPort and udpPort so that the untyped + // constant zero is converted to the appropriate type. switch p := p.(type) { - case tcpPort, udpPort: + case tcpPort: + if p != 0 { + uc.Add(p) + } + case udpPort: if p != 0 { uc.Add(p) } From 0d562a7b1fb1ccc4706e844ae4d12d13f39baeaa Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Mon, 28 Mar 2022 17:05:19 +0300 Subject: [PATCH 013/110] Pull request: add go sumdb env Merge in DNS/adguard-home from cn-sumdb to master Squashed commit of the following: commit 439973292f473efa72fb6a733a32be45e634274e Author: Eugene Burkov Date: Mon Mar 28 16:51:28 2022 +0300 Makefile: add go sumdb env --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 51269440..5d9e7a7c 100644 --- a/Makefile +++ b/Makefile @@ -17,6 +17,7 @@ DIST_DIR = dist # See https://unix.stackexchange.com/q/646255/105635. GO.MACRO = $${GO:-go} GOPROXY = https://goproxy.cn|https://proxy.golang.org|direct +GOSUMDB = sum.golang.google.cn GPG_KEY = devteam@adguard.com GPG_KEY_PASSPHRASE = not-a-real-password NPM = npm @@ -56,6 +57,7 @@ ENV = env\ DIST_DIR='$(DIST_DIR)'\ GO="$(GO.MACRO)"\ GOPROXY='$(GOPROXY)'\ + GOSUMDB='$(GOSUMDB)'\ PATH="$${PWD}/bin:$$( "$(GO.MACRO)" env GOPATH )/bin:$${PATH}"\ RACE='$(RACE)'\ SIGN='$(SIGN)'\ From f31ffcc5d1bb1789c6b2e59c0ca5c33dc515cb8e Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Tue, 29 Mar 2022 16:21:22 +0300 Subject: [PATCH 014/110] Pull request: aghnet: fix catching timeout errors Merge in DNS/adguard-home from fix-is-timeout to master Squashed commit of the following: commit b0fefd01f27a835a34e44beb2eb2c34027960a51 Author: Eugene Burkov Date: Tue Mar 29 15:57:06 2022 +0300 aghnet: fix catching timeout errors --- CHANGELOG.md | 4 ++++ internal/aghnet/dhcp_unix.go | 39 +++++++++++++----------------------- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65e8a64b..6d1e9260 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -81,6 +81,10 @@ In this release, the schema version has changed from 12 to 13. - Go 1.17 support. v0.109.0 will require at least Go 1.18 to build. +### Fixed + +- I/O timeout errors on checking another DHCP server. + ### Removed - Go 1.16 support. diff --git a/internal/aghnet/dhcp_unix.go b/internal/aghnet/dhcp_unix.go index fd2b9b93..4791d0e5 100644 --- a/internal/aghnet/dhcp_unix.go +++ b/internal/aghnet/dhcp_unix.go @@ -156,7 +156,7 @@ func tryConn4(req *dhcpv4.DHCPv4, c net.PacketConn, iface *net.Interface) (ok, n b := make([]byte, 1500) n, _, err := c.ReadFrom(b) if err != nil { - if isTimeout(err) { + if errors.Is(err, os.ErrDeadlineExceeded) { log.Debug("dhcpv4: didn't receive dhcp response") return false, false, nil @@ -176,20 +176,21 @@ func tryConn4(req *dhcpv4.DHCPv4, c net.PacketConn, iface *net.Interface) (ok, n log.Debug("dhcpv4: received message from server: %s", response.Summary()) - if !(response.OpCode == dhcpv4.OpcodeBootReply && - response.HWType == iana.HWTypeEthernet && - bytes.Equal(response.ClientHWAddr, iface.HardwareAddr) && - bytes.Equal(response.TransactionID[:], req.TransactionID[:]) && - response.Options.Has(dhcpv4.OptionDHCPMessageType)) { - - log.Debug("dhcpv4: received message from server doesn't match our request") + switch { + case + response.OpCode != dhcpv4.OpcodeBootReply, + response.HWType != iana.HWTypeEthernet, + !bytes.Equal(response.ClientHWAddr, iface.HardwareAddr), + response.TransactionID != req.TransactionID, + !response.Options.Has(dhcpv4.OptionDHCPMessageType): + log.Debug("dhcpv4: received response doesn't match the request") return false, true, nil + default: + log.Tracef("dhcpv4: the packet is from an active dhcp server") + + return true, false, nil } - - log.Tracef("dhcpv4: the packet is from an active dhcp server") - - return true, false, nil } // checkOtherDHCPv6 sends a DHCP request to the specified network interface, and @@ -275,7 +276,7 @@ func tryConn6(req *dhcpv6.Message, c net.PacketConn) (ok, next bool, err error) n, _, err := c.ReadFrom(b) if err != nil { - if isTimeout(err) { + if errors.Is(err, os.ErrDeadlineExceeded) { log.Debug("dhcpv6: didn't receive dhcp response") return false, false, nil @@ -318,15 +319,3 @@ func tryConn6(req *dhcpv6.Message, c net.PacketConn) (ok, next bool, err error) return true, false, nil } - -// isTimeout returns true if err is an operation timeout error from net package. -// -// TODO(e.burkov): Consider moving into netutil. -func isTimeout(err error) (ok bool) { - var operr *net.OpError - if errors.As(err, &operr) { - return operr.Timeout() - } - - return false -} From 5e71f5df6a8cd12a65fecd2f1e28b2aa69609193 Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Wed, 30 Mar 2022 15:11:57 +0300 Subject: [PATCH 015/110] Pull request: 2846 cover aghnet vol.3 Merge in DNS/adguard-home from 2846-cover-aghnet-vol.3 to master Updates #2846. Squashed commit of the following: commit cb22987c43c17bbc8d098e65639cc84e2284bc7b Merge: cf995e9d f31ffcc5 Author: Eugene Burkov Date: Wed Mar 30 15:01:10 2022 +0300 Merge branch 'master' into 2846-cover-aghnet-vol.3 commit cf995e9dce635f16e10406a61e2ab12f06407f1f Author: Eugene Burkov Date: Mon Mar 28 18:29:50 2022 +0300 aghnet: imp tests commit bc225fe8800633b29216840bc7d5b82d7c2d2bfb Author: Eugene Burkov Date: Mon Mar 28 18:03:06 2022 +0300 aghnet: imp tests commit a82eb6045495b94a2e81ced9a3ef5bfe65788e56 Merge: f8081249 0d562a7b Author: Eugene Burkov Date: Mon Mar 28 17:39:13 2022 +0300 Merge branch 'master' into 2846-cover-aghnet-vol.3 commit f80812490c49f69655d409c6f015b069affa2f19 Merge: edccaa79 3603b1fc Author: Eugene Burkov Date: Mon Mar 28 17:29:20 2022 +0300 Merge branch 'master' into 2846-cover-aghnet-vol.3 commit edccaa79fca061ffeea1985c293eed123b16a09c Author: Eugene Burkov Date: Mon Mar 28 13:53:40 2022 +0300 aghnet: imp tests commit 7c5028c92f0a6680516bda67c73e794182c9b825 Author: Eugene Burkov Date: Fri Mar 25 18:01:28 2022 +0300 aghnet: imp code & docs commit 7897c6b13e9be340ae8a71947a8a0bab82c682eb Author: Eugene Burkov Date: Fri Mar 25 17:11:46 2022 +0300 aghnet: imp coverage commit 1eef110af3bf721a0275c695bf27c31815abff04 Author: Eugene Burkov Date: Wed Mar 23 21:10:29 2022 +0300 all: return byte slice --- internal/aghnet/arpdb.go | 75 +++---- internal/aghnet/arpdb_bsd.go | 5 +- internal/aghnet/arpdb_linux.go | 30 +-- internal/aghnet/arpdb_linux_test.go | 67 ++++--- internal/aghnet/arpdb_openbsd.go | 5 +- internal/aghnet/arpdb_test.go | 41 ++-- internal/aghnet/arpdb_unix.go | 13 -- internal/aghnet/arpdb_windows.go | 11 +- internal/aghnet/hostscontainer_test.go | 4 + internal/aghnet/net.go | 43 ++-- internal/aghnet/net_darwin.go | 134 +++++++------ internal/aghnet/net_darwin_test.go | 261 +++++++++++++++++++++++++ internal/aghnet/net_freebsd.go | 2 +- internal/aghnet/net_freebsd_test.go | 72 ++++--- internal/aghnet/net_linux.go | 29 ++- internal/aghnet/net_linux_test.go | 202 ++++++++++--------- internal/aghnet/net_openbsd.go | 2 +- internal/aghnet/net_openbsd_test.go | 66 ++++--- internal/aghnet/net_test.go | 99 +++++++++- internal/aghos/os.go | 14 +- internal/home/service_openbsd.go | 5 +- 21 files changed, 789 insertions(+), 391 deletions(-) delete mode 100644 internal/aghnet/arpdb_unix.go create mode 100644 internal/aghnet/net_darwin_test.go diff --git a/internal/aghnet/arpdb.go b/internal/aghnet/arpdb.go index afb880c3..4909af5f 100644 --- a/internal/aghnet/arpdb.go +++ b/internal/aghnet/arpdb.go @@ -2,13 +2,11 @@ package aghnet import ( "bufio" + "bytes" "fmt" - "io" "net" - "strings" "sync" - "github.com/AdguardTeam/AdGuardHome/internal/aghos" "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/netutil" ) @@ -116,50 +114,33 @@ func (ns *neighs) reset(with []Neighbor) { // of Neighbors. type parseNeighsFunc func(sc *bufio.Scanner, lenHint int) (ns []Neighbor) -// runCmdFunc is the function that runs some command and returns its output -// wrapped to be a io.Reader. -type runCmdFunc func() (r io.Reader, err error) - // cmdARPDB is the implementation of the ARPDB that uses command line to // retrieve data. type cmdARPDB struct { - parse parseNeighsFunc - runcmd runCmdFunc - ns *neighs + parse parseNeighsFunc + ns *neighs + cmd string + args []string } // type check var _ ARPDB = (*cmdARPDB)(nil) -// runCmd runs the cmd with it's args and returns the result wrapped to be an -// io.Reader. The error is returned either if the exit code retured by command -// not equals 0 or the execution itself failed. -func runCmd(cmd string, args ...string) (r io.Reader, err error) { - var code int - var out string - code, out, err = aghos.RunCommand(cmd, args...) - if err != nil { - return nil, err - } else if code != 0 { - return nil, fmt.Errorf("unexpected exit code %d", code) - } - - return strings.NewReader(out), nil -} - // Refresh implements the ARPDB interface for *cmdARPDB. func (arp *cmdARPDB) Refresh() (err error) { defer func() { err = errors.Annotate(err, "cmd arpdb: %w") }() - var r io.Reader - r, err = arp.runcmd() + code, out, err := aghosRunCommand(arp.cmd, arp.args...) if err != nil { return fmt.Errorf("running command: %w", err) + } else if code != 0 { + return fmt.Errorf("running command: unexpected exit code %d", code) } - sc := bufio.NewScanner(r) + sc := bufio.NewScanner(bytes.NewReader(out)) ns := arp.parse(sc, arp.ns.len()) if err = sc.Err(); err != nil { + // TODO(e.burkov): This error seems unreachable. Investigate. return fmt.Errorf("scanning the output: %w", err) } @@ -180,8 +161,7 @@ func (arp *cmdARPDB) Neighbors() (ns []Neighbor) { type arpdbs struct { // arps is the set of ARPDB implementations to range through. arps []ARPDB - // last is the last succeeded ARPDB index. - last int + neighs } // newARPDBs returns a properly initialized *arpdbs. It begins refreshing from @@ -189,7 +169,10 @@ type arpdbs struct { func newARPDBs(arps ...ARPDB) (arp *arpdbs) { return &arpdbs{ arps: arps, - last: 0, + neighs: neighs{ + mu: &sync.RWMutex{}, + ns: make([]Neighbor, 0), + }, } } @@ -199,20 +182,18 @@ var _ ARPDB = (*arpdbs)(nil) // Refresh implements the ARPDB interface for *arpdbs. func (arp *arpdbs) Refresh() (err error) { var errs []error - l := len(arp.arps) - // Start from the last succeeded implementation. - for i := 0; i < l; i++ { - cur := (arp.last + i) % l - err = arp.arps[cur].Refresh() - if err == nil { - // The succeeded implementation found so update the last succeeded - // index. - arp.last = cur - return nil + for _, a := range arp.arps { + err = a.Refresh() + if err != nil { + errs = append(errs, err) + + continue } - errs = append(errs, err) + arp.reset(a.Neighbors()) + + return nil } if len(errs) > 0 { @@ -223,10 +204,8 @@ func (arp *arpdbs) Refresh() (err error) { } // Neighbors implements the ARPDB interface for *arpdbs. +// +// TODO(e.burkov): Think of a way to avoid cloning the slice twice. func (arp *arpdbs) Neighbors() (ns []Neighbor) { - if l := len(arp.arps); l > 0 && arp.last < l { - return arp.arps[arp.last].Neighbors() - } - - return nil + return arp.clone() } diff --git a/internal/aghnet/arpdb_bsd.go b/internal/aghnet/arpdb_bsd.go index fe00418a..a82da76c 100644 --- a/internal/aghnet/arpdb_bsd.go +++ b/internal/aghnet/arpdb_bsd.go @@ -15,12 +15,13 @@ import ( func newARPDB() *cmdARPDB { return &cmdARPDB{ - parse: parseArpA, - runcmd: rcArpA, + parse: parseArpA, ns: &neighs{ mu: &sync.RWMutex{}, ns: make([]Neighbor, 0), }, + cmd: "arp", + args: []string{"-a"}, } } diff --git a/internal/aghnet/arpdb_linux.go b/internal/aghnet/arpdb_linux.go index 976d8b7a..3d391f29 100644 --- a/internal/aghnet/arpdb_linux.go +++ b/internal/aghnet/arpdb_linux.go @@ -6,7 +6,6 @@ package aghnet import ( "bufio" "fmt" - "io" "io/fs" "net" "strings" @@ -34,11 +33,25 @@ func newARPDB() (arp *arpdbs) { return newARPDBs( // Try /proc/net/arp first. - &fsysARPDB{ns: ns, fsys: aghos.RootDirFS(), filename: "proc/net/arp"}, - // Try "arp -a" then. - &cmdARPDB{parse: parseF, runcmd: rcArpA, ns: ns}, - // Try "ip neigh" finally. - &cmdARPDB{parse: parseIPNeigh, runcmd: rcIPNeigh, ns: ns}, + &fsysARPDB{ + ns: ns, + fsys: rootDirFS, + filename: "proc/net/arp", + }, + // Then, try "arp -a". + &cmdARPDB{ + parse: parseF, + ns: ns, + cmd: "arp", + args: []string{"-a"}, + }, + // Finally, try "ip neigh". + &cmdARPDB{ + parse: parseIPNeigh, + ns: ns, + cmd: "ip", + args: []string{"neigh"}, + }, ) } @@ -187,11 +200,6 @@ func parseArpA(sc *bufio.Scanner, lenHint int) (ns []Neighbor) { return ns } -// rcIPNeigh runs "ip neigh". -func rcIPNeigh() (r io.Reader, err error) { - return runCmd("ip", "neigh") -} - // parseIPNeigh parses the output of the "ip neigh" command on Linux. The // expected input format: // diff --git a/internal/aghnet/arpdb_linux_test.go b/internal/aghnet/arpdb_linux_test.go index b9ed859f..46d87150 100644 --- a/internal/aghnet/arpdb_linux_test.go +++ b/internal/aghnet/arpdb_linux_test.go @@ -4,11 +4,10 @@ package aghnet import ( - "io" "net" - "strings" "sync" "testing" + "testing/fstest" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -43,6 +42,8 @@ var wantNeighs = []Neighbor{{ }} func TestFSysARPDB(t *testing.T) { + require.NoError(t, fstest.TestFS(testdata, "proc_net_arp")) + a := &fsysARPDB{ ns: &neighs{ mu: &sync.RWMutex{}, @@ -59,33 +60,43 @@ func TestFSysARPDB(t *testing.T) { assert.Equal(t, wantNeighs, ns) } -func TestCmdARPDB_arpawrt(t *testing.T) { - a := &cmdARPDB{ - parse: parseArpAWrt, - runcmd: func() (r io.Reader, err error) { return strings.NewReader(arpAOutputWrt), nil }, - ns: &neighs{ - mu: &sync.RWMutex{}, - ns: make([]Neighbor, 0), - }, +func TestCmdARPDB_linux(t *testing.T) { + sh := mapShell{ + "arp -a": {err: nil, out: arpAOutputWrt, code: 0}, + "ip neigh": {err: nil, out: ipNeighOutput, code: 0}, } + substShell(t, sh.RunCmd) - err := a.Refresh() - require.NoError(t, err) + t.Run("wrt", func(t *testing.T) { + a := &cmdARPDB{ + parse: parseArpAWrt, + cmd: "arp", + args: []string{"-a"}, + ns: &neighs{ + mu: &sync.RWMutex{}, + ns: make([]Neighbor, 0), + }, + } - assert.Equal(t, wantNeighs, a.Neighbors()) -} - -func TestCmdARPDB_ipneigh(t *testing.T) { - a := &cmdARPDB{ - parse: parseIPNeigh, - runcmd: func() (r io.Reader, err error) { return strings.NewReader(ipNeighOutput), nil }, - ns: &neighs{ - mu: &sync.RWMutex{}, - ns: make([]Neighbor, 0), - }, - } - err := a.Refresh() - require.NoError(t, err) - - assert.Equal(t, wantNeighs, a.Neighbors()) + err := a.Refresh() + require.NoError(t, err) + + assert.Equal(t, wantNeighs, a.Neighbors()) + }) + + t.Run("ip_neigh", func(t *testing.T) { + a := &cmdARPDB{ + parse: parseIPNeigh, + cmd: "ip", + args: []string{"neigh"}, + ns: &neighs{ + mu: &sync.RWMutex{}, + ns: make([]Neighbor, 0), + }, + } + err := a.Refresh() + require.NoError(t, err) + + assert.Equal(t, wantNeighs, a.Neighbors()) + }) } diff --git a/internal/aghnet/arpdb_openbsd.go b/internal/aghnet/arpdb_openbsd.go index 805cb459..a00ffa85 100644 --- a/internal/aghnet/arpdb_openbsd.go +++ b/internal/aghnet/arpdb_openbsd.go @@ -14,12 +14,13 @@ import ( func newARPDB() *cmdARPDB { return &cmdARPDB{ - runcmd: rcArpA, - parse: parseArpA, + parse: parseArpA, ns: &neighs{ mu: &sync.RWMutex{}, ns: make([]Neighbor, 0), }, + cmd: "arp", + args: []string{"-a"}, } } diff --git a/internal/aghnet/arpdb_test.go b/internal/aghnet/arpdb_test.go index aa5c821a..75778b74 100644 --- a/internal/aghnet/arpdb_test.go +++ b/internal/aghnet/arpdb_test.go @@ -1,12 +1,9 @@ package aghnet import ( - "io" "net" - "strings" "sync" "testing" - "testing/iotest" "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/testutil" @@ -16,9 +13,7 @@ import ( func TestNewARPDB(t *testing.T) { var a ARPDB - require.NotPanics(t, func() { - a = NewARPDB() - }) + require.NotPanics(t, func() { a = NewARPDB() }) assert.NotNil(t, a) } @@ -135,11 +130,11 @@ func TestARPDBS(t *testing.T) { assert.Equal(t, 1, succRefrCount) assert.NotEmpty(t, a.Neighbors()) - // Only the last succeeded ARPDB should be used. + // Unstable ARPDB should refresh successfully again. err = a.Refresh() require.NoError(t, err) - assert.Equal(t, 2, succRefrCount) + assert.Equal(t, 1, succRefrCount) assert.NotEmpty(t, a.Neighbors()) }) @@ -153,6 +148,7 @@ func TestARPDBS(t *testing.T) { func TestCmdARPDB_arpa(t *testing.T) { a := &cmdARPDB{ + cmd: "cmd", parse: parseArpA, ns: &neighs{ mu: &sync.RWMutex{}, @@ -161,7 +157,8 @@ func TestCmdARPDB_arpa(t *testing.T) { } t.Run("arp_a", func(t *testing.T) { - a.runcmd = func() (r io.Reader, err error) { return strings.NewReader(arpAOutput), nil } + sh := theOnlyCmd("cmd", 0, arpAOutput, nil) + substShell(t, sh.RunCmd) err := a.Refresh() require.NoError(t, err) @@ -170,32 +167,20 @@ func TestCmdARPDB_arpa(t *testing.T) { }) t.Run("runcmd_error", func(t *testing.T) { - a.runcmd = func() (r io.Reader, err error) { return nil, errors.Error("can't run") } + sh := theOnlyCmd("cmd", 0, "", errors.Error("can't run")) + substShell(t, sh.RunCmd) err := a.Refresh() testutil.AssertErrorMsg(t, "cmd arpdb: running command: can't run", err) }) -} -func TestCmdARPDB_errors(t *testing.T) { - const errRead errors.Error = "can't read" + t.Run("bad_code", func(t *testing.T) { + sh := theOnlyCmd("cmd", 1, "", nil) + substShell(t, sh.RunCmd) - badReaderRunCmd := runCmdFunc(func() (r io.Reader, err error) { - return iotest.ErrReader(errRead), nil + err := a.Refresh() + testutil.AssertErrorMsg(t, "cmd arpdb: running command: unexpected exit code 1", err) }) - - a := &cmdARPDB{ - runcmd: badReaderRunCmd, - parse: parseArpA, - ns: &neighs{ - mu: &sync.RWMutex{}, - ns: make([]Neighbor, 0), - }, - } - - const wantErrMsg string = "cmd arpdb: scanning the output: " + string(errRead) - - testutil.AssertErrorMsg(t, wantErrMsg, a.Refresh()) } func TestEmptyARPDB(t *testing.T) { diff --git a/internal/aghnet/arpdb_unix.go b/internal/aghnet/arpdb_unix.go deleted file mode 100644 index 50346f92..00000000 --- a/internal/aghnet/arpdb_unix.go +++ /dev/null @@ -1,13 +0,0 @@ -//go:build !windows -// +build !windows - -package aghnet - -import ( - "io" -) - -// rcArpA runs "arp -a". -func rcArpA() (r io.Reader, err error) { - return runCmd("arp", "-a") -} diff --git a/internal/aghnet/arpdb_windows.go b/internal/aghnet/arpdb_windows.go index 5156330b..2a70125f 100644 --- a/internal/aghnet/arpdb_windows.go +++ b/internal/aghnet/arpdb_windows.go @@ -5,7 +5,6 @@ package aghnet import ( "bufio" - "io" "net" "strings" "sync" @@ -13,20 +12,16 @@ import ( func newARPDB() *cmdARPDB { return &cmdARPDB{ - runcmd: rcArpA, + parse: parseArpA, ns: &neighs{ mu: &sync.RWMutex{}, ns: make([]Neighbor, 0), }, - parse: parseArpA, + cmd: "arp", + args: []string{"/a"}, } } -// rcArpA runs "arp /a". -func rcArpA() (r io.Reader, err error) { - return runCmd("arp", "/a") -} - // parseArpA parses the output of the "arp /a" command on Windows. The expected // input format (the first line is empty): // diff --git a/internal/aghnet/hostscontainer_test.go b/internal/aghnet/hostscontainer_test.go index 40bfb34c..807722a8 100644 --- a/internal/aghnet/hostscontainer_test.go +++ b/internal/aghnet/hostscontainer_test.go @@ -286,6 +286,8 @@ func TestHostsContainer_Translate(t *testing.T) { OnClose: func() (err error) { panic("not implemented") }, } + require.NoError(t, fstest.TestFS(testdata, "etc_hosts")) + hc, err := NewHostsContainer(0, testdata, &stubWatcher, "etc_hosts") require.NoError(t, err) testutil.CleanupAndRequireSuccess(t, hc.Close) @@ -358,6 +360,8 @@ func TestHostsContainer_Translate(t *testing.T) { func TestHostsContainer(t *testing.T) { const listID = 1234 + require.NoError(t, fstest.TestFS(testdata, "etc_hosts")) + testCases := []struct { want []*rules.DNSRewrite name string diff --git a/internal/aghnet/net.go b/internal/aghnet/net.go index 2d791c03..d17b9165 100644 --- a/internal/aghnet/net.go +++ b/internal/aghnet/net.go @@ -2,19 +2,27 @@ package aghnet import ( + "bytes" "encoding/json" "fmt" "io" "net" - "os/exec" - "strings" "syscall" + "github.com/AdguardTeam/AdGuardHome/internal/aghos" "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/netutil" ) +// aghosRunCommand is the function to run shell commands. It's an unexported +// variable instead of a direct call to make it substitutable in tests. +var aghosRunCommand = aghos.RunCommand + +// rootDirFS is the filesystem pointing to the root directory. It's an +// unexported variable instead to make it substitutable in tests. +var rootDirFS = aghos.RootDirFS() + // ErrNoStaticIPInfo is returned by IfaceHasStaticIP when no information about // the IP being static is available. const ErrNoStaticIPInfo errors.Error = "no information about static ip" @@ -32,22 +40,29 @@ func IfaceSetStaticIP(ifaceName string) (err error) { } // GatewayIP returns IP address of interface's gateway. -func GatewayIP(ifaceName string) net.IP { - cmd := exec.Command("ip", "route", "show", "dev", ifaceName) - log.Tracef("executing %s %v", cmd.Path, cmd.Args) - d, err := cmd.Output() - if err != nil || cmd.ProcessState.ExitCode() != 0 { +// +// TODO(e.burkov): Investigate if the gateway address may be fetched in another +// way since not every machine has the software installed. +func GatewayIP(ifaceName string) (ip net.IP) { + code, out, err := aghosRunCommand("ip", "route", "show", "dev", ifaceName) + if err != nil { + log.Debug("%s", err) + + return nil + } else if code != 0 { + log.Debug("fetching gateway ip: unexpected exit code: %d", code) + return nil } - fields := strings.Fields(string(d)) + fields := bytes.Fields(out) // The meaningful "ip route" command output should contain the word // "default" at first field and default gateway IP address at third field. - if len(fields) < 3 || fields[0] != "default" { + if len(fields) < 3 || string(fields[0]) != "default" { return nil } - return net.ParseIP(fields[2]) + return net.ParseIP(string(fields[2])) } // CanBindPort checks if we can bind to the given port. @@ -101,7 +116,7 @@ func (iface NetInterface) MarshalJSON() ([]byte, error) { // GetValidNetInterfacesForWeb returns interfaces that are eligible for DNS and WEB only // we do not return link-local addresses here -func GetValidNetInterfacesForWeb() ([]*NetInterface, error) { +func GetValidNetInterfacesForWeb() (netInterfaces []*NetInterface, err error) { ifaces, err := net.Interfaces() if err != nil { return nil, fmt.Errorf("couldn't get interfaces: %w", err) @@ -109,8 +124,6 @@ func GetValidNetInterfacesForWeb() ([]*NetInterface, error) { return nil, errors.Error("couldn't find any legible interface") } - var netInterfaces []*NetInterface - for _, iface := range ifaces { var addrs []net.Addr addrs, err = iface.Addrs() @@ -130,12 +143,14 @@ func GetValidNetInterfacesForWeb() ([]*NetInterface, error) { ipNet, ok := addr.(*net.IPNet) if !ok { // Should be net.IPNet, this is weird. - return nil, fmt.Errorf("got iface.Addrs() element %s that is not net.IPNet, it is %T", addr, addr) + return nil, fmt.Errorf("got %s that is not net.IPNet, it is %T", addr, addr) } + // Ignore link-local. if ipNet.IP.IsLinkLocalUnicast() { continue } + netIface.Addresses = append(netIface.Addresses, ipNet.IP) netIface.Subnets = append(netIface.Subnets, ipNet) } diff --git a/internal/aghnet/net_darwin.go b/internal/aghnet/net_darwin.go index 3c504988..63e57dc4 100644 --- a/internal/aghnet/net_darwin.go +++ b/internal/aghnet/net_darwin.go @@ -4,10 +4,11 @@ package aghnet import ( + "bufio" + "bytes" "fmt" - "os" + "io" "regexp" - "strings" "github.com/AdguardTeam/AdGuardHome/internal/aghos" "github.com/AdguardTeam/golibs/errors" @@ -27,7 +28,7 @@ func canBindPrivilegedPorts() (can bool, err error) { return aghos.HaveAdminRights() } -func ifaceHasStaticIP(ifaceName string) (bool, error) { +func ifaceHasStaticIP(ifaceName string) (ok bool, err error) { portInfo, err := getCurrentHardwarePortInfo(ifaceName) if err != nil { return false, err @@ -36,9 +37,10 @@ func ifaceHasStaticIP(ifaceName string) (bool, error) { return portInfo.static, nil } -// getCurrentHardwarePortInfo gets information for the specified network interface. +// getCurrentHardwarePortInfo gets information for the specified network +// interface. func getCurrentHardwarePortInfo(ifaceName string) (hardwarePortInfo, error) { - // First of all we should find hardware port name + // First of all we should find hardware port name. m := getNetworkSetupHardwareReports() hardwarePort, ok := m[ifaceName] if !ok { @@ -48,6 +50,10 @@ func getCurrentHardwarePortInfo(ifaceName string) (hardwarePortInfo, error) { return getHardwarePortInfo(hardwarePort) } +// hardwareReportsReg is the regular expression matching the lines of +// networksetup command output lines containing the interface information. +var hardwareReportsReg = regexp.MustCompile("Hardware Port: (.*?)\nDevice: (.*?)\n") + // getNetworkSetupHardwareReports parses the output of the `networksetup // -listallhardwareports` command it returns a map where the key is the // interface name, and the value is the "hardware port" returns nil if it fails @@ -56,54 +62,44 @@ func getCurrentHardwarePortInfo(ifaceName string) (hardwarePortInfo, error) { // TODO(e.burkov): There should be more proper approach than parsing the // command output. For example, see // https://developer.apple.com/documentation/systemconfiguration. -func getNetworkSetupHardwareReports() map[string]string { - _, out, err := aghos.RunCommand("networksetup", "-listallhardwareports") +func getNetworkSetupHardwareReports() (reports map[string]string) { + _, out, err := aghosRunCommand("networksetup", "-listallhardwareports") if err != nil { return nil } - re, err := regexp.Compile("Hardware Port: (.*?)\nDevice: (.*?)\n") - if err != nil { - return nil + reports = make(map[string]string) + + matches := hardwareReportsReg.FindAllSubmatch(out, -1) + for _, m := range matches { + reports[string(m[2])] = string(m[1]) } - m := make(map[string]string) - - matches := re.FindAllStringSubmatch(out, -1) - for i := range matches { - port := matches[i][1] - device := matches[i][2] - m[device] = port - } - - return m + return reports } -func getHardwarePortInfo(hardwarePort string) (hardwarePortInfo, error) { - h := hardwarePortInfo{} +// hardwarePortReg is the regular expression matching the lines of networksetup +// command output lines containing the port information. +var hardwarePortReg = regexp.MustCompile("IP address: (.*?)\nSubnet mask: (.*?)\nRouter: (.*?)\n") - _, out, err := aghos.RunCommand("networksetup", "-getinfo", hardwarePort) +func getHardwarePortInfo(hardwarePort string) (h hardwarePortInfo, err error) { + _, out, err := aghosRunCommand("networksetup", "-getinfo", hardwarePort) if err != nil { return h, err } - re := regexp.MustCompile("IP address: (.*?)\nSubnet mask: (.*?)\nRouter: (.*?)\n") - - match := re.FindStringSubmatch(out) - if len(match) == 0 { + match := hardwarePortReg.FindSubmatch(out) + if len(match) != 4 { return h, errors.Error("could not find hardware port info") } - h.name = hardwarePort - h.ip = match[1] - h.subnet = match[2] - h.gatewayIP = match[3] - - if strings.Index(out, "Manual Configuration") == 0 { - h.static = true - } - - return h, nil + return hardwarePortInfo{ + name: hardwarePort, + ip: string(match[1]), + subnet: string(match[2]), + gatewayIP: string(match[3]), + static: bytes.Index(out, []byte("Manual Configuration")) == 0, + }, nil } func ifaceSetStaticIP(ifaceName string) (err error) { @@ -113,7 +109,7 @@ func ifaceSetStaticIP(ifaceName string) (err error) { } if portInfo.static { - return errors.Error("IP address is already static") + return errors.Error("ip address is already static") } dnsAddrs, err := getEtcResolvConfServers() @@ -121,50 +117,62 @@ func ifaceSetStaticIP(ifaceName string) (err error) { return err } - args := make([]string, 0) - args = append(args, "-setdnsservers", portInfo.name) - args = append(args, dnsAddrs...) + args := append([]string{"-setdnsservers", portInfo.name}, dnsAddrs...) // Setting DNS servers is necessary when configuring a static IP - code, _, err := aghos.RunCommand("networksetup", args...) + code, _, err := aghosRunCommand("networksetup", args...) if err != nil { return err - } - if code != 0 { + } else if code != 0 { return fmt.Errorf("failed to set DNS servers, code=%d", code) } // Actually configures hardware port to have static IP - code, _, err = aghos.RunCommand("networksetup", "-setmanual", - portInfo.name, portInfo.ip, portInfo.subnet, portInfo.gatewayIP) + code, _, err = aghosRunCommand( + "networksetup", + "-setmanual", + portInfo.name, + portInfo.ip, + portInfo.subnet, + portInfo.gatewayIP, + ) if err != nil { return err - } - if code != 0 { + } else if code != 0 { return fmt.Errorf("failed to set DNS servers, code=%d", code) } return nil } +// etcResolvConfReg is the regular expression matching the lines of resolv.conf +// file containing a name server information. +var etcResolvConfReg = regexp.MustCompile("nameserver ([a-zA-Z0-9.:]+)") + // getEtcResolvConfServers returns a list of nameservers configured in // /etc/resolv.conf. -func getEtcResolvConfServers() ([]string, error) { - body, err := os.ReadFile("/etc/resolv.conf") +func getEtcResolvConfServers() (addrs []string, err error) { + const filename = "etc/resolv.conf" + + _, err = aghos.FileWalker(func(r io.Reader) (_ []string, _ bool, err error) { + sc := bufio.NewScanner(r) + for sc.Scan() { + matches := etcResolvConfReg.FindAllStringSubmatch(sc.Text(), -1) + if len(matches) == 0 { + continue + } + + for _, m := range matches { + addrs = append(addrs, m[1]) + } + } + + return nil, false, sc.Err() + }).Walk(rootDirFS, filename) if err != nil { - return nil, err - } - - re := regexp.MustCompile("nameserver ([a-zA-Z0-9.:]+)") - - matches := re.FindAllStringSubmatch(string(body), -1) - if len(matches) == 0 { - return nil, errors.Error("found no DNS servers in /etc/resolv.conf") - } - - addrs := make([]string, 0) - for i := range matches { - addrs = append(addrs, matches[i][1]) + return nil, fmt.Errorf("parsing etc/resolv.conf file: %w", err) + } else if len(addrs) == 0 { + return nil, fmt.Errorf("found no dns servers in %s", filename) } return addrs, nil diff --git a/internal/aghnet/net_darwin_test.go b/internal/aghnet/net_darwin_test.go new file mode 100644 index 00000000..905600d5 --- /dev/null +++ b/internal/aghnet/net_darwin_test.go @@ -0,0 +1,261 @@ +package aghnet + +import ( + "io/fs" + "testing" + "testing/fstest" + + "github.com/AdguardTeam/AdGuardHome/internal/aghtest" + "github.com/AdguardTeam/golibs/errors" + "github.com/AdguardTeam/golibs/testutil" + "github.com/stretchr/testify/assert" +) + +func TestIfaceHasStaticIP(t *testing.T) { + testCases := []struct { + name string + shell mapShell + ifaceName string + wantHas assert.BoolAssertionFunc + wantErrMsg string + }{{ + name: "success", + shell: mapShell{ + "networksetup -listallhardwareports": { + err: nil, + out: "Hardware Port: hwport\nDevice: en0\n", + code: 0, + }, + "networksetup -getinfo hwport": { + err: nil, + out: "IP address: 1.2.3.4\nSubnet mask: 255.255.255.0\nRouter: 1.2.3.1\n", + code: 0, + }, + }, + ifaceName: "en0", + wantHas: assert.False, + wantErrMsg: ``, + }, { + name: "success_static", + shell: mapShell{ + "networksetup -listallhardwareports": { + err: nil, + out: "Hardware Port: hwport\nDevice: en0\n", + code: 0, + }, + "networksetup -getinfo hwport": { + err: nil, + out: "Manual Configuration\nIP address: 1.2.3.4\n" + + "Subnet mask: 255.255.255.0\nRouter: 1.2.3.1\n", + code: 0, + }, + }, + ifaceName: "en0", + wantHas: assert.True, + wantErrMsg: ``, + }, { + name: "reports_error", + shell: theOnlyCmd( + "networksetup -listallhardwareports", + 0, + "", + errors.Error("can't list"), + ), + ifaceName: "en0", + wantHas: assert.False, + wantErrMsg: `could not find hardware port for en0`, + }, { + name: "port_error", + shell: mapShell{ + "networksetup -listallhardwareports": { + err: nil, + out: "Hardware Port: hwport\nDevice: en0\n", + code: 0, + }, + "networksetup -getinfo hwport": { + err: errors.Error("can't get"), + out: ``, + code: 0, + }, + }, + ifaceName: "en0", + wantHas: assert.False, + wantErrMsg: `can't get`, + }, { + name: "port_bad_output", + shell: mapShell{ + "networksetup -listallhardwareports": { + err: nil, + out: "Hardware Port: hwport\nDevice: en0\n", + code: 0, + }, + "networksetup -getinfo hwport": { + err: nil, + out: "nothing meaningful", + code: 0, + }, + }, + ifaceName: "en0", + wantHas: assert.False, + wantErrMsg: `could not find hardware port info`, + }} + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + substShell(t, tc.shell.RunCmd) + + has, err := IfaceHasStaticIP(tc.ifaceName) + testutil.AssertErrorMsg(t, tc.wantErrMsg, err) + + tc.wantHas(t, has) + }) + } +} + +func TestIfaceSetStaticIP(t *testing.T) { + succFsys := fstest.MapFS{ + "etc/resolv.conf": &fstest.MapFile{ + Data: []byte(`nameserver 1.1.1.1`), + }, + } + panicFsys := &aghtest.FS{ + OnOpen: func(name string) (fs.File, error) { panic("not implemented") }, + } + + testCases := []struct { + name string + shell mapShell + fsys fs.FS + wantErrMsg string + }{{ + name: "success", + shell: mapShell{ + "networksetup -listallhardwareports": { + err: nil, + out: "Hardware Port: hwport\nDevice: en0\n", + code: 0, + }, + "networksetup -getinfo hwport": { + err: nil, + out: "IP address: 1.2.3.4\nSubnet mask: 255.255.255.0\nRouter: 1.2.3.1\n", + code: 0, + }, + "networksetup -setdnsservers hwport 1.1.1.1": { + err: nil, + out: "", + code: 0, + }, + "networksetup -setmanual hwport 1.2.3.4 255.255.255.0 1.2.3.1": { + err: nil, + out: "", + code: 0, + }, + }, + fsys: succFsys, + wantErrMsg: ``, + }, { + name: "static_already", + shell: mapShell{ + "networksetup -listallhardwareports": { + err: nil, + out: "Hardware Port: hwport\nDevice: en0\n", + code: 0, + }, + "networksetup -getinfo hwport": { + err: nil, + out: "Manual Configuration\nIP address: 1.2.3.4\n" + + "Subnet mask: 255.255.255.0\nRouter: 1.2.3.1\n", + code: 0, + }, + }, + fsys: panicFsys, + wantErrMsg: `ip address is already static`, + }, { + name: "reports_error", + shell: theOnlyCmd( + "networksetup -listallhardwareports", + 0, + "", + errors.Error("can't list"), + ), + fsys: panicFsys, + wantErrMsg: `could not find hardware port for en0`, + }, { + name: "resolv_conf_error", + shell: mapShell{ + "networksetup -listallhardwareports": { + err: nil, + out: "Hardware Port: hwport\nDevice: en0\n", + code: 0, + }, + "networksetup -getinfo hwport": { + err: nil, + out: "IP address: 1.2.3.4\nSubnet mask: 255.255.255.0\nRouter: 1.2.3.1\n", + code: 0, + }, + }, + fsys: fstest.MapFS{ + "etc/resolv.conf": &fstest.MapFile{ + Data: []byte("this resolv.conf is invalid"), + }, + }, + wantErrMsg: `found no dns servers in etc/resolv.conf`, + }, { + name: "set_dns_error", + shell: mapShell{ + "networksetup -listallhardwareports": { + err: nil, + out: "Hardware Port: hwport\nDevice: en0\n", + code: 0, + }, + "networksetup -getinfo hwport": { + err: nil, + out: "IP address: 1.2.3.4\nSubnet mask: 255.255.255.0\nRouter: 1.2.3.1\n", + code: 0, + }, + "networksetup -setdnsservers hwport 1.1.1.1": { + err: errors.Error("can't set"), + out: "", + code: 0, + }, + }, + fsys: succFsys, + wantErrMsg: `can't set`, + }, { + name: "set_manual_error", + shell: mapShell{ + "networksetup -listallhardwareports": { + err: nil, + out: "Hardware Port: hwport\nDevice: en0\n", + code: 0, + }, + "networksetup -getinfo hwport": { + err: nil, + out: "IP address: 1.2.3.4\nSubnet mask: 255.255.255.0\nRouter: 1.2.3.1\n", + code: 0, + }, + "networksetup -setdnsservers hwport 1.1.1.1": { + err: nil, + out: "", + code: 0, + }, + "networksetup -setmanual hwport 1.2.3.4 255.255.255.0 1.2.3.1": { + err: errors.Error("can't set"), + out: "", + code: 0, + }, + }, + fsys: succFsys, + wantErrMsg: `can't set`, + }} + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + substShell(t, tc.shell.RunCmd) + substRootDirFS(t, tc.fsys) + + err := IfaceSetStaticIP("en0") + testutil.AssertErrorMsg(t, tc.wantErrMsg, err) + }) + } +} diff --git a/internal/aghnet/net_freebsd.go b/internal/aghnet/net_freebsd.go index a5200fb8..34d93303 100644 --- a/internal/aghnet/net_freebsd.go +++ b/internal/aghnet/net_freebsd.go @@ -22,7 +22,7 @@ func ifaceHasStaticIP(ifaceName string) (ok bool, err error) { walker := aghos.FileWalker(interfaceName(ifaceName).rcConfStaticConfig) - return walker.Walk(aghos.RootDirFS(), rcConfFilename) + return walker.Walk(rootDirFS, rcConfFilename) } // rcConfStaticConfig checks if the interface is configured by /etc/rc.conf to diff --git a/internal/aghnet/net_freebsd_test.go b/internal/aghnet/net_freebsd_test.go index 3781b154..e00dafa7 100644 --- a/internal/aghnet/net_freebsd_test.go +++ b/internal/aghnet/net_freebsd_test.go @@ -4,56 +4,74 @@ package aghnet import ( - "strings" + "io/fs" "testing" + "testing/fstest" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestRcConfStaticConfig(t *testing.T) { - const iface interfaceName = `em0` - const nl = "\n" + const ( + ifaceName = `em0` + rcConf = "etc/rc.conf" + ) testCases := []struct { - name string - rcconfData string - wantCont bool + name string + rootFsys fs.FS + wantHas assert.BoolAssertionFunc }{{ - name: "simple", - rcconfData: `ifconfig_em0="inet 127.0.0.253 netmask 0xffffffff"` + nl, - wantCont: false, + name: "simple", + rootFsys: fstest.MapFS{rcConf: &fstest.MapFile{ + Data: []byte(`ifconfig_` + ifaceName + `="inet 127.0.0.253 netmask 0xffffffff"` + nl), + }}, + wantHas: assert.True, }, { - name: "case_insensitiveness", - rcconfData: `ifconfig_em0="InEt 127.0.0.253 NeTmAsK 0xffffffff"` + nl, - wantCont: false, + name: "case_insensitiveness", + rootFsys: fstest.MapFS{rcConf: &fstest.MapFile{ + Data: []byte(`ifconfig_` + ifaceName + `="InEt 127.0.0.253 NeTmAsK 0xffffffff"` + nl), + }}, + wantHas: assert.True, }, { name: "comments_and_trash", - rcconfData: `# comment 1` + nl + - `` + nl + - `# comment 2` + nl + - `ifconfig_em0="inet 127.0.0.253 netmask 0xffffffff"` + nl, - wantCont: false, + rootFsys: fstest.MapFS{rcConf: &fstest.MapFile{ + Data: []byte(`# comment 1` + nl + + `` + nl + + `# comment 2` + nl + + `ifconfig_` + ifaceName + `="inet 127.0.0.253 netmask 0xffffffff"` + nl, + ), + }}, + wantHas: assert.True, }, { name: "aliases", - rcconfData: `ifconfig_em0_alias="inet 127.0.0.1/24"` + nl + - `ifconfig_em0="inet 127.0.0.253 netmask 0xffffffff"` + nl, - wantCont: false, + rootFsys: fstest.MapFS{rcConf: &fstest.MapFile{ + Data: []byte(`ifconfig_` + ifaceName + `_alias="inet 127.0.0.1/24"` + nl + + `ifconfig_` + ifaceName + `="inet 127.0.0.253 netmask 0xffffffff"` + nl, + ), + }}, + wantHas: assert.True, }, { name: "incorrect_config", - rcconfData: `ifconfig_em0="inet6 127.0.0.253 netmask 0xffffffff"` + nl + - `ifconfig_em0="inet 256.256.256.256 netmask 0xffffffff"` + nl + - `ifconfig_em0=""` + nl, - wantCont: true, + rootFsys: fstest.MapFS{rcConf: &fstest.MapFile{ + Data: []byte( + `ifconfig_` + ifaceName + `="inet6 127.0.0.253 netmask 0xffffffff"` + nl + + `ifconfig_` + ifaceName + `="inet 256.256.256.256 netmask 0xffffffff"` + nl + + `ifconfig_` + ifaceName + `=""` + nl, + ), + }}, + wantHas: assert.False, }} for _, tc := range testCases { - r := strings.NewReader(tc.rcconfData) t.Run(tc.name, func(t *testing.T) { - _, cont, err := iface.rcConfStaticConfig(r) + substRootDirFS(t, tc.rootFsys) + + has, err := IfaceHasStaticIP(ifaceName) require.NoError(t, err) - assert.Equal(t, tc.wantCont, cont) + tc.wantHas(t, has) }) } } diff --git a/internal/aghnet/net_linux.go b/internal/aghnet/net_linux.go index 93414165..c2526524 100644 --- a/internal/aghnet/net_linux.go +++ b/internal/aghnet/net_linux.go @@ -21,8 +21,7 @@ import ( // have a static IP. func (n interfaceName) dhcpcdStaticConfig(r io.Reader) (subsources []string, cont bool, err error) { s := bufio.NewScanner(r) - ifaceFound := findIfaceLine(s, string(n)) - if !ifaceFound { + if !findIfaceLine(s, string(n)) { return nil, true, s.Err() } @@ -61,9 +60,9 @@ func (n interfaceName) ifacesStaticConfig(r io.Reader) (sub []string, cont bool, fields := strings.Fields(line) fieldsNum := len(fields) - // Man page interfaces(5) declares that interface definition - // should consist of the key word "iface" followed by interface - // name, and method at fourth field. + // Man page interfaces(5) declares that interface definition should + // consist of the key word "iface" followed by interface name, and + // method at fourth field. if fieldsNum >= 4 && fields[0] == "iface" && fields[1] == string(n) && fields[3] == "static" { return nil, false, nil @@ -78,10 +77,10 @@ func (n interfaceName) ifacesStaticConfig(r io.Reader) (sub []string, cont bool, } func ifaceHasStaticIP(ifaceName string) (has bool, err error) { - // TODO(a.garipov): Currently, this function returns the first - // definitive result. So if /etc/dhcpcd.conf has a static IP while - // /etc/network/interfaces doesn't, it will return true. Perhaps this - // is not the most desirable behavior. + // TODO(a.garipov): Currently, this function returns the first definitive + // result. So if /etc/dhcpcd.conf has and /etc/network/interfaces has no + // static IP configuration, it will return true. Perhaps this is not the + // most desirable behavior. iface := interfaceName(ifaceName) @@ -95,12 +94,10 @@ func ifaceHasStaticIP(ifaceName string) (has bool, err error) { FileWalker: iface.ifacesStaticConfig, filename: "etc/network/interfaces", }} { - has, err = pair.Walk(aghos.RootDirFS(), pair.filename) + has, err = pair.Walk(rootDirFS, pair.filename) if err != nil { return false, err - } - - if has { + } else if has { return true, nil } } @@ -141,13 +138,15 @@ func ifaceSetStaticIP(ifaceName string) (err error) { gatewayIP := GatewayIP(ifaceName) add := dhcpcdConfIface(ifaceName, ipNet, gatewayIP, ipNet.IP) - body, err := os.ReadFile("/etc/dhcpcd.conf") + const filename = "/etc/dhcpcd.conf" + + body, err := os.ReadFile(filename) if err != nil && !errors.Is(err, os.ErrNotExist) { return err } body = append(body, []byte(add)...) - err = maybe.WriteFile("/etc/dhcpcd.conf", body, 0o644) + err = maybe.WriteFile(filename, body, 0o644) if err != nil { return fmt.Errorf("writing conf: %w", err) } diff --git a/internal/aghnet/net_linux_test.go b/internal/aghnet/net_linux_test.go index bf2cecfe..e46da4df 100644 --- a/internal/aghnet/net_linux_test.go +++ b/internal/aghnet/net_linux_test.go @@ -4,122 +4,130 @@ package aghnet import ( - "bytes" + "io/fs" "net" "testing" + "testing/fstest" + "github.com/AdguardTeam/golibs/testutil" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) -func TestDHCPCDStaticConfig(t *testing.T) { - const iface interfaceName = `wlan0` +func TestHasStaticIP(t *testing.T) { + const ifaceName = "wlan0" + + const ( + dhcpcd = "etc/dhcpcd.conf" + netifaces = "etc/network/interfaces" + ) testCases := []struct { - name string - data []byte - wantCont bool + rootFsys fs.FS + name string + wantHas assert.BoolAssertionFunc + wantErrMsg string }{{ - name: "has_not", - data: []byte(`#comment` + nl + - `# comment` + nl + - `interface eth0` + nl + - `static ip_address=192.168.0.1/24` + nl + - `# interface ` + iface + nl + - `static ip_address=192.168.1.1/24` + nl + - `# comment` + nl, - ), - wantCont: true, + rootFsys: fstest.MapFS{ + dhcpcd: &fstest.MapFile{ + Data: []byte(`#comment` + nl + + `# comment` + nl + + `interface eth0` + nl + + `static ip_address=192.168.0.1/24` + nl + + `# interface ` + ifaceName + nl + + `static ip_address=192.168.1.1/24` + nl + + `# comment` + nl, + ), + }, + }, + name: "dhcpcd_has_not", + wantHas: assert.False, + wantErrMsg: `no information about static ip`, }, { - name: "has", - data: []byte(`#comment` + nl + - `# comment` + nl + - `interface eth0` + nl + - `static ip_address=192.168.0.1/24` + nl + - `# interface ` + iface + nl + - `static ip_address=192.168.1.1/24` + nl + - `# comment` + nl + - `interface ` + iface + nl + - `# comment` + nl + - `static ip_address=192.168.2.1/24` + nl, - ), - wantCont: false, + rootFsys: fstest.MapFS{ + dhcpcd: &fstest.MapFile{ + Data: []byte(`#comment` + nl + + `# comment` + nl + + `interface ` + ifaceName + nl + + `static ip_address=192.168.0.1/24` + nl + + `# interface ` + ifaceName + nl + + `static ip_address=192.168.1.1/24` + nl + + `# comment` + nl, + ), + }, + }, + name: "dhcpcd_has", + wantHas: assert.True, + wantErrMsg: ``, + }, { + rootFsys: fstest.MapFS{ + netifaces: &fstest.MapFile{ + Data: []byte(`allow-hotplug ` + ifaceName + nl + + `#iface enp0s3 inet static` + nl + + `# address 192.168.0.200` + nl + + `# netmask 255.255.255.0` + nl + + `# gateway 192.168.0.1` + nl + + `iface ` + ifaceName + ` inet dhcp` + nl, + ), + }, + }, + name: "netifaces_has_not", + wantHas: assert.False, + wantErrMsg: `no information about static ip`, + }, { + rootFsys: fstest.MapFS{ + netifaces: &fstest.MapFile{ + Data: []byte(`allow-hotplug ` + ifaceName + nl + + `iface ` + ifaceName + ` inet static` + nl + + ` address 192.168.0.200` + nl + + ` netmask 255.255.255.0` + nl + + ` gateway 192.168.0.1` + nl + + `#iface ` + ifaceName + ` inet dhcp` + nl, + ), + }, + }, + name: "netifaces_has", + wantHas: assert.True, + wantErrMsg: ``, + }, { + rootFsys: fstest.MapFS{ + netifaces: &fstest.MapFile{ + Data: []byte(`source hello` + nl + + `#iface ` + ifaceName + ` inet static` + nl, + ), + }, + "hello": &fstest.MapFile{ + Data: []byte(`iface ` + ifaceName + ` inet static` + nl), + }, + }, + name: "netifaces_another_file", + wantHas: assert.True, + wantErrMsg: ``, + }, { + rootFsys: fstest.MapFS{ + netifaces: &fstest.MapFile{ + Data: []byte(`source hello` + nl + + `iface ` + ifaceName + ` inet static` + nl, + ), + }, + }, + name: "netifaces_ignore_another", + wantHas: assert.True, + wantErrMsg: ``, }} for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - r := bytes.NewReader(tc.data) - _, cont, err := iface.dhcpcdStaticConfig(r) - require.NoError(t, err) + substRootDirFS(t, tc.rootFsys) - assert.Equal(t, tc.wantCont, cont) + has, err := IfaceHasStaticIP(ifaceName) + testutil.AssertErrorMsg(t, tc.wantErrMsg, err) + + tc.wantHas(t, has) }) } } -func TestIfacesStaticConfig(t *testing.T) { - const iface interfaceName = `enp0s3` - - testCases := []struct { - name string - data []byte - wantCont bool - wantPatterns []string - }{{ - name: "has_not", - data: []byte(`allow-hotplug ` + iface + nl + - `#iface enp0s3 inet static` + nl + - `# address 192.168.0.200` + nl + - `# netmask 255.255.255.0` + nl + - `# gateway 192.168.0.1` + nl + - `iface ` + iface + ` inet dhcp` + nl, - ), - wantCont: true, - wantPatterns: []string{}, - }, { - name: "has", - data: []byte(`allow-hotplug ` + iface + nl + - `iface ` + iface + ` inet static` + nl + - ` address 192.168.0.200` + nl + - ` netmask 255.255.255.0` + nl + - ` gateway 192.168.0.1` + nl + - `#iface ` + iface + ` inet dhcp` + nl, - ), - wantCont: false, - wantPatterns: []string{}, - }, { - name: "return_patterns", - data: []byte(`source hello` + nl + - `source world` + nl + - `#iface ` + iface + ` inet static` + nl, - ), - wantCont: true, - wantPatterns: []string{"hello", "world"}, - }, { - // This one tests if the first found valid interface prevents - // checking files under the `source` directive. - name: "ignore_patterns", - data: []byte(`source hello` + nl + - `source world` + nl + - `iface ` + iface + ` inet static` + nl, - ), - wantCont: false, - wantPatterns: []string{}, - }} - - for _, tc := range testCases { - r := bytes.NewReader(tc.data) - t.Run(tc.name, func(t *testing.T) { - patterns, has, err := iface.ifacesStaticConfig(r) - require.NoError(t, err) - - assert.Equal(t, tc.wantCont, has) - assert.ElementsMatch(t, tc.wantPatterns, patterns) - }) - } -} - -func TestSetStaticIPdhcpcdConf(t *testing.T) { +func TestSetStaticIP_dhcpcdConfIface(t *testing.T) { testCases := []struct { name string dhcpcdConf string diff --git a/internal/aghnet/net_openbsd.go b/internal/aghnet/net_openbsd.go index 627db0ab..68ef90e0 100644 --- a/internal/aghnet/net_openbsd.go +++ b/internal/aghnet/net_openbsd.go @@ -20,7 +20,7 @@ func canBindPrivilegedPorts() (can bool, err error) { func ifaceHasStaticIP(ifaceName string) (ok bool, err error) { filename := fmt.Sprintf("etc/hostname.%s", ifaceName) - return aghos.FileWalker(hostnameIfStaticConfig).Walk(aghos.RootDirFS(), filename) + return aghos.FileWalker(hostnameIfStaticConfig).Walk(rootDirFS, filename) } // hostnameIfStaticConfig checks if the interface is configured by diff --git a/internal/aghnet/net_openbsd_test.go b/internal/aghnet/net_openbsd_test.go index e157d93a..356799b7 100644 --- a/internal/aghnet/net_openbsd_test.go +++ b/internal/aghnet/net_openbsd_test.go @@ -4,49 +4,69 @@ package aghnet import ( - "strings" + "fmt" + "io/fs" "testing" + "testing/fstest" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -func TestHostnameIfStaticConfig(t *testing.T) { - const nl = "\n" +func TestIfaceHasStaticIP(t *testing.T) { + const ifaceName = "em0" + + confFile := fmt.Sprintf("etc/hostname.%s", ifaceName) testCases := []struct { - name string - rcconfData string - wantHas bool + name string + rootFsys fs.FS + wantHas assert.BoolAssertionFunc }{{ - name: "simple", - rcconfData: `inet 127.0.0.253` + nl, - wantHas: true, + name: "simple", + rootFsys: fstest.MapFS{ + confFile: &fstest.MapFile{ + Data: []byte(`inet 127.0.0.253` + nl), + }, + }, + wantHas: assert.True, }, { - name: "case_sensitiveness", - rcconfData: `InEt 127.0.0.253` + nl, - wantHas: false, + name: "case_sensitiveness", + rootFsys: fstest.MapFS{ + confFile: &fstest.MapFile{ + Data: []byte(`InEt 127.0.0.253` + nl), + }, + }, + wantHas: assert.False, }, { name: "comments_and_trash", - rcconfData: `# comment 1` + nl + - `` + nl + - `# inet 127.0.0.253` + nl + - `inet` + nl, - wantHas: false, + rootFsys: fstest.MapFS{ + confFile: &fstest.MapFile{ + Data: []byte(`# comment 1` + nl + nl + + `# inet 127.0.0.253` + nl + + `inet` + nl, + ), + }, + }, + wantHas: assert.False, }, { name: "incorrect_config", - rcconfData: `inet6 127.0.0.253` + nl + - `inet 256.256.256.256` + nl, - wantHas: false, + rootFsys: fstest.MapFS{ + confFile: &fstest.MapFile{ + Data: []byte(`inet6 127.0.0.253` + nl + `inet 256.256.256.256` + nl), + }, + }, + wantHas: assert.False, }} for _, tc := range testCases { - r := strings.NewReader(tc.rcconfData) t.Run(tc.name, func(t *testing.T) { - _, has, err := hostnameIfStaticConfig(r) + substRootDirFS(t, tc.rootFsys) + + has, err := IfaceHasStaticIP(ifaceName) require.NoError(t, err) - assert.Equal(t, tc.wantHas, has) + tc.wantHas(t, has) }) } } diff --git a/internal/aghnet/net_test.go b/internal/aghnet/net_test.go index b461cb44..29de869b 100644 --- a/internal/aghnet/net_test.go +++ b/internal/aghnet/net_test.go @@ -1,9 +1,11 @@ package aghnet import ( + "fmt" "io/fs" "net" "os" + "strings" "testing" "github.com/AdguardTeam/AdGuardHome/internal/aghtest" @@ -14,11 +16,102 @@ import ( "github.com/stretchr/testify/require" ) +func TestMain(m *testing.M) { + aghtest.DiscardLogOutput(m) +} + // testdata is the filesystem containing data for testing the package. var testdata fs.FS = os.DirFS("./testdata") -func TestMain(m *testing.M) { - aghtest.DiscardLogOutput(m) +// 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) { + t.Helper() + + prev := rootDirFS + t.Cleanup(func() { rootDirFS = prev }) + rootDirFS = fsys +} + +// 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 s 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 TestGatewayIP(t *testing.T) { + testCases := []struct { + name string + shell mapShell + want net.IP + }{{ + name: "success_v4", + shell: theOnlyCmd("ip route show dev ifaceName", 0, `default via 1.2.3.4 onlink`, nil), + want: net.IP{1, 2, 3, 4}.To16(), + }, { + name: "success_v6", + shell: theOnlyCmd("ip route show dev ifaceName", 0, `default via ::ffff onlink`, nil), + want: net.IP{ + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xFF, 0xFF, + }, + }, { + name: "bad_output", + shell: theOnlyCmd("ip route show dev ifaceName", 0, `non-default via 1.2.3.4 onlink`, nil), + want: nil, + }, { + name: "err_runcmd", + shell: theOnlyCmd("ip route show dev ifaceName", 0, "", errors.Error("can't run command")), + want: nil, + }, { + name: "bad_code", + shell: theOnlyCmd("ip route show dev ifaceName", 1, "", nil), + want: nil, + }} + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + substShell(t, tc.shell.RunCmd) + + assert.Equal(t, tc.want, GatewayIP("ifaceName")) + }) + } } func TestGetInterfaceByIP(t *testing.T) { @@ -133,6 +226,8 @@ func TestCheckPort(t *testing.T) { } func TestCollectAllIfacesAddrs(t *testing.T) { + t.Skip("TODO(e.burkov): Substitute the net.Interfaces.") + addrs, err := CollectAllIfacesAddrs() require.NoError(t, err) diff --git a/internal/aghos/os.go b/internal/aghos/os.go index 8ac189a1..018a3e89 100644 --- a/internal/aghos/os.go +++ b/internal/aghos/os.go @@ -57,20 +57,22 @@ func HaveAdminRights() (bool, error) { const MaxCmdOutputSize = 64 * 1024 // RunCommand runs shell command. -func RunCommand(command string, arguments ...string) (code int, output string, err error) { +func RunCommand(command string, arguments ...string) (code int, output []byte, err error) { cmd := exec.Command(command, arguments...) out, err := cmd.Output() if len(out) > MaxCmdOutputSize { out = out[:MaxCmdOutputSize] } - if errors.As(err, new(*exec.ExitError)) { - return cmd.ProcessState.ExitCode(), string(out), nil - } else if err != nil { - return 1, "", fmt.Errorf("command %q failed: %w: %s", command, err, out) + if err != nil { + if eerr := new(exec.ExitError); errors.As(err, &eerr) { + return eerr.ExitCode(), eerr.Stderr, nil + } + + return 1, nil, fmt.Errorf("command %q failed: %w: %s", command, err, out) } - return cmd.ProcessState.ExitCode(), string(out), nil + return cmd.ProcessState.ExitCode(), out, nil } // PIDByCommand searches for process named command and returns its PID ignoring diff --git a/internal/home/service_openbsd.go b/internal/home/service_openbsd.go index 679a7437..8ad0d212 100644 --- a/internal/home/service_openbsd.go +++ b/internal/home/service_openbsd.go @@ -314,12 +314,13 @@ func (s *openbsdRunComService) runCom(cmd string) (out string, err error) { // TODO(e.burkov): It's possible that os.ErrNotExist is caused by // something different than the service script's non-existence. Keep it // in mind, when replace the aghos.RunCommand. - _, out, err = aghos.RunCommand(scriptPath, cmd) + var outData []byte + _, outData, err = aghos.RunCommand(scriptPath, cmd) if errors.Is(err, os.ErrNotExist) { return "", service.ErrNotInstalled } - return out, err + return string(outData), err } // Status implements service.Service interface for *openbsdRunComService. From a79b61aac31db689a0d704bf356e67a6ea6f881e Mon Sep 17 00:00:00 2001 From: Ildar Kamalov Date: Thu, 31 Mar 2022 11:54:47 +0300 Subject: [PATCH 016/110] Pull request: fix down flag Squashed commit of the following: commit ea446e844a21e7e7e0271d4d133c581014facda1 Merge: bb8cabfa 5e71f5df Author: Ildar Kamalov Date: Thu Mar 31 10:49:20 2022 +0300 Merge branch 'master' into client-down-flag commit bb8cabfae8e2e3eaa09f48ffe7d2fb3b308d31fb Author: Ildar Kamalov Date: Wed Mar 30 19:27:30 2022 +0300 client: fix down flag --- client/src/install/Setup/Settings.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/client/src/install/Setup/Settings.js b/client/src/install/Setup/Settings.js index ce128fb8..234d345a 100644 --- a/client/src/install/Setup/Settings.js +++ b/client/src/install/Setup/Settings.js @@ -4,6 +4,7 @@ import PropTypes from 'prop-types'; import { Field, reduxForm, formValueSelector } from 'redux-form'; import { Trans, withTranslation } from 'react-i18next'; import flow from 'lodash/flow'; +import i18n from 'i18next'; import Controls from './Controls'; import AddressList from './AddressList'; @@ -31,10 +32,10 @@ const renderInterfaces = (interfaces) => Object.values(interfaces) if (option && ip_addresses?.length > 0) { const ip = getInterfaceIp(option); - const isDown = flags?.includes('down'); + const isUp = flags?.includes('up'); - return ; } From c70f941bf87b92d819e6a7adf5255bc43404b026 Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Thu, 31 Mar 2022 19:56:50 +0300 Subject: [PATCH 017/110] Pull request: 2846 cover aghnet vol.4 Merge in DNS/adguard-home from 2846-cover-aghnet-vol.4 to master Updates #2846. Squashed commit of the following: commit 576ef857628a403ce1478c10a4aad23985c09613 Author: Eugene Burkov Date: Thu Mar 31 19:38:57 2022 +0300 aghnet: imp code commit 5b4b17ff52867aaab2c9d30a0fc7fc2fe31ff4d5 Author: Eugene Burkov Date: Thu Mar 31 14:58:34 2022 +0300 aghnet: imp coverage --- internal/aghnet/arpdb_test.go | 10 +++ internal/aghnet/hostgen.go | 9 +-- internal/aghnet/hostgen_test.go | 88 +++++++++++++--------- internal/aghnet/net.go | 80 ++++++++------------ internal/aghnet/net_darwin.go | 4 - internal/aghnet/net_freebsd.go | 4 - internal/aghnet/net_freebsd_test.go | 2 +- internal/aghnet/net_linux.go | 70 +++++++++-------- internal/aghnet/net_linux_test.go | 36 --------- internal/aghnet/net_nolinux.go | 10 +++ internal/aghnet/net_openbsd.go | 4 - internal/aghnet/net_test.go | 112 +++++++++++++++++++++++++--- internal/aghnet/net_windows.go | 4 - internal/home/home.go | 37 ++++----- scripts/make/go-lint.sh | 3 +- 15 files changed, 266 insertions(+), 207 deletions(-) create mode 100644 internal/aghnet/net_nolinux.go diff --git a/internal/aghnet/arpdb_test.go b/internal/aghnet/arpdb_test.go index 75778b74..d6971448 100644 --- a/internal/aghnet/arpdb_test.go +++ b/internal/aghnet/arpdb_test.go @@ -181,6 +181,16 @@ func TestCmdARPDB_arpa(t *testing.T) { err := a.Refresh() testutil.AssertErrorMsg(t, "cmd arpdb: running command: unexpected exit code 1", err) }) + + t.Run("empty", func(t *testing.T) { + sh := theOnlyCmd("cmd", 0, "", nil) + substShell(t, sh.RunCmd) + + err := a.Refresh() + require.NoError(t, err) + + assert.Empty(t, a.Neighbors()) + }) } func TestEmptyARPDB(t *testing.T) { diff --git a/internal/aghnet/hostgen.go b/internal/aghnet/hostgen.go index d9278515..683c8d9f 100644 --- a/internal/aghnet/hostgen.go +++ b/internal/aghnet/hostgen.go @@ -11,7 +11,7 @@ const ( ipv6HostnameMaxLen = len("ff80-f076-0000-0000-0000-0000-0000-0010") ) -// generateIPv4Hostname generates the hostname for specific IP version. +// generateIPv4Hostname generates the hostname by IP address version 4. func generateIPv4Hostname(ipv4 net.IP) (hostname string) { hnData := make([]byte, 0, ipv4HostnameMaxLen) for i, part := range ipv4 { @@ -24,7 +24,7 @@ func generateIPv4Hostname(ipv4 net.IP) (hostname string) { return string(hnData) } -// generateIPv6Hostname generates the hostname for specific IP version. +// generateIPv6Hostname generates the hostname by IP address version 6. func generateIPv6Hostname(ipv6 net.IP) (hostname string) { hnData := make([]byte, 0, ipv6HostnameMaxLen) for i, partsNum := 0, net.IPv6len/2; i < partsNum; i++ { @@ -51,12 +51,11 @@ func generateIPv6Hostname(ipv6 net.IP) (hostname string) { // // ff80-f076-0000-0000-0000-0000-0000-0010 // +// ip must be either an IPv4 or an IPv6. func GenerateHostname(ip net.IP) (hostname string) { if ipv4 := ip.To4(); ipv4 != nil { return generateIPv4Hostname(ipv4) - } else if ipv6 := ip.To16(); ipv6 != nil { - return generateIPv6Hostname(ipv6) } - return "" + return generateIPv6Hostname(ip) } diff --git a/internal/aghnet/hostgen_test.go b/internal/aghnet/hostgen_test.go index 37121628..d37e556b 100644 --- a/internal/aghnet/hostgen_test.go +++ b/internal/aghnet/hostgen_test.go @@ -8,41 +8,57 @@ import ( ) func TestGenerateHostName(t *testing.T) { - testCases := []struct { - name string - want string - ip net.IP - }{{ - name: "good_ipv4", - want: "127-0-0-1", - ip: net.IP{127, 0, 0, 1}, - }, { - name: "bad_ipv4", - want: "", - ip: net.IP{127, 0, 0, 1, 0}, - }, { - name: "good_ipv6", - want: "fe00-0000-0000-0000-0000-0000-0000-0001", - ip: net.ParseIP("fe00::1"), - }, { - name: "bad_ipv6", - want: "", - ip: net.IP{ - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, - }, - }, { - name: "nil", - want: "", - ip: nil, - }} + t.Run("valid", func(t *testing.T) { + testCases := []struct { + name string + want string + ip net.IP + }{{ + name: "good_ipv4", + want: "127-0-0-1", + ip: net.IP{127, 0, 0, 1}, + }, { + name: "good_ipv6", + want: "fe00-0000-0000-0000-0000-0000-0000-0001", + ip: net.ParseIP("fe00::1"), + }, { + name: "4to6", + want: "1-2-3-4", + ip: net.ParseIP("::ffff:1.2.3.4"), + }} - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - hostname := GenerateHostname(tc.ip) - assert.Equal(t, tc.want, hostname) - }) - } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + hostname := GenerateHostname(tc.ip) + assert.Equal(t, tc.want, hostname) + }) + } + }) + + t.Run("invalid", func(t *testing.T) { + testCases := []struct { + name string + ip net.IP + }{{ + name: "bad_ipv4", + ip: net.IP{127, 0, 0, 1, 0}, + }, { + name: "bad_ipv6", + ip: net.IP{ + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, + }, + }, { + name: "nil", + ip: nil, + }} + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + assert.Panics(t, func() { GenerateHostname(tc.ip) }) + }) + } + }) } diff --git a/internal/aghnet/net.go b/internal/aghnet/net.go index d17b9165..cd2edc72 100644 --- a/internal/aghnet/net.go +++ b/internal/aghnet/net.go @@ -15,13 +15,17 @@ import ( "github.com/AdguardTeam/golibs/netutil" ) -// aghosRunCommand is the function to run shell commands. It's an unexported -// variable instead of a direct call to make it substitutable in tests. -var aghosRunCommand = aghos.RunCommand +// Variables and functions to substitute in tests. +var ( + // aghosRunCommand is the function to run shell commands. + aghosRunCommand = aghos.RunCommand -// rootDirFS is the filesystem pointing to the root directory. It's an -// unexported variable instead to make it substitutable in tests. -var rootDirFS = aghos.RootDirFS() + // netInterfaces is the function to get the available network interfaces. + netInterfaceAddrs = net.InterfaceAddrs + + // rootDirFS is the filesystem pointing to the root directory. + rootDirFS = aghos.RootDirFS() +) // ErrNoStaticIPInfo is returned by IfaceHasStaticIP when no information about // the IP being static is available. @@ -65,23 +69,6 @@ func GatewayIP(ifaceName string) (ip net.IP) { return net.ParseIP(string(fields[2])) } -// CanBindPort checks if we can bind to the given port. -func CanBindPort(port int) (can bool, err error) { - var addr *net.TCPAddr - addr, err = net.ResolveTCPAddr("tcp", fmt.Sprintf("127.0.0.1:%d", port)) - if err != nil { - return false, err - } - - var listener *net.TCPListener - listener, err = net.ListenTCP("tcp", addr) - if err != nil { - return false, err - } - _ = listener.Close() - return true, nil -} - // CanBindPrivilegedPorts checks if current process can bind to privileged // ports. func CanBindPrivilegedPorts() (can bool, err error) { @@ -100,8 +87,8 @@ type NetInterface struct { MTU int `json:"mtu"` } -// MarshalJSON implements the json.Marshaler interface for NetInterface. -func (iface NetInterface) MarshalJSON() ([]byte, error) { +// MarshalText implements the json.Marshaler interface for NetInterface. +func (iface NetInterface) MarshalText() ([]byte, error) { type netInterface NetInterface return json.Marshal(&struct { HardwareAddr string `json:"hardware_address"` @@ -114,9 +101,12 @@ func (iface NetInterface) MarshalJSON() ([]byte, error) { }) } -// GetValidNetInterfacesForWeb returns interfaces that are eligible for DNS and WEB only -// we do not return link-local addresses here -func GetValidNetInterfacesForWeb() (netInterfaces []*NetInterface, err error) { +// GetValidNetInterfacesForWeb returns interfaces that are eligible for DNS and +// WEB only we do not return link-local addresses here. +// +// TODO(e.burkov): Can't properly test the function since it's nontrivial to +// substitute net.Interface.Addrs and the net.InterfaceAddrs can't be used. +func GetValidNetInterfacesForWeb() (netIfaces []*NetInterface, err error) { ifaces, err := net.Interfaces() if err != nil { return nil, fmt.Errorf("couldn't get interfaces: %w", err) @@ -157,14 +147,16 @@ func GetValidNetInterfacesForWeb() (netInterfaces []*NetInterface, err error) { // Discard interfaces with no addresses. if len(netIface.Addresses) != 0 { - netInterfaces = append(netInterfaces, netIface) + netIfaces = append(netIfaces, netIface) } } - return netInterfaces, nil + return netIfaces, nil } // GetInterfaceByIP returns the name of interface containing provided ip. +// +// TODO(e.burkov): See TODO on GetValidInterfacesForWeb. func GetInterfaceByIP(ip net.IP) string { ifaces, err := GetValidNetInterfacesForWeb() if err != nil { @@ -184,6 +176,8 @@ func GetInterfaceByIP(ip net.IP) string { // GetSubnet returns pointer to net.IPNet for the specified interface or nil if // the search fails. +// +// TODO(e.burkov): See TODO on GetValidInterfacesForWeb. func GetSubnet(ifaceName string) *net.IPNet { netIfaces, err := GetValidNetInterfacesForWeb() if err != nil { @@ -234,29 +228,21 @@ func IsAddrInUse(err error) (ok bool) { // CollectAllIfacesAddrs returns the slice of all network interfaces IP // addresses without port number. func CollectAllIfacesAddrs() (addrs []string, err error) { - var ifaces []net.Interface - ifaces, err = net.Interfaces() + var ifaceAddrs []net.Addr + ifaceAddrs, err = netInterfaceAddrs() if err != nil { - return nil, fmt.Errorf("getting network interfaces: %w", err) + return nil, fmt.Errorf("getting interfaces addresses: %w", err) } - for _, iface := range ifaces { - var ifaceAddrs []net.Addr - ifaceAddrs, err = iface.Addrs() + for _, addr := range ifaceAddrs { + cidr := addr.String() + var ip net.IP + ip, _, err = net.ParseCIDR(cidr) if err != nil { - return nil, fmt.Errorf("getting addresses for %q: %w", iface.Name, err) + return nil, fmt.Errorf("parsing cidr: %w", err) } - for _, addr := range ifaceAddrs { - cidr := addr.String() - var ip net.IP - ip, _, err = net.ParseCIDR(cidr) - if err != nil { - return nil, fmt.Errorf("parsing cidr: %w", err) - } - - addrs = append(addrs, ip.String()) - } + addrs = append(addrs, ip.String()) } return addrs, nil diff --git a/internal/aghnet/net_darwin.go b/internal/aghnet/net_darwin.go index 63e57dc4..296a18b0 100644 --- a/internal/aghnet/net_darwin.go +++ b/internal/aghnet/net_darwin.go @@ -24,10 +24,6 @@ type hardwarePortInfo struct { static bool } -func canBindPrivilegedPorts() (can bool, err error) { - return aghos.HaveAdminRights() -} - func ifaceHasStaticIP(ifaceName string) (ok bool, err error) { portInfo, err := getCurrentHardwarePortInfo(ifaceName) if err != nil { diff --git a/internal/aghnet/net_freebsd.go b/internal/aghnet/net_freebsd.go index 34d93303..85d40184 100644 --- a/internal/aghnet/net_freebsd.go +++ b/internal/aghnet/net_freebsd.go @@ -13,10 +13,6 @@ import ( "github.com/AdguardTeam/AdGuardHome/internal/aghos" ) -func canBindPrivilegedPorts() (can bool, err error) { - return aghos.HaveAdminRights() -} - func ifaceHasStaticIP(ifaceName string) (ok bool, err error) { const rcConfFilename = "etc/rc.conf" diff --git a/internal/aghnet/net_freebsd_test.go b/internal/aghnet/net_freebsd_test.go index e00dafa7..2c758360 100644 --- a/internal/aghnet/net_freebsd_test.go +++ b/internal/aghnet/net_freebsd_test.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/require" ) -func TestRcConfStaticConfig(t *testing.T) { +func TestIfaceHasStaticIP(t *testing.T) { const ( ifaceName = `em0` rcConf = "etc/rc.conf" diff --git a/internal/aghnet/net_linux.go b/internal/aghnet/net_linux.go index c2526524..148abe1f 100644 --- a/internal/aghnet/net_linux.go +++ b/internal/aghnet/net_linux.go @@ -13,10 +13,28 @@ import ( "github.com/AdguardTeam/AdGuardHome/internal/aghos" "github.com/AdguardTeam/golibs/errors" + "github.com/AdguardTeam/golibs/stringutil" "github.com/google/renameio/maybe" "golang.org/x/sys/unix" ) +// dhcpсdConf is the name of /etc/dhcpcd.conf file in the root filesystem. +const dhcpcdConf = "etc/dhcpcd.conf" + +func canBindPrivilegedPorts() (can bool, err error) { + cnbs, err := unix.PrctlRetInt( + unix.PR_CAP_AMBIENT, + unix.PR_CAP_AMBIENT_IS_SET, + unix.CAP_NET_BIND_SERVICE, + 0, + 0, + ) + // Don't check the error because it's always nil on Linux. + adm, _ := aghos.HaveAdminRights() + + return cnbs == 1 || adm, err +} + // dhcpcdStaticConfig checks if interface is configured by /etc/dhcpcd.conf to // have a static IP. func (n interfaceName) dhcpcdStaticConfig(r io.Reader) (subsources []string, cont bool, err error) { @@ -89,7 +107,7 @@ func ifaceHasStaticIP(ifaceName string) (has bool, err error) { filename string }{{ FileWalker: iface.dhcpcdStaticConfig, - filename: "etc/dhcpcd.conf", + filename: dhcpcdConf, }, { FileWalker: iface.ifacesStaticConfig, filename: "etc/network/interfaces", @@ -105,14 +123,6 @@ func ifaceHasStaticIP(ifaceName string) (has bool, err error) { return false, ErrNoStaticIPInfo } -func canBindPrivilegedPorts() (can bool, err error) { - cnbs, err := unix.PrctlRetInt(unix.PR_CAP_AMBIENT, unix.PR_CAP_AMBIENT_IS_SET, unix.CAP_NET_BIND_SERVICE, 0, 0) - // Don't check the error because it's always nil on Linux. - adm, _ := aghos.HaveAdminRights() - - return cnbs == 1 || adm, err -} - // findIfaceLine scans s until it finds the line that declares an interface with // the given name. If findIfaceLine can't find the line, it returns false. func findIfaceLine(s *bufio.Scanner, name string) (ok bool) { @@ -128,25 +138,23 @@ func findIfaceLine(s *bufio.Scanner, name string) (ok bool) { } // ifaceSetStaticIP configures the system to retain its current IP on the -// interface through dhcpdc.conf. +// interface through dhcpcd.conf. func ifaceSetStaticIP(ifaceName string) (err error) { ipNet := GetSubnet(ifaceName) if ipNet.IP == nil { return errors.Error("can't get IP address") } - gatewayIP := GatewayIP(ifaceName) - add := dhcpcdConfIface(ifaceName, ipNet, gatewayIP, ipNet.IP) - - const filename = "/etc/dhcpcd.conf" - - body, err := os.ReadFile(filename) + body, err := os.ReadFile(dhcpcdConf) if err != nil && !errors.Is(err, os.ErrNotExist) { return err } + gatewayIP := GatewayIP(ifaceName) + add := dhcpcdConfIface(ifaceName, ipNet, gatewayIP) + body = append(body, []byte(add)...) - err = maybe.WriteFile(filename, body, 0o644) + err = maybe.WriteFile(dhcpcdConf, body, 0o644) if err != nil { return fmt.Errorf("writing conf: %w", err) } @@ -156,22 +164,24 @@ func ifaceSetStaticIP(ifaceName string) (err error) { // dhcpcdConfIface returns configuration lines for the dhcpdc.conf files that // configure the interface to have a static IP. -func dhcpcdConfIface(ifaceName string, ipNet *net.IPNet, gatewayIP, dnsIP net.IP) (conf string) { - var body []byte - - add := fmt.Sprintf( - "\n# %[1]s added by AdGuard Home.\ninterface %[1]s\nstatic ip_address=%s\n", +func dhcpcdConfIface(ifaceName string, ipNet *net.IPNet, gwIP net.IP) (conf string) { + b := &strings.Builder{} + stringutil.WriteToBuilder( + b, + "\n# ", ifaceName, - ipNet) - body = append(body, []byte(add)...) + " added by AdGuard Home.\ninterface ", + ifaceName, + "\nstatic ip_address=", + ipNet.String(), + "\n", + ) - if gatewayIP != nil { - add = fmt.Sprintf("static routers=%s\n", gatewayIP) - body = append(body, []byte(add)...) + if gwIP != nil { + stringutil.WriteToBuilder(b, "static routers=", gwIP.String(), "\n") } - add = fmt.Sprintf("static domain_name_servers=%s\n\n", dnsIP) - body = append(body, []byte(add)...) + stringutil.WriteToBuilder(b, "static domain_name_servers=", ipNet.IP.String(), "\n\n") - return string(body) + return b.String() } diff --git a/internal/aghnet/net_linux_test.go b/internal/aghnet/net_linux_test.go index e46da4df..838802ff 100644 --- a/internal/aghnet/net_linux_test.go +++ b/internal/aghnet/net_linux_test.go @@ -5,7 +5,6 @@ package aghnet import ( "io/fs" - "net" "testing" "testing/fstest" @@ -126,38 +125,3 @@ func TestHasStaticIP(t *testing.T) { }) } } - -func TestSetStaticIP_dhcpcdConfIface(t *testing.T) { - testCases := []struct { - name string - dhcpcdConf string - routers net.IP - }{{ - name: "with_gateway", - dhcpcdConf: nl + `# wlan0 added by AdGuard Home.` + nl + - `interface wlan0` + nl + - `static ip_address=192.168.0.2/24` + nl + - `static routers=192.168.0.1` + nl + - `static domain_name_servers=192.168.0.2` + nl + nl, - routers: net.IP{192, 168, 0, 1}, - }, { - name: "without_gateway", - dhcpcdConf: nl + `# wlan0 added by AdGuard Home.` + nl + - `interface wlan0` + nl + - `static ip_address=192.168.0.2/24` + nl + - `static domain_name_servers=192.168.0.2` + nl + nl, - routers: nil, - }} - - ipNet := &net.IPNet{ - IP: net.IP{192, 168, 0, 2}, - Mask: net.IPMask{255, 255, 255, 0}, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - s := dhcpcdConfIface("wlan0", ipNet, tc.routers, net.IP{192, 168, 0, 2}) - assert.Equal(t, tc.dhcpcdConf, s) - }) - } -} diff --git a/internal/aghnet/net_nolinux.go b/internal/aghnet/net_nolinux.go new file mode 100644 index 00000000..f429c6fa --- /dev/null +++ b/internal/aghnet/net_nolinux.go @@ -0,0 +1,10 @@ +//go:build !linux +// +build !linux + +package aghnet + +import "github.com/AdguardTeam/AdGuardHome/internal/aghos" + +func canBindPrivilegedPorts() (can bool, err error) { + return aghos.HaveAdminRights() +} diff --git a/internal/aghnet/net_openbsd.go b/internal/aghnet/net_openbsd.go index 68ef90e0..cf911105 100644 --- a/internal/aghnet/net_openbsd.go +++ b/internal/aghnet/net_openbsd.go @@ -13,10 +13,6 @@ import ( "github.com/AdguardTeam/AdGuardHome/internal/aghos" ) -func canBindPrivilegedPorts() (can bool, err error) { - return aghos.HaveAdminRights() -} - func ifaceHasStaticIP(ifaceName string) (ok bool, err error) { filename := fmt.Sprintf("etc/hostname.%s", ifaceName) diff --git a/internal/aghnet/net_test.go b/internal/aghnet/net_test.go index 29de869b..77eab3be 100644 --- a/internal/aghnet/net_test.go +++ b/internal/aghnet/net_test.go @@ -56,7 +56,7 @@ type mapShell map[string]struct { code int } -// theOnlyCmd returns s that only handles a single command and arguments +// 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}} @@ -73,18 +73,34 @@ func (s mapShell) RunCmd(cmd string, args ...string) (code int, out []byte, err return ret.code, []byte(ret.out), ret.err } +// ifaceAddrsFunc is the signature of net.InterfaceAddrs function. +type ifaceAddrsFunc func() (ifaces []net.Addr, err error) + +// substNetInterfaceAddrs replaces the the net.InterfaceAddrs function used +// throughout the package with f for tests ran under t. +func substNetInterfaceAddrs(t *testing.T, f ifaceAddrsFunc) { + t.Helper() + + prev := netInterfaceAddrs + t.Cleanup(func() { netInterfaceAddrs = prev }) + netInterfaceAddrs = f +} + func TestGatewayIP(t *testing.T) { + const ifaceName = "ifaceName" + const cmd = "ip route show dev " + ifaceName + testCases := []struct { name string shell mapShell want net.IP }{{ name: "success_v4", - shell: theOnlyCmd("ip route show dev ifaceName", 0, `default via 1.2.3.4 onlink`, nil), + shell: theOnlyCmd(cmd, 0, `default via 1.2.3.4 onlink`, nil), want: net.IP{1, 2, 3, 4}.To16(), }, { name: "success_v6", - shell: theOnlyCmd("ip route show dev ifaceName", 0, `default via ::ffff onlink`, nil), + shell: theOnlyCmd(cmd, 0, `default via ::ffff onlink`, nil), want: net.IP{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, @@ -93,15 +109,15 @@ func TestGatewayIP(t *testing.T) { }, }, { name: "bad_output", - shell: theOnlyCmd("ip route show dev ifaceName", 0, `non-default via 1.2.3.4 onlink`, nil), + shell: theOnlyCmd(cmd, 0, `non-default via 1.2.3.4 onlink`, nil), want: nil, }, { name: "err_runcmd", - shell: theOnlyCmd("ip route show dev ifaceName", 0, "", errors.Error("can't run command")), + shell: theOnlyCmd(cmd, 0, "", errors.Error("can't run command")), want: nil, }, { name: "bad_code", - shell: theOnlyCmd("ip route show dev ifaceName", 1, "", nil), + shell: theOnlyCmd(cmd, 1, "", nil), want: nil, }} @@ -109,7 +125,7 @@ func TestGatewayIP(t *testing.T) { t.Run(tc.name, func(t *testing.T) { substShell(t, tc.shell.RunCmd) - assert.Equal(t, tc.want, GatewayIP("ifaceName")) + assert.Equal(t, tc.want, GatewayIP(ifaceName)) }) } } @@ -226,12 +242,56 @@ func TestCheckPort(t *testing.T) { } func TestCollectAllIfacesAddrs(t *testing.T) { - t.Skip("TODO(e.burkov): Substitute the net.Interfaces.") + testCases := []struct { + name string + wantErrMsg string + addrs []net.Addr + wantAddrs []string + }{{ + name: "success", + wantErrMsg: ``, + addrs: []net.Addr{&net.IPNet{ + IP: net.IP{1, 2, 3, 4}, + Mask: net.CIDRMask(24, netutil.IPv4BitLen), + }, &net.IPNet{ + IP: net.IP{4, 3, 2, 1}, + Mask: net.CIDRMask(16, netutil.IPv4BitLen), + }}, + wantAddrs: []string{"1.2.3.4", "4.3.2.1"}, + }, { + name: "not_cidr", + wantErrMsg: `parsing cidr: invalid CIDR address: 1.2.3.4`, + addrs: []net.Addr{&net.IPAddr{ + IP: net.IP{1, 2, 3, 4}, + }}, + wantAddrs: nil, + }, { + name: "empty", + wantErrMsg: ``, + addrs: []net.Addr{}, + wantAddrs: nil, + }} - addrs, err := CollectAllIfacesAddrs() - require.NoError(t, err) + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + substNetInterfaceAddrs(t, func() ([]net.Addr, error) { return tc.addrs, nil }) - assert.NotEmpty(t, addrs) + addrs, err := CollectAllIfacesAddrs() + testutil.AssertErrorMsg(t, tc.wantErrMsg, err) + + assert.Equal(t, tc.wantAddrs, addrs) + }) + } + + t.Run("internal_error", func(t *testing.T) { + const errAddrs errors.Error = "can't get addresses" + const wantErrMsg string = `getting interfaces addresses: ` + string(errAddrs) + + substNetInterfaceAddrs(t, func() ([]net.Addr, error) { return nil, errAddrs }) + + _, err := CollectAllIfacesAddrs() + testutil.AssertErrorMsg(t, wantErrMsg, err) + }) } func TestIsAddrInUse(t *testing.T) { @@ -250,3 +310,33 @@ func TestIsAddrInUse(t *testing.T) { assert.False(t, IsAddrInUse(anotherErr)) }) } + +func TestNetInterface_MarshalText(t *testing.T) { + const want = `{` + + `"hardware_address":"aa:bb:cc:dd:ee:ff",` + + `"flags":"up|multicast",` + + `"ip_addresses":["1.2.3.4","aaaa::1"],` + + `"name":"iface0",` + + `"mtu":1500` + + `}` + + ip4, ip6 := net.IP{1, 2, 3, 4}, net.IP{0xAA, 0xAA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} + mask4, mask6 := net.CIDRMask(24, netutil.IPv4BitLen), net.CIDRMask(8, netutil.IPv6BitLen) + + iface := &NetInterface{ + Addresses: []net.IP{ip4, ip6}, + Subnets: []*net.IPNet{{ + IP: ip4.Mask(mask4), + Mask: mask4, + }, { + IP: ip6.Mask(mask6), + Mask: mask6, + }}, + Name: "iface0", + HardwareAddr: net.HardwareAddr{0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}, + Flags: net.FlagUp | net.FlagMulticast, + MTU: 1500, + } + + testutil.AssertMarshalText(t, want, iface) +} diff --git a/internal/aghnet/net_windows.go b/internal/aghnet/net_windows.go index 128f5716..0cea8fe7 100644 --- a/internal/aghnet/net_windows.go +++ b/internal/aghnet/net_windows.go @@ -13,10 +13,6 @@ import ( "golang.org/x/sys/windows" ) -func canBindPrivilegedPorts() (can bool, err error) { - return aghos.HaveAdminRights() -} - func ifaceHasStaticIP(string) (ok bool, err error) { return false, aghos.Unsupported("checking static ip") } diff --git a/internal/home/home.go b/internal/home/home.go index 5fae42c8..df1dc95b 100644 --- a/internal/home/home.go +++ b/internal/home/home.go @@ -517,27 +517,15 @@ func StartMods() error { func checkPermissions() { log.Info("Checking if AdGuard Home has necessary permissions") - if runtime.GOOS == "windows" { - // On Windows we need to have admin rights to run properly - - admin, _ := aghos.HaveAdminRights() - if admin { - return - } - + if ok, err := aghnet.CanBindPrivilegedPorts(); !ok || err != nil { log.Fatal("This is the first launch of AdGuard Home. You must run it as Administrator.") } // We should check if AdGuard Home is able to bind to port 53 - ok, err := aghnet.CanBindPort(53) - - if ok { - log.Info("AdGuard Home can bind to port 53") - return - } - - if errors.Is(err, os.ErrPermission) { - msg := `Permission check failed. + err := aghnet.CheckPort("tcp", net.IP{127, 0, 0, 1}, defaultPortDNS) + if err != nil { + if errors.Is(err, os.ErrPermission) { + log.Fatal(`Permission check failed. AdGuard Home is not allowed to bind to privileged ports (for instance, port 53). Please note, that this is crucial for a server to be able to use privileged ports. @@ -545,16 +533,17 @@ Please note, that this is crucial for a server to be able to use privileged port You have two options: 1. Run AdGuard Home with root privileges 2. On Linux you can grant the CAP_NET_BIND_SERVICE capability: -https://github.com/AdguardTeam/AdGuardHome/wiki/Getting-Started#running-without-superuser` +https://github.com/AdguardTeam/AdGuardHome/wiki/Getting-Started#running-without-superuser`) + } - log.Fatal(msg) + log.Info( + "AdGuard failed to bind to port 53: %s\n\n"+ + "Please note, that this is crucial for a DNS server to be able to use that port.", + err, + ) } - msg := fmt.Sprintf(`AdGuard failed to bind to port 53 due to %v - -Please note, that this is crucial for a DNS server to be able to use that port.`, err) - - log.Info(msg) + log.Info("AdGuard Home can bind to port 53") } // Write PID to a file diff --git a/scripts/make/go-lint.sh b/scripts/make/go-lint.sh index 8e646f0c..32d99480 100644 --- a/scripts/make/go-lint.sh +++ b/scripts/make/go-lint.sh @@ -134,9 +134,10 @@ underscores() { -e '_bsd.go'\ -e '_darwin.go'\ -e '_freebsd.go'\ - -e '_openbsd.go'\ -e '_linux.go'\ -e '_little.go'\ + -e '_nolinux.go'\ + -e '_openbsd.go'\ -e '_others.go'\ -e '_test.go'\ -e '_unix.go'\ From e9e0b7c4f907dd37e35511639caca0a88779bd0f Mon Sep 17 00:00:00 2001 From: Ildar Kamalov Date: Wed, 6 Apr 2022 19:27:24 +0300 Subject: [PATCH 018/110] Pull request: 700 validate only enabled encryption form Merge in DNS/adguard-home from 700-validate to master Updates #700. Squashed commit of the following: commit 9cd9ff2d23352e00c7782cf68195809111c832e5 Author: Ildar Kamalov Date: Wed Apr 6 18:50:11 2022 +0300 client: validate only enabled encryption form --- client/src/components/Settings/Encryption/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/src/components/Settings/Encryption/index.js b/client/src/components/Settings/Encryption/index.js index 13f5c47c..bcd2d323 100644 --- a/client/src/components/Settings/Encryption/index.js +++ b/client/src/components/Settings/Encryption/index.js @@ -25,7 +25,9 @@ class Encryption extends Component { handleFormChange = debounce((values) => { const submitValues = this.getSubmitValues(values); - this.props.validateTlsConfig(submitValues); + if (submitValues.enabled) { + this.props.validateTlsConfig(submitValues); + } }, DEBOUNCE_TIMEOUT); getInitialValues = (data) => { From 8bb95469d92bac60811f3f76c59511e52d0ffadc Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Wed, 6 Apr 2022 19:36:13 +0300 Subject: [PATCH 019/110] Pull request: 4465 fix ifaces resp Merge in DNS/adguard-home from 4465-bad-ifaces-resp to master Closes #4465. Squashed commit of the following: commit cc44252b2f12ba4b15df315253417aba2a3f98a6 Author: Eugene Burkov Date: Wed Apr 6 19:21:40 2022 +0300 aghnet: fix get_addresses --- internal/aghnet/net.go | 4 ++-- internal/aghnet/net_test.go | 12 +++++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/internal/aghnet/net.go b/internal/aghnet/net.go index cd2edc72..268380bd 100644 --- a/internal/aghnet/net.go +++ b/internal/aghnet/net.go @@ -87,8 +87,8 @@ type NetInterface struct { MTU int `json:"mtu"` } -// MarshalText implements the json.Marshaler interface for NetInterface. -func (iface NetInterface) MarshalText() ([]byte, error) { +// MarshalJSON implements the json.Marshaler interface for NetInterface. +func (iface NetInterface) MarshalJSON() ([]byte, error) { type netInterface NetInterface return json.Marshal(&struct { HardwareAddr string `json:"hardware_address"` diff --git a/internal/aghnet/net_test.go b/internal/aghnet/net_test.go index 77eab3be..40d395ba 100644 --- a/internal/aghnet/net_test.go +++ b/internal/aghnet/net_test.go @@ -1,6 +1,8 @@ package aghnet import ( + "bytes" + "encoding/json" "fmt" "io/fs" "net" @@ -311,14 +313,14 @@ func TestIsAddrInUse(t *testing.T) { }) } -func TestNetInterface_MarshalText(t *testing.T) { +func TestNetInterface_MarshalJSON(t *testing.T) { const want = `{` + `"hardware_address":"aa:bb:cc:dd:ee:ff",` + `"flags":"up|multicast",` + `"ip_addresses":["1.2.3.4","aaaa::1"],` + `"name":"iface0",` + `"mtu":1500` + - `}` + `}` + "\n" ip4, ip6 := net.IP{1, 2, 3, 4}, net.IP{0xAA, 0xAA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} mask4, mask6 := net.CIDRMask(24, netutil.IPv4BitLen), net.CIDRMask(8, netutil.IPv6BitLen) @@ -338,5 +340,9 @@ func TestNetInterface_MarshalText(t *testing.T) { MTU: 1500, } - testutil.AssertMarshalText(t, want, iface) + b := &bytes.Buffer{} + err := json.NewEncoder(b).Encode(iface) + require.NoError(t, err) + + assert.Equal(t, want, b.String()) } From 0e608fda1367c33e8da1b8fc28029f45b3d69fab Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Wed, 6 Apr 2022 19:56:39 +0300 Subject: [PATCH 020/110] Pull request: 4437 depr memory opt Merge in DNS/adguard-home from 4437-rm-mem-opt to master Updates #4437. Updates #2044. Squashed commit of the following: commit d1e5520213f6b68570d18a8d831d4923112901ba Merge: 73a6b494 8bb95469 Author: Eugene Burkov Date: Wed Apr 6 19:37:09 2022 +0300 Merge branch 'master' into 4437-rm-mem-opt commit 73a6b4948cb32f1cb79a54b244018b29382fad76 Author: Eugene Burkov Date: Wed Apr 6 18:33:23 2022 +0300 all: imp log of changes commit a62efcdcd44de300726c906c7f6198c0a02d4ccf Author: Eugene Burkov Date: Wed Apr 6 18:27:42 2022 +0300 home: depr memory opt --- CHANGELOG.md | 3 +++ internal/home/home.go | 3 --- internal/home/memory.go | 40 ----------------------------------- internal/home/options.go | 13 ++++++------ internal/home/options_test.go | 32 +++++++++++----------------- 5 files changed, 22 insertions(+), 69 deletions(-) delete mode 100644 internal/home/memory.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d1e9260..9bc865a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -79,6 +79,8 @@ In this release, the schema version has changed from 12 to 13. ### Deprecated +- Obsolete `--no-mem-optimization` option ([#4437]). v0.109.0 will remove the + flag completely. - Go 1.17 support. v0.109.0 will require at least Go 1.18 to build. ### Fixed @@ -111,6 +113,7 @@ In this release, the schema version has changed from 12 to 13. [#4221]: https://github.com/AdguardTeam/AdGuardHome/issues/4221 [#4238]: https://github.com/AdguardTeam/AdGuardHome/issues/4238 [#4276]: https://github.com/AdguardTeam/AdGuardHome/issues/4276 +[#4437]: https://github.com/AdguardTeam/AdGuardHome/issues/4437 [repr]: https://reproducible-builds.org/docs/source-date-epoch/ [doq-draft-10]: https://datatracker.ietf.org/doc/html/draft-ietf-dprive-dnsoquic-10#section-10.2 diff --git a/internal/home/home.go b/internal/home/home.go index df1dc95b..420e67d8 100644 --- a/internal/home/home.go +++ b/internal/home/home.go @@ -389,9 +389,6 @@ func run(args options, clientBuildFS fs.FS) { // configure log level and output configureLogger(args) - // Go memory hacks - memoryUsage(args) - // Print the first message after logger is configured. log.Println(version.Full()) log.Debug("current working directory is %s", Context.workDir) diff --git a/internal/home/memory.go b/internal/home/memory.go deleted file mode 100644 index bcb6e70f..00000000 --- a/internal/home/memory.go +++ /dev/null @@ -1,40 +0,0 @@ -package home - -import ( - "os" - "runtime/debug" - "time" - - "github.com/AdguardTeam/golibs/log" -) - -// memoryUsage implements a couple of not really beautiful hacks which purpose is to -// make OS reclaim the memory freed by AdGuard Home as soon as possible. -// See this for the details on the performance hits & gains: -// https://github.com/AdguardTeam/AdGuardHome/internal/issues/2044#issuecomment-687042211 -func memoryUsage(args options) { - if args.disableMemoryOptimization { - log.Info("Memory optimization is disabled") - return - } - - // Makes Go allocate heap at a slower pace - // By default we keep it at 50% - debug.SetGCPercent(50) - - // madvdontneed: setting madvdontneed=1 will use MADV_DONTNEED - // instead of MADV_FREE on Linux when returning memory to the - // kernel. This is less efficient, but causes RSS numbers to drop - // more quickly. - _ = os.Setenv("GODEBUG", "madvdontneed=1") - - // periodically call "debug.FreeOSMemory" so - // that the OS could reclaim the free memory - go func() { - ticker := time.NewTicker(5 * time.Minute) - for range ticker.C { - log.Debug("free os memory") - debug.FreeOSMemory() - } - }() -} diff --git a/internal/home/options.go b/internal/home/options.go index 6d9a1f99..731c8620 100644 --- a/internal/home/options.go +++ b/internal/home/options.go @@ -7,6 +7,7 @@ import ( "strconv" "github.com/AdguardTeam/AdGuardHome/internal/version" + "github.com/AdguardTeam/golibs/log" ) // options passed from command-line arguments @@ -27,10 +28,6 @@ type options struct { // runningAsService flag is set to true when options are passed from the service runner runningAsService bool - // disableMemoryOptimization - disables memory optimization hacks - // see memoryUsage() function for the details - disableMemoryOptimization bool - glinetMode bool // Activate GL-Inet compatibility mode // noEtcHosts flag should be provided when /etc/hosts file shouldn't be @@ -180,8 +177,12 @@ var noCheckUpdateArg = arg{ var disableMemoryOptimizationArg = arg{ "Disable memory optimization.", "no-mem-optimization", "", - nil, func(o options) (options, error) { o.disableMemoryOptimization = true; return o, nil }, nil, - func(o options) []string { return boolSliceOrNil(o.disableMemoryOptimization) }, + nil, nil, func(_ options, _ string) (f effect, err error) { + log.Info("warning: using --no-mem-optimization flag has no effect and is deprecated") + + return nil, nil + }, + func(o options) []string { return nil }, } var verboseArg = arg{ diff --git a/internal/home/options_test.go b/internal/home/options_test.go index b189f045..21972b0a 100644 --- a/internal/home/options_test.go +++ b/internal/home/options_test.go @@ -101,9 +101,13 @@ func TestParseDisableUpdate(t *testing.T) { assert.True(t, testParseOK(t, "--no-check-update").disableUpdate, "--no-check-update is disable update") } +// TODO(e.burkov): Remove after v0.108.0. func TestParseDisableMemoryOptimization(t *testing.T) { - assert.False(t, testParseOK(t).disableMemoryOptimization, "empty is not disable update") - assert.True(t, testParseOK(t, "--no-mem-optimization").disableMemoryOptimization, "--no-mem-optimization is disable update") + o, eff, err := parse("", []string{"--no-mem-optimization"}) + require.NoError(t, err) + + assert.Nil(t, eff) + assert.Zero(t, o) } func TestParseService(t *testing.T) { @@ -127,8 +131,6 @@ func TestParseUnknown(t *testing.T) { } func TestSerialize(t *testing.T) { - const reportFmt = "expected %s but got %s" - testCases := []struct { name string opts options @@ -173,19 +175,14 @@ func TestSerialize(t *testing.T) { name: "glinet_mode", opts: options{glinetMode: true}, ss: []string{"--glinet"}, - }, { - name: "disable_mem_opt", - opts: options{disableMemoryOptimization: true}, - ss: []string{"--no-mem-optimization"}, }, { name: "multiple", opts: options{ - serviceControlAction: "run", - configFilename: "config", - workDir: "work", - pidFile: "pid", - disableUpdate: true, - disableMemoryOptimization: true, + serviceControlAction: "run", + configFilename: "config", + workDir: "work", + pidFile: "pid", + disableUpdate: true, }, ss: []string{ "-c", "config", @@ -193,18 +190,13 @@ func TestSerialize(t *testing.T) { "-s", "run", "--pidfile", "pid", "--no-check-update", - "--no-mem-optimization", }, }} for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { result := serialize(tc.opts) - require.Lenf(t, result, len(tc.ss), reportFmt, tc.ss, result) - - for i, r := range result { - assert.Equalf(t, tc.ss[i], r, reportFmt, tc.ss, result) - } + assert.ElementsMatch(t, tc.ss, result) }) } } From 4c5b38a4474b573086b1afd97c4e24522829ebe6 Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Thu, 7 Apr 2022 14:07:27 +0300 Subject: [PATCH 021/110] Pull request: 4437 imp help output Merge in DNS/adguard-home from imp-help to master Updates #4437. Squashed commit of the following: commit 941338b93e19021c5b211e9e644387e4326533ce Author: Eugene Burkov Date: Thu Apr 7 13:59:55 2022 +0300 home: imp help output --- internal/home/options.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/home/options.go b/internal/home/options.go index 731c8620..dc11ca35 100644 --- a/internal/home/options.go +++ b/internal/home/options.go @@ -175,7 +175,7 @@ var noCheckUpdateArg = arg{ } var disableMemoryOptimizationArg = arg{ - "Disable memory optimization.", + "Deprecated. Disable memory optimization.", "no-mem-optimization", "", nil, nil, func(_ options, _ string) (f effect, err error) { log.Info("warning: using --no-mem-optimization flag has no effect and is deprecated") From 96594a34333a49a8ce3a818b3b7e48ceb547d7c2 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Thu, 7 Apr 2022 18:08:39 +0300 Subject: [PATCH 022/110] Pull request: dnsforward: upd svcp param ech name Merge in DNS/adguard-home from upd-ech-dnsrewrite to master Squashed commit of the following: commit b5d9e8643fcb0d7fe7bc44c6d8fc8a9d3f2c9595 Author: Ainar Garipov Date: Thu Apr 7 18:01:18 2022 +0300 all: imp chlog commit 447c5ea6bc2031d4af46578bdb8d724bff001ca0 Author: Ainar Garipov Date: Thu Apr 7 15:40:18 2022 +0300 dnsforward: upd svcp param ech name --- CHANGELOG.md | 41 ++++++++++++++++++----------- go.mod | 10 +++---- go.sum | 18 ++++++++----- internal/dnsforward/svcbmsg.go | 30 ++++++++++++++++++--- internal/dnsforward/svcbmsg_test.go | 8 ++++-- 5 files changed, 75 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bc865a3..ca7d27ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,8 +30,11 @@ and this project adheres to ### Changed +- Filtering rules with the `dnsrewrite` modifier that create SVCB or HTTPS + responses should use `ech` instead of `echconfig` to conform with the [latest + drafts][svcb-draft-08]. - The default DNS-over-QUIC port number is now `853` instead of `754` in - accoradance with the latest [RFC draft][doq-draft-10] ([#4276]). + accordance with the latest [RFC draft][doq-draft-10] ([#4276]). - Reverse DNS now has a greater priority as the source of runtime clients' information than ARP neighborhood. - Improved detection of runtime clients through more resilient ARP processing @@ -79,6 +82,9 @@ In this release, the schema version has changed from 12 to 13. ### Deprecated +- SVCB/HTTPS parameter name `echconfig` in filtering rules with the `dnsrewrite` + modifier. Use `ech` instead. v0.109.0 will remove support for the outdated + name `echconfig`. - Obsolete `--no-mem-optimization` option ([#4437]). v0.109.0 will remove the flag completely. - Go 1.17 support. v0.109.0 will require at least Go 1.18 to build. @@ -115,8 +121,9 @@ In this release, the schema version has changed from 12 to 13. [#4276]: https://github.com/AdguardTeam/AdGuardHome/issues/4276 [#4437]: https://github.com/AdguardTeam/AdGuardHome/issues/4437 -[repr]: https://reproducible-builds.org/docs/source-date-epoch/ -[doq-draft-10]: https://datatracker.ietf.org/doc/html/draft-ietf-dprive-dnsoquic-10#section-10.2 +[repr]: https://reproducible-builds.org/docs/source-date-epoch/ +[doq-draft-10]: https://datatracker.ietf.org/doc/html/draft-ietf-dprive-dnsoquic-10#section-10.2 +[svcb-draft-08]: https://www.ietf.org/archive/id/draft-ietf-dnsop-svcb-https-08.html @@ -176,7 +183,7 @@ See also the [v0.107.3 GitHub milestone][ms-v0.107.3]. ### Added -- Support for a `$dnsrewrite` modifier with an empty `NOERROR` response +- Support for a `dnsrewrite` modifier with an empty `NOERROR` response ([#4133]). ### Fixed @@ -292,7 +299,7 @@ See also the [v0.107.0 GitHub milestone][ms-v0.107.0]. - Better error message for ED25519 private keys, which are not widely supported ([#3737]). - Cache now follows RFC more closely for negative answers ([#3707]). -- `$dnsrewrite` rules and other DNS rewrites will now be applied even when the +- `dnsrewrite` rules and other DNS rewrites will now be applied even when the protection is disabled ([#1558]). - DHCP gateway address, subnet mask, IP address range, and leases validations ([#3529]). @@ -365,7 +372,7 @@ In this release, the schema version has changed from 10 to 12. ### Fixed - EDNS0 TCP keepalive option handling ([#3778]). -- Rules with the `$denyallow` modifier applying to IP addresses when they +- Rules with the `denyallow` modifier applying to IP addresses when they shouldn't ([#3175]). - The length of the EDNS0 client subnet option appearing too long for some upstream servers ([#3887]). @@ -373,8 +380,8 @@ In this release, the schema version has changed from 10 to 12. settings ([#3558]). - Incomplete propagation of the client's IP anonymization setting to the statistics ([#3890]). -- Incorrect `$dnsrewrite` results for entries from the operating system's hosts - file ([#3815]). +- Incorrect results with the `dnsrewrite` modifier for entries from the + operating system's hosts file ([#3815]). - Matching against rules with `|` at the end of the domain name ([#3371]). - Incorrect assignment of explicitly configured DHCP options ([#3744]). - Occasional panic during shutdown ([#3655]). @@ -401,8 +408,8 @@ In this release, the schema version has changed from 10 to 12. - Letter case mismatches in `CNAME` filtering ([#3335]). - Occasional breakages on network errors with DNS-over-HTTP upstreams ([#3217]). - Errors when setting static IP on Linux ([#3257]). -- Treatment of domain names and FQDNs in custom rules with `$dnsrewrite` that - use the `PTR` type ([#3256]). +- Treatment of domain names and FQDNs in custom rules with the `dnsrewrite` + modifier that use the `PTR` type ([#3256]). - Redundant hostname generating while loading static leases with empty hostname ([#3166]). - Domain name case in responses ([#3194]). @@ -566,7 +573,7 @@ See also the [v0.106.0 GitHub milestone][ms-v0.106.0]. - The ability to block user for login after configurable number of unsuccessful attempts for configurable time ([#2826]). -- `$denyallow` modifier for filters ([#2923]). +- `denyallow` modifier for filters ([#2923]). - Hostname uniqueness validation in the DHCP server ([#2952]). - Hostname generating for DHCP clients which don't provide their own ([#2723]). - New flag `--no-etc-hosts` to disable client domain name lookups in the @@ -581,7 +588,8 @@ See also the [v0.106.0 GitHub milestone][ms-v0.106.0]. network ([#2393], [#2961]). - The ability to serve DNS queries on multiple hosts and interfaces ([#1401]). - `ips` and `text` DHCP server options ([#2385]). -- `SRV` records support in `$dnsrewrite` filters ([#2533]). +- `SRV` records support in filtering rules with the `dnsrewrite` modifier + ([#2533]). ### Changed @@ -595,7 +603,8 @@ See also the [v0.106.0 GitHub milestone][ms-v0.106.0]. ([#2704]). - Stricter validation of the IP addresses of static leases in the DHCP server with regards to the netmask ([#2838]). -- Stricter validation of `$dnsrewrite` filter modifier parameters ([#2498]). +- Stricter validation of `dnsrewrite` filtering rule modifier parameters + ([#2498]). - New, more correct versioning scheme ([#2412]). ### Deprecated @@ -604,7 +613,7 @@ See also the [v0.106.0 GitHub milestone][ms-v0.106.0]. ### Fixed -- Multiple answers for `$dnsrewrite` rule matching requests with repeating +- Multiple answers for a `dnsrewrite` rule matching requests with repeating patterns in it ([#2981]). - Root server resolving when custom upstreams for hosts are specified ([#2994]). - Inconsistent resolving of DHCP clients when the DHCP server is disabled @@ -743,7 +752,7 @@ See also the [v0.105.0 GitHub milestone][ms-v0.105.0]. - `ipset` subdomain matching, just like `dnsmasq` does ([#2179]). - ClientID support for DNS-over-HTTPS, DNS-over-QUIC, and DNS-over-TLS ([#1383]). -- `$dnsrewrite` modifier for filters ([#2102]). +- The new `dnsrewrite` modifier for filters ([#2102]). - The host checking API and the query logs API can now return multiple matched rules ([#2102]). - Detecting of network interface configured to have static IP address via @@ -751,7 +760,7 @@ See also the [v0.105.0 GitHub milestone][ms-v0.105.0]. - DNSCrypt protocol support ([#1361]). - A 5 second wait period until a DHCP server's network interface gets an IP address ([#2304]). -- `$dnstype` modifier for filters ([#2337]). +- `dnstype` modifier for filters ([#2337]). - HTTP API request body size limit ([#2305]). ### Changed diff --git a/go.mod b/go.mod index 8cfd5475..1886d519 100644 --- a/go.mod +++ b/go.mod @@ -20,14 +20,14 @@ require ( github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 github.com/mdlayher/netlink v1.5.0 github.com/mdlayher/raw v0.0.0-20211126142749-4eae47f3d54b - github.com/miekg/dns v1.1.45 + github.com/miekg/dns v1.1.48 github.com/satori/go.uuid v1.2.0 github.com/stretchr/testify v1.7.0 github.com/ti-mo/netfilter v0.4.0 go.etcd.io/bbolt v1.3.6 golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 - golang.org/x/net v0.0.0-20211216030914-fe4d6282115f - golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e + golang.org/x/net v0.0.0-20220403103023-749bd193bc2b + golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12 gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/yaml.v2 v2.4.0 howett.net/plist v1.0.0 @@ -55,10 +55,10 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/objx v0.1.1 // indirect github.com/u-root/uio v0.0.0-20210528151154-e40b768296a7 // indirect - golang.org/x/mod v0.5.1 // indirect + golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/text v0.3.7 // indirect - golang.org/x/tools v0.1.8 // indirect + golang.org/x/tools v0.1.10 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect diff --git a/go.sum b/go.sum index 5e5ef775..1e8c5022 100644 --- a/go.sum +++ b/go.sum @@ -197,8 +197,8 @@ github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00v github.com/miekg/dns v1.1.40/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= github.com/miekg/dns v1.1.44/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= -github.com/miekg/dns v1.1.45 h1:g5fRIhm9nx7g8osrAvgb16QJfmyMsyOCb+J7LSv+Qzk= -github.com/miekg/dns v1.1.45/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +github.com/miekg/dns v1.1.48 h1:Ucfr7IIVyMBz4lRE8qmGUuZ4Wt3/ZGu9hmcMT3Uu4tQ= +github.com/miekg/dns v1.1.48/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= @@ -301,6 +301,7 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -311,8 +312,9 @@ golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPI golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -353,8 +355,9 @@ golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM= golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220403103023-749bd193bc2b h1:vI32FkLJNAWtGD4BwkThwEy6XS7ZLLMHkSkYfF8M0W0= +golang.org/x/net v0.0.0-20220403103023-749bd193bc2b/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -424,9 +427,11 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12 h1:QyVthZKMsyaQwBTJE04jdNN0Pp5Fn9Qga0mrgxyERQM= +golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -451,8 +456,9 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/internal/dnsforward/svcbmsg.go b/internal/dnsforward/svcbmsg.go index 99413ed3..3d25f05b 100644 --- a/internal/dnsforward/svcbmsg.go +++ b/internal/dnsforward/svcbmsg.go @@ -32,12 +32,16 @@ func (s *Server) genAnswerHTTPS(req *dns.Msg, svcb *rules.DNSSVCB) (ans *dns.HTT // github.com/miekg/dns module. var strToSVCBKey = map[string]dns.SVCBKey{ "alpn": dns.SVCB_ALPN, - "echconfig": dns.SVCB_ECHCONFIG, + "ech": dns.SVCB_ECHCONFIG, "ipv4hint": dns.SVCB_IPV4HINT, "ipv6hint": dns.SVCB_IPV6HINT, "mandatory": dns.SVCB_MANDATORY, "no-default-alpn": dns.SVCB_NO_DEFAULT_ALPN, "port": dns.SVCB_PORT, + + // TODO(a.garipov): This is the previous name for the parameter that has + // since been changed. Remove this in v0.109.0. + "echconfig": dns.SVCB_ECHCONFIG, } // svcbKeyHandler is a handler for one SVCB parameter key. @@ -51,10 +55,10 @@ var svcbKeyHandlers = map[string]svcbKeyHandler{ } }, - "echconfig": func(valStr string) (val dns.SVCBKeyValue) { + "ech": func(valStr string) (val dns.SVCBKeyValue) { ech, err := base64.StdEncoding.DecodeString(valStr) if err != nil { - log.Debug("can't parse svcb/https echconfig: %s; ignoring", err) + log.Debug("can't parse svcb/https ech: %s; ignoring", err) return nil } @@ -119,6 +123,26 @@ var svcbKeyHandlers = map[string]svcbKeyHandler{ Port: uint16(port64), } }, + + // TODO(a.garipov): This is the previous name for the parameter that has + // since been changed. Remove this in v0.109.0. + "echconfig": func(valStr string) (val dns.SVCBKeyValue) { + log.Info( + `warning: svcb/https record parameter name "echconfig" is deprecated; ` + + `use "ech" instead`, + ) + + ech, err := base64.StdEncoding.DecodeString(valStr) + if err != nil { + log.Debug("can't parse svcb/https ech: %s; ignoring", err) + + return nil + } + + return &dns.SVCBECHConfig{ + ECH: ech, + } + }, } // genAnswerSVCB returns a properly initialized SVCB resource record. diff --git a/internal/dnsforward/svcbmsg_test.go b/internal/dnsforward/svcbmsg_test.go index db6994c3..28794531 100644 --- a/internal/dnsforward/svcbmsg_test.go +++ b/internal/dnsforward/svcbmsg_test.go @@ -87,14 +87,18 @@ func TestGenAnswerHTTPS_andSVCB(t *testing.T) { svcb: dnssvcb("alpn", "h3"), want: wantsvcb(&dns.SVCBAlpn{Alpn: []string{"h3"}}), name: "alpn", + }, { + svcb: dnssvcb("ech", "AAAA"), + want: wantsvcb(&dns.SVCBECHConfig{ECH: []byte{0, 0, 0}}), + name: "ech", }, { svcb: dnssvcb("echconfig", "AAAA"), want: wantsvcb(&dns.SVCBECHConfig{ECH: []byte{0, 0, 0}}), - name: "echconfig", + name: "ech_deprecated", }, { svcb: dnssvcb("echconfig", "%BAD%"), want: wantsvcb(nil), - name: "echconfig_invalid", + name: "ech_invalid", }, { svcb: dnssvcb("ipv4hint", "127.0.0.1"), want: wantsvcb(&dns.SVCBIPv4Hint{Hint: []net.IP{ip4}}), From 9f0fdc5e78331a9486c1be2de2d062abff63deb7 Mon Sep 17 00:00:00 2001 From: Dimitry Kolyshev Date: Fri, 8 Apr 2022 16:43:49 +0300 Subject: [PATCH 023/110] Pull request: upd bamboo-specs snapcraft Merge in DNS/adguard-home from upd-bamboo-spec to master Squashed commit of the following: commit c26c70f97cbce98afd5c7d4241188d6949869c2a Author: Dimitry Kolyshev Date: Fri Apr 8 13:51:23 2022 +0200 upd bamboo-specs snapcraft commit afe40c03b70d2b2dff9c7c25044d7924bdd3c765 Author: Dimitry Kolyshev Date: Fri Apr 8 13:10:38 2022 +0200 upd bamboo-specs snapcraft --- bamboo-specs/release.yaml | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/bamboo-specs/release.yaml b/bamboo-specs/release.yaml index 50bf1362..62abf5ce 100644 --- a/bamboo-specs/release.yaml +++ b/bamboo-specs/release.yaml @@ -183,8 +183,27 @@ cd ./dist/ + channel="${bamboo.channel}" + readonly channel + case "$channel" + in + ('release') + snapchannel='candidate' + ;; + ('beta') + snapchannel='beta' + ;; + ('edge') + snapchannel='edge' + ;; + (*) + echo "invalid channel '$channel'" + exit 1 + ;; + esac + env\ - SNAPCRAFT_CHANNEL=edge\ + SNAPCRAFT_CHANNEL="$snapchannel"\ SNAPCRAFT_EMAIL="${bamboo.snapcraftEmail}"\ SNAPCRAFT_MACAROON="${bamboo.snapcraftMacaroonPassword}"\ SNAPCRAFT_UBUNTU_DISCHARGE="${bamboo.snapcraftUbuntuDischargePassword}"\ From 2c2c0d445b338a1411208339816c75898f9fad5e Mon Sep 17 00:00:00 2001 From: Dimitry Kolyshev Date: Tue, 12 Apr 2022 15:45:18 +0300 Subject: [PATCH 024/110] Pull request #1473: svcb dohpath support Merge in DNS/adguard-home from 4463-ddr-support to master Squashed commit of the following: commit 99a149e9024354ad0341739c3c9b08cefbd74468 Author: Dimitry Kolyshev Date: Tue Apr 12 14:13:17 2022 +0200 imp docs commit 26150be8df8b35e47c108f6e3319c57b39fb8e38 Author: Dimitry Kolyshev Date: Mon Apr 11 20:36:18 2022 +0200 imp code docs commit 5a4607f71abba83a9ac8753abd74c9fb97e4a545 Merge: 00f0abf5 9f0fdc5e Author: Dimitry Kolyshev Date: Mon Apr 11 16:14:49 2022 +0200 Merge remote-tracking branch 'origin/master' into 4463-ddr-support # Conflicts: # internal/dnsforward/svcbmsg.go commit 00f0abf5eea07aeeebc2a856a958215021a51ab7 Author: Dimitry Kolyshev Date: Mon Apr 11 16:06:42 2022 +0200 svcb dohpath support commit ace81ce1ea2fb96c4434c6c1fded4a79427cf17e Author: Dimitry Kolyshev Date: Thu Apr 7 14:31:32 2022 +0200 svcb dohpath support commit a1b5df4fb2e87dab265d6ca55928610a6acc1c00 Author: Dimitry Kolyshev Date: Wed Apr 6 16:53:17 2022 +0200 svcb dohpath support --- CHANGELOG.md | 4 ++++ go.mod | 3 +++ go.sum | 2 ++ internal/dnsforward/dnsrewrite_test.go | 32 +++++++++++++++++++++----- internal/dnsforward/svcbmsg.go | 6 +++++ internal/dnsforward/svcbmsg_test.go | 4 ++++ 6 files changed, 45 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca7d27ad..aa305b2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ and this project adheres to ### Added +- Support for SVCB/HTTPS parameter `dohpath` in filtering rules with + `dnsrewrite` modifier according to the [RFC draft][dns-draft-02] ([#4463]). - The ability to customize the set of networks that are considered private through the new `dns.private_networks` property in the configuration file ([#3142]). @@ -120,10 +122,12 @@ In this release, the schema version has changed from 12 to 13. [#4238]: https://github.com/AdguardTeam/AdGuardHome/issues/4238 [#4276]: https://github.com/AdguardTeam/AdGuardHome/issues/4276 [#4437]: https://github.com/AdguardTeam/AdGuardHome/issues/4437 +[#4463]: https://github.com/AdguardTeam/AdGuardHome/issues/4463 [repr]: https://reproducible-builds.org/docs/source-date-epoch/ [doq-draft-10]: https://datatracker.ietf.org/doc/html/draft-ietf-dprive-dnsoquic-10#section-10.2 [svcb-draft-08]: https://www.ietf.org/archive/id/draft-ietf-dnsop-svcb-https-08.html +[dns-draft-02]: https://datatracker.ietf.org/doc/html/draft-ietf-add-svcb-dns-02#section-5.1 diff --git a/go.mod b/go.mod index 1886d519..110f2bbb 100644 --- a/go.mod +++ b/go.mod @@ -64,3 +64,6 @@ require ( gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect honnef.co/go/tools v0.2.2 // indirect ) + +// TODO(a.garipov): Return to the main repo once miekg/dns#1359 is merged. +replace github.com/miekg/dns => github.com/ainar-g/dns v1.1.49-0.20220411125901-8a162bbc18d8 diff --git a/go.sum b/go.sum index 1e8c5022..e405e27c 100644 --- a/go.sum +++ b/go.sum @@ -29,6 +29,8 @@ github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmH github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA= github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 h1:52m0LGchQBBVqJRyYYufQuIbVqRawmubW3OFGqK1ekw= github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635/go.mod h1:lmLxL+FV291OopO93Bwf9fQLQeLyt33VJRUg5VJ30us= +github.com/ainar-g/dns v1.1.49-0.20220411125901-8a162bbc18d8 h1:Hp2waLwK989ui3bDkFpedlIHfyWdZ77gynvd+GPEqXY= +github.com/ainar-g/dns v1.1.49-0.20220411125901-8a162bbc18d8/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/ameshkov/dnscrypt/v2 v2.2.3 h1:X9UP5AHtwp46Ji+sGFfF/1Is6OPI/SjxLqhKpx0P5UI= github.com/ameshkov/dnscrypt/v2 v2.2.3/go.mod h1:xJB9cE1/GF+NB6EEQqRlkoa4bjcV2w7VYn1G+zVq7Bs= github.com/ameshkov/dnsstamps v1.0.1/go.mod h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaEZZ4gKyIH5A= diff --git a/internal/dnsforward/dnsrewrite_test.go b/internal/dnsforward/dnsrewrite_test.go index 347b8f29..5ba10582 100644 --- a/internal/dnsforward/dnsrewrite_test.go +++ b/internal/dnsforward/dnsrewrite_test.go @@ -22,7 +22,7 @@ func TestServer_FilterDNSRewrite(t *testing.T) { Preference: 32, } svcbVal := &rules.DNSSVCB{ - Params: map[string]string{"alpn": "h3"}, + Params: map[string]string{"alpn": "h3", "dohpath": "/dns-query"}, Target: dns.Fqdn(domain), Priority: 32, } @@ -164,10 +164,20 @@ func TestServer_FilterDNSRewrite(t *testing.T) { require.Len(t, d.Res.Answer, 1) ans, ok := d.Res.Answer[0].(*dns.SVCB) - require.True(t, ok) - assert.Equal(t, dns.SVCB_ALPN, ans.Value[0].Key()) - assert.Equal(t, svcbVal.Params["alpn"], ans.Value[0].String()) + require.True(t, ok) + require.Len(t, ans.Value, 2) + + assert.ElementsMatch( + t, + []dns.SVCBKey{dns.SVCB_ALPN, dns.SVCB_DOHPATH}, + []dns.SVCBKey{ans.Value[0].Key(), ans.Value[1].Key()}, + ) + assert.ElementsMatch( + t, + []string{svcbVal.Params["alpn"], svcbVal.Params["dohpath"]}, + []string{ans.Value[0].String(), ans.Value[1].String()}, + ) assert.Equal(t, svcbVal.Target, ans.Target) assert.Equal(t, svcbVal.Priority, ans.Priority) }) @@ -186,8 +196,18 @@ func TestServer_FilterDNSRewrite(t *testing.T) { ans, ok := d.Res.Answer[0].(*dns.HTTPS) require.True(t, ok) - assert.Equal(t, dns.SVCB_ALPN, ans.Value[0].Key()) - assert.Equal(t, svcbVal.Params["alpn"], ans.Value[0].String()) + require.Len(t, ans.Value, 2) + + assert.ElementsMatch( + t, + []dns.SVCBKey{dns.SVCB_ALPN, dns.SVCB_DOHPATH}, + []dns.SVCBKey{ans.Value[0].Key(), ans.Value[1].Key()}, + ) + assert.ElementsMatch( + t, + []string{svcbVal.Params["alpn"], svcbVal.Params["dohpath"]}, + []string{ans.Value[0].String(), ans.Value[1].String()}, + ) assert.Equal(t, svcbVal.Target, ans.Target) assert.Equal(t, svcbVal.Priority, ans.Priority) }) diff --git a/internal/dnsforward/svcbmsg.go b/internal/dnsforward/svcbmsg.go index 3d25f05b..d1e3e3d8 100644 --- a/internal/dnsforward/svcbmsg.go +++ b/internal/dnsforward/svcbmsg.go @@ -143,6 +143,12 @@ var svcbKeyHandlers = map[string]svcbKeyHandler{ ECH: ech, } }, + + "dohpath": func(valStr string) (val dns.SVCBKeyValue) { + return &dns.SVCBDoHPath{ + Template: valStr, + } + }, } // genAnswerSVCB returns a properly initialized SVCB resource record. diff --git a/internal/dnsforward/svcbmsg_test.go b/internal/dnsforward/svcbmsg_test.go index 28794531..8de53988 100644 --- a/internal/dnsforward/svcbmsg_test.go +++ b/internal/dnsforward/svcbmsg_test.go @@ -127,6 +127,10 @@ func TestGenAnswerHTTPS_andSVCB(t *testing.T) { svcb: dnssvcb("no-default-alpn", ""), want: wantsvcb(&dns.SVCBNoDefaultAlpn{}), name: "no_default_alpn", + }, { + svcb: dnssvcb("dohpath", "/dns-query"), + want: wantsvcb(&dns.SVCBDoHPath{Template: "/dns-query"}), + name: "dohpath", }, { svcb: dnssvcb("port", "8080"), want: wantsvcb(&dns.SVCBPort{Port: 8080}), From 21a1187ed2d18e316d8af33c5d8bdd19034fea9f Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Wed, 13 Apr 2022 18:16:33 +0300 Subject: [PATCH 025/110] Pull request: all: upd go, tools Merge in DNS/adguard-home from upd-go to master Squashed commit of the following: commit 26cd13146df705ead5e1c39c27e73252c71fa64d Author: Ainar Garipov Date: Wed Apr 13 17:46:24 2022 +0300 all: upd go, tools --- CHANGELOG.md | 134 +++++++++++++--------- bamboo-specs/release.yaml | 6 +- bamboo-specs/test.yaml | 2 +- go.mod | 45 ++++---- go.sum | 149 +++++++++---------------- internal/aghnet/hostscontainer.go | 2 +- internal/aghnet/hostscontainer_test.go | 30 ++--- internal/filtering/filtering.go | 4 +- internal/tools/go.mod | 24 ++-- internal/tools/go.sum | 74 +++++++----- 10 files changed, 236 insertions(+), 234 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa305b2a..a80b4ea1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,13 +12,17 @@ and this project adheres to ## [Unreleased] +### Security + +- Enforced password strength policy ([#3503]). +- Weaker cipher suites that use the CBC (cipher block chaining) mode of + operation have been disabled ([#2993]). + ### Added -- Support for SVCB/HTTPS parameter `dohpath` in filtering rules with - `dnsrewrite` modifier according to the [RFC draft][dns-draft-02] ([#4463]). - The ability to customize the set of networks that are considered private through the new `dns.private_networks` property in the configuration file ([#3142]). @@ -32,9 +36,6 @@ and this project adheres to ### Changed -- Filtering rules with the `dnsrewrite` modifier that create SVCB or HTTPS - responses should use `ech` instead of `echconfig` to conform with the [latest - drafts][svcb-draft-08]. - The default DNS-over-QUIC port number is now `853` instead of `754` in accordance with the latest [RFC draft][doq-draft-10] ([#4276]). - Reverse DNS now has a greater priority as the source of runtime clients' @@ -84,28 +85,8 @@ In this release, the schema version has changed from 12 to 13. ### Deprecated -- SVCB/HTTPS parameter name `echconfig` in filtering rules with the `dnsrewrite` - modifier. Use `ech` instead. v0.109.0 will remove support for the outdated - name `echconfig`. -- Obsolete `--no-mem-optimization` option ([#4437]). v0.109.0 will remove the - flag completely. - Go 1.17 support. v0.109.0 will require at least Go 1.18 to build. -### Fixed - -- I/O timeout errors on checking another DHCP server. - -### Removed - -- Go 1.16 support. - -### Security - -- `User-Agent` HTTP header removed from outgoing DNS-over-HTTPS requests. -- Enforced password strength policy ([#3503]). -- Weaker cipher suites that use the CBC (cipher block chaining) mode of - operation have been disabled ([#2993]). - [#1730]: https://github.com/AdguardTeam/AdGuardHome/issues/1730 [#2993]: https://github.com/AdguardTeam/AdGuardHome/issues/2993 [#3057]: https://github.com/AdguardTeam/AdGuardHome/issues/3057 @@ -117,27 +98,76 @@ In this release, the schema version has changed from 12 to 13. [#3978]: https://github.com/AdguardTeam/AdGuardHome/issues/3978 [#4166]: https://github.com/AdguardTeam/AdGuardHome/issues/4166 [#4213]: https://github.com/AdguardTeam/AdGuardHome/issues/4213 -[#4216]: https://github.com/AdguardTeam/AdGuardHome/issues/4216 [#4221]: https://github.com/AdguardTeam/AdGuardHome/issues/4221 [#4238]: https://github.com/AdguardTeam/AdGuardHome/issues/4238 [#4276]: https://github.com/AdguardTeam/AdGuardHome/issues/4276 -[#4437]: https://github.com/AdguardTeam/AdGuardHome/issues/4437 -[#4463]: https://github.com/AdguardTeam/AdGuardHome/issues/4463 -[repr]: https://reproducible-builds.org/docs/source-date-epoch/ -[doq-draft-10]: https://datatracker.ietf.org/doc/html/draft-ietf-dprive-dnsoquic-10#section-10.2 -[svcb-draft-08]: https://www.ietf.org/archive/id/draft-ietf-dnsop-svcb-https-08.html -[dns-draft-02]: https://datatracker.ietf.org/doc/html/draft-ietf-add-svcb-dns-02#section-5.1 +[repr]: https://reproducible-builds.org/docs/source-date-epoch/ +[doq-draft-10]: https://datatracker.ietf.org/doc/html/draft-ietf-dprive-dnsoquic-10#section-10.2 + + + +## [v0.107.6] - 2022-04-13 See also the [v0.107.6 GitHub milestone][ms-v0.107.6]. -[ms-v0.107.6]: https://github.com/AdguardTeam/AdGuardHome/milestone/42?closed=1 ---> +### Security + +- `User-Agent` HTTP header removed from outgoing DNS-over-HTTPS requests. +- Go version was updated to prevent the possibility of exploiting the + [CVE-2022-24675], [CVE-2022-27536], and [CVE-2022-28327] vulnerabilities. + +### Added + +- Support for SVCB/HTTPS parameter `dohpath` in filtering rules with + the `dnsrewrite` modifier according to the [RFC draft][dns-draft-02] + ([#4463]). + +### Changed + +- Filtering rules with the `dnsrewrite` modifier that create SVCB or HTTPS + responses should use `ech` instead of `echconfig` to conform with the [latest + drafts][svcb-draft-08]. + +### Deprecated + +- SVCB/HTTPS parameter name `echconfig` in filtering rules with the `dnsrewrite` + modifier. Use `ech` instead. v0.109.0 will remove support for the outdated + name `echconfig`. +- Obsolete `--no-mem-optimization` option ([#4437]). v0.109.0 will remove the + flag completely. + +### Fixed + +- I/O timeout errors when checking for the presence of another DHCP server. +- Network interfaces being incorrectly labeled as down during installation. +- Rules for blocking the QQ service ([#3717]). + +### Removed + +- Go 1.16 support, since that branch of the Go compiler has reached end of life + and doesn't receive security updates anymore. + +[#3717]: https://github.com/AdguardTeam/AdGuardHome/issues/3717 +[#4437]: https://github.com/AdguardTeam/AdGuardHome/issues/4437 +[#4463]: https://github.com/AdguardTeam/AdGuardHome/issues/4463 + +[CVE-2022-24675]: https://www.cvedetails.com/cve/CVE-2022-24675 +[CVE-2022-27536]: https://www.cvedetails.com/cve/CVE-2022-27536 +[CVE-2022-28327]: https://www.cvedetails.com/cve/CVE-2022-28327 +[dns-draft-02]: https://datatracker.ietf.org/doc/html/draft-ietf-add-svcb-dns-02#section-5.1 +[ms-v0.107.6]: https://github.com/AdguardTeam/AdGuardHome/milestone/42?closed=1 +[svcb-draft-08]: https://www.ietf.org/archive/id/draft-ietf-dnsop-svcb-https-08.html @@ -159,6 +189,11 @@ were resolved. See also the [v0.107.4 GitHub milestone][ms-v0.107.4]. +### Security + +- Go version was updated to prevent the possibility of exploiting the + [CVE-2022-23806], [CVE-2022-23772], and [CVE-2022-23773] vulnerabilities. + ### Fixed - Optimistic cache now responds with expired items even if those can't be @@ -166,11 +201,6 @@ See also the [v0.107.4 GitHub milestone][ms-v0.107.4]. - Unnecessarily complex hosts-related logic leading to infinite recursion in some cases ([#4216]). -### Security - -- Go version was updated to prevent the possibility of exploiting the - [CVE-2022-23806], [CVE-2022-23772], and [CVE-2022-23773] vulnerabilities. - [#4216]: https://github.com/AdguardTeam/AdGuardHome/issues/4216 [#4254]: https://github.com/AdguardTeam/AdGuardHome/issues/4254 @@ -276,7 +306,7 @@ See also the [v0.107.0 GitHub milestone][ms-v0.107.0]. ([#2141]). - The ability to completely purge DHCP leases ([#1691]). - Settable timeouts for querying the upstream servers ([#2280]). -- Configuration file parameters to change group and user ID on startup on Unix +- Configuration file properties to change group and user ID on startup on Unix ([#2763]). - Experimental OpenBSD support for AMD64 and 64-bit ARM CPUs ([#2439], [#3225], [#3226]). @@ -325,8 +355,8 @@ See also the [v0.107.0 GitHub milestone][ms-v0.107.0]. original encoded version shown in request details ([#3013]). - When /etc/hosts-type rules have several IPs for one host, all IPs are now returned instead of only the first one ([#1381]). -- Property `rlimit_nofile` is now in the `os` object of the configuration file, - together with the new `group` and `user` properties ([#2763]). +- Property `rlimit_nofile` is now in the `os` object of the configuration + file, together with the new `group` and `user` properties ([#2763]). - Permissions on filter files are now `0o644` instead of `0o600` ([#3198]). #### Configuration Changes @@ -669,6 +699,10 @@ See also the [v0.106.0 GitHub milestone][ms-v0.106.0]. ## [v0.105.2] - 2021-03-10 +### Security + +- Session token doesn't contain user's information anymore ([#2470]). + See also the [v0.105.2 GitHub milestone][ms-v0.105.2]. ### Fixed @@ -682,10 +716,6 @@ See also the [v0.105.2 GitHub milestone][ms-v0.105.2]. - Incomplete DNS upstreams validation ([#2674]). - Wrong parsing of DHCP options of the `ip` type ([#2688]). -### Security - -- Session token doesn't contain user's information anymore ([#2470]). - [#2470]: https://github.com/AdguardTeam/AdGuardHome/issues/2470 [#2582]: https://github.com/AdguardTeam/AdGuardHome/issues/2582 [#2600]: https://github.com/AdguardTeam/AdGuardHome/issues/2600 @@ -897,13 +927,13 @@ See also the [v0.104.2 GitHub milestone][ms-v0.104.2]. - -[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.5...HEAD +[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.6...HEAD +[v0.107.6]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.5...v0.107.6 [v0.107.5]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.4...v0.107.5 [v0.107.4]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.3...v0.107.4 [v0.107.3]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.2...v0.107.3 diff --git a/bamboo-specs/release.yaml b/bamboo-specs/release.yaml index 62abf5ce..d0513f0f 100644 --- a/bamboo-specs/release.yaml +++ b/bamboo-specs/release.yaml @@ -7,7 +7,7 @@ # Make sure to sync any changes with the branch overrides below. 'variables': 'channel': 'edge' - 'dockerGo': 'adguard/golang-ubuntu:4.2' + 'dockerGo': 'adguard/golang-ubuntu:4.3' 'stages': - 'Make release': @@ -285,7 +285,7 @@ # need to build a few of these. 'variables': 'channel': 'beta' - 'dockerGo': 'adguard/golang-ubuntu:4.2' + 'dockerGo': 'adguard/golang-ubuntu:4.3' # release-vX.Y.Z branches are the branches from which the actual final release # is built. - '^release-v[0-9]+\.[0-9]+\.[0-9]+': @@ -300,4 +300,4 @@ # are the ones that actually get released. 'variables': 'channel': 'release' - 'dockerGo': 'adguard/golang-ubuntu:4.2' + 'dockerGo': 'adguard/golang-ubuntu:4.3' diff --git a/bamboo-specs/test.yaml b/bamboo-specs/test.yaml index fa410195..e973b77c 100644 --- a/bamboo-specs/test.yaml +++ b/bamboo-specs/test.yaml @@ -5,7 +5,7 @@ 'key': 'AHBRTSPECS' 'name': 'AdGuard Home - Build and run tests' 'variables': - 'dockerGo': 'adguard/golang-ubuntu:4.2' + 'dockerGo': 'adguard/golang-ubuntu:4.3' 'stages': - 'Tests': diff --git a/go.mod b/go.mod index 110f2bbb..30d8b377 100644 --- a/go.mod +++ b/go.mod @@ -3,66 +3,67 @@ module github.com/AdguardTeam/AdGuardHome go 1.17 require ( - github.com/AdguardTeam/dnsproxy v0.41.4 + github.com/AdguardTeam/dnsproxy v0.42.1 github.com/AdguardTeam/golibs v0.10.8 - github.com/AdguardTeam/urlfilter v0.15.2 + github.com/AdguardTeam/urlfilter v0.16.0 github.com/NYTimes/gziphandler v1.1.1 github.com/ameshkov/dnscrypt/v2 v2.2.3 github.com/digineo/go-ipset/v2 v2.2.1 github.com/fsnotify/fsnotify v1.5.1 github.com/go-ping/ping v0.0.0-20211130115550-779d1e919534 - github.com/google/go-cmp v0.5.6 + github.com/google/go-cmp v0.5.7 github.com/google/gopacket v1.1.19 github.com/google/renameio v1.0.1 - github.com/insomniacslk/dhcp v0.0.0-20211214070828-5297eed8f489 - github.com/kardianos/service v1.2.0 - github.com/lucas-clemente/quic-go v0.25.0 - github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 - github.com/mdlayher/netlink v1.5.0 + github.com/insomniacslk/dhcp v0.0.0-20220405050111-12fbdcb11b41 + github.com/kardianos/service v1.2.1 + github.com/lucas-clemente/quic-go v0.26.0 + github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118 + github.com/mdlayher/netlink v1.6.0 + // TODO(a.garipov): This package is deprecated; find a new one or use + // our own code for that. github.com/mdlayher/raw v0.0.0-20211126142749-4eae47f3d54b github.com/miekg/dns v1.1.48 github.com/satori/go.uuid v1.2.0 github.com/stretchr/testify v1.7.0 github.com/ti-mo/netfilter v0.4.0 go.etcd.io/bbolt v1.3.6 - golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 - golang.org/x/net v0.0.0-20220403103023-749bd193bc2b - golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12 + golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 + golang.org/x/net v0.0.0-20220412020605-290c469a71a5 + golang.org/x/sys v0.0.0-20220412211240-33da011f77ad gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/yaml.v2 v2.4.0 howett.net/plist v1.0.0 ) require ( - github.com/BurntSushi/toml v0.4.1 // indirect + github.com/BurntSushi/toml v1.1.0 // indirect github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 // indirect github.com/ameshkov/dnsstamps v1.0.3 // indirect - github.com/beefsack/go-rate v0.0.0-20200827232406-6cde80facd47 // indirect + github.com/beefsack/go-rate v0.0.0-20220214233405-116f4ca011a0 // indirect github.com/cheekybits/genny v1.0.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect github.com/google/uuid v1.3.0 // indirect - github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 // indirect - github.com/marten-seemann/qtls-go1-16 v0.1.4 // indirect - github.com/marten-seemann/qtls-go1-17 v0.1.0 // indirect - github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1 // indirect - github.com/mdlayher/socket v0.1.1 // indirect + github.com/josharian/native v1.0.0 // indirect + github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect + github.com/marten-seemann/qtls-go1-17 v0.1.1 // indirect + github.com/marten-seemann/qtls-go1-18 v0.1.1 // indirect + github.com/mdlayher/socket v0.2.3 // indirect github.com/nxadm/tail v1.4.8 // indirect github.com/onsi/ginkgo v1.16.5 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/objx v0.1.1 // indirect - github.com/u-root/uio v0.0.0-20210528151154-e40b768296a7 // indirect + github.com/u-root/uio v0.0.0-20220204230159-dac05f7d2cb4 // indirect golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/text v0.3.7 // indirect - golang.org/x/tools v0.1.10 // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + golang.org/x/tools v0.1.11-0.20220316014157-77aa08bb151a // indirect + golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect - honnef.co/go/tools v0.2.2 // indirect ) // TODO(a.garipov): Return to the main repo once miekg/dns#1359 is merged. diff --git a/go.sum b/go.sum index e405e27c..e75df993 100644 --- a/go.sum +++ b/go.sum @@ -7,20 +7,19 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= -github.com/AdguardTeam/dnsproxy v0.41.4 h1:zA8BJmWBkSL5kp4b8CblQRgIrLGzJ4IUGQ7tA1255Cw= -github.com/AdguardTeam/dnsproxy v0.41.4/go.mod h1:GCdEbTw683vBqksJIccPSYzBg2yIFbRiDnXltyIinug= +github.com/AdguardTeam/dnsproxy v0.42.1 h1:RZAtW75cvMX1d9Mibg0CA343V7VWV5PLrXsLhBZfdYc= +github.com/AdguardTeam/dnsproxy v0.42.1/go.mod h1:thHuk3599mgmucsv5J9HR9lBVQHnf4YleE08EbxNrN0= github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4= github.com/AdguardTeam/golibs v0.4.2/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4= github.com/AdguardTeam/golibs v0.10.4/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw= -github.com/AdguardTeam/golibs v0.10.6/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw= github.com/AdguardTeam/golibs v0.10.8 h1:diU9gP9qG1qeLbAkzIwfUerpHSqzR6zaBgzvRMR/m6Q= github.com/AdguardTeam/golibs v0.10.8/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw= github.com/AdguardTeam/gomitmproxy v0.2.0/go.mod h1:Qdv0Mktnzer5zpdpi5rAwixNJzW2FN91LjKJCkVbYGU= -github.com/AdguardTeam/urlfilter v0.15.2 h1:LZGgrm4l4Ys9eAqB+UUmZfiC6vHlDlYFhx0WXqo6LtQ= -github.com/AdguardTeam/urlfilter v0.15.2/go.mod h1:46YZDOV1+qtdRDuhZKVPSSp7JWWes0KayqHrKAFBdEI= +github.com/AdguardTeam/urlfilter v0.16.0 h1:IO29m+ZyQuuOnPLTzHuXj35V1DZOp1Dcryl576P2syg= +github.com/AdguardTeam/urlfilter v0.16.0/go.mod h1:46YZDOV1+qtdRDuhZKVPSSp7JWWes0KayqHrKAFBdEI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw= -github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= +github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= @@ -37,15 +36,14 @@ github.com/ameshkov/dnsstamps v1.0.1/go.mod h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaE github.com/ameshkov/dnsstamps v1.0.3 h1:Srzik+J9mivH1alRACTbys2xOxs0lRH9qnTA7Y1OYVo= github.com/ameshkov/dnsstamps v1.0.3/go.mod h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaEZZ4gKyIH5A= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= -github.com/beefsack/go-rate v0.0.0-20200827232406-6cde80facd47 h1:M57m0xQqZIhx7CEJgeLSvRFKEK1RjzRuIXiA3HfYU7g= github.com/beefsack/go-rate v0.0.0-20200827232406-6cde80facd47/go.mod h1:6YNgTHLutezwnBvyneBbwvB8C82y3dcoOj5EQJIdGXA= +github.com/beefsack/go-rate v0.0.0-20220214233405-116f4ca011a0 h1:0b2vaepXIfMsG++IsjHiI2p4bxALD1Y2nQKGMR5zDQM= +github.com/beefsack/go-rate v0.0.0-20220214233405-116f4ca011a0/go.mod h1:6YNgTHLutezwnBvyneBbwvB8C82y3dcoOj5EQJIdGXA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= -github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= -github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -58,7 +56,6 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= -github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= @@ -97,10 +94,10 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= @@ -120,87 +117,68 @@ github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpg github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis= -github.com/insomniacslk/dhcp v0.0.0-20211214070828-5297eed8f489 h1:jhdHqd7DxBrzfuFSoPxjD6nUVaV/1RIn9aHA0WCf/as= -github.com/insomniacslk/dhcp v0.0.0-20211214070828-5297eed8f489/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E= +github.com/insomniacslk/dhcp v0.0.0-20220405050111-12fbdcb11b41 h1:Yg3n3AI7GoHnWt7dyjsLPU+TEuZfPAg0OdiA3MJUV6I= +github.com/insomniacslk/dhcp v0.0.0-20220405050111-12fbdcb11b41/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= -github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 h1:uhL5Gw7BINiiPAo24A2sxkcDI0Jt/sqp1v5xQCniEFA= -github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +github.com/josharian/native v1.0.0 h1:Ts/E8zCSEsG17dUqv7joXJFybuMLjQfWE04tsBODTxk= +github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok= github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg= -github.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw= -github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs= -github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA= -github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U= -github.com/jsimonetti/rtnetlink v0.0.0-20210525051524-4cc836578190/go.mod h1:NmKSdU4VGSiv1bMsdqNALI4RSvvjtz65tTMCnD05qLo= -github.com/jsimonetti/rtnetlink v0.0.0-20211022192332-93da33804786 h1:N527AHMa793TP5z5GNAn/VLPzlc0ewzWdeP/25gDfgQ= -github.com/jsimonetti/rtnetlink v0.0.0-20211022192332-93da33804786/go.mod h1:v4hqbTdfQngbVSZJVWUhGE/lbTFf9jb+ygmNUDQMuOs= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/kardianos/service v1.2.0 h1:bGuZ/epo3vrt8IPC7mnKQolqFeYJb7Cs8Rk4PSOBB/g= -github.com/kardianos/service v1.2.0/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM= +github.com/kardianos/service v1.2.1 h1:AYndMsehS+ywIS6RB9KOlcXzteWUzxgMgBymJD7+BYk= +github.com/kardianos/service v1.2.1/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lucas-clemente/quic-go v0.24.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0= -github.com/lucas-clemente/quic-go v0.25.0 h1:K+X9Gvd7JXsOHtU0N2icZ2Nw3rx82uBej3mP4CLgibc= github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T2U9ZlW1AaHOsMOg= +github.com/lucas-clemente/quic-go v0.26.0 h1:ALBQXr9UJ8A1LyzvceX4jd9QFsHvlI0RR6BkV16o00A= +github.com/lucas-clemente/quic-go v0.26.0/go.mod h1:AzgQoPda7N+3IqMMMkywBKggIFo2KT6pfnlrQ2QieeI= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc= github.com/marten-seemann/qtls-go1-15 v0.1.4/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= -github.com/marten-seemann/qtls-go1-16 v0.1.4 h1:xbHbOGGhrenVtII6Co8akhLEdrawwB2iHl5yhJRpnco= github.com/marten-seemann/qtls-go1-16 v0.1.4/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk= -github.com/marten-seemann/qtls-go1-17 v0.1.0 h1:P9ggrs5xtwiqXv/FHNwntmuLMNq3KaSIG93AtAZ48xk= +github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ= +github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk= github.com/marten-seemann/qtls-go1-17 v0.1.0/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8= -github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1 h1:EnzzN9fPUkUck/1CuY1FlzBaIYMoiBsdwTNmNGkwUUM= +github.com/marten-seemann/qtls-go1-17 v0.1.1 h1:DQjHPq+aOzUeh9/lixAGunn6rIOQyWChPSI4+hgW7jc= +github.com/marten-seemann/qtls-go1-17 v0.1.1/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s= github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1/go.mod h1:PUhIQk19LoFt2174H4+an8TYvWOGjb/hHwphBeaDHwI= +github.com/marten-seemann/qtls-go1-18 v0.1.0/go.mod h1:PUhIQk19LoFt2174H4+an8TYvWOGjb/hHwphBeaDHwI= +github.com/marten-seemann/qtls-go1-18 v0.1.1 h1:qp7p7XXUFL7fpBvSS1sWD+uSqPvzNQK43DH+/qEkj0Y= +github.com/marten-seemann/qtls-go1-18 v0.1.1/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 h1:lez6TS6aAau+8wXUP3G9I3TGlmPFEq2CTxBaRqY6AGE= github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y= -github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo= -github.com/mdlayher/ethtool v0.0.0-20211028163843-288d040e9d60 h1:tHdB+hQRHU10CfcK0furo6rSNgZ38JT8uPh70c/pFD8= -github.com/mdlayher/ethtool v0.0.0-20211028163843-288d040e9d60/go.mod h1:aYbhishWc4Ai3I2U4Gaa2n3kHWSwzme6EsG/46HRQbE= -github.com/mdlayher/genetlink v1.0.0 h1:OoHN1OdyEIkScEmRgxLEe2M9U8ClMytqA5niynLtfj0= -github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= +github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118 h1:2oDp6OOhLxQ9JBoUuysVz9UZ9uI6oLUbvAZu0x8o+vE= +github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118/go.mod h1:ZFUnHIVchZ9lJoWoEGUg8Q3M4U8aNNWA3CVSUTkW4og= github.com/mdlayher/netlink v0.0.0-20190313131330-258ea9dff42c/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o= github.com/mdlayher/netlink v1.1.2-0.20201013204415-ded538f7f4be/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o= -github.com/mdlayher/netlink v1.2.0/go.mod h1:kwVW1io0AZy9A1E2YYgaD4Cj+C+GPkU6klXCMzIJ9p8= -github.com/mdlayher/netlink v1.2.1/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU= -github.com/mdlayher/netlink v1.2.2-0.20210123213345-5cc92139ae3e/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU= -github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuriDdoPSWys= -github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8= -github.com/mdlayher/netlink v1.4.1/go.mod h1:e4/KuJ+s8UhfUpO9z00/fDZZmhSrs+oxyqAS9cNgn6Q= -github.com/mdlayher/netlink v1.5.0 h1:r4fa439+SsMarM0rMONU3iSshSV3ArVqJl6H/zjrhh4= -github.com/mdlayher/netlink v1.5.0/go.mod h1:1Kr8BBFxGyUyNmztC9WLOayqYVAd2wsgOZm18nqGuzQ= +github.com/mdlayher/netlink v1.6.0 h1:rOHX5yl7qnlpiVkFWoqccueppMtXzeziFjWAjLg6sz0= +github.com/mdlayher/netlink v1.6.0/go.mod h1:0o3PlBmGst1xve7wQ7j/hwpNaFaH4qCRyWCdcZk8/vA= +github.com/mdlayher/packet v1.0.0/go.mod h1:eE7/ctqDhoiRhQ44ko5JZU2zxB88g+JH/6jmnjzPjOU= github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/raw v0.0.0-20211126142749-4eae47f3d54b h1:MHcTarUMC4sFA7eiyR8IEJ6j2PgmgXR+B9X2IIMjh7A= github.com/mdlayher/raw v0.0.0-20211126142749-4eae47f3d54b/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= -github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00/go.mod h1:GAFlyu4/XV68LkQKYzKhIo/WW7j3Zi0YRAz/BOoanUc= -github.com/mdlayher/socket v0.0.0-20211007213009-516dcbdf0267/go.mod h1:nFZ1EtZYK8Gi/k6QNu7z7CgO20i/4ExeQswwWuPmG/g= -github.com/mdlayher/socket v0.1.0/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs= -github.com/mdlayher/socket v0.1.1 h1:q3uOGirUPfAV2MUoaC7BavjQ154J7+JOkTWyiV+intI= github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs= +github.com/mdlayher/socket v0.2.1/go.mod h1:QLlNPkFR88mRUNQIzRBMfXxwKal8H7u1h3bL1CV+f0E= +github.com/mdlayher/socket v0.2.3 h1:XZA2X2TjdOwNoNPVPclRCURoX/hokBY8nkTmRZFEheM= +github.com/mdlayher/socket v0.2.3/go.mod h1:bz12/FozYNH/VbvC3q7TRIK/Y6dH1kCKsXaUeXi/FmY= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= -github.com/miekg/dns v1.1.40/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= -github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= -github.com/miekg/dns v1.1.44/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= -github.com/miekg/dns v1.1.48 h1:Ucfr7IIVyMBz4lRE8qmGUuZ4Wt3/ZGu9hmcMT3Uu4tQ= -github.com/miekg/dns v1.1.48/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= @@ -283,13 +261,12 @@ github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ= github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8= github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA= -github.com/u-root/uio v0.0.0-20210528151154-e40b768296a7 h1:XMAtQHwKjWHIRwg+8Nj/rzUomQY1q6cM3ncA0wP8GU4= -github.com/u-root/uio v0.0.0-20210528151154-e40b768296a7/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA= +github.com/u-root/uio v0.0.0-20220204230159-dac05f7d2cb4 h1:hl6sK6aFgTLISijk6xIzeqnPzQcsLqqvL6vEfTPinME= +github.com/u-root/uio v0.0.0-20220204230159-dac05f7d2cb4/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= @@ -304,8 +281,9 @@ golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M= -golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -314,7 +292,6 @@ golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPI golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -328,10 +305,10 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= @@ -341,25 +318,19 @@ golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210929193557-e81a3d93ecf6/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220403103023-749bd193bc2b h1:vI32FkLJNAWtGD4BwkThwEy6XS7ZLLMHkSkYfF8M0W0= -golang.org/x/net v0.0.0-20220403103023-749bd193bc2b/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5 h1:bRb386wvrE+oBNdF1d/Xh9mQrfQ4ecYhW5qJ5GvTGT4= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -387,7 +358,6 @@ golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -402,17 +372,8 @@ golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201017003518-b09fb700fbb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -421,17 +382,16 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210909193231-528a39cd75f3/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12 h1:QyVthZKMsyaQwBTJE04jdNN0Pp5Fn9Qga0mrgxyERQM= -golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -451,21 +411,19 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/tools v0.1.11-0.20220316014157-77aa08bb151a h1:ofrrl6c6NG5/IOSx/R1cyiQxxjqlur0h/TvbUhkH0II= +golang.org/x/tools v0.1.11-0.20220316014157-77aa08bb151a/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= @@ -516,9 +474,6 @@ grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJd honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.2.1/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= -honnef.co/go/tools v0.2.2 h1:MNh1AVMyVX23VUHE2O27jm6lNj3vjO5DexS4A1xvnzk= -honnef.co/go/tools v0.2.2/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= diff --git a/internal/aghnet/hostscontainer.go b/internal/aghnet/hostscontainer.go index 290dc1c0..65c9d3c4 100644 --- a/internal/aghnet/hostscontainer.go +++ b/internal/aghnet/hostscontainer.go @@ -51,7 +51,7 @@ type requestMatcher struct { // // It's safe for concurrent use. func (rm *requestMatcher) MatchRequest( - req urlfilter.DNSRequest, + req *urlfilter.DNSRequest, ) (res *urlfilter.DNSResult, ok bool) { switch req.DNSType { case dns.TypeA, dns.TypeAAAA, dns.TypePTR: diff --git a/internal/aghnet/hostscontainer_test.go b/internal/aghnet/hostscontainer_test.go index 807722a8..42202f43 100644 --- a/internal/aghnet/hostscontainer_test.go +++ b/internal/aghnet/hostscontainer_test.go @@ -193,7 +193,7 @@ func TestHostsContainer_refresh(t *testing.T) { // Require the changes are written. require.Eventually(t, func() bool { - res, ok := hc.MatchRequest(urlfilter.DNSRequest{ + res, ok := hc.MatchRequest(&urlfilter.DNSRequest{ Hostname: "hostname", DNSType: dns.TypeA, }) @@ -207,7 +207,7 @@ func TestHostsContainer_refresh(t *testing.T) { // Require the changes are written. require.Eventually(t, func() bool { - res, ok := hc.MatchRequest(urlfilter.DNSRequest{ + res, ok := hc.MatchRequest(&urlfilter.DNSRequest{ Hostname: "hostname", DNSType: dns.TypeA, }) @@ -365,7 +365,7 @@ func TestHostsContainer(t *testing.T) { testCases := []struct { want []*rules.DNSRewrite name string - req urlfilter.DNSRequest + req *urlfilter.DNSRequest }{{ want: []*rules.DNSRewrite{{ RCode: dns.RcodeSuccess, @@ -377,7 +377,7 @@ func TestHostsContainer(t *testing.T) { RRType: dns.TypeAAAA, }}, name: "simple", - req: urlfilter.DNSRequest{ + req: &urlfilter.DNSRequest{ Hostname: "simplehost", DNSType: dns.TypeA, }, @@ -392,7 +392,7 @@ func TestHostsContainer(t *testing.T) { RRType: dns.TypeAAAA, }}, name: "hello_alias", - req: urlfilter.DNSRequest{ + req: &urlfilter.DNSRequest{ Hostname: "hello.world", DNSType: dns.TypeA, }, @@ -407,21 +407,21 @@ func TestHostsContainer(t *testing.T) { RRType: dns.TypeAAAA, }}, name: "other_line_alias", - req: urlfilter.DNSRequest{ + req: &urlfilter.DNSRequest{ Hostname: "hello.world.again", DNSType: dns.TypeA, }, }, { want: []*rules.DNSRewrite{}, name: "hello_subdomain", - req: urlfilter.DNSRequest{ + req: &urlfilter.DNSRequest{ Hostname: "say.hello", DNSType: dns.TypeA, }, }, { want: []*rules.DNSRewrite{}, name: "hello_alias_subdomain", - req: urlfilter.DNSRequest{ + req: &urlfilter.DNSRequest{ Hostname: "say.hello.world", DNSType: dns.TypeA, }, @@ -436,7 +436,7 @@ func TestHostsContainer(t *testing.T) { Value: net.ParseIP("::2"), }}, name: "lots_of_aliases", - req: urlfilter.DNSRequest{ + req: &urlfilter.DNSRequest{ Hostname: "for.testing", DNSType: dns.TypeA, }, @@ -447,21 +447,21 @@ func TestHostsContainer(t *testing.T) { Value: "simplehost.", }}, name: "reverse", - req: urlfilter.DNSRequest{ + req: &urlfilter.DNSRequest{ Hostname: "1.0.0.1.in-addr.arpa", DNSType: dns.TypePTR, }, }, { want: []*rules.DNSRewrite{}, name: "non-existing", - req: urlfilter.DNSRequest{ + req: &urlfilter.DNSRequest{ Hostname: "nonexisting", DNSType: dns.TypeA, }, }, { want: nil, name: "bad_type", - req: urlfilter.DNSRequest{ + req: &urlfilter.DNSRequest{ Hostname: "1.0.0.1.in-addr.arpa", DNSType: dns.TypeSRV, }, @@ -476,7 +476,7 @@ func TestHostsContainer(t *testing.T) { Value: net.ParseIP("::42"), }}, name: "issue_4216_4_6", - req: urlfilter.DNSRequest{ + req: &urlfilter.DNSRequest{ Hostname: "domain", DNSType: dns.TypeA, }, @@ -491,7 +491,7 @@ func TestHostsContainer(t *testing.T) { Value: net.IPv4(1, 3, 5, 7), }}, name: "issue_4216_4", - req: urlfilter.DNSRequest{ + req: &urlfilter.DNSRequest{ Hostname: "domain4", DNSType: dns.TypeA, }, @@ -506,7 +506,7 @@ func TestHostsContainer(t *testing.T) { Value: net.ParseIP("::31"), }}, name: "issue_4216_6", - req: urlfilter.DNSRequest{ + req: &urlfilter.DNSRequest{ Hostname: "domain6", DNSType: dns.TypeAAAA, }, diff --git a/internal/filtering/filtering.go b/internal/filtering/filtering.go index 9bedeef7..8af49b0c 100644 --- a/internal/filtering/filtering.go +++ b/internal/filtering/filtering.go @@ -471,7 +471,7 @@ func (d *DNSFilter) matchSysHosts( return res, nil } - dnsres, _ := d.EtcHosts.MatchRequest(urlfilter.DNSRequest{ + dnsres, _ := d.EtcHosts.MatchRequest(&urlfilter.DNSRequest{ Hostname: host, SortedClientTags: setts.ClientTags, // TODO(e.burkov): Wait for urlfilter update to pass net.IP. @@ -802,7 +802,7 @@ func (d *DNSFilter) matchHost( return Result{}, nil } - ureq := urlfilter.DNSRequest{ + ureq := &urlfilter.DNSRequest{ Hostname: host, SortedClientTags: setts.ClientTags, // TODO(e.burkov): Wait for urlfilter update to pass net.IP. diff --git a/internal/tools/go.mod b/internal/tools/go.mod index 98ef459a..2ad6ce16 100644 --- a/internal/tools/go.mod +++ b/internal/tools/go.mod @@ -3,30 +3,32 @@ module github.com/AdguardTeam/AdGuardHome/internal/tools go 1.17 require ( - github.com/fzipp/gocyclo v0.4.0 + github.com/fzipp/gocyclo v0.5.1 github.com/golangci/misspell v0.3.5 github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8 github.com/kisielk/errcheck v1.6.0 github.com/kyoh86/looppointer v0.1.7 - github.com/securego/gosec/v2 v2.9.5 + github.com/securego/gosec/v2 v2.11.0 golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 - golang.org/x/tools v0.1.8 - honnef.co/go/tools v0.2.2 - mvdan.cc/gofumpt v0.2.1 - mvdan.cc/unparam v0.0.0-20211214103731-d0ef000c54e5 + golang.org/x/tools v0.1.11-0.20220316014157-77aa08bb151a + honnef.co/go/tools v0.3.0 + mvdan.cc/gofumpt v0.3.1 + mvdan.cc/unparam v0.0.0-20220316160445-06cc5682983b ) require ( - github.com/BurntSushi/toml v0.4.1 // indirect + github.com/BurntSushi/toml v1.1.0 // indirect github.com/client9/misspell v0.3.4 // indirect - github.com/google/go-cmp v0.5.6 // indirect + github.com/google/go-cmp v0.5.7 // indirect github.com/google/uuid v1.3.0 // indirect github.com/gookit/color v1.5.0 // indirect github.com/kyoh86/nolint v0.0.1 // indirect github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect - golang.org/x/mod v0.5.1 // indirect - golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + golang.org/x/exp/typeparams v0.0.0-20220407100705-7b9b53b0aca4 // indirect + golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect + golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect + golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/internal/tools/go.sum b/internal/tools/go.sum index e1b2e226..7dbf5491 100644 --- a/internal/tools/go.sum +++ b/internal/tools/go.sum @@ -34,8 +34,9 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX contrib.go.opencensus.io/exporter/stackdriver v0.13.4/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw= github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= +github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= @@ -92,14 +93,13 @@ github.com/envoyproxy/protoc-gen-validate v0.0.14/go.mod h1:iSmxcyjqTsJpI2R4NaDN github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= -github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= +github.com/frankban/quicktest v1.14.2 h1:SPb1KFFmM+ybpEjPUhCCkZOM5xlovT5UbrMvWnXyBns= +github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fullstorydev/grpcurl v1.6.0/go.mod h1:ZQ+ayqbKMJNhzLmbpCiurTVlaK2M/3nqZCxaQ2Ze/sM= -github.com/fzipp/gocyclo v0.4.0 h1:IykTnjwh2YLyYkGa0y92iTTEQcnyAz0r9zOo15EbJ7k= -github.com/fzipp/gocyclo v0.4.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= +github.com/fzipp/gocyclo v0.5.1 h1:L66amyuYogbxl0j2U+vGqJXusPF2IkduvXLnYD5TFgw= +github.com/fzipp/gocyclo v0.5.1/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -157,8 +157,8 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -168,6 +168,7 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200507031123-427632fa3b1c/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/trillian v1.3.11/go.mod h1:0tPraVHrSDkA3BO6vKX67zgLXs6SsOAbHEivX+9mPgw= github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -200,6 +201,7 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= @@ -276,7 +278,6 @@ github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 h1:4kuARK6Y6Fx github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8= github.com/nishanths/predeclared v0.0.0-20190419143655-18a43bb90ffc/go.mod h1:62PewwiQTlm/7Rj+cxVYqZvDIUc+JjZq6GHAC1fsObQ= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= @@ -284,13 +285,16 @@ github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2f github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.1.3 h1:e/3Cwtogj0HA+25nMP1jCMDIf8RtRYbGwGGuBIFztkc= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= +github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= @@ -325,8 +329,8 @@ github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4 github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/securego/gosec/v2 v2.9.5 h1:Wiyf78NNedu8RClwW0vPRgPKCY7LJX4WujjJcPV2Nwg= -github.com/securego/gosec/v2 v2.9.5/go.mod h1:lG831xFHrZofatyJb9Y5yMUE8Ws6z5U5CMHe9vYn1kM= +github.com/securego/gosec/v2 v2.11.0 h1:+PDkpzR41OI2jrw1q6AdXZCbsNGNGT7pQjal0H0cArI= +github.com/securego/gosec/v2 v2.11.0/go.mod h1:SX8bptShuG8reGC0XS09+a4H2BoWSJi+fscA+Pulbpo= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -401,7 +405,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220313003712-b769efc7c000/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -412,7 +417,11 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5 h1:FR+oGxGfbQu1d+jglI3rCkjAjUnhRSZcUxr+DqlDLNo= golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= +golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/exp/typeparams v0.0.0-20220407100705-7b9b53b0aca4 h1:P5yukcpQfG1ZDKR0pGdaZCVwaNPntMxLFKYg81li58M= +golang.org/x/exp/typeparams v0.0.0-20220407100705-7b9b53b0aca4/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -436,8 +445,9 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -473,6 +483,7 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -493,6 +504,7 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -539,15 +551,16 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -613,15 +626,17 @@ golang.org/x/tools v0.0.0-20200706234117-b22de6825cf7/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200710042808-f1c4188a97a1/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20201007032633-0806396f153e/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= -golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/tools v0.1.11-0.20220316014157-77aa08bb151a h1:ofrrl6c6NG5/IOSx/R1cyiQxxjqlur0h/TvbUhkH0II= +golang.org/x/tools v0.1.11-0.20220316014157-77aa08bb151a/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -714,7 +729,6 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= @@ -737,12 +751,12 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.2.2 h1:MNh1AVMyVX23VUHE2O27jm6lNj3vjO5DexS4A1xvnzk= -honnef.co/go/tools v0.2.2/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= -mvdan.cc/gofumpt v0.2.1 h1:7jakRGkQcLAJdT+C8Bwc9d0BANkVPSkHZkzNv07pJAs= -mvdan.cc/gofumpt v0.2.1/go.mod h1:a/rvZPhsNaedOJBzqRD9omnwVwHZsBdJirXHa9Gh9Ig= -mvdan.cc/unparam v0.0.0-20211214103731-d0ef000c54e5 h1:Jh3LAeMt1eGpxomyu3jVkmVZWW2MxZ1qIIV2TZ/nRio= -mvdan.cc/unparam v0.0.0-20211214103731-d0ef000c54e5/go.mod h1:b8RRCBm0eeiWR8cfN88xeq2G5SG3VKGO+5UPWi5FSOY= +honnef.co/go/tools v0.3.0 h1:2LdYUZ7CIxnYgskbUZfY7FPggmqnh6shBqfWa8Tn3XU= +honnef.co/go/tools v0.3.0/go.mod h1:vlRD9XErLMGT+mDuofSr0mMMquscM/1nQqtRSsh6m70= +mvdan.cc/gofumpt v0.3.1 h1:avhhrOmv0IuvQVK7fvwV91oFSGAk5/6Po8GXTzICeu8= +mvdan.cc/gofumpt v0.3.1/go.mod h1:w3ymliuxvzVx8DAutBnVyDqYb1Niy/yCJt/lk821YCE= +mvdan.cc/unparam v0.0.0-20220316160445-06cc5682983b h1:C8Pi6noat8BcrL9WnSRYeQ63fpkJk3hKVHtF5731kIw= +mvdan.cc/unparam v0.0.0-20220316160445-06cc5682983b/go.mod h1:WqFWCt8MGPoFSYGsQSiIORRlYVhkJsIk+n2MY6rhNbA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= From 57171f0a61574bf9cc4819e2f8444638c4b5693c Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Wed, 13 Apr 2022 20:30:36 +0300 Subject: [PATCH 026/110] Pull request: client: upd i18n Merge in DNS/adguard-home from upd-i18n to master Squashed commit of the following: commit 181c13667eb79e5f0c8ec6502e8bd79f7403bf8d Author: Ainar Garipov Date: Wed Apr 13 20:24:32 2022 +0300 client: upd i18n --- client/src/__locales/bg.json | 38 ++++++++++++++- client/src/__locales/de.json | 4 +- client/src/__locales/fa.json | 84 +++++++++++++++++++++++++++++++-- client/src/__locales/nl.json | 20 ++++---- client/src/__locales/no.json | 45 ++++++++++++++++-- client/src/__locales/ru.json | 4 +- client/src/__locales/sv.json | 10 ++-- client/src/__locales/tr.json | 6 +-- client/src/__locales/zh-tw.json | 4 +- 9 files changed, 183 insertions(+), 32 deletions(-) diff --git a/client/src/__locales/bg.json b/client/src/__locales/bg.json index 1b6a1db5..a64b7620 100644 --- a/client/src/__locales/bg.json +++ b/client/src/__locales/bg.json @@ -1,16 +1,22 @@ { + "client_settings": "Kлиентски настройки", + "example_upstream_comment": "Можете да поставите коментар", + "load_balancing": "Балансиране на натоварването", "check_dhcp_servers": "Проверка за активен DHCP сървър", + "save_config": "Запиши настройките", "enabled_dhcp": "DHCP е разрешен", "disabled_dhcp": "DHCP е забранен", "dhcp_title": "DHCP сървър (тестови!)", "dhcp_description": "Ако рутера ви не раздава DHCP адреси, може да използвате вградения в AdGuard DHCP сървър.", "dhcp_enable": "Рзреши DHCP сървъра", "dhcp_disable": "Забрани DHCP сървъра", + "dhcp_not_found": "Вашата мрежа няма активен DHCP сървър. Безопасно е ползването на вградения DHCP сървър.", "dhcp_found": "Вашата мрежа вече има активен DHCP сървър. Не е безопасно ползването на втори!", "dhcp_leases": "DHCP раздадени адреси", "dhcp_leases_not_found": "Няма намерени активни DHCP адреси", + "dhcp_config_saved": "Запиши конфигурацията на DHCP сървъра", "form_error_required": "Задължително поле", - "form_error_ip_format": "Невалиден IP адрес", + "form_error_ip_format": "Невалиден IPv4 адрес", "form_error_positive": "Проверете дали е положително число", "dhcp_form_gateway_input": "IP шлюз", "dhcp_form_subnet_input": "Мрежова маска", @@ -24,15 +30,21 @@ "dhcp_ip_addresses": "IP адреси", "dhcp_table_hostname": "Име на устройство", "dhcp_table_expires": "История", + "dhcp_warning": "Ако искате да използвате вградения DHCP сървър, трябва да няма друг активен DHCP в мрежата Ви!", + "country": "Държава", "city": "Град", + "delete_confirm": "Наистина ли искате да изтриете \"{{key}}\"?", + "error_details": "Подробности за грешка", "response_details": "Подробности за отговора", "request_details": "Поискайте подробности", + "details": "Детайли", "back": "Назад", "dashboard": "Табло", "settings": "Настройки", "filters": "Филтри", "filter": "Филтър", "query_log": "История на заявките", + "compact": "Compact", "faq": "ЧЗВ", "version": "версия", "address": "Адрес", @@ -60,7 +72,12 @@ "top_clients": "Най-активни IP адреси", "no_clients_found": "Нямa намерени адреси", "general_statistics": "Обща статисика", + "number_of_dns_query_24_hours": "Сума на DNS заявки за последните 24 часа", + "number_of_dns_query_blocked_24_hours": "Сума на блокирани DNS заявки от филтрите за реклама и местни", + "number_of_dns_query_blocked_24_hours_by_sec": "Сума на блокирани DNS заявки от AdGuard свързани със сигурността", + "number_of_dns_query_blocked_24_hours_adult": "Сума на блокирани сайтове за възрастни", "enforced_save_search": "Активирано Безопасно Търсене", + "number_of_dns_query_to_safe_search": "Сума на DNS заявки при който е приложено Безопасно Търсене", "average_processing_time": "Средно време за обработка", "average_processing_time_hint": "Средно време за обработка на DNS заявки в милисекунди", "block_domain_use_filters_and_hosts": "Блокирани домейни - общи и местни филтри", @@ -70,6 +87,7 @@ "use_adguard_parental": "Включи AdGuard Родителски Надзор", "use_adguard_parental_hint": "Модул XXX в AdGuard Home ще провери дали страницата има материали за възвъстни. Използва се същия API за анонимност като при модула за Сигурност.", "enforce_safe_search": "Включи Безопасно Търсене", + "enforce_save_search_hint": "AdGuard Home прилага Безопасно Търсене в следните търсачки и сайтове: Google, Youtube, Bing, и Yandex.", "no_servers_specified": "Няма избрани услуги", "general_settings": "Общи настройки", "custom_filtering_rules": "Местни правила за филтриране", @@ -106,10 +124,13 @@ "example_comment_hash": "# Това е също коментар", "example_regex_meaning": "блокирай достъп до домейни който съвпадат със следното", "example_upstream_regular": "класически DNS (UDP протокол)", + "example_upstream_udp": "обикновен DNS (върху UDP, име на хост);", "example_upstream_dot": "криптиран DNS-върху-TLS", "example_upstream_doh": "криптиран DNS-върху-HTTPS", "example_upstream_sdns": "може да ползвате DNS Подписване за DNSCrypt или DNS-върху-HTTPS сървъри", "example_upstream_tcp": "класически DNS (TCP протокол)", + "example_upstream_tcp_hostname": "обикновен DNS (върху TCP, име на хост);", + "updated_upstream_dns_toast": "Глобалните DNS сървъри са обновени", "dns_test_ok_toast": "Въведените DNS сървъри работят коректно", "dns_test_not_ok_toast": "Сървър \"{{key}}\": не работи, моля проверете дали е въведен коректно", "unblock": "Отблокирай", @@ -135,11 +156,13 @@ "rule_added_to_custom_filtering_toast": "Добавено до местни правила за филтриране: {{rule}}", "default": "По подразбиране", "custom_ip": "Персонализиран IP", + "dns_over_https": "DNS-пред-HTTPS", "dns_over_quic": "DNS-over-QUIC", "plain_dns": "Обикновен DNS", "source_label": "Източник", "found_in_known_domain_db": "Намерен в списъците с домейни.", "category_label": "Категория", + "rule_label": "Правило", "unknown_filter": "Непознат филтър {{filterId}}", "install_welcome_title": "Добре дошли в AdGuard Home!", "install_welcome_desc": "AdGuard Home e мрежово решение за блокиране на реклами и тракери на DNS ниво. Създадено е за да ви даде пълен контрол над мрежата и всичките ви устройства, без да е необходимо допълнително инсталиране на друг софтуер.", @@ -147,6 +170,7 @@ "install_settings_listen": "Активни интерфейси", "install_settings_port": "Порт", "install_settings_interface_link": "Вашата AdGuard Home страница за администрация ще е достъпна на този адрес:", + "form_error_port": "Моля въведете валиден порт", "install_settings_dns": "DNS сървър", "install_settings_dns_desc": "За да работи, ще трябва да настроите вашият рутер или устройства да ползват DNS сървър с адрес:", "install_settings_all_interfaces": "Всички интерфейси", @@ -165,6 +189,7 @@ "install_devices_router": "Рутер", "install_devices_router_desc": "Ако настроите вашият рутер няма нужда ръчно да настройвате всяко едно от устрйствата в мрежата.", "install_devices_address": "AdGuard Home DNS сървърът е на следния адрес", + "install_devices_router_list_1": "Отворете страницата за настройки на вашия рутер. Обикновено тя се намира на URL (тук http://192.168.0.1/ или тук http://192.168.1.1/). За достъп може да ви трябва парола. Ако сте забравили паролата може да я ресетнете като натиснета скрития ресет бутон - внимание това ще ресетне всички настройки на рутера до фабрични! Някой рутери могат да бъдате администрирани от софтуер или приложение, който би трябвало да е вече инсталиран на компютъра/телефона ви.", "install_devices_router_list_2": "Намерета DHCP/DNS настройки. В под раздел DHCP рзгледайте и намерете къде е полето за DNS настройка в което може да въведете персонализирани настройки за DNS сървъри.", "install_devices_router_list_3": "Въведете адресът на AdGuard Home сървъра.", "install_devices_windows_list_1": "Отворете Контролния Панел през Старт меню или чрез функция търсене на Windows.", @@ -192,8 +217,10 @@ "install_saved": "Успешно записано", "encryption_title": "Криптиране", "encryption_desc": "Подържа се сигурна връзка (HTTPS/TLS) включително за DNS и страницата за администрация", + "encryption_config_saved": "Конфигурацията е успешно записана", "encryption_server": "Име на сървъра", "encryption_server_enter": "Въведете име на домейна", + "encryption_server_desc": "За да използвате HTTPS, трябва името на сървъра да съвпада с това на SSL сертификата.", "encryption_redirect": "Автоматично пренасочване към HTTPS", "encryption_redirect_desc": "Служи за автоматично пренасочване от HTTP към HTTPS на страницата за Администрация в AdGuard Home.", "encryption_https": "HTTPS порт", @@ -219,7 +246,9 @@ "encryption_reset": "Сигурни ли сте че искате да изтриете настройките за криптиране?", "topline_expiring_certificate": "Вашият SSL сертификат изтича. Обнови <0>Настройки за криптиране.", "topline_expired_certificate": "Вашият SSL сертификат е изтекъл. Обнови <0>Настройки за криптиране.", + "form_error_port_range": "Въведете порт в диапазона 80-65535", "form_error_port_unsafe": "Не е безопасно да използвате този порт", + "form_error_equal": "Не трябва да съвпада", "form_error_password": "Паролата не съвпада", "reset_settings": "Изтрий всички настройки", "update_announcement": "Има нова AdGuard Home {{version}}! <0>Цъкни тук за повече информация.", @@ -230,7 +259,11 @@ "name": "Име", "clients_not_found": "Нямa намерени адреси", "check_updates_now": "Провери за актуализации", + "interval_6_hour": "6 часа", + "interval_24_hour": "24 часа", "domain": "Домейн", + "ecs": "ECS", + "statistics_clear": "Нулирай статистиката", "disabled": "Деактивиран", "username_label": "Потребител", "username_placeholder": "Въведете потребител", @@ -238,11 +271,14 @@ "password_placeholder": "Въведете парола", "network": "Мрежа", "descr": "Описание", + "try_again": "Опитай пак", + "disable_ipv6": "Изключете IPv6 протокола", "show_blocked_responses": "Блокирано", "show_whitelisted_responses": "В белия списък", "show_processed_responses": "Обработен", "allowed": "В белия списък", "safe_search": "Безопасно търсене", + "blocklist": "Черен списък", "filter_category_general": "General", "filter_category_security": "Сигурност", "port_53_faq_link": "Порт 53 често е зает от \"DNSStubListener\" или \"systemd-resolved\" услуги. Моля, прочетете <0>тази инструкция как да решите това.", diff --git a/client/src/__locales/de.json b/client/src/__locales/de.json index 6f8ff803..be5666a8 100644 --- a/client/src/__locales/de.json +++ b/client/src/__locales/de.json @@ -274,8 +274,8 @@ "blocking_ipv4": "IPv4-Sperren", "blocking_ipv6": "IPv6-Sperren", "dnscrypt": "DNSCrypt", - "dns_over_https": "DNS-over-HTTPS (DNS-Abfrage über HTTPS)", - "dns_over_tls": "DNS-over-TLS (DNS-Abfrage über TLS)", + "dns_over_https": "DNS-over-HTTPS", + "dns_over_tls": "DNS-over-TLS", "dns_over_quic": "DNS-over-QUIC", "client_id": "Client-ID", "client_id_placeholder": "Client-ID eingeben", diff --git a/client/src/__locales/fa.json b/client/src/__locales/fa.json index d465b2bf..20cc372d 100644 --- a/client/src/__locales/fa.json +++ b/client/src/__locales/fa.json @@ -1,26 +1,50 @@ { "client_settings": "تنظیمات کلاینت", + "example_upstream_reserved": "میتوانید جریان ارسالی DNS <0> را برای یک دامنه مشخص تعیین کنید ", + "upstream_parallel": "استفاده از جستار موازی برای سرعت دادن به تفکیک با جستار همزمان همه جریان های ارسالی", "parallel_requests": "درخواست های موازی", "bootstrap_dns": "خودراه انداز سرورهای DNS", "bootstrap_dns_desc": "خودراه انداز سرورهای DNS برای تفکیک آدرس آی پی تفکیک کننده های DoH/DoT که شما بعنوان جریان ارسالی تعیین کردید استفاده میشود.", + "local_ptr_title": "سرورهای خصوصی DNS", + "local_ptr_desc": "سرور یا سرور های DNS ای که AdGuard Home برای درخواست های منابع محلی ارائه شده مورد استفاده قرار خواهد داد. برای مثال، این سرور برای تعیین نام های سرویس دهنده برای سرویس گیرنده با آدرس های آی پی خصوصی مورد استفاده قرار خواهد گرفت. اگر تعیین نشود،AdGuard Home به طور خودکار از تعیین کننده ی DNS پیش فرض شما استفاده خواهد کرد.", + "local_ptr_default_resolver": "به طور پیش فرض، AdGuard Home از تعیین کننده های DNS معکوس زیر استفاده می کند: {{ip}}.", + "local_ptr_no_default_resolver": "AdGuard Home نتوانست برای این دستگاه تعیین کننده های DNS معکوس محرمانه مناسب را معین کند.", + "local_ptr_placeholder": "در هر خط یک آدرس سرور را وارد کنید", + "resolve_clients_title": "فعال سازی تعیین نام های سرویس دهنده ی سرویس گیرندگان", + "resolve_clients_desc": "در صورت فعال بودن،AdGuard Home به طور خودکار اقدام به تعیین نام های سرویس دهنده ی سرویس گیرندگان از آدرس های آی پی با ارسال یک درخواست PTR به یک تعیین کننده ی همتا خواهد کرد (سرور خصوصی DNS برای سرویس گیرندگان محلی،سرور مادر برای سرویس گیرندگان با آی پی عمومی).", + "use_private_ptr_resolvers_title": "از تعیین کننده های rDNS محرمانه استفاده کنید", + "use_private_ptr_resolvers_desc": "داده گیری های دی ان اس معکوس را برای آدرس های اینترنتی خدمات منظقه ای با استفاده از سرور های مادر اجرا کنید. چنانچه غیر فعال باشد،AdGuard Home با NXDOMAIN به همه چنین درخواست های PTR پاسخ می دهد به استثناء خدمات گیرنده های شناخته شده از طرف DHCP،/و غیره/هوست ها، و سایر.", "check_dhcp_servers": "بررسی برای سرورهای DHCP", + "save_config": "ذخیره پیکربندی", "enabled_dhcp": "سرور DHCP فعال شده است", "disabled_dhcp": "سرور DHCP غیرفعال شده است", "dhcp_title": "سرور DHCP", "dhcp_description": "اگر روتر شما تنظیمات DHCP ارائه نمی کند،میتوانید از سرور DHCP تو-کار خود AdGuard استفاده کنید.", "dhcp_enable": "فعالسازی سرور DHCP", "dhcp_disable": "غیرفعالسازی سرور DHCP", + "dhcp_not_found": "سرورهای فعال DHCP در شبکه یافت نشد.فعالسازی سرور DHCP تو-کار اَمن است.", "dhcp_found": "تعدادی سرور DHCP فعال در شبکه یافت شد.فعالسازی سرور DHCP توکار اَمن نیست.", "dhcp_leases": "اجاره DHCP", "dhcp_static_leases": "اجاره DHCP ایستا", "dhcp_leases_not_found": "اجاره DHCP یافت نشد", + "dhcp_config_saved": "پیکربندی سرور DHCP ذخیره شده است", "form_error_required": "فیلد مورد نیاز", "form_error_ip4_format": "فرمت نامعتبر IPv4", + "form_error_ip4_range_start_format": "قالب IPv4 شروع دامنه نامعتبر است", + "form_error_ip4_range_end_format": "قالب IPv4 پایان دامنه نامعتبر است", + "form_error_ip4_gateway_format": "قالب IPv4 درگاه نامعتبر است", "form_error_ip6_format": "فرمت نامعتبر IPv6", - "form_error_ip_format": "آدرس آی پی نامعتبر است", + "form_error_ip_format": "فرمت IPv4 نامعتبر است", "form_error_mac_format": "فرمت مَک نامعتبر است", "form_error_client_id_format": "فرمت شناسه کلاینت نامعتبر است", + "form_error_subnet": "زیرشبکه\"{{cidr}}\"آدرس آی پی {{ip}} را در بر ندارد", "form_error_positive": "باید بزرگتر از 0 باشد", + "out_of_range_error": "باید خارج از دامنه باشد\"{{start}}\"-\"{{end}}\"", + "lower_range_start_error": "باید کمتر از شروع دامنه باشد", + "greater_range_start_error": "باید بیشتر از شروع دامنه باشد", + "greater_range_end_error": "باید بیشتر از پایان دامنه باشد", + "subnet_error": "آدرس ها باید در یک زیرشبکه باشند", + "gateway_or_subnet_invalid": "پوشش زیرشبکه نامعتبر است", "dhcp_form_gateway_input": "آی پی دروازه", "dhcp_form_subnet_input": "ماسک زیر شبکه", "dhcp_form_range_title": "دامنه آدرس های آی پی", @@ -34,11 +58,19 @@ "ip": "IP", "dhcp_table_hostname": "نام میزبان", "dhcp_table_expires": "انقضاء", + "dhcp_warning": "اگر میخواهید DHCP سرور توکار را فعال کنید،مطمئن شوید DHCP سرور دیگری فعال نباشد.در غیر اینصورت،آن دسترسی به اینترنت را برای دستگاه های وصل شده قطع می کند!", + "dhcp_error": "ما نمیتوانیم تشخیص دهیم آیا یک سرور DHCP دیگر در شبکه موجود است یا نه.", + "dhcp_static_ip_error": "به منظور استفاده از سرور DHCP یک آدرس آی پی ثابت باید تنظیم شود.ما موفق به تشخیص اینکه آیا رابط این شبکه برای استفاده از آی پی ثابت تنظیم شده است یا نه موفق نشدیم.لطفا آدرس آی پی ثابت را دستی تنظیم کنید.", + "dhcp_dynamic_ip_found": "سیستم شما آدرس آی پی متغییر برای این رابط استفاده می کند <0>{{interfaceName}}. به منظور استفاده از سرور DHCP آدرس ثابت باید تعیین شود. آدرس آی پی فعلی شما هست <0>{{ipAddress}}. اگر شما دکمه DHCP را فشار دهید ما این آدرس آی پی را بعنوان ثابت تنظیم می کنیم.", "dhcp_lease_added": "اجاره ایستا \"{{key}}\" با موفقیت اضافه شد", "dhcp_lease_deleted": "اجاره ایستا \"{{key}}\" با موفقیت حذف شد", "dhcp_new_static_lease": "اجاره ایستا جدید", "dhcp_static_leases_not_found": "هیچ اجاره DHCP ایستا یافت نشد", "dhcp_add_static_lease": "افزودن اجاره ایستا", + "dhcp_reset_leases": "بازگردانی همه مجوزهای منابع", + "dhcp_reset_leases_confirm": "آیا می خواهید تمام مجوزهای منابع را بازگردانی کنید؟", + "dhcp_reset_leases_success": "مجوزهای منابع DHCP با موفقیت بازگردانی شد", + "dhcp_reset": "آیا میخواهید پیکربندی DHCP را ریست کنید؟", "country": "کشور", "city": "شهر", "delete_confirm": "آیا میخواهید \"{{key}}\" را حذف کنید؟", @@ -54,6 +86,7 @@ "filters": "فيلترها", "filter": "فیلتر", "query_log": "جستار وقایع", + "compact": "فشرده", "nothing_found": "هیچ چیز یافت نشد", "faq": "پرسش و پاسخ", "version": "نسخه", @@ -78,13 +111,22 @@ "for_last_24_hours": "برای 24 ساعت گذشته", "for_last_days": "برای {{count}} روز آخر", "for_last_days_plural": "برای {{count}} روز گذشته", + "stats_disabled": "آمار غیرفعال شده است. شما می توانید از قسمت <0>صفحه تنظیمات آن را روشن نمایید.", + "stats_disabled_short": "آمار غیرفعال شده است", "no_domains_found": "دامنه یافت نشد", "requests_count": "تعداد درخواست ها", "top_blocked_domains": "دامنه های بیشتر مسدود شده", "top_clients": "بالاترین کلاینت ها", "no_clients_found": "کلاینتی یافت نشد", "general_statistics": "آمار عمومی", + "number_of_dns_query_days": "تعداد جستار DNS پردازش شده در {{count}} روز آخر", + "number_of_dns_query_days_plural": "تعداد جستار DNS پردازش شده در {{count}} روز گذشته", + "number_of_dns_query_24_hours": "تعداد جستار DNS پردازش شده در 24 ساعت گذشته", + "number_of_dns_query_blocked_24_hours": "تعداد درخواست DNS مسدود شده با فیلترهای مسدودساز تبلیغ و لیست سیاه میزبان", + "number_of_dns_query_blocked_24_hours_by_sec": "تعداد درخواست DNS مسدود شده با مدل امنیت وب گردی AdGuard", + "number_of_dns_query_blocked_24_hours_adult": "تعداد وبسایت های غیر اخلاقی مسدود شده", "enforced_save_search": "جستجوی اَمن اجبار شده", + "number_of_dns_query_to_safe_search": "تعداد درخواست های DNS برای موتور جستجو که جستجوی اَمن اجبار شده", "average_processing_time": "میانگین زمان پردازش", "average_processing_time_hint": "زمان میانگین بر هزارم ثانیه در پردازش درخواست DNS", "block_domain_use_filters_and_hosts": "مسدودسازی دامنه ها توسط فیلترها و فایل های میزبان", @@ -94,6 +136,7 @@ "use_adguard_parental": "از سرویس وب نظارت والدین AdGuard استفاده کن", "use_adguard_parental_hint": "AdGuard Home بررسی می کند اگر دامنه حاوی موارد غیر اخلاقی است.آن از همان اِی پی آی دارای حریم خصوصی سرویس وب امنیت وب گردی استفاده می کند.", "enforce_safe_search": "اجبار جستجوی اَمن", + "enforce_save_search_hint": "AdGuard Home میتواند جستجوی اَمن را در موتور جستجوهای زیر اعمال کند:گوگل،یوتوب،بینگ و یاندکس", "no_servers_specified": "سروری تعیین نشده است", "general_settings": "تنظیمات عمومی", "dns_settings": "تنظیمات DNS", @@ -145,6 +188,7 @@ "form_error_url_or_path_format": "آدرس نامعتبر یا یک مسیر کامل لیست", "custom_filter_rules": "دستورات فیلترینگ دستی", "custom_filter_rules_hint": "یک دستور در خط وارد کنید.میتوانید از دستورات مسدودساز تبلیغ یا نحو فایل های میزبان استفاده کنید.", + "system_host_files": "فایل های هوست سیستم", "examples_title": "مثال ها", "example_meaning_filter_block": "مسدودسازی دسترسی به دامنه example.org و همه زیر دامنه ها آن", "example_meaning_filter_whitelist": "بازکردن دسترسی به دامنه example.org و همه زیر دامنه ها آن", @@ -159,6 +203,7 @@ "example_upstream_sdns": "شما میتوانید از DNS Stamps برای DNSCrypt یا DNS-over-HTTPS resolvers استفاده کنید", "example_upstream_tcp": "DNS عادی (بر TCP)", "all_lists_up_to_date_toast": "همه لیست ها از قبل بروز اند", + "updated_upstream_dns_toast": "سرورهای DNS جریان ارسالی بروز رسانی شده است", "dns_test_ok_toast": "سرورهای DNS تعیین شده بدرستی کار می کنند", "dns_test_not_ok_toast": "سرور \"{{key}}\": نمیتواند مورد استفاده قرار گیرد،لطفا بررسی کنید آن را بدرستی نوشته اید", "unblock": "رفع انسداد", @@ -169,6 +214,7 @@ "domain_or_client": "دامنه یا کلاینت", "type_table_header": "نوع", "response_table_header": "پاسخ", + "response_code": "کد پاسخ", "client_table_header": "کلاینت", "empty_response_status": "خالی", "show_all_filter_type": "نمایش همه", @@ -187,6 +233,7 @@ "query_log_filtered": "فیلتر شده با {{filter}}", "query_log_confirm_clear": "آیا واقعا میخواهید کل وقایع جستار را پاک کنید؟", "query_log_cleared": "وقایع جستار با موفقیت پاک شد", + "query_log_updated": "فیلتر با موفقیت بروز رسانی شد", "query_log_clear": "پاکسازی وقایع جستار", "query_log_retention": "حفظ وقایع جستار برای", "query_log_enable": "فعالسازی وقایع", @@ -212,15 +259,19 @@ "rate_limit": "میزان محدودیت", "edns_enable": "فعالسازی زیرشبکه کلاینت EDNS", "edns_cs_desc": "اگر فعال باشد،AdGuard Home زیرشبکه های کلاینت ها را به سرورهای DNS می فرستد.", + "rate_limit_desc": "تعداد درخواست های بر ثانیه مجازی که یک کلاینت میتواند بسازد (0: نامحدود)", "blocking_ipv4_desc": "آدرس آی پی برگشت داده شده برای درخواست مسدود شده A", "blocking_ipv6_desc": "آدرس آی پی برگشت داده شده برای درخواست مسدود شده AAAA", + "blocking_mode_default": "پیش فرض: وقتی مسدود شود با دستور سبک-مسدودساز تبلیغ REFUSED پاسخ میدهد،پاسخ با آدرس آی پی تعیین شده در دستور وقتی با دستور /etc/hosts-style rule مسدود شود", "blocking_mode_nxdomain": "NXDOMAIN: پاسخ با کُد NXDOMAIN", "blocking_mode_null_ip": "Null IP: پاسخ با آدرس آی پی صفر(0.0.0.0 برای A; :: برای AAAA)", "blocking_mode_custom_ip": "آی پی دستی: پاسخ با آدرس آی پی دستی تنظیم شده", "upstream_dns_client_desc": "اگر این فیلد را خالی نگه دارید، AdGuard Home از سرور پیکربندی شده در <0> تنظیماتDNS استفاده می کند.", + "tracker_source": "منبع ردیاب", "source_label": "منبع", "found_in_known_domain_db": "در پایگاه داده دامنه های شناخته شده پیدا شد", "category_label": "دسته بندی", + "rule_label": "دستور", "list_label": "لیست", "unknown_filter": "فیلتر ناشناخته {{filterId}}", "known_tracker": "ردیاب های شناخته شده", @@ -230,6 +281,7 @@ "install_settings_listen": "رابط گوش دادن", "install_settings_port": "پورت", "install_settings_interface_link": "رابط صفحه وب آدمین AdGuard Home شما در این آدرس قابل دسترسی خواهد بود:", + "form_error_port": "مقدار پورت معتبر وارد کنید", "install_settings_dns": "سرور DNS", "install_settings_dns_desc": "نیاز است شما دستگاه یا روتر خود را برای استفاده از سرور DNS روی آدرس های زیر پیکربندی کنید:", "install_settings_all_interfaces": "همه رابط ها", @@ -248,8 +300,10 @@ "install_devices_router": "روتر", "install_devices_router_desc": "این راه انداز خودکار همه دستگاه های متصل شده به روتر خانه را پوشش میدهد و نیازی نیست شما هر یک از آنها را دستی پیکربندی کنید.", "install_devices_address": "DNS سرور AdGuard Home به آدرس های زیر گوش میدهد", + "install_devices_router_list_1": "اولویت ها را برای روتر خود باز کنید.معمولا میتوانید آن را ز طریق مرورگر از طریق آدرسی مانند ( http://192.168.0.1/ یا http://192.168.1.1/) دسترسی داشته باشید.ممکن است رمزعبور پرسیده شود،اگر آن را بخاطر ندارید،غالبا میتوان رمزعبور را با فشردن دکمه پشت روتر ریست کرد.برخی روترها برنامه خاصی نیاز دارد که باید در رایانه/گوشی نصب شده باشد.", "install_devices_router_list_2": "تنظیمات DHCP/DNS را بیابید.دنبال حروف DNS بگردید در فیلدی که اجازه دو یا سه گروه عدد را میدهد و هر کدام در چهار گروه سه عددی شکسته شده است", "install_devices_router_list_3": "آدرس سرور AdGuard Home خود را آنجا وارد کنید", + "install_devices_router_list_4": "شما نمیتوانید DNS سرور سفارشی در برخی از روترها تنظیم کنید. در این مورد اگر شما AdGuard Home را بعنوان DHCP سرور راه اندازی کنید میتواند کمک کند. در غیر اینصورت باید راهنمای سفارشی سازی DNS سرورها برای مدل خاص روتر خود را انتخاب کنید.", "install_devices_windows_list_1": "کنترل پنل را از طریق استارت منو یا جستجوی ویندوز باز کنید.", "install_devices_windows_list_2": "بروید به شبکه و دسته اینترنت و سپس به شبکه و مرکز اشتراک گذاری", "install_devices_windows_list_3": "در سمت چپ صفحه تنظیمات آداپتور را تغییر داده و روی آن کلیک کنید", @@ -275,8 +329,10 @@ "install_saved": "با موفقیت ذخیره نشد", "encryption_title": "رمزگُذاری", "encryption_desc": "پشتیبانی رمزگُذاری (HTTPS/TLS) برای DNS و رابط آدمین وب", + "encryption_config_saved": "پیکربندی رمزگذاری ذخیره شد", "encryption_server": "نام سرور", "encryption_server_enter": "نام دامنه خود را وارد کنید", + "encryption_server_desc": "به منظور استفاده از HTTPS،شما باید نام سرور مطابق با گواهینامه اِس اِس اِل را وارد کنید.", "encryption_redirect": "تغییر مسیر خودکار به HTTPS", "encryption_redirect_desc": "اگر انتخاب شده باشد،AdGuard Home خودکار شما را از آدرس HTTP به HTTPS منتقل می کند", "encryption_https": "پورت HTTPS", @@ -302,10 +358,13 @@ "encryption_reset": "آیا میخواهید تنظیمات رمزگُذاری به پیش فرض بازگردد؟", "topline_expiring_certificate": "گواهینامه اِس اِس اِل شما در صدد انقضاء است. <0>تنظیمات رمزگُذاری را بروز رسانی کنید.", "topline_expired_certificate": "گواهینامه اِس اِس اِل شما منقضی شده است. <0>تنظیمات رمزگُذاری را بروز رسانی کنید.", + "form_error_port_range": "مقدار پورت را در محدوده 80-65535 وارد کنید", "form_error_port_unsafe": "این پورت غیر ایمن است", + "form_error_equal": "نباید برابر باشد", "form_error_password": "رمزعبور تطبیق ندارد", "reset_settings": "ریست تنظیمات", "update_announcement": "AdGuard Home {{version}} در دسترس است! <0>اینجا کلیک کنید برای اطلاعات بیشتر.", + "setup_guide": "راهنمای راه اندازی", "dns_addresses": "آدرس های DNS", "dns_start": "سرور DNS در حال شروع است", "dns_status_error": "خطا در دریافت وضعیت DNS", @@ -314,6 +373,7 @@ "dns_providers": "در اینجا یک <0>لیست از سرویس های ارائه دهنده DNS برای انتخاب هست.", "update_now": "حالا بروز رسانی", "update_failed": "بروز رسانی خودکار موفق نشد. لطفا مراحل را دنبال کرده تا بطور دستی بروز رسانی کنید.", + "manual_update": "لطفااین مراحل را دنبال کنیدتا به طور دستی بروزرسانی نمایید.", "processing_update": "منتظر بمانید،AdGuard Home در حال بروز رسانی است", "clients_title": "کلاینت ها", "clients_desc": "پیکربندی دستگاه های متصل شده به AdGuard Home", @@ -327,7 +387,9 @@ "client_edit": "ویرایش کلاینت", "client_identifier": "احراز با", "ip_address": "آدرس آی پی", + "client_identifier_desc": "کلاینت میتواند با آدرس آی پی یا آدرس مَک احراز شود. لطفا توجه کنید،که استفاده از مَک بعنوان عامل احراز زمانی امکان دارد که AdGuard Home نیز <0>سرور DHCP باشد", "form_enter_ip": "آی پی را وارد کنید", + "form_enter_subnet_ip": "یک آدرس آی پی در زیر شبکه \"{{cidr}}\" وارد کنید", "form_enter_mac": "مَک را وارد کنید", "form_enter_id": "خطای احرازکننده", "form_add_id": "افزودن احرازکننده", @@ -349,6 +411,7 @@ "access_disallowed_title": "کلاینت های غیرمجاز", "access_disallowed_desc": "یک لیست از CIDR یا آدرس های IP.اگر پیکربندی شود،AdGuard Home درخواست ها را از این آدرس های IP نمی پذیرد.", "access_blocked_title": "دامنه های مسدود شده", + "access_blocked_desc": "این را با فیلتر ها به اشتباه نگیرید.AdGuard Home جستار DNS را با این دامنه ها در جستار سوال ها نمی پذیرد.", "access_settings_saved": "تنظیمات دسترسی با موفقیت ذخیره شد", "updates_checked": "بروز رسانی با موفقیت بررسی شد", "updates_version_equal": "AdGuard Home بروز است", @@ -356,6 +419,7 @@ "dns_privacy": "حریم خصوصی DNS", "setup_dns_privacy_1": "<0>DNS-over-TLS: استفاده از<1>{{address}} .", "setup_dns_privacy_2": "<0>DNS-over-HTTPS: استفاده از <1>{{address}} .", + "setup_dns_privacy_3": "<0>لطفا توجه کنید که پروتکل های رمزگذاری شده DNS فقط در آندروئید 9 پشتیبانی می شود. پس برای سیستم عامل های دیگر نیاز است که برنامه دیگری نصب کنید.<0>در اینجا میتوانید لیست نرم افزارهای قابل استفاده را ببینید.", "setup_dns_privacy_android_1": "آندروئید 9 بطور پیش فرض از DNS-over-TLS پشتیبانی می کند. برای پیکربندی آن، بروید به تنظیمات → شبکه & اینترنت → پیشرفته → DNS خصوصی و نام دامنه را آنجا وارد کنید.", "setup_dns_privacy_android_2": "<0>AdGuard for Android پشتیبانی از <1>DNS-over-HTTPS و <1>DNS-over-TLS.", "setup_dns_privacy_android_3": "<0>Intra قابلیت <1>DNS-over-HTTPS را به آندروئید اضافه می کند.", @@ -410,10 +474,11 @@ "statistics_configuration": "پیکربندی آمارها", "statistics_retention": "مدت حفظ آمارها", "statistics_retention_desc": "اگر مقدار فاصله را کاهش دهید،برخی داده ها از بین خواهد رفت", - "statistics_clear": "بازنشانی آمار", + "statistics_clear": " پاکسازی آمار", "statistics_clear_confirm": "آیا واقعا میخواهید آمار را پاک کنید؟", "statistics_retention_confirm": "آیا واقعا میخواهید مدت حفظ آمار را تغییر دهید؟ اگر فاصله را کاهش دهید، برخی داده ها حذف میشود", "statistics_cleared": "آمارها با موفقیت حذف شد", + "statistics_enable": "فعالسازی داده های آماری", "interval_hours": "{{count}} ساعت", "interval_hours_plural": "{{count}} ساعت", "filters_configuration": "پیکربندی فیلترها", @@ -440,7 +505,10 @@ "domain_desc": "نامه دامنه یا علامت تطبیقی را برای بازنویسی وارد کنید.", "example_rewrite_domain": "فقط بازنویسی پاسخ برای این دامنه.", "example_rewrite_wildcard": "بازنویسی پاسخ ها برای همه زیردامنه های <0>example.org.", + "disable_ipv6": "غیرفعالسازی IPv6", + "disable_ipv6_desc": "اگر این ویژگی فعال شده، همه جستارهای DNS برای آدرس های IPv6 (نوع AAAA) رها میشود.", "fastest_addr": "سریعترین آدرس آی پی", + "fastest_addr_desc": "جستار همه سرورهای DNS و بازگرداندن سریعترین آدرس IP از میان همه پاسخ ها", "autofix_warning_text": "اگر روی \"تعمیر\" کلیک کنید، AdGuardHome سیستم شما را برای استفاده از DNS سرور AdGuardHome پیکربندی می کند.", "autofix_warning_list": "این وظایف را اجرا میکند: <0>غیرفعالسازی DNSStubListener سیستم <0>تنظیم آدرس DNS 127.0.0.1 سرور به <0>جایگزینی لینک نمادی هدف /etc/resolv.conf به/run/systemd/resolve/resolv.conf <0>توقف DNSStubListener (بارگیری مجدد سرویس systemd-resolved)", "autofix_warning_result": "در نتیجه همه درخواست های DNS از سیستم شما بطور پیش فرض با AdGuardHome پردازش خواهد شد.", @@ -467,6 +535,7 @@ "set_static_ip": "تنظیم یک آدرس آی پی ثابت", "install_static_ok": "خبر خوب! آدرس آی پی ثابت از قبل پیکربندی شده است", "install_static_error": "AdGuard Home نمیتواند رابط این شبکه را خودکار پیکربندی کند. لطفا دستورالعمل چگونگی انجام دستی آن را مطالعه کنید.", + "install_static_configure": "ما تشخیص دادیم از آدرس آی پی پویا استفاده شده است — <0>{{ip}}. آیا میخواهید از آن بعنوان آدرس ثابت استفاده کنید؟", "confirm_static_ip": "AdGuard Home {{ip}} بعنوان آدرس آی پی ثابت شما پیکربندی می کند. ادامه میدهید؟", "list_updated": "{{count}} لیست بروز رسانی شد", "list_updated_plural": "{{count}} لیست بروز رسانی شد", @@ -477,16 +546,21 @@ "show_whitelisted_responses": "لیست سفید", "show_processed_responses": "پردازش شده", "blocked_safebrowsing": "بستن وب گردی اَمن", - "blocked_adult_websites": "مسدود شده با نظارت والدین", + "blocked_adult_websites": "وبسایت غیراخلاقی مسدود شده", "blocked_threats": "تهدیدات مسدود شده", "allowed": "اجازه داده شده", "filtered": "فیلتر شده", "rewritten": "بازنویسی شده", - "safe_search": "فعالسازی جستجوی اَمن", + "safe_search": "جستجوی اَمن", "blocklist": "لیست سیاه", "milliseconds_abbreviation": "هـ ثـ", + "cache_optimistic": "حالت ویژه پردازش", + "cache_optimistic_desc": "AdGuard Home را وادار می کند که از سمت حافظه پنهان پاسخ دهد حتی وقتی که موارد وارد شده منقضی شده باشد و همچنین سعی بر تازه کردن آنها می کند.", "filter_category_general": "General", "filter_category_security": "مسدودسازی بدافزار و فیشینگ", "filter_category_other": "ساير", - "parental_control": "نظارت والدین" + "use_saved_key": "از کلید ذخیره شده قبلی استفاده کنید", + "parental_control": "نظارت والدین", + "safe_browsing": "وب گردی اَمن", + "form_error_password_length": "رمزعبور باید حداقل {{value}} کاراکتر باشد." } diff --git a/client/src/__locales/nl.json b/client/src/__locales/nl.json index 990f4b09..7fc19d73 100644 --- a/client/src/__locales/nl.json +++ b/client/src/__locales/nl.json @@ -126,7 +126,7 @@ "top_blocked_domains": "Top geblokkeerde domeinen", "top_clients": "Top gebruikers", "no_clients_found": "Geen gebruikers gevonden", - "general_statistics": "Generieke statistieken", + "general_statistics": "Algemene statistieken", "number_of_dns_query_days": "Aantal verwerkte DNS aanvragen van de laatste {{count}} dag", "number_of_dns_query_days_plural": "Aantal verwerkte DNS aanvragen van de laatste {{count}} dagen", "number_of_dns_query_24_hours": "Aantal verwerkte DNS aanvragen van de laatste 24 uur", @@ -137,7 +137,7 @@ "number_of_dns_query_to_safe_search": "Aantal DNS aanvragen in zoekmachines dmv geforceerd veilig zoeken", "average_processing_time": "Gemiddelde procestijd", "average_processing_time_hint": "Gemiddelde verwerkingstijd in milliseconden van een DNS aanvraag", - "block_domain_use_filters_and_hosts": "Blokkeerd domeinen dmv filters en host bestanden", + "block_domain_use_filters_and_hosts": "Domeinen blokkeren d.m.v. filters en host-bestanden", "filters_block_toggle_hint": "Je kan blokkeringsregels toevoegen in de Filters instellingen.", "use_adguard_browsing_sec": "Gebruik AdGuardBrowsing Security web service", "use_adguard_browsing_sec_hint": "AdGuard Home controleert of het domein in de blokkeerlijst voorkomt dmv Browsing Security web service. Dit gebeurt dmv een privacy vriendelijk API verzoek:een korte prefix van de domein naam met SHA256 hash wordt verzonden naar de server.", @@ -146,15 +146,15 @@ "enforce_safe_search": "Veilig zoeken gebruiken", "enforce_save_search_hint": "AdGuard Home kan veilig zoeken forceren voor de volgende zoekmachines: Google, Youtube, Bing, en DuckDuckGo, Yandex, Pixabay.", "no_servers_specified": "Geen servers gespecificeerd", - "general_settings": "Generieke instellingen", - "dns_settings": "DNS Instellingen", + "general_settings": "Algemene instellingen", + "dns_settings": "DNS instellingen", "dns_blocklists": "DNS blokkeerlijsten", "dns_allowlists": "DNS toestemmingslijsten", "dns_blocklists_desc": "AdGuard Home zal domeinen blokkeren die voorkomen in de blokkeerlijsten.", "dns_allowlists_desc": "Domeinen in de DNS toestemmingslijsten worden toegestaan zelfs al komen ze voor in de blokkeerlijsten.", "custom_filtering_rules": "Aangepaste filter regels", - "encryption_settings": "Encryptie Instellingen", - "dhcp_settings": "DHCP Instellingen", + "encryption_settings": "Encryptie instellingen", + "dhcp_settings": "DHCP instellingen", "upstream_dns": "Upstream DNS-servers", "upstream_dns_help": "Een server-adres per regel invoeren. Meer weten over het configureren van upstream DNS-servers.", "upstream_dns_configured_in_file": "Geconfigureerd in {{path}}", @@ -225,8 +225,8 @@ "block": "Blokkeren", "disallow_this_client": "Toepassing/systeem niet toelaten", "allow_this_client": "Toepassing/systeem toelaten", - "block_for_this_client_only": "Alleen voor deze toepassing/dit systeem blokkeren", - "unblock_for_this_client_only": "Alleen voor deze toepassing/dit systeem deblokkeren", + "block_for_this_client_only": "Alleen voor deze cliënt blokkeren", + "unblock_for_this_client_only": "Alleen voor deze cliënt deblokkeren", "time_table_header": "Tijd", "date": "Datum", "domain_name_table_header": "Domein naam", @@ -403,7 +403,7 @@ "down": "Uitgeschakeld", "fix": "Los op", "dns_providers": "hier is een <0>lijst of gekende DNS providers waarvan je kan kiezen.", - "update_now": "Update nu", + "update_now": "Nu bijwerken", "update_failed": "Automatisch bijwerken is mislukt. Volg deze stappen om handmatig bij te werken.", "manual_update": "Volg deze stappen om handmatig bij te werken.", "processing_update": "Even geduld, AdGuard Home wordt bijgewerkt", @@ -624,7 +624,7 @@ "original_response": "Oorspronkelijke reactie", "click_to_view_queries": "Klik om queries te bekijken", "port_53_faq_link": "Poort 53 wordt vaak gebruikt door services als DNSStubListener- of de systeem DNS-resolver. Lees a.u.b. <0>deze instructie hoe dit is op te lossen.", - "adg_will_drop_dns_queries": "AdGuard Home zal alle DNS verzoeken van deze toepassing/dit systeem negeren.", + "adg_will_drop_dns_queries": "AdGuard Home zal alle DNS-verzoeken van deze cliënt laten vervallen.", "filter_allowlist": "WAARSCHUWING: Deze actie zal ook de regel \"{{disallowed_rule}}\" uitsluiten van de lijst met toegestane clients.", "last_rule_in_allowlist": "Kan deze client niet weigeren omdat het uitsluiten van de regel \"{{disallowed_rule}}\" de lijst \"Toegestane clients\" zal UITSCHAKELEN.", "use_saved_key": "De eerder opgeslagen sleutel gebruiken", diff --git a/client/src/__locales/no.json b/client/src/__locales/no.json index b8f8bc63..0259d267 100644 --- a/client/src/__locales/no.json +++ b/client/src/__locales/no.json @@ -10,6 +10,10 @@ "bootstrap_dns_desc": "Bootstrap-DNS-tjenere brukes til å oppklare IP-adressene til DoH/DoT-oppklarerene som du har valgt som oppstrømstjenere.", "local_ptr_title": "Private DNS-tjenere", "local_ptr_desc": "DNS-tjenerne som AdGuard Home bruker for lokale PTR-spørringer. Disse tjenerne brukes til å løse vertsnavnene til klienter med private IP-adresser, for eksempel \"192.168.12.34\", ved bruk av omvendt DNS. Hvis det ikke er angitt, bruker AdGuard Home adressene til standard-DNS-løserne til operativsystemet ditt, bortsett fra adressene til selve AdGuard Home.", + "local_ptr_default_resolver": "Som standard, bruker AdGuard Home følgende revers-DNS-oppletere: {{ip}}.", + "local_ptr_no_default_resolver": "AdGuard Home klarte ikke å finne egnede private revers-DNS-oppletere for dette systemet.", + "local_ptr_placeholder": "Skriv inn én tjeneradresse per linje", + "resolve_clients_title": "Skru på revers-oppleting av klienters IP-adresser", "use_private_ptr_resolvers_title": "Bruk private omvendte DNS-løsere", "check_dhcp_servers": "Se etter DHCP-tjenere", "save_config": "Lagre oppsettet", @@ -21,20 +25,24 @@ "dhcp_description": "Dersom ruteren din ikke har DHCP-innstillinger, kan du bruke AdGuard Home sin egen innebygde DHCP-tjener.", "dhcp_enable": "Skru på DHCP-tjeneren", "dhcp_disable": "Skru av DHCP-tjeneren", + "dhcp_not_found": "Det er trygt å skru på den innebygde DHCP-tjeneren - vi kunne ikke finne noen aktive DHCP-tjenere i nettverket. Men vi oppfordrer deg til å dobbeltsjekke manuelt, siden vår automatiske test ikke gir 100% sikre svar ennå.", "dhcp_found": "En aktiv DHCP-tjener ble oppdaget i nettverket. Det er ikke trygt å bruke den innebygde DHCP-tjeneren.", "dhcp_leases": "DHCP-leieavtaler", "dhcp_static_leases": "Statiske DHCP-leieavtaler", "dhcp_leases_not_found": "Ingen DHCP-leieavtaler ble funnet", + "dhcp_config_saved": "Lagret DHCP-tjeneroppsettet", "dhcp_ipv4_settings": "DHCP IPv4-innstillinger", "dhcp_ipv6_settings": "DHCP IPv6-innstillinger", "form_error_required": "Påkrevd felt", "form_error_ip4_format": "Ugyldig IPv4-format", "form_error_ip6_format": "Ugyldig IPv6-format", - "form_error_ip_format": "Ugyldig IP-adresse", + "form_error_ip_format": "Ugyldig IPv4-format", "form_error_mac_format": "Ugyldig MAC-format", "form_error_client_id_format": "Ugyldig ID-klientformat", "form_error_server_name": "Ugyldig tjenernavn", + "form_error_subnet": "Undernettet «{{cidr}}» inneholder ikke IP-adressen «{{ip}}»", "form_error_positive": "Må være høyere enn 0", + "greater_range_start_error": "Må være høyere enn rekkeviddens start", "dhcp_form_gateway_input": "Gateway-IP", "dhcp_form_subnet_input": "Nettverksmaske", "dhcp_form_range_title": "Spennvidden til IP-adressene", @@ -48,11 +56,16 @@ "ip": "IP-adresse", "dhcp_table_hostname": "Vertsnavn", "dhcp_table_expires": "Utløper", + "dhcp_warning": "Hvis du vil aktivere DHCP-tjeneren likevel, så sørg for at det ikke er noen andre aktive DHCP-tjenere i nettverket ditt. Ellers kan det knekke internettilgangen til tilkoblede enheter!", + "dhcp_error": "Vi klarte ikke å fastslå om det er en annen DHCP-tjener i nettverket ditt eller ikke.", + "dhcp_static_ip_error": "For å kunne bruke DHCP-tjeneren, må det være satt en statisk IP-adresse. Vi klarte ikke å finne ut om dette nettverksgrensesnittet har blitt satt opp med en statisk IP-adresse. Vennligst sett opp en statisk IP-adresse manuelt.", + "dhcp_dynamic_ip_found": "Systemet ditt bruker et oppsett med dynamisk IP-adresse for grensesnittet <0>{{interfaceName}}. For å kunne bruke DHCP-tjeneren, må en statisk IP-adresse ha blitt satt opp. Din nåværende IP-adresse er <0>{{ipAddress}}. Vi vil automatisk gjøre denne IP-adressen statisk hvis du trykker på «Skru på DHCP»-knappen.", "dhcp_lease_added": "Den statiske leieavtalen «{{key}}» ble vellykket lagt til", "dhcp_lease_deleted": "Den statiske leieavtalen «{{key}}» ble vellykket lagt slettet", "dhcp_new_static_lease": "Ny statisk leieavtale", "dhcp_static_leases_not_found": "Ingen statiske DHCP-leieavtaler ble funnet", "dhcp_add_static_lease": "Legg til statisk leieavtale", + "dhcp_reset": "Er du sikker på at du vil tilbakestille DHCP-oppsettet?", "country": "Land", "city": "By", "delete_confirm": "Er du sikker på at du vil slette «{{key}}»?", @@ -93,13 +106,22 @@ "for_last_24_hours": "de siste 24 timene", "for_last_days": "det siste døgnet", "for_last_days_plural": "de siste {{count}} dagene", + "stats_disabled": "Statistikkene har blitt skrudd av. Du kan skru den på fra <0>innstillingssiden.", + "stats_disabled_short": "Statistikkene har blitt skrudd av", "no_domains_found": "Ingen domener ble funnet", "requests_count": "Antall forespørsler", "top_blocked_domains": "Mest blokkerte domener", "top_clients": "Vanligste klienter", "no_clients_found": "Ingen klienter ble funnet", "general_statistics": "Generelle statistikker", + "number_of_dns_query_days": "Antall DNS-forespørsler som ble behandlet det siste døgnet", + "number_of_dns_query_days_plural": "Antall DNS-forespørsler som ble behandlet de siste {{count}} dagene", + "number_of_dns_query_24_hours": "Antall DNS-forespørsler som ble behandlet de siste 24 timene", + "number_of_dns_query_blocked_24_hours": "Antall DNS-forespørsler som ble blokkert av adblock-filtre, hosts-lister, og domene-lister", + "number_of_dns_query_blocked_24_hours_by_sec": "Antall DNS-forespørsler som ble blokkert av AdGuard sin nettlesersikkerhetsmodul", + "number_of_dns_query_blocked_24_hours_adult": "Antall voksennettsteder som ble blokkert", "enforced_save_search": "Påtvungede barnevennlige søk", + "number_of_dns_query_to_safe_search": "Antall DNS-forespørsler til søkemotorer der \"Safe Search\" ble fremtvunget", "average_processing_time": "Gjennomsnittlig behandlingstid", "average_processing_time_hint": "Gjennomsnittstid for behandling av DNS-forespørsler i millisekunder", "block_domain_use_filters_and_hosts": "Blokker domener ved hjelp av filtre, «hosts»-filer, og rå domener", @@ -181,6 +203,7 @@ "example_upstream_sdns": "du kan bruke <0>DNS-stempler med <1>DNSCrypt eller <2>DNS-over-HTTPS-behandlere", "example_upstream_tcp": "vanlig DNS (over TCP)", "all_lists_up_to_date_toast": "Alle listene er allerede oppdatert", + "updated_upstream_dns_toast": "Oppdaterte oppstrøms-DNS-tjenerne", "dns_test_ok_toast": "De spesifiserte DNS-tjenerne fungerer riktig", "dns_test_not_ok_toast": "Tjeneren «{{key}}» kunne ikke brukes, vennligst dobbeltsjekk at du har skrevet den riktig", "unblock": "Tillat", @@ -241,13 +264,16 @@ "dns_over_quic": "DNS-over-QUIC", "client_id": "Klient-ID", "client_id_placeholder": "Skriv inn klient-ID", + "client_id_desc": "Forskjellige klienter kan identifiserer med en spesiell klient-ID. Her kan du lære mer om hvordan man identifiserer klienter.", "download_mobileconfig_doh": "Last ned .mobileconfig for DNS-over-HTTPS", "download_mobileconfig_dot": "Last ned .mobileconfig for DNS-over-TLS", + "download_mobileconfig": "Last ned oppsettsfil", "plain_dns": "Ordinær DNS", "form_enter_rate_limit": "Skriv inn forespørselsfrekvensgrense", "rate_limit": "Forespørselsfrekvensgrense", "edns_enable": "Aktiver EDNS-klientundernett", "edns_cs_desc": "Hvis det er skrudd på, vil AdGuard Home sende klientenes undernett til DNS-tjenerne.", + "rate_limit_desc": "Antallet forespørsler per sekund som én enkelt klient har lov til å be om (0: ubegrenset)", "blocking_ipv4_desc": "IP-adressen som det skal svares med for blokkerte A-forespørsler", "blocking_ipv6_desc": "IP-adressen som det skal svares med for blokkerte AAAA-forespørsler", "blocking_mode_default": "Standard: Svar med null-IP-adresse (0.0.0.0 for A; :: for AAAA) når den blokkeres av adblock-aktige oppføringer; svar med IP-adressen som er spesifisert i oppføringen når den blokkeres av /etc/hosts-typeoppføringer", @@ -289,8 +315,10 @@ "install_devices_router": "Ruter", "install_devices_router_desc": "Dette oppsettet vil automatisk dekke alle enhetene som er koblet til hjemmeruteren din, og du vil ikke måtte sette opp hver av dem manuelt.", "install_devices_address": "AdGuard Home-DNS-tjeneren lytter til de følgende adressene", + "install_devices_router_list_1": "Åpne innstillingene til ruteren din. Vanligvis kan du få tilgang til den på nettleseren din gjennom en URL (f.eks. http://192.168.0.1/ eller http://192.168.1.1/). Du kan bli spurt om å skrive inn passordet ditt. Hvis du ikke husker det, kan du som oftest tilbakestille passordet ditt ved å trykke på knapp på selve ruteren. Noen rutere krever et spesifikt program, som i så fall er ment å allerede ha blitt installert på din PC/mobil.", "install_devices_router_list_2": "Finn DHCP-/DNS-innstillingene. Se etter DNS-bokstavene ved siden av et felt som tillater to eller tre sett med sifre, som hver er delt opp i fire grupper på 1-3 sifre.", "install_devices_router_list_3": "Skriv inn din AdGuard Home-tjeners adresser her.", + "install_devices_router_list_4": "På noen rutertyper, f.eks. Altibox sine hjemmesentraler, kan man ikke velge en selvvalgt DNS-tjener. I så fall kan det hjelpe på saken om du setter opp AdGuard Home som en <0>DHCP-tjener. Alternativt, burde du se i bruksanvisningen til din spesifikke rutermodell om hvordan man tilpasser DNS-tjenerne.", "install_devices_windows_list_1": "Åpne «Kontrollpanel» gjennom Start-menyen eller et Windows-søk.", "install_devices_windows_list_2": "Gå til «Nettverk og internett»-kategorien, og så til «Nettverks- og delingssenter».", "install_devices_windows_list_3": "På den venstre siden av skjermen, finn «Endre innstillinger for nettverkskort» og klikk på den.", @@ -316,6 +344,7 @@ "install_saved": "Lagringen var vellykket", "encryption_title": "Kryptering", "encryption_desc": "Krypteringsstøtte (HTTPS/TLS) for både DNS og admin-nettgrensesnittet", + "encryption_config_saved": "Krypteringsoppsettet ble lagret", "encryption_server": "Tjenerens navn", "encryption_server_enter": "Skriv inn domenenavnet ditt", "encryption_server_desc": "For å kunne bruke HTTPS, må du skrive inn tjenernavnet som samsvarer med ditt SSL-sertifikat eller jokertegnsertifikat. Hvis feltet er tomt, vil den akseptere TLS-tilkoblinger til ethvert domene.", @@ -346,7 +375,9 @@ "encryption_reset": "Er du sikker på at du vil tilbakestille krypteringsinnstillingene?", "topline_expiring_certificate": "Ditt SSL-sertifikat er i ferd med å utløpe. Oppdater <0>Krypteringsinnstillinger.", "topline_expired_certificate": "SSL-sertifikatet har utløpt. Oppdater <0>Krypteringsinnstillinger.", + "form_error_port_range": "Skriv inn et portnummer i området 80-65535", "form_error_port_unsafe": "Denne porten er ikke trygg", + "form_error_equal": "Burde ikke være de samme", "form_error_password": "Passordet samsvarer ikke", "reset_settings": "Tilbakestill innstillinger", "update_announcement": "AdGuard Home {{version}} er nå tilgjengelig! <0>Klikk her for mere informasjon.", @@ -374,6 +405,7 @@ "ip_address": "IP-adresse", "client_identifier_desc": "Klienter kan bli identifisert gjennom IP-adressen, CIDR, MAC-adressen, eller en spesiell klient-ID (kan også brukes for DoT/DoH/DoQ). <0>Her kan du lære mer om å identifisere klienter.", "form_enter_ip": "Skriv inn IP", + "form_enter_subnet_ip": "Skriv inn en IP-adresse i undernettet «{{cidr}}»", "form_enter_mac": "Skriv inn MAC", "form_enter_id": "Skriv inn identifikator", "form_add_id": "Legg til identifikator", @@ -416,6 +448,7 @@ "setup_dns_privacy_other_3": "<0>dnscrypt-proxy støtter <1>DNS-over-HTTPS.", "setup_dns_privacy_other_4": "<0>Mozilla Firefox støtter <1>DNS-over-HTTPS.", "setup_dns_privacy_other_5": "Du finner flere implementeringer <0>her og <1>her.", + "setup_dns_privacy_ioc_mac": "iOS- og macOS-oppsett", "setup_dns_notice": "For å benytte <1>DNS-over-HTTPS eller <1>DNS-over-TLS, må du <0>sette opp Kryptering i AdGuard Home-innstillingene.", "rewrite_added": "DNS-omdirigeringen for «{{key}}» ble vellykket lagt til", "rewrite_deleted": "DNS-omdirigeringen for «{{key}}» ble vellykket slettet", @@ -453,6 +486,7 @@ "interval_days": "{{count}} dag", "interval_days_plural": "{{count}} dager", "domain": "Domene", + "punycode": "Punycode", "answer": "Svar", "filter_added_successfully": "Filteret har blitt vellykket lagt til", "filter_removed_successfully": "Listen ble vellykket fjernet", @@ -499,6 +533,7 @@ "disable_ipv6": "Skru av IPv6", "disable_ipv6_desc": "Hvis dette er skrudd på, vil alle DNS-forespørslene til IPv6-adresser (AAAA-type) bli droppet.", "fastest_addr": "Raskeste IP-adresse", + "fastest_addr_desc": "Forespør alle DNS-tjenerne og hent den raskeste IP-adressen blant alle svarene. Dette vil gjøre DNS-forespørslene tregere, siden vi må vente på svar fra alle DNS-tjenerne, men det vil forbedre tilkoblingen generelt.", "autofix_warning_text": "Hvis du klikker på «Fiks», vil AdGuard Home sette opp systemet ditt til å bruke 'AdGuard Home'-DNS-tjeneren.", "autofix_warning_list": "Den vil utføre disse handlingene: <0>Skru av systemets DNSStubListener <0>Sette DNS-tjeneradressen til 127.0.0.1 <0>Bytte ut det symbolske lenkemålet til /etc/resolv.conf med /run/systemd/resolve/resolv.conf <0>Stoppe DNSStubListener (gjeninnlast 'systemd-resolved'-tjenesten)", "autofix_warning_result": "Som følge av det vil alle DNS-forespørsler fra systemet ditt bli behandlet av AdGuard Home som standard.", @@ -528,6 +563,7 @@ "set_static_ip": "Velg en statisk IP-adresse", "install_static_ok": "Gode nyheter! Den statiske IP-adressen er allerede satt opp", "install_static_error": "AdGuard Home kan ikke sette opp automatisk i dette nettverksgrensesnitt. Vennligst let opp anvisningen for hvordan man gjør det manuellt.", + "install_static_configure": "Vi har oppdaget at det brukes en dynamisk IP-adresse — <0>{{ip}}. Vil du bruke det som din statiske adresse?", "confirm_static_ip": "AdGuard Home vil sette opp {{ip}} til å bli din statiske IP-adresse. Vil du fortsette?", "list_updated": "{{count}} liste oppdatert", "list_updated_plural": "{{count}} lister oppdatert", @@ -539,12 +575,12 @@ "show_whitelisted_responses": "Hvitelistet", "show_processed_responses": "Bearbeidet", "blocked_safebrowsing": "Blokkert av barnevennlig nettlesing", - "blocked_adult_websites": "Blokkert av foreldrekontroll", + "blocked_adult_websites": "Blokkerte voksennettsteder", "blocked_threats": "Blokkerte trusler", "allowed": "Unntak", "filtered": "Filtrert", "rewritten": "Omskrevet", - "safe_search": "Aktivert sikkert søk", + "safe_search": "Trygge søk", "blocklist": "Blokkeringsliste", "milliseconds_abbreviation": "ms", "cache_size": "Mellomlagerstørrelse", @@ -564,13 +600,16 @@ "filter_category_regional": "Regional", "filter_category_other": "Andre", "filter_category_general_desc": "Lister som blokkerer sporing og reklamer på de fleste enheter", + "filter_category_security_desc": "Lister som spesialiserer seg på å blokkere skadevare-, phishing- eller svindeldomener", "filter_category_regional_desc": "Lister som fokuserer på regionale reklamer og sporingstjenere", "filter_category_other_desc": "Andre blokkeringslister", + "setup_config_to_enable_dhcp_server": "Oppsett for å skru på DHCP-tjeneren", "original_response": "Opprinnelig svar", "click_to_view_queries": "Klikk for å vise forespørsler", "port_53_faq_link": "Port 53 er ofte opptatt av «DNSStubListener»- eller «systemd-resolved»-tjenestene. Vennligst les <0>denne instruksjonen om hvordan man løser dette.", "adg_will_drop_dns_queries": "AdGuard Home vil droppe alle DNS-forespørsler fra denne klienten.", "use_saved_key": "Bruk den tidligere lagrede nøkkelen", "parental_control": "Foreldrekontroll", + "safe_browsing": "Sikker surfing", "served_from_cache": "{{value}} (formidlet fra mellomlageret)" } diff --git a/client/src/__locales/ru.json b/client/src/__locales/ru.json index 214169fd..d439d0ff 100644 --- a/client/src/__locales/ru.json +++ b/client/src/__locales/ru.json @@ -198,7 +198,7 @@ "enter_valid_allowlist": "Добавьте действующий URL-адрес в белый список.", "form_error_url_format": "Неверный формат URL", "form_error_url_or_path_format": "Неверный URL или абсолютный путь к списку", - "custom_filter_rules": "Пользовательское правило фильтрации", + "custom_filter_rules": "Пользовательские правила фильтрации", "custom_filter_rules_hint": "Вводите по одному правилу на строчку. Вы можете использовать правила блокировки или синтаксис файлов hosts.", "system_host_files": "Системные hosts-файлы", "examples_title": "Примеры", @@ -475,7 +475,7 @@ "rewrite_applied": "Применено правило перезаписи", "rewrite_hosts_applied": "Переписано по правилу файла hosts", "dns_rewrites": "Перезапись DNS-запросов", - "form_domain": "Введите домен", + "form_domain": "Введите имя или маску домена", "form_answer": "Введите IP адрес или домен", "form_error_domain_format": "Некорректный домен", "form_error_answer_format": "Некорректный ответ", diff --git a/client/src/__locales/sv.json b/client/src/__locales/sv.json index 90ddd608..a107e8c7 100644 --- a/client/src/__locales/sv.json +++ b/client/src/__locales/sv.json @@ -1,7 +1,7 @@ { "client_settings": "Klientinställningar", - "example_upstream_reserved": "Du kan specificera DNS-uppström <0>för en specifik domän", - "example_upstream_comment": "Du kan ange en kommentar", + "example_upstream_reserved": "uppström <0>för en specifik domän;", + "example_upstream_comment": "du kan ange en kommentar.", "upstream_parallel": "Använd parallella förfrågningar för att snabba upp dessa genom att fråga alla uppströmsservrar samtidigt.", "parallel_requests": "Parallella förfrågningar", "load_balancing": "Lastbalansering", @@ -196,7 +196,7 @@ "choose_allowlist": "Välj frilistor", "enter_valid_blocklist": "Ange en giltig URL till blockeringslistan.", "enter_valid_allowlist": "Ange en giltig URL till frilistan.", - "form_error_url_format": "Ogiltigt URL format", + "form_error_url_format": "Ogiltigt URL-format", "form_error_url_or_path_format": "Ogiltig URL eller absolut sökväg till listan", "custom_filter_rules": "Egna filterregler", "custom_filter_rules_hint": "Skriv en regel per rad. Du kan använda antingen annonsblockeringsregler eller värdfilssyntax.", @@ -210,11 +210,13 @@ "example_comment_hash": "# Också en kommentar", "example_regex_meaning": "blockera åtkomst till domäner som matchar det angivna uttrycket", "example_upstream_regular": "vanlig DNS (över UDP)", + "example_upstream_udp": "vanlig DNS (över UDP, värdnamn);", "example_upstream_dot": "krypterat <0>DNS-over-TLS", "example_upstream_doh": "krypterat <0>DNS-over-HTTPS", - "example_upstream_doq": "krypterat <0>DNS-over-QUIC", + "example_upstream_doq": "krypterat <0>DNS-over-QUIC (experimentell);", "example_upstream_sdns": "Du kan använda <0>DNS-stamps för <1>DNSCrypt eller <2>DNS-over-HTTPS-resolvers", "example_upstream_tcp": "vanlig DNS (över UDP)", + "example_upstream_tcp_hostname": "vanlig DNS (över TCP, värdnamn);", "all_lists_up_to_date_toast": "Alla listor är redan uppdaterade", "updated_upstream_dns_toast": "Sparade uppströms dns-servrar", "dns_test_ok_toast": "Angivna DNS servrar fungerar korrekt", diff --git a/client/src/__locales/tr.json b/client/src/__locales/tr.json index 5aa53ec1..74dedd8b 100644 --- a/client/src/__locales/tr.json +++ b/client/src/__locales/tr.json @@ -388,7 +388,7 @@ "encryption_issuer": "Sağlayan", "encryption_hostnames": "Ana makine adları", "encryption_reset": "Şifreleme ayarlarını sıfırlamak istediğinizden emin misiniz?", - "topline_expiring_certificate": "SSL sertifikanızın süresi sona erdi. <0>Şifreleme ayarlarını güncelleyin.", + "topline_expiring_certificate": "SSL sertifikanızın süresi sona üzere. <0>Şifreleme ayarlarını güncelleyin.", "topline_expired_certificate": "SSL sertifikanızın süresi sona erdi. <0>Şifreleme ayarlarını güncelleyin.", "form_error_port_range": "80-65535 aralığında geçerli bir bağlantı noktası değeri girin", "form_error_port_unsafe": "Güvenli olmayan bağlantı noktası", @@ -489,9 +489,9 @@ "blocked_service": "Engellenen hizmet", "block_all": "Tümünü engelle", "unblock_all": "Tüm engellemeyi kaldır", - "encryption_certificate_path": "Sertifika yolu", + "encryption_certificate_path": "Sertifika dosya yolu", "encryption_private_key_path": "Özel anahtar yolu", - "encryption_certificates_source_path": "Sertifika dosyalarının yolunu belirleyin", + "encryption_certificates_source_path": "Bir sertifika dosyası yolu ayarlayın", "encryption_certificates_source_content": "Sertifika içeriğini yapıştır", "encryption_key_source_path": "Özel bir anahtar dosyası belirleyin", "encryption_key_source_content": "Özel anahtar içeriğini yapıştır", diff --git a/client/src/__locales/zh-tw.json b/client/src/__locales/zh-tw.json index 8b1fab72..666ddcc3 100644 --- a/client/src/__locales/zh-tw.json +++ b/client/src/__locales/zh-tw.json @@ -625,8 +625,8 @@ "click_to_view_queries": "點擊以檢視查詢", "port_53_faq_link": "連接埠 53 常被 \"DNSStubListener\" 或 \"systemd-resolved\" 服務佔用。請閱讀有關如何解決這個的<0>用法說明。", "adg_will_drop_dns_queries": "AdGuard Home 將持續排除來自此用戶端之所有的 DNS 查詢。", - "filter_allowlist": "警告:此操作將把 \"{{disallowed_rule}}\" 規則排除在已允許用戶端的清單之外。", - "last_rule_in_allowlist": "無法禁止此用戶端,因為排除 “{{disallowed_rule}}” 規則將禁用“已允許用戶端”的清單。", + "filter_allowlist": "警告:此動作也將把 \"{{disallowed_rule}}\" 規則排除在已允許的用戶端的清單之外。", + "last_rule_in_allowlist": "因為排除 \"{{disallowed_rule}}\" 規則將禁用\"已允許的用戶端\"清單,無法不允許此用戶端。", "use_saved_key": "使用該先前已儲存的金鑰", "parental_control": "家長控制", "safe_browsing": "安全瀏覽", From 12ee287d0b25cc1fb498e54c4484c995613e9bcb Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Tue, 19 Apr 2022 15:01:49 +0300 Subject: [PATCH 027/110] Pull request: 3157 excessive ptrs Merge in DNS/adguard-home from 3157-excessive-ptrs to master Updates #3157. Squashed commit of the following: commit 6803988240dca2f147bb80a5b3f78d7749d2fa14 Author: Eugene Burkov Date: Tue Apr 19 14:50:01 2022 +0300 aghnet: and again commit 1a7f4d1dbc8fd4d3ae620349917526a75fa71b47 Author: Eugene Burkov Date: Tue Apr 19 14:49:20 2022 +0300 aghnet: docs again commit d88da1fc7135f3cd03aff10b02d9957c8ffdfd30 Author: Eugene Burkov Date: Tue Apr 19 14:47:36 2022 +0300 aghnet: imp docs commit c45dbc7800e882c6c4110aab640c32b03046f89a Author: Eugene Burkov Date: Tue Apr 19 14:41:19 2022 +0300 aghnet: keep alphabetical order commit b61781785d096ef43f60fb4f1905a4ed3cdf7c68 Author: Eugene Burkov Date: Tue Apr 19 13:50:56 2022 +0300 aghnet: imp code quality commit 578dbd71ed2f2089c69343d7d4bf8bbc29150ace Author: Eugene Burkov Date: Tue Apr 12 17:02:38 2022 +0300 aghnet: imp arp container --- CHANGELOG.md | 5 +++++ internal/aghnet/arpdb_bsd.go | 13 +++++++++---- internal/aghnet/arpdb_linux.go | 19 ++++++++++++------- internal/aghnet/arpdb_openbsd.go | 15 ++++++++++----- internal/aghnet/arpdb_windows.go | 2 +- internal/dnsforward/dns.go | 1 - internal/dnsforward/recursiondetector_test.go | 14 ++++---------- internal/home/rdns.go | 11 +++++------ 8 files changed, 46 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a80b4ea1..9d82fb57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -87,10 +87,15 @@ In this release, the schema version has changed from 12 to 13. - Go 1.17 support. v0.109.0 will require at least Go 1.18 to build. +### Fixed + +- ARP tables refreshing process causing excessive PTR requests ([#3157]). + [#1730]: https://github.com/AdguardTeam/AdGuardHome/issues/1730 [#2993]: https://github.com/AdguardTeam/AdGuardHome/issues/2993 [#3057]: https://github.com/AdguardTeam/AdGuardHome/issues/3057 [#3142]: https://github.com/AdguardTeam/AdGuardHome/issues/3142 +[#3157]: https://github.com/AdguardTeam/AdGuardHome/issues/3157 [#3367]: https://github.com/AdguardTeam/AdGuardHome/issues/3367 [#3381]: https://github.com/AdguardTeam/AdGuardHome/issues/3381 [#3503]: https://github.com/AdguardTeam/AdGuardHome/issues/3503 diff --git a/internal/aghnet/arpdb_bsd.go b/internal/aghnet/arpdb_bsd.go index a82da76c..26ac7758 100644 --- a/internal/aghnet/arpdb_bsd.go +++ b/internal/aghnet/arpdb_bsd.go @@ -13,19 +13,24 @@ import ( "github.com/AdguardTeam/golibs/netutil" ) -func newARPDB() *cmdARPDB { +func newARPDB() (arp *cmdARPDB) { return &cmdARPDB{ parse: parseArpA, ns: &neighs{ mu: &sync.RWMutex{}, ns: make([]Neighbor, 0), }, - cmd: "arp", - args: []string{"-a"}, + cmd: "arp", + // Use -n flag to avoid resolving the hostnames of the neighbors. By + // default ARP attempts to resolve the hostnames via DNS. See man 8 + // arp. + // + // See also https://github.com/AdguardTeam/AdGuardHome/issues/3157. + args: []string{"-a", "-n"}, } } -// parseArpA parses the output of the "arp -a" command on macOS and FreeBSD. +// parseArpA parses the output of the "arp -a -n" command on macOS and FreeBSD. // The expected input format: // // host.name (192.168.0.1) at ff:ff:ff:ff:ff:ff on en0 ifscope [ethernet] diff --git a/internal/aghnet/arpdb_linux.go b/internal/aghnet/arpdb_linux.go index 3d391f29..9cc38906 100644 --- a/internal/aghnet/arpdb_linux.go +++ b/internal/aghnet/arpdb_linux.go @@ -38,12 +38,17 @@ func newARPDB() (arp *arpdbs) { fsys: rootDirFS, filename: "proc/net/arp", }, - // Then, try "arp -a". + // Then, try "arp -a -n". &cmdARPDB{ parse: parseF, ns: ns, cmd: "arp", - args: []string{"-a"}, + // Use -n flag to avoid resolving the hostnames of the neighbors. + // By default ARP attempts to resolve the hostnames via DNS. See + // man 8 arp. + // + // See also https://github.com/AdguardTeam/AdGuardHome/issues/3157. + args: []string{"-a", "-n"}, }, // Finally, try "ip neigh". &cmdARPDB{ @@ -109,11 +114,11 @@ func (arp *fsysARPDB) Neighbors() (ns []Neighbor) { return arp.ns.clone() } -// parseArpAWrt parses the output of the "arp -a" command on OpenWrt. The +// parseArpAWrt parses the output of the "arp -a -n" command on OpenWrt. The // expected input format: // -// IP address HW type Flags HW address Mask Device -// 192.168.11.98 0x1 0x2 5a:92:df:a9:7e:28 * wan +// IP address HW type Flags HW address Mask Device +// 192.168.11.98 0x1 0x2 5a:92:df:a9:7e:28 * wan // func parseArpAWrt(sc *bufio.Scanner, lenHint int) (ns []Neighbor) { if !sc.Scan() { @@ -153,8 +158,8 @@ func parseArpAWrt(sc *bufio.Scanner, lenHint int) (ns []Neighbor) { return ns } -// parseArpA parses the output of the "arp -a" command on Linux. The expected -// input format: +// parseArpA parses the output of the "arp -a -n" command on Linux. The +// expected input format: // // hostname (192.168.1.1) at ab:cd:ef:ab:cd:ef [ether] on enp0s3 // diff --git a/internal/aghnet/arpdb_openbsd.go b/internal/aghnet/arpdb_openbsd.go index a00ffa85..d5ec5fea 100644 --- a/internal/aghnet/arpdb_openbsd.go +++ b/internal/aghnet/arpdb_openbsd.go @@ -12,20 +12,25 @@ import ( "github.com/AdguardTeam/golibs/log" ) -func newARPDB() *cmdARPDB { +func newARPDB() (arp *cmdARPDB) { return &cmdARPDB{ parse: parseArpA, ns: &neighs{ mu: &sync.RWMutex{}, ns: make([]Neighbor, 0), }, - cmd: "arp", - args: []string{"-a"}, + cmd: "arp", + // Use -n flag to avoid resolving the hostnames of the neighbors. By + // default ARP attempts to resolve the hostnames via DNS. See man 8 + // arp. + // + // See also https://github.com/AdguardTeam/AdGuardHome/issues/3157. + args: []string{"-a", "-n"}, } } -// parseArpA parses the output of the "arp -a" command on OpenBSD. The expected -// input format: +// parseArpA parses the output of the "arp -a -n" command on OpenBSD. The +// expected input format: // // Host Ethernet Address Netif Expire Flags // 192.168.1.1 ab:cd:ef:ab:cd:ef em0 19m59s diff --git a/internal/aghnet/arpdb_windows.go b/internal/aghnet/arpdb_windows.go index 2a70125f..8d5431eb 100644 --- a/internal/aghnet/arpdb_windows.go +++ b/internal/aghnet/arpdb_windows.go @@ -10,7 +10,7 @@ import ( "sync" ) -func newARPDB() *cmdARPDB { +func newARPDB() (arp *cmdARPDB) { return &cmdARPDB{ parse: parseArpA, ns: &neighs{ diff --git a/internal/dnsforward/dns.go b/internal/dnsforward/dns.go index 63f694bd..d423482a 100644 --- a/internal/dnsforward/dns.go +++ b/internal/dnsforward/dns.go @@ -135,7 +135,6 @@ func (s *Server) processRecursion(dctx *dnsContext) (rc resultCode) { pctx.Res = s.genNXDomain(pctx.Req) return resultCodeFinish - } return resultCodeSuccess diff --git a/internal/dnsforward/recursiondetector_test.go b/internal/dnsforward/recursiondetector_test.go index 7573b668..4edb3a37 100644 --- a/internal/dnsforward/recursiondetector_test.go +++ b/internal/dnsforward/recursiondetector_test.go @@ -83,7 +83,7 @@ func TestRecursionDetector_Suspect(t *testing.T) { testCases := []struct { name string msg dns.Msg - want bool + want int }{{ name: "simple", msg: dns.Msg{ @@ -95,24 +95,18 @@ func TestRecursionDetector_Suspect(t *testing.T) { Qtype: dns.TypeA, }}, }, - want: true, + want: 1, }, { name: "unencumbered", msg: dns.Msg{}, - want: false, + want: 0, }} for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Cleanup(rd.clear) - rd.add(tc.msg) - - if tc.want { - assert.Equal(t, 1, rd.recentRequests.Stats().Count) - } else { - assert.Zero(t, rd.recentRequests.Stats().Count) - } + assert.Equal(t, tc.want, rd.recentRequests.Stats().Count) }) } } diff --git a/internal/home/rdns.go b/internal/home/rdns.go index 7a2d1bcd..924aff37 100644 --- a/internal/home/rdns.go +++ b/internal/home/rdns.go @@ -16,18 +16,17 @@ type RDNS struct { exchanger dnsforward.RDNSExchanger clients *clientsContainer - // usePrivate is used to store the state of current private RDNS - // resolving settings and to react to it's changes. + // usePrivate is used to store the state of current private RDNS resolving + // settings and to react to it's changes. usePrivate uint32 // ipCh used to pass client's IP to rDNS workerLoop. ipCh chan net.IP // ipCache caches the IP addresses to be resolved by rDNS. The resolved - // address stays here while it's inside clients. After leaving clients - // the address will be resolved once again. If the address couldn't be - // resolved, cache prevents further attempts to resolve it for some - // time. + // address stays here while it's inside clients. After leaving clients the + // address will be resolved once again. If the address couldn't be + // resolved, cache prevents further attempts to resolve it for some time. ipCache cache.Cache } From 82af43039c78b49908151c09175a5161dd911601 Mon Sep 17 00:00:00 2001 From: Dimitry Kolyshev Date: Tue, 19 Apr 2022 16:07:57 +0300 Subject: [PATCH 028/110] Pull request: whotracksme tracker links Merge in DNS/adguard-home from 4416-ui-tracker-href to master Squashed commit of the following: commit 979ea82a3b4d2c2a895b81aacd613fb7e5bec586 Merge: 4fe6328b 12ee287d Author: Dimitry Kolyshev Date: Tue Apr 19 15:03:13 2022 +0200 Merge remote-tracking branch 'origin/master' into 4416-ui-tracker-href commit 4fe6328b276e697a2aa351c6543d2efe6d2dc2e1 Author: Dimitry Kolyshev Date: Tue Apr 19 14:08:10 2022 +0200 whotracksme tracker links --- client/src/helpers/trackers/trackers.js | 19 ++++++++++++++++++- .../src/helpers/trackers/whotracksme_web.json | 6 ++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 client/src/helpers/trackers/whotracksme_web.json diff --git a/client/src/helpers/trackers/trackers.js b/client/src/helpers/trackers/trackers.js index 7af6dcb4..5327d18e 100644 --- a/client/src/helpers/trackers/trackers.js +++ b/client/src/helpers/trackers/trackers.js @@ -1,4 +1,5 @@ import whotracksmeDb from './whotracksme.json'; +import whotracksmeWebsites from './whotracksme_web.json'; import adguardDb from './adguard.json'; import { REPOSITORY } from '../constants'; @@ -20,6 +21,22 @@ export const sources = { ADGUARD: 2, }; +/** + * Gets link to tracker page on whotracks.me. + * + * @param trackerId + * @return {string} + */ +const getWhotracksmeUrl = (trackerId) => { + const websiteId = whotracksmeWebsites.websites[trackerId]; + if (websiteId) { + // Overrides links to websites. + return `https://whotracks.me/websites/${websiteId}.html`; + } + + return `https://whotracks.me/trackers/${trackerId}.html`; +}; + /** * Gets the source metadata for the specified tracker * @param {TrackerData} trackerData tracker data @@ -33,7 +50,7 @@ export const getSourceData = (trackerData) => { if (trackerData.source === sources.WHOTRACKSME) { return { name: 'Whotracks.me', - url: `https://whotracks.me/trackers/${trackerData.id}.html`, + url: getWhotracksmeUrl(trackerData.id), }; } if (trackerData.source === sources.ADGUARD) { diff --git a/client/src/helpers/trackers/whotracksme_web.json b/client/src/helpers/trackers/whotracksme_web.json new file mode 100644 index 00000000..8123fe1b --- /dev/null +++ b/client/src/helpers/trackers/whotracksme_web.json @@ -0,0 +1,6 @@ +{ + "timeUpdated": "2021-12-19T13:50:00.512Z", + "websites": { + "netflix": "netflix.com" + } +} From 9b7fe740862c590f3311ad427672a0b06c6b4ff6 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Mon, 25 Apr 2022 13:59:34 +0300 Subject: [PATCH 029/110] Pull request: all: do not mark help-wanted issues as stale Merge in DNS/adguard-home from help-wanted-stale to master Squashed commit of the following: commit 1c5ffcdd0153dd7d9d9bcc1e35dee4a0b3113f59 Author: Ainar Garipov Date: Fri Apr 22 20:04:01 2022 +0300 all: do not mark help-wanted issues as stale --- .github/stale.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/stale.yml b/.github/stale.yml index d242832f..6ed9a7df 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -8,6 +8,7 @@ - 'documentation' - 'enhancement' - 'feature request' +- 'help wanted' - 'localization' - 'needs investigation' - 'recurrent' From 9d144ecb0a4433e594365ea89c73881da561938d Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Mon, 25 Apr 2022 17:09:49 +0300 Subject: [PATCH 030/110] Pull request: client: imp rdns desc Squashed commit of the following: commit 5631f5f7155d7e5ad58dc5088cc3c93cb40a94a4 Author: Eugene Burkov Date: Mon Apr 25 17:03:13 2022 +0300 client: imp rdns desc --- client/src/__locales/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index 706ddf55..f39d2f51 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -9,7 +9,7 @@ "bootstrap_dns": "Bootstrap DNS servers", "bootstrap_dns_desc": "Bootstrap DNS servers are used to resolve IP addresses of the DoH/DoT resolvers you specify as upstreams.", "local_ptr_title": "Private reverse DNS servers", - "local_ptr_desc": "The DNS servers that AdGuard Home uses for local PTR queries. These servers are used to resolve the hostnames of clients with private IP addresses, for example \"192.168.12.34\", using reverse DNS. If not set, AdGuard Home uses the addresses of the default DNS resolvers of your OS except for the addresses of AdGuard Home itself.", + "local_ptr_desc": "The DNS servers that AdGuard Home uses for local PTR queries. These servers are used to resolve PTR requests for addresses in private IP ranges, for example \"192.168.12.34\", using reverse DNS. If not set, AdGuard Home uses the addresses of the default DNS resolvers of your OS except for the addresses of AdGuard Home itself.", "local_ptr_default_resolver": "By default, AdGuard Home uses the following reverse DNS resolvers: {{ip}}.", "local_ptr_no_default_resolver": "AdGuard Home could not determine suitable private reverse DNS resolvers for this system.", "local_ptr_placeholder": "Enter one server address per line", From 2a1ad532f454ed2ab25d19eaf168ba9f6d534f2f Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Mon, 25 Apr 2022 18:41:39 +0300 Subject: [PATCH 031/110] Pull request: home: rm unnecessary locking in update; refactor Merge in DNS/adguard-home from 4499-rm-unnecessary-locking to master Squashed commit of the following: commit 6d70472506dd0fd69225454c73d9f7f6a208b76b Author: Ainar Garipov Date: Mon Apr 25 17:26:54 2022 +0300 home: rm unnecessary locking in update; refactor --- CHANGELOG.md | 2 + .../aghnet/{net_nolinux.go => net_bsd.go} | 4 +- internal/aghnet/net_windows.go | 8 +- internal/home/controlupdate.go | 122 ++++++++++-------- internal/updater/check.go | 2 +- scripts/make/go-lint.sh | 1 - 6 files changed, 79 insertions(+), 60 deletions(-) rename internal/aghnet/{net_nolinux.go => net_bsd.go} (69%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d82fb57..b43f0524 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -89,6 +89,7 @@ In this release, the schema version has changed from 12 to 13. ### Fixed +- Slow version update queries making other HTTP APIs unresponsible ([#4499]). - ARP tables refreshing process causing excessive PTR requests ([#3157]). [#1730]: https://github.com/AdguardTeam/AdGuardHome/issues/1730 @@ -106,6 +107,7 @@ In this release, the schema version has changed from 12 to 13. [#4221]: https://github.com/AdguardTeam/AdGuardHome/issues/4221 [#4238]: https://github.com/AdguardTeam/AdGuardHome/issues/4238 [#4276]: https://github.com/AdguardTeam/AdGuardHome/issues/4276 +[#4499]: https://github.com/AdguardTeam/AdGuardHome/issues/4499 [repr]: https://reproducible-builds.org/docs/source-date-epoch/ [doq-draft-10]: https://datatracker.ietf.org/doc/html/draft-ietf-dprive-dnsoquic-10#section-10.2 diff --git a/internal/aghnet/net_nolinux.go b/internal/aghnet/net_bsd.go similarity index 69% rename from internal/aghnet/net_nolinux.go rename to internal/aghnet/net_bsd.go index f429c6fa..bd705e92 100644 --- a/internal/aghnet/net_nolinux.go +++ b/internal/aghnet/net_bsd.go @@ -1,5 +1,5 @@ -//go:build !linux -// +build !linux +//go:build darwin || freebsd || openbsd +// +build darwin freebsd openbsd package aghnet diff --git a/internal/aghnet/net_windows.go b/internal/aghnet/net_windows.go index 0cea8fe7..17499cce 100644 --- a/internal/aghnet/net_windows.go +++ b/internal/aghnet/net_windows.go @@ -1,5 +1,5 @@ -//go:build !(linux || darwin || freebsd || openbsd) -// +build !linux,!darwin,!freebsd,!openbsd +//go:build windows +// +build windows package aghnet @@ -13,6 +13,10 @@ import ( "golang.org/x/sys/windows" ) +func canBindPrivilegedPorts() (can bool, err error) { + return true, nil +} + func ifaceHasStaticIP(string) (ok bool, err error) { return false, aghos.Unsupported("checking static ip") } diff --git a/internal/home/controlupdate.go b/internal/home/controlupdate.go index 79b9f37e..ae469598 100644 --- a/internal/home/controlupdate.go +++ b/internal/home/controlupdate.go @@ -3,6 +3,7 @@ package home import ( "context" "encoding/json" + "fmt" "net/http" "os" "os/exec" @@ -27,12 +28,16 @@ type temporaryError interface { // Get the latest available version from the Internet func handleGetVersionJSON(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + resp := &versionResponse{} if Context.disableUpdate { - // w.Header().Set("Content-Type", "application/json") resp.Disabled = true - _ = json.NewEncoder(w).Encode(resp) - // TODO(e.burkov): Add error handling and deal with headers. + err := json.NewEncoder(w).Encode(resp) + if err != nil { + aghhttp.Error(r, w, http.StatusInternalServerError, "writing body: %s", err) + } + return } @@ -44,30 +49,48 @@ func handleGetVersionJSON(w http.ResponseWriter, r *http.Request) { if r.ContentLength != 0 { err = json.NewDecoder(r.Body).Decode(req) if err != nil { - aghhttp.Error(r, w, http.StatusBadRequest, "JSON parse: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "parsing request: %s", err) return } } + err = requestVersionInfo(resp, req.Recheck) + if err != nil { + // Don't wrap the error, because it's informative enough as is. + aghhttp.Error(r, w, http.StatusBadGateway, "%s", err) + + return + } + + err = resp.setAllowedToAutoUpdate() + if err != nil { + // Don't wrap the error, because it's informative enough as is. + aghhttp.Error(r, w, http.StatusInternalServerError, "%s", err) + + return + } + + err = json.NewEncoder(w).Encode(resp) + if err != nil { + aghhttp.Error(r, w, http.StatusInternalServerError, "writing body: %s", err) + } +} + +// requestVersionInfo sets the VersionInfo field of resp if it can reach the +// update server. +func requestVersionInfo(resp *versionResponse, recheck bool) (err error) { for i := 0; i != 3; i++ { - func() { - Context.controlLock.Lock() - defer Context.controlLock.Unlock() - - resp.VersionInfo, err = Context.updater.VersionInfo(req.Recheck) - }() - + resp.VersionInfo, err = Context.updater.VersionInfo(recheck) if err != nil { var terr temporaryError if errors.As(err, &terr) && terr.Temporary() { - // Temporary network error. This case may happen while - // we're restarting our DNS server. Log and sleep for - // some time. + // Temporary network error. This case may happen while we're + // restarting our DNS server. Log and sleep for some time. // // See https://github.com/AdguardTeam/AdGuardHome/issues/934. d := time.Duration(i) * time.Second - log.Info("temp net error: %q; sleeping for %s and retrying", err, d) + log.Info("update: temp net error: %q; sleeping for %s and retrying", err, d) time.Sleep(d) continue @@ -76,29 +99,14 @@ func handleGetVersionJSON(w http.ResponseWriter, r *http.Request) { break } + if err != nil { vcu := Context.updater.VersionCheckURL() - // TODO(a.garipov): Figure out the purpose of %T verb. - aghhttp.Error( - r, - w, - http.StatusBadGateway, - "Couldn't get version check json from %s: %T %s\n", - vcu, - err, - err, - ) - return + return fmt.Errorf("getting version info from %s: %s", vcu, err) } - resp.confirmAutoUpdate() - - w.Header().Set("Content-Type", "application/json") - err = json.NewEncoder(w).Encode(resp) - if err != nil { - aghhttp.Error(r, w, http.StatusInternalServerError, "Couldn't write body: %s", err) - } + return nil } // handleUpdate performs an update to the latest available version procedure. @@ -132,31 +140,37 @@ func handleUpdate(w http.ResponseWriter, r *http.Request) { // versionResponse is the response for /control/version.json endpoint. type versionResponse struct { - Disabled bool `json:"disabled"` updater.VersionInfo + Disabled bool `json:"disabled"` } -// confirmAutoUpdate checks the real possibility of auto update. -func (vr *versionResponse) confirmAutoUpdate() { - if vr.CanAutoUpdate != nil && *vr.CanAutoUpdate { - canUpdate := true - - var tlsConf *tlsConfigSettings - if runtime.GOOS != "windows" { - tlsConf = &tlsConfigSettings{} - Context.tls.WriteDiskConfig(tlsConf) - } - - if tlsConf != nil && - ((tlsConf.Enabled && (tlsConf.PortHTTPS < 1024 || - tlsConf.PortDNSOverTLS < 1024 || - tlsConf.PortDNSOverQUIC < 1024)) || - config.BindPort < 1024 || - config.DNS.Port < 1024) { - canUpdate, _ = aghnet.CanBindPrivilegedPorts() - } - vr.CanAutoUpdate = &canUpdate +// setAllowedToAutoUpdate sets CanAutoUpdate to true if AdGuard Home is actually +// allowed to perform an automatic update by the OS. +func (vr *versionResponse) setAllowedToAutoUpdate() (err error) { + if vr.CanAutoUpdate == nil || !*vr.CanAutoUpdate { + return } + + tlsConf := &tlsConfigSettings{} + Context.tls.WriteDiskConfig(tlsConf) + + canUpdate := true + if tlsConfUsesPrivilegedPorts(tlsConf) || config.BindPort < 1024 || config.DNS.Port < 1024 { + canUpdate, err = aghnet.CanBindPrivilegedPorts() + if err != nil { + return fmt.Errorf("checking ability to bind privileged ports: %w", err) + } + } + + vr.CanAutoUpdate = &canUpdate + + return nil +} + +// tlsConfUsesPrivilegedPorts returns true if the provided TLS configuration +// indicates that privileged ports are used. +func tlsConfUsesPrivilegedPorts(c *tlsConfigSettings) (ok bool) { + return c.Enabled && (c.PortHTTPS < 1024 || c.PortDNSOverTLS < 1024 || c.PortDNSOverQUIC < 1024) } // finishUpdate completes an update procedure. diff --git a/internal/updater/check.go b/internal/updater/check.go index edf046af..ec7176b2 100644 --- a/internal/updater/check.go +++ b/internal/updater/check.go @@ -17,11 +17,11 @@ const versionCheckPeriod = 8 * time.Hour // VersionInfo contains information about a new version. type VersionInfo struct { + CanAutoUpdate *bool `json:"can_autoupdate,omitempty"` NewVersion string `json:"new_version,omitempty"` Announcement string `json:"announcement,omitempty"` AnnouncementURL string `json:"announcement_url,omitempty"` SelfUpdateMinVersion string `json:"-"` - CanAutoUpdate *bool `json:"can_autoupdate,omitempty"` } // MaxResponseSize is responses on server's requests maximum length in bytes. diff --git a/scripts/make/go-lint.sh b/scripts/make/go-lint.sh index 32d99480..c363e513 100644 --- a/scripts/make/go-lint.sh +++ b/scripts/make/go-lint.sh @@ -136,7 +136,6 @@ underscores() { -e '_freebsd.go'\ -e '_linux.go'\ -e '_little.go'\ - -e '_nolinux.go'\ -e '_openbsd.go'\ -e '_others.go'\ -e '_test.go'\ From 0a1ff65b4a3155ce65661d051fb6e8600c265702 Mon Sep 17 00:00:00 2001 From: Ildar Kamalov Date: Mon, 25 Apr 2022 19:10:52 +0300 Subject: [PATCH 032/110] Pull request: client: fix constant loading for blocked requests Updates #4420 Squashed commit of the following: commit 461a59e1541626020bf0bcfaf34ba7d2f4509dc7 Merge: 5c5e7b5d 2a1ad532 Author: Ainar Garipov Date: Mon Apr 25 18:46:02 2022 +0300 Merge branch 'master' into 4420-loading-log commit 5c5e7b5d1a69d30e40e71f49f46dea89fa8c40a2 Author: Ildar Kamalov Date: Sun Apr 24 22:18:22 2022 +0300 client: fix constant loading for blocked requests --- client/src/components/Logs/InfiniteTable.js | 29 ++++++++++++++------- client/src/helpers/helpers.js | 4 +-- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/client/src/components/Logs/InfiniteTable.js b/client/src/components/Logs/InfiniteTable.js index d419ac3d..36f411c8 100644 --- a/client/src/components/Logs/InfiniteTable.js +++ b/client/src/components/Logs/InfiniteTable.js @@ -43,7 +43,7 @@ const InfiniteTable = ({ useEffect(() => { listener(); - }, [items.length < QUERY_LOGS_PAGE_LIMIT]); + }, [items.length < QUERY_LOGS_PAGE_LIMIT, isEntireLog]); useEffect(() => { const THROTTLE_TIME = 100; @@ -66,15 +66,24 @@ const InfiniteTable = ({ const isNothingFound = items.length === 0 && !processingGetLogs; - return
- {loading && } -
- {isNothingFound - ? - : <>{items.map(renderRow)} - {!isEntireLog &&
{t('loading_table_status')}
} - } -
; + return ( +
+ {loading && } +
+ {isNothingFound ? ( + + ) : ( + <> + {items.map(renderRow)} + {!isEntireLog && ( +
+ {t('loading_table_status')} +
+ )} + + )} +
+ ); }; InfiniteTable.propTypes = { diff --git a/client/src/helpers/helpers.js b/client/src/helpers/helpers.js index 5fb42c05..a7bf9485 100644 --- a/client/src/helpers/helpers.js +++ b/client/src/helpers/helpers.js @@ -693,8 +693,8 @@ export const replaceZeroWithEmptyString = (value) => (parseInt(value, 10) === 0 * @returns {string} */ export const getLogsUrlParams = (search, response_status) => `?${queryString.stringify({ - search, - response_status, + search: search || undefined, + response_status: response_status || undefined, })}`; export const processContent = ( From 235316e0508ee015bf4ce663d2b7929079541c59 Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Tue, 26 Apr 2022 13:04:16 +0300 Subject: [PATCH 033/110] Pull request: 3020 runtime clients sources control Merge in DNS/adguard-home from 3020-client-sources to master Closes #3020. Squashed commit of the following: commit f8e6b6d63373f99b52f7b8c32f4242c453daf1a4 Merge: 41fb071d 0a1ff65b Author: Ainar Garipov Date: Mon Apr 25 19:19:15 2022 +0300 Merge branch 'master' into 3020-client-sources commit 41fb071deb2a87e0a69d09c8f418a016b4dd7e93 Author: Eugene Burkov Date: Mon Apr 25 13:38:28 2022 +0300 home: fix nil, imp docs commit aaa7765914a8a4645eba357cd088a9470611ffdc Author: Eugene Burkov Date: Mon Apr 25 12:25:47 2022 +0300 home: imp code commit 3f71b999564c604583b46313d29f5b70cf51ee14 Author: Eugene Burkov Date: Fri Apr 22 19:12:27 2022 +0300 home: runtime clients sources control --- CHANGELOG.md | 36 ++++++++- internal/home/clients.go | 26 ++++-- internal/home/config.go | 28 ++++--- internal/home/dns.go | 17 ++-- internal/home/home.go | 15 ++-- internal/home/options.go | 12 ++- internal/home/upgrade.go | 69 +++++++++++++++- internal/home/upgrade_test.go | 145 ++++++++++++++++++++++++++-------- 8 files changed, 283 insertions(+), 65 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b43f0524..047726ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ and this project adheres to ### Added +- The ability to control each source of runtime clients separately via + `clients.runtime_sources` configuration object ([#3020]). - The ability to customize the set of networks that are considered private through the new `dns.private_networks` property in the configuration file ([#3142]). @@ -63,8 +65,36 @@ and this project adheres to #### Configuration Changes -In this release, the schema version has changed from 12 to 13. +In this release, the schema version has changed from 12 to 14. +- Object `clients`, which in schema versions 13 and earlier was an array of + actual persistent clients, is now consist of `persistent` and + `runtime_sources` properties: + + ```yaml + # BEFORE: + 'clients': + - name: client-name + # … + + # AFTER: + 'clients': + 'persistent': + - name: client-name + # … + 'runtime_sources': + whois: true + arp: true + rdns: true + dhcp: true + hosts: true + ``` + + The value for `clients.runtime_sources.rdns` field is taken from + `dns.resolve_clients` property. To rollback this change, remove the + `runtime_sources` property, move the contents of `persistent` into the + `clients` itself, the value of `clients.runtime_sources.rdns` into the + `dns.resolve_clietns`, and change the `schema_version` back to `13`. - Property `local_domain_name`, which in schema versions 12 and earlier used to be a part of the `dns` object, is now a part of the `dhcp` object: @@ -85,6 +115,9 @@ In this release, the schema version has changed from 12 to 13. ### Deprecated +- The `--no-etc-hosts` option. Its' functionality is now controlled by + `clients.runtime_sources.hosts` configuration property. v0.109.0 will remove + the flag completely. - Go 1.17 support. v0.109.0 will require at least Go 1.18 to build. ### Fixed @@ -94,6 +127,7 @@ In this release, the schema version has changed from 12 to 13. [#1730]: https://github.com/AdguardTeam/AdGuardHome/issues/1730 [#2993]: https://github.com/AdguardTeam/AdGuardHome/issues/2993 +[#3020]: https://github.com/AdguardTeam/AdGuardHome/issues/3020 [#3057]: https://github.com/AdguardTeam/AdGuardHome/issues/3057 [#3142]: https://github.com/AdguardTeam/AdGuardHome/issues/3142 [#3157]: https://github.com/AdguardTeam/AdGuardHome/issues/3157 diff --git a/internal/home/clients.go b/internal/home/clients.go index fe15e514..d4d6b959 100644 --- a/internal/home/clients.go +++ b/internal/home/clients.go @@ -59,6 +59,16 @@ const ( ClientSourceHostsFile ) +// clientSourceConf is used to configure where the runtime clients will be +// obtained from. +type clientSourcesConf struct { + WHOIS bool `yaml:"whois"` + ARP bool `yaml:"arp"` + RDNS bool `yaml:"rdns"` + DHCP bool `yaml:"dhcp"` + HostsFile bool `yaml:"hosts"` +} + // RuntimeClient information type RuntimeClient struct { WHOISInfo *RuntimeClientWHOISInfo @@ -134,14 +144,14 @@ func (clients *clientsContainer) Init( clients.dhcpServer.SetOnLeaseChanged(clients.onDHCPLeaseChanged) } - go clients.handleHostsUpdates() + if clients.etcHosts != nil { + go clients.handleHostsUpdates() + } } func (clients *clientsContainer) handleHostsUpdates() { - if clients.etcHosts != nil { - for upd := range clients.etcHosts.Upd() { - clients.addFromHostsFile(upd) - } + for upd := range clients.etcHosts.Upd() { + clients.addFromHostsFile(upd) } } @@ -158,7 +168,9 @@ func (clients *clientsContainer) Start() { // Reload reloads runtime clients. func (clients *clientsContainer) Reload() { - clients.addFromSystemARP() + if clients.arpdb != nil { + clients.addFromSystemARP() + } } type clientObject struct { @@ -843,7 +855,7 @@ func (clients *clientsContainer) addFromSystemARP() { // updateFromDHCP adds the clients that have a non-empty hostname from the DHCP // server. func (clients *clientsContainer) updateFromDHCP(add bool) { - if clients.dhcpServer == nil { + if clients.dhcpServer == nil || !config.Clients.Sources.DHCP { return } diff --git a/internal/home/config.go b/internal/home/config.go index aa8450be..720683a1 100644 --- a/internal/home/config.go +++ b/internal/home/config.go @@ -51,6 +51,13 @@ type osConfig struct { RlimitNoFile uint64 `yaml:"rlimit_nofile"` } +type clientsConfig struct { + // Sources defines the set of sources to fetch the runtime clients from. + Sources *clientSourcesConf `yaml:"runtime_sources"` + // Persistent are the configured clients. + Persistent []*clientObject `yaml:"persistent"` +} + // configuration is loaded from YAML // field ordering is important -- yaml fields will mirror ordering from here type configuration struct { @@ -88,7 +95,7 @@ type configuration struct { // Clients contains the YAML representations of the persistent clients. // This field is only used for reading and writing persistent client data. // Keep this field sorted to ensure consistent ordering. - Clients []*clientObject `yaml:"clients"` + Clients *clientsConfig `yaml:"clients"` logSettings `yaml:",inline"` @@ -123,9 +130,6 @@ type dnsConfig struct { // UpstreamTimeout is the timeout for querying upstream servers. UpstreamTimeout timeutil.Duration `yaml:"upstream_timeout"` - // ResolveClients enables and disables resolving clients with RDNS. - ResolveClients bool `yaml:"resolve_clients"` - // PrivateNets is the set of IP networks for which the private reverse DNS // resolver should be used. PrivateNets []string `yaml:"private_networks"` @@ -198,7 +202,6 @@ var config = &configuration{ FilteringEnabled: true, // whether or not use filter lists FiltersUpdateIntervalHours: 24, UpstreamTimeout: timeutil.Duration{Duration: dnsforward.DefaultTimeout}, - ResolveClients: true, UsePrivateRDNS: true, }, TLS: tlsConfigSettings{ @@ -209,6 +212,15 @@ var config = &configuration{ DHCP: &dhcpd.ServerConfig{ LocalDomainName: "lan", }, + Clients: &clientsConfig{ + Sources: &clientSourcesConf{ + WHOIS: true, + ARP: true, + RDNS: true, + DHCP: true, + HostsFile: true, + }, + }, logSettings: logSettings{ LogCompress: false, LogLocalTime: false, @@ -404,9 +416,7 @@ func (c *configuration) write() error { s.WriteDiskConfig(&c) dns := &config.DNS dns.FilteringConfig = c - dns.LocalPTRResolvers, - dns.ResolveClients, - dns.UsePrivateRDNS = s.RDNSSettings() + dns.LocalPTRResolvers, config.Clients.Sources.RDNS, dns.UsePrivateRDNS = s.RDNSSettings() } if Context.dhcpServer != nil { @@ -415,7 +425,7 @@ func (c *configuration) write() error { config.DHCP = c } - config.Clients = Context.clients.forConfig() + config.Clients.Persistent = Context.clients.forConfig() configFile := config.getConfigFilename() log.Debug("Writing YAML file: %s", configFile) diff --git a/internal/home/dns.go b/internal/home/dns.go index c30e12ec..e0fc1aab 100644 --- a/internal/home/dns.go +++ b/internal/home/dns.go @@ -136,7 +136,10 @@ func initDNSServer() (err error) { } Context.rdns = NewRDNS(Context.dnsServer, &Context.clients, config.DNS.UsePrivateRDNS) - Context.whois = initWHOIS(&Context.clients) + + if !config.Clients.Sources.WHOIS { + Context.whois = initWHOIS(&Context.clients) + } Context.filters.Init() return nil @@ -153,10 +156,11 @@ func onDNSRequest(pctx *proxy.DNSContext) { return } - if config.DNS.ResolveClients && !ip.IsLoopback() { + srcs := config.Clients.Sources + if srcs.RDNS && !ip.IsLoopback() { Context.rdns.Begin(ip) } - if !netutil.IsSpecialPurpose(ip) { + if srcs.WHOIS && !netutil.IsSpecialPurpose(ip) { Context.whois.Begin(ip) } } @@ -239,7 +243,7 @@ func generateServerConfig() (newConf dnsforward.ServerConfig, err error) { newConf.FilterHandler = applyAdditionalFiltering newConf.GetCustomUpstreamByClient = Context.clients.findUpstreams - newConf.ResolveClients = dnsConf.ResolveClients + newConf.ResolveClients = config.Clients.Sources.RDNS newConf.UsePrivateRDNS = dnsConf.UsePrivateRDNS newConf.LocalPTRResolvers = dnsConf.LocalPTRResolvers newConf.UpstreamTimeout = dnsConf.UpstreamTimeout.Duration @@ -387,10 +391,11 @@ func startDNSServer() error { continue } - if config.DNS.ResolveClients && !ip.IsLoopback() { + srcs := config.Clients.Sources + if srcs.RDNS && !ip.IsLoopback() { Context.rdns.Begin(ip) } - if !netutil.IsSpecialPurpose(ip) { + if srcs.WHOIS && !netutil.IsSpecialPurpose(ip) { Context.whois.Begin(ip) } } diff --git a/internal/home/home.go b/internal/home/home.go index 420e67d8..539552d1 100644 --- a/internal/home/home.go +++ b/internal/home/home.go @@ -173,6 +173,11 @@ func setupContext(args options) { os.Exit(0) } + + if !args.noEtcHosts && config.Clients.Sources.HostsFile { + err = setupHostsContainer() + fatalOnError(err) + } } Context.mux = http.NewServeMux() @@ -285,14 +290,12 @@ func setupConfig(args options) (err error) { ConfName: config.getConfigFilename(), }) - if !args.noEtcHosts { - if err = setupHostsContainer(); err != nil { - return err - } + var arpdb aghnet.ARPDB + if config.Clients.Sources.ARP { + arpdb = aghnet.NewARPDB() } - arpdb := aghnet.NewARPDB() - Context.clients.Init(config.Clients, Context.dhcpServer, Context.etcHosts, arpdb) + Context.clients.Init(config.Clients.Persistent, Context.dhcpServer, Context.etcHosts, arpdb) if args.bindPort != 0 { uc := aghalg.UniqChecker{} diff --git a/internal/home/options.go b/internal/home/options.go index dc11ca35..6f5a4d8d 100644 --- a/internal/home/options.go +++ b/internal/home/options.go @@ -230,13 +230,19 @@ var helpArg = arg{ } var noEtcHostsArg = arg{ - description: "Do not use the OS-provided hosts.", + description: "Deprecated. Do not use the OS-provided hosts.", longName: "no-etc-hosts", shortName: "", updateWithValue: nil, updateNoValue: func(o options) (options, error) { o.noEtcHosts = true; return o, nil }, - effect: nil, - serialize: func(o options) []string { return boolSliceOrNil(o.noEtcHosts) }, + effect: func(_ options, _ string) (f effect, err error) { + log.Info( + "warning: --no-etc-hosts flag is deprecated and will be removed in the future versions", + ) + + return nil, nil + }, + serialize: func(o options) []string { return boolSliceOrNil(o.noEtcHosts) }, } var localFrontendArg = arg{ diff --git a/internal/home/upgrade.go b/internal/home/upgrade.go index 34297470..d9611dc9 100644 --- a/internal/home/upgrade.go +++ b/internal/home/upgrade.go @@ -21,9 +21,11 @@ import ( ) // currentSchemaVersion is the current schema version. -const currentSchemaVersion = 13 +const currentSchemaVersion = 14 // These aliases are provided for convenience. +// +// TODO(e.burkov): Remove any after updating to Go 1.18. type ( any = interface{} yarr = []any @@ -86,6 +88,7 @@ func upgradeConfigSchema(oldVersion int, diskConf yobj) (err error) { upgradeSchema10to11, upgradeSchema11to12, upgradeSchema12to13, + upgradeSchema13to14, } n := 0 @@ -726,7 +729,7 @@ func upgradeSchema12to13(diskConf yobj) (err error) { var dhcp yobj dhcp, ok = dhcpVal.(yobj) if !ok { - return fmt.Errorf("unexpected type of dhcp: %T", dnsVal) + return fmt.Errorf("unexpected type of dhcp: %T", dhcpVal) } const field = "local_domain_name" @@ -737,6 +740,68 @@ func upgradeSchema12to13(diskConf yobj) (err error) { return nil } +// upgradeSchema13to14 performs the following changes: +// +// # BEFORE: +// 'clients': +// - 'name': 'client-name' +// # … +// +// # AFTER: +// 'clients': +// 'persistent': +// - 'name': 'client-name' +// # … +// 'runtime_sources': +// 'whois': true +// 'arp': true +// 'rdns': true +// 'dhcp': true +// 'hosts': true +// +func upgradeSchema13to14(diskConf yobj) (err error) { + log.Printf("Upgrade yaml: 13 to 14") + diskConf["schema_version"] = 14 + + clientsVal, ok := diskConf["clients"] + if !ok { + clientsVal = yarr{} + } + + var rdnsSrc bool + if dnsVal, dok := diskConf["dns"]; dok { + var dnsSettings yobj + dnsSettings, ok = dnsVal.(yobj) + if !ok { + return fmt.Errorf("unexpected type of dns: %T", dnsVal) + } + + var rdnsSrcVal any + rdnsSrcVal, ok = dnsSettings["resolve_clients"] + if ok { + rdnsSrc, ok = rdnsSrcVal.(bool) + if !ok { + return fmt.Errorf("unexpected type of resolve_clients: %T", rdnsSrcVal) + } + + delete(dnsSettings, "resolve_clients") + } + } + + diskConf["clients"] = yobj{ + "persistent": clientsVal, + "runtime_sources": &clientSourcesConf{ + WHOIS: true, + ARP: true, + RDNS: rdnsSrc, + DHCP: true, + HostsFile: true, + }, + } + + return nil +} + // TODO(a.garipov): Replace with log.Output when we port it to our logging // package. func funcName() string { diff --git a/internal/home/upgrade_test.go b/internal/home/upgrade_test.go index c63bc443..4c25cba3 100644 --- a/internal/home/upgrade_test.go +++ b/internal/home/upgrade_test.go @@ -513,46 +513,129 @@ func TestUpgradeSchema11to12(t *testing.T) { } func TestUpgradeSchema12to13(t *testing.T) { - t.Run("no_dns", func(t *testing.T) { - conf := yobj{} + const newSchemaVer = 13 - err := upgradeSchema12to13(conf) - require.NoError(t, err) - - assert.Equal(t, conf["schema_version"], 13) - }) - - t.Run("no_dhcp", func(t *testing.T) { - conf := yobj{ - "dns": yobj{}, - } - - err := upgradeSchema12to13(conf) - require.NoError(t, err) - - assert.Equal(t, conf["schema_version"], 13) - }) - - t.Run("good", func(t *testing.T) { - conf := yobj{ + testCases := []struct { + in yobj + want yobj + name string + }{{ + in: yobj{}, + want: yobj{"schema_version": newSchemaVer}, + name: "no_dns", + }, { + in: yobj{"dns": yobj{}}, + want: yobj{ + "dns": yobj{}, + "schema_version": newSchemaVer, + }, + name: "no_dhcp", + }, { + in: yobj{ "dns": yobj{ "local_domain_name": "lan", }, "dhcp": yobj{}, - "schema_version": 12, - } - - wantConf := yobj{ + "schema_version": newSchemaVer - 1, + }, + want: yobj{ "dns": yobj{}, "dhcp": yobj{ "local_domain_name": "lan", }, - "schema_version": 13, - } + "schema_version": newSchemaVer, + }, + name: "good", + }} - err := upgradeSchema12to13(conf) - require.NoError(t, err) + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := upgradeSchema12to13(tc.in) + require.NoError(t, err) - assert.Equal(t, wantConf, conf) - }) + assert.Equal(t, tc.want, tc.in) + }) + } +} + +func TestUpgradeSchema13to14(t *testing.T) { + const newSchemaVer = 14 + + testClient := &clientObject{ + Name: "agh-client", + IDs: []string{"id1"}, + UseGlobalSettings: true, + } + + testCases := []struct { + in yobj + want yobj + name string + }{{ + in: yobj{}, + want: yobj{ + "schema_version": newSchemaVer, + // The clients field will be added anyway. + "clients": yobj{ + "persistent": yarr{}, + "runtime_sources": &clientSourcesConf{ + WHOIS: true, + ARP: true, + RDNS: false, + DHCP: true, + HostsFile: true, + }, + }, + }, + name: "no_clients", + }, { + in: yobj{ + "clients": []*clientObject{testClient}, + }, + want: yobj{ + "schema_version": newSchemaVer, + "clients": yobj{ + "persistent": []*clientObject{testClient}, + "runtime_sources": &clientSourcesConf{ + WHOIS: true, + ARP: true, + RDNS: false, + DHCP: true, + HostsFile: true, + }, + }, + }, + name: "no_dns", + }, { + in: yobj{ + "clients": []*clientObject{testClient}, + "dns": yobj{ + "resolve_clients": true, + }, + }, + want: yobj{ + "schema_version": newSchemaVer, + "clients": yobj{ + "persistent": []*clientObject{testClient}, + "runtime_sources": &clientSourcesConf{ + WHOIS: true, + ARP: true, + RDNS: true, + DHCP: true, + HostsFile: true, + }, + }, + "dns": yobj{}, + }, + name: "good", + }} + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := upgradeSchema13to14(tc.in) + require.NoError(t, err) + + assert.Equal(t, tc.want, tc.in) + }) + } } From 1c89394aef6abb1e4810c84db01d44cec770dee7 Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Tue, 26 Apr 2022 15:21:45 +0300 Subject: [PATCH 034/110] Pull request: 4525 fix panic Merge in DNS/adguard-home from 3020-fix-panic to master Closes #4525. Squashed commit of the following: commit f8d9e25eccb485269aa2f0275d4e08da767f9d05 Author: Eugene Burkov Date: Tue Apr 26 15:09:11 2022 +0300 home: imp code commit 8fe02c8f057c05b9e8ce1de056a92e7cd69ae4c6 Author: Eugene Burkov Date: Tue Apr 26 14:44:33 2022 +0300 home: fix panic --- internal/home/dns.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/internal/home/dns.go b/internal/home/dns.go index e0fc1aab..e28193ee 100644 --- a/internal/home/dns.go +++ b/internal/home/dns.go @@ -135,9 +135,11 @@ func initDNSServer() (err error) { return fmt.Errorf("dnsServer.Prepare: %w", err) } - Context.rdns = NewRDNS(Context.dnsServer, &Context.clients, config.DNS.UsePrivateRDNS) + if config.Clients.Sources.RDNS { + Context.rdns = NewRDNS(Context.dnsServer, &Context.clients, config.DNS.UsePrivateRDNS) + } - if !config.Clients.Sources.WHOIS { + if config.Clients.Sources.WHOIS { Context.whois = initWHOIS(&Context.clients) } From ed449c618628c5e3ee76072cb010ece32eea565e Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Tue, 26 Apr 2022 20:50:09 +0300 Subject: [PATCH 035/110] Pull request: all: add stub binary for new api Merge in DNS/adguard-home from new-api to master Squashed commit of the following: commit 83f4418c253b9abc5131d9e2acc2a4a96e4122c4 Author: Ainar Garipov Date: Tue Apr 26 19:09:34 2022 +0300 all: fix build commit 1fbb53fdf779bde79fab72f9c8eb929e08bb044c Merge: 73a55197 1c89394a Author: Ainar Garipov Date: Tue Apr 26 18:37:27 2022 +0300 Merge branch 'master' into new-api commit 73a5519723f662979bdeb5192bc15835e7f03512 Author: Ainar Garipov Date: Tue Apr 26 18:36:50 2022 +0300 v1: imp names, docs commit d3fbc2f2082612b8ba438c8216c6c74421cc2df5 Author: Ainar Garipov Date: Fri Apr 22 17:55:42 2022 +0300 cmd: imp docs commit c2a73aa364a848e8066d1132d4b53bbc3e22db2d Author: Ainar Garipov Date: Fri Apr 22 16:19:14 2022 +0300 all: add stub binary for new api --- Makefile | 3 + internal/aghos/os.go | 10 + internal/aghos/os_unix.go | 27 + internal/aghos/os_windows.go | 21 + internal/v1/agh/agh.go | 33 + internal/v1/cmd/cmd.go | 69 + internal/v1/cmd/signal.go | 70 + internal/v1/websvc/websvc.go | 185 ++ internal/v1/websvc/websvc_test.go | 69 + main.go | 3 + main_v1.go | 21 + openapi/v1.yaml | 4913 +++++++++++++++++++++++++++++ scripts/make/go-build.sh | 12 +- scripts/make/go-lint.sh | 3 +- 14 files changed, 5437 insertions(+), 2 deletions(-) create mode 100644 internal/aghos/os_unix.go create mode 100644 internal/v1/agh/agh.go create mode 100644 internal/v1/cmd/cmd.go create mode 100644 internal/v1/cmd/signal.go create mode 100644 internal/v1/websvc/websvc.go create mode 100644 internal/v1/websvc/websvc_test.go create mode 100644 main_v1.go create mode 100644 openapi/v1.yaml diff --git a/Makefile b/Makefile index 5d9e7a7c..7c8f205f 100644 --- a/Makefile +++ b/Makefile @@ -34,6 +34,8 @@ YARN_INSTALL_FLAGS = $(YARN_FLAGS) --network-timeout 120000 --silent\ --ignore-engines --ignore-optional --ignore-platform\ --ignore-scripts +V1API = 0 + # Macros for the build-release target. If FRONTEND_PREBUILT is 0, the # default, the macro $(BUILD_RELEASE_DEPS_$(FRONTEND_PREBUILT)) expands # into BUILD_RELEASE_DEPS_0, and so both frontend and backend @@ -61,6 +63,7 @@ ENV = env\ PATH="$${PWD}/bin:$$( "$(GO.MACRO)" env GOPATH )/bin:$${PATH}"\ RACE='$(RACE)'\ SIGN='$(SIGN)'\ + V1API='$(V1API)'\ VERBOSE='$(VERBOSE)'\ VERSION='$(VERSION)'\ diff --git a/internal/aghos/os.go b/internal/aghos/os.go index 018a3e89..3b688749 100644 --- a/internal/aghos/os.go +++ b/internal/aghos/os.go @@ -175,3 +175,13 @@ func RootDirFS() (fsys fs.FS) { // behavior is undocumented but it currently works. return os.DirFS("") } + +// NotifyShutdownSignal notifies c on receiving shutdown signals. +func NotifyShutdownSignal(c chan<- os.Signal) { + notifyShutdownSignal(c) +} + +// IsShutdownSignal returns true if sig is a shutdown signal. +func IsShutdownSignal(sig os.Signal) (ok bool) { + return isShutdownSignal(sig) +} diff --git a/internal/aghos/os_unix.go b/internal/aghos/os_unix.go new file mode 100644 index 00000000..9a3cc308 --- /dev/null +++ b/internal/aghos/os_unix.go @@ -0,0 +1,27 @@ +//go:build darwin || freebsd || linux || openbsd +// +build darwin freebsd linux openbsd + +package aghos + +import ( + "os" + "os/signal" + + "golang.org/x/sys/unix" +) + +func notifyShutdownSignal(c chan<- os.Signal) { + signal.Notify(c, unix.SIGINT, unix.SIGQUIT, unix.SIGTERM) +} + +func isShutdownSignal(sig os.Signal) (ok bool) { + switch sig { + case + unix.SIGINT, + unix.SIGQUIT, + unix.SIGTERM: + return true + default: + return false + } +} diff --git a/internal/aghos/os_windows.go b/internal/aghos/os_windows.go index bff5a3f0..31fca3ef 100644 --- a/internal/aghos/os_windows.go +++ b/internal/aghos/os_windows.go @@ -4,6 +4,10 @@ package aghos import ( + "os" + "os/signal" + "syscall" + "golang.org/x/sys/windows" ) @@ -35,3 +39,20 @@ func haveAdminRights() (bool, error) { func isOpenWrt() (ok bool) { return false } + +func notifyShutdownSignal(c chan<- os.Signal) { + // syscall.SIGTERM is processed automatically. See go doc os/signal, + // section Windows. + signal.Notify(c, os.Interrupt) +} + +func isShutdownSignal(sig os.Signal) (ok bool) { + switch sig { + case + os.Interrupt, + syscall.SIGTERM: + return true + default: + return false + } +} diff --git a/internal/v1/agh/agh.go b/internal/v1/agh/agh.go new file mode 100644 index 00000000..212da4d6 --- /dev/null +++ b/internal/v1/agh/agh.go @@ -0,0 +1,33 @@ +// Package agh contains common entities and interfaces of AdGuard Home. +// +// TODO(a.garipov): Move to the upper-level internal/. +package agh + +import "context" + +// Service is the interface for API servers. +// +// TODO(a.garipov): Consider adding a context to Start. +// +// TODO(a.garipov): Consider adding a Wait method or making an extension +// interface for that. +type Service interface { + // Start starts the service. It does not block. + Start() (err error) + + // Shutdown gracefully stops the service. ctx is used to determine + // a timeout before trying to stop the service less gracefully. + Shutdown(ctx context.Context) (err error) +} + +// type check +var _ Service = EmptyService{} + +// EmptyService is a Service that does nothing. +type EmptyService struct{} + +// Start implements the Service interface for EmptyService. +func (EmptyService) Start() (err error) { return nil } + +// Shutdown implements the Service interface for EmptyService. +func (EmptyService) Shutdown(_ context.Context) (err error) { return nil } diff --git a/internal/v1/cmd/cmd.go b/internal/v1/cmd/cmd.go new file mode 100644 index 00000000..4c4e252f --- /dev/null +++ b/internal/v1/cmd/cmd.go @@ -0,0 +1,69 @@ +// Package cmd is the AdGuard Home entry point. It contains the on-disk +// configuration file utilities, signal processing logic, and so on. +// +// TODO(a.garipov): Move to the upper-level internal/. +package cmd + +import ( + "context" + "io/fs" + "math/rand" + "net" + "time" + + "github.com/AdguardTeam/AdGuardHome/internal/v1/websvc" + "github.com/AdguardTeam/golibs/log" + "github.com/AdguardTeam/golibs/netutil" +) + +// Main is the entry point of application. +func Main(clientBuildFS fs.FS) { + // # Initial Configuration + + rand.Seed(time.Now().UnixNano()) + + // TODO(a.garipov): Set up logging. + + // # Web Service + + // TODO(a.garipov): Use in the Web service. + _ = clientBuildFS + + // TODO(a.garipov): Make configurable. + web := websvc.New(&websvc.Config{ + Addresses: []*netutil.IPPort{{ + IP: net.IP{127, 0, 0, 1}, + Port: 3001, + }}, + Timeout: 60 * time.Second, + }) + + err := web.Start() + fatalOnError(err) + + sigHdlr := newSignalHandler( + web, + ) + + go sigHdlr.handle() + + select {} +} + +// defaultTimeout is the timeout used for some operations where another timeout +// hasn't been defined yet. +const defaultTimeout = 15 * time.Second + +// ctxWithDefaultTimeout is a helper function that returns a context with +// timeout set to defaultTimeout. +func ctxWithDefaultTimeout() (ctx context.Context, cancel context.CancelFunc) { + return context.WithTimeout(context.Background(), defaultTimeout) +} + +// fatalOnError is a helper that exits the program with an error code if err is +// not nil. It must only be used within Main. +func fatalOnError(err error) { + if err != nil { + log.Fatal(err) + } +} diff --git a/internal/v1/cmd/signal.go b/internal/v1/cmd/signal.go new file mode 100644 index 00000000..b9f09673 --- /dev/null +++ b/internal/v1/cmd/signal.go @@ -0,0 +1,70 @@ +package cmd + +import ( + "os" + + "github.com/AdguardTeam/AdGuardHome/internal/aghos" + "github.com/AdguardTeam/AdGuardHome/internal/v1/agh" + "github.com/AdguardTeam/golibs/log" +) + +// signalHandler processes incoming signals and shuts services down. +type signalHandler struct { + signal chan os.Signal + + // services are the services that are shut down before application + // exiting. + services []agh.Service +} + +// handle processes OS signals. +func (h *signalHandler) handle() { + defer log.OnPanic("signalProcessor.handle") + + for sig := range h.signal { + log.Info("sigproc: received signal %q", sig) + + if aghos.IsShutdownSignal(sig) { + h.shutdown() + } + } +} + +// Exit status constants. +const ( + statusSuccess = 0 + statusError = 1 +) + +// shutdown gracefully shuts down all services. +func (h *signalHandler) shutdown() { + ctx, cancel := ctxWithDefaultTimeout() + defer cancel() + + status := statusSuccess + + log.Info("sigproc: shutting down services") + for i, service := range h.services { + err := service.Shutdown(ctx) + if err != nil { + log.Error("sigproc: shutting down service at index %d: %s", i, err) + status = statusError + } + } + + log.Info("sigproc: shutting down adguard home") + + os.Exit(status) +} + +// newSignalHandler returns a new signalHandler that shuts down svcs. +func newSignalHandler(svcs ...agh.Service) (h *signalHandler) { + h = &signalHandler{ + signal: make(chan os.Signal, 1), + services: svcs, + } + + aghos.NotifyShutdownSignal(h.signal) + + return h +} diff --git a/internal/v1/websvc/websvc.go b/internal/v1/websvc/websvc.go new file mode 100644 index 00000000..e741ff3d --- /dev/null +++ b/internal/v1/websvc/websvc.go @@ -0,0 +1,185 @@ +// Package websvc contains the AdGuard Home web service. +// +// TODO(a.garipov): Add tests. +package websvc + +import ( + "context" + "crypto/tls" + "fmt" + "io" + "net" + "net/http" + "sync" + "time" + + "github.com/AdguardTeam/AdGuardHome/internal/v1/agh" + "github.com/AdguardTeam/golibs/errors" + "github.com/AdguardTeam/golibs/log" + "github.com/AdguardTeam/golibs/netutil" +) + +// Config is the AdGuard Home web service configuration structure. +type Config struct { + // TLS is the optional TLS configuration. If TLS is not nil, + // SecureAddresses must not be empty. + TLS *tls.Config + + // Addresses are the addresses on which to serve the plain HTTP API. + Addresses []*netutil.IPPort + + // SecureAddresses are the addresses on which to serve the HTTPS API. If + // SecureAddresses is not empty, TLS must not be nil. + SecureAddresses []*netutil.IPPort + + // Timeout is the timeout for all server operations. + Timeout time.Duration +} + +// Service is the AdGuard Home web service. A nil *Service is a valid service +// that does nothing. +type Service struct { + tls *tls.Config + servers []*http.Server + timeout time.Duration +} + +// New returns a new properly initialized *Service. If c is nil, svc is a nil +// *Service that does nothing. +func New(c *Config) (svc *Service) { + if c == nil { + return nil + } + + svc = &Service{ + tls: c.TLS, + timeout: c.Timeout, + } + + mux := http.NewServeMux() + mux.HandleFunc("/health-check", svc.handleGetHealthCheck) + + for _, a := range c.Addresses { + addr := a.String() + errLog := log.StdLog("websvc: http: "+addr, log.ERROR) + svc.servers = append(svc.servers, &http.Server{ + Addr: addr, + Handler: mux, + ErrorLog: errLog, + ReadTimeout: c.Timeout, + WriteTimeout: c.Timeout, + IdleTimeout: c.Timeout, + ReadHeaderTimeout: c.Timeout, + }) + } + + for _, a := range c.SecureAddresses { + addr := a.String() + errLog := log.StdLog("websvc: https: "+addr, log.ERROR) + svc.servers = append(svc.servers, &http.Server{ + Addr: addr, + Handler: mux, + TLSConfig: c.TLS, + ErrorLog: errLog, + ReadTimeout: c.Timeout, + WriteTimeout: c.Timeout, + IdleTimeout: c.Timeout, + ReadHeaderTimeout: c.Timeout, + }) + } + + return svc +} + +// Addrs returns all addresses on which this server serves the HTTP API. Addrs +// must not be called until Start returns. +func (svc *Service) Addrs() (addrs []string) { + addrs = make([]string, 0, len(svc.servers)) + for _, srv := range svc.servers { + addrs = append(addrs, srv.Addr) + } + + return addrs +} + +// handleGetHealthCheck is the handler for the GET /health-check HTTP API. +func (svc *Service) handleGetHealthCheck(w http.ResponseWriter, _ *http.Request) { + _, _ = io.WriteString(w, "OK") +} + +// unit is a convenient alias for struct{}. +type unit = struct{} + +// type check +var _ agh.Service = (*Service)(nil) + +// Start implements the agh.Service interface for *Service. svc may be nil. +// After Start exits, all HTTP servers have tried to start, possibly failing and +// writing error messages to the log. +func (svc *Service) Start() (err error) { + if svc == nil { + return nil + } + + srvs := svc.servers + + wg := &sync.WaitGroup{} + wg.Add(len(srvs)) + for _, srv := range srvs { + go serve(srv, wg) + } + + wg.Wait() + + return nil +} + +// serve starts and runs srv and writes all errors into its log. +func serve(srv *http.Server, wg *sync.WaitGroup) { + addr := srv.Addr + defer log.OnPanic(addr) + + var l net.Listener + var err error + if srv.TLSConfig == nil { + l, err = net.Listen("tcp", addr) + } else { + l, err = tls.Listen("tcp", addr, srv.TLSConfig) + } + if err != nil { + srv.ErrorLog.Printf("starting srv %s: binding: %s", addr, err) + } + + // Update the server's address in case the address had the port zero, which + // would mean that a random available port was automatically chosen. + srv.Addr = l.Addr().String() + + log.Info("websvc: starting srv http://%s", srv.Addr) + wg.Done() + + err = srv.Serve(l) + if err != nil && !errors.Is(err, http.ErrServerClosed) { + srv.ErrorLog.Printf("starting srv %s: %s", addr, err) + } +} + +// Shutdown implements the agh.Service interface for *Service. svc may be nil. +func (svc *Service) Shutdown(ctx context.Context) (err error) { + if svc == nil { + return nil + } + + var errs []error + for _, srv := range svc.servers { + serr := srv.Shutdown(ctx) + if serr != nil { + errs = append(errs, fmt.Errorf("shutting down srv %s: %w", srv.Addr, serr)) + } + } + + if len(errs) > 0 { + return errors.List("shutting down") + } + + return nil +} diff --git a/internal/v1/websvc/websvc_test.go b/internal/v1/websvc/websvc_test.go new file mode 100644 index 00000000..01b892cd --- /dev/null +++ b/internal/v1/websvc/websvc_test.go @@ -0,0 +1,69 @@ +package websvc_test + +import ( + "context" + "io" + "net" + "net/http" + "net/url" + "testing" + "time" + + "github.com/AdguardTeam/AdGuardHome/internal/v1/websvc" + "github.com/AdguardTeam/golibs/netutil" + "github.com/AdguardTeam/golibs/testutil" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const testTimeout = 1 * time.Second + +func TestService_Start_getHealthCheck(t *testing.T) { + c := &websvc.Config{ + TLS: nil, + Addresses: []*netutil.IPPort{{ + IP: net.IP{127, 0, 0, 1}, + Port: 0, + }}, + SecureAddresses: nil, + Timeout: testTimeout, + } + + svc := websvc.New(c) + + err := svc.Start() + require.NoError(t, err) + t.Cleanup(func() { + ctx, cancel := context.WithTimeout(context.Background(), testTimeout) + t.Cleanup(cancel) + + err = svc.Shutdown(ctx) + require.NoError(t, err) + }) + + addrs := svc.Addrs() + require.Len(t, addrs, 1) + + u := &url.URL{ + Scheme: "http", + Host: addrs[0], + Path: "/health-check", + } + req, err := http.NewRequest(http.MethodGet, u.String(), nil) + require.NoError(t, err) + + httpCli := &http.Client{ + Timeout: testTimeout, + } + resp, err := httpCli.Do(req) + require.NoError(t, err) + + testutil.CleanupAndRequireSuccess(t, resp.Body.Close) + + assert.Equal(t, http.StatusOK, resp.StatusCode) + + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + + assert.Equal(t, []byte("OK"), body) +} diff --git a/main.go b/main.go index 505eb3e5..03ad2f03 100644 --- a/main.go +++ b/main.go @@ -1,3 +1,6 @@ +//go:build !v1 +// +build !v1 + package main import ( diff --git a/main_v1.go b/main_v1.go new file mode 100644 index 00000000..6b5f3dea --- /dev/null +++ b/main_v1.go @@ -0,0 +1,21 @@ +//go:build v1 +// +build v1 + +package main + +import ( + "embed" + + "github.com/AdguardTeam/AdGuardHome/internal/v1/cmd" +) + +// Embed the prebuilt client here since we strive to keep .go files inside the +// internal directory and the embed package is unable to embed files located +// outside of the same or underlying directory. + +//go:embed build2 +var clientBuildFS embed.FS + +func main() { + cmd.Main(clientBuildFS) +} diff --git a/openapi/v1.yaml b/openapi/v1.yaml new file mode 100644 index 00000000..30c318bc --- /dev/null +++ b/openapi/v1.yaml @@ -0,0 +1,4913 @@ +'openapi': '3.0.3' +'info': + 'contact': + 'email': 'devteam@adguard.com' + 'name': 'AdGuard Home' + 'url': 'https://github.com/AdguardTeam/AdGuardHome' + 'description': | + **!! WARNING! API IS AT THE DRAFT STAGE! THINGS WILL BREAK! !!** + + AdGuard Home REST API, V1 **DRAFT**. Our administration web interface is + built on top of this REST API. + + This API is currently a **DRAFT** and is not covered by any stability + guarantees. Once this API reaches maturity, the old `/control/` API will + mostly be removed. + + ## Information For API Users + + * Empty arrays are always sent by the backend, unless documented + otherwise. If the backend doesn't, it's a backend error. + + * `PATCH` requests with JSON bodies use RFC 7396 JSON Merge Patch unless + documented otherwise. + + * The property `x-error-class` on plain text error responses suggests, + which class of error should be used if the API user wants to wrap it + into an object. The property `x-error-code` suggest the error code for + the error object. The code usually goes into the `code` property, and + the content, into `msg`. + + * The property `x-skip-web-api` on operations suggests API clients for + web, like our frontend, to skip this operation in their generated code. + + * The header `Server` will be set to `AdGuardHome/<>`. For + example: `AdGuardHome/v0.107.0-a.42+abcd1234`. + + ## Conventions For API Authors + + ### Naming + + * `CapitalCamelCase` for entities. + + * Initialisms are spelled like `DhcpSettings` and not `DHCPSettings`. + + * `lower_snake_case` for path and query parameters. + + * No unit suffices. + + * Path parameters's names start with `Path`; query, with `Query`. + + * Requests end with `Req`; responses, with `Resp`. + + ### Structure + + * Add `400` and `422` responses to requests that accept data. + + * Add `401` responses, unless the method can work without authorization. + + * Add `500` responses. + + * Descriptions are always on their own lines. + + * Don't add a description if there is already one a level above. + + * Five levels of indentation max, except for descriptions and array + items. + + * Keep things in alphabetical order. + + * Mark required things as such. Document possibly-absent fields **both** + in `required` **and** in `description`, if there is one. + + * Prefer flat objects. Example: `resp.top_user`, not `resp.top.user.val`. + + * Prefer to make it easier for the frontend where possible. + + * Provide examples for requests and responses. If examples are provided + elsewhere, document that. + + * Summaries and descriptions with dots. + + * Top-level value in a JSON request or response must be an object. + + ### Types + + * Add `'maximum': 65535` for 16-bit unsigned integers (for example, port + numbers). + + * Add `'minimum': 0` for unsigned integers. + + * Duration in milliseconds. Time in milliseconds in the Unix epoch. Both + of type `double`, because that is easier for the JS frontend. + + * Integers are always `int64`, numbers are always `double. + + 'license': + 'name': 'GNU General Public License v3.0' + 'url': 'https://www.gnu.org/licenses/gpl-3.0.txt' + 'title': 'AdGuard Home V1 DRAFT API' + 'version': '0.108' + +'servers': +- 'description': > + The V1 HTTP API namespace. + 'url': '/api/v1' + +'security': +- 'basicAuth': [] + +'tags': +- 'description': > + Authorization and account management. + 'name': 'accounts' +- 'description': > + Configuration and settings for Apple products. + 'name': 'apple' +- 'description': > + Runtime and persistent client information. + 'name': 'clients' +- 'description': > + DHCP server methods. + 'name': 'dhcp' +- 'description': > + First-time install configuration handlers. Will not be available once the + installation is done. + 'name': 'install' +- 'description': > + Query logs. + 'name': 'log' +- 'description': > + Filter lists, blocked services, and custom filtering rules. + 'name': 'protection' +- 'description': > + Settings management. + 'name': 'settings' +- 'description': > + Query, filtering, system, and other statistics. + 'name': 'stats' +- 'description': > + Information about the AdGuard Home server and the host system. + 'name': 'system' + +'paths': + '/health-check': + 'get': + 'operationId': 'HealthCheck' + 'servers': + - 'url': '/' + 'summary': 'Check if the server is up.' + 'tags': + - 'system' + + '/accounts/profile': + 'get': + 'operationId': 'GetV1AccountsProfile' + 'responses': + '200': + '$ref': '#/components/responses/GetV1AccountsProfileResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get the profile of the current user.' + 'tags': + - 'accounts' + 'patch': + 'operationId': 'PatchV1AccountsProfile' + 'requestBody': + '$ref': '#/components/requestBodies/PatchV1AccountsProfileReq' + 'responses': + '200': + '$ref': '#/components/responses/PatchV1AccountsProfileResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Update the profile of the current user.' + 'tags': + - 'accounts' + + '/accounts/session': + 'delete': + 'operationId': 'DeleteV1AccountsSession' + 'responses': + '204': + '$ref': '#/components/responses/NoContentResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Log out of the system.' + 'tags': + - 'accounts' + 'post': + 'operationId': 'PostV1AccountsSession' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1AccountsSessionReq' + 'responses': + '204': + '$ref': '#/components/responses/NoContentResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Log into the system.' + 'tags': + - 'accounts' + + '/apple/doh.mobileconfig': + 'get': + 'operationId': 'GetV1AppleDohMobileconfig' + 'parameters': + - '$ref': '#/components/parameters/QueryClientId' + - '$ref': '#/components/parameters/QueryHost' + 'responses': + '200': + '$ref': '#/components/responses/GetV1AppleDohMobileconfigResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get a DNS-over-HTTPS .mobileconfig.' + 'tags': + - 'apple' + 'x-skip-web-api': true + + '/apple/dot.mobileconfig': + 'get': + 'operationId': 'GetV1AppleDotMobileconfig' + 'parameters': + - '$ref': '#/components/parameters/QueryHost' + - '$ref': '#/components/parameters/QueryClientId' + 'responses': + '200': + '$ref': '#/components/responses/GetV1AppleDotMobileconfigResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get a DNS-over-HTTPS .mobileconfig.' + 'tags': + - 'apple' + 'x-skip-web-api': true + + '/clients/persistent': + 'get': + 'operationId': 'GetV1ClientsPersistent' + 'responses': + '200': + '$ref': '#/components/responses/GetV1ClientsPersistentResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get all persistent clients.' + 'tags': + - 'clients' + 'post': + 'operationId': 'PostV1ClientsPersistent' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1ClientsPersistentReq' + 'responses': + '201': + '$ref': '#/components/responses/PostV1ClientsPersistentResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Create a new persistent client.' + 'tags': + - 'clients' + + '/clients/persistent/{client_uid}': + 'delete': + 'operationId': 'DeleteV1ClientPersistent' + 'responses': + '204': + '$ref': '#/components/responses/NoContentResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '404': + '$ref': '#/components/responses/NotFoundResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Delete a persistent client.' + 'tags': + - 'clients' + 'parameters': + - '$ref': '#/components/parameters/PathClientUid' + 'patch': + 'operationId': 'PatchV1ClientPersistent' + 'requestBody': + '$ref': '#/components/requestBodies/PatchV1ClientPersistentReq' + 'responses': + '200': + '$ref': '#/components/responses/PatchV1ClientPersistentResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '404': + '$ref': '#/components/responses/NotFoundResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Update a persistent client.' + 'tags': + - 'clients' + + '/clients/runtime': + 'get': + 'operationId': 'GetV1ClientsRuntime' + 'responses': + '200': + '$ref': '#/components/responses/GetV1ClientsRuntimeResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get all runtime clients.' + 'tags': + - 'clients' + + '/dhcp/leases': + 'get': + 'operationId': 'GetV1DhcpLeases' + 'responses': + '200': + '$ref': '#/components/responses/GetV1DhcpLeasesResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get all dynamic and static DHCP leases.' + 'tags': + - 'dhcp' + 'post': + 'operationId': 'PostV1DhcpLeases' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1DhcpLeasesReq' + 'responses': + '200': + '$ref': '#/components/responses/PostV1DhcpLeasesResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Create a new static DHCP lease.' + 'tags': + - 'dhcp' + + '/dhcp/leases/{lease_uid}': + 'delete': + 'operationId': 'DeleteV1DhcpLease' + 'responses': + '204': + '$ref': '#/components/responses/NoContentResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '404': + '$ref': '#/components/responses/NotFoundResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Delete a static DHCP lease.' + 'tags': + - 'dhcp' + 'parameters': + - '$ref': '#/components/parameters/PathLeaseUid' + 'patch': + 'operationId': 'PatchV1DhcpLease' + 'requestBody': + '$ref': '#/components/requestBodies/PatchV1DhcpLeaseReq' + 'responses': + '200': + '$ref': '#/components/responses/PatchV1DhcpLeaseResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '404': + '$ref': '#/components/responses/NotFoundResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Update a static DHCP lease.' + 'tags': + - 'dhcp' + + '/dhcp/status': + 'get': + 'operationId': 'GetV1DhcpStatus' + 'responses': + '200': + '$ref': '#/components/responses/GetV1DhcpStatusResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get DHCP server status.' + 'tags': + - 'dhcp' + + '/install/check': + 'post': + 'operationId': 'PostV1InstallCheck' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1InstallCheckReq' + 'responses': + '200': + '$ref': '#/components/responses/PostV1InstallCheckResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Check initial configuration.' + 'tags': + - 'install' + + '/install/configure': + 'post': + 'operationId': 'PostV1InstallConfigure' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1InstallConfigureReq' + 'responses': + '204': + '$ref': '#/components/responses/NoContentResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Apply initial configuration.' + 'tags': + - 'install' + + '/install/info': + 'get': + 'operationId': 'GetV1InstallInfo' + 'responses': + '200': + '$ref': '#/components/responses/GetV1InstallInfoResp' + '404': + '$ref': '#/components/responses/NotFoundResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get initial configuration information.' + 'tags': + - 'install' + + '/log/clear': + 'post': + 'operationId': 'PostV1LogClear' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1LogClearReq' + 'responses': + '204': + '$ref': '#/components/responses/NoContentResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Clear the whole query log.' + 'tags': + - 'log' + + '/log/search': + 'get': + 'operationId': 'GetV1LogSearch' + 'parameters': + - '$ref': '#/components/parameters/QueryBefore' + - '$ref': '#/components/parameters/QueryLimit' + - '$ref': '#/components/parameters/QueryReason' + - '$ref': '#/components/parameters/QueryTerm' + 'responses': + '200': + '$ref': '#/components/responses/GetV1LogSearchResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Search query logs.' + 'tags': + - 'log' + + '/protection/blocked_services': + 'get': + 'operationId': 'GetV1ProtectionBlockedServices' + 'responses': + '200': + '$ref': '#/components/responses/GetV1ProtectionBlockedServicesResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get blocked services.' + 'tags': + - 'protection' + 'put': + 'operationId': 'PutV1ProtectionBlockedServices' + 'requestBody': + '$ref': '#/components/requestBodies/PutV1ProtectionBlockedServicesReq' + 'responses': + '200': + '$ref': '#/components/responses/GetV1ProtectionBlockedServicesResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Replace blocked services.' + 'tags': + - 'protection' + + '/protection/check_custom_rules': + 'post': + 'operationId': 'PostV1ProtectionCheckCustomRules' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1ProtectionCheckCustomRulesReq' + 'responses': + '201': + '$ref': '#/components/responses/PostV1ProtectionCheckCustomRulesResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Check custom filtering rules.' + 'tags': + - 'protection' + + '/protection/custom_rules': + 'get': + 'operationId': 'GetV1ProtectionCustomRules' + 'responses': + '200': + '$ref': '#/components/responses/GetV1ProtectionCustomRulesResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get custom rules.' + 'tags': + - 'protection' + 'put': + 'operationId': 'PutV1ProtectionCustomRules' + 'requestBody': + '$ref': '#/components/requestBodies/PutV1ProtectionCustomRulesReq' + 'responses': + '204': + '$ref': '#/components/responses/NoContentResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Replace custom rules.' + 'tags': + - 'protection' + + '/protection/dns_rewrites': + 'get': + 'operationId': 'GetV1ProtectionDnsRewrites' + 'responses': + '200': + '$ref': '#/components/responses/GetV1ProtectionDnsRewritesResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get all classic DNS rewrites.' + 'tags': + - 'protection' + 'post': + 'operationId': 'PostV1ProtectionDnsRewrites' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1ProtectionDnsRewritesReq' + 'responses': + '201': + '$ref': '#/components/responses/PostV1ProtectionDnsRewritesResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Add a new classic DNS rewrite.' + 'tags': + - 'protection' + + '/protection/dns_rewrites/{dns_rewrite_uid}': + 'delete': + 'operationId': 'DeleteV1ProtectionDnsRewrite' + 'responses': + '204': + '$ref': '#/components/responses/NoContentResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '404': + '$ref': '#/components/responses/NotFoundResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Delete a classic DNS rewrite.' + 'tags': + - 'protection' + 'parameters': + - '$ref': '#/components/parameters/PathDnsRewriteUid' + + '/protection/filters': + 'get': + 'operationId': 'GetV1ProtectionFilters' + 'responses': + '200': + '$ref': '#/components/responses/GetV1ProtectionFiltersResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get all filters.' + 'tags': + - 'protection' + 'post': + 'operationId': 'PostV1ProtectionFilters' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1ProtectionFiltersReq' + 'responses': + '201': + '$ref': '#/components/responses/PostV1ProtectionFiltersResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Add a new filter.' + 'tags': + - 'protection' + + '/protection/filters/{filter_uid}': + 'delete': + 'operationId': 'DeleteV1ProtectionFilter' + 'responses': + '204': + '$ref': '#/components/responses/NoContentResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '404': + '$ref': '#/components/responses/NotFoundResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Delete a filter.' + 'tags': + - 'protection' + 'parameters': + - '$ref': '#/components/parameters/PathFilterUid' + 'patch': + 'operationId': 'PatchV1ProtectionFilter' + 'requestBody': + '$ref': '#/components/requestBodies/PatchV1ProtectionFilterReq' + 'responses': + '200': + '$ref': '#/components/responses/PatchV1ProtectionFilterResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '404': + '$ref': '#/components/responses/NotFoundResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': > + Update a filter's settings. + 'tags': + - 'protection' + + '/protection/refresh_filters': + 'post': + 'operationId': 'PostV1ProtectionRefreshFilters' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1ProtectionRefreshFiltersReq' + 'responses': + '200': + '$ref': '#/components/responses/PostV1ProtectionRefreshFiltersResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': > + Refresh all filters. + 'tags': + - 'protection' + + '/protection/refresh_filters/{filter_uid}': + 'parameters': + - '$ref': '#/components/parameters/PathFilterUid' + 'post': + 'operationId': 'PostV1ProtectionRefreshFilter' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1ProtectionRefreshFilterReq' + 'responses': + '200': + '$ref': '#/components/responses/PostV1ProtectionRefreshFilterResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': > + Refresh a filter. + 'tags': + - 'protection' + + '/settings/all': + 'get': + 'operationId': 'GetV1SettingsAll' + 'responses': + '200': + '$ref': '#/components/responses/GetV1SettingsAllResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get all settings.' + 'tags': + - 'settings' + + '/settings/dhcp': + 'patch': + 'operationId': 'PatchV1SettingsDhcp' + 'requestBody': + '$ref': '#/components/requestBodies/PatchV1SettingsDhcpReq' + 'responses': + '200': + '$ref': '#/components/responses/PatchV1SettingsDhcpResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Update DHCP server settings.' + 'tags': + - 'settings' + + '/settings/dns': + 'patch': + 'operationId': 'PatchV1SettingsDns' + 'requestBody': + '$ref': '#/components/requestBodies/PatchV1SettingsDnsReq' + 'responses': + '200': + '$ref': '#/components/responses/PatchV1SettingsDnsResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Update DNS server settings.' + 'tags': + - 'settings' + + '/settings/dns/access': + 'get': + 'description': > + Get DNS access settings. This is a separate API, because these lists + can become quite big. + 'operationId': 'GetV1SettingsDnsAccess' + 'responses': + '200': + '$ref': '#/components/responses/GetV1SettingsDnsAccessResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get DNS access settings.' + 'tags': + - 'settings' + 'put': + 'description': > + Update DNS access settings. This is a separate API, because these lists + can become quite big. + 'operationId': 'PutV1SettingsDnsAccess' + 'requestBody': + '$ref': '#/components/requestBodies/PutV1SettingsDnsAccessReq' + 'responses': + '204': + '$ref': '#/components/responses/NoContentResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Update DNS access settings.' + 'tags': + - 'settings' + + '/settings/dns/check': + 'post': + 'operationId': 'PostV1SettingsDnsCheck' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1SettingsDnsCheckReq' + 'responses': + '200': + '$ref': '#/components/responses/PostV1SettingsDnsCheckResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Check DNS upstream settings.' + 'tags': + - 'settings' + + '/settings/log': + 'patch': + 'operationId': 'PatchV1SettingsLog' + 'requestBody': + '$ref': '#/components/requestBodies/PatchV1SettingsLogReq' + 'responses': + '200': + '$ref': '#/components/responses/PatchV1SettingsLogResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Update query logging settings.' + 'tags': + - 'settings' + + '/settings/protection': + 'patch': + 'operationId': 'PatchV1SettingsProtection' + 'requestBody': + '$ref': '#/components/requestBodies/PatchV1SettingsProtectionReq' + 'responses': + '200': + '$ref': '#/components/responses/PatchV1SettingsProtectionResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Update protection settings.' + 'tags': + - 'settings' + + '/settings/stats': + 'patch': + 'operationId': 'PatchV1SettingsStats' + 'requestBody': + '$ref': '#/components/requestBodies/PatchV1SettingsStatsReq' + 'responses': + '200': + '$ref': '#/components/responses/PatchV1SettingsStatsResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Update statistics settings.' + 'tags': + - 'settings' + + '/settings/tls': + 'patch': + 'operationId': 'PatchV1SettingsTls' + 'requestBody': + '$ref': '#/components/requestBodies/PatchV1SettingsTlsReq' + 'responses': + '200': + '$ref': '#/components/responses/PatchV1SettingsTlsResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Update TLS and encryption settings.' + 'tags': + - 'settings' + + '/settings/tls/check': + 'post': + 'operationId': 'PostV1SettingsTlsCheck' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1SettingsTlsCheckReq' + 'responses': + '200': + '$ref': '#/components/responses/PostV1SettingsTlsCheckResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Check TLS and encryption settings.' + 'tags': + - 'settings' + + '/stats/all': + 'get': + 'operationId': 'GetV1StatsAll' + 'responses': + '200': + '$ref': '#/components/responses/GetV1StatsAllResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get all statistics.' + 'tags': + - 'stats' + + '/stats/clear': + 'post': + 'operationId': 'PostV1StatsClear' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1StatsClearReq' + 'responses': + '204': + '$ref': '#/components/responses/NoContentResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Clear all statistics.' + 'tags': + - 'stats' + + '/system/info': + 'get': + 'operationId': 'GetV1SystemInfo' + 'responses': + '200': + '$ref': '#/components/responses/GetV1SystemInfoResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Get server information.' + 'tags': + - 'system' + + '/system/reset': + 'post': + 'operationId': 'PostV1SystemReset' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1SystemResetReq' + 'responses': + '200': + '$ref': '#/components/responses/PostV1SystemResetResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Reset all settings to defaults.' + 'tags': + - 'system' + + '/system/update': + 'post': + 'operationId': 'PostV1SystemUpdate' + 'requestBody': + '$ref': '#/components/requestBodies/PostV1SystemUpdateReq' + 'responses': + '200': + '$ref': '#/components/responses/PostV1SystemUpdateResp' + '400': + '$ref': '#/components/responses/BadRequestResp' + '401': + '$ref': '#/components/responses/UnauthorizedResp' + '422': + '$ref': '#/components/responses/UnprocessableEntityResp' + '500': + '$ref': '#/components/responses/InternalServerErrorResp' + 'summary': 'Update AdGuard Home.' + 'tags': + - 'system' + +'components': + 'parameters': + 'PathDnsRewriteUid': + 'description': > + DNS rewrite ID. + 'example': 'abcd1234' + 'in': 'path' + 'name': 'dns_rewrite_uid' + 'required': true + 'schema': + '$ref': '#/components/schemas/Uid' + + 'PathClientUid': + 'description': > + The unique ID of a client. + 'example': 'abcd1234' + 'in': 'path' + 'name': 'client_uid' + 'required': true + 'schema': + '$ref': '#/components/schemas/Uid' + + 'PathFilterUid': + 'description': > + The ID of a filter. + 'example': 'abcd1234' + 'in': 'path' + 'name': 'filter_uid' + 'required': true + 'schema': + '$ref': '#/components/schemas/Uid' + + 'PathLeaseUid': + 'description': > + The ID of a static lease. + 'example': 'abcd1234' + 'in': 'path' + 'name': 'lease_uid' + 'required': true + 'schema': + '$ref': '#/components/schemas/Uid' + + 'QueryBefore': + 'description': > + Unix time, before which to show the search results, in milliseconds. + 'example': 1614345496000 + 'in': 'query' + 'name': 'before' + 'required': false + 'schema': + 'format': 'double' + 'type': 'number' + + 'QueryClientId': + 'description': > + ClientID, **not** its UID. + 'example': 'client-1' + 'in': 'query' + 'name': 'client_id' + 'required': false + 'schema': + '$ref': '#/components/schemas/ClientId' + + 'QueryHost': + 'description': > + The host for which the Configuration is generated. + 'example': 'example.org' + 'in': 'query' + 'name': 'host' + 'required': true + 'schema': + 'type': 'string' + + 'QueryLimit': + 'description': > + Maximum amount of records to return. + 'example': 100 + 'in': 'query' + 'name': 'limit' + 'required': false + 'schema': + 'format': 'int64' + 'type': 'integer' + + 'QueryReason': + 'description': > + Filter query log results by filtering reason. + 'example': 'not_filtered_notfound' + 'in': 'query' + 'name': 'reason' + 'required': false + 'schema': + '$ref': '#/components/schemas/FilteringReason' + + 'QueryTerm': + 'description': > + Search term. + 'example': '127.0.0.1' + 'in': 'query' + 'name': 'term' + 'required': false + 'schema': + 'type': 'string' + + 'requestBodies': + 'PatchV1AccountsProfileReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1AccountsProfileReq' + 'required': true + + 'PatchV1ClientPersistentReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1ClientPersistentReq' + 'required': true + + 'PatchV1DhcpLeaseReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1DhcpLeaseReq' + 'required': true + + 'PatchV1ProtectionFilterReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1ProtectionFilterReq' + 'required': true + + 'PatchV1SettingsDhcpReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1SettingsDhcpReq' + 'required': true + + 'PatchV1SettingsDnsReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1SettingsDnsReq' + 'required': true + + 'PatchV1SettingsLogReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1SettingsLogReq' + 'required': true + + 'PatchV1SettingsProtectionReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1SettingsProtectionReq' + 'required': true + + 'PatchV1SettingsStatsReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1SettingsStatsReq' + 'required': true + + 'PatchV1SettingsTlsReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1SettingsTlsReq' + 'required': true + + 'PostV1AccountsSessionReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1AccountsSessionReq' + 'required': true + + 'PostV1ClientsPersistentReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1ClientsPersistentReq' + 'required': true + + 'PostV1DhcpLeasesReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1DhcpLeasesReq' + 'required': true + + 'PostV1InstallCheckReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1InstallCheckReq' + 'required': true + + 'PostV1InstallConfigureReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1InstallConfigureReq' + 'required': true + + 'PostV1LogClearReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1LogClearReq' + 'required': true + + 'PostV1ProtectionCheckCustomRulesReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1ProtectionCheckCustomRulesReq' + 'required': true + + 'PostV1ProtectionDnsRewritesReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1ProtectionDnsRewritesReq' + 'required': true + + 'PostV1ProtectionFiltersReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1ProtectionFiltersReq' + 'required': true + + 'PostV1ProtectionRefreshFilterReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1ProtectionRefreshFilterReq' + 'required': true + + 'PostV1ProtectionRefreshFiltersReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1ProtectionRefreshFiltersReq' + 'required': true + + 'PostV1SettingsDnsCheckReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1SettingsDnsCheckReq' + 'required': true + + 'PostV1SettingsTlsCheckReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1SettingsTlsCheckReq' + 'required': true + + 'PostV1StatsClearReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1StatsClearReq' + 'required': true + + 'PostV1SystemResetReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1SystemResetReq' + 'required': true + + 'PostV1SystemUpdateReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1SystemUpdateReq' + 'required': true + + 'PutV1ProtectionBlockedServicesReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PutV1ProtectionBlockedServicesReq' + 'required': true + + 'PutV1ProtectionCustomRulesReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PutV1ProtectionCustomRulesReq' + 'required': true + + 'PutV1SettingsDnsAccessReq': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PutV1SettingsDnsAccessReq' + 'required': true + + 'responses': + 'BadRequestResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/BadRequestResp' + 'text/plain': + 'example': >- + invalid character '{' looking for beginning of object key string + 'x-error-class': '#/components/schemas/BadRequestResp' + 'x-error-code': 'TXT400' + 'description': > + Generic bad request response. Sent when the request data is malformed + (for example, invalid JSON). + + 'GetV1AccountsProfileResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1AccountsProfileResp' + 'description': > + A successful response to a `GET /api/v1/accounts/profile` request. + + 'GetV1AppleDohMobileconfigResp': + 'content': + 'application/xml': + 'schema': + '$ref': '#/components/schemas/GetV1AppleDohMobileconfigResp' + 'description': > + A successful response to a `GET /api/v1/apple/doh.mobileconfig` request. + + 'GetV1AppleDotMobileconfigResp': + 'content': + 'application/xml': + 'schema': + '$ref': '#/components/schemas/GetV1AppleDotMobileconfigResp' + 'description': > + A successful response to a `GET /api/v1/apple/dot.mobileconfig` request. + + 'GetV1ClientsPersistentResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1ClientsPersistentResp' + 'description': > + A successful response to a `GET /api/v1/clients/persistent` request. + + 'GetV1ClientsRuntimeResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1ClientsRuntimeResp' + 'description': > + A successful response to a `GET /api/v1/clients/runtime` request. + + 'GetV1DhcpLeasesResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1DhcpLeasesResp' + 'description': > + A successful response to a `GET /api/v1/dhcp/leases` request. + + 'GetV1DhcpStatusResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1DhcpStatusResp' + 'description': > + A successful response to a `GET /api/v1/dhcp/status` request. + + 'GetV1InstallInfoResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1InstallInfoResp' + 'description': > + A successful response to a `GET /api/v1/install/info` request. + + 'GetV1LogSearchResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1LogSearchResp' + 'description': > + A successful response to a `GET /api/v1/log/search` request. + + 'GetV1ProtectionBlockedServicesResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1ProtectionBlockedServicesResp' + 'description': > + A successful response to a `GET /api/v1/protection/blocked_services` + or a `PUT /api/v1/protection/blocked_services` request. + + 'GetV1ProtectionCustomRulesResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1ProtectionCustomRulesResp' + 'description': > + A successful response to a `GET /api/v1/protection/custom_rules` + request. + + 'GetV1ProtectionDnsRewritesResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1ProtectionDnsRewritesResp' + 'description': > + A successful response to a `GET /api/v1/protection/dns_rewrites` + request. + + 'GetV1ProtectionFiltersResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1ProtectionFiltersResp' + 'description': > + A successful response to a `GET /api/v1/protection/filters` request. + + 'GetV1SettingsAllResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1SettingsAllResp' + 'description': > + A successful response to a `GET /api/v1/settings/all` request. + + 'GetV1SettingsDnsAccessResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1SettingsDnsAccessResp' + 'description': > + A successful response to a `GET /api/v1/settings/dns/access` request. + + 'GetV1StatsAllResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1StatsAllResp' + 'description': > + A successful response to a `GET /api/v1/stats/all` request. + + 'GetV1SystemInfoResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/GetV1SystemInfoResp' + 'description': > + A successful response to a `GET /api/v1/server/info` request. + + 'InternalServerErrorResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/InternalServerErrorResp' + 'text/plain': + 'example': >- + runtime error: invalid memory address or nil pointer dereference + 'x-error-class': '#/components/schemas/InternalServerErrorResp' + 'x-error-code': 'TXT500' + 'description': > + Generic internal server error. + + 'NoContentResp': + 'description': > + Generic no-error no-content response. + + 'NotFoundResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/NotFoundResp' + 'text/plain': + 'example': >- + Not found. + 'x-error-class': '#/components/schemas/NotFoundResp' + 'x-error-code': 'TXT404' + 'description': > + Generic not found response. + + 'PatchV1AccountsProfileResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1AccountsProfileResp' + 'description': > + A successful response to a `PATCH /api/v1/accounts/profile` request. + + 'PatchV1ClientPersistentResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1ClientPersistentResp' + 'description': > + A successful response to + a `PATCH /api/v1/clients/persistent/{client_uid}` request. + + 'PatchV1DhcpLeaseResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1DhcpLeaseResp' + 'description': > + A successful response to a `PATCH /api/v1/dhcp/leases/{lease_uid}` + request. + + 'PatchV1ProtectionFilterResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1ProtectionFilterResp' + 'description': > + A successful response to a `PATCH /api/v1/filters/{filter_uid}` request. + + 'PatchV1SettingsDhcpResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1SettingsDhcpResp' + 'description': > + A successful response to a `PATCH /api/v1/settings/dhcp` request. + + 'PatchV1SettingsDnsResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1SettingsDnsResp' + 'description': > + A successful response to a `PATCH /api/v1/settings/dns` request. + + 'PatchV1SettingsLogResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1SettingsLogResp' + 'description': > + A successful response to a `PATCH /api/v1/settings/log` request. + + 'PatchV1SettingsProtectionResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1SettingsProtectionResp' + 'description': > + A successful response to a `PATCH /api/v1/settings/protection` request. + + 'PatchV1SettingsStatsResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1SettingsStatsResp' + 'description': > + A successful response to a `PATCH /api/v1/settings/stats` request. + + 'PatchV1SettingsTlsResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PatchV1SettingsTlsResp' + 'description': > + A successful response to a `PATCH /api/v1/settings/tls` request. + + 'PostV1ClientsPersistentResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1ClientsPersistentResp' + 'description': > + A successful response to a `POST /api/v1/clients/persistent` request. + + 'PostV1DhcpLeasesResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1DhcpLeasesResp' + 'description': > + A successful response to a `POST /api/v1/dhcp/leases` request. + + 'PostV1InstallCheckResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1InstallCheckResp' + 'description': > + A successful response to a `POST /api/v1/install/check` request. + + 'PostV1ProtectionCheckCustomRulesResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1ProtectionCheckCustomRulesResp' + 'description': > + A successful response to a `POST /api/v1/protection/check_custom_rules` + request. + + 'PostV1ProtectionDnsRewritesResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1ProtectionDnsRewritesResp' + 'description': > + A successful response to a `POST /api/v1/protection/dns_rewrites` + request. + + 'PostV1ProtectionFiltersResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1ProtectionFiltersResp' + 'description': > + A successful response to a `POST /api/v1/protection/filters` request. + + 'PostV1ProtectionRefreshFilterResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1ProtectionRefreshFilterResp' + 'description': > + A successful response to + a `POST /api/v1/protection/refresh_filters/{filter_uid}` request. + + 'PostV1ProtectionRefreshFiltersResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1ProtectionRefreshFiltersResp' + 'description': > + A successful response to a `POST /api/v1/protection/refresh_filters` + request. + + 'PostV1SettingsDnsCheckResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1SettingsDnsCheckResp' + 'description': > + A successful response to a `POST /api/v1/settings/dns/check` request. + + 'PostV1SettingsTlsCheckResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1SettingsTlsCheckResp' + 'description': > + A successful response to a `POST /api/v1/settings/tls/check` request. + + 'PostV1SystemResetResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1SystemResetResp' + 'description': > + A successful response to a `POST /api/v1/system/reset` request. + + 'PostV1SystemUpdateResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/PostV1SystemUpdateResp' + 'description': > + A successful response to a `POST /api/v1/system/update` request. + + 'UnauthorizedResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/UnauthorizedResp' + 'text/plain': + 'example': 'no or bad authorization provided' + 'x-error-class': '#/components/schemas/UnauthorizedResp' + 'x-error-code': 'TXT401' + 'description': > + This API requires authorization. + 'headers': + 'WWW-Authenticate': + 'description': > + The required WWW-Authenticate header. + 'example': 'Basic realm="AdGuard Home", charset="UTF-8"' + 'required': true + 'schema': + 'type': 'string' + + 'UnprocessableEntityResp': + 'content': + 'application/json': + 'schema': + '$ref': '#/components/schemas/UnprocessableEntityResp' + 'description': > + Generic bad request data response. Sent when the request data is + well-formed but is invalid for this request. + + 'schemas': + 'BadRequestResp': + 'example': + 'code': 'JSN000' + 'msg': >- + invalid character '{' looking for beginning of object key string + 'properties': + 'code': + '$ref': '#/components/schemas/ErrorCode' + 'msg': + 'description': > + Error message string. + 'type': 'string' + 'required': + - 'code' + - 'msg' + 'type': 'object' + + 'BlockedServiceId': + 'description': > + ID of a blocked service. + 'enum': + - '9gag' + - 'amazon' + - 'cloudflare' + - 'dailymotion' + - 'discord' + - 'disneyplus' + - 'ebay' + - 'epic_games' + - 'facebook' + - 'hulu' + - 'imgur' + - 'instagram' + - 'mail_ru' + - 'netflix' + - 'ok' + - 'origin' + - 'pinterest' + - 'qq' + - 'reddit' + - 'skype' + - 'snapchat' + - 'spotify' + - 'steam' + - 'telegram' + - 'tiktok' + - 'tinder' + - 'twitch' + - 'twitter' + - 'viber' + - 'vimeo' + - 'vk' + - 'wechat' + - 'weibo' + - 'whatsapp' + - 'youtube' + 'type': 'string' + + 'BlockedServices': + 'description': > + Blocked services. + 'example': + 'services': + - '9gag' + - 'dailymotion' + 'properties': + 'services': + 'description': > + All blocked services. + 'items': + '$ref': '#/components/schemas/BlockedServiceId' + 'type': 'array' + 'required': + - 'services' + 'type': 'object' + + 'Channel': + 'description': > + AdGuard Home release channel. + 'enum': + - 'beta' + - 'development' + - 'edge' + - 'release' + 'type': 'string' + + 'ClientId': + 'pattern': '[0-9a-z-]{1,64}' + 'type': 'string' + + 'ClientInfo': + 'description': > + A shorter information about a client. If the `uid` field is present, + this is a persistent client. Otherwise, this is a runtime client. + 'properties': + 'blocked': + 'description': > + If `true`, client is blocked. + 'type': 'boolean' + 'ids': + 'description': | + Client identifiers. That includes ClientIDs set by users as well as + IP addresses. There must be at least one identifier. + + Not to be confused with the `uid` field. + 'example': + - '1.2.3.4' + - 'user-1' + 'items': + 'type': 'string' + 'minItems': 1 + 'type': 'array' + 'name': + 'description': > + The name of the client, if any. If there are none, this field is + absent. + 'example': 'User 1' + 'type': 'string' + 'num': + 'description': > + Total number of requests for this client. + 'example': 1000 + 'format': 'int64' + 'type': 'integer' + 'num_blocked': + 'description': > + Total number of blocked requests for this client. + 'example': 1000 + 'format': 'int64' + 'type': 'integer' + 'uid': + '$ref': '#/components/schemas/Uid' + 'whois': + '$ref': '#/components/schemas/Whois' + 'required': + - 'blocked' + - 'ids' + - 'num' + - 'num_blocked' + 'type': 'object' + + 'CustomRules': + 'description': > + Custom filtering rules. + 'example': + 'rules': + - '||example.com' + - '# Some comment' + 'properties': + 'rules': + 'description': > + All custom filtering rules + 'items': + 'type': 'string' + 'type': 'array' + 'required': + - 'rules' + 'type': 'object' + + 'DhcpLease': + 'allOf': + - '$ref': '#/components/schemas/DhcpLeasePost' + - 'description': > + A dynamic or static DHCP lease. If the `uid` field is present, this is + a static lease. Otherwise, this is a dynamic lease. + 'example': + 'expires': 1614345496000 + 'hostname': 'my-mobile' + 'ip': '192.168.1.2' + 'mac': '01:23:45:67:89:ab' + 'uid': 'abcd1234' + 'properties': + 'uid': + '$ref': '#/components/schemas/Uid' + + 'DhcpLeasePatch': + 'description': > + A static DHCP lease update object. + 'example': + 'expires': 1614345496000 + 'properties': + 'expires': + 'description': > + The Unix time of the lease's expiry time, in milliseconds. + 'format': 'double' + 'type': 'number' + 'hostname': + 'description': > + Client's hostname. + 'type': 'string' + 'ip': + 'description': > + IP address leased to the client. + 'type': 'string' + 'mac': + 'description': > + Hardware address of the lease client. + 'type': 'string' + 'type': 'object' + + 'DhcpLeasePost': + 'allOf': + - '$ref': '#/components/schemas/DhcpLeasePatch' + - 'description': > + A static DHCP lease create object. + 'example': + 'expires': 1614345496000 + 'hostname': 'my-mobile' + 'ip': '192.168.1.2' + 'mac': '01:23:45:67:89:ab' + 'required': + - 'expires' + - 'hostname' + - 'ip' + - 'mac' + + 'DhcpSettings': + 'allOf': + - '$ref': '#/components/schemas/DhcpSettingsPatch' + - 'description': > + DHCP server settings. + 'example': + 'enabled': true + 'interface_name': 'wlan0' + 'ipv4_gateway_ip': '192.168.1.1' + 'ipv4_lease_duration': 86400000 + 'ipv4_range_end': '192.168.1.101' + 'ipv4_range_start': '192.168.1.2' + 'ipv4_subnet_mask': '255.255.255.0' + 'ipv6_range_start': '2001:db8::1' + 'ipv6_lease_duration': 86400000 + 'required': + - 'enabled' + + 'DhcpSettingsPatch': + 'description': > + DHCP server settings update object. + 'example': + 'enabled': true + 'interface_name': 'wlan0' + 'ipv4_gateway_ip': '192.168.1.1' + 'ipv4_lease_duration': 86400000 + 'ipv4_range_end': '192.168.1.101' + 'ipv4_range_start': '192.168.1.2' + 'ipv4_subnet_mask': '255.255.255.0' + 'properties': + 'enabled': + 'description': > + If `true`, the DHCP server is enabled. + 'type': 'boolean' + 'interface_name': + 'description': > + The name of network interface to serve on. + 'type': 'string' + 'ipv4_gateway_ip': + 'description': > + The IP address of the gateway. + 'type': 'string' + 'ipv4_lease_duration': + 'description': > + The duration of the IPv4 lease, in milliseconds. + 'type': 'number' + 'ipv4_range_end': + 'description': > + The end of the IPv4 addresses to serve to clients. + 'type': 'string' + 'ipv4_range_start': + 'description': > + The start of the IPv4 addresses to serve to clients. + 'type': 'string' + 'ipv4_subnet_mask': + 'description': > + The IP subnet mask. + 'type': 'string' + 'ipv6_lease_duration': + 'description': > + The duration of the IPv6 lease, in milliseconds. + 'type': 'number' + 'ipv6_range_start': + 'description': > + The start of the IPv6 addresses to serve to clients. + 'type': 'string' + 'type': 'object' + + 'DnsAccessSettings': + 'description': > + DNS server access settings. + 'example': + 'allowed_clients': [] + 'blocked_clients': + - '1.2.3.4' + - '5.6.7.8/16' + 'blocked_domain_rules': + - 'id.server' + - '*.example.org' + - '||example.com^' + 'properties': + 'allowed_clients': + 'description': > + CIDR or IP addresses of clients in the allowlist. If non-empty, + AdGuard Home will accept requests from these IP addresses only. + 'items': + 'type': 'string' + 'type': 'array' + 'blocked_clients': + 'description': > + CIDR or IP addresses of clients in the blocklist. If non-empty, + AdGuard Home will drop requests from these IP addresses. + 'items': + 'type': 'string' + 'type': 'array' + 'blocked_domain_rules': + 'description': > + AdGuard Home will drop DNS queries, if the domains in their queries + match these rules. Here you can specify the exact domain + names, wildcards, and `urlfilter` rules. Examples: + + * `example.org` + + * `*.example.org` + + * `||example.org^` + 'items': + 'type': 'string' + 'type': 'array' + 'required': + - 'allowed_clients' + - 'blocked_clients' + - 'blocked_domain_rules' + 'type': 'object' + + 'DnsBlockingMode': + 'description': | + DNS blocking mode. + + * `custom_ip`: Respond with a custom IP address. If this mode is + selected, both `blocking_ipv4` and `blocking_ipv6` parameters must + be set. + + * `default`: Same as `null_ip` for Adblock-style rules, but respond + with the IP address specified in the rule when blocked by an + `/etc/hosts`-style rule. + + * `null_ip`: Respond with a zero IP address: `0.0.0.0` for `A` + requests and `::` for `AAAA` ones. + + * `nxdomain`: Respond with the `NXDOMAIN` code. + + * `refused`: Respond with the `REFUSET` code. + + 'enum': + - 'custom_ip' + - 'default' + - 'null_ip' + - 'nxdomain' + - 'refused' + 'type': 'string' + + 'DnsClass': + 'description': > + DNS resource record class, aka `CLASS`. + 'enum': + - 'any' + - 'ch' + - 'cs' + - 'hs' + - 'in' + 'type': 'string' + + 'DnsProto': + 'description': > + DNS protocol. + 'enum': + - 'dot' + - 'doh' + - 'doq' + - 'dnscrypt' + - 'udp' + 'type': 'string' + + 'DnsResponseCode': + 'description': > + DNS response code, aka `RCODE`. + 'enum': + - 'badalg' + - 'badcookie' + - 'badkey' + - 'badmode' + - 'badname' + - 'badsig' + - 'badtime' + - 'badtrunc' + - 'badvers' + - 'formerr' + - 'noerror' + - 'notauth' + - 'notimp' + - 'notzone' + - 'nxdomain' + - 'nxrrset' + - 'refused' + - 'servfail' + - 'yxdomain' + - 'yxrrset' + 'type': 'string' + + 'DnsRewrite': + 'allOf': + - '$ref': '#/components/schemas/DnsRewritePost' + - 'description': > + A classic DNS rewrite. + 'example': + 'answer': 'A' + 'domain': 'example.com' + 'id': 'abcd1234' + 'properties': + 'id': + '$ref': '#/components/schemas/Uid' + 'required': + - 'answer' + - 'domain' + - 'id' + 'type': 'object' + + 'DnsRewritePost': + 'description': > + A classic DNS rewrite create object. + 'example': + 'answer': 'A' + 'domain': 'example.com' + 'properties': + 'answer': + 'description': > + The value of an `A`, `AAAA`, or `CNAME` DNS record in the response. + Acceptable formats: + + * Domain name: add a `CNAME` record with this domain name. + + * IPv4 address: use this IP in an `A` response. + + * IPv6 address: use this IP in an `AAAA` response. + + * The literal `A`: keep only `A` records from the upstream + response. + + * The literal `AAAA`: keep only `AAAA` records from the upstream + response. + 'type': 'string' + 'domain': + 'description': > + Domain name or wildcard. + 'type': 'string' + 'required': + - 'answer' + - 'domain' + 'type': 'object' + + 'DnsSettings': + 'allOf': + - '$ref': '#/components/schemas/DnsSettingsPatch' + - 'description': > + DNS server settings. + 'example': + 'blocking_mode': 'default' + 'bootstrap_servers': + - '9.9.9.10' + - '149.112.112.10' + 'cache_size': 4194304 + 'cache_ttl_max': 0 + 'cache_ttl_min': 0 + 'dnssec': false + 'edns_client_subnet': false + 'ipv6': true + 'rate_limit': 20 + 'upstream_mode': 'load_balancing' + 'upstream_servers': + - '1.1.1.1' + - '8.8.8.8' + 'required': + - 'blocking_mode' + - 'bootstrap_servers' + - 'cache_size' + - 'cache_ttl_max' + - 'cache_ttl_min' + - 'dnssec' + - 'edns_client_subnet' + - 'ipv6' + - 'rate_limit' + - 'upstream_mode' + - 'upstream_servers' + + 'DnsSettingsPatch': + 'description': > + DNS server settings update object. + 'example': + 'cache_size': 4194304 + 'upstream_servers': + - '1.1.1.1' + 'properties': + 'blocking_ipv4': + 'description': > + IPv4 address to respond with when `blocking_mode` is `custom_ip`. + See the documentation for the `DnsBlockingMode` schema. If + `blocking_mode` is different from `custom_ip`, this property is not + included. + 'type': 'string' + 'blocking_ipv6': + 'description': > + IPv6 address to respond with when `blocking_mode` is `custom_ip`. + See the documentation for the `DnsBlockingMode` schema. If + `blocking_mode` is different from `custom_ip`, this property is not + included. + 'type': 'string' + 'blocking_mode': + '$ref': '#/components/schemas/DnsBlockingMode' + 'bootstrap_servers': + 'description': | + Bootstrap DNS servers' IP addresses to resolve the hostnames of the + encrypted DNS server providers. + 'items': + 'type': 'string' + 'type': 'array' + 'cache_size': + 'description': > + DNS cache size in bytes. + 'format': 'int64' + 'minimum': 0 + 'type': 'integer' + 'cache_ttl_max': + 'description': > + Set a maximum time-to-live value for entries in the DNS cache. `0` + means no override. The value is in **seconds**, like in DNS record + headers. + 'format': 'int64' + 'minimum': 0 + 'type': 'integer' + 'cache_ttl_min': + 'description': > + Extend short time-to-live values received from the upstream server + when caching DNS responses. `0` means no override. TThe value is + in **seconds**, like in DNS record headers. + 'format': 'int64' + 'minimum': 0 + 'type': 'integer' + 'dnssec': + 'description': > + If `true`, set DNSSEC flag in outcoming DNS queries and check the + result. A DNSSEC-enabled resolver is required. + 'type': 'boolean' + 'edns_client_subnet': + 'description': > + If `true`, enable EDNS Client Subnet support and send clients' + subnets to DNS servers. + 'type': 'boolean' + 'ipv6': + 'description': > + If `true`, accept `AAAA` DNS queries. If `false`, respond to them + with an empty answer. + 'type': 'boolean' + 'rate_limit': + 'description': > + The number of requests per second that a single client is allowed to + make. `0` means no limit. + 'format': 'int64' + 'minimum': 0 + 'type': 'integer' + 'upstream_mode': + '$ref': '#/components/schemas/DnsUpstreamMode' + 'upstream_servers': + 'description': > + Upstream DNS servers. + 'items': + '$ref': '#/components/schemas/UpstreamServerAddr' + 'type': 'array' + 'type': 'object' + + 'DnsType': + 'description': > + DNS resource record type, aka `TYPE`. + 'enum': + - 'a' + - 'aaaa' + - 'afsdb' + - 'any' + - 'apl' + - 'atma' + - 'avc' + - 'axfr' + - 'caa' + - 'cdnskey' + - 'cds' + - 'cert' + - 'cname' + - 'csync' + - 'dhcid' + - 'dlv' + - 'dname' + - 'dnskey' + - 'ds' + - 'eid' + - 'eui48' + - 'eui64' + - 'gid' + - 'gpos' + - 'hinfo' + - 'hip' + - 'https' + - 'isdn' + - 'ixfr' + - 'key' + - 'kx' + - 'l32' + - 'l64' + - 'loc' + - 'lp' + - 'maila' + - 'mailb' + - 'mb' + - 'md' + - 'mf' + - 'mg' + - 'minfo' + - 'mr' + - 'mx' + - 'naptr' + - 'nid' + - 'nimloc' + - 'ninfo' + - 'ns' + - 'nsap-ptr' + - 'nsec' + - 'nsec3' + - 'nsec3param' + - 'null' + - 'nxt' + - 'openpgpkey' + - 'opt' + - 'ptr' + - 'px' + - 'rkey' + - 'rp' + - 'rrsig' + - 'rt' + - 'sig' + - 'smimea' + - 'soa' + - 'spf' + - 'srv' + - 'sshfp' + - 'svcb' + - 'ta' + - 'talink' + - 'tkey' + - 'tlsa' + - 'tsig' + - 'txt' + - 'uid' + - 'uinfo' + - 'unspec' + - 'uri' + - 'x25' + 'type': 'string' + + 'DnsUpstreamMode': + 'description': | + Upstream request mode. + + * `fastest`: Query all DNS servers and return the IP address that was + returned by the fastest response. Slows down DNS responses, since + it waits for responses from all upstreams, but improves the overall + connectivity. + + * `load_balancing`: Query one server at a time using a weighted random + algorithm picking the server so that the fastest server is used + more often. + + * `parallel`: Use parallel requests to speed up resolving by + simultaneously querying all upstream servers. + 'enum': + - 'fastest' + - 'load_balancing' + - 'parallel' + 'type': 'string' + + 'ErrorCode': + 'description': | + An error code. + + * `AUT000`: No or bad authorization credentials provided. + + * `ENT404`: Entity not found; as opposed to path not found. + + * `JSN000`: A JSON syntax error. + + * `JSN001`: A JSON type error. + + * `OSS000`: The server's operating system doesn't support the + requested functionality. + + * `PTH404`: Path not found; as opposed to entity not found. + + * `RNT000`: A server runtime error. + + * `TXT400`: A plaintext bad request error. Used when a plaintext + error is wrapped. + + * `TXT401`: A plaintext unauthorized error. Used when a plaintext + error is wrapped. + + * `TXT404`: A plaintext not found error. Used when a plaintext error + is wrapped. + + * `TXT500`: A plaintext internal server error. Used when a plaintext + error is wrapped. + + TODO(a.garipov): Expand with TLS validation errors, DHCP errors, filter + URL reaching errors, OS and I/O errors, and so on. + 'enum': + - 'AUT000' + - 'ENT404' + - 'JSN000' + - 'JSN001' + - 'OSS000' + - 'PTH404' + - 'RNT000' + - 'TXT400' + - 'TXT401' + - 'TXT404' + - 'TXT500' + 'type': 'string' + + 'Filter': + 'allOf': + - '$ref': '#/components/schemas/FilterPatch' + - 'description': > + A single filter list of rules. + 'example': + 'allowlist': false + 'enabled': true + 'name': 'AdMaster 5000 Super List v2.0 Final' + 'num_rules': 36766 + 'refreshed': 1614345496000 + 'uid': 'abcd1234' + 'url': 'https://admaster.example.com/list.txt' + 'properties': + 'num_rules': + 'description': > + Number of rules in this filter. + 'format': 'int64' + 'minimum': 0 + 'type': 'integer' + 'refreshed': + 'description': > + Unix time of last refresh for this filter, in milliseconds. + 'format': 'double' + 'type': 'number' + 'uid': + '$ref': '#/components/schemas/Uid' + 'required': + - 'allowlist' + - 'enabled' + - 'name' + - 'num_rules' + - 'refreshed' + - 'uid' + - 'url' + + 'FilterPatch': + 'description': > + A filter update object. + 'example': + 'enabled': true + 'properties': + 'allowlist': + 'description': > + If `true`, this filter works as an allowlist filters. + 'type': 'boolean' + 'enabled': + 'description': > + If `true`, this filter is applied. + 'type': 'boolean' + 'name': + 'description': > + The name of this filter. + 'type': 'string' + 'url': + 'description': | + A URL of the file containing filtering rules. + + Examples of allowed schemes: + + * `file:///home/user/ads/rules.txt`: A local file. + + * `http://example.com/ads/rules.txt`: Remote list, fetched over + plain HTTP. + + * `https://example.com/ads/rules.txt`: Remote list, fetched over + HTTPS. + 'type': 'string' + 'type': 'object' + + 'FilterPost': + 'allOf': + - '$ref': '#/components/schemas/FilterPatch' + - 'description': > + A filter create object. + 'example': + 'allowlist': false + 'enabled': true + 'name': 'AdMaster 5000 Super List v2.0 Final' + 'url': 'https://admaster.example.com/list.txt' + 'required': + - 'allowlist' + - 'enabled' + - 'name' + - 'url' + + 'FilteringReason': + 'description': > + Request filtering status. + 'enum': + - 'filtered_blocked_service' + - 'filtered_blocklist' + - 'filtered_invalid' + - 'filtered_parental' + - 'filtered_safe_browsing' + - 'filtered_safe_search' + - 'not_filtered_allowlist' + - 'not_filtered_error' + - 'not_filtered_notfound' + - 'rewrite' + - 'rewrite_etc_hosts' + - 'rewrite_rule' + 'type': 'string' + + 'FilteringResultRule': + 'description': > + Applied filtering rule. + 'properties': + 'filter_list_uid': + '$ref': '#/components/schemas/Uid' + 'text': + 'description': > + The text of the filtering rule applied to the request, if any. + 'type': 'string' + 'required': + - 'filter_list_uid' + - 'text' + 'type': 'object' + + 'GetV1AccountsProfileResp': + '$ref': '#/components/schemas/Profile' + + # TODO(a.garipov): Find a way to describe such XML documents using OpenAPI. + # If that is even possible. + 'GetV1AppleDohMobileconfigResp': + 'example': | + + + + + PayloadContent + + + DNSSettings + + DNSProtocol + HTTPS + ServerName + example.com + ServerURL + https://example.com/dns-query/123 + + Name + myexample.local DoH + PayloadDescription + Configures device to use AdGuard Home + PayloadDisplayName + myexample.local DoH + PayloadIdentifier + com.apple.dnsSettings.managed.b6928468-ae3a-4368-a70d-cb7122275013 + PayloadType + com.apple.dnsSettings.managed + PayloadUUID + 18526b8c-6065-4b96-b635-9cde769ac0f2 + PayloadVersion + 1 + + + PayloadDescription + Adds AdGuard Home to Big Sur and iOS 14 or newer systems + PayloadDisplayName + myexample.local DoH + PayloadIdentifier + 9a37b659-7541-4f9e-8b4d-6e2a59a123c8 + PayloadRemovalDisallowed + + PayloadType + Configuration + PayloadUUID + 255dbaf7-0c52-4855-9b22-ad8209690197 + PayloadVersion + 1 + + + 'type': 'object' + + # TODO(a.garipov): See the comment on GetV1AppleDohMobileconfigResp. + 'GetV1AppleDotMobileconfigResp': + 'example': | + + + + + PayloadContent + + + DNSSettings + + DNSProtocol + TLS + ServerName + 123.example.com + + Name + example.com DoT + PayloadDescription + Configures device to use AdGuard Home + PayloadDisplayName + example.com DoT + PayloadIdentifier + com.apple.dnsSettings.managed.7807cb66-c6ec-4c78-be29-d8ffcb3321ee + PayloadType + com.apple.dnsSettings.managed + PayloadUUID + b0fb9137-e27a-4f95-abc3-556103ad9ac1 + PayloadVersion + 1 + + + PayloadDescription + Adds AdGuard Home to Big Sur and iOS 14 or newer systems + PayloadDisplayName + myexample.local DoT + PayloadIdentifier + f1095036-406e-4243-8210-cf0ffa52b3f6 + PayloadRemovalDisallowed + + PayloadType + Configuration + PayloadUUID + 21cd3597-0769-486a-86d0-7b5e32d24305 + PayloadVersion + 1 + + + 'type': 'object' + + 'GetV1ClientsPersistentResp': + 'description': > + Persistent clients. + 'example': + 'clients': + - 'blocked': false + 'blocked_services': [] + 'filtering': false + 'ids': ['client-1'] + 'name': 'Client 1' + 'parental': false + 'safe_browsing': false + 'safe_search': false + 'tags': ['user_admin'] + 'use_global_blocked_services': true + 'use_global_settings': true + 'uid': 'abcd1234' + 'upstream_servers': [] + - 'blocked': false + 'blocked_services': [] + 'filtering': true + 'ids': ['client-2'] + 'name': 'Client 2' + 'parental': true + 'safe_browsing': true + 'safe_search': true + 'tags': ['user_child'] + 'use_global_blocked_services': false + 'use_global_settings': false + 'uid': 'efgh5678' + 'upstream_servers': [] + 'properties': + 'clients': + 'description': > + All persistent clients. + 'items': + '$ref': '#/components/schemas/PersistentClient' + 'type': 'array' + 'required': + - 'clients' + 'type': 'object' + + 'GetV1ClientsRuntimeResp': + 'description': > + Runtime clients. + 'example': + 'clients': + - 'host': 'my-box' + 'ip': '1.2.3.4' + 'num_blocked_requests': 0 + 'num_requests': 100 + 'sources': + - 'arp' + - 'ip': '5.6.7.8' + 'num_blocked_requests': 100 + 'num_requests': 100 + 'sources': + - 'whois' + 'whois': + 'city': 'Minsk' + 'country': 'BY' + 'properties': + 'clients': + 'description': > + All runtime clients. + 'items': + '$ref': '#/components/schemas/RuntimeClient' + 'type': 'array' + 'required': + - 'clients' + 'type': 'object' + + 'GetV1DhcpLeasesResp': + 'description': > + All dynamic and static DHCP leases. + 'example': + 'leases': + - 'expires': 1614345496000 + 'hostname': 'my-mobile' + 'ip': '192.168.1.2' + 'mac': '01:23:45:67:89:ab' + 'uid': 'abcd1234' + - 'expires': 1614345497000 + 'hostname': '' + 'ip': '192.168.1.3' + 'mac': '01:23:45:67:89:cd' + 'properties': + 'leases': + 'description': > + Dynamic and static DHCP leases. + 'items': + '$ref': '#/components/schemas/DhcpLease' + 'type': 'array' + 'required': + - 'leases' + 'type': 'object' + + 'GetV1DhcpStatusResp': + 'description': > + Current DHCP server status and data for enabling it. + 'example': + 'interfaces': + - 'ips': + - '192.168.1.1' + 'mac': '01:23:45:67:89:ab' + 'mtu': 1500 + 'name': 'lan0' + 'up': true + 'ipv4_other_servers': + 'ips': + - '192.169.1.1' + 'ipv4_static_ip': + 'ip': '192.168.1.1' + 'static': true + 'supported': true + 'ipv6_other_servers': + 'ips': [] + 'error': 'permission denied' + 'ipv6_static_ip': + 'ip': '200f::1' + 'static': true + 'supported': true + 'properties': + 'interfaces': + 'description': > + Available network interfaces. + 'items': + '$ref': '#/components/schemas/NetworkInterface' + 'type': 'array' + 'ipv4_other_servers': + '$ref': '#/components/schemas/GetV1DhcpStatusRespOtherServer' + 'ipv4_static_ip': + '$ref': '#/components/schemas/StaticIpCheckResult' + 'ipv6_other_servers': + '$ref': '#/components/schemas/GetV1DhcpStatusRespOtherServer' + 'ipv6_static_ip': + '$ref': '#/components/schemas/StaticIpCheckResult' + 'required': + - 'interfaces' + - 'ipv4_other_servers' + - 'ipv4_static_ip' + - 'ipv6_other_servers' + - 'ipv6_static_ip' + 'type': 'object' + + 'GetV1DhcpStatusRespOtherServer': + 'properties': + 'error': + 'description': > + Error, if any. If there is no error, this field is absent. + 'type': 'string' + 'ips': + 'description': > + IP addresses of other DHCP servers, if found. + 'required': + - 'ips' + 'type': 'object' + + 'GetV1InstallInfoResp': + 'description': > + AdGuard Home addresses configuration. + 'example': + 'dns_port': 53 + 'interfaces': + - 'ips': + - '192.168.1.1' + 'mac': '01:23:45:67:89:ab' + 'mtu': 1500 + 'name': 'lan0' + 'up': true + 'web_port': 80 + 'properties': + 'dns_port': + 'description': > + Recommended DNS port. + 'format': 'int64' + 'maximum': 65535 + 'minimum': 0 + 'type': 'integer' + 'interfaces': + 'description': > + Available network interfaces. + 'items': + '$ref': '#/components/schemas/NetworkInterface' + 'type': 'array' + 'web_port': + 'description': > + Recommended web interface port. + 'format': 'int64' + 'maximum': 65535 + 'minimum': 0 + 'type': 'integer' + 'required': + - 'dns_port' + - 'interfaces' + - 'web_port' + 'type': 'object' + + 'GetV1LogSearchResp': + 'description': > + Query log search results. + 'example': + 'results': + - 'answer': + - 'ttl': 60 + 'type': 'a' + 'value': '5.6.7.8' + 'answer_dnssec': false + 'client': + 'blocked': false + 'ids': + - '1.2.3.4' + - 'user-1' + 'name': 'User 1' + 'num': 100 + 'num_blocked': 50 + 'uid': 'abcd1234' + 'whois': + 'city': 'Minsk' + 'country': 'BY' + 'elapsed': 3.2 + 'proto': 'udp' + 'question': + 'class': 'in' + 'host': 'example.com' + 'type': 'a' + 'rcode': 'noerror' + 'reason': 'not_filtered_notfound' + 'rules': [] + 'start': 1614345496000 + 'upstream': '8.8.8.8' + 'properties': + 'results': + 'description': > + The query log. + 'items': + '$ref': '#/components/schemas/LogRecord' + 'type': 'array' + 'required': + - 'results' + 'type': 'object' + + 'GetV1ProtectionBlockedServicesResp': + '$ref': '#/components/schemas/BlockedServices' + + 'GetV1ProtectionCustomRulesResp': + '$ref': '#/components/schemas/CustomRules' + + 'GetV1ProtectionDnsRewritesResp': + 'description': > + Classic DNS rewrites. + 'example': + 'rules': + - 'answer': 'A' + 'domain': 'example.com' + 'id': 'abcd1234' + - 'answer': '0.0.0.0' + 'domain': '*.example.org' + 'id': 'efgh5678' + - 'answer': 'my.example.net' + 'domain': 'example.net' + 'id': 'ijkl9012' + 'properties': + 'rules': + 'description': > + All classic DNS rewrites. + 'items': + '$ref': '#/components/schemas/DnsRewrite' + 'type': 'array' + 'required': + - 'rules' + 'type': 'object' + + 'GetV1ProtectionFiltersResp': + 'description': > + Filters. + 'example': + 'filters': + - 'allowlist': false + 'enabled': true + 'name': 'AdMaster 5000 Super List v2.0 Final' + 'num_rules': 36766 + 'refreshed': 1614345496000 + 'uid': 'abcd1234' + 'url': 'https://admaster.example.com/list.txt' + - 'allowlist': false + 'enabled': true + 'name': 'My personal list' + 'num_rules': 0 + 'refreshed': 1614345497000 + 'uid': 'efgh5678' + 'url': 'file:///home/user/Documents/ad_list.txt' + 'properties': + 'filters': + 'description': > + All current filters. + 'items': + '$ref': '#/components/schemas/Filter' + 'type': 'array' + 'required': + - 'filters' + 'type': 'object' + + # Perhaps a lot of these belong in separate APIs, but our colleagues asked + # to pack as much data into every request as reasonably possible. + 'GetV1SettingsAllResp': + 'description': > + Most settings. + # Don't add examples, as are provided by the subclasses. + 'properties': + 'dhcp': + '$ref': '#/components/schemas/DhcpSettings' + 'dns': + '$ref': '#/components/schemas/DnsSettings' + 'log': + '$ref': '#/components/schemas/LogSettings' + 'protection': + '$ref': '#/components/schemas/ProtectionSettings' + 'stats': + '$ref': '#/components/schemas/StatsSettings' + 'tls': + '$ref': '#/components/schemas/TlsSettings' + 'required': + - 'dhcp' + - 'dns' + - 'log' + - 'protection' + - 'stats' + - 'tls' + 'type': 'object' + + 'GetV1SettingsDnsAccessResp': + '$ref': '#/components/schemas/DnsAccessSettings' + + # See the comment on the GetV1SettingsAllResp schema. + 'GetV1StatsAllResp': + 'description': > + All statistics. + 'example': + 'dns_cache_hit_rate': 56.7 + 'dns_cache_records': 123 + 'graph_avg_processing': + - 3.0 + - 0.4 + 'graph_blocked_ad_queries': + - 10 + - 20 + 'graph_blocked_custom_rule_queries': + - 10 + - 20 + 'graph_blocked_domains': + - 10 + - 20 + 'graph_blocked_parental_control_queries': + - 10 + - 20 + 'graph_blocked_safe_browsing_queries': + - 10 + - 20 + 'graph_blocked_safe_search_queries': + - 10 + - 20 + 'graph_blocked_service_queries': + - 10 + - 20 + 'graph_blocked_tracker_queries': + - 10 + - 20 + 'graph_cpu_percent': + - 50 + - 75 + 'graph_domains': + - 20 + - 30 + 'graph_queries': + - 1000 + - 2002 + 'graph_ram_resident': + - 1048576 + - 2097152 + 'time_unit': 'hour' + 'top_blocked_domains': + - 'name': 'example.net' + 'num': 100 + 'top_clients': + - 'blocked': false + 'ids': + - '1.2.3.4' + - 'user-1' + 'name': 'User 1' + 'num': 100 + 'num_blocked': 50 + 'uid': 'abcd1234' + 'whois': + 'city': 'Minsk' + 'country': 'BY' + - 'blocked': true + 'ids': + - '5.6.7.8' + 'num': 100 + 'num_blocked': 100 + 'top_domains': + - 'name': 'example.com' + 'num': 1000 + - 'name': 'example.net' + 'num': 100 + 'total_blocked_ad_queries': 100 + 'total_blocked_custom_rule_queries': 10 + 'total_blocked_domains': 500 + 'total_blocked_parental_control_queries': 10 + 'total_blocked_safe_browsing_queries': 10 + 'total_blocked_safe_search_queries': 10 + 'total_blocked_service_queries': 10 + 'total_blocked_tracker_queries': 10 + 'total_domains': 1000 + 'total_queries': 10000 + 'properties': + 'dns_cache_hit_rate': + 'description': > + DNS cache hit rate, in percent. + 'maximum': 100.0 + 'minimum': 0.0 + 'format': 'double' + 'type': 'number' + 'dns_cache_records': + 'description': > + Number of DNS responses currently in cache. + 'minimum': 0 + 'format': 'int64' + 'type': 'integer' + 'graph_avg_processing': + 'description': > + Average DNS query processing duration graph information. Each item + is one `time_unit` long. The duration is in milliseconds. Sorted + by time in descending order. + 'items': + 'format': 'double' + 'type': 'number' + 'type': 'array' + 'graph_blocked_ad_queries': + 'description': > + Number of queries blocked by advertising filters graph information. + Each item is one `time_unit` long. Sorted by time in descending + order. + 'items': + 'format': 'int64' + 'type': 'integer' + 'type': 'array' + 'graph_blocked_custom_rule_queries': + 'description': > + Number of queries blocked by custom filtering rules graph + information. Each item is one `time_unit` long. Sorted by time in + descending order. + 'items': + 'format': 'int64' + 'type': 'integer' + 'type': 'array' + 'graph_blocked_domains': + 'description': > + Blocked queried domains graph information. Each item is one + `time_unit` long. Sorted by time in descending order. + 'items': + 'format': 'int64' + 'type': 'integer' + 'type': 'array' + 'graph_blocked_parental_control_queries': + 'description': > + Number of queries blocked by parental control services graph + information. Each item is one `time_unit` long. Sorted by time in + descending order. + 'items': + 'format': 'int64' + 'type': 'integer' + 'type': 'array' + 'graph_blocked_safe_browsing_queries': + 'description': > + Number of queries blocked by safe browsing services graph + information. Each item is one `time_unit` long. Sorted by time in + descending order. + 'items': + 'format': 'int64' + 'type': 'integer' + 'type': 'array' + 'graph_blocked_safe_search_queries': + 'description': > + Number of queries blocked by safe search services graph information. + Each item is one `time_unit` long. Sorted by time in descending + order. + 'items': + 'format': 'int64' + 'type': 'integer' + 'type': 'array' + 'graph_blocked_service_queries': + 'description': > + Number of queries blocked by blocked service settings graph + information. Each item is one `time_unit` long. Sorted by time in + descending order. + 'items': + 'format': 'int64' + 'type': 'integer' + 'type': 'array' + 'graph_blocked_tracker_queries': + 'description': > + Number of queries blocked by tracker filters graph information. + Each item is one `time_unit` long. Sorted by time in descending + order. + 'items': + 'format': 'int64' + 'type': 'integer' + 'type': 'array' + 'graph_cpu_percent': + 'description': > + CPU usage percentage graph information. Each item is one + `time_unit` long. Sorted by time in descending order. + 'items': + 'format': 'double' + 'type': 'number' + 'type': 'array' + 'graph_domains': + 'description': > + Queried domains graph information. Each item is one `time_unit` + long. Sorted by time in descending order. + 'items': + 'format': 'int64' + 'type': 'integer' + 'type': 'array' + 'graph_queries': + 'description': > + Number of served DNS queries graph information. Each item is one + `time_unit` long. Sorted by time in descending order. + 'items': + 'format': 'int64' + 'type': 'integer' + 'type': 'array' + 'graph_ram_resident': + 'description': > + AdGuard Home's resident memory usage graph information. The size is + in bytes. Each item is one `time_unit` long. Sorted by time in + descending order. + 'items': + 'format': 'int64' + 'type': 'integer' + 'type': 'array' + 'time_unit': + '$ref': '#/components/schemas/TimeUnit' + 'top_blocked_domains': + 'description': > + Top blocked queried domains. Sorted by number in descending order. + 'items': + '$ref': '#/components/schemas/GetV1StatsAllRespTopsItem' + 'type': 'array' + 'top_clients': + 'description': > + Top clients. Sorted by number in descending order. + 'items': + '$ref': '#/components/schemas/ClientInfo' + 'type': 'array' + 'top_domains': + 'description': > + Top queried domains. Sorted by number in descending order. + 'items': + '$ref': '#/components/schemas/GetV1StatsAllRespTopsItem' + 'type': 'array' + 'total_blocked_ad_queries': + 'description': > + Total number of queries blocked by advertising filters. + 'format': 'int64' + 'type': 'integer' + 'total_blocked_custom_rule_queries': + 'description': > + Total number of queries blocked by custom filtering rules. + 'format': 'int64' + 'type': 'integer' + 'total_blocked_domains': + 'description': > + Total number of blocked queried domains. + 'format': 'int64' + 'type': 'integer' + 'total_blocked_parental_control_queries': + 'description': > + Total number of queries blocked by parental control services. + 'format': 'int64' + 'type': 'integer' + 'total_blocked_safe_browsing_queries': + 'description': > + Total number of queries blocked by safe browsing services. + 'format': 'int64' + 'type': 'integer' + 'total_blocked_safe_search_queries': + 'description': > + Total number of queries blocked by safe search services. + 'format': 'int64' + 'type': 'integer' + 'total_blocked_service_queries': + 'description': > + Total number of queries blocked by blocked service settings. + 'format': 'int64' + 'type': 'integer' + 'total_blocked_tracker_queries': + 'description': > + Total number of queries blocked by tracker filters. + 'format': 'int64' + 'type': 'integer' + 'total_domains': + 'description': > + Total number of queried domains. + 'format': 'int64' + 'type': 'integer' + 'total_queries': + 'description': > + Total number of served DNS queries. + 'format': 'int64' + 'type': 'integer' + 'required': + - 'dns_cache_hit_rate' + - 'dns_cache_records' + - 'graph_avg_processing' + - 'graph_blocked_ad_queries' + - 'graph_blocked_custom_rule_queries' + - 'graph_blocked_domains' + - 'graph_blocked_parental_control_queries' + - 'graph_blocked_safe_browsing_queries' + - 'graph_blocked_safe_search_queries' + - 'graph_blocked_service_queries' + - 'graph_blocked_tracker_queries' + - 'graph_cpu_percent' + - 'graph_domains' + - 'graph_queries' + - 'graph_ram_resident' + - 'time_unit' + - 'top_blocked_domains' + - 'top_clients' + - 'top_domains' + - 'total_blocked_ad_queries' + - 'total_blocked_custom_rule_queries' + - 'total_blocked_domains' + - 'total_blocked_parental_control_queries' + - 'total_blocked_safe_browsing_queries' + - 'total_blocked_safe_search_queries' + - 'total_blocked_service_queries' + - 'total_blocked_tracker_queries' + - 'total_domains' + - 'total_queries' + 'type': 'object' + + 'GetV1StatsAllRespTopsItem': + 'description': > + A top array item. + 'properties': + 'name': + 'description': > + The name of the entity. Mostly domain names. + 'example': 'example.com' + 'type': 'string' + 'num': + 'description': > + The value of the statistic. + 'example': 1000 + 'format': 'int64' + 'type': 'integer' + 'required': + - 'name' + - 'num' + 'type': 'object' + + 'GetV1SystemInfoResp': + 'description': > + Information about the AdGuard Home server. + 'example': + 'channel': 'release' + 'new_version': 'v0.106.1' + 'start': 1614345496000 + 'version': 'v0.106.0' + 'properties': + 'channel': + '$ref': '#/components/schemas/Channel' + 'new_version': + 'description': > + New available version of AdGuard Home to which the server can be + updated, if any. If there are none, this field is absent. + 'type': 'string' + 'start': + 'description': > + Unix time at which AdGuard Home started working, in milliseconds. + 'format': 'double' + 'type': 'number' + 'version': + 'description': > + Current AdGuard Home version. + 'type': 'string' + 'required': + - 'channel' + - 'start' + - 'version' + 'type': 'object' + + 'InternalServerErrorResp': + 'example': + 'code': 'RNT000' + 'msg': >- + runtime error: invalid memory address or nil pointer dereference + 'properties': + 'code': + '$ref': '#/components/schemas/ErrorCode' + 'msg': + 'description': > + Error message string. + 'type': 'string' + 'required': + - 'code' + - 'msg' + 'type': 'object' + + 'Lang': + 'description': > + Language code. + # Hold the enum in sync with .twosky.json. + 'enum': + - 'be' + - 'bg' + - 'cs' + - 'da' + - 'de' + - 'en' + - 'es' + - 'fa' + - 'fr' + - 'hr' + - 'hu' + - 'id' + - 'it' + - 'ja' + - 'ko' + - 'nl' + - 'no' + - 'pl' + - 'pt-br' + - 'pt-pt' + - 'ro' + - 'ru' + - 'si-lk' + - 'sk' + - 'sl' + - 'sr-cs' + - 'sv' + - 'th' + - 'tr' + - 'vi' + - 'zh-cn' + - 'zh-hk' + - 'zh-tw' + 'type': 'string' + + 'LogRecord': + 'description': > + Query log record. + 'properties': + 'answer': + 'description': > + The answer given to the user. + 'items': + '$ref': '#/components/schemas/LogRecordDnsAnswer' + 'type': 'array' + 'answer_dnssec': + 'description': > + If `true`, DNSSEC was used. + 'type': 'boolean' + 'blocked_service': + 'description': > + Set if `reason` is `filtered_blocked_service`. Otherwise, this + field is absent. + 'type': 'string' + 'client': + '$ref': '#/components/schemas/ClientInfo' + 'elapsed': + 'description': > + Time it took to process the request, in milliseconds. + 'format': 'double' + 'type': 'number' + 'original_answer': + 'description': > + Original answer from the upstream server, if the answer was + rewritten. + 'items': + '$ref': '#/components/schemas/LogRecordDnsAnswer' + 'type': 'array' + 'proto': + '$ref': '#/components/schemas/DnsProto' + 'question': + '$ref': '#/components/schemas/LogRecordDnsQuestion' + 'rcode': + '$ref': '#/components/schemas/DnsResponseCode' + 'reason': + '$ref': '#/components/schemas/FilteringReason' + 'rules': + 'description': > + Applied rules. + 'items': + '$ref': '#/components/schemas/FilteringResultRule' + 'type': 'array' + 'start': + 'description': > + Request processing start Unix time, in milliseconds. + 'format': 'double' + 'type': 'number' + 'upstream': + '$ref': '#/components/schemas/UpstreamServerAddr' + 'required': + - 'answer' + - 'answer_dnssec' + - 'client' + - 'elapsed' + - 'proto' + - 'question' + - 'rcode' + - 'reason' + - 'rules' + - 'start' + - 'upstream' + 'type': 'object' + + 'LogRecordDnsAnswer': + 'description': > + DNS answer section. + 'properties': + 'ttl': + 'description': > + TTL of a record. This value is in **seconds**, like in DNS record + headers. + 'format': 'int64' + 'minimum': 0 + 'type': 'integer' + 'type': + '$ref': '#/components/schemas/DnsType' + 'value': + 'description': > + An opaque string describing the result value. + 'type': 'string' + 'required': + - 'ttl' + - 'type' + - 'value' + 'type': 'object' + + 'LogRecordDnsQuestion': + 'description': > + DNS question section. + 'properties': + 'class': + '$ref': '#/components/schemas/DnsClass' + 'host': + 'description': > + Host from the query. + 'type': 'string' + 'type': + '$ref': '#/components/schemas/DnsType' + 'required': + - 'class' + - 'host' + - 'type' + 'type': 'object' + + 'LogSettings': + 'allOf': + - '$ref': '#/components/schemas/LogSettingsPatch' + - 'description': > + Query logging settings. + 'example': + 'anonymize': true + 'enabled': true + 'rotation': 604800000 + 'required': + - 'anonymize' + - 'enabled' + - 'rotation' + + 'LogSettingsPatch': + 'description': > + Query logging settings update object. + 'properties': + 'anonymize': + 'description': > + If `true`, client IP address anonymization is enabled. + 'type': 'boolean' + 'enabled': + 'description': > + If `true`, query logging is enabled. + 'type': 'boolean' + 'rotation': + 'description': > + Log rotation interval, in milliseconds. After that time, the log + file will be replaced by a new one, while the old one gets renamed. + 'format': 'double' + 'minimum': 86400000 + 'maximum': 7776000000 + 'type': 'number' + 'type': 'object' + + 'NetworkInterface': + 'properties': + 'ips': + 'description': > + The IP addresses of the interface, if any. + 'items': + 'type': 'string' + 'type': 'array' + 'mac': + 'description': > + The MAC address of the interface. + 'type': 'string' + 'mtu': + 'description': > + The interface's MTU, the maximum transmission unit. + 'format': 'int64' + 'type': 'integer' + 'name': + 'description': > + The name of the interface. + 'type': 'string' + 'up': + 'description': > + If `true`, the interface is up. + 'type': 'boolean' + 'required': + - 'ips' + - 'mac' + - 'mtu' + - 'name' + - 'up' + 'type': 'object' + + 'NotFoundResp': + 'example': + 'code': 'ENT404' + 'msg': >- + entity not found + 'properties': + 'code': + '$ref': '#/components/schemas/ErrorCode' + 'msg': + 'description': > + Error message string. + 'type': 'string' + 'required': + - 'code' + - 'msg' + 'type': 'object' + + 'PatchV1AccountsProfileReq': + 'example': + 'lang': 'ru' + 'properties': + 'lang': + '$ref': '#/components/schemas/Lang' + 'type': 'object' + + 'PatchV1AccountsProfileResp': + '$ref': '#/components/schemas/Profile' + + 'PatchV1ClientPersistentReq': + '$ref': '#/components/schemas/PersistentClientPatch' + + 'PatchV1ClientPersistentResp': + '$ref': '#/components/schemas/PersistentClient' + + 'PatchV1DhcpLeaseReq': + '$ref': '#/components/schemas/DhcpLeasePatch' + + 'PatchV1DhcpLeaseResp': + '$ref': '#/components/schemas/DhcpLease' + + 'PatchV1ProtectionFilterReq': + '$ref': '#/components/schemas/FilterPatch' + + 'PatchV1ProtectionFilterResp': + '$ref': '#/components/schemas/Filter' + + 'PatchV1SettingsDhcpReq': + '$ref': '#/components/schemas/DhcpSettingsPatch' + + 'PatchV1SettingsDhcpResp': + '$ref': '#/components/schemas/DhcpSettings' + + 'PatchV1SettingsDnsReq': + '$ref': '#/components/schemas/DnsSettingsPatch' + + 'PatchV1SettingsDnsResp': + '$ref': '#/components/schemas/DnsSettings' + + 'PatchV1SettingsLogReq': + '$ref': '#/components/schemas/LogSettingsPatch' + + 'PatchV1SettingsLogResp': + '$ref': '#/components/schemas/LogSettings' + + 'PatchV1SettingsProtectionReq': + '$ref': '#/components/schemas/ProtectionSettingsPatch' + + 'PatchV1SettingsProtectionResp': + '$ref': '#/components/schemas/ProtectionSettings' + + 'PatchV1SettingsStatsReq': + '$ref': '#/components/schemas/StatsSettingsPatch' + + 'PatchV1SettingsStatsResp': + '$ref': '#/components/schemas/StatsSettings' + + 'PatchV1SettingsTlsReq': + '$ref': '#/components/schemas/TlsSettingsPatch' + + 'PatchV1SettingsTlsResp': + '$ref': '#/components/schemas/TlsSettings' + + 'PersistentClient': + 'allOf': + - '$ref': '#/components/schemas/PersistentClientPatch' + - 'description': > + Persistent client. + 'example': + 'blocked': false + 'blocked_services': [] + 'filtering': false + 'ids': ['client-1'] + 'name': 'Client 1' + 'num_blocked_requests': 50 + 'num_requests': 100 + 'parental': false + 'safe_browsing': false + 'safe_search': false + 'tags': ['user_admin'] + 'use_global_blocked_services': true + 'use_global_settings': true + 'uid': 'abcd1234' + 'upstream_servers': [] + 'properties': + 'num_blocked_requests': + 'description': > + Total number of blocked requests for this runtime client. + 'format': 'int64' + 'minimum': 0 + 'type': 'integer' + 'num_requests': + 'description': > + Total number of requests for this runtime client. + 'format': 'int64' + 'minimum': 0 + 'type': 'integer' + 'uid': + '$ref': '#/components/schemas/Uid' + 'required': + - 'blocked' + - 'blocked_services' + - 'filtering' + - 'ids' + - 'name' + - 'parental' + - 'safe_browsing' + - 'safe_search' + - 'tags' + - 'uid' + - 'upstream_servers' + - 'use_global_blocked_services' + - 'use_global_settings' + + 'PersistentClientPatch': + 'description': > + Persistent client update object. + 'example': + 'filtering': false + 'parental': false + 'safe_browsing': false + 'safe_search': false + 'tags': ['user_admin'] + 'properties': + 'blocked': + 'description': > + If `true`, the client is blocked. + 'type': 'boolean' + 'blocked_services': + 'description': > + Custom blocked services for this client. + 'items': + '$ref': '#/components/schemas/BlockedServiceId' + 'type': 'array' + 'filtering': + 'description': > + If `true`, filtering based on filter rule lists is enabled for this + client. + 'type': 'boolean' + 'ids': + 'description': > + IP, CIDR, MAC, or ClientID (not to be confused with the `uid` field) + for client identification. + 'items': + 'type': 'string' + 'type': 'array' + 'name': + 'description': > + The name of this client. + 'type': 'string' + 'parental': + 'description': > + If `true`, parental protection is enabled for this client. + 'type': 'boolean' + 'safe_browsing': + 'description': > + If `true`, safe browsing protection is enabled for this client. + 'type': 'boolean' + 'safe_search': + 'description': > + If `true`, safe search protection is enabled for this client. + 'type': 'boolean' + 'tags': + 'description': > + Client tags. + 'items': + '$ref': '#/components/schemas/PersistentClientTag' + 'type': 'array' + 'use_global_blocked_services': + 'description': > + If `true`, use global blocked services for this client instead of + the custom ones. + 'type': 'boolean' + 'use_global_settings': + 'description': > + If `true`, use global protection settings for this client instead of + the custom ones. + 'type': 'boolean' + 'upstream_servers': + 'description': > + Custom upstream DNS servers for this client. + 'items': + '$ref': '#/components/schemas/UpstreamServerAddr' + 'type': 'array' + 'type': 'object' + + 'PersistentClientPost': + 'allOf': + - '$ref': '#/components/schemas/PersistentClientPatch' + - 'description': > + Persistent client create object. + 'example': + 'blocked': false + 'blocked_services': [] + 'filtering': false + 'ids': ['client-1'] + 'name': 'Client 1' + 'parental': false + 'safe_browsing': false + 'safe_search': false + 'tags': ['user_admin'] + 'use_global_blocked_services': true + 'use_global_settings': true + 'upstream_servers': [] + 'required': + - 'blocked' + - 'blocked_services' + - 'filtering' + - 'ids' + - 'name' + - 'parental' + - 'safe_browsing' + - 'safe_search' + - 'tags' + - 'upstream_servers' + - 'use_global_blocked_services' + - 'use_global_settings' + + 'PersistentClientTag': + 'description': > + Tags can be included in filtering rules to allow you to apply them more + accurately. + 'enum': + - 'device_audio' + - 'device_camera' + - 'device_gameconsole' + - 'device_laptop' + - 'device_nas' + - 'device_other' + - 'device_pc' + - 'device_phone' + - 'device_printer' + - 'device_securityalarm' + - 'device_tablet' + - 'device_tv' + - 'os_android' + - 'os_ios' + - 'os_linux' + - 'os_macos' + - 'os_other' + - 'os_windows' + - 'user_admin' + - 'user_child' + - 'user_regular' + 'type': 'string' + + 'PostV1AccountsSessionReq': + 'example': + 'password': 'G00dp455word!' + 'username': 'admin' + 'properties': + 'password': + 'description': > + Password. + 'format': 'password' + 'type': 'string' + 'username': + 'description': > + Username. + 'type': 'string' + 'required': + - 'password' + - 'username' + 'type': 'object' + + 'PostV1ClientsPersistentReq': + '$ref': '#/components/schemas/PersistentClientPost' + + 'PostV1ClientsPersistentResp': + '$ref': '#/components/schemas/PersistentClient' + + 'PostV1DhcpLeasesReq': + '$ref': '#/components/schemas/DhcpLeasePost' + + 'PostV1DhcpLeasesResp': + '$ref': '#/components/schemas/DhcpLease' + + 'PostV1InstallCheckReq': + 'description': > + Configuration for checking. + 'example': + 'dns': + 'ip': + - '0.0.0.0' + 'port': 53 + 'static_ip': false + 'web': + 'ip': + - '0.0.0.0' + 'port': 80 + 'properties': + 'dns': + '$ref': '#/components/schemas/PostV1InstallCheckReqServer' + 'static_ip': + 'description': > + If `true`, check if a static IP is set or can be set. + 'type': 'boolean' + 'web': + '$ref': '#/components/schemas/PostV1InstallCheckReqServer' + 'required': + - 'dns' + - 'static_ip' + - 'web' + 'type': 'object' + + 'PostV1InstallCheckReqServer': + 'description': > + A configuration for a server check. + 'properties': + 'ip': + 'description': > + IP addresses to check for availability. + 'items': + 'type': 'string' + 'minItems': 1 + 'type': 'array' + 'port': + 'description': > + Port to check for availability. + 'format': 'int64' + 'maximum': 65535 + 'minimum': 0 + 'type': 'integer' + 'required': + - 'ip' + - 'port' + 'type': 'object' + + 'PostV1InstallCheckResp': + 'description': > + Configuration checking response. + 'example': + 'dns': + 'error': 'permission denied' + 'static_ip': + 'ip': '192.168.1.1' + 'static': true + 'supported': true + 'web': {} + 'properties': + 'dns': + '$ref': '#/components/schemas/PostV1InstallCheckRespNetwork' + 'static_ip': + '$ref': '#/components/schemas/StaticIpCheckResult' + 'web': + '$ref': '#/components/schemas/PostV1InstallCheckRespNetwork' + 'required': + - 'dns' + - 'static_ip' + - 'web' + 'type': 'object' + + 'PostV1InstallCheckRespNetwork': + 'properties': + 'error': + 'description': > + Error, if any. If there is no error, this field is absent. + 'type': 'string' + 'type': 'object' + + 'PostV1InstallConfigureReq': + 'description': > + AdGuard Home initial configuration. + 'example': + 'dns_ip': '0.0.0.0' + 'dns_port': 53 + 'password': 'G00dp455word!' + 'username': 'admin' + 'set_static_ip': true + 'web_ip': '0.0.0.0' + 'web_port': 80 + 'properties': + 'dns_ip': + 'description': > + The IP address to serve DNS queries on. + 'type': 'string' + 'dns_port': + 'description': > + The port to serve DNS queries on. + 'format': 'int64' + 'maximum': 65535 + 'minimum': 0 + 'type': 'integer' + 'password': + 'description': > + Password. + 'type': 'string' + 'username': + 'description': > + Username. + 'type': 'string' + 'set_static_ip': + 'description': > + If `true`, set the server's IP address to static. + 'type': 'boolean' + 'web_ip': + 'description': > + The IP address to serve the web interface on. + 'type': 'string' + 'web_port': + 'description': > + The port to serve the web interface on. + 'format': 'int64' + 'maximum': 65535 + 'minimum': 0 + 'type': 'integer' + 'required': + - 'dns_ip' + - 'dns_port' + - 'password' + - 'username' + - 'set_static_ip' + - 'web_ip' + - 'web_port' + 'type': 'object' + + 'PostV1LogClearReq': + 'description': > + Currently empty, may get more fields in the future. + 'type': 'object' + + 'PostV1ProtectionCheckCustomRulesReq': + 'description': > + Data to check using custom filtering rules. + 'example': + 'host': 'example.com' + 'properties': + 'host': + 'description': > + The hostname to check. + 'type': 'string' + 'required': + - 'host' + 'type': 'object' + + 'PostV1ProtectionCheckCustomRulesResp': + 'description': > + Custom filtering rules check results. + 'example': + 'reason': 'filtered_blocklist' + 'rules': + - 'filter_list_uid': 'abcd1234' + 'text': '||example.com^' + 'properties': + 'cname': + 'description': > + Set if `reason` is `Rewrite`. Otherwise, this field is absent. + 'type': 'string' + 'ip_addrs': + 'description': > + Set if `reason` is `Rewrite`. Otherwise, this field is absent. + 'items': + 'type': 'string' + 'type': 'array' + 'reason': + '$ref': '#/components/schemas/FilteringReason' + 'rules': + 'description': > + Applied rules. + 'items': + '$ref': '#/components/schemas/FilteringResultRule' + 'type': 'array' + 'service_name': + 'description': > + Set if `reason` is `FilteredBlockedService`. Otherwise, this field + is absent. + 'type': 'string' + 'required': + - 'reason' + - 'rules' + 'type': 'object' + + 'PostV1ProtectionDnsRewritesReq': + '$ref': '#/components/schemas/DnsRewritePost' + + 'PostV1ProtectionDnsRewritesResp': + '$ref': '#/components/schemas/DnsRewrite' + + 'PostV1ProtectionFiltersReq': + '$ref': '#/components/schemas/FilterPost' + + 'PostV1ProtectionFiltersResp': + '$ref': '#/components/schemas/Filter' + + 'PostV1ProtectionRefreshFilterReq': + 'description': > + Currently empty, may get more fields in the future. + 'type': 'object' + + 'PostV1ProtectionRefreshFilterResp': + '$ref': '#/components/schemas/Filter' + + 'PostV1ProtectionRefreshFiltersReq': + 'description': > + Filters refresh parameters. + 'example': + 'allowlist': false + 'blocklist': true + 'properties': + 'allowlist': + 'description': > + If `true`, refresh all allowlist filters. + 'type': 'boolean' + 'blocklist': + 'description': > + If `true`, refresh all blocklist filters. + 'type': 'boolean' + 'required': + - 'allowlist' + - 'blocklist' + 'type': 'object' + + 'PostV1ProtectionRefreshFiltersResp': + 'description': > + Refresh results. + 'example': + 'errors': + - 'msg': 'context deadline exceeded' + 'uid': 'efgh5678' + 'refreshed': + - 'allowlist': false + 'enabled': true + 'name': 'AdMaster 5000 Super List v2.0 Final' + 'num_rules': 36766 + 'refreshed': 1614345496000 + 'uid': 'abcd1234' + 'url': 'https://admaster.example.com/list.txt' + 'properties': + 'errors': + 'description': > + All encountered errors. + 'items': + '$ref': '#/components/schemas/RefreshFilterError' + 'type': 'array' + 'refreshed': + 'description': > + Refreshed filters. + 'items': + '$ref': '#/components/schemas/Filter' + 'type': 'array' + 'required': + - 'errors' + - 'refreshed' + 'type': 'object' + + 'PostV1SettingsDnsCheckReq': + 'description': > + Validatable DNS settings. + 'example': + 'bootstrap_servers': + - '9.9.9.10' + - '149.112.112.10' + 'upstream_servers': + - '1.1.1.1' + - '8.8.8.8' + 'properties': + 'bootstrap_servers': + 'description': | + Bootstrap DNS servers' IP addresses to check. + 'items': + 'type': 'string' + 'type': 'array' + 'upstream_servers': + 'description': > + Upstream DNS servers to check. + 'items': + '$ref': '#/components/schemas/UpstreamServerAddr' + 'type': 'array' + 'required': + - 'bootstrap_servers' + - 'upstream_servers' + 'type': 'object' + + 'PostV1SettingsDnsCheckResp': + 'description': > + DNS settings validation results. + 'example': + 'bootstrap_servers': + '9.9.9.10': 'network is unreachable' + 'upstream_servers': + '8.8.8.8': 'network is unreachable' + 'properties': + 'bootstrap_servers': + 'additionalProperties': + 'minLength': 1 + 'type': 'string' + 'description': > + An IP-address-to-error mapping. If an address is not in this + object, the check for that address is successful. If there were no + errors, this field is absent. + 'upstream_servers': + 'additionalProperties': + 'type': 'string' + 'description': > + An upstream-address-to-error mapping. If an address is not in this + object, the check for that address is successful. If there were no + errors, this field is absent. + 'type': 'object' + + 'PostV1SettingsTlsCheckReq': + 'description': > + Validatable TLS settings. + 'example': + 'certificate_path': '/etc/ssl/example.com.cert' + 'port_dns_over_quic': 784 + 'port_dns_over_tls': 853 + 'port_https': 443 + 'private_key_path': '/etc/ssl/example.com.key' + 'server_name': 'dns.example.com' + 'properties': + 'certificate': + 'description': | + Base64-encoded string with PEM-encoded certificate chain. + + Should not be sent if `certificate_path` is sent. Otherwise, must + be sent. + 'format': 'byte' + 'type': 'string' + 'certificate_path': + 'description': | + Path to the certificate file. + + Should not be sent if `certificate` is sent. Otherwise, must be + sent. + 'type': 'string' + 'port_dns_over_quic': + 'default': 784 + 'description': > + The DNS-over-QUIC port. If `0`, DNS-over-QUIC is disabled. + 'format': 'int64' + 'maximum': 65535 + 'minimum': 0 + 'type': 'integer' + 'port_dns_over_tls': + 'default': 853 + 'description': > + The DNS-over-TLS port. If `0`, DNS-over-TLS is disabled. + 'format': 'int64' + 'maximum': 65535 + 'minimum': 0 + 'type': 'integer' + 'port_https': + 'default': 443 + 'description': > + The HTTPS port. If `0`, HTTPS is disabled. + 'format': 'int64' + 'maximum': 65535 + 'minimum': 0 + 'type': 'integer' + 'private_key': + 'description': | + Base64-encoded string with PEM-encoded private key. + + Should not be sent if `private_key_path` is sent. Otherwise, must + be sent. + 'format': 'byte' + 'type': 'string' + 'private_key_path': + 'description': | + Path to the private key file. + + Should not be sent if `private_key` is sent. Otherwise, must be + sent. + 'type': 'string' + 'server_name': + 'description': > + The name of the server. Used to validate the certificates as well + as to check ClientIDs in DNS-over-HTTP and DNS-over-TLS. + 'type': 'string' + 'required': + - 'port_dns_over_quic' + - 'port_dns_over_tls' + - 'port_https' + - 'server_name' + 'type': 'object' + + 'PostV1SettingsTlsCheckResp': + 'description': > + TLS settings validation results. + 'example': + 'dns_names': + - '*.example.com' + - 'example.com' + 'issuer': 'CN=Example CA,OU=Development,O=Example CA,L=Canberra,ST=Canberra,C=AU' + 'key_type': 'RSA' + 'not_after': 1614345497000 + 'not_before': 1614345496000 + 'port_https_error': 'address already in use' + 'subject': 'CN=Example CA,OU=Development,O=Example CA,L=Canberra,ST=Canberra,C=AU' + 'warnings': [] + 'properties': + 'cert_error': + 'description': > + Certificate validation error, if any. If the certificate is valid, + this field is absent. + 'type': 'string' + 'chain_error': + 'description': > + Certificate chain validation error, if any. If the certificate + chain is valid, this field is absent. + 'type': 'string' + 'dns_names': + 'description': > + The value of the `SubjectAltNames` field of the first certificate in + the chain. + 'items': + 'type': 'string' + 'type': 'array' + 'issuer': + 'description': > + The issuer of the first certificate in the chain. + 'type': 'string' + 'key_error': + 'description': > + Private key pair error, if any. If the key is valid, this field is + absent. + 'type': 'string' + 'key_type': + '$ref': '#/components/schemas/TlsKeyType' + 'not_after': + 'description': > + The value of the `NotAfter` field of the first certificate in the + chain, as a Unix time, in milliseconds. + 'format': 'double' + 'type': 'number' + 'not_before': + 'description': > + The value of the `NotBefore` field of the first certificate in the + chain, as a Unix time, in milliseconds. + 'format': 'double' + 'type': 'number' + 'port_dns_over_quic_error': + 'description': > + DNS-over-QUIC port checking error, if any. If the port is + available, this field is absent. + 'type': 'string' + 'port_dns_over_tls_error': + 'description': > + DNS-over-TLS port checking error, if any. If the port is available, + this field is absent. + 'type': 'string' + 'port_https_error': + 'description': > + DNS-over-HTTPS port checking error, if any. If the port is + available, this field is absent. + 'type': 'string' + 'pair_error': + 'description': > + Certificate and key pair error, if any. If the pair is valid, this + field is absent. + 'type': 'string' + 'subject': + 'description': > + The subject of the first certificate in the chain. + 'type': 'string' + 'warnings': + 'description': > + Validation warnings, if any. + 'items': + 'type': 'string' + 'type': 'array' + 'required': + - 'dns_names' + - 'issuer' + - 'key_type' + - 'not_after' + - 'not_before' + - 'subject' + - 'warnings' + 'type': 'object' + + 'PostV1StatsClearReq': + 'description': > + Currently empty, may get more fields in the future. + 'type': 'object' + + 'PostV1SystemResetReq': + 'description': > + Currently empty, may get more fields in the future. + 'type': 'object' + + 'PostV1SystemResetResp': + 'description': > + Currently empty, may get more fields in the future. + 'type': 'object' + + 'PostV1SystemUpdateReq': + 'description': > + Currently empty, may get more fields in the future. + 'type': 'object' + + 'PostV1SystemUpdateResp': + 'example': + 'reload': 10000 + 'properties': + 'reload': + 'description': > + Time, after which the frontend must reload the page, in + milliseconds. + 'format': 'double' + 'type': 'number' + 'type': 'object' + + 'Profile': + 'description': > + Current user's profile. + 'example': + 'lang': 'en' + 'username': 'admin' + 'properties': + 'lang': + '$ref': '#/components/schemas/Lang' + 'username': + 'description': > + Current user's name. + 'type': 'string' + 'required': + - 'lang' + - 'username' + 'type': 'object' + + 'ProtectionSettings': + 'allOf': + - '$ref': '#/components/schemas/ProtectionSettingsPatch' + - 'description': > + Protection settings. + 'example': + 'autoupdate': 86400000 + 'filtering': true + 'parental': true + 'safe_browsing': false + 'safe_search': false + 'required': + - 'autoupdate' + - 'filtering' + - 'parental' + - 'safe_browsing' + - 'safe_search' + + 'ProtectionSettingsPatch': + 'description': > + Protection settings update object. + 'example': + 'autoupdate': 0 + 'properties': + 'autoupdate': + 'description': > + Filter automatic update interval, in milliseconds. Set to `0` to + disable automatic updates. + 'format': 'double' + 'minimum': 0 + 'maximum': 604800000 + 'type': 'number' + 'filtering': + 'description': > + If `true`, filtering based on filter rule lists is enabled. + 'type': 'boolean' + 'parental': + 'description': > + If `true`, parental protection is enabled. + 'type': 'boolean' + 'pause_end': + 'description': | + If `state` is `paused`, `pause_end` will show the Unix time until + which the protection is disabled in milliseconds. Otherwise, the + property won't be set. + + When updating, if `state` is set to `paused`, `pause_end` must be + set to a timestamp in the future. + 'format': 'double' + 'type': 'number' + 'safe_browsing': + 'description': > + If `true`, safe browsing protection is enabled. + 'type': 'boolean' + 'safe_search': + 'description': > + If `true`, safe search protection is enabled. + 'type': 'boolean' + 'state': + '$ref': '#/components/schemas/ProtectionSettingsState' + 'type': 'object' + + 'ProtectionSettingsState': + 'description': | + State of protection. + + * `off`: Protection is disabled. + + * `on`: Protection is enabled. + + * `paused`: Protection is paused. See the `pause_end` property to get + or set the end of the pause. + 'enum': + - 'off' + - 'on' + - 'paused' + 'type': 'string' + + 'PutV1ProtectionBlockedServicesReq': + '$ref': '#/components/schemas/BlockedServices' + + 'PutV1ProtectionCustomRulesReq': + '$ref': '#/components/schemas/CustomRules' + + 'PutV1SettingsDnsAccessReq': + '$ref': '#/components/schemas/DnsAccessSettings' + + 'RefreshFilterError': + 'description': > + Filter refresh error. + 'properties': + 'msg': + 'description': > + Error message. + 'type': 'string' + 'uid': + '$ref': '#/components/schemas/Uid' + 'required': + - 'msg' + - 'uid' + 'type': 'object' + + 'RuntimeClient': + 'description': > + A runtime client's information. + 'properties': + 'host': + 'description': > + The RDNS host of the runtime, if any. If there is none, this field + is absent. + 'type': 'string' + 'ip': + 'description': > + The IP-address of the runtime client. + 'type': 'string' + 'sources': + 'description': > + The sources from which the information about this runtime client was + collected. + 'items': + '$ref': '#/components/schemas/RuntimeClientSource' + 'minItems': 1 + 'type': 'array' + 'num_blocked_requests': + 'description': > + Total number of blocked requests for this runtime client. + 'format': 'int64' + 'minimum': 0 + 'type': 'integer' + 'num_requests': + 'description': > + Total number of requests for this runtime client. + 'format': 'int64' + 'minimum': 0 + 'type': 'integer' + 'whois': + '$ref': '#/components/schemas/Whois' + 'required': + - 'ip' + - 'num_blocked_requests' + - 'num_requests' + - 'sources' + 'type': 'object' + + 'RuntimeClientSource': + 'description': > + The source from which the information about this runtime client was + collected. + + * `arp`: The information was collected from the `arp -a` output. + + * `dhcp`: The information was collected from our DHCP server. + + * `hosts_file`: The information was collected from the `/etc/hosts` + file. + + * `rdns`: The information was collected by performing a reverse DNS + lookup. + + * `whois`: The information was collected by performing a WHOIS lookup. + 'enum': + - 'arp' + - 'dhcp' + - 'hosts_file' + - 'rdns' + - 'whois' + 'type': 'string' + + 'StaticIpCheckResult': + 'properties': + 'error': + 'description': > + Error, if any. If there is no error, this field is absent. + 'type': 'string' + 'ip': + 'description': > + The IP address. + 'type': 'string' + 'static': + 'description': > + If `true`, the interface has a static IP address. + 'type': 'boolean' + 'supported': + 'description': > + If `true`, setting a static IP on this system is supported. + 'type': 'boolean' + 'required': + - 'ip' + - 'static' + - 'supported' + 'type': 'object' + + 'StatsSettings': + 'allOf': + - '$ref': '#/components/schemas/StatsSettingsPatch' + - 'description': > + Statistics settings. + 'required': + - 'autorefresh' + - 'retention' + + 'StatsSettingsPatch': + 'description': > + Statistics settings update object. + 'properties': + 'autorefresh': + 'description': > + Statistics UI autorefresh time in milliseconds. `0` means + autorefresh is disabled. + 'format': 'double' + 'type': 'number' + 'retention': + 'description': > + Statistics retention interval, in milliseconds. + 'format': 'double' + 'type': 'number' + 'type': 'object' + + 'TimeUnit': + 'description': > + Time units used for statistics. See the documentation for the + `GET /api/v1/stats/all` request. + 'enum': + - 'hour' + - 'day' + 'type': 'string' + + 'TlsKeyType': + 'description': > + TLS key type. + 'enum': + - 'ECDSA' + - 'RSA' + 'type': 'string' + + 'TlsSettings': + 'allOf': + - '$ref': '#/components/schemas/TlsSettingsPatch' + - 'description': > + TLS and encryption settings. + 'example': + 'certificate_path': '/etc/ssl/example.com.cert' + 'enabled': true + 'force_https': true + 'port_dns_over_quic': 784 + 'port_dns_over_tls': 853 + 'port_https': 443 + 'private_key_path': '/etc/ssl/example.com.key' + 'server_name': 'dns.example.com' + 'required': + - 'enabled' + - 'force_https' + - 'port_dns_over_quic' + - 'port_dns_over_tls' + - 'port_https' + - 'server_name' + + 'TlsSettingsPatch': + 'description': > + TLS and encryption settings update object. + 'example': + 'certificate': 'Base64KeyDatAA==' + 'enabled': true + 'private_key': 'Base64CertDatA==' + 'properties': + 'certificate': + 'description': | + Base64-encoded string with PEM-encoded certificate chain. + + Should not be sent if `certificate_path` is sent. Otherwise, must + be sent. + 'format': 'byte' + 'type': 'string' + 'certificate_path': + 'description': | + Path to the certificate file. + + Should not be sent if `certificate` is sent. Otherwise, must be + sent. + 'type': 'string' + 'enabled': + 'description': > + If `true`, AdGuard Home the administration interface will be served + over HTTPS, and the DNS server will listen requests over + DNS-over-TLS and other protocols. + 'type': 'boolean' + 'force_https': + 'description': > + If `true`, enabled the HTTP-to-HTTPS redirect. + 'type': 'boolean' + 'port_dns_over_quic': + 'default': 784 + 'description': > + The DNS-over-QUIC port. If `0`, DNS-over-QUIC is disabled. + 'format': 'int64' + 'maximum': 65535 + 'minimum': 0 + 'type': 'integer' + 'port_dns_over_tls': + 'default': 853 + 'description': > + The DNS-over-TLS port. If `0`, DNS-over-TLS is disabled. + 'format': 'int64' + 'maximum': 65535 + 'minimum': 0 + 'type': 'integer' + 'port_https': + 'default': 443 + 'description': > + The HTTPS port. If `0`, HTTPS is disabled. + 'format': 'int64' + 'maximum': 65535 + 'minimum': 0 + 'type': 'integer' + 'private_key': + 'description': | + Base64-encoded string with PEM-encoded private key. + + Should not be sent if `private_key_path` is sent. Otherwise, must + be sent. + 'format': 'byte' + 'type': 'string' + 'private_key_path': + 'description': | + Path to the private key file. + + Should not be sent if `private_key` is sent. Otherwise, must be + sent. + 'type': 'string' + 'server_name': + 'description': > + The name of the server. Used to validate the certificates as well + as to check ClientIDs in DNS-over-HTTP and DNS-over-TLS. + 'type': 'string' + 'type': 'object' + + 'Uid': + 'description': > + A unique ID of an entity, an opaque string. + 'pattern': '[0-9a-zA-Z_-]{1,64}' + 'type': 'string' + + 'UnauthorizedResp': + 'example': + 'code': 'AUT000' + 'msg': 'no or bad authorization provided' + 'properties': + 'code': + '$ref': '#/components/schemas/ErrorCode' + 'msg': + 'description': > + Error message string. + 'type': 'string' + 'required': + - 'code' + - 'msg' + 'type': 'object' + + 'UnprocessableEntityResp': + 'example': + 'code': 'JSN001' + 'msg': >- + json: cannot unmarshal string into Go struct field T.A of type int + 'properties': + 'code': + '$ref': '#/components/schemas/ErrorCode' + 'msg': + 'description': > + Error message string. + 'type': 'string' + 'required': + - 'code' + - 'msg' + 'type': 'object' + + 'UpstreamServerAddr': + 'description': | + Upstream DNS server address. Supported item formats: + + * `94.140.14.140`: plain DNS-over-UDP. + + * `tls://dns-unfiltered.adguard.com`: encrypted DNS-over-TLS. + + * `https://dns-unfiltered.adguard.com/dns-query`: encrypted + DNS-over-HTTPS. + + * `quic://dns-unfiltered.adguard.com:784`: encrypted DNS-over-QUIC + (experimental). + + * `tcp://94.140.14.140`: plain DNS-over-TCP. + + * `sdns://...`: DNS Stamps for DNSCrypt or DNS-over-HTTPS + resolvers. + + * `[/example.local/]94.140.14.140`: DNS upstream for specific + domain(s). + + * `# comment`: A comment. + 'type': 'string' + + 'Whois': + 'additionalProperties': + 'type': 'string' + 'description': > + WHOIS information, if any. If there are none, this field is usually + absent. + 'minProperties': 1 + 'type': 'object' + + # TODO(a.garipov): Find a way to specify a cookie authorization. + 'securitySchemes': + 'basicAuth': + 'description': > + Basic HTTP authorization. + 'scheme': 'basic' + 'type': 'http' diff --git a/scripts/make/go-build.sh b/scripts/make/go-build.sh index 7854166c..c998a611 100644 --- a/scripts/make/go-build.sh +++ b/scripts/make/go-build.sh @@ -123,4 +123,14 @@ CGO_ENABLED="$cgo_enabled" GO111MODULE='on' export CGO_ENABLED GO111MODULE -"$go" build --ldflags "$ldflags" "$race_flags" --trimpath "$o_flags" "$v_flags" "$x_flags" +# Build the new binary if requested. +if [ "${V1API:-0}" -eq '0' ] +then + tags_flags='--tags=' +else + tags_flags='--tags=v1' +fi +readonly tags_flags + +"$go" build --ldflags "$ldflags" "$race_flags" "$tags_flags" --trimpath "$o_flags" "$v_flags"\ + "$x_flags" diff --git a/scripts/make/go-lint.sh b/scripts/make/go-lint.sh index c363e513..df2f297a 100644 --- a/scripts/make/go-lint.sh +++ b/scripts/make/go-lint.sh @@ -140,6 +140,7 @@ underscores() { -e '_others.go'\ -e '_test.go'\ -e '_unix.go'\ + -e '_v1.go'\ -e '_windows.go' \ -v\ | sed -e 's/./\t\0/' @@ -222,7 +223,7 @@ gocyclo --over 17 ./internal/dhcpd/ ./internal/dnsforward/\ # Apply stricter standards to new or somewhat refactored code. gocyclo --over 10 ./internal/aghio/ ./internal/aghnet/ ./internal/aghos/\ ./internal/aghtest/ ./internal/stats/ ./internal/tools/\ - ./internal/updater/ ./internal/version/ ./main.go + ./internal/updater/ ./internal/v1/ ./internal/version/ ./main.go\ ineffassign ./... From c4ff80fd3aa070b75bcfc02b0aaf6b5670fddefe Mon Sep 17 00:00:00 2001 From: Dimitry Kolyshev Date: Wed, 27 Apr 2022 11:39:48 +0300 Subject: [PATCH 036/110] Pull request: dnsforward: ddr support Merge in DNS/adguard-home from 4463-ddr-support-1 to master Squashed commit of the following: commit 74d8337a9d78e00a0b01301bbf92054fc58aff0d Merge: 7882c56e ed449c61 Author: Dimitry Kolyshev Date: Wed Apr 27 10:32:48 2022 +0200 Merge remote-tracking branch 'origin/master' into 4463-ddr-support-1 commit 7882c56eced204b99a0189c839f5b5ef56fcbfd8 Author: Dimitry Kolyshev Date: Tue Apr 26 13:29:16 2022 +0200 all: docs commit 59593cf47f8db2131fb8a4a44ec3721de8f73567 Author: Dimitry Kolyshev Date: Tue Apr 26 13:06:49 2022 +0200 all: docs commit 13bfe00d91b190a2538eeee642ce40abe031ecf2 Author: Dimitry Kolyshev Date: Tue Apr 26 12:58:48 2022 +0200 all: docs commit a663b53d211483a717a480e24e120a201dc3d9da Merge: 53122f6a 235316e0 Author: Dimitry Kolyshev Date: Tue Apr 26 12:33:07 2022 +0200 Merge remote-tracking branch 'origin/master' into 4463-ddr-support-1 commit 53122f6aac8e9ede69de833e367e006f4c5c75c0 Author: Dimitry Kolyshev Date: Tue Apr 26 12:30:56 2022 +0200 dnsforward: ddr support commit 87083ded02c120e1fb3e54b885a1992efd8f780d Author: Dimitry Kolyshev Date: Tue Apr 26 11:51:06 2022 +0200 dnsforward: ddr support commit 3dc711e0a9ba1a024e7d24527b2a690aa36413ce Author: Dimitry Kolyshev Date: Tue Apr 26 11:39:59 2022 +0200 dnsforward: imp code commit f63f6a9d65a96960ae2c06aeca2b32aef70d8f63 Author: Dimitry Kolyshev Date: Tue Apr 26 11:34:23 2022 +0200 dnsforward: ddr support commit e64ffcdac8f9428e4c93a6dc99cc3f1bb090af35 Author: Dimitry Kolyshev Date: Tue Apr 26 11:22:20 2022 +0200 dnsforward: ddr support commit 297460946bb1765137c7c3fe3e298cd574635287 Author: Dimitry Kolyshev Date: Tue Apr 26 11:08:59 2022 +0200 dnsforward: imp code commit 61b4e2e0e06e212c31b7a9d1b09fab392ae6dbc4 Author: Dimitry Kolyshev Date: Mon Apr 25 14:39:34 2022 +0200 dnsforward: ddr support commit 7c2787e12eb67a02b41cbb4fe36a12671259f9c9 Author: Dimitry Kolyshev Date: Mon Apr 25 11:41:42 2022 +0200 all: docs commit 29c2c872843f6d006e6a98144a52e23a4cbe7be9 Author: Dimitry Kolyshev Date: Mon Apr 25 11:26:07 2022 +0200 dnsforward: ddr support commit 2d4ba0c4ce4fbbf3d99da8dd92349da2ec9cff13 Author: Dimitry Kolyshev Date: Mon Apr 25 11:03:34 2022 +0200 dnsforward: ddr support commit 0efb5b5cd55bcba3dfae35e80209277f0643a87e Author: Dimitry Kolyshev Date: Sun Apr 24 13:07:25 2022 +0200 dnsforward: imp code commit 884381ef04029d5d743834555cb6601d891c2d25 Author: Dimitry Kolyshev Date: Sun Apr 24 12:56:41 2022 +0200 dnsforward: imp code commit 41231f24e83a9690d36546e83fd61ddd709050ed Author: Dimitry Kolyshev Date: Fri Apr 22 16:05:47 2022 +0200 dnsforward: ddr support commit 9d9da3f479efa5d5609f9b1e6b0d1a93fc253b9f Author: Dimitry Kolyshev Date: Fri Apr 22 13:46:29 2022 +0200 all: ddr support commit b225363df143d599e9acbf1a6b0bf6d00044dd47 Author: Dimitry Kolyshev Date: Fri Apr 22 13:38:27 2022 +0200 dnsforward: imp code ... and 10 more commits --- CHANGELOG.md | 5 +- internal/dnsforward/config.go | 3 +- internal/dnsforward/dns.go | 76 +++++++++++++++++ internal/dnsforward/dns_test.go | 146 ++++++++++++++++++++++++++++++++ internal/home/config.go | 1 + 5 files changed, 229 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 047726ff..84f45312 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ and this project adheres to ### Added +- Support for Discovery of Designated Resolvers (DDR) according to the + [RFC draft][ddr-draft-06] ([#4463]). - The ability to control each source of runtime clients separately via `clients.runtime_sources` configuration object ([#3020]). - The ability to customize the set of networks that are considered private @@ -143,8 +145,9 @@ In this release, the schema version has changed from 12 to 14. [#4276]: https://github.com/AdguardTeam/AdGuardHome/issues/4276 [#4499]: https://github.com/AdguardTeam/AdGuardHome/issues/4499 -[repr]: https://reproducible-builds.org/docs/source-date-epoch/ +[ddr-draft-06]: https://www.ietf.org/archive/id/draft-ietf-add-ddr-06.html [doq-draft-10]: https://datatracker.ietf.org/doc/html/draft-ietf-dprive-dnsoquic-10#section-10.2 +[repr]: https://reproducible-builds.org/docs/source-date-epoch/ diff --git a/internal/dnsforward/config.go b/internal/dnsforward/config.go index 9a050f52..16a6325e 100644 --- a/internal/dnsforward/config.go +++ b/internal/dnsforward/config.go @@ -122,6 +122,7 @@ type FilteringConfig struct { EnableDNSSEC bool `yaml:"enable_dnssec"` // Set AD flag in outcoming DNS request EnableEDNSClientSubnet bool `yaml:"edns_client_subnet"` // Enable EDNS Client Subnet option MaxGoroutines uint32 `yaml:"max_goroutines"` // Max. number of parallel goroutines for processing incoming requests + HandleDDR bool `yaml:"handle_ddr"` // Handle DDR requests // IpsetList is the ipset configuration that allows AdGuard Home to add // IP addresses of the specified domain names to an ipset list. Syntax: @@ -151,7 +152,7 @@ type TLSConfig struct { PrivateKeyData []byte `yaml:"-" json:"-"` // ServerName is the hostname of the server. Currently, it is only being - // used for ClientID checking. + // used for ClientID checking and Discovery of Designated Resolvers (DDR). ServerName string `yaml:"-" json:"-"` cert tls.Certificate diff --git a/internal/dnsforward/dns.go b/internal/dnsforward/dns.go index d423482a..19d54d91 100644 --- a/internal/dnsforward/dns.go +++ b/internal/dnsforward/dns.go @@ -76,6 +76,10 @@ const ( resultCodeError ) +// ddrHostFQDN is the FQDN used in Discovery of Designated Resolvers (DDR) requests. +// See https://www.ietf.org/archive/id/draft-ietf-add-ddr-06.html. +const ddrHostFQDN = "_dns.resolver.arpa." + // handleDNSRequest filters the incoming DNS requests and writes them to the query log func (s *Server) handleDNSRequest(_ *proxy.Proxy, d *proxy.DNSContext) error { ctx := &dnsContext{ @@ -94,6 +98,7 @@ func (s *Server) handleDNSRequest(_ *proxy.Proxy, d *proxy.DNSContext) error { mods := []modProcessFunc{ s.processRecursion, s.processInitial, + s.processDDRQuery, s.processDetermineLocal, s.processInternalHosts, s.processRestrictLocal, @@ -241,6 +246,77 @@ func (s *Server) onDHCPLeaseChanged(flags int) { s.setTableIPToHost(ipToHost) } +// processDDRQuery responds to SVCB query for a special use domain name +// ‘_dns.resolver.arpa’. The result contains different types of encryption +// supported by current user configuration. +// +// See https://www.ietf.org/archive/id/draft-ietf-add-ddr-06.html. +func (s *Server) processDDRQuery(ctx *dnsContext) (rc resultCode) { + d := ctx.proxyCtx + question := d.Req.Question[0] + + if !s.conf.HandleDDR { + return resultCodeSuccess + } + + if question.Name == ddrHostFQDN { + // TODO(a.garipov): Check DoQ support in next RFC drafts. + if s.dnsProxy.TLSListenAddr == nil && s.dnsProxy.HTTPSListenAddr == nil || + question.Qtype != dns.TypeSVCB { + d.Res = s.makeResponse(d.Req) + + return resultCodeFinish + } + + d.Res = s.makeDDRResponse(d.Req) + + return resultCodeFinish + } + + return resultCodeSuccess +} + +// makeDDRResponse creates DDR answer according to server configuration. +func (s *Server) makeDDRResponse(req *dns.Msg) (resp *dns.Msg) { + resp = s.makeResponse(req) + domainName := s.conf.ServerName + + for _, addr := range s.dnsProxy.HTTPSListenAddr { + values := []dns.SVCBKeyValue{ + &dns.SVCBAlpn{Alpn: []string{"h2"}}, + &dns.SVCBPort{Port: uint16(addr.Port)}, + &dns.SVCBDoHPath{Template: "/dns-query?dns"}, + } + + ans := &dns.SVCB{ + Hdr: s.hdr(req, dns.TypeSVCB), + Priority: 1, + Target: domainName, + Value: values, + } + + resp.Answer = append(resp.Answer, ans) + } + + for _, addr := range s.dnsProxy.TLSListenAddr { + values := []dns.SVCBKeyValue{ + &dns.SVCBAlpn{Alpn: []string{"dot"}}, + &dns.SVCBPort{Port: uint16(addr.Port)}, + } + + ans := &dns.SVCB{ + Hdr: s.hdr(req, dns.TypeSVCB), + Priority: 2, + Target: domainName, + Value: values, + } + + resp.Answer = append(resp.Answer, ans) + } + + return resp +} + // processDetermineLocal determines if the client's IP address is from // locally-served network and saves the result into the context. func (s *Server) processDetermineLocal(dctx *dnsContext) (rc resultCode) { diff --git a/internal/dnsforward/dns_test.go b/internal/dnsforward/dns_test.go index 54104268..8ab7501c 100644 --- a/internal/dnsforward/dns_test.go +++ b/internal/dnsforward/dns_test.go @@ -14,6 +14,152 @@ import ( "github.com/stretchr/testify/require" ) +const ddrTestDomainName = "dns.example.net" + +func TestServer_ProcessDDRQuery(t *testing.T) { + dohSVCB := &dns.SVCB{ + Priority: 1, + Target: ddrTestDomainName, + Value: []dns.SVCBKeyValue{ + &dns.SVCBAlpn{Alpn: []string{"h2"}}, + &dns.SVCBPort{Port: 8044}, + &dns.SVCBDoHPath{Template: "/dns-query?dns"}, + }, + } + + dotSVCB := &dns.SVCB{ + Priority: 2, + Target: ddrTestDomainName, + Value: []dns.SVCBKeyValue{ + &dns.SVCBAlpn{Alpn: []string{"dot"}}, + &dns.SVCBPort{Port: 8043}, + }, + } + + testCases := []struct { + name string + host string + want []*dns.SVCB + wantRes resultCode + portDoH int + portDoT int + qtype uint16 + ddrEnabled bool + }{{ + name: "pass_host", + wantRes: resultCodeSuccess, + host: "example.net.", + qtype: dns.TypeSVCB, + ddrEnabled: true, + portDoH: 8043, + }, { + name: "pass_qtype", + wantRes: resultCodeFinish, + host: ddrHostFQDN, + qtype: dns.TypeA, + ddrEnabled: true, + portDoH: 8043, + }, { + name: "pass_disabled_tls", + wantRes: resultCodeFinish, + host: ddrHostFQDN, + qtype: dns.TypeSVCB, + ddrEnabled: true, + }, { + name: "pass_disabled_ddr", + wantRes: resultCodeSuccess, + host: ddrHostFQDN, + qtype: dns.TypeSVCB, + ddrEnabled: false, + portDoH: 8043, + }, { + name: "dot", + wantRes: resultCodeFinish, + want: []*dns.SVCB{dotSVCB}, + host: ddrHostFQDN, + qtype: dns.TypeSVCB, + ddrEnabled: true, + portDoT: 8043, + }, { + name: "doh", + wantRes: resultCodeFinish, + want: []*dns.SVCB{dohSVCB}, + host: ddrHostFQDN, + qtype: dns.TypeSVCB, + ddrEnabled: true, + portDoH: 8044, + }, { + name: "dot_doh", + wantRes: resultCodeFinish, + want: []*dns.SVCB{dotSVCB, dohSVCB}, + host: ddrHostFQDN, + qtype: dns.TypeSVCB, + ddrEnabled: true, + portDoT: 8043, + portDoH: 8044, + }} + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + s := prepareTestServer(t, tc.portDoH, tc.portDoT, tc.ddrEnabled) + + req := createTestMessageWithType(tc.host, tc.qtype) + + dctx := &dnsContext{ + proxyCtx: &proxy.DNSContext{ + Req: req, + }, + } + + res := s.processDDRQuery(dctx) + require.Equal(t, tc.wantRes, res) + + if tc.wantRes != resultCodeFinish { + return + } + + msg := dctx.proxyCtx.Res + require.NotNil(t, msg) + + for _, v := range tc.want { + v.Hdr = s.hdr(req, dns.TypeSVCB) + } + + assert.ElementsMatch(t, tc.want, msg.Answer) + }) + } +} + +func prepareTestServer(t *testing.T, portDoH, portDoT int, ddrEnabled bool) (s *Server) { + t.Helper() + + proxyConf := proxy.Config{} + + if portDoH > 0 { + proxyConf.HTTPSListenAddr = []*net.TCPAddr{{Port: portDoH}} + } + + if portDoT > 0 { + proxyConf.TLSListenAddr = []*net.TCPAddr{{Port: portDoT}} + } + + s = &Server{ + dnsProxy: &proxy.Proxy{ + Config: proxyConf, + }, + conf: ServerConfig{ + FilteringConfig: FilteringConfig{ + HandleDDR: ddrEnabled, + }, + TLSConfig: TLSConfig{ + ServerName: ddrTestDomainName, + }, + }, + } + + return s +} + func TestServer_ProcessDetermineLocal(t *testing.T) { s := &Server{ privateNets: netutil.SubnetSetFunc(netutil.IsLocallyServed), diff --git a/internal/home/config.go b/internal/home/config.go index 720683a1..14f5781e 100644 --- a/internal/home/config.go +++ b/internal/home/config.go @@ -187,6 +187,7 @@ var config = &configuration{ Ratelimit: 20, RefuseAny: true, AllServers: false, + HandleDDR: true, FastestTimeout: timeutil.Duration{ Duration: fastip.DefaultPingWaitTimeout, }, From 5d52e68d264b77dd27ac53616027e6a26637c6e8 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Wed, 27 Apr 2022 14:06:10 +0300 Subject: [PATCH 037/110] Pull request: home: imp client finding logging Updates #4526. Squashed commit of the following: commit 970476ea238cbab797912e1c50eca35e3f74a52f Merge: 3e2dde81 c4ff80fd Author: Ainar Garipov Date: Wed Apr 27 14:01:17 2022 +0300 Merge branch 'master' into 4526-add-client-logs commit 3e2dde81d7325b75c257f333e2c4e417f4ae203d Author: Ainar Garipov Date: Wed Apr 27 13:59:19 2022 +0300 home: imp logs commit 094bfe34770b4bdc504b5ae97dd2d3842b2f73cf Author: Ainar Garipov Date: Tue Apr 26 21:11:18 2022 +0300 home: imp client finding logging --- internal/home/dns.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/internal/home/dns.go b/internal/home/dns.go index e28193ee..1c04c6c3 100644 --- a/internal/home/dns.go +++ b/internal/home/dns.go @@ -330,24 +330,28 @@ func getDNSEncryption() (de dnsEncryption) { // applyAdditionalFiltering adds additional client information and settings if // the client has them. -func applyAdditionalFiltering(clientAddr net.IP, clientID string, setts *filtering.Settings) { +func applyAdditionalFiltering(clientIP net.IP, clientID string, setts *filtering.Settings) { Context.dnsFilter.ApplyBlockedServices(setts, nil, true) - if clientAddr == nil { + log.Debug("looking up settings for client with ip %s and clientid %q", clientIP, clientID) + + if clientIP == nil { return } - setts.ClientIP = clientAddr + setts.ClientIP = clientIP c, ok := Context.clients.Find(clientID) if !ok { - c, ok = Context.clients.Find(clientAddr.String()) + c, ok = Context.clients.Find(clientIP.String()) if !ok { + log.Debug("client with ip %s and clientid %q not found", clientIP, clientID) + return } } - log.Debug("using settings for client %s with ip %s and clientid %q", c.Name, clientAddr, clientID) + log.Debug("using settings for client %q with ip %s and clientid %q", c.Name, clientIP, clientID) if c.UseOwnBlockedServices { Context.dnsFilter.ApplyBlockedServices(setts, c.BlockedServices, false) From 6dc9e73ce4d8bdc01ed3b99facc7d4062288a760 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Wed, 27 Apr 2022 14:18:50 +0300 Subject: [PATCH 038/110] Pull request: client: upd i18n Merge in DNS/adguard-home from upd-i18n to master Squashed commit of the following: commit 0e0a3290a02780b147aacff529c4ba3bd3ace68f Author: Ainar Garipov Date: Wed Apr 27 14:13:24 2022 +0300 client: upd i18n --- client/src/__locales/cs.json | 4 ++-- client/src/__locales/da.json | 4 ++-- client/src/__locales/de.json | 16 ++++++++-------- client/src/__locales/es.json | 4 ++-- client/src/__locales/fi.json | 2 +- client/src/__locales/nl.json | 2 +- client/src/__locales/ro.json | 18 +++++++++--------- client/src/__locales/tr.json | 20 ++++++++++---------- client/src/__locales/uk.json | 22 +++++++++++----------- client/src/__locales/zh-cn.json | 23 +++++++++++------------ client/src/__locales/zh-tw.json | 2 +- 11 files changed, 58 insertions(+), 59 deletions(-) diff --git a/client/src/__locales/cs.json b/client/src/__locales/cs.json index 26759394..8331dd50 100644 --- a/client/src/__locales/cs.json +++ b/client/src/__locales/cs.json @@ -9,7 +9,7 @@ "bootstrap_dns": "Bootstrap DNS servery", "bootstrap_dns_desc": "Servery Bootstrap DNS se používají k řešení IP adres DoH/DoT, které zadáváte jako upstreamy.", "local_ptr_title": "Soukromé reverzní DNS servery", - "local_ptr_desc": "Servery DNS, které AdGuard Home používá pro lokální dotazy PTR. Tyto servery se používají k rozlišení názvů hostitelů klientů se soukromými adresami IP, například \"192.168.12.34\" pomocí rDNS. Pokud není nastaveno, AdGuard Home automaticky použije výchozí řešitele vašeho OS s výjimkou adres samotného AdGuard Home.", + "local_ptr_desc": "Servery DNS, které AdGuard Home používá pro lokální dotazy PTR. Tyto servery se používají k řešení požadavků PTR na adresy v soukromých rozmezích IP, například \"192.168.12.34\", pomocí reverzního DNS. Pokud není nastaveno, AdGuard Home automaticky použije výchozí řešitele vašeho OS s výjimkou adres samotného AdGuard Home.", "local_ptr_default_resolver": "Ve výchozím nastavení používá AdGuard Home následující reverzní DNS řešitele: {{ip}}.", "local_ptr_no_default_resolver": "AdGuard Home nemohl určit vhodné soukromé reverzní DNS řešitele pro tento systém.", "local_ptr_placeholder": "Zadejte jednu adresu serveru na řádek", @@ -283,7 +283,7 @@ "download_mobileconfig_doh": "Stáhnout .mobileconfig pro DNS skrze HTTPS", "download_mobileconfig_dot": "Stáhnout .mobileconfig pro DNS skrze TLS", "download_mobileconfig": "Stáhnout konfigurační soubor", - "plain_dns": "Čisté DNS", + "plain_dns": "Běžný DNS", "form_enter_rate_limit": "Zadejte rychlostní limit", "rate_limit": "Rychlostní limit", "edns_enable": "Povolit klientskou podsíť EDNS", diff --git a/client/src/__locales/da.json b/client/src/__locales/da.json index 1b12ad06..4b077cf8 100644 --- a/client/src/__locales/da.json +++ b/client/src/__locales/da.json @@ -9,7 +9,7 @@ "bootstrap_dns": "Bootstrap DNS-servere", "bootstrap_dns_desc": "Bootstrap DNS-servere bruges til at fortolke IP-adresser for de DoH-/DoT-resolvere, du angiver som upstream.", "local_ptr_title": "Private reverse DNS-servere", - "local_ptr_desc": "De DNS-servere, som AdGuard Home bruger til lokale PTR-forespørgsler. Disse servere bruges til at opløse klientværtsnavne med private IP-adresser, f.eks. \"192.168.12.34\", vha. rDNS. Hvis ikke indstillet, bruger AdGuard Home dit operativsystems standard DNS-opløsere undtagen for sine egne adresser.", + "local_ptr_desc": "DNS-servere brugt af AdGuard Home til lokale PTR-forespørgsler. Disse servere bruges til at opløse PTR-forespørgsler fra private IP-adresseområder, f.eks. \"192.168.12.34\", vha. reverse DNS. Hvis ikke opsat, bruger AdGuard Home operativsystems standard DNS-opløsere undtagen for sine egne adresser.", "local_ptr_default_resolver": "AdGuard Home bruger som standard flg. reverse DNS-opløsere: {{ip}}.", "local_ptr_no_default_resolver": "AdGuard Home kunne ikke fastslå egnede private reverse DNS-opløsere for dette system.", "local_ptr_placeholder": "Indtast en serveradresse pr. Linje", @@ -351,7 +351,7 @@ "install_devices_android_list_5": "Skift de aktuelle DNS 1- og DNS 2-værdier til dine AdGuard Home-serveradresser.", "install_devices_ios_list_1": "Tryk på Indstillinger på Hjem-skærmen.", "install_devices_ios_list_2": "Vælg Wi-Fi i menuen til venstre (det er umuligt at opsætte DNS for mobilnetværker).", - "install_devices_ios_list_3": "Tryk på navnet på det aktuelt aktive netværk.", + "install_devices_ios_list_3": "Tryk på navnet for det aktuelt aktive netværk.", "install_devices_ios_list_4": "Angiv dine AdGuard Home-serveradresser i DNS-feltet.", "get_started": "Komme I Gang", "next": "Næste", diff --git a/client/src/__locales/de.json b/client/src/__locales/de.json index be5666a8..0fe6345d 100644 --- a/client/src/__locales/de.json +++ b/client/src/__locales/de.json @@ -149,9 +149,9 @@ "general_settings": "Allgemeine Einstellungen", "dns_settings": "DNS-Einstellungen", "dns_blocklists": "DNS-Sperrliste", - "dns_allowlists": "DNS-Freigabelisten", + "dns_allowlists": "DNS-Positivlisten", "dns_blocklists_desc": "AdGuard Home sperrt Domains, die in den Sperrlisten enthalten sind.", - "dns_allowlists_desc": "Domains aus DNS-Freigabelisten werden auch dann zugelassen, wenn sie in einer der Sperrlisten enthalten sind.", + "dns_allowlists_desc": "Domains aus DNS-Positivlisten werden auch dann zugelassen, wenn sie in einer der Sperrlisten enthalten sind.", "custom_filtering_rules": "Benutzerdefinierte Filterregeln", "encryption_settings": "Verschlüsselungseinstellungen", "dhcp_settings": "DHCP-Einstellungen", @@ -181,21 +181,21 @@ "elapsed": "Verstrichen", "filters_and_hosts_hint": "AdGuard Home versteht grundlegende Werbefilterregeln und Host-Datei-Syntax.", "no_blocklist_added": "Keine Sperrliste hinzugefügt", - "no_whitelist_added": "Keine Freigabeliste hinzugefügt", + "no_whitelist_added": "Keine Positivliste hinzugefügt", "add_blocklist": "Sperrliste hinzufügen", - "add_allowlist": "Freigabeliste hinzufügen", + "add_allowlist": "Positivliste hinzufügen", "cancel_btn": "Abbrechen", "enter_name_hint": "Name eingeben", "enter_url_or_path_hint": "URL oder absoluten Pfad der Liste eingeben", "check_updates_btn": "Nach Aktualisierungen suchen", "new_blocklist": "Neue Sperrliste", - "new_allowlist": "Neue Freigabeliste", + "new_allowlist": "Neue Positivliste", "edit_blocklist": "Sperrliste bearbeiten", - "edit_allowlist": "Freigabeliste bearbeiten", + "edit_allowlist": "Positivliste bearbeiten", "choose_blocklist": "Sperrliste wählen", - "choose_allowlist": "Freigabeliste wählen", + "choose_allowlist": "Positivliste wählen", "enter_valid_blocklist": "Gültige Webadresse zur Sperrliste eingeben.", - "enter_valid_allowlist": "Gültige Webadresse zur Freigabeliste eingeben.", + "enter_valid_allowlist": "Gültige Webadresse zur Positivliste eingeben.", "form_error_url_format": "Ungültiges URL-Format", "form_error_url_or_path_format": "Ungültige URL oder absoluter Pfad der Liste", "custom_filter_rules": "Benutzerdefinierte Filterregeln", diff --git a/client/src/__locales/es.json b/client/src/__locales/es.json index a83527ed..e495c81d 100644 --- a/client/src/__locales/es.json +++ b/client/src/__locales/es.json @@ -9,7 +9,7 @@ "bootstrap_dns": "Servidores DNS de arranque", "bootstrap_dns_desc": "Los servidores DNS de arranque se utilizan para resolver las direcciones IP de los resolutores DoH/DoT que especifiques como DNS de subida.", "local_ptr_title": "Servidores DNS inversos y privados", - "local_ptr_desc": "Los servidores DNS que AdGuard Home utiliza para las consultas PTR locales. Estos servidores se utilizan para resolver los nombres de hosts de los clientes a direcciones IP privadas, por ejemplo \"192.168.12.34\", utilizando DNS inverso. Si no está establecido, AdGuard Home utilizará los resolutores DNS predeterminados de tu sistema operativo, excepto las direcciones del propio AdGuard Home.", + "local_ptr_desc": "Los servidores DNS que AdGuard Home utiliza para las consultas PTR locales. Estos servidores se utilizan para resolver las peticiones PTR de direcciones en rangos de IP privadas, por ejemplo \"192.168.12.34\", utilizando DNS inverso. Si no está establecido, AdGuard Home utilizará los resolutores DNS predeterminados de tu sistema operativo, excepto las direcciones del propio AdGuard Home.", "local_ptr_default_resolver": "Por defecto, AdGuard Home utiliza los siguientes resolutores DNS inversos: {{ip}}.", "local_ptr_no_default_resolver": "AdGuard Home no pudo determinar los resolutores DNS inversos y privados adecuados para este sistema.", "local_ptr_placeholder": "Ingresa una dirección de servidor por línea", @@ -351,7 +351,7 @@ "install_devices_android_list_5": "Cambia los valores de DNS 1 y DNS 2 a las direcciones de tu servidor AdGuard Home.", "install_devices_ios_list_1": "En la pantalla de inicio, pulsa en Configuración.", "install_devices_ios_list_2": "Elige Wi-Fi en el menú de la izquierda (es imposible configurar DNS para redes móviles).", - "install_devices_ios_list_3": "Pulsa sobre el nombre de la red activa en ese momento.", + "install_devices_ios_list_3": "Pulsa sobre el nombre de la red actualmente activa.", "install_devices_ios_list_4": "En el campo DNS ingresa las direcciones de tu servidor AdGuard Home.", "get_started": "Comenzar", "next": "Siguiente", diff --git a/client/src/__locales/fi.json b/client/src/__locales/fi.json index 5e6c8089..3141b12a 100644 --- a/client/src/__locales/fi.json +++ b/client/src/__locales/fi.json @@ -338,7 +338,7 @@ "install_devices_windows_list_2": "Avaa \"Verkko ja Internet\" -ryhmä ja sitten \"Verkko ja jakamiskeskus\".", "install_devices_windows_list_3": "Paina ikkunan vasemmasta laidasta \"Muuta sovittimen asetuksia\".", "install_devices_windows_list_4": "Paina aktiivista yhteyttäsi hiiren kakkospainikkeella ja valitse \"Ominaisuudet\".", - "install_devices_windows_list_5": "Etsi listasta \"Internet protokolla versio 4 (TCP/IP)\", valitse se ja paina jälleen \"Ominaisuudet\".", + "install_devices_windows_list_5": "Etsi listasta \"Internet Protocol Version 4 (TCP/IPv4)\" (tai IPv6:lle \"Internet Protocol Version 6 (TCP/IPv6)\"), valitse se ja paina jälleen \"Ominaisuudet\".", "install_devices_windows_list_6": "Valitse \"Käytä seuraavia DNS-palvelinten osoitteita\" ja syötä AdGuard Home -palvelimesi osoitteet.", "install_devices_macos_list_1": "Paina Omena-kuvaketta ja valitse \"Järjestelmäasetukset\".", "install_devices_macos_list_2": "Paina \"Verkko\".", diff --git a/client/src/__locales/nl.json b/client/src/__locales/nl.json index 7fc19d73..83278ee3 100644 --- a/client/src/__locales/nl.json +++ b/client/src/__locales/nl.json @@ -9,7 +9,7 @@ "bootstrap_dns": "Bootstrap DNS-servers", "bootstrap_dns_desc": "Bootstrap DNS-servers worden gebruikt om IP-adressen op te lossen van de DoH / DoT-resolvers die u opgeeft als upstreams.", "local_ptr_title": "Private omgekeerde DNS-servers", - "local_ptr_desc": "De DNS-servers die AdGuard Home zal gebruiken voor lokale PTR zoekopdrachten. Deze server wordt gebruikt om de hostnamen van de clients met private IP-adressen, bijvoorbeeld \"192.168.12.34\", dmv. rDNS. Indien niet ingesteld, gebruikt AdGuard Home automatisch je standaard DNS-resolver.", + "local_ptr_desc": "De DNS-servers die AdGuard Home gebruikt voor lokale PTR-zoekopdrachten. Deze servers worden gebruikt om PTR-verzoeken voor adressen in privé-IP-bereiken op te lossen, bijvoorbeeld \"192.168.12.34\", met behulp van reverse DNS. Indien niet ingesteld, gebruikt AdGuard Home de adressen van de standaard DNS-resolvers van uw besturingssysteem, behalve de adressen van AdGuard Home zelf.", "local_ptr_default_resolver": "Standaard gebruikt AdGuard Home de volgende omgekeerde DNS-resolvers: {{ip}}.", "local_ptr_no_default_resolver": "AdGuard Home kon voor dit systeem geen geschikte private omgekeerde DNS-resolvers bepalen.", "local_ptr_placeholder": "Voer één serveradres per regel in", diff --git a/client/src/__locales/ro.json b/client/src/__locales/ro.json index b19b8576..097dba59 100644 --- a/client/src/__locales/ro.json +++ b/client/src/__locales/ro.json @@ -7,15 +7,15 @@ "load_balancing": "Echilibrare-sarcini", "load_balancing_desc": "Interoghează câte un server în amonte la un moment dat. AdGuard Home utilizează un algoritm de randomizare ponderat pentru a alege serverul, astfel încât cel mai rapid server să fie utilizat mai des.", "bootstrap_dns": "Serverele DNS Bootstrap", - "bootstrap_dns_desc": "Serverele DNS Bootstrap sunt folosite pentru a rezolva adresele IP ale resolverelor DoH/DoT indicate ca upstreams.", + "bootstrap_dns_desc": "Serverele DNS Bootstrap sunt folosite pentru a rezolva adresele IP ale rezolvatorilor DoH/DoT indicați ca upstreams.", "local_ptr_title": "Servere DNS inverse private", - "local_ptr_desc": "Servere DNS pe care AdGuard Home le utilizează pentru interogări PTR locale. Aceste servere sunt folosite pentru a rezolva numele gazdelor de clienți cu adrese IP private, cum ar fi \"192.168.12.34\", folosind DNS inversat. Dacă nu este setat, AdGuard Home utilizează adresele resolverelor DNS implicite ale SO al dvs., cu excepția adreselor AdGuard Home înseși.", - "local_ptr_default_resolver": "În mod implicit, AdGuard Home utilizează următoarele resolvere DNS inverse: {{ip}}.", - "local_ptr_no_default_resolver": "AdGuard Home nu a putut determina resolvere DNS private adecvate pentru acest sistem.", + "local_ptr_desc": "Serverele DNS pe care AdGuard Home le utilizează pentru interogările PTR locale. Aceste servere sunt utilizate pentru a rezolva solicitările PTR pentru adrese din intervale IP private, de exemplu „192.168.12.34”, utilizând DNS invers. Dacă nu este configurat, AdGuard Home utilizează adresele rezolvatorilor DNS impliciți ai sistemului dvs. de operare, cu excepția adreselor AdGuard Home în sine.", + "local_ptr_default_resolver": "În mod implicit, AdGuard Home utilizează următorii rezolvatori DNS inverși: {{ip}}.", + "local_ptr_no_default_resolver": "AdGuard Home nu a putut determina rezolvatorii DNS privați adecvați pentru acest sistem.", "local_ptr_placeholder": "Introduceți o adresă de server per linie", "resolve_clients_title": "Permiteți rezolvarea inversa a adreselor IP ale clienților", - "resolve_clients_desc": "Rezolvă invers adresele IP ale clienților în numele lor de gazde prin trimiterea interogărilor PTR la resolverele corespunzătoare (servere DNS private pentru clienți locali, servere în amonte pentru clienți cu adrese IP publice).", - "use_private_ptr_resolvers_title": "Utilizați resolvere DNS inverse private", + "resolve_clients_desc": "Rezolvă invers adresele IP ale clienților în numele lor de gazde prin trimiterea interogărilor PTR la rezolvatorii corespunzători (servere DNS private pentru clienți locali, servere în amonte pentru clienți cu adrese IP publice).", + "use_private_ptr_resolvers_title": "Utilizați rezolvatori DNS inverși privați", "use_private_ptr_resolvers_desc": "Efectuează examinări DNS inverse pentru adresele deservite local folosind aceste servere în amonte. Dacă este dezactivată, AdGuard Home răspunde cu NXDOMAIN la toate aceste cereri PTR, cu excepția clienților cunoscuți din DHCP, /etc/hosts și așa mai departe.", "check_dhcp_servers": "Căutați servere DHCP", "save_config": "Salvare configurare", @@ -214,7 +214,7 @@ "example_upstream_dot": "<0>DNS-over-TLS criptat;", "example_upstream_doh": "<0>DNS-over-HTTPS criptat;", "example_upstream_doq": "<0>DNS-over-QUIC criptat (experimental);", - "example_upstream_sdns": "<0>DNS Stamps pentru <1>DNSCrypt sau rezolvere <2>DNS-over-HTTPS;", + "example_upstream_sdns": "<0>DNS Stamps pentru <1>DNSCrypt sau rezolvatori <2>DNS-over-HTTPS;", "example_upstream_tcp": "DNS clasic (over TCP);", "example_upstream_tcp_hostname": "DNS obișnuit (over TCP, nume de gazdă);", "all_lists_up_to_date_toast": "Toate listele sunt deja la zi", @@ -351,7 +351,7 @@ "install_devices_android_list_5": "Schimbați valorile DNS 1 și DNS 2 la adresele serverului dvs. AdGuard Home.", "install_devices_ios_list_1": "Din ecranul de start, tapați Setări.", "install_devices_ios_list_2": "Alegeți Wi-Fi în meniul din stânga (este imposibil să configurați DNS pentru rețelele mobile).", - "install_devices_ios_list_3": "Tapați numele rețelei active curente.", + "install_devices_ios_list_3": "Apăsați pe numele rețelei active în prezent.", "install_devices_ios_list_4": "În câmpul DNS, introduceți adresele serverului dvs. AdGuard Home.", "get_started": "Să începem", "next": "Următor", @@ -585,7 +585,7 @@ "list_updated": "{{count}} listă actualizată", "list_updated_plural": "{{count}} liste actualizate", "dnssec_enable": "Activați DNSSEC", - "dnssec_enable_desc": "Activați semnalul DNSSEC în interogările DNS de ieșire și verificați rezultatul (este necesar un resolver compatibil DNSSEC).", + "dnssec_enable_desc": "Activați semnalul DNSSEC în interogările DNS de ieșire și verificați rezultatul (este necesar un rezolvator compatibil DNSSEC).", "validated_with_dnssec": "Validat cu DNSSEC", "all_queries": "Toate interogările", "show_blocked_responses": "Blocat", diff --git a/client/src/__locales/tr.json b/client/src/__locales/tr.json index 74dedd8b..f26e0011 100644 --- a/client/src/__locales/tr.json +++ b/client/src/__locales/tr.json @@ -9,7 +9,7 @@ "bootstrap_dns": "DNS Önyükleme sunucuları", "bootstrap_dns_desc": "DNS Önyükleme sunucuları, belirttiğiniz üst sunucuların DoH/DoT çözümleyicilerine ait IP adreslerinin çözümlemek için kullanılır.", "local_ptr_title": "Özel ters DNS sunucuları", - "local_ptr_desc": "AdGuard Home'un yerel PTR sorguları için kullandığı DNS sunucuları. Bu sunucular, rDNS kullanarak \"192.168.12.34\" gibi özel IP adreslerine sahip istemcilerin ana makine adlarını çözmek için kullanılır. Ayarlanmadığı durumda AdGuard Home, işletim sisteminizin varsayılan DNS çözümleme adreslerini kullanır.", + "local_ptr_desc": "AdGuard Home'un yerel PTR sorguları için kullandığı DNS sunucuları. Bu sunucular, rDNS kullanarak, örneğin \"192.168.12.34\" gibi özel IP aralıklarındaki adresler için PTR isteklerini çözmek için kullanılır. Ayarlanmadığı durumda AdGuard Home, işletim sisteminizin varsayılan DNS çözümleme adreslerini kullanır.", "local_ptr_default_resolver": "AdGuard Home, varsayılan olarak aşağıdaki ters DNS çözümleyicilerini kullanır: {{ip}}.", "local_ptr_no_default_resolver": "AdGuard Home, bu sistem için uygun olan özel ters DNS çözümleyicilerini belirleyemedi.", "local_ptr_placeholder": "Her satıra bir sunucu adresi girin", @@ -115,7 +115,7 @@ "blocked_by": "<0>Filtreler tarafından engellenen", "stats_malware_phishing": "Engellenen kötü amaçlı yazılım ve kimlik avı", "stats_adult": "Engellenen yetişkin içerikli siteler", - "stats_query_domain": "En fazla sorgulanan alan adları", + "stats_query_domain": "Başlıca sorgulanan alan adları", "for_last_24_hours": "son 24 saat içindekiler", "for_last_days": "son {{count}} gün boyunca", "for_last_days_plural": "son {{count}} gün boyunca", @@ -123,8 +123,8 @@ "stats_disabled_short": "İstatistikler devre dışı bırakıldı", "no_domains_found": "Alan adı bulunamadı", "requests_count": "İstek sayısı", - "top_blocked_domains": "En fazla engellenen alan adları", - "top_clients": "En aktif istemciler", + "top_blocked_domains": "Başlıca engellenen alan adları", + "top_clients": "Başlıca istemciler", "no_clients_found": "İstemci bulunamadı", "general_statistics": "Genel istatistikler", "number_of_dns_query_days": "Son {{count}} gün boyunca işlenen DNS sorgularının sayısı", @@ -351,7 +351,7 @@ "install_devices_android_list_5": "DNS 1 ve DNS 2 değerlerini AdGuard Home sunucunuzun adresleriyle değiştirin.", "install_devices_ios_list_1": "Ana ekrandan Ayarlar'a dokunun.", "install_devices_ios_list_2": "Sol menüde bulunan Wi-Fi bölümüne girin (mobil ağlar için özel DNS sunucusu ayarlanamaz).", - "install_devices_ios_list_3": "Bağlı olduğunuz ağın ismine dokunun.", + "install_devices_ios_list_3": "O anda aktif olan ağın adına dokunun.", "install_devices_ios_list_4": "DNS alanına AdGuard Home sunucunuzun adreslerini girin.", "get_started": "Başlayın", "next": "Sonraki", @@ -602,14 +602,14 @@ "milliseconds_abbreviation": "ms", "cache_size": "Önbellek boyutu", "cache_size_desc": "DNS önbellek boyutu (bayt cinsinden).", - "cache_ttl_min_override": "Minimum TTL'i değiştir", - "cache_ttl_max_override": "Maksimum TTL'i değiştir", + "cache_ttl_min_override": "Minimum kullanım süresini geçersiz kıl", + "cache_ttl_max_override": "Maksimum kullanım süresini geçersiz kıl", "enter_cache_size": "Önbellek boyutunu girin (bayt)", - "enter_cache_ttl_min_override": "Minimum TTL değerini girin (saniye olarak)", - "enter_cache_ttl_max_override": "Maksimum TTL değerini girin (saniye olarak)", + "enter_cache_ttl_min_override": "Minimum kullanım süresi girin (saniye olarak)", + "enter_cache_ttl_max_override": "Maksimum kullanım süresi girin (saniye olarak)", "cache_ttl_min_override_desc": "DNS yanıtlarını önbelleğe alırken üst sunucudan alınan kullanım süresi değerini uzatın (saniye olarak).", "cache_ttl_max_override_desc": "DNS önbelleğindeki girişler için maksimum kullanım süresi değerini ayarlayın (saniye olarak).", - "ttl_cache_validation": "Minimum önbellek TTL geçersiz kılma, maksimuma eşit veya bundan küçük olmalıdır", + "ttl_cache_validation": "Minimum önbellek kullanım süresi geçersiz kılma, maksimum değerden küçük veya ona eşit olmalıdır", "cache_optimistic": "İyimser önbelleğe alma", "cache_optimistic_desc": "Girişlerin süresi dolduğunda bile AdGuard Home'un önbellekten yanıt vermesini sağlayın ve bunları yenilemeye çalışın.", "filter_category_general": "Genel", diff --git a/client/src/__locales/uk.json b/client/src/__locales/uk.json index 5d349618..9fcbd460 100644 --- a/client/src/__locales/uk.json +++ b/client/src/__locales/uk.json @@ -65,7 +65,7 @@ "dhcp_ip_addresses": "IP-адреси", "ip": "IP", "dhcp_table_hostname": "Назва вузла", - "dhcp_table_expires": "Термін дії", + "dhcp_table_expires": "Закінчується", "dhcp_warning": "Якщо ви однаково хочете увімкнути DHCP-сервер, переконайтеся, що у вашій мережі немає інших активних DHCP-серверів. Інакше, це може порушити роботу інтернету на під'єднаних пристроях!", "dhcp_error": "AdGuard Home не зміг визначити, чи є в мережі інший DHCP-сервер", "dhcp_static_ip_error": "Для використання DHCP-сервера необхідно встановити статичну IP-адресу. Нам не вдалося визначити, чи цей мережевий інтерфейс налаштовано для використання статичної IP-адреси. Встановіть статичну IP-адресу вручну.", @@ -137,15 +137,15 @@ "number_of_dns_query_to_safe_search": "Кількість DNS-запитів до пошукових систем, для яких примусово застосований безпечний пошук", "average_processing_time": "Середній час обробки", "average_processing_time_hint": "Середній час обробки DNS запиту в мілісекундах", - "block_domain_use_filters_and_hosts": "Блокувати домени з використанням фільтрів та hosts-файлів", + "block_domain_use_filters_and_hosts": "Блокування доменів за допомогою фільтрів та hosts-файлів", "filters_block_toggle_hint": "Ви можете налаштувати правила блокування в розділі Фільтри.", - "use_adguard_browsing_sec": "Використовувати веб-службу безпечного перегляду AdGuard", + "use_adguard_browsing_sec": "Використовувати Безпечну навігацію AdGuard", "use_adguard_browsing_sec_hint": "AdGuard Home перевірятиме, чи додано домен до списку веб-служби безпечного перегляду браузера. Він використовуватиме API для перевірки — на сервер надсилається лише короткий префікс хешу SHA256 доменного імені.", "use_adguard_parental": "Використовувати вебсервіс Батьківського контролю AdGuard", - "use_adguard_parental_hint": "AdGuard Home перевірятиме, чи домен містить матеріали для дорослих. Він використовує той самий орієнтований на приватність API, що й веб-служба безпечного перегляду.", - "enforce_safe_search": "Використовувати безпечний пошук", + "use_adguard_parental_hint": "AdGuard Home перевірить, чи містить домен матеріали для дорослих. Він використовує то же API, що й Безпечна навігація AdGuard.", + "enforce_safe_search": "Використовувати Безпечний пошук", "enforce_save_search_hint": "AdGuard Home може примусово застосовувати безпечний пошук в таких пошукових системах: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.", - "no_servers_specified": "Не вказано сервери", + "no_servers_specified": "Сервери не вказано", "general_settings": "Загальні налаштування", "dns_settings": "Налаштування DNS", "dns_blocklists": "Список блокування DNS", @@ -158,7 +158,7 @@ "upstream_dns": "Upstream DNS-сервери", "upstream_dns_help": "Введіть адреси серверів по одній на рядок. Докладніше про налаштування DNS-серверів.", "upstream_dns_configured_in_file": "Налаштовано в {{path}}", - "test_upstream_btn": "Тест upstream серверів", + "test_upstream_btn": "Перевірити сервери", "upstreams": "Upstreams", "apply_btn": "Застосувати", "disabled_filtering_toast": "Фільтрування вимкнено", @@ -266,7 +266,7 @@ "dns_cache_config": "Конфігурація кешу DNS", "dns_cache_config_desc": "Тут ви можете налаштувати DNS-кеш", "blocking_mode": "Режим блокування", - "default": "Типовий", + "default": "Усталено", "nxdomain": "NXDOMAIN", "refused": "REFUSED", "null_ip": "Нульовий IP", @@ -316,7 +316,7 @@ "install_settings_dns_desc": "Вам потрібно буде налаштувати свої пристрої або маршрутизатор для використання DNS-сервера за такими адресами:", "install_settings_all_interfaces": "Усі інтерфейси", "install_auth_title": "Авторизація", - "install_auth_desc": "Необходно налаштувати автентифікацію паролем для вебінтерфейсу AdGuard Home. Навіть якщо він доступний лише у вашій локальній мережі, важливо захистити його від необмеженого доступу.\n\nДолжна быть настроена аутентификация паролем для веб-интерфейса AdGuard Home. Даже если он доступен только в вашей локальной сети, важно защитить его от неограниченного доступа.", + "install_auth_desc": "Необхідно налаштувати автентифікацію паролем для вебінтерфейсу AdGuard Home. Навіть якщо він доступний лише у вашій локальній мережі, важливо захистити його від необмеженого доступу.", "install_auth_username": "Ім'я користувача", "install_auth_password": "Пароль", "install_auth_confirm": "Підтвердьте пароль", @@ -336,7 +336,7 @@ "install_devices_router_list_4": "Ви не можете встановити власний DNS-сервер на деяких типах маршрутизаторів. У цьому разі вам може допомогти налаштування AdGuard Home в якості <0>DHCP-сервера. В іншому разі вам потрібно знайти інструкцію щодо налаштування DNS-сервера для вашої конкретної моделі маршрутизатора.", "install_devices_windows_list_1": "Відкрийте Панель керування через меню «Пуск» або пошук Windows.", "install_devices_windows_list_2": "Перейдіть до категорії Мережа й Інтернет, а потім до Центру мереж і спільного доступу.", - "install_devices_windows_list_3": "Зліва на екрані натисніть на «Змінити настройки адаптера».", + "install_devices_windows_list_3": "Зліва на екрані натисніть на «Змінити налаштування адаптера».", "install_devices_windows_list_4": "Клацніть на активному з'єднанні правою кнопкою миші та виберіть «Властивості».", "install_devices_windows_list_5": "Знайдіть у списку пункт «Internet Protocol Version 4 (TCP/IPv4)» або «Internet Protocol Version 6 (TCP/IPv6)», виберіть його та натисніть кнопку Властивості ще раз.", "install_devices_windows_list_6": "Виберіть «Використовувати наступні адреси DNS-серверів» та введіть адреси вашого сервера AdGuard Home.", @@ -375,7 +375,7 @@ "encryption_certificates_desc": "Для використання шифрування потрібно надати дійсний ланцюжок сертифікатів SSL для вашого домену. Ви можете отримати безкоштовний сертифікат на <0>{{link}} або придбати його в одному з надійних Центрів Сертифікації.", "encryption_certificates_input": "Скопіюйте/вставте сюди свої кодовані PEM сертифікати.", "encryption_status": "Статус", - "encryption_expire": "Закічнується", + "encryption_expire": "Закінчується", "encryption_key": "Приватний ключ", "encryption_key_input": "Скопіюйте/вставте сюди свій приватний ключ кодований PEM для вашого сертифіката.", "encryption_enable": "Увімкнути шифрування (HTTPS, DNS-over-HTTPS і DNS-over-TLS)", diff --git a/client/src/__locales/zh-cn.json b/client/src/__locales/zh-cn.json index 69d5b8b0..4640432f 100644 --- a/client/src/__locales/zh-cn.json +++ b/client/src/__locales/zh-cn.json @@ -148,8 +148,8 @@ "no_servers_specified": "未找到指定的服务器", "general_settings": "常规设置", "dns_settings": "DNS 设置", - "dns_blocklists": "DNS封锁清单", - "dns_allowlists": "DNS允许清单", + "dns_blocklists": "DNS 拦截列表", + "dns_allowlists": "DNS 允许列表", "dns_blocklists_desc": "AdGuard Home将阻止匹配DNS拦截清单的域名", "dns_allowlists_desc": "来自DNS允许列表的域将被允许,即使它们位于任意阻止列表中也是如此", "custom_filtering_rules": "自定义过滤规则", @@ -335,23 +335,22 @@ "install_devices_router_list_3": "请在此处输入您的 AdGuard Home 服务器地址。", "install_devices_router_list_4": "在某些类型的路由器上无法设置自定义 DNS 服务器。在此情况下将 AdGuard Home 设置为 <0>DHCP 服务器,可能会有所帮助。否则您应该查找如何根据特定路由器型号设置 DNS 服务器的使用手册。", "install_devices_windows_list_1": "通过开始菜单或 Windows 搜索功能打开控制面板。", - "install_devices_windows_list_2": "点击进入 ”网络和 Internet“ 后,再次点击进入 “网络和共享中心”", + "install_devices_windows_list_2": "点击进入「网络和 Internet」后,再次点击进入「网络和共享中心」", "install_devices_windows_list_3": "在窗口的左侧点击「更改适配器设置」。", "install_devices_windows_list_4": "选择您正在连接的网络设备,右击它并选择「属性”」。", - "install_devices_windows_list_5": "在列表中找到 ”Internet 协议版本 4 (TCP/IPv4)“ ,选择并再次点击 ”属性“ 。", + "install_devices_windows_list_5": "在列表中找到「Internet 协议版本 4 (TCP/IPv4)」,选择并再次点击「属性」。", "install_devices_windows_list_6": "选择“使用下面的 DNS 服务器地址”,并输入您的 AdGuard Home 服务器地址。", "install_devices_macos_list_1": "点击苹果图标,进入「系统首选项」。", "install_devices_macos_list_2": "点击「网络」。", - "install_devices_macos_list_3": "选择在列表中的第一个连接,并点击 ”高级“ 。", - "install_devices_macos_list_4": "选择 ”DNS“ 选项卡,并输入您的 AdGuard Home 服务器地址。", + "install_devices_macos_list_3": "选择在列表中的第一个连接,并点击「高级」。", + "install_devices_macos_list_4": "选择「DNS」选项卡,并输入您的 AdGuard Home 服务器地址。", "install_devices_android_list_1": "在安卓主屏幕菜单中点击设置。", - "install_devices_android_list_2": "点击菜单上的 ”无线局域网“ 选项。在屏幕上将列出所有可用的网络(蜂窝移动网络不支持修改 DNS )。", - "install_devices_android_list_3": "长按当前已连接的网络,然后点击 ”修改网络设置“ 。", - "install_devices_android_list_4": "在某些设备上,您可能需要选中 ”高级“ 复选框以查看进一步的设置。您可能需要调整您安卓设备的 DNS 设置,或是需要将 IP 设置从 DHCP 切换到静态。", + "install_devices_android_list_2": "点击菜单上的「无线局域网」选项。在屏幕上将列出所有可用的网络(蜂窝移动网络不支持修改 DNS )。", + "install_devices_android_list_3": "长按当前已连接的网络,然后点击「修改网络设置」。", + "install_devices_android_list_4": "在某些设备上,您可能需要选中「高级」复选框以查看进一步的设置。您可能需要调整您安卓设备的 DNS 设置,或是需要将 IP 设置从 DHCP 切换到静态。", "install_devices_android_list_5": "将 DNS 1 和 DNS 2 的值改为您的 AdGuard Home 服务器地址。", - "install_devices_ios_list_1": "从主屏幕中点击 ”设置“ 。", - "install_devices_ios_list_2": "从左侧目录中选择 ”无线局域网“(移动数据网络环境下不支持修改 DNS )。", - "install_devices_ios_list_3": "点击当前已连接网络的名称。", + "install_devices_ios_list_1": "从主屏幕中点击「设置」。", + "install_devices_ios_list_2": "从左侧目录中选择「无线局域网」(移动数据网络环境下不支持修改 DNS )。", "install_devices_ios_list_4": "在 DNS 字段中输入您的 AdGuard Home 服务器地址。", "get_started": "开始配置", "next": "下一步", diff --git a/client/src/__locales/zh-tw.json b/client/src/__locales/zh-tw.json index 666ddcc3..435d6b01 100644 --- a/client/src/__locales/zh-tw.json +++ b/client/src/__locales/zh-tw.json @@ -9,7 +9,7 @@ "bootstrap_dns": "自我啟動(Bootstrap)DNS 伺服器", "bootstrap_dns_desc": "自我啟動(Bootstrap)DNS 伺服器被用於解析您明確指定作為上游的 DoH/DoT 解析器之 IP 位址。", "local_ptr_title": "私人反向的 DNS 伺服器", - "local_ptr_desc": "AdGuard Home 用於區域指標(PTR)查詢之 DNS 伺服器。這些伺服器被用於解析含私人 IP 位址的用戶端之主機名稱,例如,\"192.168.12.34\",使用反向的 DNS。如果未被設定,除 AdGuard Home 它本身的位址之外,AdGuard Home 使用您的作業系統之預設 DNS 解析器的位址。", + "local_ptr_desc": "AdGuard Home 用於區域指標(PTR)查詢之 DNS 伺服器。這些伺服器被用於解析有關在私人 IP 範圍的位址之區域指標查詢,例如,\"192.168.12.34\",使用反向的 DNS。如果未被設定,AdGuard Home 使用您的作業系統之預設 DNS 解析器的位址。", "local_ptr_default_resolver": "預設下,AdGuard Home 使用以下反向的 DNS 解析器:{{ip}}。", "local_ptr_no_default_resolver": "AdGuard Home 無法為此系統決定合適的私人反向的 DNS 解析器。", "local_ptr_placeholder": "每行輸入一個伺服器位址", From a580149ad67b604a1e3c6e7b3483d856a51c905a Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Wed, 27 Apr 2022 14:32:29 +0300 Subject: [PATCH 039/110] Pull request: all: upd dnsproxy, tools Merge in DNS/adguard-home from upd-dnsproxy to master Squashed commit of the following: commit ea2a88dfd6e3820f0b3319d6aa09313de467e423 Author: Ainar Garipov Date: Wed Apr 27 14:24:49 2022 +0300 all: upd dnsproxy, tools --- go.mod | 12 ++++++------ go.sum | 21 ++++++++++++--------- internal/tools/go.mod | 8 ++++---- internal/tools/go.sum | 15 ++++++++------- 4 files changed, 30 insertions(+), 26 deletions(-) diff --git a/go.mod b/go.mod index 30d8b377..3b64e7db 100644 --- a/go.mod +++ b/go.mod @@ -3,13 +3,13 @@ module github.com/AdguardTeam/AdGuardHome go 1.17 require ( - github.com/AdguardTeam/dnsproxy v0.42.1 + github.com/AdguardTeam/dnsproxy v0.42.2 github.com/AdguardTeam/golibs v0.10.8 github.com/AdguardTeam/urlfilter v0.16.0 github.com/NYTimes/gziphandler v1.1.1 github.com/ameshkov/dnscrypt/v2 v2.2.3 github.com/digineo/go-ipset/v2 v2.2.1 - github.com/fsnotify/fsnotify v1.5.1 + github.com/fsnotify/fsnotify v1.5.4 github.com/go-ping/ping v0.0.0-20211130115550-779d1e919534 github.com/google/go-cmp v0.5.7 github.com/google/gopacket v1.1.19 @@ -28,8 +28,8 @@ require ( github.com/ti-mo/netfilter v0.4.0 go.etcd.io/bbolt v1.3.6 golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 - golang.org/x/net v0.0.0-20220412020605-290c469a71a5 - golang.org/x/sys v0.0.0-20220412211240-33da011f77ad + golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 + golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/yaml.v2 v2.4.0 howett.net/plist v1.0.0 @@ -57,10 +57,10 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/objx v0.1.1 // indirect github.com/u-root/uio v0.0.0-20220204230159-dac05f7d2cb4 // indirect - golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect + golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/text v0.3.7 // indirect - golang.org/x/tools v0.1.11-0.20220316014157-77aa08bb151a // indirect + golang.org/x/tools v0.1.11-0.20220426200323-dcaea06afc12 // indirect golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect diff --git a/go.sum b/go.sum index e75df993..06ae9b96 100644 --- a/go.sum +++ b/go.sum @@ -7,8 +7,8 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= -github.com/AdguardTeam/dnsproxy v0.42.1 h1:RZAtW75cvMX1d9Mibg0CA343V7VWV5PLrXsLhBZfdYc= -github.com/AdguardTeam/dnsproxy v0.42.1/go.mod h1:thHuk3599mgmucsv5J9HR9lBVQHnf4YleE08EbxNrN0= +github.com/AdguardTeam/dnsproxy v0.42.2 h1:aBhbuvqg/rZN8Rab5ILSfPFJDkiTviWXXcceJgajnNs= +github.com/AdguardTeam/dnsproxy v0.42.2/go.mod h1:thHuk3599mgmucsv5J9HR9lBVQHnf4YleE08EbxNrN0= github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4= github.com/AdguardTeam/golibs v0.4.2/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4= github.com/AdguardTeam/golibs v0.10.4/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw= @@ -58,8 +58,9 @@ github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= @@ -292,8 +293,9 @@ golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPI golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -329,8 +331,8 @@ golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5 h1:bRb386wvrE+oBNdF1d/Xh9mQrfQ4ecYhW5qJ5GvTGT4= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -390,8 +392,9 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -416,8 +419,8 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= -golang.org/x/tools v0.1.11-0.20220316014157-77aa08bb151a h1:ofrrl6c6NG5/IOSx/R1cyiQxxjqlur0h/TvbUhkH0II= -golang.org/x/tools v0.1.11-0.20220316014157-77aa08bb151a/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/tools v0.1.11-0.20220426200323-dcaea06afc12 h1:pODAJF0uBqx6zFa1MYaiTobVo5FzCbnTVUXeO8o71fE= +golang.org/x/tools v0.1.11-0.20220426200323-dcaea06afc12/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/internal/tools/go.mod b/internal/tools/go.mod index 2ad6ce16..bb587070 100644 --- a/internal/tools/go.mod +++ b/internal/tools/go.mod @@ -11,7 +11,7 @@ require ( github.com/securego/gosec/v2 v2.11.0 golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 golang.org/x/tools v0.1.11-0.20220316014157-77aa08bb151a - honnef.co/go/tools v0.3.0 + honnef.co/go/tools v0.3.1 mvdan.cc/gofumpt v0.3.1 mvdan.cc/unparam v0.0.0-20220316160445-06cc5682983b ) @@ -19,16 +19,16 @@ require ( require ( github.com/BurntSushi/toml v1.1.0 // indirect github.com/client9/misspell v0.3.4 // indirect - github.com/google/go-cmp v0.5.7 // indirect + github.com/google/go-cmp v0.5.8 // indirect github.com/google/uuid v1.3.0 // indirect github.com/gookit/color v1.5.0 // indirect github.com/kyoh86/nolint v0.0.1 // indirect github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect - golang.org/x/exp/typeparams v0.0.0-20220407100705-7b9b53b0aca4 // indirect + golang.org/x/exp/typeparams v0.0.0-20220426173459-3bcf042a4bf5 // indirect golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect - golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect + golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 // indirect golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/internal/tools/go.sum b/internal/tools/go.sum index 7dbf5491..2f04e4a6 100644 --- a/internal/tools/go.sum +++ b/internal/tools/go.sum @@ -157,8 +157,9 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -420,8 +421,8 @@ golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMk golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5 h1:FR+oGxGfbQu1d+jglI3rCkjAjUnhRSZcUxr+DqlDLNo= golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= -golang.org/x/exp/typeparams v0.0.0-20220407100705-7b9b53b0aca4 h1:P5yukcpQfG1ZDKR0pGdaZCVwaNPntMxLFKYg81li58M= -golang.org/x/exp/typeparams v0.0.0-20220407100705-7b9b53b0aca4/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/exp/typeparams v0.0.0-20220426173459-3bcf042a4bf5 h1:pKfHvPtBtqS0+V/V9Y0cZQa2h8HJV/qSRJiGgYu+LQA= +golang.org/x/exp/typeparams v0.0.0-20220426173459-3bcf042a4bf5/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -559,8 +560,8 @@ golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -751,8 +752,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.3.0 h1:2LdYUZ7CIxnYgskbUZfY7FPggmqnh6shBqfWa8Tn3XU= -honnef.co/go/tools v0.3.0/go.mod h1:vlRD9XErLMGT+mDuofSr0mMMquscM/1nQqtRSsh6m70= +honnef.co/go/tools v0.3.1 h1:1kJlrWJLkaGXgcaeosRXViwviqjI7nkBvU2+sZW0AYc= +honnef.co/go/tools v0.3.1/go.mod h1:vlRD9XErLMGT+mDuofSr0mMMquscM/1nQqtRSsh6m70= mvdan.cc/gofumpt v0.3.1 h1:avhhrOmv0IuvQVK7fvwV91oFSGAk5/6Po8GXTzICeu8= mvdan.cc/gofumpt v0.3.1/go.mod h1:w3ymliuxvzVx8DAutBnVyDqYb1Niy/yCJt/lk821YCE= mvdan.cc/unparam v0.0.0-20220316160445-06cc5682983b h1:C8Pi6noat8BcrL9WnSRYeQ63fpkJk3hKVHtF5731kIw= From 21905d98693a58a24560ceac5461a470beb70af8 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Fri, 29 Apr 2022 14:39:02 +0300 Subject: [PATCH 040/110] Pull request: home: imp openbsd init script Closes #4533. Squashed commit of the following: commit 48ca9e100619e714eab565273daeb4ee9adb5b74 Author: Ainar Garipov Date: Thu Apr 28 20:25:15 2022 +0300 home: imp openbsd init script --- CHANGELOG.md | 8 ++++++-- internal/home/service.go | 2 +- internal/v1/cmd/signal.go | 10 +++++----- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84f45312..289b1d2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,8 +23,8 @@ and this project adheres to ### Added -- Support for Discovery of Designated Resolvers (DDR) according to the - [RFC draft][ddr-draft-06] ([#4463]). +- Support for Discovery of Designated Resolvers (DDR) according to the [RFC + draft][ddr-draft-06] ([#4463]). - The ability to control each source of runtime clients separately via `clients.runtime_sources` configuration object ([#3020]). - The ability to customize the set of networks that are considered private @@ -40,6 +40,9 @@ and this project adheres to ### Changed +- On OpenBSD, the daemon script now uses the recommended `/bin/ksh` shell + instead of the `/bin/sh` one ([#4533]). To apply this change, backup your + data and run `AdGuardHome -s uninstall && AdGuardHome -s install`. - The default DNS-over-QUIC port number is now `853` instead of `754` in accordance with the latest [RFC draft][doq-draft-10] ([#4276]). - Reverse DNS now has a greater priority as the source of runtime clients' @@ -144,6 +147,7 @@ In this release, the schema version has changed from 12 to 14. [#4238]: https://github.com/AdguardTeam/AdGuardHome/issues/4238 [#4276]: https://github.com/AdguardTeam/AdGuardHome/issues/4276 [#4499]: https://github.com/AdguardTeam/AdGuardHome/issues/4499 +[#4533]: https://github.com/AdguardTeam/AdGuardHome/issues/4533 [ddr-draft-06]: https://www.ietf.org/archive/id/draft-ietf-add-ddr-06.html [doq-draft-10]: https://datatracker.ietf.org/doc/html/draft-ietf-dprive-dnsoquic-10#section-10.2 diff --git a/internal/home/service.go b/internal/home/service.go index 081974e2..70ab3c78 100644 --- a/internal/home/service.go +++ b/internal/home/service.go @@ -609,7 +609,7 @@ command_args="-P ${pidfile} -p ${pidfile_child} -T ${name} -r {{.WorkingDirector run_rc_command "$1" ` -const openBSDScript = `#!/bin/sh +const openBSDScript = `#!/bin/ksh # # $OpenBSD: {{ .SvcInfo }} diff --git a/internal/v1/cmd/signal.go b/internal/v1/cmd/signal.go index b9f09673..b66075f6 100644 --- a/internal/v1/cmd/signal.go +++ b/internal/v1/cmd/signal.go @@ -19,10 +19,10 @@ type signalHandler struct { // handle processes OS signals. func (h *signalHandler) handle() { - defer log.OnPanic("signalProcessor.handle") + defer log.OnPanic("signalHandler.handle") for sig := range h.signal { - log.Info("sigproc: received signal %q", sig) + log.Info("sighdlr: received signal %q", sig) if aghos.IsShutdownSignal(sig) { h.shutdown() @@ -43,16 +43,16 @@ func (h *signalHandler) shutdown() { status := statusSuccess - log.Info("sigproc: shutting down services") + log.Info("sighdlr: shutting down services") for i, service := range h.services { err := service.Shutdown(ctx) if err != nil { - log.Error("sigproc: shutting down service at index %d: %s", i, err) + log.Error("sighdlr: shutting down service at index %d: %s", i, err) status = statusError } } - log.Info("sigproc: shutting down adguard home") + log.Info("sighdlr: shutting down adguard home") os.Exit(status) } From 58515fce4304538ba374305c27d71640993f046e Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Wed, 4 May 2022 21:01:41 +0300 Subject: [PATCH 041/110] Pull request: 4542 clientid case Merge in DNS/adguard-home from 4542-clientid-case to master Updates #4542. Squashed commit of the following: commit 2a3111ebcef09460b407cd1c870cad2391cd5650 Author: Eugene Burkov Date: Wed May 4 20:44:18 2022 +0300 all: fix changelog link commit 3732def83e2a36eeff2d682149dc4dcef4e92a7d Author: Eugene Burkov Date: Wed May 4 20:43:37 2022 +0300 all: log changes commit 9fe1001cf586669ae238c9c4818070cf94e23ce8 Author: Eugene Burkov Date: Wed May 4 19:37:33 2022 +0300 dnsforward: lowercase clientid --- CHANGELOG.md | 2 ++ internal/dnsforward/clientid.go | 4 ++-- internal/dnsforward/clientid_test.go | 21 +++++++++++++++++++++ internal/home/clients.go | 3 ++- 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 289b1d2e..3c2fa06c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -127,6 +127,7 @@ In this release, the schema version has changed from 12 to 14. ### Fixed +- Case-sensitive ClientID ([#4542]). - Slow version update queries making other HTTP APIs unresponsible ([#4499]). - ARP tables refreshing process causing excessive PTR requests ([#3157]). @@ -148,6 +149,7 @@ In this release, the schema version has changed from 12 to 14. [#4276]: https://github.com/AdguardTeam/AdGuardHome/issues/4276 [#4499]: https://github.com/AdguardTeam/AdGuardHome/issues/4499 [#4533]: https://github.com/AdguardTeam/AdGuardHome/issues/4533 +[#4542]: https://github.com/AdguardTeam/AdGuardHome/issues/4542 [ddr-draft-06]: https://www.ietf.org/archive/id/draft-ietf-add-ddr-06.html [doq-draft-10]: https://datatracker.ietf.org/doc/html/draft-ietf-dprive-dnsoquic-10#section-10.2 diff --git a/internal/dnsforward/clientid.go b/internal/dnsforward/clientid.go index 481fb84d..bb687a41 100644 --- a/internal/dnsforward/clientid.go +++ b/internal/dnsforward/clientid.go @@ -65,7 +65,7 @@ func clientIDFromClientServerName( return "", err } - return clientID, nil + return strings.ToLower(clientID), nil } // clientIDFromDNSContextHTTPS extracts the client's ID from the path of the @@ -104,7 +104,7 @@ func clientIDFromDNSContextHTTPS(pctx *proxy.DNSContext) (clientID string, err e return "", fmt.Errorf("clientid check: %w", err) } - return clientID, nil + return strings.ToLower(clientID), nil } // tlsConn is a narrow interface for *tls.Conn to simplify testing. diff --git a/internal/dnsforward/clientid_test.go b/internal/dnsforward/clientid_test.go index e62dbe58..6e23d639 100644 --- a/internal/dnsforward/clientid_test.go +++ b/internal/dnsforward/clientid_test.go @@ -143,6 +143,22 @@ func TestServer_clientIDFromDNSContext(t *testing.T) { wantErrMsg: `clientid check: client server name "cli.myexample.com" ` + `doesn't match host server name "example.com"`, strictSNI: true, + }, { + name: "tls_case", + proto: proxy.ProtoTLS, + hostSrvName: "example.com", + cliSrvName: "InSeNsItIvE.example.com", + wantClientID: "insensitive", + wantErrMsg: ``, + strictSNI: true, + }, { + name: "quic_case", + proto: proxy.ProtoQUIC, + hostSrvName: "example.com", + cliSrvName: "InSeNsItIvE.example.com", + wantClientID: "insensitive", + wantErrMsg: ``, + strictSNI: true, }} for _, tc := range testCases { @@ -210,6 +226,11 @@ func TestClientIDFromDNSContextHTTPS(t *testing.T) { path: "/dns-query/cli/", wantClientID: "cli", wantErrMsg: "", + }, { + name: "clientid_case", + path: "/dns-query/InSeNsItIvE", + wantClientID: "insensitive", + wantErrMsg: ``, }, { name: "bad_url", path: "/foo", diff --git a/internal/home/clients.go b/internal/home/clients.go index d4d6b959..4ba6b884 100644 --- a/internal/home/clients.go +++ b/internal/home/clients.go @@ -5,6 +5,7 @@ import ( "fmt" "net" "sort" + "strings" "sync" "time" @@ -546,7 +547,7 @@ func (clients *clientsContainer) check(c *Client) (err error) { } else if mac, err = net.ParseMAC(id); err == nil { c.IDs[i] = mac.String() } else if err = dnsforward.ValidateClientID(id); err == nil { - c.IDs[i] = id + c.IDs[i] = strings.ToLower(id) } else { return fmt.Errorf("invalid clientid at index %d: %q", i, id) } From f289f4b1b6f91f38d99ac8b9e3f9bdc9536609e7 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Thu, 12 May 2022 17:41:39 +0300 Subject: [PATCH 042/110] Pull request: websvc: add system info Merge in DNS/adguard-home from websvc-system-info to master Squashed commit of the following: commit 333aaa0602da254e25e0262a10080bf44a3718a7 Author: Ainar Garipov Date: Thu May 12 16:32:32 2022 +0300 websvc: fmt commit d8a35bf71dcc59fdd595494e5b220e3d24516728 Author: Ainar Garipov Date: Thu May 12 16:10:11 2022 +0300 websvc: refactor, imp tests commit dfeb24f3f35513bf51323d3ab6f717f582a1defc Author: Ainar Garipov Date: Wed May 11 20:52:02 2022 +0300 websvc: add system info --- go.mod | 1 + go.sum | 2 + internal/v1/cmd/cmd.go | 4 +- internal/v1/websvc/json.go | 61 +++++++++++++++++++++++++++++++ internal/v1/websvc/middleware.go | 16 ++++++++ internal/v1/websvc/path.go | 8 ++++ internal/v1/websvc/system.go | 35 ++++++++++++++++++ internal/v1/websvc/system_test.go | 36 ++++++++++++++++++ internal/v1/websvc/websvc.go | 46 ++++++++++++++++++++++- internal/v1/websvc/websvc_test.go | 52 ++++++++++++++++++++------ openapi/v1.yaml | 16 +++++++- 11 files changed, 260 insertions(+), 17 deletions(-) create mode 100644 internal/v1/websvc/json.go create mode 100644 internal/v1/websvc/middleware.go create mode 100644 internal/v1/websvc/path.go create mode 100644 internal/v1/websvc/system.go create mode 100644 internal/v1/websvc/system_test.go diff --git a/go.mod b/go.mod index 3b64e7db..8da34653 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/NYTimes/gziphandler v1.1.1 github.com/ameshkov/dnscrypt/v2 v2.2.3 github.com/digineo/go-ipset/v2 v2.2.1 + github.com/dimfeld/httptreemux/v5 v5.4.0 github.com/fsnotify/fsnotify v1.5.4 github.com/go-ping/ping v0.0.0-20211130115550-779d1e919534 github.com/google/go-cmp v0.5.7 diff --git a/go.sum b/go.sum index 06ae9b96..807a6849 100644 --- a/go.sum +++ b/go.sum @@ -52,6 +52,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/digineo/go-ipset/v2 v2.2.1 h1:k6skY+0fMqeUjjeWO/m5OuWPSZUAn7AucHMnQ1MX77g= github.com/digineo/go-ipset/v2 v2.2.1/go.mod h1:wBsNzJlZlABHUITkesrggFnZQtgW5wkqw1uo8Qxe0VU= +github.com/dimfeld/httptreemux/v5 v5.4.0 h1:IiHYEjh+A7pYbhWyjmGnj5HZK6gpOOvyBXCJ+BE8/Gs= +github.com/dimfeld/httptreemux/v5 v5.4.0/go.mod h1:QeEylH57C0v3VO0tkKraVz9oD3Uu93CKPnTLbsidvSw= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= diff --git a/internal/v1/cmd/cmd.go b/internal/v1/cmd/cmd.go index 4c4e252f..1f1cc64e 100644 --- a/internal/v1/cmd/cmd.go +++ b/internal/v1/cmd/cmd.go @@ -20,7 +20,8 @@ import ( func Main(clientBuildFS fs.FS) { // # Initial Configuration - rand.Seed(time.Now().UnixNano()) + start := time.Now() + rand.Seed(start.UnixNano()) // TODO(a.garipov): Set up logging. @@ -35,6 +36,7 @@ func Main(clientBuildFS fs.FS) { IP: net.IP{127, 0, 0, 1}, Port: 3001, }}, + Start: start, Timeout: 60 * time.Second, }) diff --git a/internal/v1/websvc/json.go b/internal/v1/websvc/json.go new file mode 100644 index 00000000..beb7f7ec --- /dev/null +++ b/internal/v1/websvc/json.go @@ -0,0 +1,61 @@ +package websvc + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "strconv" + "time" + + "github.com/AdguardTeam/golibs/log" +) + +// JSON Utilities + +// 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{} + +// nsecPerMsec is the number of nanoseconds in a millisecond. +const nsecPerMsec = float64(time.Millisecond / time.Nanosecond) + +// 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', 3, 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 encodes v into w and logs any errors it encounters. r is +// used to get additional information from the request. +func writeJSONResponse(w io.Writer, r *http.Request, v interface{}) { + err := json.NewEncoder(w).Encode(v) + if err != nil { + log.Error("websvc: writing resp to %s %s: %s", r.Method, r.URL.Path, err) + } +} diff --git a/internal/v1/websvc/middleware.go b/internal/v1/websvc/middleware.go new file mode 100644 index 00000000..c87c57d5 --- /dev/null +++ b/internal/v1/websvc/middleware.go @@ -0,0 +1,16 @@ +package websvc + +import "net/http" + +// Middlewares + +// jsonMw sets the content type of the response to application/json. +func jsonMw(h http.Handler) (wrapped http.HandlerFunc) { + f := func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + + h.ServeHTTP(w, r) + } + + return http.HandlerFunc(f) +} diff --git a/internal/v1/websvc/path.go b/internal/v1/websvc/path.go new file mode 100644 index 00000000..cfd67fd9 --- /dev/null +++ b/internal/v1/websvc/path.go @@ -0,0 +1,8 @@ +package websvc + +// Path constants +const ( + PathHealthCheck = "/health-check" + + PathV1SystemInfo = "/api/v1/system/info" +) diff --git a/internal/v1/websvc/system.go b/internal/v1/websvc/system.go new file mode 100644 index 00000000..47d0c63c --- /dev/null +++ b/internal/v1/websvc/system.go @@ -0,0 +1,35 @@ +package websvc + +import ( + "net/http" + "runtime" + + "github.com/AdguardTeam/AdGuardHome/internal/version" +) + +// System Handlers + +// RespGetV1SystemInfo describes the response of the GET /api/v1/system/info +// HTTP API. +type RespGetV1SystemInfo struct { + Arch string `json:"arch"` + Channel string `json:"channel"` + OS string `json:"os"` + NewVersion string `json:"new_version,omitempty"` + Start jsonTime `json:"start"` + Version string `json:"version"` +} + +// handleGetV1SystemInfo is the handler for the GET /api/v1/system/info HTTP +// API. +func (svc *Service) handleGetV1SystemInfo(w http.ResponseWriter, r *http.Request) { + writeJSONResponse(w, r, &RespGetV1SystemInfo{ + Arch: runtime.GOARCH, + Channel: version.Channel(), + OS: runtime.GOOS, + // TODO(a.garipov): Fill this when we have an updater. + NewVersion: "", + Start: jsonTime(svc.start), + Version: version.Version(), + }) +} diff --git a/internal/v1/websvc/system_test.go b/internal/v1/websvc/system_test.go new file mode 100644 index 00000000..49579ca5 --- /dev/null +++ b/internal/v1/websvc/system_test.go @@ -0,0 +1,36 @@ +package websvc_test + +import ( + "encoding/json" + "net/http" + "net/url" + "runtime" + "testing" + "time" + + "github.com/AdguardTeam/AdGuardHome/internal/v1/websvc" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestService_handleGetV1SystemInfo(t *testing.T) { + _, addr := newTestServer(t) + u := &url.URL{ + Scheme: "http", + Host: addr, + Path: websvc.PathV1SystemInfo, + } + + body := httpGet(t, u, http.StatusOK) + resp := &websvc.RespGetV1SystemInfo{} + err := json.Unmarshal(body, resp) + require.NoError(t, err) + + // TODO(a.garipov): Consider making version.Channel and version.Version + // testable and test these better. + assert.NotEmpty(t, resp.Channel) + + assert.Equal(t, resp.Arch, runtime.GOARCH) + assert.Equal(t, resp.OS, runtime.GOOS) + assert.Equal(t, testStart, time.Time(resp.Start)) +} diff --git a/internal/v1/websvc/websvc.go b/internal/v1/websvc/websvc.go index e741ff3d..9af22a15 100644 --- a/internal/v1/websvc/websvc.go +++ b/internal/v1/websvc/websvc.go @@ -17,6 +17,7 @@ import ( "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/netutil" + httptreemux "github.com/dimfeld/httptreemux/v5" ) // Config is the AdGuard Home web service configuration structure. @@ -32,6 +33,9 @@ type Config struct { // SecureAddresses is not empty, TLS must not be nil. SecureAddresses []*netutil.IPPort + // Start is the time of start of AdGuard Home. + Start time.Time + // Timeout is the timeout for all server operations. Timeout time.Duration } @@ -41,6 +45,7 @@ type Config struct { type Service struct { tls *tls.Config servers []*http.Server + start time.Time timeout time.Duration } @@ -53,11 +58,11 @@ func New(c *Config) (svc *Service) { svc = &Service{ tls: c.TLS, + start: c.Start, timeout: c.Timeout, } - mux := http.NewServeMux() - mux.HandleFunc("/health-check", svc.handleGetHealthCheck) + mux := newMux(svc) for _, a := range c.Addresses { addr := a.String() @@ -91,6 +96,43 @@ func New(c *Config) (svc *Service) { return svc } +// newMux returns a new HTTP request multiplexor for the AdGuard Home web +// service. +func newMux(svc *Service) (mux *httptreemux.ContextMux) { + mux = httptreemux.NewContextMux() + + routes := []struct { + handler http.HandlerFunc + method string + path string + isJSON bool + }{{ + handler: svc.handleGetHealthCheck, + method: http.MethodGet, + path: PathHealthCheck, + isJSON: false, + }, { + handler: svc.handleGetV1SystemInfo, + method: http.MethodGet, + path: PathV1SystemInfo, + isJSON: true, + }} + + for _, r := range routes { + var h http.HandlerFunc + if r.isJSON { + // TODO(a.garipov): Consider using httptreemux's MiddlewareFunc. + h = jsonMw(r.handler) + } else { + h = r.handler + } + + mux.Handle(r.method, r.path, h) + } + + return mux +} + // Addrs returns all addresses on which this server serves the HTTP API. Addrs // must not be called until Start returns. func (svc *Service) Addrs() (addrs []string) { diff --git a/internal/v1/websvc/websvc_test.go b/internal/v1/websvc/websvc_test.go index 01b892cd..459ffd14 100644 --- a/internal/v1/websvc/websvc_test.go +++ b/internal/v1/websvc/websvc_test.go @@ -18,7 +18,17 @@ import ( const testTimeout = 1 * time.Second -func TestService_Start_getHealthCheck(t *testing.T) { +// testStart is the server start value for tests. +var testStart = time.Date(2022, 1, 1, 0, 0, 0, 0, time.UTC) + +// newTestServer creates and starts a new web service instance as well as its +// sole address. It also registers a cleanup procedure, which shuts the +// instance down. +// +// TODO(a.garipov): Use svc or remove it. +func newTestServer(t testing.TB) (svc *websvc.Service, addr string) { + t.Helper() + c := &websvc.Config{ TLS: nil, Addresses: []*netutil.IPPort{{ @@ -27,9 +37,10 @@ func TestService_Start_getHealthCheck(t *testing.T) { }}, SecureAddresses: nil, Timeout: testTimeout, + Start: testStart, } - svc := websvc.New(c) + svc = websvc.New(c) err := svc.Start() require.NoError(t, err) @@ -44,26 +55,43 @@ func TestService_Start_getHealthCheck(t *testing.T) { addrs := svc.Addrs() require.Len(t, addrs, 1) - u := &url.URL{ - Scheme: "http", - Host: addrs[0], - Path: "/health-check", - } + return svc, addrs[0] +} + +// httpGet is a helper that performs an HTTP GET request and returns the body of +// the response as well as checks that the status code is correct. +// +// TODO(a.garipov): Add helpers for other methods. +func httpGet(t testing.TB, u *url.URL, wantCode int) (body []byte) { + t.Helper() + req, err := http.NewRequest(http.MethodGet, u.String(), nil) - require.NoError(t, err) + require.NoErrorf(t, err, "creating req") httpCli := &http.Client{ Timeout: testTimeout, } resp, err := httpCli.Do(req) - require.NoError(t, err) + require.NoErrorf(t, err, "performing req") + require.Equal(t, wantCode, resp.StatusCode) testutil.CleanupAndRequireSuccess(t, resp.Body.Close) - assert.Equal(t, http.StatusOK, resp.StatusCode) + body, err = io.ReadAll(resp.Body) + require.NoErrorf(t, err, "reading body") - body, err := io.ReadAll(resp.Body) - require.NoError(t, err) + return body +} + +func TestService_Start_getHealthCheck(t *testing.T) { + _, addr := newTestServer(t) + u := &url.URL{ + Scheme: "http", + Host: addr, + Path: websvc.PathHealthCheck, + } + + body := httpGet(t, u, http.StatusOK) assert.Equal(t, []byte("OK"), body) } diff --git a/openapi/v1.yaml b/openapi/v1.yaml index 30c318bc..a9092c98 100644 --- a/openapi/v1.yaml +++ b/openapi/v1.yaml @@ -3393,11 +3393,17 @@ 'description': > Information about the AdGuard Home server. 'example': + 'arch': 'amd64' 'channel': 'release' - 'new_version': 'v0.106.1' + 'new_version': 'v0.108.1' + 'os': 'linux' 'start': 1614345496000 - 'version': 'v0.106.0' + 'version': 'v0.108.0' 'properties': + 'arch': + 'description': > + CPU architecture. + 'type': 'string' 'channel': '$ref': '#/components/schemas/Channel' 'new_version': @@ -3405,6 +3411,10 @@ New available version of AdGuard Home to which the server can be updated, if any. If there are none, this field is absent. 'type': 'string' + 'os': + 'description': > + Operating system type. + 'type': 'string' 'start': 'description': > Unix time at which AdGuard Home started working, in milliseconds. @@ -3415,7 +3425,9 @@ Current AdGuard Home version. 'type': 'string' 'required': + - 'arch' - 'channel' + - 'os' - 'start' - 'version' 'type': 'object' From 79d85a24e970450767997d2e3a1b1876f652f0f7 Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Wed, 18 May 2022 15:00:36 +0300 Subject: [PATCH 043/110] Pull request: all: log changes Updates #4273. Squashed commit of the following: commit ebae1a4d0944fa348b7dcb7e73e59d083c7a5e97 Author: Eugene Burkov Date: Wed May 18 14:48:16 2022 +0300 all: log changes --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c2fa06c..d183c45d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -127,6 +127,7 @@ In this release, the schema version has changed from 12 to 14. ### Fixed +- Detection of the stopped service status on macOS and Linux ([#4273]). - Case-sensitive ClientID ([#4542]). - Slow version update queries making other HTTP APIs unresponsible ([#4499]). - ARP tables refreshing process causing excessive PTR requests ([#3157]). @@ -146,6 +147,7 @@ In this release, the schema version has changed from 12 to 14. [#4213]: https://github.com/AdguardTeam/AdGuardHome/issues/4213 [#4221]: https://github.com/AdguardTeam/AdGuardHome/issues/4221 [#4238]: https://github.com/AdguardTeam/AdGuardHome/issues/4238 +[#4273]: https://github.com/AdguardTeam/AdGuardHome/issues/4273 [#4276]: https://github.com/AdguardTeam/AdGuardHome/issues/4276 [#4499]: https://github.com/AdguardTeam/AdGuardHome/issues/4499 [#4533]: https://github.com/AdguardTeam/AdGuardHome/issues/4533 From 24d7dc8e8a36654bc8d2d64c2014419bd7a9eb25 Mon Sep 17 00:00:00 2001 From: Dimitry Kolyshev Date: Mon, 23 May 2022 16:04:14 +0300 Subject: [PATCH 044/110] Pull request: all: upd dnsproxy Merge in DNS/adguard-home from 4503-upstream-conf to master Squashed commit of the following: commit c6cb1babd4cbf9aacafe902e3d54ce17e8d2cc81 Merge: 75d85ed1 79d85a24 Author: Dimitry Kolyshev Date: Mon May 23 13:06:00 2022 +0200 Merge remote-tracking branch 'origin/master' into 4503-upstream-conf commit 75d85ed1f4d8d5060800b2f8a4cde662db02ae30 Author: Dimitry Kolyshev Date: Fri May 20 13:14:16 2022 +0200 all: upd dnsproxy commit 781768d639388a60fc90631f819cfc5dd90b9eba Author: Dimitry Kolyshev Date: Mon May 16 16:27:25 2022 +0200 all: docs commit 0dafb5b3fe11b1952d9a04294bcaaa8091b9c2a7 Author: Dimitry Kolyshev Date: Mon May 16 16:17:35 2022 +0200 all: docs commit 0d5463e4157132b0e6be78fd97eaf5a5cb8d1edc Merge: e2c86909 f289f4b1 Author: Dimitry Kolyshev Date: Mon May 16 16:01:40 2022 +0200 Merge remote-tracking branch 'origin/master' into 4503-upstream-conf # Conflicts: # go.mod # go.sum commit e2c869091b1386065076f44dbf9498a31c9d5451 Author: Dimitry Kolyshev Date: Mon May 16 15:29:17 2022 +0200 all: upd dnsrpoxy --- CHANGELOG.md | 2 ++ go.mod | 2 +- go.sum | 4 ++-- internal/dnsforward/http.go | 1 + 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d183c45d..8aca8f15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ and this project adheres to ### Added +- Support upstreams for subdomains of a domain only ([#4503]). - Support for Discovery of Designated Resolvers (DDR) according to the [RFC draft][ddr-draft-06] ([#4463]). - The ability to control each source of runtime clients separately via @@ -150,6 +151,7 @@ In this release, the schema version has changed from 12 to 14. [#4273]: https://github.com/AdguardTeam/AdGuardHome/issues/4273 [#4276]: https://github.com/AdguardTeam/AdGuardHome/issues/4276 [#4499]: https://github.com/AdguardTeam/AdGuardHome/issues/4499 +[#4503]: https://github.com/AdguardTeam/AdGuardHome/issues/4503 [#4533]: https://github.com/AdguardTeam/AdGuardHome/issues/4533 [#4542]: https://github.com/AdguardTeam/AdGuardHome/issues/4542 diff --git a/go.mod b/go.mod index 8da34653..4d9d2191 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/AdguardTeam/AdGuardHome go 1.17 require ( - github.com/AdguardTeam/dnsproxy v0.42.2 + github.com/AdguardTeam/dnsproxy v0.42.4 github.com/AdguardTeam/golibs v0.10.8 github.com/AdguardTeam/urlfilter v0.16.0 github.com/NYTimes/gziphandler v1.1.1 diff --git a/go.sum b/go.sum index 807a6849..73accb25 100644 --- a/go.sum +++ b/go.sum @@ -7,8 +7,8 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= -github.com/AdguardTeam/dnsproxy v0.42.2 h1:aBhbuvqg/rZN8Rab5ILSfPFJDkiTviWXXcceJgajnNs= -github.com/AdguardTeam/dnsproxy v0.42.2/go.mod h1:thHuk3599mgmucsv5J9HR9lBVQHnf4YleE08EbxNrN0= +github.com/AdguardTeam/dnsproxy v0.42.4 h1:Rf45a3H6U/8XqWMYAMEsC1g/dVudyfgx4WY8N2syJMw= +github.com/AdguardTeam/dnsproxy v0.42.4/go.mod h1:thHuk3599mgmucsv5J9HR9lBVQHnf4YleE08EbxNrN0= github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4= github.com/AdguardTeam/golibs v0.4.2/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4= github.com/AdguardTeam/golibs v0.10.4/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw= diff --git a/internal/dnsforward/http.go b/internal/dnsforward/http.go index 2b7cfd13..50ab9643 100644 --- a/internal/dnsforward/http.go +++ b/internal/dnsforward/http.go @@ -510,6 +510,7 @@ func separateUpstream(upstreamStr string) (upstream string, isDomainSpec bool, e continue } + host = strings.TrimPrefix(host, "*.") err = netutil.ValidateDomainName(host) if err != nil { return "", true, fmt.Errorf("domain at index %d: %w", i, err) From c0ac82be6a91cd4f5e43e7de6281d2854bbf63c2 Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Tue, 24 May 2022 14:43:54 +0300 Subject: [PATCH 045/110] Pull request: 4480 fix sysv service script Merge in DNS/adguard-home from 4480-sysv-boot to master Updates #4480. Squashed commit of the following: commit c9645b1f3bd22a249c666e4485818bab6769f32d Author: Eugene Burkov Date: Tue May 24 14:25:09 2022 +0300 home: imp sysv script commit cc323364ba6cce0284cbc6be9133a50a51b71f56 Author: Eugene Burkov Date: Mon May 23 21:13:06 2022 +0300 home: fix sysv service script --- CHANGELOG.md | 2 ++ internal/home/service.go | 9 ++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8aca8f15..9d837c95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -128,6 +128,7 @@ In this release, the schema version has changed from 12 to 14. ### Fixed +- Service startup on boot on systems using SysV-init ([#4480]). - Detection of the stopped service status on macOS and Linux ([#4273]). - Case-sensitive ClientID ([#4542]). - Slow version update queries making other HTTP APIs unresponsible ([#4499]). @@ -150,6 +151,7 @@ In this release, the schema version has changed from 12 to 14. [#4238]: https://github.com/AdguardTeam/AdGuardHome/issues/4238 [#4273]: https://github.com/AdguardTeam/AdGuardHome/issues/4273 [#4276]: https://github.com/AdguardTeam/AdGuardHome/issues/4276 +[#4480]: https://github.com/AdguardTeam/AdGuardHome/issues/4480 [#4499]: https://github.com/AdguardTeam/AdGuardHome/issues/4499 [#4503]: https://github.com/AdguardTeam/AdGuardHome/issues/4503 [#4533]: https://github.com/AdguardTeam/AdGuardHome/issues/4533 diff --git a/internal/home/service.go b/internal/home/service.go index 70ab3c78..831a80d0 100644 --- a/internal/home/service.go +++ b/internal/home/service.go @@ -433,8 +433,11 @@ EnvironmentFile=-/etc/sysconfig/{{.Name}} WantedBy=multi-user.target ` -// Note: we should keep it in sync with the template from service_sysv_linux.go file -// Use "ps | grep -v grep | grep $(get_pid)" because "ps PID" may not work on OpenWrt +// sysvScript is the source of the daemon script for SysV-based Linux systems. +// Keep as close as possible to the https://github.com/kardianos/service/blob/29f8c79c511bc18422bb99992779f96e6bc33921/service_sysv_linux.go#L187. +// +// Use ps command instead of reading the procfs since it's a more +// implementation-independent approach. const sysvScript = `#!/bin/sh # For RedHat and cousins: # chkconfig: - 99 01 @@ -465,7 +468,7 @@ get_pid() { } is_running() { - [ -f "$pid_file" ] && ps | grep -v grep | grep $(get_pid) > /dev/null 2>&1 + [ -f "$pid_file" ] && ps -p "$(get_pid)" > /dev/null 2>&1 } case "$1" in From a82ec09afdfbc66a8f07614b77e825f527a3b35b Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Tue, 24 May 2022 19:47:09 +0300 Subject: [PATCH 046/110] Pull request: all: upd dnsproxy, supp rfc 9250 Updates #4592. Squashed commit of the following: commit 1a80875d6aa7811d7d1d978f6fa8d558dec1ca87 Author: Ainar Garipov Date: Tue May 24 19:28:27 2022 +0300 all: upd dnsproxy, supp rfc 9250 --- CHANGELOG.md | 10 ++++++---- go.mod | 4 ++-- go.sum | 14 ++++---------- internal/dnsforward/clientid.go | 12 ++++++------ internal/dnsforward/clientid_test.go | 25 +++++++++++++------------ 5 files changed, 31 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d837c95..e0c32ce7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ and this project adheres to ### Added +- Support for the final DNS-over-QUIC standard, [RFC 9250][rfc-9250] ([#4592]). - Support upstreams for subdomains of a domain only ([#4503]). - Support for Discovery of Designated Resolvers (DDR) according to the [RFC draft][ddr-draft-06] ([#4463]). @@ -45,7 +46,7 @@ and this project adheres to instead of the `/bin/sh` one ([#4533]). To apply this change, backup your data and run `AdGuardHome -s uninstall && AdGuardHome -s install`. - The default DNS-over-QUIC port number is now `853` instead of `754` in - accordance with the latest [RFC draft][doq-draft-10] ([#4276]). + accordance with [RFC 9250][rfc-9250] ([#4276]). - Reverse DNS now has a greater priority as the source of runtime clients' information than ARP neighborhood. - Improved detection of runtime clients through more resilient ARP processing @@ -100,7 +101,7 @@ In this release, the schema version has changed from 12 to 14. `dns.resolve_clients` property. To rollback this change, remove the `runtime_sources` property, move the contents of `persistent` into the `clients` itself, the value of `clients.runtime_sources.rdns` into the - `dns.resolve_clietns`, and change the `schema_version` back to `13`. + `dns.resolve_clients`, and change the `schema_version` back to `13`. - Property `local_domain_name`, which in schema versions 12 and earlier used to be a part of the `dns` object, is now a part of the `dhcp` object: @@ -131,7 +132,7 @@ In this release, the schema version has changed from 12 to 14. - Service startup on boot on systems using SysV-init ([#4480]). - Detection of the stopped service status on macOS and Linux ([#4273]). - Case-sensitive ClientID ([#4542]). -- Slow version update queries making other HTTP APIs unresponsible ([#4499]). +- Slow version update queries making other HTTP APIs unresponsive ([#4499]). - ARP tables refreshing process causing excessive PTR requests ([#3157]). [#1730]: https://github.com/AdguardTeam/AdGuardHome/issues/1730 @@ -156,9 +157,10 @@ In this release, the schema version has changed from 12 to 14. [#4503]: https://github.com/AdguardTeam/AdGuardHome/issues/4503 [#4533]: https://github.com/AdguardTeam/AdGuardHome/issues/4533 [#4542]: https://github.com/AdguardTeam/AdGuardHome/issues/4542 +[#4592]: https://github.com/AdguardTeam/AdGuardHome/issues/4592 +[rfc-9250]: https://datatracker.ietf.org/doc/html/rfc9250 [ddr-draft-06]: https://www.ietf.org/archive/id/draft-ietf-add-ddr-06.html -[doq-draft-10]: https://datatracker.ietf.org/doc/html/draft-ietf-dprive-dnsoquic-10#section-10.2 [repr]: https://reproducible-builds.org/docs/source-date-epoch/ diff --git a/go.mod b/go.mod index 4d9d2191..d3c3e1de 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/AdguardTeam/AdGuardHome go 1.17 require ( - github.com/AdguardTeam/dnsproxy v0.42.4 + github.com/AdguardTeam/dnsproxy v0.43.0 github.com/AdguardTeam/golibs v0.10.8 github.com/AdguardTeam/urlfilter v0.16.0 github.com/NYTimes/gziphandler v1.1.1 @@ -17,7 +17,7 @@ require ( github.com/google/renameio v1.0.1 github.com/insomniacslk/dhcp v0.0.0-20220405050111-12fbdcb11b41 github.com/kardianos/service v1.2.1 - github.com/lucas-clemente/quic-go v0.26.0 + github.com/lucas-clemente/quic-go v0.27.1 github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118 github.com/mdlayher/netlink v1.6.0 // TODO(a.garipov): This package is deprecated; find a new one or use diff --git a/go.sum b/go.sum index 73accb25..ae65fdab 100644 --- a/go.sum +++ b/go.sum @@ -7,8 +7,8 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= -github.com/AdguardTeam/dnsproxy v0.42.4 h1:Rf45a3H6U/8XqWMYAMEsC1g/dVudyfgx4WY8N2syJMw= -github.com/AdguardTeam/dnsproxy v0.42.4/go.mod h1:thHuk3599mgmucsv5J9HR9lBVQHnf4YleE08EbxNrN0= +github.com/AdguardTeam/dnsproxy v0.43.0 h1:K082nx37DaNqSyT3kDtAfgBACNWc+ZDI1Yr/kGppu1k= +github.com/AdguardTeam/dnsproxy v0.43.0/go.mod h1:JUGTm5dmlll47JltztsT0N//pVJjdg6zu0SNeUeaA7g= github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4= github.com/AdguardTeam/golibs v0.4.2/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4= github.com/AdguardTeam/golibs v0.10.4/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw= @@ -143,21 +143,15 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T2U9ZlW1AaHOsMOg= -github.com/lucas-clemente/quic-go v0.26.0 h1:ALBQXr9UJ8A1LyzvceX4jd9QFsHvlI0RR6BkV16o00A= -github.com/lucas-clemente/quic-go v0.26.0/go.mod h1:AzgQoPda7N+3IqMMMkywBKggIFo2KT6pfnlrQ2QieeI= +github.com/lucas-clemente/quic-go v0.27.1 h1:sOw+4kFSVrdWOYmUjufQ9GBVPqZ+tu+jMtXxXNmRJyk= +github.com/lucas-clemente/quic-go v0.27.1/go.mod h1:AzgQoPda7N+3IqMMMkywBKggIFo2KT6pfnlrQ2QieeI= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc= -github.com/marten-seemann/qtls-go1-15 v0.1.4/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= -github.com/marten-seemann/qtls-go1-16 v0.1.4/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk= github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ= github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk= -github.com/marten-seemann/qtls-go1-17 v0.1.0/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8= github.com/marten-seemann/qtls-go1-17 v0.1.1 h1:DQjHPq+aOzUeh9/lixAGunn6rIOQyWChPSI4+hgW7jc= github.com/marten-seemann/qtls-go1-17 v0.1.1/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s= -github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1/go.mod h1:PUhIQk19LoFt2174H4+an8TYvWOGjb/hHwphBeaDHwI= -github.com/marten-seemann/qtls-go1-18 v0.1.0/go.mod h1:PUhIQk19LoFt2174H4+an8TYvWOGjb/hHwphBeaDHwI= github.com/marten-seemann/qtls-go1-18 v0.1.1 h1:qp7p7XXUFL7fpBvSS1sWD+uSqPvzNQK43DH+/qEkj0Y= github.com/marten-seemann/qtls-go1-18 v0.1.1/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= diff --git a/internal/dnsforward/clientid.go b/internal/dnsforward/clientid.go index bb687a41..16bac881 100644 --- a/internal/dnsforward/clientid.go +++ b/internal/dnsforward/clientid.go @@ -112,8 +112,8 @@ type tlsConn interface { ConnectionState() (cs tls.ConnectionState) } -// quicSession is a narrow interface for quic.Session to simplify testing. -type quicSession interface { +// quicConnection is a narrow interface for quic.Connection to simplify testing. +type quicConnection interface { ConnectionState() (cs quic.ConnectionState) } @@ -148,16 +148,16 @@ func (s *Server) clientIDFromDNSContext(pctx *proxy.DNSContext) (clientID string cliSrvName = tc.ConnectionState().ServerName case proxy.ProtoQUIC: - qs, ok := pctx.QUICSession.(quicSession) + conn, ok := pctx.QUICConnection.(quicConnection) if !ok { return "", fmt.Errorf( - "proxy ctx quic session of proto %s is %T, want quic.Session", + "proxy ctx quic conn of proto %s is %T, want quic.Connection", proto, - pctx.QUICSession, + pctx.QUICConnection, ) } - cliSrvName = qs.ConnectionState().TLS.ServerName + cliSrvName = conn.ConnectionState().TLS.ServerName } clientID, err = clientIDFromClientServerName( diff --git a/internal/dnsforward/clientid_test.go b/internal/dnsforward/clientid_test.go index 6e23d639..31c55fcd 100644 --- a/internal/dnsforward/clientid_test.go +++ b/internal/dnsforward/clientid_test.go @@ -29,17 +29,18 @@ func (c testTLSConn) ConnectionState() (cs tls.ConnectionState) { return cs } -// testQUICSession is a quicSession for tests. -type testQUICSession struct { - // Session is embedded here simply to make testQUICSession a quic.Session - // without actually implementing all methods. - quic.Session +// testQUICConnection is a quicConnection for tests. +type testQUICConnection struct { + // Connection is embedded here simply to make testQUICConnection a + // quic.Connection without actually implementing all methods. + quic.Connection serverName string } -// ConnectionState implements the quicSession interface for testQUICSession. -func (c testQUICSession) ConnectionState() (cs quic.ConnectionState) { +// ConnectionState implements the quicConnection interface for +// testQUICConnection. +func (c testQUICConnection) ConnectionState() (cs quic.ConnectionState) { cs.TLS.ServerName = c.serverName return cs @@ -179,17 +180,17 @@ func TestServer_clientIDFromDNSContext(t *testing.T) { } } - var qs quic.Session + var qconn quic.Connection if tc.proto == proxy.ProtoQUIC { - qs = testQUICSession{ + qconn = testQUICConnection{ serverName: tc.cliSrvName, } } pctx := &proxy.DNSContext{ - Proto: tc.proto, - Conn: conn, - QUICSession: qs, + Proto: tc.proto, + Conn: conn, + QUICConnection: qconn, } clientID, err := srv.clientIDFromDNSContext(pctx) From 75f01d51f7312601cd323bdbdd4648dfd673ea75 Mon Sep 17 00:00:00 2001 From: Dimitry Kolyshev Date: Wed, 25 May 2022 14:31:32 +0300 Subject: [PATCH 047/110] Pull request: all: filters json Merge in DNS/adguard-home from 4581-filters-json to master Squashed commit of the following: commit da0b86983432ac1791645da328df5848daac5ea6 Merge: 62fa4fc6 a82ec09a Author: Dimitry Kolyshev Date: Wed May 25 12:58:25 2022 +0200 Merge remote-tracking branch 'origin/master' into 4581-filters-json commit 62fa4fc6ff150ebb8dbd8888a58819fb644d43ad Author: Dimitry Kolyshev Date: Wed May 25 11:55:52 2022 +0200 all: filters json commit 96486ffbb41947b5e748f6e35eb96ee73867eba1 Merge: 9956f0af c0ac82be Author: Dimitry Kolyshev Date: Tue May 24 15:57:52 2022 +0200 Merge branch 'master' into 4581-filters-json commit 9956f0aff1b7029f336d22013a62f2871a964322 Author: Dimitry Kolyshev Date: Tue May 24 15:53:43 2022 +0200 all: filters json --- client/src/helpers/filters/filters.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/helpers/filters/filters.json b/client/src/helpers/filters/filters.json index 565cd74d..63fe0995 100644 --- a/client/src/helpers/filters/filters.json +++ b/client/src/helpers/filters/filters.json @@ -81,8 +81,8 @@ "urlhaus-filter-online": { "name": "Online Malicious URL Blocklist", "categoryId": "security", - "homepage": "https://gitlab.com/curben/urlhaus-filter", - "source": "https://curben.gitlab.io/malware-filter/urlhaus-filter-agh-online.txt" + "homepage": "https://gitlab.com/malware-filter/urlhaus-filter", + "source": "https://malware-filter.gitlab.io/malware-filter/urlhaus-filter-agh-online.txt" }, "dandelion-sprouts-anti-malware-list": { "name": "Dandelion Sprout's Anti-Malware List", From 549b20bdea3c3215bb355ffc39546f7bb3260d80 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Wed, 25 May 2022 18:00:50 +0300 Subject: [PATCH 048/110] Pull request: querylog: fix oldest calc Updates #4591. Squashed commit of the following: commit 70b70c78c85311363535536c7ea12336b21accf8 Author: Ainar Garipov Date: Wed May 25 17:35:54 2022 +0300 querylog: fix oldest calc --- CHANGELOG.md | 2 ++ internal/dnsforward/stats.go | 2 +- internal/home/dns.go | 2 +- internal/querylog/http.go | 2 +- internal/querylog/qlog.go | 2 +- internal/querylog/qlog_test.go | 2 +- internal/querylog/querylog.go | 18 +++++++++--------- internal/querylog/search.go | 17 ++++++++++++----- 8 files changed, 28 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0c32ce7..4a72447c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -129,6 +129,7 @@ In this release, the schema version has changed from 12 to 14. ### Fixed +- Query log occasionally going into an infinite loop ([#4591]). - Service startup on boot on systems using SysV-init ([#4480]). - Detection of the stopped service status on macOS and Linux ([#4273]). - Case-sensitive ClientID ([#4542]). @@ -157,6 +158,7 @@ In this release, the schema version has changed from 12 to 14. [#4503]: https://github.com/AdguardTeam/AdGuardHome/issues/4503 [#4533]: https://github.com/AdguardTeam/AdGuardHome/issues/4533 [#4542]: https://github.com/AdguardTeam/AdGuardHome/issues/4542 +[#4591]: https://github.com/AdguardTeam/AdGuardHome/issues/4591 [#4592]: https://github.com/AdguardTeam/AdGuardHome/issues/4592 [rfc-9250]: https://datatracker.ietf.org/doc/html/rfc9250 diff --git a/internal/dnsforward/stats.go b/internal/dnsforward/stats.go index 56cc19c5..9a7b1ddb 100644 --- a/internal/dnsforward/stats.go +++ b/internal/dnsforward/stats.go @@ -64,9 +64,9 @@ func (s *Server) logQuery( Answer: pctx.Res, OrigAnswer: dctx.origResp, Result: dctx.result, - Elapsed: elapsed, ClientID: dctx.clientID, ClientIP: ip, + Elapsed: elapsed, AuthenticatedData: dctx.responseAD, } diff --git a/internal/home/dns.go b/internal/home/dns.go index 1c04c6c3..9eabfefa 100644 --- a/internal/home/dns.go +++ b/internal/home/dns.go @@ -58,6 +58,7 @@ func initDNSServer() (err error) { } conf := querylog.Config{ + Anonymizer: anonymizer, ConfigModified: onConfigModified, HTTPRegister: httpRegister, FindClient: Context.clients.findMultiple, @@ -67,7 +68,6 @@ func initDNSServer() (err error) { Enabled: config.DNS.QueryLogEnabled, FileEnabled: config.DNS.QueryLogFileEnabled, AnonymizeClientIP: config.DNS.AnonymizeClientIP, - Anonymizer: anonymizer, } Context.queryLog = querylog.New(conf) diff --git a/internal/querylog/http.go b/internal/querylog/http.go index 6a2bdcee..11f62d0d 100644 --- a/internal/querylog/http.go +++ b/internal/querylog/http.go @@ -19,10 +19,10 @@ import ( ) type qlogConfig struct { - Enabled bool `json:"enabled"` // Use float64 here to support fractional numbers and not mess the API // users by changing the units. Interval float64 `json:"interval"` + Enabled bool `json:"enabled"` AnonymizeClientIP bool `json:"anonymize_client_ip"` } diff --git a/internal/querylog/qlog.go b/internal/querylog/qlog.go index 8856fd9c..24eec40e 100644 --- a/internal/querylog/qlog.go +++ b/internal/querylog/qlog.go @@ -149,7 +149,7 @@ func (l *queryLog) clear() { log.Error("removing log file %q: %s", l.logFile, err) } - log.Debug("Query log: cleared") + log.Debug("querylog: cleared") } func (l *queryLog) Add(params *AddParams) { diff --git a/internal/querylog/qlog_test.go b/internal/querylog/qlog_test.go index fbfc459d..6beed1be 100644 --- a/internal/querylog/qlog_test.go +++ b/internal/querylog/qlog_test.go @@ -285,8 +285,8 @@ func addEntry(l *queryLog, host string, answerStr, client net.IP) { Answer: &a, OrigAnswer: &a, Result: &res, - ClientIP: client, Upstream: "upstream", + ClientIP: client, } l.Add(params) diff --git a/internal/querylog/querylog.go b/internal/querylog/querylog.go index bd6e1569..a854c2c4 100644 --- a/internal/querylog/querylog.go +++ b/internal/querylog/querylog.go @@ -28,8 +28,11 @@ type QueryLog interface { WriteDiskConfig(c *Config) } -// Config - configuration object +// Config is the query log configuration structure. type Config struct { + // Anonymizer processes the IP addresses to anonymize those if needed. + Anonymizer *aghnet.IPMut + // ConfigModified is called when the configuration is changed, for // example by HTTP requests. ConfigModified func() @@ -68,9 +71,6 @@ type Config struct { // AnonymizeClientIP tells if the query log should anonymize clients' IP // addresses. AnonymizeClientIP bool - - // Anonymizer processes the IP addresses to anonymize those if needed. - Anonymizer *aghnet.IPMut } // AddParams is the parameters for adding an entry. @@ -91,18 +91,18 @@ type AddParams struct { // Result is the filtering result (optional). Result *filtering.Result - // Elapsed is the time spent for processing the request. - Elapsed time.Duration - ClientID string - ClientIP net.IP - // Upstream is the URL of the upstream DNS server. Upstream string ClientProto ClientProto + ClientIP net.IP + + // Elapsed is the time spent for processing the request. + Elapsed time.Duration + // Cached indicates if the response is served from cache. Cached bool diff --git a/internal/querylog/search.go b/internal/querylog/search.go index 4a3de979..8fb32e60 100644 --- a/internal/querylog/search.go +++ b/internal/querylog/search.go @@ -73,7 +73,7 @@ func (l *queryLog) searchMemory(params *searchParams, cache clientCache) (entrie // search - searches log entries in the query log using specified parameters // returns the list of entries found + time of the oldest entry -func (l *queryLog) search(params *searchParams) ([]*logEntry, time.Time) { +func (l *queryLog) search(params *searchParams) (entries []*logEntry, oldest time.Time) { now := time.Now() if params.limit == 0 { @@ -88,7 +88,7 @@ func (l *queryLog) search(params *searchParams) ([]*logEntry, time.Time) { totalLimit := params.offset + params.limit // now let's get a unified collection - entries := append(memoryEntries, fileEntries...) + entries = append(memoryEntries, fileEntries...) if len(entries) > totalLimit { // remove extra records entries = entries[:totalLimit] @@ -111,13 +111,18 @@ func (l *queryLog) search(params *searchParams) ([]*logEntry, time.Time) { } } - if len(entries) > 0 && len(entries) <= totalLimit { + if len(entries) > 0 { // Update oldest after merging in the memory buffer. oldest = entries[len(entries)-1].Time } - log.Debug("QueryLog: prepared data (%d/%d) older than %s in %s", - len(entries), total, params.olderThan, time.Since(now)) + log.Debug( + "querylog: prepared data (%d/%d) older than %s in %s", + len(entries), + total, + params.olderThan, + time.Since(now), + ) return entries, oldest } @@ -180,6 +185,8 @@ func (l *queryLog) searchFiles( e, ts, err = l.readNextEntry(r, params, cache) if err != nil { if err == io.EOF { + oldestNano = 0 + break } From 1a49d2f0c9eff0e084de83598e5e5825125d5905 Mon Sep 17 00:00:00 2001 From: Ildar Kamalov Date: Thu, 26 May 2022 12:49:13 +0300 Subject: [PATCH 049/110] Pull request: client: reset filtered logs on url params clear Merge in DNS/adguard-home from fix-querylog-link to master Squashed commit of the following: commit fc4043258eb1e427a76ee44d2a4a525a6d659ab9 Merge: 25b91504 549b20bd Author: Ildar Kamalov Date: Thu May 26 12:42:02 2022 +0300 Merge branch 'master' into fix-querylog-link commit 25b91504e8949bd381e6774148e4a7ecbb81610e Author: Ildar Kamalov Date: Thu May 26 12:21:57 2022 +0300 fix commit f567b9b1e4eeb6499c79b05e4d837e905850a6b9 Author: Ildar Kamalov Date: Thu May 26 12:20:48 2022 +0300 client: reset filtered logs on url params clear --- client/src/components/Logs/index.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/client/src/components/Logs/index.js b/client/src/components/Logs/index.js index c3b30703..3e89c3b1 100644 --- a/client/src/components/Logs/index.js +++ b/client/src/components/Logs/index.js @@ -152,6 +152,16 @@ const Logs = () => { }; }, []); + useEffect(() => { + if (!history.location.search) { + (async () => { + setIsLoading(true); + await dispatch(setFilteredLogs()); + setIsLoading(false); + })(); + } + }, [history.location.search]); + const renderPage = () => <> Date: Thu, 26 May 2022 14:20:36 +0300 Subject: [PATCH 050/110] Pull request: client: upd i18n Merge in DNS/adguard-home from upd-i18n to master Squashed commit of the following: commit 7ddd8cb01f8136ad4690a439ee3b810043af749e Author: Ainar Garipov Date: Thu May 26 14:10:31 2022 +0300 client: upd i18n --- client/src/__locales/cs.json | 2 +- client/src/__locales/fi.json | 4 +-- client/src/__locales/pt-br.json | 2 +- client/src/__locales/pt-pt.json | 2 +- client/src/__locales/sl.json | 4 +-- client/src/__locales/tr.json | 12 ++++---- client/src/__locales/uk.json | 50 ++++++++++++++++----------------- client/src/__locales/zh-cn.json | 1 + 8 files changed, 39 insertions(+), 38 deletions(-) diff --git a/client/src/__locales/cs.json b/client/src/__locales/cs.json index 8331dd50..8467df91 100644 --- a/client/src/__locales/cs.json +++ b/client/src/__locales/cs.json @@ -85,7 +85,7 @@ "form_enter_hostname": "Zadejte název hostitele", "error_details": "Podrobnosti chyby", "response_details": "Detail odpovědi", - "request_details": "Detail požadavku", + "request_details": "Detaily požadavku", "client_details": "Detaily klienta", "details": "Detaily", "back": "Zpět", diff --git a/client/src/__locales/fi.json b/client/src/__locales/fi.json index 3141b12a..a5f3fa01 100644 --- a/client/src/__locales/fi.json +++ b/client/src/__locales/fi.json @@ -9,7 +9,7 @@ "bootstrap_dns": "Bootstrap DNS-palvelimet", "bootstrap_dns_desc": "Bootstrap DNS-palvelimia käytetään ylävirroiksi määritettyjen DoH/DoT-resolvereiden IP-osoitteiden selvitykseen.", "local_ptr_title": "Yksityiset käänteiset DNS-palvelimet", - "local_ptr_desc": "DNS-palvelimet, joita AdGuard Home käyttää paikallisille PTR-pyynnöille. Näitä palvelimia käytetään yksityistä IP-osoitetta käyttävien päätelaitteiden osoitteiden, kuten \"192.168.12.34\", selvitykseen käänteisen DNS:n avulla. Jos ei käytössä, käyttää AdGuard Home käyttöjärjestelmän oletusarvoisia DNS-resolvereita, poislukien AdGuard Homen omat osoitteet.", + "local_ptr_desc": "DNS-palvelimet, joita AdGuard Home käyttää paikallisille PTR-kyselyille. Näitä palvelimia käytetään yksityistä IP-osoitetta käyttävien PTR-kyselyiden osoitteiden, kuten \"192.168.12.34\", selvitykseen käänteisen DNS:n avulla. Jos ei käytössä, AdGuard Home käyttää käyttöjärjestelmän oletusarvoisia DNS-resolvereita, poislukien AdGuard Homen omat osoitteet.", "local_ptr_default_resolver": "Oletusarvoisesti AdGuard Home käyttää seuraavia käänteisiä DNS-resolvereita: {{ip}}.", "local_ptr_no_default_resolver": "AdGuard Home ei voinut määrittää tälle järjestelmälle sopivaa yksityistä käänteistä DNS-resolveria.", "local_ptr_placeholder": "Syötä yksi palvelimen osoite per rivi", @@ -351,7 +351,7 @@ "install_devices_android_list_5": "Syötä \"DNS 1\" ja \"DNS 2\" -kenttiin AdGuard Home -palvelimesi osoitteet.", "install_devices_ios_list_1": "Napauta aloitusnäytöstä \"Asetukset\".", "install_devices_ios_list_2": "Valitse vasemmalta \"Wi-Fi\" (mobiiliverkolle ei ole mahdollista määrittää omaa DNS-palvelinta).", - "install_devices_ios_list_3": "Valitse yhdistetty verkko.", + "install_devices_ios_list_3": "Valitse tällä hetkellä aktiivinen verkko.", "install_devices_ios_list_4": "Syötä \"DNS\" -kenttään AdGuard Home -palvelimesi osoitteet.", "get_started": "Aloita", "next": "Seuraava", diff --git a/client/src/__locales/pt-br.json b/client/src/__locales/pt-br.json index 48d82e0d..d52d6961 100644 --- a/client/src/__locales/pt-br.json +++ b/client/src/__locales/pt-br.json @@ -9,7 +9,7 @@ "bootstrap_dns": "Servidores DNS de inicialização", "bootstrap_dns_desc": "Servidores DNS de inicialização são usados para resolver endereços IP dos resolvedores DoH/DoT que você especifica como upstreams.", "local_ptr_title": "Servidores DNS reversos privados", - "local_ptr_desc": "Os servidores DNS que o AdGuard Home usa para consultas PTR locais. Esses servidores são usados para resolver os nomes de host de clientes com endereços IP privados, por exemplo \"192.168.12.34\", usando DNS reverso. Se não for definido, o AdGuard Home usa os endereços dos resolvedores DNS padrão do seu sistema operacional, exceto os endereços do AdGuard Home.", + "local_ptr_desc": "Os servidores DNS que o AdGuard Home usa para consultas PTR locais. Esses servidores são usados para resolver solicitações de PTR para endereços em intervalos de IP privados, por exemplo \"192.168.12.34\", usando DNS reverso. Se não estiver definido, o AdGuard Home usa os endereços dos resolvedores de DNS padrão do seu sistema operacional, exceto os endereços do próprio AdGuard Home.", "local_ptr_default_resolver": "Por padrão, o AdGuard Home usa os seguintes resolvedores de DNS reverso: {{ip}}.", "local_ptr_no_default_resolver": "A página inicial do AdGuard não conseguiu determinar resolvedores DNS reversos privados adequados para este sistema.", "local_ptr_placeholder": "Insira um endereço de servidor por linha", diff --git a/client/src/__locales/pt-pt.json b/client/src/__locales/pt-pt.json index 1a2d5c7c..6502f9f9 100644 --- a/client/src/__locales/pt-pt.json +++ b/client/src/__locales/pt-pt.json @@ -9,7 +9,7 @@ "bootstrap_dns": "Servidores DNS de arranque", "bootstrap_dns_desc": "Servidores DNS de inicialização são usados para resolver endereços IP dos resolvedores DoH/DoT que especifica como upstreams.", "local_ptr_title": "Servidores DNS reversos privados", - "local_ptr_desc": "Os servidores DNS que o AdGuard Home usa para consultas PTR locais. Esses servidores são usados para resolver os nomes de host de clientes com endereços IP privados, por exemplo \"192.168.12.34\", usando DNS reverso. Se não for definido, o AdGuard Home usa os endereços dos resolvedores DNS padrão do seu sistema operacional, exceto os endereços do AdGuard Home.", + "local_ptr_desc": "Os servidores DNS que o AdGuard Home usa para consultas PTR locais. Esses servidores são usados para resolver solicitações de PTR para endereços em intervalos de IP privados, por exemplo \"192.168.12.34\", usando DNS reverso. Se não estiver definido, o AdGuard Home usa os endereços dos resolvedores de DNS padrão do seu sistema operacional, exceto os endereços do próprio AdGuard Home.", "local_ptr_default_resolver": "Por predefinição, o AdGuard Home usa os seguintes resolvedores de DNS reverso: {{ip}}.", "local_ptr_no_default_resolver": "A página inicial do AdGuard não conseguiu determinar resolvedores DNS reversos privados adequados para este sistema.", "local_ptr_placeholder": "Insira um endereço de servidor por linha", diff --git a/client/src/__locales/sl.json b/client/src/__locales/sl.json index 8dffefc7..80dfd9aa 100644 --- a/client/src/__locales/sl.json +++ b/client/src/__locales/sl.json @@ -9,7 +9,7 @@ "bootstrap_dns": "Zagonski DNS strežniki", "bootstrap_dns_desc": "Zagonski DNS strežniki se uporabljajo za razreševanje IP naslovov DoH/DoT reševalcev, ki jih določite kot navzgornje.", "local_ptr_title": "Zasebni povratni strežniki DNS", - "local_ptr_desc": "Strežniki DNS, ki jih AdGuard Home uporablja za lokalne poizvedbe PTR. Ti strežniki se uporabljajo za razreševanje imen gostiteljev z zasebnimi naslovi IP, na primer \"192.168.12.34\" uporablja DNS. Če ni nastavljen, uporablja naslove privzetih razreševalnikov DNS vašega OS, razen naslovov samega AdGuard Home.", + "local_ptr_desc": "Strežniki DNS, ki jih AdGuard Home uporablja za lokalne PTR poizvedbe. Ti strežniki se uporabljajo za reševanje zahtev PTR za naslove v zasebnih obsegih IP, na primer \"192.168.12.34\", z uporabo obratnega DNS. Če ni nastavljen, AdGuard Home uporablja naslove privzetih razreševalnikov DNS vašega OS, razen naslovov samega AdGuard Home.", "local_ptr_default_resolver": "AdGuard Home privzeto uporablja te povratne razreševalnike DNS: {{ip}}.", "local_ptr_no_default_resolver": "AdGuard Home ni mogel določiti ustreznih zasebnih povratnih reševalcev DNS za ta sistem.", "local_ptr_placeholder": "V vrstico vnesite en naslov strežnika", @@ -351,7 +351,7 @@ "install_devices_android_list_5": "Spremeni nastavitev vrednosti DNS 1 in DNS 2 na naslove strežnikov AdGuard Home.", "install_devices_ios_list_1": "Na začetnem zaslonu izberite Nastavitve.", "install_devices_ios_list_2": "V levem meniju izberite Wi-Fi (nemogoče je konfigurirati DNS za mobilna omrežja).", - "install_devices_ios_list_3": "Dotaknite se imena trenutno aktivnega omrežja.", + "install_devices_ios_list_3": "Tapnite na ime trenutno aktivnega omrežja.", "install_devices_ios_list_4": "V polje DNS vnesite vaše naslove AdGuard Home strežnika.", "get_started": "Začnimo", "next": "Naprej", diff --git a/client/src/__locales/tr.json b/client/src/__locales/tr.json index f26e0011..6fd679ac 100644 --- a/client/src/__locales/tr.json +++ b/client/src/__locales/tr.json @@ -336,16 +336,16 @@ "install_devices_router_list_4": "Bazı yönlendirici türlerinde özel bir DNS sunucusu ayarlanamaz. Bu durumda, AdGuard Home'u <0>DHCP sunucusu olarak ayarlamak yardımcı olabilir. Aksi takdirde, yönlendirici modeliniz için DNS sunucularını nasıl ayarlayacağınız konusunda yönlendirici kılavuzuna bakmalısınız.", "install_devices_windows_list_1": "Başlat menüsünden veya Windows araması aracılığıyla Denetim Masası'nı açın.", "install_devices_windows_list_2": "Ağ ve İnternet kategorisine girin ve ardından Ağ ve Paylaşım Merkezi'ne girin.", - "install_devices_windows_list_3": "Sol panelde \"Bağdaştırıcı ayarlarını değiştirin'e\" tıklayın.", + "install_devices_windows_list_3": "Sol panelde \"Bağdaştırıcı ayarlarını değiştirin\" öğesine tıklayın.", "install_devices_windows_list_4": "Kullandığınız aktif bağlantının üzerine sağ tıklayın ve Özellikler öğesine tıklayın.", - "install_devices_windows_list_5": "Listede \"İnternet Protokolü Sürüm 4 (TCP/IPv4)\" (veya IPv6 için \"İnternet Protokolü Sürüm 6 (TCP/IPv6)\") öğesini bulun, seçin ve ardından tekrar Özellikler'e tıklayın.", + "install_devices_windows_list_5": "Listede \"İnternet Protokolü Sürüm 4 (TCP/IPv4)\" (veya IPv6 için \"İnternet Protokolü Sürüm 6 (TCP/IPv6)\") öğesini bulun, seçin ve ardından tekrar Özellikler öğesine tıklayın.", "install_devices_windows_list_6": "\"Aşağıdaki DNS sunucu adreslerini kullan\"ı seçin ve AdGuard Home sunucu adreslerinizi girin.", - "install_devices_macos_list_1": "Apple simgesine tıklayın ve Sistem Tercihleri'ne gidin.", - "install_devices_macos_list_2": "Ağ'a tıklayın.", + "install_devices_macos_list_1": "Apple simgesine tıklayın ve Sistem Tercihleri öğesine gidin.", + "install_devices_macos_list_2": "Ağ öğesine tıklayın.", "install_devices_macos_list_3": "Listedeki ilk bağlantıyı seçin ve Gelişmiş öğesine tıklayın.", "install_devices_macos_list_4": "DNS sekmesini seçin ve AdGuard Home sunucunuzun adreslerini girin.", "install_devices_android_list_1": "Android Menüsü ana ekranından Ayarlar'a dokunun.", - "install_devices_android_list_2": "Menüde bulunan Wi-Fi seçeneğine dokunun. Mevcut tüm ağlar listelenecektir (mobil ağlar için özel DNS sunucusu ayarlanamaz).", + "install_devices_android_list_2": "Menüde bulunan Wi-Fi öğesine dokunun. Mevcut tüm ağlar listelenecektir (mobil ağlar için özel DNS sunucusu ayarlanamaz).", "install_devices_android_list_3": "Bağlı olduğunuz ağın üzerine basılı tutun ve Ağı Değiştir'e dokunun.", "install_devices_android_list_4": "Bazı cihazlarda, diğer ayarları görmek için \"Gelişmiş\" seçeneğini seçmeniz gerekebilir. Android DNS ayarlarınızı yapmak için IP ayarlarını DHCP modundan Statik moda almanız gerekecektir.", "install_devices_android_list_5": "DNS 1 ve DNS 2 değerlerini AdGuard Home sunucunuzun adresleriyle değiştirin.", @@ -453,7 +453,7 @@ "setup_dns_privacy_2": "<0>DNS-over-HTTPS: <1>{{address}} dizesini kullan.", "setup_dns_privacy_3": "<0>İşte, kullanabileceğiniz yazılımların bir listesi.", "setup_dns_privacy_4": "Bir iOS 14 veya macOS Big Sur cihazında, DNS ayarlarına DNS-over-HTTPS veya DNS-over-TLS sunucuları ekleyen özel '.mobileconfig' dosyasını indirebilirsiniz.", - "setup_dns_privacy_android_1": "Android 9, yerel olarak DNS-over-TLS protokolünü destekler. Yapılandırmak için Ayarlar → Ağ ve İnternet → Gelişmiş → Özel DNS seçeneğine gidin ve alan adınızı girin.", + "setup_dns_privacy_android_1": "Android 9, yerel olarak DNS-over-TLS protokolünü destekler. Yapılandırmak için Ayarlar → Ağ ve İnternet → Gelişmiş → Özel DNS öğesine gidin ve alan adınızı girin.", "setup_dns_privacy_android_2": "<0>Android için AdGuard, <1>DNS-over-HTTPS ve <1>DNS-over-TLS protokolünü destekler.", "setup_dns_privacy_android_3": "<0>Intra Android'e <1>DNS-over-HTTPS protokol desteğini ekler.", "setup_dns_privacy_ios_1": "<0>DNSCloak, <1>DNS-over-HTTPS protokolünü destekler, ancak kendi sunucunuzu kullanacak şekilde yapılandırmak için bir <2>DNS Damgası oluşturmanız gerekir.", diff --git a/client/src/__locales/uk.json b/client/src/__locales/uk.json index 9fcbd460..84a6974e 100644 --- a/client/src/__locales/uk.json +++ b/client/src/__locales/uk.json @@ -7,16 +7,16 @@ "load_balancing": "Балансування навантаження", "load_balancing_desc": "Запитувати один сервер за раз. AdGuard Home використовуватиме зважений випадковий алгоритм для вибору сервера, щоб найшвидший сервер використовувався частіше.", "bootstrap_dns": "Bootstrap DNS-сервери", - "bootstrap_dns_desc": "Bootstrap DNS-сервери використовуються для пошуку IP-адреси DoH/DoT серверів, які ви встановили.", + "bootstrap_dns_desc": "Bootstrap DNS-сервери використовуються для вирішення IP-адрес встановлених серверів DoH/DoT.", "local_ptr_title": "Приватні сервери для зворотного DNS", - "local_ptr_desc": "DNS-сервери, які AdGuard Home використовує для локальних PTR-запитів. Ці сервери, використовуючи rDNS, використовуються для отримання доменних імен клієнтів у приватних мережах, наприклад, «192.168.12.34». Якщо список порожній, буде використовуватись системний DNS-сервер.", - "local_ptr_default_resolver": "AdGuard Home усталено використовує такі зворотні DNS-резолвери: {{ip}}.", - "local_ptr_no_default_resolver": "AdGuard Home не зміг визначити приватні реверсивні DNS-резолвери, що були б придатними для цієї системи.", + "local_ptr_desc": "DNS-сервери, які AdGuard Home використовує для локальних PTR-запитів. Ці сервери використовуються для вирішення PTR-запитів для адрес у приватних мережах, наприклад, «192.168.12.34». Якщо список порожній, AdGuard Home буде усталено використовувати системний DNS-сервер.", + "local_ptr_default_resolver": "Стандартно AdGuard Home користується такими зворотними DNS-вирішувачами: {{ip}}.", + "local_ptr_no_default_resolver": "AdGuard Home не зміг визначити приватні зворотні DNS-вирішувачі, які підійшли б для цієї системи.", "local_ptr_placeholder": "Вводьте одну адресу на рядок", - "resolve_clients_title": "Увімкнути запитування доменних імен для IP-адрес клієнтів", + "resolve_clients_title": "Увімкнути зворотне вирішення IP-адрес клієнтів", "resolve_clients_desc": "Визначати доменні імена клієнтів за допомогою PTR-запитів до відповідних серверів — приватних DNS-серверів для локальних клієнтів та upstream-серверів для клієнтів з публічними IP-адресами.", "use_private_ptr_resolvers_title": "Використовувати приватні зворотні DNS-резолвери", - "use_private_ptr_resolvers_desc": "Надсилати зворотні DNS-запити до вказаних серверів для клієнтів, що обслуговуються локально. Якщо вимкнено, AdGuard Home буде відповідати NXDOMAIN на всі такі PTR-запити, окрім запитів про клієнтів, що уже відомі по DHCP, /etc/hosts тощо.", + "use_private_ptr_resolvers_desc": "Надсилати зворотні DNS-запити до вказаних серверів для клієнтів, що обслуговуються локально. Якщо вимкнено, AdGuard Home буде відповідати NXDOMAIN на всі такі PTR-запити, окрім запитів про клієнтів, що уже відомі завдяки DHCP, /etc/hosts тощо.", "check_dhcp_servers": "Перевірити DHCP-сервери", "save_config": "Зберегти конфігурацію", "enabled_dhcp": "DHCP-сервер увімкнено", @@ -60,7 +60,7 @@ "dhcp_form_range_end": "Кінець діапазону", "dhcp_form_lease_title": "Час оренди DHCP (в секундах)", "dhcp_form_lease_input": "Тривалість оренди", - "dhcp_interface_select": "Оберіть інтерфейс DHCP", + "dhcp_interface_select": "Вибрати DHCP-інтерфейс", "dhcp_hardware_address": "Апаратна адреса", "dhcp_ip_addresses": "IP-адреси", "ip": "IP", @@ -117,11 +117,11 @@ "stats_adult": "Заблоковано вебсайтів для дорослих", "stats_query_domain": "Найчастіші запити доменів", "for_last_24_hours": "за останні 24 години", - "for_last_days": "за останній день", + "for_last_days": "за останній {{count}} день", "for_last_days_plural": "за останні {{count}} днів", "stats_disabled": "Статистику вимкнено. Ви можете увімкнути її на <0>сторінці налаштувань.", "stats_disabled_short": "Статистику вимкнено", - "no_domains_found": "Доменів не знайдено", + "no_domains_found": "Не знайдено жодного домену", "requests_count": "Кількість запитів", "top_blocked_domains": "Найчастіше блоковані домени", "top_clients": "Найактивніші клієнти", @@ -131,7 +131,7 @@ "number_of_dns_query_days_plural": "Кількість DNS-запитів, оброблених за останні {{count}} днів", "number_of_dns_query_24_hours": "Кількість DNS-запитів, оброблених за останні 24 години", "number_of_dns_query_blocked_24_hours": "Кількість DNS-запитів, заблокованих фільтрами і списками блокування hosts", - "number_of_dns_query_blocked_24_hours_by_sec": "Кількість DNS-запитів, заблокованих модулем безпеки перегляду AdGuard", + "number_of_dns_query_blocked_24_hours_by_sec": "Кількість DNS-запитів, заблокованих модулем «Безпека перегляду» AdGuard", "number_of_dns_query_blocked_24_hours_adult": "Кількість заблокованих вебсайтів для дорослих", "enforced_save_search": "Примусовий безпечний пошук", "number_of_dns_query_to_safe_search": "Кількість DNS-запитів до пошукових систем, для яких примусово застосований безпечний пошук", @@ -139,10 +139,10 @@ "average_processing_time_hint": "Середній час обробки DNS запиту в мілісекундах", "block_domain_use_filters_and_hosts": "Блокування доменів за допомогою фільтрів та hosts-файлів", "filters_block_toggle_hint": "Ви можете налаштувати правила блокування в розділі Фільтри.", - "use_adguard_browsing_sec": "Використовувати Безпечну навігацію AdGuard", - "use_adguard_browsing_sec_hint": "AdGuard Home перевірятиме, чи додано домен до списку веб-служби безпечного перегляду браузера. Він використовуватиме API для перевірки — на сервер надсилається лише короткий префікс хешу SHA256 доменного імені.", - "use_adguard_parental": "Використовувати вебсервіс Батьківського контролю AdGuard", - "use_adguard_parental_hint": "AdGuard Home перевірить, чи містить домен матеріали для дорослих. Він використовує то же API, що й Безпечна навігація AdGuard.", + "use_adguard_browsing_sec": "Використовувати вебслужбу «Безпека перегляду» AdGuard", + "use_adguard_browsing_sec_hint": "AdGuard Home перевірятиме, чи підлягає домен блокуванню завдяки вебслужбі «Безпека перегляду». Для перевірки буде використано безпечний API — на сервер надсилається лише короткий префікс хешу SHA256 доменного імені.", + "use_adguard_parental": "Використовувати вебслужбу «Батьківський контроль» AdGuard", + "use_adguard_parental_hint": "AdGuard Home перевірить, чи містить домен матеріали для дорослих. Буде використано той же безпечний API, що й для «Безпеки перегляду» AdGuard.", "enforce_safe_search": "Використовувати Безпечний пошук", "enforce_save_search_hint": "AdGuard Home може примусово застосовувати безпечний пошук в таких пошукових системах: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.", "no_servers_specified": "Сервери не вказано", @@ -165,8 +165,8 @@ "enabled_filtering_toast": "Фільтрування увімкнено", "disabled_safe_browsing_toast": "Безпечний перегляд вимкнено", "enabled_safe_browsing_toast": "Безпечний перегляд увімкнено", - "disabled_parental_toast": "Батьківський контроль вимкнено", - "enabled_parental_toast": "Батьківський контроль увімкнено", + "disabled_parental_toast": "«Батьківський контроль» вимкнено", + "enabled_parental_toast": "«Батьківський контроль» увімкнено", "disabled_safe_search_toast": "Безпечний пошук вимкнено", "enabled_save_search_toast": "Безпечний пошук увімкнено", "enabled_table_header": "Увімкнено", @@ -193,7 +193,7 @@ "edit_blocklist": "Змінити список блокування", "edit_allowlist": "Змінити список дозволів", "choose_blocklist": "Виберіть списки блокування", - "choose_allowlist": "Обрати списки дозволених сайтів", + "choose_allowlist": "Виберіть списки дозволів", "enter_valid_blocklist": "Введіть дійсну URL-адресу в список блокування.", "enter_valid_allowlist": "Введіть дійсну URL-адресу в список дозволів.", "form_error_url_format": "Неправильний формат URL", @@ -214,7 +214,7 @@ "example_upstream_dot": "зашифрований <0>DNS-over-TLS;", "example_upstream_doh": "зашифрований <0>DNS-over-HTTPS;", "example_upstream_doq": "зашифрований <0>DNS-over-QUIC (експериментальний);", - "example_upstream_sdns": "<0>DNS Stamps для <1>DNSCrypt або <2>DNS-over-HTTPS серверів;", + "example_upstream_sdns": "<0>DNS Stamps для <1>DNSCrypt- або <2>DNS-over-HTTPS-вирішувачів;", "example_upstream_tcp": "звичайний DNS (через TCP);", "example_upstream_tcp_hostname": "звичайний DNS (поверх TCP, з назвою вузла);", "all_lists_up_to_date_toast": "Всі списки вже оновлені", @@ -351,7 +351,7 @@ "install_devices_android_list_5": "Змініть встановлені значення DNS 1 і DNS 2 на адреси вашого домашнього сервера AdGuard.", "install_devices_ios_list_1": "На головному екрані торкніться Налаштування.", "install_devices_ios_list_2": "Виберіть Wi-Fi у меню ліворуч (неможливо налаштувати DNS для мобільних мереж).", - "install_devices_ios_list_3": "Натисніть на назву поточно активної мережі.", + "install_devices_ios_list_3": "Натисніть на назву поточної активної мережі.", "install_devices_ios_list_4": "У полі DNS введіть адреси вашого сервера AdGuard Home.", "get_started": "Розпочати", "next": "Наступні", @@ -372,7 +372,7 @@ "encryption_doq": "Порт DNS-over-QUIC (експериментальний)", "encryption_doq_desc": "Якщо цей порт налаштовано, AdGuard Home запустить на цьому порту сервер DNS-over-QUIC. Це експериментально і може бути ненадійним. Крім того, зараз не так багато клієнтів, які це підтримують.", "encryption_certificates": "Сертифікати", - "encryption_certificates_desc": "Для використання шифрування потрібно надати дійсний ланцюжок сертифікатів SSL для вашого домену. Ви можете отримати безкоштовний сертифікат на <0>{{link}} або придбати його в одному з надійних Центрів Сертифікації.", + "encryption_certificates_desc": "Для використання шифрування потрібно надати дійсний ланцюжок сертифікатів SSL для вашого домену. Ви можете отримати безплатний сертифікат на <0>{{link}} або придбати його в одному з надійних Центрів Сертифікації.", "encryption_certificates_input": "Скопіюйте/вставте сюди свої кодовані PEM сертифікати.", "encryption_status": "Статус", "encryption_expire": "Закінчується", @@ -552,16 +552,16 @@ "fastest_addr": "Найшвидша IP-адреса", "fastest_addr_desc": "Опитати всі DNS-сервери й повернути найшвидшу IP-адресу серед усіх наданих. Це сповільнить швидкість DNS-запитів, оскільки AdGuard Home повинен буде чекати відповіді усіх DNS-серверів, але водночас може покращити якість з'єднання.", "autofix_warning_text": "Якщо ви натиснете «Виправити», AdGuard Home налаштує вашу систему на використання DNS-сервера AdGuard Home.", - "autofix_warning_list": "Це виконає наступні завдання: <0>Деактивує систему DNSStubListener <0>Змінить адресу DNS сервера на 127.0.0.1 <0>Замінить символічне посилання /etc/resolv.conf на /run/systemd/resolve/resolv.conf <0>Зупинить DNSStubListener (перезапустить сервіс systemd-resolved)", + "autofix_warning_list": "Будуть виконані такі дії: <0>Деактивація системи DNSStubListener <0>Зміна адреси DNS-сервера на «127.0.0.1» <0>Заміна символічного посилання «/etc/resolv.conf» на «/run/systemd/resolve/resolv.conf» <0>Зупинка DNSStubListener (перезапуск системної служби systemd-resolved)", "autofix_warning_result": "В результаті буде усталено, що усі DNS-запити вашої системи будуть опрацьовані AdGuard Home.", "tags_title": "Теги", "tags_desc": "Ви можете вибрати теги, які відповідають клієнту. Теги можна використати в правилах фільтрування, щоб точніше застосовувати їх. <0>Докладніше.", "form_select_tags": "Виберіть теги клієнта", - "check_title": "Перевірте фільтрування", + "check_title": "Перевірити фільтрування", "check_desc": "Перевірити чи фільтрується назва вузла.", "check": "Перевірити", "form_enter_host": "Введіть назву вузла", - "filtered_custom_rules": "Відфільтровано за власними правилами фільтрування", + "filtered_custom_rules": "Відфільтровано завдяки власним правилам фільтрування", "choose_from_list": "Виберіть зі списку", "add_custom_list": "Додати власний список", "host_whitelisted": "Вузол додано до списку дозволів", @@ -585,14 +585,14 @@ "list_updated": "{{count}} список оновлено", "list_updated_plural": "{{count}} списки оновлено", "dnssec_enable": "Увімкнути DNSSEC", - "dnssec_enable_desc": "Встановити прапорець DNSSEC для вихідних DNS запитів та перевірити результат (потрібен розпізнавач з підтримкою DNSSEC).", + "dnssec_enable_desc": "Увімкнути DNSSEC для вихідних DNS-запитів та перевірити результат (потрібен вирішувач з підтримкою DNSSEC).", "validated_with_dnssec": "Засвідчено DNSSEC", "all_queries": "Усі запити", "show_blocked_responses": "Заблоковані", "show_whitelisted_responses": "Дозволені", "show_processed_responses": "Оброблені", "blocked_safebrowsing": "Заблоковано Безпечним переглядом", - "blocked_adult_websites": "Заблоковано Батьківським контролем", + "blocked_adult_websites": "Заблоковано «Батьківським контролем»", "blocked_threats": "Заблоковано загроз", "allowed": "Дозволено", "filtered": "Відфільтровано", diff --git a/client/src/__locales/zh-cn.json b/client/src/__locales/zh-cn.json index 4640432f..8903052f 100644 --- a/client/src/__locales/zh-cn.json +++ b/client/src/__locales/zh-cn.json @@ -351,6 +351,7 @@ "install_devices_android_list_5": "将 DNS 1 和 DNS 2 的值改为您的 AdGuard Home 服务器地址。", "install_devices_ios_list_1": "从主屏幕中点击「设置」。", "install_devices_ios_list_2": "从左侧目录中选择「无线局域网」(移动数据网络环境下不支持修改 DNS )。", + "install_devices_ios_list_3": "点击当前已连接网络的名称。", "install_devices_ios_list_4": "在 DNS 字段中输入您的 AdGuard Home 服务器地址。", "get_started": "开始配置", "next": "下一步", From c3d5fcc6692bbbf7271c5ee44dac7d984fa7cd80 Mon Sep 17 00:00:00 2001 From: Dimitry Kolyshev Date: Thu, 26 May 2022 16:21:59 +0300 Subject: [PATCH 051/110] Pull request: locales: DoQ status Merge in DNS/adguard-home from 4592-doq-status to master Squashed commit of the following: commit 96bc041b736a45711419160aebb79296f13ff84d Author: Dimitry Kolyshev Date: Thu May 26 14:21:10 2022 +0200 all: locales --- client/src/__locales/en.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index f39d2f51..a5c21109 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -213,7 +213,7 @@ "example_upstream_udp": "regular DNS (over UDP, hostname);", "example_upstream_dot": "encrypted <0>DNS-over-TLS;", "example_upstream_doh": "encrypted <0>DNS-over-HTTPS;", - "example_upstream_doq": "encrypted <0>DNS-over-QUIC (experimental);", + "example_upstream_doq": "encrypted <0>DNS-over-QUIC;", "example_upstream_sdns": "<0>DNS Stamps for <1>DNSCrypt or <2>DNS-over-HTTPS resolvers;", "example_upstream_tcp": "regular DNS (over TCP);", "example_upstream_tcp_hostname": "regular DNS (over TCP, hostname);", @@ -369,8 +369,8 @@ "encryption_https_desc": "If HTTPS port is configured, AdGuard Home admin interface will be accessible via HTTPS, and it will also provide DNS-over-HTTPS on '/dns-query' location.", "encryption_dot": "DNS-over-TLS port", "encryption_dot_desc": "If this port is configured, AdGuard Home will run a DNS-over-TLS server on this port.", - "encryption_doq": "DNS-over-QUIC port (experimental)", - "encryption_doq_desc": "If this port is configured, AdGuard Home will run a DNS-over-QUIC server on this port. It's experimental and may not be reliable. Also, there are not too many clients that support it at the moment.", + "encryption_doq": "DNS-over-QUIC port", + "encryption_doq_desc": "If this port is configured, AdGuard Home will run a DNS-over-QUIC server on this port.", "encryption_certificates": "Certificates", "encryption_certificates_desc": "In order to use encryption, you need to provide a valid SSL certificates chain for your domain. You can get a free certificate on <0>{{link}} or you can buy it from one of the trusted Certificate Authorities.", "encryption_certificates_input": "Copy/paste your PEM-encoded certificates here.", From 756c932e372e36b5a6814d73fa6dac6c8799c9a1 Mon Sep 17 00:00:00 2001 From: Dimitry Kolyshev Date: Thu, 26 May 2022 17:53:11 +0300 Subject: [PATCH 052/110] Pull request: dnsforward: add doq alpn Merge in DNS/adguard-home from 4592-doq-alpn to master Squashed commit of the following: commit 5985445dbf5158ae1e5b0235b404dd188c856e60 Author: Dimitry Kolyshev Date: Thu May 26 16:42:06 2022 +0200 dnsforward: add doq alpn commit 9dcd6fee615a1a5ac1f80641ac16c18371b67096 Merge: 2564c870 c3d5fcc6 Author: Dimitry Kolyshev Date: Thu May 26 15:24:07 2022 +0200 Merge remote-tracking branch 'origin/master' into 4592-doq-alpn commit 2564c870e704ff453d0ad2fb22fa295ef725dd13 Author: Dimitry Kolyshev Date: Thu May 26 15:20:16 2022 +0200 dnsforward: add doq alpn --- internal/dnsforward/dns.go | 21 ++++++++++++++++++--- internal/dnsforward/dns_test.go | 26 ++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/internal/dnsforward/dns.go b/internal/dnsforward/dns.go index 19d54d91..e049bef0 100644 --- a/internal/dnsforward/dns.go +++ b/internal/dnsforward/dns.go @@ -260,9 +260,8 @@ func (s *Server) processDDRQuery(ctx *dnsContext) (rc resultCode) { } if question.Name == ddrHostFQDN { - // TODO(a.garipov): Check DoQ support in next RFC drafts. - if s.dnsProxy.TLSListenAddr == nil && s.dnsProxy.HTTPSListenAddr == nil || - question.Qtype != dns.TypeSVCB { + if s.dnsProxy.TLSListenAddr == nil && s.dnsProxy.HTTPSListenAddr == nil && + s.dnsProxy.QUICListenAddr == nil || question.Qtype != dns.TypeSVCB { d.Res = s.makeResponse(d.Req) return resultCodeFinish @@ -314,6 +313,22 @@ func (s *Server) makeDDRResponse(req *dns.Msg) (resp *dns.Msg) { resp.Answer = append(resp.Answer, ans) } + for _, addr := range s.dnsProxy.QUICListenAddr { + values := []dns.SVCBKeyValue{ + &dns.SVCBAlpn{Alpn: []string{"doq"}}, + &dns.SVCBPort{Port: uint16(addr.Port)}, + } + + ans := &dns.SVCB{ + Hdr: s.hdr(req, dns.TypeSVCB), + Priority: 3, + Target: domainName, + Value: values, + } + + resp.Answer = append(resp.Answer, ans) + } + return resp } diff --git a/internal/dnsforward/dns_test.go b/internal/dnsforward/dns_test.go index 8ab7501c..b40b7bc2 100644 --- a/internal/dnsforward/dns_test.go +++ b/internal/dnsforward/dns_test.go @@ -36,6 +36,15 @@ func TestServer_ProcessDDRQuery(t *testing.T) { }, } + doqSVCB := &dns.SVCB{ + Priority: 3, + Target: ddrTestDomainName, + Value: []dns.SVCBKeyValue{ + &dns.SVCBAlpn{Alpn: []string{"doq"}}, + &dns.SVCBPort{Port: 8042}, + }, + } + testCases := []struct { name string host string @@ -43,6 +52,7 @@ func TestServer_ProcessDDRQuery(t *testing.T) { wantRes resultCode portDoH int portDoT int + portDoQ int qtype uint16 ddrEnabled bool }{{ @@ -88,6 +98,14 @@ func TestServer_ProcessDDRQuery(t *testing.T) { qtype: dns.TypeSVCB, ddrEnabled: true, portDoH: 8044, + }, { + name: "doq", + wantRes: resultCodeFinish, + want: []*dns.SVCB{doqSVCB}, + host: ddrHostFQDN, + qtype: dns.TypeSVCB, + ddrEnabled: true, + portDoQ: 8042, }, { name: "dot_doh", wantRes: resultCodeFinish, @@ -101,7 +119,7 @@ func TestServer_ProcessDDRQuery(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - s := prepareTestServer(t, tc.portDoH, tc.portDoT, tc.ddrEnabled) + s := prepareTestServer(t, tc.portDoH, tc.portDoT, tc.portDoQ, tc.ddrEnabled) req := createTestMessageWithType(tc.host, tc.qtype) @@ -130,7 +148,7 @@ func TestServer_ProcessDDRQuery(t *testing.T) { } } -func prepareTestServer(t *testing.T, portDoH, portDoT int, ddrEnabled bool) (s *Server) { +func prepareTestServer(t *testing.T, portDoH, portDoT, portDoQ int, ddrEnabled bool) (s *Server) { t.Helper() proxyConf := proxy.Config{} @@ -143,6 +161,10 @@ func prepareTestServer(t *testing.T, portDoH, portDoT int, ddrEnabled bool) (s * proxyConf.TLSListenAddr = []*net.TCPAddr{{Port: portDoT}} } + if portDoQ > 0 { + proxyConf.QUICListenAddr = []*net.UDPAddr{{Port: portDoQ}} + } + s = &Server{ dnsProxy: &proxy.Proxy{ Config: proxyConf, From 7ce7e908654579789f23ea5302416b67885494ae Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Mon, 30 May 2022 16:04:28 +0300 Subject: [PATCH 053/110] Pull request: dnsforward: fix ddr target Updates #4463. Squashed commit of the following: commit 047155b585a1c762d709874f44abb2d8c5a9dbca Author: Eugene Burkov Date: Mon May 30 15:34:38 2022 +0300 dnsforward: imp code commit b0508ffec13ccf5fc5d3d2e37c9e1bd83c3c039e Author: Eugene Burkov Date: Mon May 30 15:27:02 2022 +0300 dnsforward: fix ddr target --- internal/dnsforward/dns.go | 4 +++- internal/dnsforward/dns_test.go | 11 +++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/internal/dnsforward/dns.go b/internal/dnsforward/dns.go index e049bef0..2865bc84 100644 --- a/internal/dnsforward/dns.go +++ b/internal/dnsforward/dns.go @@ -278,7 +278,9 @@ func (s *Server) processDDRQuery(ctx *dnsContext) (rc resultCode) { // makeDDRResponse creates DDR answer according to server configuration. func (s *Server) makeDDRResponse(req *dns.Msg) (resp *dns.Msg) { resp = s.makeResponse(req) - domainName := s.conf.ServerName + // TODO(e.burkov): Think about stroing the FQDN version of the server's + // name somewhere. + domainName := dns.Fqdn(s.conf.ServerName) for _, addr := range s.dnsProxy.HTTPSListenAddr { values := []dns.SVCBKeyValue{ diff --git a/internal/dnsforward/dns_test.go b/internal/dnsforward/dns_test.go index b40b7bc2..129e3c2f 100644 --- a/internal/dnsforward/dns_test.go +++ b/internal/dnsforward/dns_test.go @@ -14,12 +14,15 @@ import ( "github.com/stretchr/testify/require" ) -const ddrTestDomainName = "dns.example.net" +const ( + ddrTestDomainName = "dns.example.net" + ddrTestFQDN = ddrTestDomainName + "." +) func TestServer_ProcessDDRQuery(t *testing.T) { dohSVCB := &dns.SVCB{ Priority: 1, - Target: ddrTestDomainName, + Target: ddrTestFQDN, Value: []dns.SVCBKeyValue{ &dns.SVCBAlpn{Alpn: []string{"h2"}}, &dns.SVCBPort{Port: 8044}, @@ -29,7 +32,7 @@ func TestServer_ProcessDDRQuery(t *testing.T) { dotSVCB := &dns.SVCB{ Priority: 2, - Target: ddrTestDomainName, + Target: ddrTestFQDN, Value: []dns.SVCBKeyValue{ &dns.SVCBAlpn{Alpn: []string{"dot"}}, &dns.SVCBPort{Port: 8043}, @@ -38,7 +41,7 @@ func TestServer_ProcessDDRQuery(t *testing.T) { doqSVCB := &dns.SVCB{ Priority: 3, - Target: ddrTestDomainName, + Target: ddrTestFQDN, Value: []dns.SVCBKeyValue{ &dns.SVCBAlpn{Alpn: []string{"doq"}}, &dns.SVCBPort{Port: 8042}, From 4b884ace622f86fa2b77efb7c5ade513ff5ae3b5 Mon Sep 17 00:00:00 2001 From: Dimitry Kolyshev Date: Tue, 31 May 2022 17:28:50 +0300 Subject: [PATCH 054/110] Pull request: all: fix doh ddr Merge in DNS/adguard-home from fix-ddr-doh to master Squashed commit of the following: commit 53d3147b22044061d78b3bf4badca60505ac245a Author: Dimitry Kolyshev Date: Tue May 31 15:02:17 2022 +0200 all: fix doh ddr --- internal/dnsforward/config.go | 5 +++-- internal/dnsforward/dns.go | 6 +++--- internal/dnsforward/dns_test.go | 8 ++++---- internal/home/dns.go | 4 ++++ 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/internal/dnsforward/config.go b/internal/dnsforward/config.go index 16a6325e..f9234155 100644 --- a/internal/dnsforward/config.go +++ b/internal/dnsforward/config.go @@ -134,8 +134,9 @@ type FilteringConfig struct { // TLSConfig is the TLS configuration for HTTPS, DNS-over-HTTPS, and DNS-over-TLS type TLSConfig struct { - TLSListenAddrs []*net.TCPAddr `yaml:"-" json:"-"` - QUICListenAddrs []*net.UDPAddr `yaml:"-" json:"-"` + TLSListenAddrs []*net.TCPAddr `yaml:"-" json:"-"` + QUICListenAddrs []*net.UDPAddr `yaml:"-" json:"-"` + HTTPSListenAddrs []*net.TCPAddr `yaml:"-" json:"-"` // Reject connection if the client uses server name (in SNI) that doesn't match the certificate StrictSNICheck bool `yaml:"strict_sni_check" json:"-"` diff --git a/internal/dnsforward/dns.go b/internal/dnsforward/dns.go index 2865bc84..55a38a2f 100644 --- a/internal/dnsforward/dns.go +++ b/internal/dnsforward/dns.go @@ -260,7 +260,7 @@ func (s *Server) processDDRQuery(ctx *dnsContext) (rc resultCode) { } if question.Name == ddrHostFQDN { - if s.dnsProxy.TLSListenAddr == nil && s.dnsProxy.HTTPSListenAddr == nil && + if s.dnsProxy.TLSListenAddr == nil && s.conf.HTTPSListenAddrs == nil && s.dnsProxy.QUICListenAddr == nil || question.Qtype != dns.TypeSVCB { d.Res = s.makeResponse(d.Req) @@ -278,11 +278,11 @@ func (s *Server) processDDRQuery(ctx *dnsContext) (rc resultCode) { // makeDDRResponse creates DDR answer according to server configuration. func (s *Server) makeDDRResponse(req *dns.Msg) (resp *dns.Msg) { resp = s.makeResponse(req) - // TODO(e.burkov): Think about stroing the FQDN version of the server's + // TODO(e.burkov): Think about storing the FQDN version of the server's // name somewhere. domainName := dns.Fqdn(s.conf.ServerName) - for _, addr := range s.dnsProxy.HTTPSListenAddr { + for _, addr := range s.conf.HTTPSListenAddrs { values := []dns.SVCBKeyValue{ &dns.SVCBAlpn{Alpn: []string{"h2"}}, &dns.SVCBPort{Port: uint16(addr.Port)}, diff --git a/internal/dnsforward/dns_test.go b/internal/dnsforward/dns_test.go index 129e3c2f..b9c7e47b 100644 --- a/internal/dnsforward/dns_test.go +++ b/internal/dnsforward/dns_test.go @@ -156,10 +156,6 @@ func prepareTestServer(t *testing.T, portDoH, portDoT, portDoQ int, ddrEnabled b proxyConf := proxy.Config{} - if portDoH > 0 { - proxyConf.HTTPSListenAddr = []*net.TCPAddr{{Port: portDoH}} - } - if portDoT > 0 { proxyConf.TLSListenAddr = []*net.TCPAddr{{Port: portDoT}} } @@ -182,6 +178,10 @@ func prepareTestServer(t *testing.T, portDoH, portDoT, portDoQ int, ddrEnabled b }, } + if portDoH > 0 { + s.conf.TLSConfig.HTTPSListenAddrs = []*net.TCPAddr{{Port: portDoH}} + } + return s } diff --git a/internal/home/dns.go b/internal/home/dns.go index 9eabfefa..d51a6dd2 100644 --- a/internal/home/dns.go +++ b/internal/home/dns.go @@ -221,6 +221,10 @@ func generateServerConfig() (newConf dnsforward.ServerConfig, err error) { newConf.TLSConfig = tlsConf.TLSConfig newConf.TLSConfig.ServerName = tlsConf.ServerName + if tlsConf.PortHTTPS != 0 { + newConf.HTTPSListenAddrs = ipsToTCPAddrs(hosts, tlsConf.PortHTTPS) + } + if tlsConf.PortDNSOverTLS != 0 { newConf.TLSListenAddrs = ipsToTCPAddrs(hosts, tlsConf.PortDNSOverTLS) } From f46c9f74d5b03f8caa60d8e648bbc46fe306714d Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Thu, 2 Jun 2022 15:57:06 +0300 Subject: [PATCH 055/110] Pull request: all: upd go Merge in DNS/adguard-home from upd-go to master Squashed commit of the following: commit b0bec8926508fb7ee3f26c2303d9628e21f0b62f Author: Ainar Garipov Date: Thu Jun 2 15:47:51 2022 +0300 all: upd go --- CHANGELOG.md | 15 +++++++++++---- bamboo-specs/release.yaml | 6 +++--- bamboo-specs/test.yaml | 2 +- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a72447c..3bdd37ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,9 @@ and this project adheres to ### Security +- Go version was updated to prevent the possibility of exploiting the + [CVE-2022-29526], [CVE-2022-30634], [CVE-2022-30629], [CVE-2022-30580], and + [CVE-2022-29804] vulnerabilities. - Enforced password strength policy ([#3503]). - Weaker cipher suites that use the CBC (cipher block chaining) mode of operation have been disabled ([#2993]). @@ -161,10 +164,14 @@ In this release, the schema version has changed from 12 to 14. [#4591]: https://github.com/AdguardTeam/AdGuardHome/issues/4591 [#4592]: https://github.com/AdguardTeam/AdGuardHome/issues/4592 -[rfc-9250]: https://datatracker.ietf.org/doc/html/rfc9250 -[ddr-draft-06]: https://www.ietf.org/archive/id/draft-ietf-add-ddr-06.html -[repr]: https://reproducible-builds.org/docs/source-date-epoch/ - +[CVE-2022-29526]: https://www.cvedetails.com/cve/CVE-2022-29526 +[CVE-2022-29804]: https://www.cvedetails.com/cve/CVE-2022-29804 +[CVE-2022-30580]: https://www.cvedetails.com/cve/CVE-2022-30580 +[CVE-2022-30629]: https://www.cvedetails.com/cve/CVE-2022-30629 +[CVE-2022-30634]: https://www.cvedetails.com/cve/CVE-2022-30634 +[ddr-draft-06]: https://www.ietf.org/archive/id/draft-ietf-add-ddr-06.html +[repr]: https://reproducible-builds.org/docs/source-date-epoch/ +[rfc-9250]: https://datatracker.ietf.org/doc/html/rfc9250 ### Security +- Weaker cipher suites that use the CBC (cipher block chaining) mode of + operation have been disabled ([#2993]). + +### Added + +- Support for Discovery of Designated Resolvers (DDR) according to the [RFC + draft][ddr-draft-06] ([#4463]). +- `windows/arm64` support ([#3057]). + +### Deprecated + +- Go 1.17 support. v0.109.0 will require at least Go 1.18 to build. + +[#2993]: https://github.com/AdguardTeam/AdGuardHome/issues/2993 +[#3057]: https://github.com/AdguardTeam/AdGuardHome/issues/3057 + +[ddr-draft-06]: https://www.ietf.org/archive/id/draft-ietf-add-ddr-06.html + + + + + + + +## [v0.107.7] - 2022-06-06 + +See also the [v0.107.7 GitHub milestone][ms-v0.107.7]. + +### Security + - Go version was updated to prevent the possibility of exploiting the [CVE-2022-29526], [CVE-2022-30634], [CVE-2022-30629], [CVE-2022-30580], and [CVE-2022-29804] vulnerabilities. - Enforced password strength policy ([#3503]). -- Weaker cipher suites that use the CBC (cipher block chaining) mode of - operation have been disabled ([#2993]). ### Added - Support for the final DNS-over-QUIC standard, [RFC 9250][rfc-9250] ([#4592]). - Support upstreams for subdomains of a domain only ([#4503]). -- Support for Discovery of Designated Resolvers (DDR) according to the [RFC - draft][ddr-draft-06] ([#4463]). - The ability to control each source of runtime clients separately via `clients.runtime_sources` configuration object ([#3020]). - The ability to customize the set of networks that are considered private @@ -41,7 +69,6 @@ and this project adheres to ([#4166]). - Logs are now collected by default on FreeBSD and OpenBSD when AdGuard Home is installed as a service ([#4213]). -- `windows/arm64` support ([#3057]). ### Changed @@ -125,10 +152,9 @@ In this release, the schema version has changed from 12 to 14. ### Deprecated -- The `--no-etc-hosts` option. Its' functionality is now controlled by +- The `--no-etc-hosts` option. Its functionality is now controlled by `clients.runtime_sources.hosts` configuration property. v0.109.0 will remove the flag completely. -- Go 1.17 support. v0.109.0 will require at least Go 1.18 to build. ### Fixed @@ -140,9 +166,7 @@ In this release, the schema version has changed from 12 to 14. - ARP tables refreshing process causing excessive PTR requests ([#3157]). [#1730]: https://github.com/AdguardTeam/AdGuardHome/issues/1730 -[#2993]: https://github.com/AdguardTeam/AdGuardHome/issues/2993 [#3020]: https://github.com/AdguardTeam/AdGuardHome/issues/3020 -[#3057]: https://github.com/AdguardTeam/AdGuardHome/issues/3057 [#3142]: https://github.com/AdguardTeam/AdGuardHome/issues/3142 [#3157]: https://github.com/AdguardTeam/AdGuardHome/issues/3157 [#3367]: https://github.com/AdguardTeam/AdGuardHome/issues/3367 @@ -169,20 +193,10 @@ In this release, the schema version has changed from 12 to 14. [CVE-2022-30580]: https://www.cvedetails.com/cve/CVE-2022-30580 [CVE-2022-30629]: https://www.cvedetails.com/cve/CVE-2022-30629 [CVE-2022-30634]: https://www.cvedetails.com/cve/CVE-2022-30634 -[ddr-draft-06]: https://www.ietf.org/archive/id/draft-ietf-add-ddr-06.html -[repr]: https://reproducible-builds.org/docs/source-date-epoch/ +[ms-v0.107.7]: https://github.com/AdguardTeam/AdGuardHome/milestone/43?closed=1 [rfc-9250]: https://datatracker.ietf.org/doc/html/rfc9250 - - - ## [v0.107.6] - 2022-04-13 @@ -234,6 +248,7 @@ See also the [v0.107.6 GitHub milestone][ms-v0.107.6]. [CVE-2022-28327]: https://www.cvedetails.com/cve/CVE-2022-28327 [dns-draft-02]: https://datatracker.ietf.org/doc/html/draft-ietf-add-svcb-dns-02#section-5.1 [ms-v0.107.6]: https://github.com/AdguardTeam/AdGuardHome/milestone/42?closed=1 +[repr]: https://reproducible-builds.org/docs/source-date-epoch/ [svcb-draft-08]: https://www.ietf.org/archive/id/draft-ietf-dnsop-svcb-https-08.html @@ -995,11 +1010,12 @@ See also the [v0.104.2 GitHub milestone][ms-v0.104.2]. -[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.6...HEAD +[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.7...HEAD +[v0.107.7]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.6...v0.107.7 [v0.107.6]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.5...v0.107.6 [v0.107.5]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.4...v0.107.5 [v0.107.4]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.3...v0.107.4 From 1c1ca1c6e3d490ddfaf2f176a54f5b93b24a9c1a Mon Sep 17 00:00:00 2001 From: Ildar Kamalov Date: Thu, 9 Jun 2022 11:57:58 +0300 Subject: [PATCH 060/110] Pull request: 4641 fix button clickable area Updates #4641 Squashed commit of the following: commit f9f018388a198d7712e5caabba94035e42e393c4 Author: Ildar Kamalov Date: Tue Jun 7 16:21:37 2022 +0300 client: fix button clickable area --- client/src/components/Settings/Settings.css | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/components/Settings/Settings.css b/client/src/components/Settings/Settings.css index 4efb0868..3fd560f9 100644 --- a/client/src/components/Settings/Settings.css +++ b/client/src/components/Settings/Settings.css @@ -113,6 +113,7 @@ width: 30px; height: 30px; background-color: transparent; + overflow: hidden; } .btn-icon--green { From 302faca32f849cb1d63202b0a905077fba56bfa9 Mon Sep 17 00:00:00 2001 From: Ildar Kamalov Date: Thu, 9 Jun 2022 12:07:29 +0300 Subject: [PATCH 061/110] Pull request: 4642 update dns addresses on encryption update Updates #4642 Squashed commit of the following: commit 75729120d3532dc2bd12b6c9e724a691043a1870 Merge: 5b681867 1c1ca1c6 Author: Ildar Kamalov Date: Thu Jun 9 11:58:13 2022 +0300 Merge branch 'master' into 4642-dns-privacy commit 5b68186705c3a9287a44e33c8cf7ab79060f35a4 Author: Ildar Kamalov Date: Tue Jun 7 18:39:02 2022 +0300 fix commit 46a9346154d33206e829a97021f3ef47ac2a5611 Author: Ildar Kamalov Date: Tue Jun 7 18:18:18 2022 +0300 client: update dns addresses on encryption update --- client/src/actions/encryption.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/client/src/actions/encryption.js b/client/src/actions/encryption.js index 36faf2ec..2f58abd3 100644 --- a/client/src/actions/encryption.js +++ b/client/src/actions/encryption.js @@ -24,6 +24,7 @@ export const getTlsStatus = () => async (dispatch) => { export const setTlsConfigRequest = createAction('SET_TLS_CONFIG_REQUEST'); export const setTlsConfigFailure = createAction('SET_TLS_CONFIG_FAILURE'); export const setTlsConfigSuccess = createAction('SET_TLS_CONFIG_SUCCESS'); +export const dnsStatusSuccess = createAction('DNS_STATUS_SUCCESS'); export const setTlsConfig = (config) => async (dispatch, getState) => { dispatch(setTlsConfigRequest()); @@ -39,6 +40,12 @@ export const setTlsConfig = (config) => async (dispatch, getState) => { const response = await apiClient.setTlsConfig(values); response.certificate_chain = atob(response.certificate_chain); response.private_key = atob(response.private_key); + + const dnsStatus = await apiClient.getGlobalStatus(); + if (dnsStatus) { + dispatch(dnsStatusSuccess(dnsStatus)); + } + dispatch(setTlsConfigSuccess(response)); dispatch(addSuccessToast('encryption_config_saved')); redirectToCurrentProtocol(response, httpPort); From e738508d7a5e09e257724c557069000506e055ad Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Thu, 9 Jun 2022 17:47:05 +0300 Subject: [PATCH 062/110] Pull request: all: imp updater Merge in DNS/adguard-home from imp-updater to master Squashed commit of the following: commit 6ed487359e56a35b36f13dcbf2efbf2a7a2d8734 Author: Ainar Garipov Date: Thu Jun 9 16:29:35 2022 +0300 all: imp logs, err handling commit e930044cb619a43e5a44c230dadbe2228e9a93f5 Author: Ainar Garipov Date: Thu Jun 9 15:53:35 2022 +0300 all: imp updater --- client/src/__locales/en.json | 2 +- internal/aghalg/nullbool.go | 59 +++++++++++++++++++++ internal/{dhcpd => aghalg}/nullbool_test.go | 23 ++++---- internal/dhcpd/http.go | 19 +++---- internal/dhcpd/nullbool.go | 58 -------------------- internal/home/controlupdate.go | 7 +-- internal/updater/check.go | 30 +++++------ internal/updater/updater.go | 34 +++++++----- internal/updater/updater_test.go | 16 ++---- scripts/make/build-release.sh | 1 + 10 files changed, 124 insertions(+), 125 deletions(-) create mode 100644 internal/aghalg/nullbool.go rename internal/{dhcpd => aghalg}/nullbool_test.go (72%) delete mode 100644 internal/dhcpd/nullbool.go diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index a5c21109..dd885677 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -445,7 +445,7 @@ "access_blocked_title": "Disallowed domains", "access_blocked_desc": "Not to be confused with filters. AdGuard Home drops DNS queries matching these domains, and these queries don't even appear in the query log. You can specify exact domain names, wildcards, or URL filter rules, e.g. \"example.org\", \"*.example.org\", or \"||example.org^\" correspondingly.", "access_settings_saved": "Access settings successfully saved", - "updates_checked": "Updates successfully checked", + "updates_checked": "A new version of AdGuard Home is available", "updates_version_equal": "AdGuard Home is up-to-date", "check_updates_now": "Check for updates now", "dns_privacy": "DNS Privacy", diff --git a/internal/aghalg/nullbool.go b/internal/aghalg/nullbool.go new file mode 100644 index 00000000..3c5633e3 --- /dev/null +++ b/internal/aghalg/nullbool.go @@ -0,0 +1,59 @@ +package aghalg + +import ( + "bytes" + "encoding/json" + "fmt" +) + +// NullBool is a nullable boolean. Use these in JSON requests and responses +// instead of pointers to bool. +type NullBool uint8 + +// NullBool values +const ( + NBNull NullBool = iota + NBTrue + NBFalse +) + +// String implements the fmt.Stringer interface for NullBool. +func (nb NullBool) String() (s string) { + switch nb { + case NBNull: + return "null" + case NBTrue: + return "true" + case NBFalse: + return "false" + } + + return fmt.Sprintf("!invalid NullBool %d", uint8(nb)) +} + +// BoolToNullBool converts a bool into a NullBool. +func BoolToNullBool(cond bool) (nb NullBool) { + if cond { + return NBTrue + } + + return NBFalse +} + +// type check +var _ json.Unmarshaler = (*NullBool)(nil) + +// UnmarshalJSON implements the json.Unmarshaler interface for *NullBool. +func (nb *NullBool) UnmarshalJSON(b []byte) (err error) { + if len(b) == 0 || bytes.Equal(b, []byte("null")) { + *nb = NBNull + } else if bytes.Equal(b, []byte("true")) { + *nb = NBTrue + } else if bytes.Equal(b, []byte("false")) { + *nb = NBFalse + } else { + return fmt.Errorf("unmarshalling json data into aghalg.NullBool: bad value %q", b) + } + + return nil +} diff --git a/internal/dhcpd/nullbool_test.go b/internal/aghalg/nullbool_test.go similarity index 72% rename from internal/dhcpd/nullbool_test.go rename to internal/aghalg/nullbool_test.go index 549df608..0fe7f203 100644 --- a/internal/dhcpd/nullbool_test.go +++ b/internal/aghalg/nullbool_test.go @@ -1,9 +1,10 @@ -package dhcpd +package aghalg_test import ( "encoding/json" "testing" + "github.com/AdguardTeam/AdGuardHome/internal/aghalg" "github.com/AdguardTeam/golibs/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -14,37 +15,37 @@ func TestNullBool_UnmarshalJSON(t *testing.T) { name string wantErrMsg string data []byte - want nullBool + want aghalg.NullBool }{{ name: "empty", wantErrMsg: "", data: []byte{}, - want: nbNull, + want: aghalg.NBNull, }, { name: "null", wantErrMsg: "", data: []byte("null"), - want: nbNull, + want: aghalg.NBNull, }, { name: "true", wantErrMsg: "", data: []byte("true"), - want: nbTrue, + want: aghalg.NBTrue, }, { name: "false", wantErrMsg: "", data: []byte("false"), - want: nbFalse, + want: aghalg.NBFalse, }, { name: "invalid", - wantErrMsg: `invalid nullBool value "invalid"`, + wantErrMsg: `unmarshalling json data into aghalg.NullBool: bad value "invalid"`, data: []byte("invalid"), - want: nbNull, + want: aghalg.NBNull, }} for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - var got nullBool + var got aghalg.NullBool err := got.UnmarshalJSON(tc.data) testutil.AssertErrorMsg(t, tc.wantErrMsg, err) @@ -53,9 +54,9 @@ func TestNullBool_UnmarshalJSON(t *testing.T) { } t.Run("json", func(t *testing.T) { - want := nbTrue + want := aghalg.NBTrue var got struct { - A nullBool + A aghalg.NullBool } err := json.Unmarshal([]byte(`{"A":true}`), &got) diff --git a/internal/dhcpd/http.go b/internal/dhcpd/http.go index e340addb..62a08f66 100644 --- a/internal/dhcpd/http.go +++ b/internal/dhcpd/http.go @@ -10,6 +10,7 @@ import ( "strings" "time" + "github.com/AdguardTeam/AdGuardHome/internal/aghalg" "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/AdGuardHome/internal/aghnet" "github.com/AdguardTeam/golibs/errors" @@ -145,7 +146,7 @@ type dhcpServerConfigJSON struct { V4 *v4ServerConfJSON `json:"v4"` V6 *v6ServerConfJSON `json:"v6"` InterfaceName string `json:"interface_name"` - Enabled nullBool `json:"enabled"` + Enabled aghalg.NullBool `json:"enabled"` } func (s *Server) handleDHCPSetConfigV4( @@ -156,7 +157,7 @@ func (s *Server) handleDHCPSetConfigV4( } v4Conf := v4JSONToServerConf(conf.V4) - v4Conf.Enabled = conf.Enabled == nbTrue + v4Conf.Enabled = conf.Enabled == aghalg.NBTrue if len(v4Conf.RangeStart) == 0 { v4Conf.Enabled = false } @@ -183,7 +184,7 @@ func (s *Server) handleDHCPSetConfigV6( } v6Conf := v6JSONToServerConf(conf.V6) - v6Conf.Enabled = conf.Enabled == nbTrue + v6Conf.Enabled = conf.Enabled == aghalg.NBTrue if len(v6Conf.RangeStart) == 0 { v6Conf.Enabled = false } @@ -206,7 +207,7 @@ func (s *Server) handleDHCPSetConfigV6( func (s *Server) handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) { conf := &dhcpServerConfigJSON{} - conf.Enabled = boolToNullBool(s.conf.Enabled) + conf.Enabled = aghalg.BoolToNullBool(s.conf.Enabled) conf.InterfaceName = s.conf.InterfaceName err := json.NewDecoder(r.Body).Decode(conf) @@ -230,7 +231,7 @@ func (s *Server) handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) { return } - if conf.Enabled == nbTrue && !v4Enabled && !v6Enabled { + if conf.Enabled == aghalg.NBTrue && !v4Enabled && !v6Enabled { aghhttp.Error(r, w, http.StatusBadRequest, "dhcpv4 or dhcpv6 configuration must be complete") return @@ -243,8 +244,8 @@ func (s *Server) handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) { return } - if conf.Enabled != nbNull { - s.conf.Enabled = conf.Enabled == nbTrue + if conf.Enabled != aghalg.NBNull { + s.conf.Enabled = conf.Enabled == aghalg.NBTrue } if conf.InterfaceName != "" { @@ -279,11 +280,11 @@ func (s *Server) handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) { type netInterfaceJSON struct { Name string `json:"name"` - GatewayIP net.IP `json:"gateway_ip"` HardwareAddr string `json:"hardware_address"` + Flags string `json:"flags"` + GatewayIP net.IP `json:"gateway_ip"` Addrs4 []net.IP `json:"ipv4_addresses"` Addrs6 []net.IP `json:"ipv6_addresses"` - Flags string `json:"flags"` } func (s *Server) handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) { diff --git a/internal/dhcpd/nullbool.go b/internal/dhcpd/nullbool.go deleted file mode 100644 index b07f6768..00000000 --- a/internal/dhcpd/nullbool.go +++ /dev/null @@ -1,58 +0,0 @@ -package dhcpd - -import ( - "bytes" - "fmt" -) - -// nullBool is a nullable boolean. Use these in JSON requests and responses -// instead of pointers to bool. -// -// TODO(a.garipov): Inspect uses of *bool, move this type into some new package -// if we need it somewhere else. -type nullBool uint8 - -// nullBool values -const ( - nbNull nullBool = iota - nbTrue - nbFalse -) - -// String implements the fmt.Stringer interface for nullBool. -func (nb nullBool) String() (s string) { - switch nb { - case nbNull: - return "null" - case nbTrue: - return "true" - case nbFalse: - return "false" - } - - return fmt.Sprintf("!invalid nullBool %d", uint8(nb)) -} - -// boolToNullBool converts a bool into a nullBool. -func boolToNullBool(cond bool) (nb nullBool) { - if cond { - return nbTrue - } - - return nbFalse -} - -// UnmarshalJSON implements the json.Unmarshaler interface for *nullBool. -func (nb *nullBool) UnmarshalJSON(b []byte) (err error) { - if len(b) == 0 || bytes.Equal(b, []byte("null")) { - *nb = nbNull - } else if bytes.Equal(b, []byte("true")) { - *nb = nbTrue - } else if bytes.Equal(b, []byte("false")) { - *nb = nbFalse - } else { - return fmt.Errorf("invalid nullBool value %q", b) - } - - return nil -} diff --git a/internal/home/controlupdate.go b/internal/home/controlupdate.go index ae469598..08ddd455 100644 --- a/internal/home/controlupdate.go +++ b/internal/home/controlupdate.go @@ -12,6 +12,7 @@ import ( "syscall" "time" + "github.com/AdguardTeam/AdGuardHome/internal/aghalg" "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/AdGuardHome/internal/aghnet" "github.com/AdguardTeam/AdGuardHome/internal/updater" @@ -147,8 +148,8 @@ type versionResponse struct { // setAllowedToAutoUpdate sets CanAutoUpdate to true if AdGuard Home is actually // allowed to perform an automatic update by the OS. func (vr *versionResponse) setAllowedToAutoUpdate() (err error) { - if vr.CanAutoUpdate == nil || !*vr.CanAutoUpdate { - return + if vr.CanAutoUpdate != aghalg.NBTrue { + return nil } tlsConf := &tlsConfigSettings{} @@ -162,7 +163,7 @@ func (vr *versionResponse) setAllowedToAutoUpdate() (err error) { } } - vr.CanAutoUpdate = &canUpdate + vr.CanAutoUpdate = aghalg.BoolToNullBool(canUpdate) return nil } diff --git a/internal/updater/check.go b/internal/updater/check.go index ec7176b2..2bac6153 100644 --- a/internal/updater/check.go +++ b/internal/updater/check.go @@ -5,9 +5,9 @@ import ( "fmt" "io" "net/http" - "strings" "time" + "github.com/AdguardTeam/AdGuardHome/internal/aghalg" "github.com/AdguardTeam/AdGuardHome/internal/aghio" "github.com/AdguardTeam/golibs/errors" ) @@ -17,11 +17,12 @@ const versionCheckPeriod = 8 * time.Hour // VersionInfo contains information about a new version. type VersionInfo struct { - CanAutoUpdate *bool `json:"can_autoupdate,omitempty"` - NewVersion string `json:"new_version,omitempty"` - Announcement string `json:"announcement,omitempty"` - AnnouncementURL string `json:"announcement_url,omitempty"` - SelfUpdateMinVersion string `json:"-"` + NewVersion string `json:"new_version,omitempty"` + Announcement string `json:"announcement,omitempty"` + AnnouncementURL string `json:"announcement_url,omitempty"` + // TODO(a.garipov): See if the frontend actually still cares about + // nullability. + CanAutoUpdate aghalg.NullBool `json:"can_autoupdate,omitempty"` } // MaxResponseSize is responses on server's requests maximum length in bytes. @@ -67,15 +68,13 @@ func (u *Updater) VersionInfo(forceRecheck bool) (vi VersionInfo, err error) { } func (u *Updater) parseVersionResponse(data []byte) (VersionInfo, error) { - var canAutoUpdate bool info := VersionInfo{ - CanAutoUpdate: &canAutoUpdate, + CanAutoUpdate: aghalg.NBFalse, } versionJSON := map[string]string{ - "version": "", - "announcement": "", - "announcement_url": "", - "selfupdate_min_version": "", + "version": "", + "announcement": "", + "announcement_url": "", } err := json.Unmarshal(data, &versionJSON) if err != nil { @@ -91,14 +90,9 @@ func (u *Updater) parseVersionResponse(data []byte) (VersionInfo, error) { info.NewVersion = versionJSON["version"] info.Announcement = versionJSON["announcement"] info.AnnouncementURL = versionJSON["announcement_url"] - info.SelfUpdateMinVersion = versionJSON["selfupdate_min_version"] packageURL, ok := u.downloadURL(versionJSON) - if ok && - info.NewVersion != u.version && - strings.TrimPrefix(u.version, "v") >= strings.TrimPrefix(info.SelfUpdateMinVersion, "v") { - canAutoUpdate = true - } + info.CanAutoUpdate = aghalg.BoolToNullBool(ok && info.NewVersion != u.version) u.newVersion = info.NewVersion u.packageURL = packageURL diff --git a/internal/updater/updater.go b/internal/updater/updater.go index 0cc49f9e..d975d977 100644 --- a/internal/updater/updater.go +++ b/internal/updater/updater.go @@ -104,11 +104,14 @@ func NewUpdater(conf *Config) *Updater { } // Update performs the auto-update. -func (u *Updater) Update() error { +func (u *Updater) Update() (err error) { u.mu.Lock() defer u.mu.Unlock() - err := u.prepare() + log.Info("updater: updating") + defer func() { log.Info("updater: finished; errors: %v", err) }() + + err = u.prepare() if err != nil { return err } @@ -178,7 +181,12 @@ func (u *Updater) prepare() (err error) { u.backupExeName = filepath.Join(u.backupDir, exeName) u.updateExeName = filepath.Join(u.updateDir, exeName) - log.Info("Updating from %s to %s. URL:%s", version.Version(), u.newVersion, u.packageURL) + log.Debug( + "updater: updating from %s to %s using url: %s", + version.Version(), + u.newVersion, + u.packageURL, + ) // TODO(a.garipov): Use os.Args[0] instead? u.currentExeName = filepath.Join(u.workDir, exeName) @@ -194,7 +202,7 @@ func (u *Updater) unpack() error { var err error _, pkgNameOnly := filepath.Split(u.packageURL) - log.Debug("updater: unpacking the package") + log.Debug("updater: unpacking package") if strings.HasSuffix(pkgNameOnly, ".zip") { u.unpackedFiles, err = zipFileUnpack(u.packageName, u.updateDir) if err != nil { @@ -229,7 +237,7 @@ func (u *Updater) check() error { } func (u *Updater) backup() error { - log.Debug("updater: backing up the current configuration") + log.Debug("updater: backing up current configuration") _ = os.Mkdir(u.backupDir, 0o755) err := copyFile(u.confName, filepath.Join(u.backupDir, "AdGuardHome.yaml")) if err != nil { @@ -252,7 +260,7 @@ func (u *Updater) replace() error { return fmt.Errorf("copySupportingFiles(%s, %s) failed: %s", u.updateDir, u.workDir, err) } - log.Debug("updater: renaming: %s -> %s", u.currentExeName, u.backupExeName) + log.Debug("updater: renaming: %s to %s", u.currentExeName, u.backupExeName) err = os.Rename(u.currentExeName, u.backupExeName) if err != nil { return err @@ -268,7 +276,7 @@ func (u *Updater) replace() error { return err } - log.Debug("updater: renamed: %s -> %s", u.updateExeName, u.currentExeName) + log.Debug("updater: renamed: %s to %s", u.updateExeName, u.currentExeName) return nil } @@ -297,7 +305,7 @@ func (u *Updater) downloadPackageFile(url, filename string) (err error) { return fmt.Errorf("http request failed: %w", err) } - log.Debug("updater: reading HTTP body") + log.Debug("updater: reading http body") // This use of ReadAll is now safe, because we limited body's Reader. body, err := io.ReadAll(r) if err != nil { @@ -343,7 +351,7 @@ func tarGzFileUnpackOne(outDir string, tr *tar.Reader, hdr *tar.Header) (name st } if hdr.Typeflag != tar.TypeReg { - log.Debug("updater: %s: unknown file type %d, skipping", name, hdr.Typeflag) + log.Info("updater: %s: unknown file type %d, skipping", name, hdr.Typeflag) return "", nil } @@ -364,7 +372,7 @@ func tarGzFileUnpackOne(outDir string, tr *tar.Reader, hdr *tar.Header) (name st return "", fmt.Errorf("io.Copy(): %w", err) } - log.Tracef("updater: created file %s", outputName) + log.Debug("updater: created file %q", outputName) return name, nil } @@ -440,7 +448,7 @@ func zipFileUnpackOne(outDir string, zf *zip.File) (name string, err error) { return "", fmt.Errorf("os.Mkdir(%q): %w", outputName, err) } - log.Tracef("created directory %q", outputName) + log.Debug("updater: created directory %q", outputName) return "", nil } @@ -457,7 +465,7 @@ func zipFileUnpackOne(outDir string, zf *zip.File) (name string, err error) { return "", fmt.Errorf("io.Copy(): %w", err) } - log.Tracef("created file %s", outputName) + log.Debug("updater: created file %q", outputName) return name, nil } @@ -516,7 +524,7 @@ func copySupportingFiles(files []string, srcdir, dstdir string) error { return err } - log.Debug("updater: copied: %q -> %q", src, dst) + log.Debug("updater: copied: %q to %q", src, dst) } return nil diff --git a/internal/updater/updater_test.go b/internal/updater/updater_test.go index 3a29d277..771fb6d4 100644 --- a/internal/updater/updater_test.go +++ b/internal/updater/updater_test.go @@ -10,6 +10,7 @@ import ( "strconv" "testing" + "github.com/AdguardTeam/AdGuardHome/internal/aghalg" "github.com/AdguardTeam/AdGuardHome/internal/aghtest" "github.com/AdguardTeam/AdGuardHome/internal/version" "github.com/AdguardTeam/golibs/testutil" @@ -92,10 +93,7 @@ func TestUpdateGetVersion(t *testing.T) { assert.Equal(t, "v0.103.0-beta.2", info.NewVersion) assert.Equal(t, "AdGuard Home v0.103.0-beta.2 is now available!", info.Announcement) assert.Equal(t, "https://github.com/AdguardTeam/AdGuardHome/internal/releases", info.AnnouncementURL) - assert.Equal(t, "v0.0", info.SelfUpdateMinVersion) - if assert.NotNil(t, info.CanAutoUpdate) { - assert.True(t, *info.CanAutoUpdate) - } + assert.Equal(t, aghalg.NBTrue, info.CanAutoUpdate) // check cached _, err = u.VersionInfo(false) @@ -290,10 +288,7 @@ func TestUpdater_VersionInto_ARM(t *testing.T) { assert.Equal(t, "v0.103.0-beta.2", info.NewVersion) assert.Equal(t, "AdGuard Home v0.103.0-beta.2 is now available!", info.Announcement) assert.Equal(t, "https://github.com/AdguardTeam/AdGuardHome/internal/releases", info.AnnouncementURL) - assert.Equal(t, "v0.0", info.SelfUpdateMinVersion) - if assert.NotNil(t, info.CanAutoUpdate) { - assert.True(t, *info.CanAutoUpdate) - } + assert.Equal(t, aghalg.NBTrue, info.CanAutoUpdate) } func TestUpdater_VersionInto_MIPS(t *testing.T) { @@ -330,8 +325,5 @@ func TestUpdater_VersionInto_MIPS(t *testing.T) { assert.Equal(t, "v0.103.0-beta.2", info.NewVersion) assert.Equal(t, "AdGuard Home v0.103.0-beta.2 is now available!", info.Announcement) assert.Equal(t, "https://github.com/AdguardTeam/AdGuardHome/internal/releases", info.AnnouncementURL) - assert.Equal(t, "v0.0", info.SelfUpdateMinVersion) - if assert.NotNil(t, info.CanAutoUpdate) { - assert.True(t, *info.CanAutoUpdate) - } + assert.Equal(t, aghalg.NBTrue, info.CanAutoUpdate) } diff --git a/scripts/make/build-release.sh b/scripts/make/build-release.sh index 36fc98f7..2cf95086 100644 --- a/scripts/make/build-release.sh +++ b/scripts/make/build-release.sh @@ -363,6 +363,7 @@ else fi readonly announcement_url +# TODO(a.garipov): Remove "selfupdate_min_version" in future versions. rm -f "$version_json" echo "{ \"version\": \"${version}\", From d3f39b0aa168ddf89755e769a1477ae3c91ece3a Mon Sep 17 00:00:00 2001 From: Ildar Kamalov Date: Fri, 10 Jun 2022 12:41:20 +0300 Subject: [PATCH 063/110] Pull request: 4637 fix blocked services icons and actions highlight Updates #4637 Squashed commit of the following: commit d69887586d15582406fab642e576a46f8984107b Merge: 65453371 e738508d Author: Ildar Kamalov Date: Fri Jun 10 12:07:29 2022 +0300 Merge branch 'master' into 4637-table commit 65453371fc7309e772a12fb9f522247e1392a64a Author: Ildar Kamalov Date: Thu Jun 9 18:43:44 2022 +0300 client: fix blocked services icons and actions highlight --- client/src/components/Filters/Rewrites/Table.js | 2 ++ client/src/components/Filters/Table.js | 4 +++- client/src/components/Logs/Logs.css | 9 +++++++++ client/src/components/Settings/Clients/ClientsTable.js | 4 +++- .../src/components/Settings/Dhcp/StaticLeases/index.js | 2 ++ 5 files changed, 19 insertions(+), 2 deletions(-) diff --git a/client/src/components/Filters/Rewrites/Table.js b/client/src/components/Filters/Rewrites/Table.js index 45638ec0..28009ca3 100644 --- a/client/src/components/Filters/Rewrites/Table.js +++ b/client/src/components/Filters/Rewrites/Table.js @@ -29,6 +29,8 @@ class Table extends Component { Header: this.props.t('actions_table_header'), accessor: 'actions', maxWidth: 100, + sortable: false, + resizable: false, Cell: (value) => (
@@ -101,6 +103,7 @@ Form.propTypes = { ip: PropTypes.string.isRequired, hostname: PropTypes.string.isRequired, cidr: PropTypes.string.isRequired, + gatewayIp: PropTypes.string, }), pristine: PropTypes.bool.isRequired, handleSubmit: PropTypes.func.isRequired, diff --git a/client/src/components/Settings/Dhcp/StaticLeases/Modal.js b/client/src/components/Settings/Dhcp/StaticLeases/Modal.js index 8ad0f009..0baf487e 100644 --- a/client/src/components/Settings/Dhcp/StaticLeases/Modal.js +++ b/client/src/components/Settings/Dhcp/StaticLeases/Modal.js @@ -13,6 +13,7 @@ const Modal = ({ cidr, rangeStart, rangeEnd, + gatewayIp, }) => { const dispatch = useDispatch(); @@ -42,6 +43,7 @@ const Modal = ({ cidr, rangeStart, rangeEnd, + gatewayIp, }} onSubmit={handleSubmit} processingAdding={processingAdding} @@ -61,6 +63,7 @@ Modal.propTypes = { cidr: PropTypes.string.isRequired, rangeStart: PropTypes.string, rangeEnd: PropTypes.string, + gatewayIp: PropTypes.string, }; export default withTranslation()(Modal); diff --git a/client/src/components/Settings/Dhcp/StaticLeases/index.js b/client/src/components/Settings/Dhcp/StaticLeases/index.js index a63f78cd..2374f044 100644 --- a/client/src/components/Settings/Dhcp/StaticLeases/index.js +++ b/client/src/components/Settings/Dhcp/StaticLeases/index.js @@ -24,6 +24,7 @@ const StaticLeases = ({ cidr, rangeStart, rangeEnd, + gatewayIp, }) => { const [t] = useTranslation(); const dispatch = useDispatch(); @@ -106,6 +107,7 @@ const StaticLeases = ({ cidr={cidr} rangeStart={rangeStart} rangeEnd={rangeEnd} + gatewayIp={gatewayIp} /> ); @@ -119,6 +121,7 @@ StaticLeases.propTypes = { cidr: PropTypes.string.isRequired, rangeStart: PropTypes.string, rangeEnd: PropTypes.string, + gatewayIp: PropTypes.string, }; cellWrap.propTypes = { diff --git a/client/src/components/Settings/Dhcp/index.js b/client/src/components/Settings/Dhcp/index.js index a84e0a93..bd3a45e3 100644 --- a/client/src/components/Settings/Dhcp/index.js +++ b/client/src/components/Settings/Dhcp/index.js @@ -278,6 +278,7 @@ const Dhcp = () => { cidr={cidr} rangeStart={dhcp?.values?.v4?.range_start} rangeEnd={dhcp?.values?.v4?.range_end} + gatewayIp={dhcp?.values?.v4?.gateway_ip} />
; + const blockButton = ( + <> +
+ + + ); const blockForClientButton =