From adec2c998bc83282b2befb4f515d5ca784cd57b8 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Mon, 11 Oct 2021 15:56:22 +0300 Subject: [PATCH 001/135] Pull request: all: upd golang-ubuntu image version Merge in DNS/adguard-home from upd-golang-ubuntu to master Squashed commit of the following: commit 67874bad7e018d6d17dc4f000aef79a5a430b994 Author: Ainar Garipov Date: Mon Oct 11 15:32:39 2021 +0300 all: upd golang-ubuntu image version --- bamboo-specs/release.yaml | 6 +++--- bamboo-specs/test.yaml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bamboo-specs/release.yaml b/bamboo-specs/release.yaml index 419dba39..86b3f0aa 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:3.3' + 'dockerGo': 'adguard/golang-ubuntu:3.6' 'stages': - 'Make release': @@ -266,7 +266,7 @@ # need to build a few of these. 'variables': 'channel': 'beta' - 'dockerGo': 'adguard/golang-ubuntu:3.3' + 'dockerGo': 'adguard/golang-ubuntu:3.6' # release-vX.Y.Z branches are the branches from which the actual final release # is built. - '^release-v[0-9]+\.[0-9]+\.[0-9]+': @@ -276,4 +276,4 @@ # are the ones that actually get released. 'variables': 'channel': 'release' - 'dockerGo': 'adguard/golang-ubuntu:3.3' + 'dockerGo': 'adguard/golang-ubuntu:3.6' diff --git a/bamboo-specs/test.yaml b/bamboo-specs/test.yaml index 5c106b20..e34a1a09 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:3.3' + 'dockerGo': 'adguard/golang-ubuntu:3.6' 'stages': - 'Tests': From 2b635bf689f5321890f112f528678bdf072aaa64 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Tue, 12 Oct 2021 13:58:51 +0300 Subject: [PATCH 002/135] Pull request: client: upd i18n Merge in DNS/adguard-home from upd-i18n to master Squashed commit of the following: commit 5c9b2c73bacfe64915d5deef1c18cb14fcfcf303 Author: Ainar Garipov Date: Tue Oct 12 13:40:45 2021 +0300 client: upd i18n --- client/src/__locales/hr.json | 13 ++++++++----- client/src/__locales/ro.json | 19 +++++++++++++------ 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/client/src/__locales/hr.json b/client/src/__locales/hr.json index 1a963548..a8f51ab9 100644 --- a/client/src/__locales/hr.json +++ b/client/src/__locales/hr.json @@ -208,7 +208,7 @@ "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)", "all_lists_up_to_date_toast": "Svi popisi su ažurirani", - "updated_upstream_dns_toast": "Ažurirani su upstream DNS poslužitelji", + "updated_upstream_dns_toast": "Uzvodni poslužitelji uspješno su spremljeni", "dns_test_ok_toast": "Odabrani DNS poslužitelji su trenutno aktivni", "dns_test_not_ok_toast": "\"{{key}}\" poslužitelja: ne može se upotrijebiti, provjerite jeste li to ispravno napisali", "unblock": "Odblokiraj", @@ -235,7 +235,7 @@ "loading_table_status": "Učitavanje...", "page_table_footer_text": "Stranica", "rows_table_footer_text": "redova", - "updated_custom_filtering_toast": "Ažurirana su prilagođena pravila filtriranja", + "updated_custom_filtering_toast": "Prilagođena pravila uspješno su spremljena", "rule_removed_from_custom_filtering_toast": "Pravilo je uklonjeno iz prilagođenih pravila filtriranja: {{rule}}", "rule_added_to_custom_filtering_toast": "Pravilo je dodano u prilagođena pravila filtriranja: {{rule}}", "query_log_response_status": "Status: {{value}}", @@ -306,7 +306,7 @@ "install_settings_dns_desc": "Potrebno je postaviti uređaj ili router da koristi DNS poslužitelj na sljedećim adresama:", "install_settings_all_interfaces": "Sva sučelja", "install_auth_title": "Autentikacija", - "install_auth_desc": "Izrazito se preporučuje postavljanje autentikacije za web administratorsko sučelje AdGuard Home. Iako je dostupna samo u vašoj lokalnoj mreži, važno je zaštititi je od ne dozvoljenog pristupa.", + "install_auth_desc": "Provjera autentičnosti lozinke na web-sučelje AdGuard Home admin mora biti konfigurirana. Čak i ako je AdGuard Home dostupan samo u vašoj lokalnoj mreži, i dalje je važno zaštititi ga od neograničenog pristupa.", "install_auth_username": "Korisničko ime", "install_auth_password": "Lozinka", "install_auth_confirm": "Potvrdi lozinku", @@ -503,6 +503,7 @@ "statistics_clear_confirm": "Jeste li sigurni da želite poništiti statistiku?", "statistics_retention_confirm": "Jeste li sigurni da želite promijeniti zadržavanje statistike? Ako smanjite vrijednost intervala, neki će podaci biti izgubljeni", "statistics_cleared": "Statistika je uspješno uklonjenja", + "statistics_enable": "Omogući statistiku", "interval_hours": "{{count}} sata/i", "interval_hours_plural": "{{count}} sata/i", "filters_configuration": "Postavke filtara", @@ -612,6 +613,8 @@ "click_to_view_queries": "Kliknite za pregled upita", "port_53_faq_link": "Port 53 često zauzimaju usluge \"DNSStubListener\" ili \"systemd-resolved\". Molimo pročitajte <0>ove upute o tome kako to riješiti.", "adg_will_drop_dns_queries": "AdGuard Home odbaciti će sve DNS upite od ovog klijenta.", - "client_not_in_allowed_clients": "Klijent nije dopušten jer nije na popisu \"Dopuštenih klijenata\".", - "experimental": "Eksperimentalno" + "filter_allowlist": "UPOZORENJE: Ova akcija će također isključiti pravilo \"{{disallowed_rule}}\" s popisa dopuštenih klijenata.", + "last_rule_in_allowlist": "Ovaj klijent nije moguće onemogućiti jer će isključivanje pravila \"{{disallowed_rule}}\" ONEMOGUĆITI popis \"Dopušteni klijenti\".", + "experimental": "Eksperimentalno", + "use_saved_key": "Korištenje prethodno spremljenog ključa" } diff --git a/client/src/__locales/ro.json b/client/src/__locales/ro.json index 10eb7924..0f793be5 100644 --- a/client/src/__locales/ro.json +++ b/client/src/__locales/ro.json @@ -112,6 +112,8 @@ "for_last_24_hours": "în ultimele 24 ore", "for_last_days": "în ultima {{count}} zi", "for_last_days_plural": "pentru ultimele {{count}} zile", + "stats_disabled": "Statisticile au fost dezactivate. Puteți să le porniți din <0>pagina de setări.", + "stats_disabled_short": "Statisticile au fost dezactivate", "no_domains_found": "Nu s-au găsit domenii", "requests_count": "Cont interogări", "top_blocked_domains": "Domeniile blocate cel mai des", @@ -206,7 +208,7 @@ "example_upstream_sdns": "puteți utiliza <0>DNS Stamps pentru rezolvere <1>DNSCrypt sau <2>DNS-over-HTTPS", "example_upstream_tcp": "DNS clasic (over TCP)", "all_lists_up_to_date_toast": "Toate listele sunt deja la zi", - "updated_upstream_dns_toast": "Serverele DNS în amonte aduse la zi", + "updated_upstream_dns_toast": "Serverele din amonte au fost salvate cu succes", "dns_test_ok_toast": "Serverele DNS specificate funcționează corect", "dns_test_not_ok_toast": "Serverul \"{{key}}\": nu a putut fi utilizat, verificați dacă l-ați scris corect", "unblock": "Deblocați", @@ -233,7 +235,7 @@ "loading_table_status": "Se încarcă...", "page_table_footer_text": "Pagina", "rows_table_footer_text": "linii", - "updated_custom_filtering_toast": "Reguli personalizate de filtrare aduse la zi", + "updated_custom_filtering_toast": "Regulile personalizate au fost salvate cu succes", "rule_removed_from_custom_filtering_toast": "Regulă scoasă din regullei personalizate de filtrare: {{rule}}", "rule_added_to_custom_filtering_toast": "Regulă adăugată la regulile de filtrare personalizate: {{rule}}", "query_log_response_status": "Statut: {{value}}", @@ -304,7 +306,7 @@ "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", "install_auth_title": "Autentificare", - "install_auth_desc": "Este foarte recomandat să configurați o parolă pentru accesul la interfața web de administrare AdGuard Home. Chiar dacă este accesibil numai în rețeaua dvs. locală, este încă important să îl protejați de accesul fără restricții.", + "install_auth_desc": "Trebuie configurată autentificarea cu parolă la interfața web AdGuard Home admin. Chiar dacă AdGuard Home este accesibil numai în rețeaua locală, este important să îl protejați de accesul fără restricții.", "install_auth_username": "Nume utilizator", "install_auth_password": "Parola", "install_auth_confirm": "Confirmați parola", @@ -327,7 +329,7 @@ "install_devices_windows_list_3": "În partea stângă a ecranului găsiți \"Schimbare setări adaptor\" și clicați pe el.", "install_devices_windows_list_4": "Selectați conexiunea activă, faceți clic dreapta pe ea și alegeți \"Proprietăți\".", "install_devices_windows_list_5": "Găsiți Internet Protocol Versiunea 4 (TCP/IPv4) din listă, selectați-l și apoi clicați din nou pe Proprietăți.", - "install_devices_windows_list_6": "Alegeți Utilizați următoarele adrese de server DNS și introduceți adresele de server AdGuard Home.", + "install_devices_windows_list_6": "Alegeți „Utilizați următoarele adrese de server DNS” și introduceți adresele serverului dvs. AdGuard Home.", "install_devices_macos_list_1": "Clicați pe icoana Apple și accesați Preferințele Sistemului.", "install_devices_macos_list_2": "Clicați pe Network.", "install_devices_macos_list_3": "Selectați prima conexiune din listă și clicați pe Avansat.", @@ -501,6 +503,7 @@ "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", "statistics_cleared": "Statisticile au fost șterse cu succes", + "statistics_enable": "Activați statisticile", "interval_hours": "{{count}} oră", "interval_hours_plural": "{{count}} ore", "filters_configuration": "Configurația filtrelor", @@ -595,6 +598,8 @@ "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ă", + "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", "filter_category_security": "Securitate", "filter_category_regional": "Regional", @@ -608,6 +613,8 @@ "click_to_view_queries": "Clicați pentru a vizualiza interogări", "port_53_faq_link": "Portul 53 este adesea ocupat de serviciile \"DNSStubListener\" sau \"systemd-resolved\". Vă rugăm să citiți <0>această instrucțiune despre cum să rezolvați aceasta.", "adg_will_drop_dns_queries": "AdGuard Home va renunța la toate interogările DNS de la acest client.", - "client_not_in_allowed_clients": "Clientul nu este permis deoarece nu este în lista de \"Clienți permiși\".", - "experimental": "Experimental" + "filter_allowlist": "AVERTISMENT: Această acțiune va exclude și regula „{{disallowed_rule}}” din lista de clienți permiși.", + "last_rule_in_allowlist": "Acest client nu poate fi exclus deoarece excluderea regulii „{{disallowed_rule}}” va DEZACTIVA lista „Clienți acceptați”.", + "experimental": "Experimental", + "use_saved_key": "Folosiți cheia salvată anterior" } From 2796e65468a87c7e556087fdec1c8663eedfe90e Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Thu, 14 Oct 2021 19:39:21 +0300 Subject: [PATCH 003/135] Pull request: 2499 merge rewrites vol.1 Merge in DNS/adguard-home from 2499-merge-rewrites-vol.1 to master Updates #2499. Squashed commit of the following: commit 6b308bc2b360cee8c22e506f31d62bacb4bf8fb3 Merge: f49e9186 2b635bf6 Author: Eugene Burkov Date: Thu Oct 14 19:23:07 2021 +0300 Merge branch 'master' into 2499-merge-rewrites-vol.1 commit f49e9186ffc8b7074d03c6721ee56cdb09243684 Author: Eugene Burkov Date: Thu Oct 14 18:50:49 2021 +0300 aghos: fix fs events filtering commit 567dd646556606212af5dab60e3ecbb8fff22c25 Author: Eugene Burkov Date: Thu Oct 14 16:50:37 2021 +0300 all: imp code, docs, fix windows commit 140c8bf519345eb54d0e7500a996fcf465353d71 Author: Eugene Burkov Date: Wed Oct 13 19:41:53 2021 +0300 aghnet: use const commit bebf3f76bd394a498ccad812c57d4507c69529ba Author: Eugene Burkov Date: Wed Oct 13 19:32:37 2021 +0300 all: imp tests, docs commit 9bfdbb6eb454833135d616e208e82699f98e2562 Author: Eugene Burkov Date: Wed Oct 13 18:42:20 2021 +0300 all: imp path more, imp docs commit ee9ea4c132a6b17787d150bf2bee703abaa57be3 Author: Eugene Burkov Date: Wed Oct 13 16:09:46 2021 +0300 all: fix windows, imp paths commit 6fac8338a81e9ecfebfc23a1adcb964e89f6aee6 Author: Eugene Burkov Date: Mon Oct 11 19:53:35 2021 +0300 all: imp code, docs commit da1ce1a2a3dd2be3fdff2412a6dbd596859dc249 Author: Eugene Burkov Date: Mon Oct 11 18:22:50 2021 +0300 aghnet: fix windows tests commit d29de359ed68118d71efb226a8433fac15ff5c66 Author: Eugene Burkov Date: Fri Oct 8 21:02:14 2021 +0300 all: repl & imp commit 1356c08944cdbb85ce5532d90fe5b077219ce5ff Author: Eugene Burkov Date: Fri Oct 8 01:41:19 2021 +0300 all: add tests, mv logic, added tmpfs commit f4b11adf8998bc8d9d955c5ac9f386f671bd5213 Author: Eugene Burkov Date: Thu Oct 7 14:26:30 2021 +0300 all: imp filewalker, refactor hosts container --- internal/aghnet/etchostscontainer.go | 387 ----------------- internal/aghnet/etchostscontainer_test.go | 130 ------ internal/aghnet/hostscontainer.go | 343 +++++++++++++++ internal/aghnet/hostscontainer_linux.go | 18 + internal/aghnet/hostscontainer_others.go | 8 + internal/aghnet/hostscontainer_test.go | 504 ++++++++++++++++++++++ internal/aghnet/hostscontainer_windows.go | 33 ++ internal/aghnet/net_freebsd.go | 6 +- internal/aghnet/net_linux.go | 8 +- internal/aghnet/net_linux_test.go | 2 - internal/aghnet/net_openbsd.go | 4 +- internal/aghnet/net_test.go | 5 + internal/aghos/filewalker.go | 70 +-- internal/aghos/filewalker_test.go | 181 ++++---- internal/aghos/fswatcher.go | 131 ++++++ internal/aghos/os.go | 9 + internal/aghos/os_linux.go | 4 +- internal/aghtest/fswatcher.go | 23 + internal/dnsforward/dnsforward_test.go | 47 +- internal/filtering/dnsrewrite.go | 6 +- internal/filtering/filtering.go | 130 +++--- internal/home/clients.go | 43 +- internal/home/filter.go | 7 +- internal/home/home.go | 53 ++- 24 files changed, 1377 insertions(+), 775 deletions(-) delete mode 100644 internal/aghnet/etchostscontainer.go delete mode 100644 internal/aghnet/etchostscontainer_test.go create mode 100644 internal/aghnet/hostscontainer.go create mode 100644 internal/aghnet/hostscontainer_linux.go create mode 100644 internal/aghnet/hostscontainer_others.go create mode 100644 internal/aghnet/hostscontainer_test.go create mode 100644 internal/aghnet/hostscontainer_windows.go create mode 100644 internal/aghos/fswatcher.go create mode 100644 internal/aghtest/fswatcher.go diff --git a/internal/aghnet/etchostscontainer.go b/internal/aghnet/etchostscontainer.go deleted file mode 100644 index af597e61..00000000 --- a/internal/aghnet/etchostscontainer.go +++ /dev/null @@ -1,387 +0,0 @@ -package aghnet - -import ( - "bufio" - "net" - "os" - "path/filepath" - "runtime" - "strings" - "sync" - - "github.com/AdguardTeam/AdGuardHome/internal/aghos" - "github.com/AdguardTeam/golibs/errors" - "github.com/AdguardTeam/golibs/log" - "github.com/AdguardTeam/golibs/netutil" - "github.com/fsnotify/fsnotify" - "github.com/miekg/dns" -) - -type onChangedT func() - -// EtcHostsContainer - automatic DNS records -// -// TODO(e.burkov): Move the logic under interface. Refactor. Probably remove -// the resolving logic. -type EtcHostsContainer struct { - // lock protects table and tableReverse. - lock sync.RWMutex - // table is the host-to-IPs map. - table map[string][]net.IP - // tableReverse is the IP-to-hosts map. The type of the values in the - // map is []string. - tableReverse *netutil.IPMap - - hostsFn string // path to the main hosts-file - hostsDirs []string // paths to OS-specific directories with hosts-files - watcher *fsnotify.Watcher // file and directory watcher object - - // onlyWritesChan used to contain only writing events from watcher. - onlyWritesChan chan fsnotify.Event - - onChanged onChangedT // notification to other modules -} - -// SetOnChanged - set callback function that will be called when the data is changed -func (ehc *EtcHostsContainer) SetOnChanged(onChanged onChangedT) { - ehc.onChanged = onChanged -} - -// Notify other modules -func (ehc *EtcHostsContainer) notify() { - if ehc.onChanged == nil { - return - } - ehc.onChanged() -} - -// Init - initialize -// hostsFn: Override default name for the hosts-file (optional) -func (ehc *EtcHostsContainer) Init(hostsFn string) { - ehc.table = make(map[string][]net.IP) - ehc.onlyWritesChan = make(chan fsnotify.Event, 2) - - ehc.hostsFn = "/etc/hosts" - if runtime.GOOS == "windows" { - ehc.hostsFn = os.ExpandEnv("$SystemRoot\\system32\\drivers\\etc\\hosts") - } - if len(hostsFn) != 0 { - ehc.hostsFn = hostsFn - } - - if aghos.IsOpenWrt() { - // OpenWrt: "/tmp/hosts/dhcp.cfg01411c". - ehc.hostsDirs = append(ehc.hostsDirs, "/tmp/hosts") - } - - // Load hosts initially - ehc.updateHosts() - - var err error - ehc.watcher, err = fsnotify.NewWatcher() - if err != nil { - log.Error("etchosts: %s", err) - } -} - -// Start - start module -func (ehc *EtcHostsContainer) Start() { - if ehc == nil { - return - } - - log.Debug("Start etchostscontainer module") - - ehc.updateHosts() - - if ehc.watcher != nil { - go ehc.watcherLoop() - - err := ehc.watcher.Add(ehc.hostsFn) - if err != nil { - log.Error("Error while initializing watcher for a file %s: %s", ehc.hostsFn, err) - } - - for _, dir := range ehc.hostsDirs { - err = ehc.watcher.Add(dir) - if err != nil { - log.Error("Error while initializing watcher for a directory %s: %s", dir, err) - } - } - } -} - -// Close - close module -func (ehc *EtcHostsContainer) Close() { - if ehc == nil { - return - } - - if ehc.watcher != nil { - _ = ehc.watcher.Close() - } - - // Don't close onlyWritesChan here and let onlyWrites close it after - // watcher.Events is closed to prevent close races. -} - -// Process returns the list of IP addresses for the hostname or nil if nothing -// found. -func (ehc *EtcHostsContainer) Process(host string, qtype uint16) []net.IP { - if qtype == dns.TypePTR { - return nil - } - - var ipsCopy []net.IP - ehc.lock.RLock() - defer ehc.lock.RUnlock() - - if ips, ok := ehc.table[host]; ok { - ipsCopy = make([]net.IP, len(ips)) - copy(ipsCopy, ips) - } - - log.Debug("etchosts: answer: %s -> %v", host, ipsCopy) - return ipsCopy -} - -// ProcessReverse processes a PTR request. It returns nil if nothing is found. -func (ehc *EtcHostsContainer) ProcessReverse(addr string, qtype uint16) (hosts []string) { - if qtype != dns.TypePTR { - return nil - } - - ip, err := netutil.IPFromReversedAddr(addr) - if err != nil { - log.Error("etchosts: reversed addr: %s", err) - - return nil - } - - ehc.lock.RLock() - defer ehc.lock.RUnlock() - - v, ok := ehc.tableReverse.Get(ip) - if !ok { - return nil - } - - hosts, ok = v.([]string) - if !ok { - log.Error("etchosts: bad type %T in tableReverse for %s", v, ip) - - return nil - } else if len(hosts) == 0 { - return nil - } - - log.Debug("etchosts: reverse-lookup: %s -> %s", addr, hosts) - - return hosts -} - -// List returns an IP-to-hostnames table. The type of the values in the map is -// []string. It is safe for concurrent use. -func (ehc *EtcHostsContainer) List() (ipToHosts *netutil.IPMap) { - ehc.lock.RLock() - defer ehc.lock.RUnlock() - - return ehc.tableReverse.ShallowClone() -} - -// update table -func (ehc *EtcHostsContainer) updateTable(table map[string][]net.IP, host string, ipAddr net.IP) { - ips, ok := table[host] - if ok { - for _, ip := range ips { - if ip.Equal(ipAddr) { - // IP already exists: don't add duplicates - ok = false - break - } - } - if !ok { - ips = append(ips, ipAddr) - table[host] = ips - } - } else { - table[host] = []net.IP{ipAddr} - ok = true - } - if ok { - log.Debug("etchosts: added %s -> %s", ipAddr, host) - } -} - -// updateTableRev updates the reverse address table. -func (ehc *EtcHostsContainer) updateTableRev(tableRev *netutil.IPMap, newHost string, ip net.IP) { - v, ok := tableRev.Get(ip) - if !ok { - tableRev.Set(ip, []string{newHost}) - log.Debug("etchosts: added reverse-address %s -> %s", ip, newHost) - - return - } - - hosts, _ := v.([]string) - for _, host := range hosts { - if host == newHost { - return - } - } - - hosts = append(hosts, newHost) - tableRev.Set(ip, hosts) - - log.Debug("etchosts: added reverse-address %s -> %s", ip, newHost) -} - -// parseHostsLine parses hosts from the fields. -func parseHostsLine(fields []string) (hosts []string) { - for _, f := range fields { - hashIdx := strings.IndexByte(f, '#') - if hashIdx == 0 { - // The rest of the fields are a part of the comment. - // Skip immediately. - return - } else if hashIdx > 0 { - // Only a part of the field is a comment. - hosts = append(hosts, f[:hashIdx]) - - return hosts - } - - hosts = append(hosts, f) - } - - return hosts -} - -// load reads IP-hostname pairs from the hosts file. Multiple hostnames per -// line for one IP are supported. -func (ehc *EtcHostsContainer) load( - table map[string][]net.IP, - tableRev *netutil.IPMap, - fn string, -) { - f, err := os.Open(fn) - if err != nil { - log.Error("etchosts: %s", err) - - return - } - - defer func() { - derr := f.Close() - if derr != nil { - log.Error("etchosts: closing file: %s", err) - } - }() - - log.Debug("etchosts: loading hosts from file %s", fn) - - s := bufio.NewScanner(f) - for s.Scan() { - line := strings.TrimSpace(s.Text()) - fields := strings.Fields(line) - if len(fields) < 2 { - continue - } - - ip := net.ParseIP(fields[0]) - if ip == nil { - continue - } - - hosts := parseHostsLine(fields[1:]) - for _, host := range hosts { - ehc.updateTable(table, host, ip) - ehc.updateTableRev(tableRev, host, ip) - } - } - - err = s.Err() - if err != nil { - log.Error("etchosts: %s", err) - } -} - -// onlyWrites is a filter for (*fsnotify.Watcher).Events. -func (ehc *EtcHostsContainer) onlyWrites() { - for event := range ehc.watcher.Events { - if event.Op&fsnotify.Write == fsnotify.Write { - ehc.onlyWritesChan <- event - } - } - - close(ehc.onlyWritesChan) -} - -// Receive notifications from fsnotify package -func (ehc *EtcHostsContainer) watcherLoop() { - go ehc.onlyWrites() - for { - select { - case event, ok := <-ehc.onlyWritesChan: - if !ok { - return - } - - // Assume that we sometimes have the same event occurred - // several times. - repeat := true - for repeat { - select { - case _, ok = <-ehc.onlyWritesChan: - repeat = ok - default: - repeat = false - } - } - - if event.Op&fsnotify.Write == fsnotify.Write { - log.Debug("etchosts: modified: %s", event.Name) - ehc.updateHosts() - } - - case err, ok := <-ehc.watcher.Errors: - if !ok { - return - } - log.Error("etchosts: %s", err) - } - } -} - -// updateHosts - loads system hosts -func (ehc *EtcHostsContainer) updateHosts() { - table := make(map[string][]net.IP) - tableRev := netutil.NewIPMap(0) - - ehc.load(table, tableRev, ehc.hostsFn) - - for _, dir := range ehc.hostsDirs { - des, err := os.ReadDir(dir) - if err != nil { - if !errors.Is(err, os.ErrNotExist) { - log.Error("etchosts: Opening directory: %q: %s", dir, err) - } - - continue - } - - for _, de := range des { - ehc.load(table, tableRev, filepath.Join(dir, de.Name())) - } - } - - func() { - ehc.lock.Lock() - defer ehc.lock.Unlock() - - ehc.table = table - ehc.tableReverse = tableRev - }() - - ehc.notify() -} diff --git a/internal/aghnet/etchostscontainer_test.go b/internal/aghnet/etchostscontainer_test.go deleted file mode 100644 index b83f2dd2..00000000 --- a/internal/aghnet/etchostscontainer_test.go +++ /dev/null @@ -1,130 +0,0 @@ -package aghnet - -import ( - "net" - "os" - "strings" - "testing" - "time" - - "github.com/AdguardTeam/AdGuardHome/internal/aghtest" - "github.com/miekg/dns" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestMain(m *testing.M) { - aghtest.DiscardLogOutput(m) -} - -func prepareTestFile(t *testing.T) (f *os.File) { - t.Helper() - - dir := t.TempDir() - - f, err := os.CreateTemp(dir, "") - require.NoError(t, err) - require.NotNil(t, f) - - t.Cleanup(func() { - assert.NoError(t, f.Close()) - }) - - return f -} - -func assertWriting(t *testing.T, f *os.File, strs ...string) { - t.Helper() - - for _, str := range strs { - n, err := f.WriteString(str) - require.NoError(t, err) - assert.Equal(t, n, len(str)) - } -} - -func TestEtcHostsContainerResolution(t *testing.T) { - ehc := &EtcHostsContainer{} - - f := prepareTestFile(t) - - assertWriting(t, f, - " 127.0.0.1 host localhost # comment \n", - " ::1 localhost#comment \n", - ) - ehc.Init(f.Name()) - - t.Run("existing_host", func(t *testing.T) { - ips := ehc.Process("localhost", dns.TypeA) - require.Len(t, ips, 1) - assert.Equal(t, net.IPv4(127, 0, 0, 1), ips[0]) - }) - - t.Run("unknown_host", func(t *testing.T) { - ips := ehc.Process("newhost", dns.TypeA) - assert.Nil(t, ips) - - // Comment. - ips = ehc.Process("comment", dns.TypeA) - assert.Nil(t, ips) - }) - - t.Run("hosts_file", func(t *testing.T) { - names, ok := ehc.List().Get(net.IP{127, 0, 0, 1}) - require.True(t, ok) - assert.Equal(t, []string{"host", "localhost"}, names) - }) - - t.Run("ptr", func(t *testing.T) { - testCases := []struct { - wantIP string - wantHost string - wantLen int - }{ - {wantIP: "127.0.0.1", wantHost: "host", wantLen: 2}, - {wantIP: "::1", wantHost: "localhost", wantLen: 1}, - } - - for _, tc := range testCases { - a, err := dns.ReverseAddr(tc.wantIP) - require.NoError(t, err) - - a = strings.TrimSuffix(a, ".") - hosts := ehc.ProcessReverse(a, dns.TypePTR) - require.Len(t, hosts, tc.wantLen) - assert.Equal(t, tc.wantHost, hosts[0]) - } - }) -} - -func TestEtcHostsContainerFSNotify(t *testing.T) { - ehc := &EtcHostsContainer{} - - f := prepareTestFile(t) - - assertWriting(t, f, " 127.0.0.1 host localhost \n") - ehc.Init(f.Name()) - - t.Run("unknown_host", func(t *testing.T) { - ips := ehc.Process("newhost", dns.TypeA) - assert.Nil(t, ips) - }) - - // Start monitoring for changes. - ehc.Start() - t.Cleanup(ehc.Close) - - assertWriting(t, f, "127.0.0.2 newhost\n") - require.NoError(t, f.Sync()) - - // Wait until fsnotify has triggered and processed the file-modification - // event. - time.Sleep(50 * time.Millisecond) - - t.Run("notified", func(t *testing.T) { - ips := ehc.Process("newhost", dns.TypeA) - assert.NotNil(t, ips) - require.Len(t, ips, 1) - assert.True(t, net.IP{127, 0, 0, 2}.Equal(ips[0])) - }) -} diff --git a/internal/aghnet/hostscontainer.go b/internal/aghnet/hostscontainer.go new file mode 100644 index 00000000..c0e12a7b --- /dev/null +++ b/internal/aghnet/hostscontainer.go @@ -0,0 +1,343 @@ +package aghnet + +import ( + "bufio" + "fmt" + "io" + "io/fs" + "net" + "path" + "strings" + "sync" + + "github.com/AdguardTeam/AdGuardHome/internal/aghos" + "github.com/AdguardTeam/golibs/errors" + "github.com/AdguardTeam/golibs/log" + "github.com/AdguardTeam/golibs/netutil" + "github.com/AdguardTeam/golibs/stringutil" + "github.com/AdguardTeam/urlfilter" + "github.com/AdguardTeam/urlfilter/filterlist" + "github.com/miekg/dns" +) + +// DefaultHostsPaths returns the slice of paths default for the operating system +// to files and directories which are containing the hosts database. The result +// is intended to use within fs.FS so the initial slash is omitted. +func DefaultHostsPaths() (paths []string) { + return defaultHostsPaths() +} + +// hostsContainerPref is a prefix for logging and wrapping errors in +// HostsContainer's methods. +const hostsContainerPref = "hosts container" + +// HostsContainer stores the relevant hosts database provided by the OS and +// processes both A/AAAA and PTR DNS requests for those. +type HostsContainer struct { + // engLock protects rulesStrg and engine. + engLock *sync.RWMutex + + // rulesStrg stores the rules obtained from the hosts' file. + rulesStrg *filterlist.RuleStorage + // engine serves rulesStrg. + engine *urlfilter.DNSEngine + + // Updates is the channel for receiving updated hosts. The receivable map's + // values has a type of slice of strings. + updates chan *netutil.IPMap + + // fsys is the working file system to read hosts files from. + fsys fs.FS + + // w tracks the changes in specified files and directories. + w aghos.FSWatcher + // patterns stores specified paths in the fs.Glob-compatible form. + patterns []string +} + +// errNoPaths is returned when there are no paths to watch passed to the +// HostsContainer. +const errNoPaths errors.Error = "hosts paths are empty" + +// NewHostsContainer creates a container of hosts, that watches the paths with +// w. paths shouldn't be empty and each of them should locate either a file or +// a directory in fsys. fsys and w must be non-nil. +func NewHostsContainer( + fsys fs.FS, + w aghos.FSWatcher, + paths ...string, +) (hc *HostsContainer, err error) { + defer func() { err = errors.Annotate(err, "%s: %w", hostsContainerPref) }() + + if len(paths) == 0 { + return nil, errNoPaths + } + + patterns, err := pathsToPatterns(fsys, paths) + if err != nil { + return nil, err + } + + hc = &HostsContainer{ + engLock: &sync.RWMutex{}, + updates: make(chan *netutil.IPMap, 1), + fsys: fsys, + w: w, + patterns: patterns, + } + + log.Debug("%s: starting", hostsContainerPref) + + // Load initially. + if err = hc.refresh(); err != nil { + return nil, err + } + + for _, p := range paths { + err = w.Add(p) + if err == nil { + continue + } else if errors.Is(err, fs.ErrNotExist) { + log.Debug("%s: file %q expected to exist but doesn't", hostsContainerPref, p) + + continue + } + + return nil, fmt.Errorf("adding path: %w", err) + } + + go hc.handleEvents() + + return hc, nil +} + +// MatchRequest is the request processing method to resolve hostnames and +// addresses from the operating system's hosts files. Any request not of A/AAAA +// or PTR type will return with an empty result. It's safe for concurrent use. +func (hc *HostsContainer) MatchRequest( + req urlfilter.DNSRequest, +) (res urlfilter.DNSResult, ok bool) { + switch req.DNSType { + case dns.TypeA, dns.TypeAAAA, dns.TypePTR: + log.Debug("%s: handling the request", hostsContainerPref) + default: + return urlfilter.DNSResult{}, false + } + + hc.engLock.RLock() + defer hc.engLock.RUnlock() + + return hc.engine.MatchRequest(req) +} + +// Close implements the io.Closer interface for *HostsContainer. +func (hc *HostsContainer) Close() (err error) { + log.Debug("%s: closing hosts container", hostsContainerPref) + + return errors.Annotate(hc.w.Close(), "%s: closing: %w", hostsContainerPref) +} + +// Upd returns the channel into which the updates are sent. +func (hc *HostsContainer) Upd() (updates <-chan *netutil.IPMap) { + return hc.updates +} + +// pathsToPatterns converts paths into patterns compatible with fs.Glob. +func pathsToPatterns(fsys fs.FS, paths []string) (patterns []string, err error) { + for i, p := range paths { + var fi fs.FileInfo + if fi, err = fs.Stat(fsys, p); err != nil { + return nil, fmt.Errorf("%q at index %d: %w", p, i, err) + } + + if fi.IsDir() { + p = path.Join(p, "*") + } + + patterns = append(patterns, p) + } + + return patterns, nil +} + +// handleEvents concurrently handles the events. It closes the update channel +// of HostsContainer when finishes. Used to be called within a goroutine. +func (hc *HostsContainer) handleEvents() { + defer log.OnPanic(fmt.Sprintf("%s: handling events", hostsContainerPref)) + + defer close(hc.updates) + + for range hc.w.Events() { + if err := hc.refresh(); err != nil { + log.Error("%s: %s", hostsContainerPref, err) + } + } +} + +// hostsParser is a helper type to parse rules from the operating system's hosts +// file. +type hostsParser struct { + // rules builds the resulting rules list content. + rules *strings.Builder + + // table stores only the unique IP-hostname pairs. It's also sent to the + // updates channel afterwards. + table *netutil.IPMap +} + +// parseHostsFile is a aghtest.FileWalker for parsing the files with hosts +// syntax. It never signs to stop the walking. +// +// See man hosts(5). +func (hp hostsParser) parseHostsFile( + r io.Reader, +) (patterns []string, cont bool, err error) { + s := bufio.NewScanner(r) + for s.Scan() { + ip, hosts := hp.parseLine(s.Text()) + if ip == nil { + continue + } + + for _, host := range hosts { + hp.addPair(ip, host) + } + } + + return nil, true, s.Err() +} + +// parseLine parses the line having the hosts syntax ignoring invalid ones. +func (hp hostsParser) parseLine(line string) (ip net.IP, hosts []string) { + line = strings.TrimSpace(line) + fields := strings.Fields(line) + if len(fields) < 2 { + return nil, nil + } + + if ip = net.ParseIP(fields[0]); ip == nil { + return nil, nil + } + +loop: + for _, f := range fields[1:] { + switch hashIdx := strings.IndexByte(f, '#'); hashIdx { + case 0: + // The rest of the fields are a part of the comment so skip + // immediately. + break loop + case -1: + hosts = append(hosts, f) + default: + // Only a part of the field is a comment. + hosts = append(hosts, f[:hashIdx]) + + break loop + } + } + + return ip, hosts +} + +// add returns true if the pair of ip and host wasn't added to the hp before. +func (hp hostsParser) add(ip net.IP, host string) (added bool) { + v, ok := hp.table.Get(ip) + hosts, _ := v.([]string) + if ok && stringutil.InSlice(hosts, host) { + return false + } + + hp.table.Set(ip, append(hosts, host)) + + return true +} + +// addPair puts the pair of ip and host to the rules builder if needed. +func (hp hostsParser) addPair(ip net.IP, host string) { + arpa, err := netutil.IPToReversedAddr(ip) + if err != nil { + return + } + + if !hp.add(ip, host) { + return + } + + qtype := "AAAA" + if ip.To4() != nil { + // Assume the validation of the IP address is performed already. + qtype = "A" + } + + stringutil.WriteToBuilder( + hp.rules, + "||", + host, + "^$dnsrewrite=NOERROR;", + qtype, + ";", + ip.String(), + "\n", + "||", + arpa, + "^$dnsrewrite=NOERROR;PTR;", + dns.Fqdn(host), + "\n", + ) + + log.Debug("%s: added ip-host pair %q/%q", hostsContainerPref, ip, host) +} + +// sendUpd tries to send the parsed data to the ch. +func (hp hostsParser) sendUpd(ch chan *netutil.IPMap) { + log.Debug("%s: sending upd", hostsContainerPref) + select { + case ch <- hp.table: + // Updates are delivered. Go on. + default: + log.Debug("%s: the buffer is full", hostsContainerPref) + } +} + +// newStrg creates a new rules storage from parsed data. +func (hp hostsParser) newStrg() (s *filterlist.RuleStorage, err error) { + return filterlist.NewRuleStorage([]filterlist.RuleList{&filterlist.StringRuleList{ + ID: 1, + RulesText: hp.rules.String(), + IgnoreCosmetic: true, + }}) +} + +// refresh gets the data from specified files and propagates the updates. +func (hc *HostsContainer) refresh() (err error) { + log.Debug("%s: refreshing", hostsContainerPref) + + hp := hostsParser{ + rules: &strings.Builder{}, + table: netutil.NewIPMap(0), + } + + _, err = aghos.FileWalker(hp.parseHostsFile).Walk(hc.fsys, hc.patterns...) + if err != nil { + return fmt.Errorf("updating: %w", err) + } + + defer hp.sendUpd(hc.updates) + + var rulesStrg *filterlist.RuleStorage + if rulesStrg, err = hp.newStrg(); err != nil { + return fmt.Errorf("initializing rules storage: %w", err) + } + + hc.resetEng(rulesStrg) + + return nil +} + +func (hc *HostsContainer) resetEng(rulesStrg *filterlist.RuleStorage) { + hc.engLock.Lock() + defer hc.engLock.Unlock() + + hc.rulesStrg = rulesStrg + hc.engine = urlfilter.NewDNSEngine(hc.rulesStrg) +} diff --git a/internal/aghnet/hostscontainer_linux.go b/internal/aghnet/hostscontainer_linux.go new file mode 100644 index 00000000..b456efdd --- /dev/null +++ b/internal/aghnet/hostscontainer_linux.go @@ -0,0 +1,18 @@ +//go:build linux +// +build linux + +package aghnet + +import ( + "github.com/AdguardTeam/AdGuardHome/internal/aghos" +) + +func defaultHostsPaths() (paths []string) { + paths = []string{"etc/hosts"} + + if aghos.IsOpenWrt() { + paths = append(paths, "tmp/hosts") + } + + return paths +} diff --git a/internal/aghnet/hostscontainer_others.go b/internal/aghnet/hostscontainer_others.go new file mode 100644 index 00000000..cd9f0fb7 --- /dev/null +++ b/internal/aghnet/hostscontainer_others.go @@ -0,0 +1,8 @@ +//go:build !(windows || linux) +// +build !windows,!linux + +package aghnet + +func defaultHostsPaths() (paths []string) { + return []string{"etc/hosts"} +} diff --git a/internal/aghnet/hostscontainer_test.go b/internal/aghnet/hostscontainer_test.go new file mode 100644 index 00000000..ce137c87 --- /dev/null +++ b/internal/aghnet/hostscontainer_test.go @@ -0,0 +1,504 @@ +package aghnet + +import ( + "io/fs" + "net" + "path" + "strings" + "sync/atomic" + "testing" + "testing/fstest" + + "github.com/AdguardTeam/AdGuardHome/internal/aghtest" + "github.com/AdguardTeam/golibs/errors" + "github.com/AdguardTeam/golibs/netutil" + "github.com/AdguardTeam/urlfilter" + "github.com/miekg/dns" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const ( + nl = "\n" + sp = " " +) + +const closeCalled errors.Error = "close method called" + +// fsWatcherOnCloseStub is a stub implementation of the Close method of +// aghos.FSWatcher. +func fsWatcherOnCloseStub() (err error) { + return closeCalled +} + +func TestNewHostsContainer(t *testing.T) { + const dirname = "dir" + const filename = "file1" + + p := path.Join(dirname, filename) + + testFS := fstest.MapFS{ + p: &fstest.MapFile{Data: []byte("127.0.0.1 localhost")}, + } + + testCases := []struct { + name string + paths []string + wantErr error + wantPatterns []string + }{{ + name: "one_file", + paths: []string{p}, + wantErr: nil, + wantPatterns: []string{p}, + }, { + name: "no_files", + paths: []string{}, + wantErr: errNoPaths, + wantPatterns: nil, + }, { + name: "non-existent_file", + paths: []string{path.Join(dirname, filename+"2")}, + wantErr: fs.ErrNotExist, + wantPatterns: nil, + }, { + name: "whole_dir", + paths: []string{dirname}, + wantErr: nil, + wantPatterns: []string{path.Join(dirname, "*")}, + }} + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + onAdd := func(name string) (err error) { + assert.Contains(t, tc.paths, name) + + return nil + } + + var eventsCalledCounter uint32 + eventsCh := make(chan struct{}) + onEvents := func() (e <-chan struct{}) { + assert.Equal(t, uint32(1), atomic.AddUint32(&eventsCalledCounter, 1)) + + return eventsCh + } + + hc, err := NewHostsContainer(testFS, &aghtest.FSWatcher{ + OnEvents: onEvents, + OnAdd: onAdd, + OnClose: fsWatcherOnCloseStub, + }, tc.paths...) + if tc.wantErr != nil { + require.ErrorIs(t, err, tc.wantErr) + + assert.Nil(t, hc) + + return + } + + require.NoError(t, err) + t.Cleanup(func() { + require.ErrorIs(t, hc.Close(), closeCalled) + }) + + require.NotNil(t, hc) + + assert.Equal(t, tc.wantPatterns, hc.patterns) + assert.NotNil(t, <-hc.Upd()) + + eventsCh <- struct{}{} + assert.Equal(t, uint32(1), atomic.LoadUint32(&eventsCalledCounter)) + }) + } + + t.Run("nil_fs", func(t *testing.T) { + require.Panics(t, func() { + _, _ = NewHostsContainer(nil, &aghtest.FSWatcher{ + // Those shouldn't panic. + OnEvents: func() (e <-chan struct{}) { return nil }, + OnAdd: func(name string) (err error) { return nil }, + OnClose: func() (err error) { return nil }, + }, p) + }) + }) + + t.Run("nil_watcher", func(t *testing.T) { + require.Panics(t, func() { + _, _ = NewHostsContainer(testFS, nil, p) + }) + }) + + t.Run("err_watcher", func(t *testing.T) { + const errOnAdd errors.Error = "error" + + errWatcher := &aghtest.FSWatcher{ + OnEvents: func() (e <-chan struct{}) { panic("not implemented") }, + OnAdd: func(name string) (err error) { return errOnAdd }, + OnClose: func() (err error) { panic("not implemented") }, + } + + hc, err := NewHostsContainer(testFS, errWatcher, p) + require.ErrorIs(t, err, errOnAdd) + + assert.Nil(t, hc) + }) +} + +func TestHostsContainer_Refresh(t *testing.T) { + knownIP := net.IP{127, 0, 0, 1} + + const knownHost = "localhost" + const knownAlias = "hocallost" + + const dirname = "dir" + const filename1 = "file1" + const filename2 = "file2" + + p1 := path.Join(dirname, filename1) + p2 := path.Join(dirname, filename2) + + testFS := fstest.MapFS{ + p1: &fstest.MapFile{ + Data: []byte(strings.Join([]string{knownIP.String(), knownHost}, sp) + nl), + }, + } + + eventsCh := make(chan struct{}, 1) + t.Cleanup(func() { close(eventsCh) }) + + w := &aghtest.FSWatcher{ + OnEvents: func() (e <-chan struct{}) { return eventsCh }, + OnAdd: func(name string) (err error) { + assert.Equal(t, dirname, name) + + return nil + }, + OnClose: fsWatcherOnCloseStub, + } + + hc, err := NewHostsContainer(testFS, w, dirname) + require.NoError(t, err) + t.Cleanup(func() { require.ErrorIs(t, hc.Close(), closeCalled) }) + + checkRefresh := func(t *testing.T, wantHosts []string) { + upd, ok := <-hc.Upd() + require.True(t, ok) + require.NotNil(t, upd) + + assert.Equal(t, 1, upd.Len()) + + v, ok := upd.Get(knownIP) + require.True(t, ok) + + var hosts []string + hosts, ok = v.([]string) + require.True(t, ok) + require.Len(t, hosts, len(wantHosts)) + + assert.Equal(t, wantHosts, hosts) + } + + t.Run("initial_refresh", func(t *testing.T) { + checkRefresh(t, []string{knownHost}) + }) + + testFS[p2] = &fstest.MapFile{ + Data: []byte(strings.Join([]string{knownIP.String(), knownAlias}, sp) + nl), + } + + eventsCh <- struct{}{} + + t.Run("second_refresh", func(t *testing.T) { + checkRefresh(t, []string{knownHost, knownAlias}) + }) +} + +func TestHostsContainer_MatchRequest(t *testing.T) { + var ( + ip4 = net.IP{127, 0, 0, 1} + ip6 = net.IP{ + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 1, + } + + hostname4 = "localhost" + hostname6 = "localhostv6" + hostname4a = "abcd" + + reversed4, _ = netutil.IPToReversedAddr(ip4) + reversed6, _ = netutil.IPToReversedAddr(ip6) + ) + + const filename = "file1" + + gsfs := fstest.MapFS{ + filename: &fstest.MapFile{Data: []byte( + strings.Join([]string{ip4.String(), hostname4, hostname4a}, sp) + nl + + strings.Join([]string{ip6.String(), hostname6}, sp) + nl + + strings.Join([]string{"256.256.256.256", "fakebroadcast"}, sp) + nl, + )}, + } + + hc, err := NewHostsContainer(gsfs, &aghtest.FSWatcher{ + OnEvents: func() (e <-chan struct{}) { panic("not implemented") }, + OnAdd: func(name string) (err error) { + assert.Equal(t, filename, name) + + return nil + }, + OnClose: fsWatcherOnCloseStub, + }, filename) + require.NoError(t, err) + t.Cleanup(func() { require.ErrorIs(t, hc.Close(), closeCalled) }) + + testCase := []struct { + name string + want interface{} + req urlfilter.DNSRequest + }{{ + name: "a", + want: ip4.To16(), + req: urlfilter.DNSRequest{ + Hostname: hostname4, + DNSType: dns.TypeA, + }, + }, { + name: "aaaa", + want: ip6, + req: urlfilter.DNSRequest{ + Hostname: hostname6, + DNSType: dns.TypeA, + }, + }, { + name: "ptr", + want: dns.Fqdn(hostname4), + req: urlfilter.DNSRequest{ + Hostname: reversed4, + DNSType: dns.TypePTR, + }, + }, { + name: "ptr_v6", + want: dns.Fqdn(hostname6), + req: urlfilter.DNSRequest{ + Hostname: reversed6, + DNSType: dns.TypePTR, + }, + }, { + name: "a_alias", + want: ip4.To16(), + req: urlfilter.DNSRequest{ + Hostname: hostname4a, + DNSType: dns.TypeA, + }, + }} + + for _, tc := range testCase { + t.Run(tc.name, func(t *testing.T) { + res, ok := hc.MatchRequest(tc.req) + require.False(t, ok) + + assert.Equal(t, tc.want, res.DNSRewrites()[0].DNSRewrite.Value) + }) + } + + t.Run("cname", func(t *testing.T) { + res, ok := hc.MatchRequest(urlfilter.DNSRequest{ + Hostname: hostname4, + DNSType: dns.TypeCNAME, + }) + require.False(t, ok) + + assert.Empty(t, res) + }) +} + +func TestHostsContainer_PathsToPatterns(t *testing.T) { + const ( + dir0 = "dir" + dir1 = "dir_1" + fn1 = "file_1" + fn2 = "file_2" + fn3 = "file_3" + fn4 = "file_4" + ) + + fp1 := path.Join(dir0, fn1) + fp2 := path.Join(dir0, fn2) + fp3 := path.Join(dir0, dir1, fn3) + + gsfs := fstest.MapFS{ + fp1: &fstest.MapFile{Data: []byte{1}}, + fp2: &fstest.MapFile{Data: []byte{2}}, + fp3: &fstest.MapFile{Data: []byte{3}}, + } + + testCases := []struct { + name string + wantErr error + want []string + paths []string + }{{ + name: "no_paths", + wantErr: nil, + want: nil, + paths: nil, + }, { + name: "single_file", + wantErr: nil, + want: []string{fp1}, + paths: []string{fp1}, + }, { + name: "several_files", + wantErr: nil, + want: []string{fp1, fp2}, + paths: []string{fp1, fp2}, + }, { + name: "whole_dir", + wantErr: nil, + want: []string{path.Join(dir0, "*")}, + paths: []string{dir0}, + }, { + name: "file_and_dir", + wantErr: nil, + want: []string{fp1, path.Join(dir0, dir1, "*")}, + paths: []string{fp1, path.Join(dir0, dir1)}, + }, { + name: "non-existing", + wantErr: fs.ErrNotExist, + want: nil, + paths: []string{path.Join(dir0, "file_3")}, + }} + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + patterns, err := pathsToPatterns(gsfs, tc.paths) + if tc.wantErr != nil { + assert.ErrorIs(t, err, tc.wantErr) + + return + } + + require.NoError(t, err) + + assert.Equal(t, tc.want, patterns) + }) + } +} + +func TestUniqueRules_AddPair(t *testing.T) { + knownIP := net.IP{1, 2, 3, 4} + + const knownHost = "host1" + + ipToHost := netutil.NewIPMap(0) + ipToHost.Set(knownIP, []string{knownHost}) + + testCases := []struct { + name string + host string + wantRules string + ip net.IP + }{{ + name: "new_one", + host: "host2", + wantRules: "||host2^$dnsrewrite=NOERROR;A;1.2.3.4\n" + + "||4.3.2.1.in-addr.arpa^$dnsrewrite=NOERROR;PTR;host2.\n", + ip: knownIP, + }, { + name: "existing_one", + host: knownHost, + wantRules: "", + ip: knownIP, + }, { + name: "new_ip", + host: knownHost, + wantRules: "||" + knownHost + "^$dnsrewrite=NOERROR;A;1.2.3.5\n" + + "||5.3.2.1.in-addr.arpa^$dnsrewrite=NOERROR;PTR;" + knownHost + ".\n", + ip: net.IP{1, 2, 3, 5}, + }, { + name: "bad_ip", + host: knownHost, + wantRules: "", + ip: net.IP{1, 2, 3, 4, 5}, + }} + + for _, tc := range testCases { + hp := hostsParser{ + rules: &strings.Builder{}, + table: ipToHost.ShallowClone(), + } + + t.Run(tc.name, func(t *testing.T) { + hp.addPair(tc.ip, tc.host) + assert.Equal(t, tc.wantRules, hp.rules.String()) + }) + } +} + +func TestUniqueRules_ParseLine(t *testing.T) { + const ( + hostname = "localhost" + alias = "hocallost" + ) + + knownIP := net.IP{127, 0, 0, 1} + + testCases := []struct { + name string + line string + wantIP net.IP + wantHosts []string + }{{ + name: "simple", + line: strings.Join([]string{knownIP.String(), hostname}, sp), + wantIP: knownIP, + wantHosts: []string{"localhost"}, + }, { + name: "aliases", + line: strings.Join([]string{knownIP.String(), hostname, alias}, sp), + wantIP: knownIP, + wantHosts: []string{"localhost", "hocallost"}, + }, { + name: "invalid_line", + line: knownIP.String(), + wantIP: nil, + wantHosts: nil, + }, { + name: "invalid_line_hostname", + line: strings.Join([]string{knownIP.String(), "#" + hostname}, sp), + wantIP: knownIP, + wantHosts: nil, + }, { + name: "commented_aliases", + line: strings.Join([]string{knownIP.String(), hostname, "#" + alias}, sp), + wantIP: knownIP, + wantHosts: []string{"localhost"}, + }, { + name: "whole_comment", + line: strings.Join([]string{"#", knownIP.String(), hostname}, sp), + wantIP: nil, + wantHosts: nil, + }, { + name: "partial_comment", + line: strings.Join([]string{knownIP.String(), hostname[:4] + "#" + hostname[4:]}, sp), + wantIP: knownIP, + wantHosts: []string{hostname[:4]}, + }, { + name: "empty", + line: ``, + wantIP: nil, + wantHosts: nil, + }} + + for _, tc := range testCases { + hp := hostsParser{} + t.Run(tc.name, func(t *testing.T) { + ip, hosts := hp.parseLine(tc.line) + assert.True(t, tc.wantIP.Equal(ip)) + assert.Equal(t, tc.wantHosts, hosts) + }) + } +} diff --git a/internal/aghnet/hostscontainer_windows.go b/internal/aghnet/hostscontainer_windows.go new file mode 100644 index 00000000..9eb2fe6f --- /dev/null +++ b/internal/aghnet/hostscontainer_windows.go @@ -0,0 +1,33 @@ +//go:build windows +// +build windows + +package aghnet + +import ( + "os" + "path" + "path/filepath" + "strings" + + "github.com/AdguardTeam/golibs/log" + "golang.org/x/sys/windows" +) + +func defaultHostsPaths() (paths []string) { + sysDir, err := windows.GetSystemDirectory() + if err != nil { + log.Error("getting system directory: %s", err) + + return []string{} + } + + // Split all the elements of the path to join them afterwards. This is + // needed to make the Windows-specific path string returned by + // windows.GetSystemDirectory to be compatible with fs.FS. + pathElems := strings.Split(sysDir, string(os.PathSeparator)) + if len(pathElems) > 0 && pathElems[0] == filepath.VolumeName(sysDir) { + pathElems = pathElems[1:] + } + + return []string{path.Join(append(pathElems, "drivers/etc/hosts")...)} +} diff --git a/internal/aghnet/net_freebsd.go b/internal/aghnet/net_freebsd.go index f4c106f1..a5200fb8 100644 --- a/internal/aghnet/net_freebsd.go +++ b/internal/aghnet/net_freebsd.go @@ -18,9 +18,11 @@ func canBindPrivilegedPorts() (can bool, err error) { } func ifaceHasStaticIP(ifaceName string) (ok bool, err error) { - const filename = "/etc/rc.conf" + const rcConfFilename = "etc/rc.conf" - return aghos.FileWalker(interfaceName(ifaceName).rcConfStaticConfig).Walk(filename) + walker := aghos.FileWalker(interfaceName(ifaceName).rcConfStaticConfig) + + return walker.Walk(aghos.RootDirFS(), rcConfFilename) } // rcConfStaticConfig checks if the interface is configured by /etc/rc.conf to diff --git a/internal/aghnet/net_linux.go b/internal/aghnet/net_linux.go index 3c6a6659..93414165 100644 --- a/internal/aghnet/net_linux.go +++ b/internal/aghnet/net_linux.go @@ -85,17 +85,17 @@ func ifaceHasStaticIP(ifaceName string) (has bool, err error) { iface := interfaceName(ifaceName) - for _, pair := range []struct { + for _, pair := range [...]struct { aghos.FileWalker filename string }{{ FileWalker: iface.dhcpcdStaticConfig, - filename: "/etc/dhcpcd.conf", + filename: "etc/dhcpcd.conf", }, { FileWalker: iface.ifacesStaticConfig, - filename: "/etc/network/interfaces", + filename: "etc/network/interfaces", }} { - has, err = pair.Walk(pair.filename) + has, err = pair.Walk(aghos.RootDirFS(), pair.filename) if err != nil { return false, err } diff --git a/internal/aghnet/net_linux_test.go b/internal/aghnet/net_linux_test.go index a907819c..bf2cecfe 100644 --- a/internal/aghnet/net_linux_test.go +++ b/internal/aghnet/net_linux_test.go @@ -12,8 +12,6 @@ import ( "github.com/stretchr/testify/require" ) -const nl = "\n" - func TestDHCPCDStaticConfig(t *testing.T) { const iface interfaceName = `wlan0` diff --git a/internal/aghnet/net_openbsd.go b/internal/aghnet/net_openbsd.go index a2b5e6e6..627db0ab 100644 --- a/internal/aghnet/net_openbsd.go +++ b/internal/aghnet/net_openbsd.go @@ -18,9 +18,9 @@ func canBindPrivilegedPorts() (can bool, err error) { } func ifaceHasStaticIP(ifaceName string) (ok bool, err error) { - filename := fmt.Sprintf("/etc/hostname.%s", ifaceName) + filename := fmt.Sprintf("etc/hostname.%s", ifaceName) - return aghos.FileWalker(hostnameIfStaticConfig).Walk(filename) + return aghos.FileWalker(hostnameIfStaticConfig).Walk(aghos.RootDirFS(), filename) } // hostnameIfStaticConfig checks if the interface is configured by diff --git a/internal/aghnet/net_test.go b/internal/aghnet/net_test.go index 0773f67f..38fdf9cc 100644 --- a/internal/aghnet/net_test.go +++ b/internal/aghnet/net_test.go @@ -4,10 +4,15 @@ import ( "net" "testing" + "github.com/AdguardTeam/AdGuardHome/internal/aghtest" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) +func TestMain(m *testing.M) { + aghtest.DiscardLogOutput(m) +} + func TestGetValidNetInterfacesForWeb(t *testing.T) { ifaces, err := GetValidNetInterfacesForWeb() require.NoErrorf(t, err, "cannot get net interfaces: %s", err) diff --git a/internal/aghos/filewalker.go b/internal/aghos/filewalker.go index b6473d1f..a72e2f5c 100644 --- a/internal/aghos/filewalker.go +++ b/internal/aghos/filewalker.go @@ -3,8 +3,7 @@ package aghos import ( "fmt" "io" - "os" - "path/filepath" + "io/fs" "github.com/AdguardTeam/AdGuardHome/internal/aghio" "github.com/AdguardTeam/golibs/errors" @@ -14,10 +13,10 @@ import ( // FileWalker is the signature of a function called for files in the file tree. // As opposed to filepath.Walk it only walk the files (not directories) matching // the provided pattern and those returned by function itself. All patterns -// should be valid for filepath.Glob. If cont is false, the walking terminates. -// Each opened file is also limited for reading to MaxWalkedFileSize. +// should be valid for fs.Glob. If cont is false, the walking terminates. Each +// opened file is also limited for reading to MaxWalkedFileSize. // -// TODO(e.burkov): Consider moving to the separate package like pathutil. +// TODO(e.burkov, a.garipov): Move into another package like aghfs. // // TODO(e.burkov): Think about passing filename or any additional data. type FileWalker func(r io.Reader) (patterns []string, cont bool, err error) @@ -26,15 +25,19 @@ type FileWalker func(r io.Reader) (patterns []string, cont bool, err error) // check. const MaxWalkedFileSize = 1024 * 1024 -// checkFile tries to open and process a single file located on sourcePath. -func checkFile(c FileWalker, sourcePath string) (patterns []string, cont bool, err error) { - var f *os.File - f, err = os.Open(sourcePath) +// checkFile tries to open and process a single file located on sourcePath in +// the specified fsys. The path is skipped if it's a directory. +func checkFile( + fsys fs.FS, + c FileWalker, + sourcePath string, +) (patterns []string, cont bool, err error) { + var f fs.File + f, err = fsys.Open(sourcePath) if err != nil { - if errors.Is(err, os.ErrNotExist) { - // Ignore non-existing files since this may only happen - // when the file was removed after filepath.Glob matched - // it. + if errors.Is(err, fs.ErrNotExist) { + // Ignore non-existing files since this may only happen when the + // file was removed after filepath.Glob matched it. return nil, true, nil } @@ -42,9 +45,18 @@ func checkFile(c FileWalker, sourcePath string) (patterns []string, cont bool, e } defer func() { err = errors.WithDeferred(err, f.Close()) }() + var fi fs.FileInfo + if fi, err = f.Stat(); err != nil { + return nil, true, err + } + if fi.IsDir() { + // Skip the directories. + return nil, true, nil + } + var r io.Reader - // Ignore the error since LimitReader function returns error only if - // passed limit value is less than zero, but the constant used. + // Ignore the error since LimitReader function returns error only if passed + // limit value is less than zero, but the constant used. // // TODO(e.burkov): Make variable. r, _ = aghio.LimitReader(f, MaxWalkedFileSize) @@ -52,13 +64,17 @@ func checkFile(c FileWalker, sourcePath string) (patterns []string, cont bool, e return c(r) } -// handlePatterns parses the patterns and ignores duplicates using srcSet. -// srcSet must be non-nil. -func handlePatterns(srcSet *stringutil.Set, patterns ...string) (sub []string, err error) { +// handlePatterns parses the patterns in fsys and ignores duplicates using +// srcSet. srcSet must be non-nil. +func handlePatterns( + fsys fs.FS, + srcSet *stringutil.Set, + patterns ...string, +) (sub []string, err error) { sub = make([]string, 0, len(patterns)) for _, p := range patterns { var matches []string - matches, err = filepath.Glob(p) + matches, err = fs.Glob(fsys, p) if err != nil { // Enrich error with the pattern because filepath.Glob // doesn't do it. @@ -78,14 +94,14 @@ func handlePatterns(srcSet *stringutil.Set, patterns ...string) (sub []string, e return sub, nil } -// Walk starts walking the files defined by initPattern. It only returns true -// if c signed to stop walking. -func (c FileWalker) Walk(initPattern string) (ok bool, err error) { - // The slice of sources keeps the order in which the files are walked - // since srcSet.Values() returns strings in undefined order. +// Walk starts walking the files in fsys defined by patterns from initial. +// It only returns true if fw signed to stop walking. +func (fw FileWalker) Walk(fsys fs.FS, initial ...string) (ok bool, err error) { + // The slice of sources keeps the order in which the files are walked since + // srcSet.Values() returns strings in undefined order. srcSet := stringutil.NewSet() var src []string - src, err = handlePatterns(srcSet, initPattern) + src, err = handlePatterns(fsys, srcSet, initial...) if err != nil { return false, err } @@ -97,7 +113,7 @@ func (c FileWalker) Walk(initPattern string) (ok bool, err error) { var patterns []string var cont bool filename = src[i] - patterns, cont, err = checkFile(c, src[i]) + patterns, cont, err = checkFile(fsys, fw, src[i]) if err != nil { return false, err } @@ -107,7 +123,7 @@ func (c FileWalker) Walk(initPattern string) (ok bool, err error) { } var subsrc []string - subsrc, err = handlePatterns(srcSet, patterns...) + subsrc, err = handlePatterns(fsys, srcSet, patterns...) if err != nil { return false, err } diff --git a/internal/aghos/filewalker_test.go b/internal/aghos/filewalker_test.go index 4ba1db20..97d1a845 100644 --- a/internal/aghos/filewalker_test.go +++ b/internal/aghos/filewalker_test.go @@ -4,56 +4,19 @@ import ( "bufio" "io" "io/fs" - "os" - "path/filepath" + "path" "testing" + "testing/fstest" "github.com/AdguardTeam/golibs/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -// testFSDir maps entries' names to entries which should either be a testFSDir -// or byte slice. -type testFSDir map[string]interface{} - -// testFSGen is used to generate a temporary filesystem consisting of -// directories and plain text files from itself. -type testFSGen testFSDir - -// gen returns the name of top directory of the generated filesystem. -func (g testFSGen) gen(t *testing.T) (dirName string) { - t.Helper() - - dirName = t.TempDir() - g.rangeThrough(t, dirName) - - return dirName -} - -func (g testFSGen) rangeThrough(t *testing.T, dirName string) { - const perm fs.FileMode = 0o777 - - for k, e := range g { - switch e := e.(type) { - case []byte: - require.NoError(t, os.WriteFile(filepath.Join(dirName, k), e, perm)) - - case testFSDir: - newDir := filepath.Join(dirName, k) - require.NoError(t, os.Mkdir(newDir, perm)) - - testFSGen(e).rangeThrough(t, newDir) - default: - t.Fatalf("unexpected entry type %T", e) - } - } -} - func TestFileWalker_Walk(t *testing.T) { const attribute = `000` - makeFileWalker := func(dirName string) (fw FileWalker) { + makeFileWalker := func(_ string) (fw FileWalker) { return func(r io.Reader) (patterns []string, cont bool, err error) { s := bufio.NewScanner(r) for s.Scan() { @@ -63,7 +26,7 @@ func TestFileWalker_Walk(t *testing.T) { } if len(line) != 0 { - patterns = append(patterns, filepath.Join(dirName, line)) + patterns = append(patterns, path.Join(".", line)) } } @@ -74,136 +37,150 @@ func TestFileWalker_Walk(t *testing.T) { const nl = "\n" testCases := []struct { - name string - testFS testFSGen + testFS fstest.MapFS + want assert.BoolAssertionFunc initPattern string - want bool + name string }{{ name: "simple", - testFS: testFSGen{ - "simple_0001.txt": []byte(attribute + nl), + testFS: fstest.MapFS{ + "simple_0001.txt": &fstest.MapFile{Data: []byte(attribute + nl)}, }, initPattern: "simple_0001.txt", - want: true, + want: assert.True, }, { name: "chain", - testFS: testFSGen{ - "chain_0001.txt": []byte(`chain_0002.txt` + nl), - "chain_0002.txt": []byte(`chain_0003.txt` + nl), - "chain_0003.txt": []byte(attribute + nl), + testFS: fstest.MapFS{ + "chain_0001.txt": &fstest.MapFile{Data: []byte(`chain_0002.txt` + nl)}, + "chain_0002.txt": &fstest.MapFile{Data: []byte(`chain_0003.txt` + nl)}, + "chain_0003.txt": &fstest.MapFile{Data: []byte(attribute + nl)}, }, initPattern: "chain_0001.txt", - want: true, + want: assert.True, }, { name: "several", - testFS: testFSGen{ - "several_0001.txt": []byte(`several_*` + nl), - "several_0002.txt": []byte(`several_0001.txt` + nl), - "several_0003.txt": []byte(attribute + nl), + testFS: fstest.MapFS{ + "several_0001.txt": &fstest.MapFile{Data: []byte(`several_*` + nl)}, + "several_0002.txt": &fstest.MapFile{Data: []byte(`several_0001.txt` + nl)}, + "several_0003.txt": &fstest.MapFile{Data: []byte(attribute + nl)}, }, initPattern: "several_0001.txt", - want: true, + want: assert.True, }, { name: "no", - testFS: testFSGen{ - "no_0001.txt": []byte(nl), - "no_0002.txt": []byte(nl), - "no_0003.txt": []byte(nl), + testFS: fstest.MapFS{ + "no_0001.txt": &fstest.MapFile{Data: []byte(nl)}, + "no_0002.txt": &fstest.MapFile{Data: []byte(nl)}, + "no_0003.txt": &fstest.MapFile{Data: []byte(nl)}, }, initPattern: "no_*", - want: false, + want: assert.False, }, { name: "subdirectory", - testFS: testFSGen{ - "dir": testFSDir{ - "subdir_0002.txt": []byte(attribute + nl), + testFS: fstest.MapFS{ + path.Join("dir", "subdir_0002.txt"): &fstest.MapFile{ + Data: []byte(attribute + nl), }, - "subdir_0001.txt": []byte(`dir/*`), + "subdir_0001.txt": &fstest.MapFile{Data: []byte(`dir/*`)}, }, initPattern: "subdir_0001.txt", - want: true, + want: assert.True, }} for _, tc := range testCases { - testDir := tc.testFS.gen(t) - fw := makeFileWalker(testDir) + fw := makeFileWalker("") t.Run(tc.name, func(t *testing.T) { - ok, err := fw.Walk(filepath.Join(testDir, tc.initPattern)) + ok, err := fw.Walk(tc.testFS, tc.initPattern) require.NoError(t, err) - assert.Equal(t, tc.want, ok) + tc.want(t, ok) }) } t.Run("pattern_malformed", func(t *testing.T) { - ok, err := makeFileWalker("").Walk("[]") + f := fstest.MapFS{} + ok, err := makeFileWalker("").Walk(f, "[]") require.Error(t, err) assert.False(t, ok) - assert.ErrorIs(t, err, filepath.ErrBadPattern) + assert.ErrorIs(t, err, path.ErrBadPattern) }) t.Run("bad_filename", func(t *testing.T) { - dir := testFSGen{ - "bad_filename.txt": []byte("[]"), - }.gen(t) - fw := FileWalker(func(r io.Reader) (patterns []string, cont bool, err error) { + const filename = "bad_filename.txt" + + f := fstest.MapFS{ + filename: &fstest.MapFile{Data: []byte("[]")}, + } + ok, err := FileWalker(func(r io.Reader) (patterns []string, cont bool, err error) { s := bufio.NewScanner(r) for s.Scan() { patterns = append(patterns, s.Text()) } return patterns, true, s.Err() - }) - - ok, err := fw.Walk(filepath.Join(dir, "bad_filename.txt")) + }).Walk(f, filename) require.Error(t, err) assert.False(t, ok) - assert.ErrorIs(t, err, filepath.ErrBadPattern) + assert.ErrorIs(t, err, path.ErrBadPattern) }) t.Run("itself_error", func(t *testing.T) { const rerr errors.Error = "returned error" - dir := testFSGen{ - "mockfile.txt": []byte(`mockdata`), - }.gen(t) + f := fstest.MapFS{ + "mockfile.txt": &fstest.MapFile{Data: []byte(`mockdata`)}, + } ok, err := FileWalker(func(r io.Reader) (patterns []string, ok bool, err error) { return nil, true, rerr - }).Walk(filepath.Join(dir, "*")) - require.Error(t, err) - require.False(t, ok) + }).Walk(f, "*") + require.ErrorIs(t, err, rerr) - assert.ErrorIs(t, err, rerr) + assert.False(t, ok) }) } +type errFS struct { + fs.GlobFS +} + +const errErrFSOpen errors.Error = "this error is always returned" + +func (efs *errFS) Open(name string) (fs.File, error) { + return nil, errErrFSOpen +} + func TestWalkerFunc_CheckFile(t *testing.T) { + emptyFS := fstest.MapFS{} + t.Run("non-existing", func(t *testing.T) { - _, ok, err := checkFile(nil, "lol") + _, ok, err := checkFile(emptyFS, nil, "lol") require.NoError(t, err) assert.True(t, ok) }) t.Run("invalid_argument", func(t *testing.T) { - const badPath = "\x00" - - _, ok, err := checkFile(nil, badPath) - require.Error(t, err) + _, ok, err := checkFile(&errFS{}, nil, "") + require.ErrorIs(t, err, errErrFSOpen) assert.False(t, ok) - // TODO(e.burkov): Use assert.ErrorsIs within the error from - // less platform-dependent package instead of syscall.EINVAL. - // - // See https://github.com/golang/go/issues/46849 and - // https://github.com/golang/go/issues/30322. - pathErr := &os.PathError{} - require.ErrorAs(t, err, &pathErr) - assert.Equal(t, "open", pathErr.Op) - assert.Equal(t, badPath, pathErr.Path) + }) + + t.Run("ignore_dirs", func(t *testing.T) { + const dirName = "dir" + + testFS := fstest.MapFS{ + path.Join(dirName, "file"): &fstest.MapFile{Data: []byte{}}, + } + + patterns, ok, err := checkFile(testFS, nil, dirName) + require.NoError(t, err) + + assert.Empty(t, patterns) + assert.True(t, ok) }) } diff --git a/internal/aghos/fswatcher.go b/internal/aghos/fswatcher.go new file mode 100644 index 00000000..a113610f --- /dev/null +++ b/internal/aghos/fswatcher.go @@ -0,0 +1,131 @@ +package aghos + +import ( + "fmt" + "io" + "io/fs" + "path/filepath" + + "github.com/AdguardTeam/golibs/errors" + "github.com/AdguardTeam/golibs/log" + "github.com/fsnotify/fsnotify" +) + +// event is a convenient alias for an empty struct to signal that watching +// event happened. +type event = struct{} + +// FSWatcher tracks all the fyle system events and notifies about those. +// +// TODO(e.burkov, a.garipov): Move into another package like aghfs. +type FSWatcher interface { + io.Closer + + // Events should return a read-only channel which notifies about events. + Events() (e <-chan event) + + // Add should check if the file named name is accessible and starts tracking + // it. + Add(name string) (err error) +} + +// osWatcher tracks the file system provided by the OS. +type osWatcher struct { + // w is the actual notifier that is handled by osWatcher. + w *fsnotify.Watcher + + // events is the channel to notify. + events chan event +} + +const ( + // osWatcherPref is a prefix for logging and wrapping errors in osWathcer's + // methods. + osWatcherPref = "os watcher" +) + +// NewOSWritesWatcher creates FSWatcher that tracks the real file system of the +// OS and notifies only about writing events. +func NewOSWritesWatcher() (w FSWatcher, err error) { + defer func() { err = errors.Annotate(err, "%s: %w", osWatcherPref) }() + + var watcher *fsnotify.Watcher + watcher, err = fsnotify.NewWatcher() + if err != nil { + return nil, fmt.Errorf("creating watcher: %w", err) + } + + fsw := &osWatcher{ + w: watcher, + events: make(chan event, 1), + } + + go fsw.handleErrors() + go fsw.handleEvents() + + return fsw, nil +} + +// handleErrors handles accompanying errors. It used to be called in a separate +// goroutine. +func (w *osWatcher) handleErrors() { + defer log.OnPanic(fmt.Sprintf("%s: handling errors", osWatcherPref)) + + for err := range w.w.Errors { + log.Error("%s: %s", osWatcherPref, err) + } +} + +// Events implements the FSWatcher interface for *osWatcher. +func (w *osWatcher) Events() (e <-chan event) { + return w.events +} + +// Add implements the FSWatcher interface for *osWatcher. +func (w *osWatcher) Add(name string) (err error) { + defer func() { err = errors.Annotate(err, "%s: %w", osWatcherPref) }() + + if _, err = fs.Stat(RootDirFS(), name); err != nil { + return fmt.Errorf("checking file %q: %w", name, err) + } + + return w.w.Add(filepath.Join("/", name)) +} + +// Close implements the FSWatcher interface for *osWatcher. +func (w *osWatcher) Close() (err error) { + return w.w.Close() +} + +// handleEvents notifies about the received file system's event if needed. It +// used to be called in a separate goroutine. +func (w *osWatcher) handleEvents() { + defer log.OnPanic(fmt.Sprintf("%s: handling events", osWatcherPref)) + + defer close(w.events) + + ch := w.w.Events + for e := range ch { + if e.Op&fsnotify.Write == 0 { + continue + } + + // Skip the following events assuming that sometimes the same event + // occurrs several times. + for ok := true; ok; { + select { + case _, ok = <-ch: + // Go on. + default: + ok = false + } + } + + select { + case w.events <- event{}: + // Go on. + default: + log.Debug("%s: events buffer is full", osWatcherPref) + } + } +} diff --git a/internal/aghos/os.go b/internal/aghos/os.go index 501f7d66..1723e001 100644 --- a/internal/aghos/os.go +++ b/internal/aghos/os.go @@ -7,6 +7,8 @@ import ( "bufio" "fmt" "io" + "io/fs" + "os" "os/exec" "path" "runtime" @@ -159,3 +161,10 @@ ScanLoop: func IsOpenWrt() (ok bool) { return isOpenWrt() } + +// RootDirFS returns the fs.FS rooted at the operating system's root. +func RootDirFS() (fsys fs.FS) { + // Use empty string since os.DirFS implicitly prepends a slash to it. This + // behavior is undocumented but it currently works. + return os.DirFS("") +} diff --git a/internal/aghos/os_linux.go b/internal/aghos/os_linux.go index 349fc18a..ed513b00 100644 --- a/internal/aghos/os_linux.go +++ b/internal/aghos/os_linux.go @@ -26,6 +26,8 @@ func haveAdminRights() (bool, error) { } func isOpenWrt() (ok bool) { + const etcReleasePattern = "etc/*release*" + var err error ok, err = FileWalker(func(r io.Reader) (_ []string, cont bool, err error) { const osNameData = "openwrt" @@ -39,7 +41,7 @@ func isOpenWrt() (ok bool) { } return nil, !stringutil.ContainsFold(string(data), osNameData), nil - }).Walk("/etc/*release*") + }).Walk(RootDirFS(), etcReleasePattern) return err == nil && ok } diff --git a/internal/aghtest/fswatcher.go b/internal/aghtest/fswatcher.go new file mode 100644 index 00000000..0df4470d --- /dev/null +++ b/internal/aghtest/fswatcher.go @@ -0,0 +1,23 @@ +package aghtest + +// FSWatcher is a mock aghos.FSWatcher implementation to use in tests. +type FSWatcher struct { + OnEvents func() (e <-chan struct{}) + OnAdd func(name string) (err error) + OnClose func() (err error) +} + +// Events implements the aghos.FSWatcher interface for *FSWatcher. +func (w *FSWatcher) Events() (e <-chan struct{}) { + return w.OnEvents() +} + +// Add implements the aghos.FSWatcher interface for *FSWatcher. +func (w *FSWatcher) Add(name string) (err error) { + return w.OnAdd(name) +} + +// Close implements the aghos.FSWatcher interface for *FSWatcher. +func (w *FSWatcher) Close() (err error) { + return w.OnClose() +} diff --git a/internal/dnsforward/dnsforward_test.go b/internal/dnsforward/dnsforward_test.go index 397f496e..3ab76a40 100644 --- a/internal/dnsforward/dnsforward_test.go +++ b/internal/dnsforward/dnsforward_test.go @@ -11,9 +11,10 @@ import ( "fmt" "math/big" "net" - "os" "sync" + "sync/atomic" "testing" + "testing/fstest" "time" "github.com/AdguardTeam/AdGuardHome/internal/aghnet" @@ -1057,23 +1058,43 @@ func TestPTRResponseFromDHCPLeases(t *testing.T) { } func TestPTRResponseFromHosts(t *testing.T) { - c := filtering.Config{ - EtcHosts: &aghnet.EtcHostsContainer{}, + // Prepare test hosts file. + + const hostsFilename = "hosts" + + testFS := fstest.MapFS{ + hostsFilename: &fstest.MapFile{Data: []byte(` + 127.0.0.1 host # comment + ::1 localhost#comment + `)}, } - // Prepare test hosts file. - hf, err := os.CreateTemp("", "") + const closeCalled errors.Error = "close method called" + + var eventsCalledCounter uint32 + hc, err := aghnet.NewHostsContainer(testFS, &aghtest.FSWatcher{ + OnEvents: func() (e <-chan struct{}) { + assert.Equal(t, uint32(1), atomic.AddUint32(&eventsCalledCounter, 1)) + + return nil + }, + OnAdd: func(name string) (err error) { + assert.Equal(t, hostsFilename, name) + + return nil + }, + OnClose: func() (err error) { return closeCalled }, + }, hostsFilename) require.NoError(t, err) t.Cleanup(func() { - assert.NoError(t, hf.Close()) - assert.NoError(t, os.Remove(hf.Name())) + assert.Equal(t, uint32(1), atomic.LoadUint32(&eventsCalledCounter)) + + require.ErrorIs(t, hc.Close(), closeCalled) }) - _, _ = hf.WriteString(" 127.0.0.1 host # comment \n") - _, _ = hf.WriteString(" ::1 localhost#comment \n") - - c.EtcHosts.Init(hf.Name()) - t.Cleanup(c.EtcHosts.Close) + c := filtering.Config{ + EtcHosts: hc, + } var snd *aghnet.SubnetDetector snd, err = aghnet.NewSubnetDetector() @@ -1109,7 +1130,7 @@ func TestPTRResponseFromHosts(t *testing.T) { resp, err := dns.Exchange(req, addr.String()) require.NoError(t, err) - require.Len(t, resp.Answer, 1) + require.Lenf(t, resp.Answer, 1, "%#v", resp) assert.Equal(t, dns.TypePTR, resp.Answer[0].Header().Rrtype) assert.Equal(t, "1.0.0.127.in-addr.arpa.", resp.Answer[0].Header().Name) diff --git a/internal/filtering/dnsrewrite.go b/internal/filtering/dnsrewrite.go index 5cefe01d..e98dfa3d 100644 --- a/internal/filtering/dnsrewrite.go +++ b/internal/filtering/dnsrewrite.go @@ -15,9 +15,9 @@ type DNSRewriteResult struct { // the server returns. type DNSRewriteResultResponse map[rules.RRType][]rules.RRValue -// processDNSRewrites processes DNS rewrite rules in dnsr. It returns -// an empty result if dnsr is empty. Otherwise, the result will have -// either CanonName or DNSRewriteResult set. +// processDNSRewrites processes DNS rewrite rules in dnsr. It returns an empty +// result if dnsr is empty. Otherwise, the result will have either CanonName or +// DNSRewriteResult set. func (d *DNSFilter) processDNSRewrites(dnsr []*rules.NetworkRule) (res Result) { if len(dnsr) == 0 { return Result{} diff --git a/internal/filtering/filtering.go b/internal/filtering/filtering.go index 4db69cd2..f7a8ebe4 100644 --- a/internal/filtering/filtering.go +++ b/internal/filtering/filtering.go @@ -73,7 +73,7 @@ type Config struct { // EtcHosts is a container of IP-hostname pairs taken from the operating // system configuration files (e.g. /etc/hosts). - EtcHosts *aghnet.EtcHostsContainer `yaml:"-"` + EtcHosts *aghnet.HostsContainer `yaml:"-"` // Called when the configuration is changed by HTTP request ConfigModified func() `yaml:"-"` @@ -176,8 +176,8 @@ const ( // FilteredBlockedService - the host is blocked by "blocked services" settings FilteredBlockedService - // Rewritten is returned when there was a rewrite by a legacy DNS - // rewrite rule. + // Rewritten is returned when there was a rewrite by a legacy DNS rewrite + // rule. Rewritten // RewrittenAutoHosts is returned when there was a rewrite by autohosts @@ -186,8 +186,8 @@ const ( // RewrittenRule is returned when a $dnsrewrite filter rule was applied. // - // TODO(a.garipov): Remove Rewritten and RewrittenAutoHosts by merging - // their functionality into RewrittenRule. + // TODO(a.garipov): Remove Rewritten and RewrittenAutoHosts by merging their + // functionality into RewrittenRule. // // See https://github.com/AdguardTeam/AdGuardHome/issues/2499. RewrittenRule @@ -371,24 +371,23 @@ type Result struct { // Reason is the reason for blocking or unblocking the request. Reason Reason `json:",omitempty"` - // Rules are applied rules. If Rules are not empty, each rule - // is not nil. + // Rules are applied rules. If Rules are not empty, each rule is not nil. Rules []*ResultRule `json:",omitempty"` - // ReverseHosts is the reverse lookup rewrite result. It is - // empty unless Reason is set to RewrittenAutoHosts. + // ReverseHosts is the reverse lookup rewrite result. It is empty unless + // Reason is set to RewrittenAutoHosts. ReverseHosts []string `json:",omitempty"` - // IPList is the lookup rewrite result. It is empty unless - // Reason is set to RewrittenAutoHosts or Rewritten. + // IPList is the lookup rewrite result. It is empty unless Reason is set to + // RewrittenAutoHosts or Rewritten. IPList []net.IP `json:",omitempty"` - // CanonName is the CNAME value from the lookup rewrite result. - // It is empty unless Reason is set to Rewritten or RewrittenRule. + // CanonName is the CNAME value from the lookup rewrite result. It is empty + // unless Reason is set to Rewritten or RewrittenRule. CanonName string `json:",omitempty"` - // ServiceName is the name of the blocked service. It is empty - // unless Reason is set to FilteredBlockedService. + // ServiceName is the name of the blocked service. It is empty unless + // Reason is set to FilteredBlockedService. ServiceName string `json:",omitempty"` // DNSRewriteResult is the $dnsrewrite filter rule result. @@ -446,43 +445,49 @@ func (d *DNSFilter) CheckHost( return Result{}, nil } -// checkEtcHosts compares the host against our /etc/hosts table. The err is -// always nil, it is only there to make this a valid hostChecker function. -func (d *DNSFilter) checkEtcHosts( - host string, - qtype uint16, - _ *Settings, -) (res Result, err error) { - if d.Config.EtcHosts == nil { +// matchSysHosts tries to match the host against the operating system's hosts +// database. +func (d *DNSFilter) matchSysHosts(host string, qtype uint16, setts *Settings) (res Result, err error) { + if d.EtcHosts == nil { return Result{}, nil } - ips := d.Config.EtcHosts.Process(host, qtype) - if ips != nil { - res = Result{ - Reason: RewrittenAutoHosts, - IPList: ips, - } + dnsres, _ := d.EtcHosts.MatchRequest(urlfilter.DNSRequest{ + Hostname: host, + SortedClientTags: setts.ClientTags, + // TODO(e.burkov): Wait for urlfilter update to pass net.IP. + ClientIP: setts.ClientIP.String(), + ClientName: setts.ClientName, + DNSType: qtype, + }) - return res, nil + dnsr := dnsres.DNSRewrites() + if len(dnsr) == 0 { + return Result{}, nil } - revHosts := d.Config.EtcHosts.ProcessReverse(host, qtype) - if len(revHosts) != 0 { - res = Result{ - Reason: RewrittenAutoHosts, + var ips []net.IP + var revHosts []string + + for _, nr := range dnsr { + dr := nr.DNSRewrite + if dr == nil { + continue } - // TODO(a.garipov): Optimize this with a buffer. - res.ReverseHosts = make([]string, len(revHosts)) - for i := range revHosts { - res.ReverseHosts[i] = revHosts[i] + "." + switch val := nr.DNSRewrite.Value.(type) { + case net.IP: + ips = append(ips, val) + case string: + revHosts = append(revHosts, val) } - - return res, nil } - return Result{}, nil + return Result{ + Reason: RewrittenAutoHosts, + IPList: ips, + ReverseHosts: revHosts, + }, nil } // Process rewrites table @@ -647,15 +652,18 @@ func (d *DNSFilter) initFiltering(allowFilters, blockFilters []Filter) error { return err } - d.engineLock.Lock() - d.reset() - d.rulesStorage = rulesStorage - d.filteringEngine = filteringEngine - d.rulesStorageAllow = rulesStorageAllow - d.filteringEngineAllow = filteringEngineAllow - d.engineLock.Unlock() + func() { + d.engineLock.Lock() + defer d.engineLock.Unlock() - // Make sure that the OS reclaims memory as soon as possible + d.reset() + d.rulesStorage = rulesStorage + d.filteringEngine = filteringEngine + d.rulesStorageAllow = rulesStorageAllow + d.filteringEngineAllow = filteringEngineAllow + }() + + // Make sure that the OS reclaims memory as soon as possible. debug.FreeOSMemory() log.Debug("initialized filtering engine") @@ -734,8 +742,8 @@ func (d *DNSFilter) matchHostProcessDNSResult( } if dnsres.HostRulesV4 != nil || dnsres.HostRulesV6 != nil { - // Question type doesn't match the host rules. Return the first - // matched host rule, but without an IP address. + // Question type doesn't match the host rules. Return the first matched + // host rule, but without an IP address. var matchedRules []rules.Rule if dnsres.HostRulesV4 != nil { matchedRules = []rules.Rule{dnsres.HostRulesV4[0]} @@ -760,11 +768,6 @@ func (d *DNSFilter) matchHost( return Result{}, nil } - d.engineLock.RLock() - // Keep in mind that this lock must be held no just when calling Match() - // but also while using the rules returned by it. - defer d.engineLock.RUnlock() - ureq := urlfilter.DNSRequest{ Hostname: host, SortedClientTags: setts.ClientTags, @@ -774,6 +777,13 @@ func (d *DNSFilter) matchHost( DNSType: qtype, } + d.engineLock.RLock() + // Keep in mind that this lock must be held no just when calling Match() but + // also while using the rules returned by it. + // + // TODO(e.burkov): Inspect if the above is true. + defer d.engineLock.RUnlock() + if d.filteringEngineAllow != nil { dnsres, ok := d.filteringEngineAllow.MatchRequest(ureq) if ok { @@ -791,8 +801,8 @@ func (d *DNSFilter) matchHost( if dnsr := dnsres.DNSRewrites(); len(dnsr) > 0 { res = d.processDNSRewrites(dnsr) if res.Reason == RewrittenRule && res.CanonName == host { - // A rewrite of a host to itself. Go on and try - // matching other things. + // A rewrite of a host to itself. Go on and try matching other + // things. } else { return res, nil } @@ -868,8 +878,8 @@ func New(c *Config, blockFilters []Filter) *DNSFilter { } d.hostCheckers = []hostChecker{{ - check: d.checkEtcHosts, - name: "etchosts", + check: d.matchSysHosts, + name: "hosts container", }, { check: d.matchHost, name: "filtering", diff --git a/internal/home/clients.go b/internal/home/clients.go index 9b660757..85eec9fd 100644 --- a/internal/home/clients.go +++ b/internal/home/clients.go @@ -95,7 +95,9 @@ type clientsContainer struct { // dnsServer is used for checking clients IP status access list status dnsServer *dnsforward.Server - etcHosts *aghnet.EtcHostsContainer // get entries from system hosts-files + // etcHosts contains list of rewrite rules taken from the operating system's + // hosts databse. + etcHosts *aghnet.HostsContainer testing bool // if TRUE, this object is used for internal tests } @@ -106,7 +108,7 @@ type clientsContainer struct { func (clients *clientsContainer) Init( objects []clientObject, dhcpServer *dhcpd.Server, - etcHosts *aghnet.EtcHostsContainer, + etcHosts *aghnet.HostsContainer, ) { if clients.list != nil { log.Fatal("clients.list != nil") @@ -121,13 +123,22 @@ func (clients *clientsContainer) Init( clients.etcHosts = etcHosts clients.addFromConfig(objects) - if !clients.testing { - clients.updateFromDHCP(true) - if clients.dhcpServer != nil { - clients.dhcpServer.SetOnLeaseChanged(clients.onDHCPLeaseChanged) - } - if clients.etcHosts != nil { - clients.etcHosts.SetOnChanged(clients.onHostsChanged) + if clients.testing { + return + } + + clients.updateFromDHCP(true) + if clients.dhcpServer != nil { + clients.dhcpServer.SetOnLeaseChanged(clients.onDHCPLeaseChanged) + } + + go clients.handleHostsUpdates() +} + +func (clients *clientsContainer) handleHostsUpdates() { + if clients.etcHosts != nil { + for upd := range clients.etcHosts.Upd() { + clients.addFromHostsFile(upd) } } } @@ -250,10 +261,6 @@ func (clients *clientsContainer) onDHCPLeaseChanged(flags int) { } } -func (clients *clientsContainer) onHostsChanged() { - clients.addFromHostsFile() -} - // Exists checks if client with this IP address already exists. func (clients *clientsContainer) Exists(ip net.IP, source clientSource) (ok bool) { clients.lock.Lock() @@ -697,7 +704,7 @@ func (clients *clientsContainer) SetWHOISInfo(ip net.IP, wi *RuntimeClientWHOISI log.Debug("clients: set whois info for runtime client with ip %s: %+v", ip, wi) } -// AddHost adds a new IP-hostname pairing. The priorities of the sources is +// AddHost adds a new IP-hostname pairing. The priorities of the sources are // taken into account. ok is true if the pairing was added. func (clients *clientsContainer) AddHost(ip net.IP, host string, src clientSource) (ok bool, err error) { clients.lock.Lock() @@ -757,13 +764,7 @@ func (clients *clientsContainer) rmHostsBySrc(src clientSource) { // addFromHostsFile fills the client-hostname pairing index from the system's // hosts files. -func (clients *clientsContainer) addFromHostsFile() { - if clients.etcHosts == nil { - return - } - - hosts := clients.etcHosts.List() - +func (clients *clientsContainer) addFromHostsFile(hosts *netutil.IPMap) { clients.lock.Lock() defer clients.lock.Unlock() diff --git a/internal/home/filter.go b/internal/home/filter.go index 22bc7435..74f85356 100644 --- a/internal/home/filter.go +++ b/internal/home/filter.go @@ -710,7 +710,6 @@ func enableFilters(async bool) { } func enableFiltersLocked(async bool) { - var whiteFilters []filtering.Filter filters := []filtering.Filter{{ Data: []byte(strings.Join(config.UserRules, "\n")), }} @@ -725,18 +724,20 @@ func enableFiltersLocked(async bool) { FilePath: filter.Path(), }) } + + var allowFilters []filtering.Filter for _, filter := range config.WhitelistFilters { if !filter.Enabled { continue } - whiteFilters = append(whiteFilters, filtering.Filter{ + allowFilters = append(allowFilters, filtering.Filter{ ID: filter.ID, FilePath: filter.Path(), }) } - if err := Context.dnsFilter.SetFilters(filters, whiteFilters, async); err != nil { + if err := Context.dnsFilter.SetFilters(filters, allowFilters, async); err != nil { log.Debug("enabling filters: %s", err) } diff --git a/internal/home/home.go b/internal/home/home.go index 6dceb1fd..c5a6a5e6 100644 --- a/internal/home/home.go +++ b/internal/home/home.go @@ -44,20 +44,22 @@ type homeContext struct { // Modules // -- - clients clientsContainer // per-client-settings module - stats stats.Stats // statistics module - queryLog querylog.QueryLog // query log module - dnsServer *dnsforward.Server // DNS module - rdns *RDNS // rDNS module - whois *WHOIS // WHOIS module - dnsFilter *filtering.DNSFilter // DNS filtering module - dhcpServer *dhcpd.Server // DHCP module - auth *Auth // HTTP authentication module - filters Filtering // DNS filtering module - web *Web // Web (HTTP, HTTPS) module - tls *TLSMod // TLS module - etcHosts *aghnet.EtcHostsContainer // IP-hostname pairs taken from system configuration (e.g. /etc/hosts) files - updater *updater.Updater + clients clientsContainer // per-client-settings module + stats stats.Stats // statistics module + queryLog querylog.QueryLog // query log module + dnsServer *dnsforward.Server // DNS module + rdns *RDNS // rDNS module + whois *WHOIS // WHOIS module + dnsFilter *filtering.DNSFilter // DNS filtering module + dhcpServer *dhcpd.Server // DHCP module + auth *Auth // HTTP authentication module + filters Filtering // DNS filtering module + web *Web // Web (HTTP, HTTPS) module + tls *TLSMod // TLS module + // etcHosts is an IP-hostname pairs set taken from system configuration + // (e.g. /etc/hosts) files. + etcHosts *aghnet.HostsContainer + updater *updater.Updater subnetDetector *aghnet.SubnetDetector @@ -257,8 +259,20 @@ func setupConfig(args options) (err error) { }) if !args.noEtcHosts { - Context.etcHosts = &aghnet.EtcHostsContainer{} - Context.etcHosts.Init("") + var osWritesWatcher aghos.FSWatcher + osWritesWatcher, err = aghos.NewOSWritesWatcher() + if err != nil { + return fmt.Errorf("initing os watcher: %w", err) + } + + Context.etcHosts, err = aghnet.NewHostsContainer( + aghos.RootDirFS(), + osWritesWatcher, + aghnet.DefaultHostsPaths()..., + ) + if err != nil { + return fmt.Errorf("initing hosts container: %w", err) + } } Context.clients.Init(config.Clients, Context.dhcpServer, Context.etcHosts) config.Clients = nil @@ -424,7 +438,6 @@ func run(args options, clientBuildFS fs.FS) { fatalOnError(err) Context.tls.Start() - Context.etcHosts.Start() go func() { serr := startDNSServer() @@ -647,7 +660,11 @@ func cleanup(ctx context.Context) { } } - Context.etcHosts.Close() + if Context.etcHosts != nil { + if err = Context.etcHosts.Close(); err != nil { + log.Error("stopping hosts container: %s", err) + } + } if Context.tls != nil { Context.tls.Close() From 3fa38fb4203986b20a5b4f8d33e3fdc7857c1ca6 Mon Sep 17 00:00:00 2001 From: Ildar Kamalov Date: Fri, 15 Oct 2021 15:01:50 +0300 Subject: [PATCH 004/135] Pull request: 3684 validate client id in the mobileconfig form Closes #3684 Squashed commit of the following: commit 78e9862f7a06262f91c28d6ddcc10512560eedae Author: Ildar Kamalov Date: Fri Oct 15 14:39:36 2021 +0300 fix build commit 3ed4ee69590f238396dd3aab2b62f110baa6d681 Author: Ildar Kamalov Date: Fri Oct 15 13:39:12 2021 +0300 client: validate client id in the mobileconfig form --- .../src/components/ui/Guide/MobileConfigForm.js | 4 ++-- client/src/helpers/constants.js | 2 +- client/src/helpers/validators.js | 15 +++++++++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/client/src/components/ui/Guide/MobileConfigForm.js b/client/src/components/ui/Guide/MobileConfigForm.js index ce9a6942..f726b40c 100644 --- a/client/src/components/ui/Guide/MobileConfigForm.js +++ b/client/src/components/ui/Guide/MobileConfigForm.js @@ -14,7 +14,7 @@ import { toNumber, } from '../../../helpers/form'; import { - validateClientId, + validateConfigClientId, validateServerName, validatePort, validateIsSafePort, @@ -132,7 +132,7 @@ const MobileConfigForm = ({ invalid }) => { component={renderInputField} className="form-control" placeholder={i18next.t('client_id_placeholder')} - validate={validateClientId} + validate={validateConfigClientId} />
diff --git a/client/src/helpers/constants.js b/client/src/helpers/constants.js index f9431cf6..195efdb3 100644 --- a/client/src/helpers/constants.js +++ b/client/src/helpers/constants.js @@ -24,7 +24,7 @@ export const R_UNIX_ABSOLUTE_PATH = /^(\/[^/\x00]+)+$/; // eslint-disable-next-line no-control-regex export const R_WIN_ABSOLUTE_PATH = /^([a-zA-Z]:)?(\\|\/)(?:[^\\/:*?"<>|\x00]+\\)*[^\\/:*?"<>|\x00]*$/; -export const R_CLIENT_ID = /^[a-z0-9-]{1,64}$/; +export const R_CLIENT_ID = /^[a-z0-9-]{1,63}$/; export const HTML_PAGES = { INSTALL: '/install.html', diff --git a/client/src/helpers/validators.js b/client/src/helpers/validators.js index 25a7168d..7075ca47 100644 --- a/client/src/helpers/validators.js +++ b/client/src/helpers/validators.js @@ -83,6 +83,21 @@ export const validateClientId = (value) => { return undefined; }; +/** + * @param value {string} + * @returns {undefined|string} + */ +export const validateConfigClientId = (value) => { + if (!value) { + return undefined; + } + const formattedValue = value.trim(); + if (formattedValue && !R_CLIENT_ID.test(formattedValue)) { + return 'form_error_client_id_format'; + } + return undefined; +}; + /** * @param value {string} * @returns {undefined|string} From 49d67a70b6e813cc220ee03731d792253d6d1ad1 Mon Sep 17 00:00:00 2001 From: bruvv <3063928+bruvv@users.noreply.github.com> Date: Mon, 18 Oct 2021 10:04:24 +0200 Subject: [PATCH 005/135] Cleaned up the list Since SPAM404 is not maintained anymore and is a huge full spam list now of it's own (https://github.com/Spam404/lists/pull/18) it is save to remove it I would say. Also removed X since it is also unmaintained Added Netherlands blocking list --- client/src/helpers/filters/filters.json | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/client/src/helpers/filters/filters.json b/client/src/helpers/filters/filters.json index 6cd61084..419f5253 100644 --- a/client/src/helpers/filters/filters.json +++ b/client/src/helpers/filters/filters.json @@ -60,12 +60,6 @@ "homepage": "https://github.com/crazy-max/WindowsSpyBlocker", "source": "https://raw.githubusercontent.com/crazy-max/WindowsSpyBlocker/master/data/hosts/spy.txt" }, - "spam404": { - "name": "Spam404", - "categoryId": "security", - "homepage": "https://github.com/Spam404/lists", - "source": "https://raw.githubusercontent.com/Spam404/lists/master/main-blacklist.txt" - }, "nocoin-filter-list": { "name": "NoCoin Filter List", "categoryId": "security", @@ -156,11 +150,11 @@ "homepage": "https://github.com/ABPindo/indonesianadblockrules/", "source": "https://raw.githubusercontent.com/ABPindo/indonesianadblockrules/master/subscriptions/abpindo.txt" }, - "barb-block": { - "name": "BarbBlock", - "categoryId": "other", - "homepage": "https://github.com/paulgb/BarbBlock/", - "source": "https://paulgb.github.io/BarbBlock/blacklists/hosts-file.txt" - } + "NLD-Easylist": { + "name": "NLD: Easylist", + "categoryId": "regional", + "homepage": "https://forums.lanik.us/viewforum.php?f=100", + "source": "https://easylist-downloads.adblockplus.org/easylistdutch.txt" + }, } } From b296fa224653c1ae0003709708039a08f40842eb Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Mon, 18 Oct 2021 15:29:29 +0300 Subject: [PATCH 006/135] Pull request: 3744 DNS server DHCP option Merge in DNS/adguard-home from 3744-options-priority to master Updates #3744. Squashed commit of the following: commit 30f1d483bebd92348250573d2edd708247081b45 Author: Eugene Burkov Date: Mon Oct 18 15:22:49 2021 +0300 dhcpd: imp tests more commit 9a8194e2f259ac7a88b23a1480c74decfef587b3 Author: Eugene Burkov Date: Mon Oct 18 15:09:20 2021 +0300 dhcpd: imp tests commit d915e0b407adcfd24df6e28be22f095909749aa3 Author: Eugene Burkov Date: Mon Oct 18 14:46:20 2021 +0300 dhcpd: fix options priority --- CHANGELOG.md | 2 + internal/dhcpd/v4.go | 7 +- internal/dhcpd/v4_test.go | 145 ++++++++++++++++++++++++++++---------- 3 files changed, 113 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b017cf0..d4de38dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -114,6 +114,7 @@ In this release, the schema version has changed from 10 to 12. ### Fixed +- Incorrect assignment of explicitly configured DHCP options ([#3744]). - Occasional panic during shutdown ([#3655]). - Addition of IPs into only one as opposed to all matching ipsets on Linux ([#3638]). @@ -204,6 +205,7 @@ In this release, the schema version has changed from 10 to 12. [#3607]: https://github.com/AdguardTeam/AdGuardHome/issues/3607 [#3638]: https://github.com/AdguardTeam/AdGuardHome/issues/3638 [#3655]: https://github.com/AdguardTeam/AdGuardHome/issues/3655 +[#3744]: https://github.com/AdguardTeam/AdGuardHome/issues/3744 diff --git a/internal/dhcpd/v4.go b/internal/dhcpd/v4.go index d7e4dfae..8ddfe98b 100644 --- a/internal/dhcpd/v4.go +++ b/internal/dhcpd/v4.go @@ -900,9 +900,10 @@ func (s *v4Server) process(req, resp *dhcpv4.DHCPv4) int { resp.UpdateOption(dhcpv4.OptGeneric(code, configured.Get(code))) } } - // Update the value of Domain Name Server option separately from others - // since its value is set after server's creating. - if requested.Has(dhcpv4.OptionDomainNameServer) { + // Update the value of Domain Name Server option separately from others if + // not assigned yet since its value is set after server's creating. + if requested.Has(dhcpv4.OptionDomainNameServer) && + !resp.Options.Has(dhcpv4.OptionDomainNameServer) { resp.UpdateOption(dhcpv4.OptDNS(s.conf.dnsIPAddrs...)) } diff --git a/internal/dhcpd/v4_test.go b/internal/dhcpd/v4_test.go index d20e715c..9bed3c60 100644 --- a/internal/dhcpd/v4_test.go +++ b/internal/dhcpd/v4_test.go @@ -5,8 +5,10 @@ package dhcpd import ( "net" + "strings" "testing" + "github.com/AdguardTeam/golibs/stringutil" "github.com/insomniacslk/dhcp/dhcpv4" "github.com/mdlayher/raw" "github.com/stretchr/testify/assert" @@ -16,17 +18,34 @@ import ( func notify4(flags uint32) { } -func TestV4_AddRemove_static(t *testing.T) { - s, err := v4Create(V4ServerConf{ +// defaultV4ServerConf returns the default configuration for *v4Server to use in +// tests. +func defaultV4ServerConf() (conf V4ServerConf) { + return V4ServerConf{ Enabled: true, RangeStart: net.IP{192, 168, 10, 100}, RangeEnd: net.IP{192, 168, 10, 200}, GatewayIP: net.IP{192, 168, 10, 1}, SubnetMask: net.IP{255, 255, 255, 0}, notify: notify4, - }) + } +} + +// defaultSrv prepares the default DHCPServer to use in tests. The underlying +// type of s is *v4Server. +func defaultSrv(t *testing.T) (s DHCPServer) { + t.Helper() + + var err error + s, err = v4Create(defaultV4ServerConf()) require.NoError(t, err) + return s +} + +func TestV4_AddRemove_static(t *testing.T) { + s := defaultSrv(t) + ls := s.GetLeases(LeasesStatic) assert.Empty(t, ls) @@ -37,7 +56,7 @@ func TestV4_AddRemove_static(t *testing.T) { IP: net.IP{192, 168, 10, 150}, } - err = s.AddStaticLease(l) + err := s.AddStaticLease(l) require.NoError(t, err) err = s.AddStaticLease(l) @@ -65,15 +84,7 @@ func TestV4_AddRemove_static(t *testing.T) { } func TestV4_AddReplace(t *testing.T) { - sIface, err := v4Create(V4ServerConf{ - Enabled: true, - RangeStart: net.IP{192, 168, 10, 100}, - RangeEnd: net.IP{192, 168, 10, 200}, - GatewayIP: net.IP{192, 168, 10, 1}, - SubnetMask: net.IP{255, 255, 255, 0}, - notify: notify4, - }) - require.NoError(t, err) + sIface := defaultSrv(t) s, ok := sIface.(*v4Server) require.True(t, ok) @@ -89,7 +100,7 @@ func TestV4_AddReplace(t *testing.T) { }} for i := range dynLeases { - err = s.addLease(&dynLeases[i]) + err := s.addLease(&dynLeases[i]) require.NoError(t, err) } @@ -104,7 +115,7 @@ func TestV4_AddReplace(t *testing.T) { }} for _, l := range stLeases { - err = s.AddStaticLease(l) + err := s.AddStaticLease(l) require.NoError(t, err) } @@ -118,17 +129,80 @@ func TestV4_AddReplace(t *testing.T) { } } -func TestV4StaticLease_Get(t *testing.T) { - var err error - sIface, err := v4Create(V4ServerConf{ - Enabled: true, - RangeStart: net.IP{192, 168, 10, 100}, - RangeEnd: net.IP{192, 168, 10, 200}, - GatewayIP: net.IP{192, 168, 10, 1}, - SubnetMask: net.IP{255, 255, 255, 0}, - notify: notify4, +func TestV4Server_Process_optionsPriority(t *testing.T) { + defaultIP := net.IP{192, 168, 1, 1} + knownIP := net.IP{1, 2, 3, 4} + + // prepareSrv creates a *v4Server and sets the opt6IPs in the initial + // configuration of the server as the value for DHCP option 6. + prepareSrv := func(t *testing.T, opt6IPs []net.IP) (s *v4Server) { + t.Helper() + + conf := defaultV4ServerConf() + if len(opt6IPs) > 0 { + b := &strings.Builder{} + stringutil.WriteToBuilder(b, "6 ips ", opt6IPs[0].String()) + for _, ip := range opt6IPs[1:] { + stringutil.WriteToBuilder(b, ",", ip.String()) + } + conf.Options = []string{b.String()} + } + + ss, err := v4Create(conf) + require.NoError(t, err) + + var ok bool + s, ok = ss.(*v4Server) + require.True(t, ok) + + s.conf.dnsIPAddrs = []net.IP{defaultIP} + + return s + } + + // checkResp creates a discovery message with DHCP option 6 requested amd + // asserts the response to contain wantIPs in this option. + checkResp := func(t *testing.T, s *v4Server, wantIPs []net.IP) { + t.Helper() + + mac := net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA} + req, err := dhcpv4.NewDiscovery(mac, dhcpv4.WithRequestedOptions( + dhcpv4.OptionDomainNameServer, + )) + require.NoError(t, err) + + var resp *dhcpv4.DHCPv4 + resp, err = dhcpv4.NewReplyFromRequest(req) + require.NoError(t, err) + + res := s.process(req, resp) + require.Equal(t, 1, res) + + o := resp.GetOneOption(dhcpv4.OptionDomainNameServer) + require.NotEmpty(t, o) + + wantData := []byte{} + for _, ip := range wantIPs { + wantData = append(wantData, ip...) + } + assert.Equal(t, o, wantData) + } + + t.Run("default", func(t *testing.T) { + s := prepareSrv(t, nil) + + checkResp(t, s, []net.IP{defaultIP}) }) - require.NoError(t, err) + + t.Run("explicitly_configured", func(t *testing.T) { + s := prepareSrv(t, []net.IP{knownIP, knownIP}) + + checkResp(t, s, []net.IP{knownIP, knownIP}) + }) +} + +func TestV4StaticLease_Get(t *testing.T) { + sIface := defaultSrv(t) s, ok := sIface.(*v4Server) require.True(t, ok) @@ -140,7 +214,7 @@ func TestV4StaticLease_Get(t *testing.T) { HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA}, IP: net.IP{192, 168, 10, 150}, } - err = s.AddStaticLease(l) + err := s.AddStaticLease(l) require.NoError(t, err) var req, resp *dhcpv4.DHCPv4 @@ -208,19 +282,14 @@ func TestV4StaticLease_Get(t *testing.T) { } func TestV4DynamicLease_Get(t *testing.T) { + conf := defaultV4ServerConf() + conf.Options = []string{ + "81 hex 303132", + "82 ip 1.2.3.4", + } + var err error - sIface, err := v4Create(V4ServerConf{ - Enabled: true, - RangeStart: net.IP{192, 168, 10, 100}, - RangeEnd: net.IP{192, 168, 10, 200}, - GatewayIP: net.IP{192, 168, 10, 1}, - SubnetMask: net.IP{255, 255, 255, 0}, - notify: notify4, - Options: []string{ - "81 hex 303132", - "82 ip 1.2.3.4", - }, - }) + sIface, err := v4Create(conf) require.NoError(t, err) s, ok := sIface.(*v4Server) From d7aafa7dc6e89d71b613c28689a1ea5f31e09238 Mon Sep 17 00:00:00 2001 From: Dmitry Seregin Date: Tue, 19 Oct 2021 19:28:18 +0300 Subject: [PATCH 007/135] Pull request #1329: 3529 validate dhcpv4 Merge in DNS/adguard-home from 3529-validate-dhcpv4 to master Squashed commit of the following: commit 2f2455aa13a41398cd2846f31be96da9d34ba95d Author: Dmitriy Seregin Date: Tue Oct 19 19:18:12 2021 +0300 dhcpv4: better test && fix changelog commit ec4ff9180e8390fb739b3be0fc76fd2c715fe691 Author: Dmitriy Seregin Date: Mon Oct 18 19:08:44 2021 +0300 dhcpv4: better tests commit e0e2f27b7a063ed84af170b16c3f87636cb738d2 Author: Dmitriy Seregin Date: Mon Oct 18 18:55:47 2021 +0300 dhcpv4: better tests commit 73e1d08e1265e336ee6339d5021f90883fe3e395 Author: Dmitriy Seregin Date: Mon Oct 18 18:47:21 2021 +0300 dhcpv4: better tests commit f636fc316123f26b6e2930afb4b22c18024ec93d Author: Dmitriy Seregin Date: Mon Oct 18 18:47:07 2021 +0300 all: updated golibs commit 86dd107a1d483ac24bd8c26422324eb8b9c3d086 Merge: 51aaf6d9 b296fa22 Author: Dmitriy Seregin Date: Mon Oct 18 17:18:17 2021 +0300 Merge branch 'master' into 3529-validate-dhcpv4 commit 51aaf6d9eb5fbe2b4304254dc6782305a19c53fa Author: Dmitriy Seregin Date: Mon Oct 18 17:18:02 2021 +0300 dhcpv4: better changelog commit 720b896bb595c57fab6d376f88c8a4b1d131db40 Author: Dmitriy Seregin Date: Mon Oct 18 17:14:25 2021 +0300 dhcpv4: better tests commit 1098beffca8d5feb2ec104d26419210962c9a97d Author: Dmitriy Seregin Date: Mon Oct 18 12:08:26 2021 +0300 dhcp: changelog commit d1f6c89d68657431fb261658133c67e9e3135c1c Author: Dmitriy Seregin Date: Mon Oct 18 12:03:06 2021 +0300 dhcpv4: fixed tests commit 8b6713468fc04321c5238300df90bbb2d67ee679 Merge: 9991e9cb 3fa38fb4 Author: Dmitriy Seregin Date: Mon Oct 18 11:57:57 2021 +0300 Merge branch 'master' into 3529-validate-dhcpv4 commit 9991e9cbee7dc87d8fa1d7e86e6cc7e09ab6938c Author: Dmitriy Seregin Date: Mon Oct 18 11:55:40 2021 +0300 dhcpv4: added tests commit 5798a80de6c060365c1c647326d46cc13ccf28cb Author: Dmitriy Seregin Date: Mon Oct 18 11:46:03 2021 +0300 dhcpv4: validate subnet mask and ip range --- CHANGELOG.md | 3 + client/src/__locales/en.json | 12 +- .../components/Settings/Dhcp/FormDHCPv4.js | 28 ++++- .../Settings/Dhcp/StaticLeases/Form.js | 8 +- .../Settings/Dhcp/StaticLeases/Modal.js | 8 ++ .../Settings/Dhcp/StaticLeases/index.js | 6 + client/src/components/Settings/Dhcp/index.js | 2 + client/src/helpers/helpers.js | 14 +++ client/src/helpers/validators.js | 113 +++++++++++++++++- go.mod | 2 +- go.sum | 4 +- internal/dhcpd/dhcpd_test.go | 44 +++++++ internal/dhcpd/v4.go | 25 ++++ 13 files changed, 258 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4de38dd..99821349 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,8 @@ and this project adheres to ### Changed +- DHCP gateway address, subnet mask, IP address range, and leases validations + ([#3529]). - The `systemd` service script will now create the `/var/log` directory when it doesn't exist ([#3579]). - Items in allowed clients, disallowed clients, and blocked hosts lists are now @@ -196,6 +198,7 @@ In this release, the schema version has changed from 10 to 12. [#3450]: https://github.com/AdguardTeam/AdGuardHome/issues/3450 [#3457]: https://github.com/AdguardTeam/AdGuardHome/issues/3457 [#3506]: https://github.com/AdguardTeam/AdGuardHome/issues/3506 +[#3529]: https://github.com/AdguardTeam/AdGuardHome/issues/3529 [#3538]: https://github.com/AdguardTeam/AdGuardHome/issues/3538 [#3551]: https://github.com/AdguardTeam/AdGuardHome/issues/3551 [#3564]: https://github.com/AdguardTeam/AdGuardHome/issues/3564 diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index f3d8abcd..6db195fe 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -37,6 +37,9 @@ "dhcp_ipv6_settings": "DHCP IPv6 Settings", "form_error_required": "Required field", "form_error_ip4_format": "Invalid IPv4 format", + "form_error_ip4_range_start_format": "Invalid range start IPv4 format", + "form_error_ip4_range_end_format": "Invalid range end IPv4 format", + "form_error_ip4_gateway_format": "Invalid gateway IPv4 format", "form_error_ip6_format": "Invalid IPv6 format", "form_error_ip_format": "Invalid IP format", "form_error_mac_format": "Invalid MAC format", @@ -45,7 +48,14 @@ "form_error_subnet": "Subnet \"{{cidr}}\" does not contain the IP address \"{{ip}}\"", "form_error_positive": "Must be greater than 0", "form_error_negative": "Must be equal to 0 or greater", - "range_end_error": "Must be greater than range start", + "out_of_range_error": "Must be out of range \"{{start}}\"-\"{{end}}\"", + "in_range_error": "Must be in range \"{{start}}\"-\"{{end}}\"", + "lower_range_start_error": "Must be lower than range start", + "lower_range_end_error": "Must be lower than range end", + "greater_range_start_error": "Must be greater than range start", + "greater_range_end_error": "Must be greater than range end", + "subnet_error": "Addresses must be in one subnet", + "gateway_or_subnet_invalid": "Subnet mask invalid", "dhcp_form_gateway_input": "Gateway IP", "dhcp_form_subnet_input": "Subnet mask", "dhcp_form_range_title": "Range of IP addresses", diff --git a/client/src/components/Settings/Dhcp/FormDHCPv4.js b/client/src/components/Settings/Dhcp/FormDHCPv4.js index 873e7696..cb371f9f 100644 --- a/client/src/components/Settings/Dhcp/FormDHCPv4.js +++ b/client/src/components/Settings/Dhcp/FormDHCPv4.js @@ -13,6 +13,9 @@ import { validateIpv4, validateRequiredValue, validateIpv4RangeEnd, + validateGatewaySubnetMask, + validateIpForGatewaySubnetMask, + validateNotInRange, } from '../../../helpers/validators'; const FormDHCPv4 = ({ @@ -54,7 +57,11 @@ const FormDHCPv4 = ({ type="text" className="form-control" placeholder={t(ipv4placeholders.gateway_ip)} - validate={[validateIpv4, validateRequired]} + validate={[ + validateIpv4, + validateRequired, + validateNotInRange, + ]} disabled={!isInterfaceIncludesIpv4} />
@@ -66,7 +73,11 @@ const FormDHCPv4 = ({ type="text" className="form-control" placeholder={t(ipv4placeholders.subnet_mask)} - validate={[validateIpv4, validateRequired]} + validate={[ + validateIpv4, + validateRequired, + validateGatewaySubnetMask, + ]} disabled={!isInterfaceIncludesIpv4} /> @@ -84,7 +95,11 @@ const FormDHCPv4 = ({ type="text" className="form-control" placeholder={t(ipv4placeholders.range_start)} - validate={[validateIpv4]} + validate={[ + validateIpv4, + validateGatewaySubnetMask, + validateIpForGatewaySubnetMask, + ]} disabled={!isInterfaceIncludesIpv4} /> @@ -95,7 +110,12 @@ const FormDHCPv4 = ({ type="text" className="form-control" placeholder={t(ipv4placeholders.range_end)} - validate={[validateIpv4, validateIpv4RangeEnd]} + validate={[ + validateIpv4, + validateIpv4RangeEnd, + validateGatewaySubnetMask, + validateIpForGatewaySubnetMask, + ]} disabled={!isInterfaceIncludesIpv4} /> diff --git a/client/src/components/Settings/Dhcp/StaticLeases/Form.js b/client/src/components/Settings/Dhcp/StaticLeases/Form.js index e857144d..7e9c641b 100644 --- a/client/src/components/Settings/Dhcp/StaticLeases/Form.js +++ b/client/src/components/Settings/Dhcp/StaticLeases/Form.js @@ -10,6 +10,7 @@ import { validateMac, validateRequiredValue, validateIpv4InCidr, + validateInRange, } from '../../../../helpers/validators'; import { FORM_NAME } from '../../../../helpers/constants'; import { toggleLeaseModal } from '../../../../actions'; @@ -53,7 +54,12 @@ const Form = ({ type="text" className="form-control" placeholder={t('form_enter_subnet_ip', { cidr })} - validate={[validateRequiredValue, validateIpv4, validateIpv4InCidr]} + validate={[ + validateRequiredValue, + validateIpv4, + validateIpv4InCidr, + validateInRange, + ]} />
diff --git a/client/src/components/Settings/Dhcp/StaticLeases/Modal.js b/client/src/components/Settings/Dhcp/StaticLeases/Modal.js index b65c298e..8ad0f009 100644 --- a/client/src/components/Settings/Dhcp/StaticLeases/Modal.js +++ b/client/src/components/Settings/Dhcp/StaticLeases/Modal.js @@ -11,6 +11,8 @@ const Modal = ({ handleSubmit, processingAdding, cidr, + rangeStart, + rangeEnd, }) => { const dispatch = useDispatch(); @@ -38,10 +40,14 @@ const Modal = ({ ip: '', hostname: '', cidr, + rangeStart, + rangeEnd, }} onSubmit={handleSubmit} processingAdding={processingAdding} cidr={cidr} + rangeStart={rangeStart} + rangeEnd={rangeEnd} />
@@ -53,6 +59,8 @@ Modal.propTypes = { handleSubmit: PropTypes.func.isRequired, processingAdding: PropTypes.bool.isRequired, cidr: PropTypes.string.isRequired, + rangeStart: PropTypes.string, + rangeEnd: 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 6e12f30e..bdd7cec5 100644 --- a/client/src/components/Settings/Dhcp/StaticLeases/index.js +++ b/client/src/components/Settings/Dhcp/StaticLeases/index.js @@ -22,6 +22,8 @@ const StaticLeases = ({ processingDeleting, staticLeases, cidr, + rangeStart, + rangeEnd, }) => { const [t] = useTranslation(); const dispatch = useDispatch(); @@ -100,6 +102,8 @@ const StaticLeases = ({ handleSubmit={handleSubmit} processingAdding={processingAdding} cidr={cidr} + rangeStart={rangeStart} + rangeEnd={rangeEnd} /> ); @@ -111,6 +115,8 @@ StaticLeases.propTypes = { processingAdding: PropTypes.bool.isRequired, processingDeleting: PropTypes.bool.isRequired, cidr: PropTypes.string.isRequired, + rangeStart: PropTypes.string, + rangeEnd: PropTypes.string, }; cellWrap.propTypes = { diff --git a/client/src/components/Settings/Dhcp/index.js b/client/src/components/Settings/Dhcp/index.js index 844e662e..6208d4a6 100644 --- a/client/src/components/Settings/Dhcp/index.js +++ b/client/src/components/Settings/Dhcp/index.js @@ -275,6 +275,8 @@ const Dhcp = () => { processingAdding={processingAdding} processingDeleting={processingDeleting} cidr={cidr} + rangeStart={dhcp?.values?.v4?.range_start} + rangeEnd={dhcp?.values?.v4?.range_end} />
diff --git a/client/src/helpers/validators.js b/client/src/helpers/validators.js index 4a4125d2..54bf0341 100644 --- a/client/src/helpers/validators.js +++ b/client/src/helpers/validators.js @@ -99,35 +99,6 @@ export const validateNotInRange = (value, allValues) => { return undefined; }; -/** - * @returns {undefined|string} - * @param _ - * @param allValues - */ -export const validateInRange = (value, allValues) => { - const { rangeStart, rangeEnd } = allValues; - - if (rangeStart && validateIpv4(rangeStart)) { - return 'form_error_ip4_range_start_format'; - } - - if (rangeEnd && validateIpv4(rangeEnd)) { - return 'form_error_ip4_range_end_format'; - } - - const isBelowMin = rangeStart && ip4ToInt(value) < ip4ToInt(rangeStart); - const isAboveMax = rangeEnd && ip4ToInt(value) > ip4ToInt(rangeEnd); - - if (isAboveMax || isBelowMin) { - return i18next.t('in_range_error', { - start: rangeStart, - end: rangeEnd, - }); - } - - return undefined; -}; - /** * @returns {undefined|string} * @param _ From c0b14b481103b915c9200b3aea0cf9b5910d2248 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Wed, 3 Nov 2021 14:05:06 +0300 Subject: [PATCH 017/135] Pull request: client: upd i18n Merge in DNS/adguard-home from upd-i18n to master Squashed commit of the following: commit f52a8ab20389f094211039f14bd6f934042c68e1 Author: Ainar Garipov Date: Wed Nov 3 13:58:40 2021 +0300 client: upd i18n --- client/src/__locales/bg.json | 27 ++++++++++++++++++++++++++- client/src/__locales/fa.json | 12 ++++++++---- client/src/__locales/nl.json | 10 +++++----- client/src/__locales/no.json | 1 + client/src/__locales/pt-pt.json | 2 +- client/src/__locales/ru.json | 4 ++-- client/src/__locales/sr-cs.json | 3 +++ client/src/__locales/sv.json | 19 +++++++++++++++++++ client/src/__locales/th.json | 11 ++++++++++- client/src/__locales/zh-tw.json | 6 +++--- 10 files changed, 78 insertions(+), 17 deletions(-) diff --git a/client/src/__locales/bg.json b/client/src/__locales/bg.json index a9a0dde7..458d93a9 100644 --- a/client/src/__locales/bg.json +++ b/client/src/__locales/bg.json @@ -31,6 +31,7 @@ "dashboard": "Табло", "settings": "Настройки", "filters": "Филтри", + "filter": "Филтър", "query_log": "История на заявките", "faq": "ЧЗВ", "version": "версия", @@ -41,6 +42,7 @@ "copyright": "Авторско право", "homepage": "Домашна страница", "report_an_issue": "Съобщи за проблем", + "privacy_policy": "Правила за поверителност", "enable_protection": "Разреши защита", "enabled_protection": "Защитата е разрешена", "disable_protection": "Забрани защита", @@ -70,6 +72,7 @@ "enforce_safe_search": "Включи Безопасно Търсене", "no_servers_specified": "Няма избрани услуги", "general_settings": "Общи настройки", + "custom_filtering_rules": "Местни правила за филтриране", "upstream_dns": "Главен DNS сървър", "test_upstream_btn": "Тествай главния DNS", "apply_btn": "Приложи", @@ -86,6 +89,7 @@ "rules_count_table_header": "Правила общо", "last_time_updated_table_header": "Последно обновен", "actions_table_header": "Действия", + "edit_table_action": "Редактирай", "delete_table_action": "Изтрий", "filters_and_hosts_hint": "AdGuard Home разбира adblock и host синтаксис.", "cancel_btn": "Откажи", @@ -130,6 +134,9 @@ "updated_custom_filtering_toast": "Обновени местни правила за филтриране", "rule_removed_from_custom_filtering_toast": "Премахнато от местни правила за филтриране: {{rule}}", "rule_added_to_custom_filtering_toast": "Добавено до местни правила за филтриране: {{rule}}", + "default": "По подразбиране", + "custom_ip": "Персонализиран IP", + "dns_over_quic": "DNS-over-QUIC", "plain_dns": "Обикновен DNS", "source_label": "Източник", "found_in_known_domain_db": "Намерен в списъците с домейни.", @@ -217,8 +224,26 @@ "form_error_password": "Паролата не съвпада", "reset_settings": "Изтрий всички настройки", "update_announcement": "Има нова AdGuard Home {{version}}! <0>Цъкни тук за повече информация.", - "disable_ipv6": "Изключете IPv6 протокола", + "settings_custom": "Персонализиране", + "table_client": "Клиент", + "table_name": "Име", + "save_btn": "Запази", + "name": "Име", + "clients_not_found": "Нямa намерени адреси", "check_updates_now": "Провери за актуализации", + "domain": "Домейн", + "disabled": "Деактивиран", + "username_label": "Потребител", + "username_placeholder": "Въведете потребител", + "password_label": "Парола", + "password_placeholder": "Въведете парола", + "network": "Мрежа", + "descr": "Описание", "show_blocked_responses": "Блокирано", + "show_whitelisted_responses": "В белия списък", + "show_processed_responses": "Обработен", + "allowed": "В белия списък", + "filter_category_general": "General", + "filter_category_security": "Сигурност", "port_53_faq_link": "Порт 53 често е зает от \"DNSStubListener\" или \"systemd-resolved\" услуги. Моля, прочетете <0>тази инструкция как да решите това." } diff --git a/client/src/__locales/fa.json b/client/src/__locales/fa.json index d880e0cd..20ccaf83 100644 --- a/client/src/__locales/fa.json +++ b/client/src/__locales/fa.json @@ -206,8 +206,10 @@ "custom_ip": "آی پی دستی", "blocking_ipv4": "مسدودسازی IPv4", "blocking_ipv6": "مسدودسازی IPv6", + "dnscrypt": "DNSCrypt", "dns_over_https": "DNS-over-HTTPS", "dns_over_tls": "DNS-over-TLS", + "dns_over_quic": "DNS-over-QUIC", "form_enter_rate_limit": "میزان محدودیت را وارد کنید", "rate_limit": "میزان محدودیت", "edns_enable": "فعالسازی زیرشبکه کلاینت EDNS", @@ -399,6 +401,7 @@ "encryption_key_source_content": "چسباندن محتوای کلید خصوصی", "stats_params": "پیکربندی آمار", "config_successfully_saved": "پیکربندی با موفقیت ذخیره شد", + "interval_6_hour": "6 ساعت", "interval_24_hour": "24 ساعت", "interval_days": "{{value}} روز", "interval_days_plural": "{{count}} روز", @@ -409,7 +412,7 @@ "statistics_configuration": "پیکربندی آمارها", "statistics_retention": "مدت حفظ آمارها", "statistics_retention_desc": "اگر مقدار فاصله را کاهش دهید،برخی داده ها از بین خواهد رفت", - "statistics_clear": " پاکسازی آمار", + "statistics_clear": "بازنشانی آمار", "statistics_clear_confirm": "آیا واقعا میخواهید آمار را پاک کنید؟", "statistics_retention_confirm": "آیا واقعا میخواهید مدت حفظ آمار را تغییر دهید؟ اگر فاصله را کاهش دهید، برخی داده ها حذف میشود", "statistics_cleared": "آمارها با موفقیت حذف شد", @@ -439,8 +442,6 @@ "domain_desc": "نامه دامنه یا علامت تطبیقی را برای بازنویسی وارد کنید.", "example_rewrite_domain": "فقط بازنویسی پاسخ برای این دامنه.", "example_rewrite_wildcard": "بازنویسی پاسخ ها برای همه زیردامنه های <0>example.org.", - "disable_ipv6": "غیرفعالسازی IPv6", - "disable_ipv6_desc": "اگر این ویژگی فعال شده، همه جستارهای DNS برای آدرس های IPv6 (نوع AAAA) رها میشود.", "fastest_addr": "سریعترین آدرس آی پی", "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)", @@ -485,5 +486,8 @@ "rewritten": "بازنویسی شده", "safe_search": "جستجوی اَمن", "blocklist": "لیست سیاه", - "milliseconds_abbreviation": "هـ ثـ" + "milliseconds_abbreviation": "هـ ثـ", + "filter_category_general": "General", + "filter_category_security": "مسدودسازی بدافزار و فیشینگ", + "filter_category_other": "ساير" } diff --git a/client/src/__locales/nl.json b/client/src/__locales/nl.json index cf32d1ed..57bd6ca7 100644 --- a/client/src/__locales/nl.json +++ b/client/src/__locales/nl.json @@ -207,7 +207,7 @@ "example_upstream_doq": "versleutelde <0>DNS-via-QUIC", "example_upstream_sdns": "je kunt <0>DNS Stamps voor <1>DNSCrypt of <2>DNS-via-HTTPS oplossingen gebruiken", "example_upstream_tcp": "standaard DNS (over TCP)", - "all_lists_up_to_date_toast": "Alle lijsten zijn reeds up-to-date", + "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", "dns_test_not_ok_toast": "Server \"{{key}}\": kon niet worden gebruikt, controleer of je het correct hebt geschreven", @@ -378,8 +378,8 @@ "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. Update <0>Encryptie instellingen.", - "topline_expired_certificate": "Jouw SSL certificaat is vervallen. Update <0>Encryptie instellingen.", + "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": "Poort nummer invoeren tussen 80 en 65535", "form_error_port_unsafe": "Dit is een onveilige poort", "form_error_equal": "Mag niet gelijk zijn", @@ -394,7 +394,7 @@ "fix": "Los op", "dns_providers": "hier is een <0>lijst of gekende DNS providers waarvan je kan kiezen.", "update_now": "Update nu", - "update_failed": "Auto-update is mislukt. Volg deze stappen om manueel te updaten.", + "update_failed": "Automatisch bijwerken is mislukt. Volg deze stappen om handmatig bij te werken.", "processing_update": "Even geduld, AdGuard Home wordt bijgewerkt", "clients_title": "Gebruikers", "clients_desc": "Configureer apparaten die gebruik maken van AdGuard Home", @@ -435,7 +435,7 @@ "access_blocked_desc": "Verwar dit niet met filters. AdGuard Home zal deze DNS-zoekopdrachten niet uitvoeren die deze domeinen in de zoekopdracht bevatten. Hier kan je de exacte domeinnamen, wildcards en URL-filter-regels specifiëren, bijv. \"example.org\", \"*.example.org\" of \"||example.org^\".", "access_settings_saved": "Toegangsinstellingen succesvol opgeslagen", "updates_checked": "Met succes op updates gecontroleerd", - "updates_version_equal": "AdGuard Home is up-to-date", + "updates_version_equal": "AdGuard Home is actueel", "check_updates_now": "Controleer op updates", "dns_privacy": "DNS Privacy", "setup_dns_privacy_1": "<0>DNS-via-TLS: Gebruik <1>{{address}} string.", diff --git a/client/src/__locales/no.json b/client/src/__locales/no.json index c91eb2e6..5ab93a6f 100644 --- a/client/src/__locales/no.json +++ b/client/src/__locales/no.json @@ -436,6 +436,7 @@ "encryption_key_source_content": "Lim inn innholdet til den private nøkkelen", "stats_params": "Statistikk-oppsett", "config_successfully_saved": "Oppsettet ble vellykket lagret", + "interval_6_hour": "6 timer", "interval_24_hour": "24 timer", "interval_days": "{{count}} dag", "interval_days_plural": "{{count}} dager", diff --git a/client/src/__locales/pt-pt.json b/client/src/__locales/pt-pt.json index b97b246f..72bd8934 100644 --- a/client/src/__locales/pt-pt.json +++ b/client/src/__locales/pt-pt.json @@ -103,7 +103,7 @@ "enabled_protection": "Ativar proteção", "disable_protection": "Desativar proteção", "disabled_protection": "Desativar proteção", - "refresh_statics": "Repor estatísticas", + "refresh_statics": "Actualizar estatísticas", "dns_query": "Consultas de DNS", "blocked_by": "<0>Bloqueado por filtros", "stats_malware_phishing": "Malware/phishing bloqueados", diff --git a/client/src/__locales/ru.json b/client/src/__locales/ru.json index 221e7a38..931d1ca6 100644 --- a/client/src/__locales/ru.json +++ b/client/src/__locales/ru.json @@ -231,7 +231,7 @@ "no_logs_found": "Логи не найдены", "refresh_btn": "Обновить", "previous_btn": "Назад", - "next_btn": "Вперёд", + "next_btn": "Далее", "loading_table_status": "Загрузка…", "page_table_footer_text": "Страница", "rows_table_footer_text": "строк", @@ -344,7 +344,7 @@ "install_devices_ios_list_3": "Нажмите на название сети, к которой устройство подключено в данный момент.", "install_devices_ios_list_4": "В поле «DNS» введите введите адреса AdGuard Home.", "get_started": "Поехали", - "next": "Дальше", + "next": "Далее", "open_dashboard": "Открыть Панель управления", "install_saved": "Успешно сохранено", "encryption_title": "Шифрование", diff --git a/client/src/__locales/sr-cs.json b/client/src/__locales/sr-cs.json index 6be6e9cc..819e3056 100644 --- a/client/src/__locales/sr-cs.json +++ b/client/src/__locales/sr-cs.json @@ -226,8 +226,10 @@ "custom_ip": "Prilagođeni IP", "blocking_ipv4": "Blokiranje IPv4", "blocking_ipv6": "Blokiranje IPv6", + "dnscrypt": "DNSCrypt", "dns_over_https": "DNS-over-HTTPS", "dns_over_tls": "DNS-over-TLS", + "dns_over_quic": "DNS-over-QUIC", "download_mobileconfig_doh": "Preuzimanja", "download_mobileconfig_dot": "Preuzmi .mobileconfig za DNS-over-TLS", "plain_dns": "Plain DNS", @@ -430,6 +432,7 @@ "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_24_hour": "24 časa", "interval_days": "{{count}} dan", "interval_days_plural": "{{count}} dana", diff --git a/client/src/__locales/sv.json b/client/src/__locales/sv.json index 4f984baa..70f75570 100644 --- a/client/src/__locales/sv.json +++ b/client/src/__locales/sv.json @@ -39,14 +39,18 @@ "delete_confirm": "Är du säker på att du vill ta bort \"{{key}}\"?", "form_enter_hostname": "Skriv in värdnamn", "error_details": "Felinformation", + "request_details": "Förfrågningsdetaljer", + "details": "Detaljer", "back": "Tiilbaka", "dashboard": "Kontrollpanel", "settings": "Inställningar", "filters": "Filter", + "filter": "Filter", "query_log": "Förfrågningslogg", "faq": "FAQ", "version": "version", "address": "Adress", + "protocol": "Protokoll", "on": "PÅ", "off": "AV", "copyright": "Copyright", @@ -85,6 +89,7 @@ "no_servers_specified": "Inga servrar angivna", "general_settings": "Allmänna inställningar", "dns_settings": "DNS-inställningar", + "custom_filtering_rules": "Egna filterregler", "encryption_settings": "Krypteringsinställningar", "dhcp_settings": "DHCP-inställningar", "upstream_dns": "Upstream DNS-servrar", @@ -159,6 +164,12 @@ "query_log_disabled": "Förfrågningsloggen är avaktiverad och kan konfigureras i <0>inställningar", "query_log_strict_search": "Använd dubbla citattecken för strikt sökning", "query_log_retention_confirm": "Är du säker på att du vill ändra förfrågningsloggars retentionstid? Om du minskar intervallet kommer viss data att gå förlorad", + "default": "Standard", + "custom_ip": "Eget IP", + "dnscrypt": "DNSCrypt", + "dns_over_https": "DNS-over-HTTPS", + "dns_over_tls": "DNS-over-TLS", + "dns_over_quic": "DNS-over-QUIC", "source_label": "Källa", "found_in_known_domain_db": "Hittad i domändatabas.", "category_label": "Kategori", @@ -333,12 +344,20 @@ "location": "Plats", "orgname": "Organisationsnamn", "netname": "Nätverksnamn", + "network": "Nätverk", "descr": "Beskrivning", "whois": "Whois", "filtering_rules_learn_more": "<0>Mer info om att skapa dina egna blockeringslistor för värdar.", "try_again": "Försök igen", "show_blocked_responses": "Blockerade", + "show_whitelisted_responses": "Vitlistade", + "show_processed_responses": "Utförda", "blocked_adult_websites": "Blockerade vuxensajter", "blocked_threats": "Blockerade hot", + "allowed": "Vitlistade", + "safe_search": "Säker surf", + "filter_category_general": "General", + "filter_category_security": "säkerhet", + "filter_category_other": "Annat", "use_saved_key": "Använd den tidigare sparade nyckeln" } diff --git a/client/src/__locales/th.json b/client/src/__locales/th.json index 720b7959..14e69757 100644 --- a/client/src/__locales/th.json +++ b/client/src/__locales/th.json @@ -41,6 +41,7 @@ "delete_confirm": "คุณแน่ใจหรือว่าต้องการลบ \"{{key}}\"?", "form_enter_hostname": "ป้อนชื่อโฮสต์", "error_details": "รายละเอียดข้อผิดพลาด", + "request_details": "ขอรายละเอียด", "back": "กลับ", "dashboard": "แผงควบคุม", "settings": "การตั้งค่า", @@ -87,6 +88,7 @@ "no_servers_specified": "ไม่ได้ระบุเซิร์ฟเวอร์", "general_settings": "การตั้งค่าทั่วไป", "dns_settings": "การตั้งค่า DNS", + "custom_filtering_rules": "กฎการกรองที่กำหนดเอง", "encryption_settings": "การตั้งค่าการเข้ารหัส", "dhcp_settings": "การตั้งค่า DHCP", "upstream_dns": "เซิร์ฟเวอร์ DNS ต้นทาง", @@ -169,6 +171,9 @@ "custom_ip": "IP กำหนดเอง", "blocking_ipv4": "ปิดกั้น IPv4", "blocking_ipv6": "ปิดกั้น IPv6", + "dnscrypt": "DNSCrypt", + "dns_over_https": "DNS-over-HTTPS", + "dns_over_tls": "DNS-over-TLS", "form_enter_rate_limit": "ป้อนขีดจำกัดอัตรา", "rate_limit": "จำกัดอัตรา", "edns_enable": "เปิดใช้งานซับเน็ตไคลเอ็นต์ EDNS", @@ -333,6 +338,7 @@ "encryption_key_source_content": "วางเนื้อหาคีย์ส่วนตัว", "stats_params": "การกำหนดค่าสถิติ", "config_successfully_saved": "บันทึกการตั้งค่าเรีบยร้อยแล้ว", + "interval_6_hour": "6 ชั่วโมง", "interval_24_hour": "24 ชั่วโมง", "interval_days": "{{count}} วัน", "interval_days_plural": "{{count}} วัน", @@ -383,5 +389,8 @@ "form_select_tags": "เลือกแท็กเครื่อง", "check_title": "ตรวจสอบการกรอง", "check_desc": "ตรวจสอบว่าชื่อโฮสต์ถูกกรอง", - "form_enter_host": "ป้อนชื่อโฮสต์" + "form_enter_host": "ป้อนชื่อโฮสต์", + "show_processed_responses": "การประมวลผล", + "safe_search": "ค้นหาอย่างปลอดภัย", + "filter_category_other": "อื่น ๆ" } diff --git a/client/src/__locales/zh-tw.json b/client/src/__locales/zh-tw.json index 24f0e5a4..108cb666 100644 --- a/client/src/__locales/zh-tw.json +++ b/client/src/__locales/zh-tw.json @@ -215,8 +215,8 @@ "block": "封鎖", "disallow_this_client": "不允許此用戶端", "allow_this_client": "允許此用戶端", - "block_for_this_client_only": "僅封鎖此用戶端", - "unblock_for_this_client_only": "僅解除封鎖此用戶端", + "block_for_this_client_only": "僅對此用戶端封鎖", + "unblock_for_this_client_only": "僅對此用戶端解除封鎖", "time_table_header": "時間", "date": "日期", "domain_name_table_header": "域名", @@ -529,7 +529,7 @@ "blocked_by_cname_or_ip": "被正規名稱(CNAME)或 IP 封鎖", "try_again": "再次嘗試", "domain_desc": "輸入您想要被改寫的域名或萬用字元(wildcard)。", - "example_rewrite_domain": "僅對於此域名改寫回應。", + "example_rewrite_domain": "僅對此域名改寫回應。", "example_rewrite_wildcard": "對於所有的 <0>example.org 子網域改寫回應。", "rewrite_ip_address": "IP 位址:在一個 A 或 AAAA 回應中使用此 IP", "rewrite_domain_name": "域名:新增一筆正規名稱(CNAME)記錄", From b0b2eb3741898f64a0ad0724fa1fbc0625fe660c Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Mon, 8 Nov 2021 18:35:49 +0300 Subject: [PATCH 018/135] Pull request: client: imp en locale Merge in DNS/adguard-home from imp-i18n to master Squashed commit of the following: commit cc5dfc8f7cdfdc8b530e284f38b851ad316d765a Author: Ainar Garipov Date: Mon Nov 8 18:25:08 2021 +0300 client: imp en locale --- client/src/__locales/en.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index 070f1afa..7107418a 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -36,14 +36,14 @@ "dhcp_ipv4_settings": "DHCP IPv4 Settings", "dhcp_ipv6_settings": "DHCP IPv6 Settings", "form_error_required": "Required field", - "form_error_ip4_format": "Invalid IPv4 format", - "form_error_ip4_range_start_format": "Invalid range start IPv4 format", - "form_error_ip4_range_end_format": "Invalid range end IPv4 format", - "form_error_ip4_gateway_format": "Invalid gateway IPv4 format", - "form_error_ip6_format": "Invalid IPv6 format", - "form_error_ip_format": "Invalid IP format", - "form_error_mac_format": "Invalid MAC format", - "form_error_client_id_format": "Invalid client ID format", + "form_error_ip4_format": "Invalid IPv4 address", + "form_error_ip4_range_start_format": "Invalid IPv4 address of the range start", + "form_error_ip4_range_end_format": "Invalid IPv4 address of the range end", + "form_error_ip4_gateway_format": "Invalid IPv4 address of the gateway", + "form_error_ip6_format": "Invalid IPv6 address", + "form_error_ip_format": "Invalid IP address", + "form_error_mac_format": "Invalid MAC address", + "form_error_client_id_format": "Invalid client ID", "form_error_server_name": "Invalid server name", "form_error_subnet": "Subnet \"{{cidr}}\" does not contain the IP address \"{{ip}}\"", "form_error_positive": "Must be greater than 0", From 6fd9e72fbb47c6ebd517e91703752daa31081b05 Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Tue, 9 Nov 2021 17:17:57 +0300 Subject: [PATCH 019/135] Pull request: 3823 fix rotation check Merge in DNS/adguard-home from 3823-log-rotation to master Closes #3823. Squashed commit of the following: commit 4075c6994ec71210fa38b3e05021149e0fa13841 Author: Eugene Burkov Date: Tue Nov 9 18:27:09 2021 +0500 querylog: fix rotation check --- internal/querylog/querylogfile.go | 70 ++++++++++++++++++------------- 1 file changed, 41 insertions(+), 29 deletions(-) diff --git a/internal/querylog/querylogfile.go b/internal/querylog/querylogfile.go index a1ad0bf5..f46e15cd 100644 --- a/internal/querylog/querylogfile.go +++ b/internal/querylog/querylogfile.go @@ -9,7 +9,6 @@ import ( "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/log" - "github.com/AdguardTeam/golibs/timeutil" ) // flushLogBuffer flushes the current buffer to file and resets the current buffer @@ -136,36 +135,49 @@ func (l *queryLog) readFileFirstTimeValue() (first time.Time, err error) { func (l *queryLog) periodicRotate() { defer log.OnPanic("querylog: rotating") - rotations := time.NewTicker(1 * timeutil.Day) + l.checkAndRotate() + + // rotationCheckIvl is the period of time between checking the need for + // rotating log files. It's smaller of any available rotation interval to + // increase time accuracy. + // + // See https://github.com/AdguardTeam/AdGuardHome/issues/3823. + const rotationCheckIvl = 1 * time.Hour + + rotations := time.NewTicker(rotationCheckIvl) defer rotations.Stop() for range rotations.C { - oldest, err := l.readFileFirstTimeValue() - if err != nil && !errors.Is(err, os.ErrNotExist) { - log.Error("querylog: reading oldest record for rotation: %s", err) - - continue - } - - rot := oldest.Add(l.conf.RotationIvl) - now := time.Now() - if rot.After(time.Now()) { - log.Debug( - "querylog: %s <= %s, not rotating", - now.Format(time.RFC3339), - rot.Format(time.RFC3339), - ) - - continue - } - - err = l.rotate() - if err != nil { - log.Error("querylog: rotating: %s", err) - - continue - } - - log.Debug("querylog: rotated successfully") + l.checkAndRotate() } } + +// checkAndRotate rotates log files if those are older than the specified +// rotation interval. +func (l *queryLog) checkAndRotate() { + oldest, err := l.readFileFirstTimeValue() + if err != nil && !errors.Is(err, os.ErrNotExist) { + log.Error("querylog: reading oldest record for rotation: %s", err) + + return + } + + if rot, now := oldest.Add(l.conf.RotationIvl), time.Now(); rot.After(now) { + log.Debug( + "querylog: %s <= %s, not rotating", + now.Format(time.RFC3339), + rot.Format(time.RFC3339), + ) + + return + } + + err = l.rotate() + if err != nil { + log.Error("querylog: rotating: %s", err) + + return + } + + log.Debug("querylog: rotated successfully") +} From 884a98501da14dd4be79948f30738fb37458a712 Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Thu, 11 Nov 2021 16:19:33 +0300 Subject: [PATCH 020/135] Pull request: 3371 pipe-tailed rules Merge in DNS/adguard-home from 3371-rules-validation to master Updates #3371. Squashed commit of the following: commit 7881a0bc788f130eaed27ea9306309dea52f62e7 Author: Eugene Burkov Date: Thu Nov 11 15:06:42 2021 +0300 all: imp code, docs commit 613775a4bc3e75ca7792fb6896e161f3ef6b1a29 Author: Eugene Burkov Date: Tue Nov 2 16:50:43 2021 +0300 all: upd urlfilter --- CHANGELOG.md | 2 ++ go.mod | 4 ++-- go.sum | 29 +++++++++++++---------- internal/aghnet/hostscontainer.go | 8 +++---- internal/aghnet/hostscontainer_test.go | 32 ++++++++++++++++++-------- internal/dnsforward/dns.go | 12 ++++------ internal/filtering/filtering.go | 13 ++++++++--- 7 files changed, 63 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd40945e..b090aad5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -121,6 +121,7 @@ In this release, the schema version has changed from 10 to 12. ### Fixed +- 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]). - Addition of IPs into only one as opposed to all matching ipsets on Linux @@ -195,6 +196,7 @@ In this release, the schema version has changed from 10 to 12. [#3335]: https://github.com/AdguardTeam/AdGuardHome/issues/3335 [#3343]: https://github.com/AdguardTeam/AdGuardHome/issues/3343 [#3351]: https://github.com/AdguardTeam/AdGuardHome/issues/3351 +[#3371]: https://github.com/AdguardTeam/AdGuardHome/issues/3371 [#3372]: https://github.com/AdguardTeam/AdGuardHome/issues/3372 [#3417]: https://github.com/AdguardTeam/AdGuardHome/issues/3417 [#3419]: https://github.com/AdguardTeam/AdGuardHome/issues/3419 diff --git a/go.mod b/go.mod index 36e90cd5..7c032047 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.16 require ( github.com/AdguardTeam/dnsproxy v0.39.9 github.com/AdguardTeam/golibs v0.10.2 - github.com/AdguardTeam/urlfilter v0.14.6 + github.com/AdguardTeam/urlfilter v0.15.0 github.com/NYTimes/gziphandler v1.1.1 github.com/ameshkov/dnscrypt/v2 v2.2.2 github.com/digineo/go-ipset/v2 v2.2.1 @@ -28,7 +28,7 @@ require ( go.etcd.io/bbolt v1.3.6 golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 golang.org/x/net v0.0.0-20210929193557-e81a3d93ecf6 - golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e + golang.org/x/sys v0.0.0-20210909193231-528a39cd75f3 gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/yaml.v2 v2.4.0 howett.net/plist v0.0.0-20201203080718-1454fab16a06 diff --git a/go.sum b/go.sum index 4f41011f..6db8fa82 100644 --- a/go.sum +++ b/go.sum @@ -17,14 +17,14 @@ github.com/AdguardTeam/golibs v0.9.2/go.mod h1:fCAMwPBJ8S7YMYbTWvYS+eeTLblP5E04I github.com/AdguardTeam/golibs v0.10.2 h1:TAwnS4Y49sSUa4UX1yz/MWNGbIlXHqafrWr9MxdIh9A= github.com/AdguardTeam/golibs v0.10.2/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw= github.com/AdguardTeam/gomitmproxy v0.2.0/go.mod h1:Qdv0Mktnzer5zpdpi5rAwixNJzW2FN91LjKJCkVbYGU= -github.com/AdguardTeam/urlfilter v0.14.6 h1:emqoKZElooHACYehRBYENeKVN1a/rspxiqTIMYLuoIo= -github.com/AdguardTeam/urlfilter v0.14.6/go.mod h1:klx4JbOfc4EaNb5lWLqOwfg+pVcyRukmoJRvO55lL5U= +github.com/AdguardTeam/urlfilter v0.15.0 h1:K3WWZE0K5nPTHe2l+TRXDFpYWJJnvkHdlWidt6NQUTk= +github.com/AdguardTeam/urlfilter v0.15.0/go.mod h1:EwXwrYhowP7bedqmOrmKKmQtpBYFyDNEBFQ+lxdUgQU= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= -github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= -github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= +github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY= 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= @@ -60,8 +60,8 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4 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= -github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= -github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= +github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ping/ping v0.0.0-20210506233800-ff8be3320020 h1:mdi6AbCEoKCA1xKCmp7UtRB5fvGFlP92PvlhxgdvXEw= github.com/go-ping/ping v0.0.0-20210506233800-ff8be3320020/go.mod h1:KmHOjTUmJh/l04ukqPoBWPEZr9jwN05h5NXQl5C+DyY= github.com/go-test/deep v1.0.5 h1:AKODKU3pDH1RzZzm6YZu77YWtEAq6uh1rLIAQlay2qc= @@ -109,7 +109,6 @@ github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8 github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis= 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/joomcode/errorx v1.0.1/go.mod h1:kgco15ekB6cs+4Xjzo7SPeXzx38PbJzBwbnu9qfVNHQ= github.com/joomcode/errorx v1.0.3 h1:3e1mi0u7/HTPNdg6d6DYyKGBhA5l9XpsfuVE29NxnWw= github.com/joomcode/errorx v1.0.3/go.mod h1:eQzdtdlNyN7etw6YCS4W4+lu442waxZYw5yvz0ULrRo= github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 h1:uhL5Gw7BINiiPAo24A2sxkcDI0Jt/sqp1v5xQCniEFA= @@ -170,7 +169,6 @@ github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZ github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf h1:InctQoB89TIkmgIFQeIL4KXNvWc1iebQXdZggqPSwL8= github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= -github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.40/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg= github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= @@ -205,8 +203,8 @@ github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/shirou/gopsutil v2.20.3+incompatible h1:0JVooMPsT7A7HqEYdydp/OfjSOYSjhXV7w1hkKj/NPQ= -github.com/shirou/gopsutil v2.20.3+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shirou/gopsutil/v3 v3.21.8 h1:nKct+uP0TV8DjjNiHanKf8SAuub+GNsbrOtM9Nl9biA= +github.com/shirou/gopsutil/v3 v3.21.8/go.mod h1:YWp/H8Qs5fVmf17v7JNZzA0mPJ+mS2e9JdiUF9LlKzQ= github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= @@ -246,6 +244,10 @@ github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cb github.com/ti-mo/netfilter v0.2.0/go.mod h1:8GbBGsY/8fxtyIdfwy29JiluNcPK4K7wIT+x42ipqUU= github.com/ti-mo/netfilter v0.4.0 h1:rTN1nBYULDmMfDeBHZpKuNKX/bWEXQUhe02a/10orzg= github.com/ti-mo/netfilter v0.4.0/go.mod h1:V54q75mUx8CNA2JnFl+wv9iZ5+JP9nCcRlaFS5OZSRM= +github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo= +github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs= +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/u-root v7.0.0+incompatible h1:u+KSS04pSxJGI5E7WE4Bs9+Zd75QjFv+REkjy/aoAc8= github.com/u-root/u-root v7.0.0+incompatible/go.mod h1:RYkpo8pTHrNjW08opNd/U6p/RJE7K0D8fXO0d47+3YY= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= @@ -303,6 +305,7 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v 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-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210908191846-a5e095526f91/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210929193557-e81a3d93ecf6 h1:Z04ewVs7JhXaYkmDhBERPi41gnltfQpMWDnTnQbaCqk= golang.org/x/net v0.0.0-20210929193557-e81a3d93ecf6/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -330,6 +333,7 @@ golang.org/x/sys v0.0.0-20190418153312-f0ce4c0180be/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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= @@ -359,8 +363,9 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w 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-20210831042530-f4d43177bf5e h1:XMgFehsDnnLGtjvjOfqWSUzt0alpTR1RSEuznObga2c= -golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/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-20210909193231-528a39cd75f3 h1:3Ad41xy2WCESpufXwgs7NpDSu+vjxqLt2UFqUV+20bI= +golang.org/x/sys v0.0.0-20210909193231-528a39cd75f3/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.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/internal/aghnet/hostscontainer.go b/internal/aghnet/hostscontainer.go index c0e12a7b..852bf299 100644 --- a/internal/aghnet/hostscontainer.go +++ b/internal/aghnet/hostscontainer.go @@ -112,16 +112,16 @@ func NewHostsContainer( } // MatchRequest is the request processing method to resolve hostnames and -// addresses from the operating system's hosts files. Any request not of A/AAAA -// or PTR type will return with an empty result. It's safe for concurrent use. +// addresses from the operating system's hosts files. res is nil for any +// request having not an A/AAAA or PTR type. It's safe for concurrent use. func (hc *HostsContainer) MatchRequest( req urlfilter.DNSRequest, -) (res urlfilter.DNSResult, ok bool) { +) (res *urlfilter.DNSResult, ok bool) { switch req.DNSType { case dns.TypeA, dns.TypeAAAA, dns.TypePTR: log.Debug("%s: handling the request", hostsContainerPref) default: - return urlfilter.DNSResult{}, false + return nil, false } hc.engLock.RLock() diff --git a/internal/aghnet/hostscontainer_test.go b/internal/aghnet/hostscontainer_test.go index ce137c87..213f4e7b 100644 --- a/internal/aghnet/hostscontainer_test.go +++ b/internal/aghnet/hostscontainer_test.go @@ -256,39 +256,42 @@ func TestHostsContainer_MatchRequest(t *testing.T) { testCase := []struct { name string - want interface{} + want []interface{} req urlfilter.DNSRequest }{{ name: "a", - want: ip4.To16(), + want: []interface{}{ip4.To16()}, req: urlfilter.DNSRequest{ Hostname: hostname4, DNSType: dns.TypeA, }, }, { name: "aaaa", - want: ip6, + want: []interface{}{ip6}, req: urlfilter.DNSRequest{ Hostname: hostname6, - DNSType: dns.TypeA, + DNSType: dns.TypeAAAA, }, }, { name: "ptr", - want: dns.Fqdn(hostname4), + want: []interface{}{ + dns.Fqdn(hostname4), + dns.Fqdn(hostname4a), + }, req: urlfilter.DNSRequest{ Hostname: reversed4, DNSType: dns.TypePTR, }, }, { name: "ptr_v6", - want: dns.Fqdn(hostname6), + want: []interface{}{dns.Fqdn(hostname6)}, req: urlfilter.DNSRequest{ Hostname: reversed6, DNSType: dns.TypePTR, }, }, { name: "a_alias", - want: ip4.To16(), + want: []interface{}{ip4.To16()}, req: urlfilter.DNSRequest{ Hostname: hostname4a, DNSType: dns.TypeA, @@ -299,8 +302,19 @@ func TestHostsContainer_MatchRequest(t *testing.T) { t.Run(tc.name, func(t *testing.T) { res, ok := hc.MatchRequest(tc.req) require.False(t, ok) + require.NotNil(t, res) - assert.Equal(t, tc.want, res.DNSRewrites()[0].DNSRewrite.Value) + rws := res.DNSRewrites() + require.Len(t, rws, len(tc.want)) + + for i, w := range tc.want { + require.NotNil(t, rws[i]) + + rw := rws[i].DNSRewrite + require.NotNil(t, rw) + + assert.Equal(t, w, rw.Value) + } }) } @@ -311,7 +325,7 @@ func TestHostsContainer_MatchRequest(t *testing.T) { }) require.False(t, ok) - assert.Empty(t, res) + assert.Nil(t, res) }) } diff --git a/internal/dnsforward/dns.go b/internal/dnsforward/dns.go index a0aa4cb1..204995fb 100644 --- a/internal/dnsforward/dns.go +++ b/internal/dnsforward/dns.go @@ -341,14 +341,12 @@ 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 !ctx.isLocalClient { - log.Debug("dns: %q requests for internal ip", d.Addr) - d.Res = s.genNXDomain(req) + if s.subnetDetector.IsLocallyServedNetwork(ip) && !ctx.isLocalClient { + log.Debug("dns: %q requests for internal ip", d.Addr) + d.Res = s.genNXDomain(req) - // Do not even put into query log. - return resultCodeFinish - } + // Do not even put into query log. + return resultCodeFinish } // Do not perform unreversing ever again. diff --git a/internal/filtering/filtering.go b/internal/filtering/filtering.go index 87d0da15..defd9e2f 100644 --- a/internal/filtering/filtering.go +++ b/internal/filtering/filtering.go @@ -451,7 +451,11 @@ func (d *DNSFilter) CheckHost( // matchSysHosts tries to match the host against the operating system's hosts // database. -func (d *DNSFilter) matchSysHosts(host string, qtype uint16, setts *Settings) (res Result, err error) { +func (d *DNSFilter) matchSysHosts( + host string, + qtype uint16, + setts *Settings, +) (res Result, err error) { if !setts.FilteringEnabled || d.EtcHosts == nil { return Result{}, nil } @@ -464,6 +468,9 @@ func (d *DNSFilter) matchSysHosts(host string, qtype uint16, setts *Settings) (r ClientName: setts.ClientName, DNSType: qtype, }) + if dnsres == nil { + return Result{}, nil + } dnsr := dnsres.DNSRewrites() if len(dnsr) == 0 { @@ -695,7 +702,7 @@ func hostRulesToRules(netRules []*rules.HostRule) (res []rules.Rule) { // matching. func (d *DNSFilter) matchHostProcessAllowList( host string, - dnsres urlfilter.DNSResult, + dnsres *urlfilter.DNSResult, ) (res Result, err error) { var matchedRules []rules.Rule if dnsres.NetworkRule != nil { @@ -718,7 +725,7 @@ func (d *DNSFilter) matchHostProcessAllowList( // matchHostProcessDNSResult processes the matched DNS filtering result. func (d *DNSFilter) matchHostProcessDNSResult( qtype uint16, - dnsres urlfilter.DNSResult, + dnsres *urlfilter.DNSResult, ) (res Result) { if dnsres.NetworkRule != nil { reason := FilteredBlockList From 4f257a1cfcd2b7f45eb98e955bb0f69656d5bcec Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Mon, 15 Nov 2021 14:35:46 +0300 Subject: [PATCH 021/135] Pull request: client: add fi, uk locales Merge in DNS/adguard-home from add-fi-uk to master Squashed commit of the following: commit eb293912036ddb4f209827f3e3f87e849c402c6c Author: Ainar Garipov Date: Mon Nov 15 14:26:35 2021 +0300 client: fix locale selection commit 077b7ede31dd6ec0a154d38b32d40a3dd39ba383 Author: Ainar Garipov Date: Mon Nov 15 14:10:55 2021 +0300 client: add fi, uk locales --- .twosky.json | 2 + CHANGELOG.md | 1 + client/src/__locales/fi.json | 628 +++++++++++++++++++++++++++++++++++ client/src/__locales/uk.json | 628 +++++++++++++++++++++++++++++++++++ client/src/i18n.js | 140 +++----- internal/home/i18n.go | 4 +- 6 files changed, 1300 insertions(+), 103 deletions(-) create mode 100644 client/src/__locales/fi.json create mode 100644 client/src/__locales/uk.json diff --git a/.twosky.json b/.twosky.json index db2e0265..244df6a9 100644 --- a/.twosky.json +++ b/.twosky.json @@ -12,6 +12,7 @@ "en": "English", "es": "Español", "fa": "فارسی", + "fi": "Suomi", "fr": "Français", "hr": "Hrvatski", "hu": "Magyar", @@ -33,6 +34,7 @@ "sv": "Svenska", "th": "ภาษาไทย", "tr": "Türkçe", + "uk": "Українська", "vi": "Tiếng Việt", "zh-cn": "简体中文", "zh-hk": "繁體中文(香港)", diff --git a/CHANGELOG.md b/CHANGELOG.md index b090aad5..eed5f0f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to ### Added +- Finnish and Ukrainian translations. - Setting the timeout for IP address pinging in the "Fastest IP address" mode through the new `fastest_timeout` field in the configuration file ([#1992]). - Static IP address detection on FreeBSD ([#3289]). diff --git a/client/src/__locales/fi.json b/client/src/__locales/fi.json new file mode 100644 index 00000000..d6f9ce5b --- /dev/null +++ b/client/src/__locales/fi.json @@ -0,0 +1,628 @@ +{ + "client_settings": "Päätelaiteasetukset", + "example_upstream_reserved": "voit määrittää DNS-ylävirran <0>tietyille verkkotunnuksille", + "example_upstream_comment": "voit määrittää kommentin", + "upstream_parallel": "Käytä rinnakkaisia pyyntöjä ja nopeuta selvitystä käyttämällä kaikkia ylävirran palvelimia samanaikaisesti.", + "parallel_requests": "Rinnakkaiset pyynnöt", + "load_balancing": "Kuormantasaus", + "load_balancing_desc": "Lähetä pyyntö yhdelle ylävirran palvelimelle kerrallaan. AdGuard Home pyrkii valitsemaan nopeimman palvelimen painotetun satunnaisalgoritminsa avulla.", + "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_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", + "resolve_clients_title": "Käytä päätelaitteiden IP-osoitteille käänteistä selvitystä", + "resolve_clients_desc": "Selvitä päätelaitteiden IP-osoitteiden isäntänimet käänteisesti lähettämällä PTR-kyselyt sopiville resolvereille (yksityiset DNS-palvelimet paikallisille päätelaitteille, lähtevät palvelimet päätelaitteille, joilla on julkiset IP-osoitteet).", + "use_private_ptr_resolvers_title": "Käytä yksityisiä käänteisiä DNS-resolvereita", + "use_private_ptr_resolvers_desc": "Suorita käänteiset DNS-selvitykset paikallisesti tarjotuille osoitteille käyttäen näitä ylävirran palvelimia. Jos ei käytössä, vastaa AdGuard Home kaikkiin sen tyyppisiin PTR-pyyntöihin NXDOMAIN-arvolla, pois lukien DHCP, /etc/hosts, yms. -tiedoista tunnistettut päätelaitteet.", + "check_dhcp_servers": "Etsi DHCP-palvelimia", + "save_config": "Tallenna asetukset", + "enabled_dhcp": "DHCP-palvelin otettiin käyttöön", + "disabled_dhcp": "DHCP-palvelin poistettiin käytöstä", + "unavailable_dhcp": "DHCP ei ole käytettävissä", + "unavailable_dhcp_desc": "AdGuard Home ei voi suorittaa DHCP-palvelinta käyttöjärjestelmässäsi", + "dhcp_title": "DHCP-palvelin (kokeellinen!)", + "dhcp_description": "Jos reitittimessäsi ei ole DHCP-asetuksia, voit käyttää AdGuard Homen omaa sisäänrakennettua DHCP-palvelinta.", + "dhcp_enable": "Ota DHCP-palvelin käyttöön", + "dhcp_disable": "Poista DHCP-palvelin käytöstä", + "dhcp_not_found": "On turvallista ottaa sisäänrakennettu DHCP-palvelin käyttöön, koska AdGuard Home ei havainnut verkossa muita aktiivisia DHCP-palvelimia. Suosittelemme, että varmistat tämän vielä itse, koska automaattinen tunnistus ei ole 100% varma.", + "dhcp_found": "Verkossa havaittiin aktiivinen DHCP-palvelin. Sisäänrakennetun DHCP-palvelimen käyttöönotto ei ole turvallista.", + "dhcp_leases": "DHCP-lainat", + "dhcp_static_leases": "Kiinteät DHCP-lainat", + "dhcp_leases_not_found": "DHCP-lainoja ei löytynyt", + "dhcp_config_saved": "DHCP-asetukset tallennettiin", + "dhcp_ipv4_settings": "DHCP:n IPv4-asetukset", + "dhcp_ipv6_settings": "DHCP:n IPv6-asetukset", + "form_error_required": "Vaaditaan", + "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": "Virheellinen päätelaitteen ID", + "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", + "form_error_negative": "Oltava yhtä suuri tai 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", + "dhcp_form_range_start": "Alueen aloitus", + "dhcp_form_range_end": "Alueen päätös", + "dhcp_form_lease_title": "DHCP-lainan kesto (sekunteina)", + "dhcp_form_lease_input": "Lainan kesto", + "dhcp_interface_select": "Valitse DHCP:lle käytettävä verkkosovitin", + "dhcp_hardware_address": "Laiteosoite (MAC)", + "dhcp_ip_addresses": "IP-osoitteet", + "ip": "IP", + "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_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", + "dhcp_lease_deleted": "Kiinteä laina \"{{key}}\" poistettiin", + "dhcp_new_static_lease": "Uusi kiinteä laina", + "dhcp_static_leases_not_found": "Kiinteitä DHCP-lainoja ei löytynyt", + "dhcp_add_static_lease": "Lisää kiinteä laina", + "dhcp_reset_leases": "Tyhjennä kaikki lainat", + "dhcp_reset_leases_confirm": "Haluatko varmasti tyhjentää kaikki lainat?", + "dhcp_reset_leases_success": "DHCP-lainat tyhjennettiin", + "dhcp_reset": "Haluatko varmasti palauttaa DHCP-asetukset?", + "country": "Maa", + "city": "Kaupunki", + "delete_confirm": "Haluatko varmasti poistaa kohteen \"{{key}}\"?", + "form_enter_hostname": "Syötä isäntänimi", + "error_details": "Virheen tiedot", + "response_details": "Vastauksen tiedot", + "request_details": "Pyynnön tiedot", + "client_details": "Päätelaitteen tiedot", + "details": "Tiedot", + "back": "Takaisin", + "dashboard": "Tila", + "settings": "Asetukset", + "filters": "Suodattimet", + "filter": "Suodatin", + "query_log": "Pyyntöhistoria", + "compact": "Tiivis", + "nothing_found": "Ei tuloksia", + "faq": "UKK", + "version": "Versio", + "address": "Osoite", + "protocol": "Protokolla", + "on": "Käytössä", + "off": "Ei käytössä", + "copyright": "Tekijänoikeus", + "homepage": "Kotisivu", + "report_an_issue": "Ilmoita ongelmasta", + "privacy_policy": "Tietosuojakäytäntö", + "enable_protection": "Ota suojaus käyttöön", + "enabled_protection": "Suojaus otettiin käyttöön", + "disable_protection": "Poista suojaus käytöstä", + "disabled_protection": "Suojaus poistettiin käytöstä", + "refresh_statics": "Päivitä tilastot", + "dns_query": "DNS-pyyntöä", + "blocked_by": "<0>Suodatinten estämää", + "stats_malware_phishing": "Estetyt haittaohjelmat/tietojenkalastelut", + "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_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ä", + "no_domains_found": "Verkkotunnuksia ei löytynyt", + "requests_count": "Pyyntöjen määrä", + "top_blocked_domains": "Estetyimmät verkkotunnukset", + "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_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ä", + "number_of_dns_query_blocked_24_hours_by_sec": "AdGuardin Turvallinen selaus -moduulin estämien DNS-pyyntöjen määrä", + "number_of_dns_query_blocked_24_hours_adult": "Estettyjen aikuisille tarkoitettujen sivustojen määrä", + "enforced_save_search": "Turvallinen haku pakotettiin", + "number_of_dns_query_to_safe_search": "DNS-pyyntöjen määrä, joille turvallinen haku pakotettiin käyttöön", + "average_processing_time": "Keskimääräinen käsittelyaika", + "average_processing_time_hint": "Keskimääräinen DNS-pyynnön käsittelyyn kulutettu aika millisekunteina", + "block_domain_use_filters_and_hosts": "Estä verkkotunnuksia suodattimilla ja hosts-tiedostoilla", + "filters_block_toggle_hint": "Voit määrittää estosääntöjä suodatinasetuksissa.", + "use_adguard_browsing_sec": "Käytä AdGuardin turvallisen selauksen palvelua", + "use_adguard_browsing_sec_hint": "AdGuard Home tarkistaa onko verkkotunnus turvallisen selauksen verkkopalvelun estämä. Se käyttää tarkastukseen yksityisyyspainotteista rajapintaa: palvelimelle lähetetään vain pieni osa verkkotunnuksen SHA256-hajautusarvosta.", + "use_adguard_parental": "Käytä AdGuardin lapsilukko-palvelua", + "use_adguard_parental_hint": "AdGuard Home tarkistaa, sisältääkö verkkotunnus aikuisille tarkoitettua sisältöä. Se käyttää samaa yksityisyyspainotteista rajapintaa, kuin turvallisen selauksen palvelu.", + "enforce_safe_search": "Pakota turvallinen haku", + "enforce_save_search_hint": "AdGuard Home voi pakottaa turvallisen haun käyttöön seuraavissa hakukoneissa: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.", + "no_servers_specified": "Palvelimia ei ole määritetty", + "general_settings": "Yleiset asetukset", + "dns_settings": "DNS-asetukset", + "dns_blocklists": "DNS-estolistat", + "dns_allowlists": "DNS-sallittujen listat", + "dns_blocklists_desc": "AdGuard Home estää estolistalla olevat verkkotunnukset.", + "dns_allowlists_desc": "DNS-sallittujen listalla olevat verkkotunnukset sallitaan myös silloin, jos ne ovat jollain muulla estolistalla.", + "custom_filtering_rules": "Omat suodatussäännöt", + "encryption_settings": "Salausasetukset", + "dhcp_settings": "DHCP-asetukset", + "upstream_dns": "Ylävirran DNS-palvelimet", + "upstream_dns_help": "Syötä yksi palvelinosoite per rivi. Lue lisää ylävirran DNS-palvelinten määrityksestä.", + "upstream_dns_configured_in_file": "Määritetty tiedostossa {{path}}", + "test_upstream_btn": "Testaa ylävirtoja", + "upstreams": "Ylävirrat", + "apply_btn": "Käytä", + "disabled_filtering_toast": "Suodatus poistettiin käytöstä", + "enabled_filtering_toast": "Suodatus otettiin käyttöön", + "disabled_safe_browsing_toast": "Turvallinen selaus poistettiin käytöstä", + "enabled_safe_browsing_toast": "Turvallinen selaus otettiin käyttöön", + "disabled_parental_toast": "Lapsilukko poistettiin käytöstä", + "enabled_parental_toast": "Lapsilukko otettiin käyttöön", + "disabled_safe_search_toast": "Turvallinen haku poistettiin käytöstä", + "enabled_save_search_toast": "Turvallinen haku otettiin käyttöön", + "enabled_table_header": "Käytössä", + "name_table_header": "Nimi", + "list_url_table_header": "Listan URL", + "rules_count_table_header": "Sääntöjä", + "last_time_updated_table_header": "Viimeisin päivitys", + "actions_table_header": "Toiminnot", + "request_table_header": "Pyyntö", + "edit_table_action": "Muokkaa", + "delete_table_action": "Poista", + "elapsed": "Kesto", + "filters_and_hosts_hint": "AdGuard Home ymmärtää mainoseston perussääntöjen sekä hosts-tiedostojen syntakseja.", + "no_blocklist_added": "Estolistoja ei ole lisätty", + "no_whitelist_added": "Sallittujen listoja ei ole lisätty", + "add_blocklist": "Lisää estolista", + "add_allowlist": "Lisää sallittujen lista", + "cancel_btn": "Peruuta", + "enter_name_hint": "Syötä nimi", + "enter_url_or_path_hint": "Syötä listan URL-osoite tai tarkka tiedostosijainti", + "check_updates_btn": "Tarkista päivitykset", + "new_blocklist": "Uusi estolista", + "new_allowlist": "Uusi sallittujen lista", + "edit_blocklist": "Muokkaa estolistaa", + "edit_allowlist": "Muokkaa sallittujen listaa", + "choose_blocklist": "Valitse estolistat", + "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", + "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.", + "examples_title": "Esimerkkejä", + "example_meaning_filter_block": "estä pääsy verkkotunnukseen example.org ja sen aliverkkotunnuksiin", + "example_meaning_filter_whitelist": "salli pääsy verkkotunnukseen example.org ja sen aliverkkotunnuksiin", + "example_meaning_host_block": "AdGuard Home palauttaa verkkotunnukselle example.org osoitteen 127.0.0.1 (muttei sen aliverkkotunnuksille)", + "example_comment": "! Tähän tulee kommentti", + "example_comment_meaning": "voit määrittää kommentin", + "example_comment_hash": "# Myös tämä on kommentti", + "example_regex_meaning": "estä pääsy säännöllistä lauseketta vastaaviin verkkotunnuksiin", + "example_upstream_regular": "tavallinen DNS (UDP)", + "example_upstream_dot": "salattu <0>DNS-over-TLS", + "example_upstream_doh": "salattu <0>DNS-over-HTTPS", + "example_upstream_doq": "salattu <0>DNS-over-QUIC", + "example_upstream_sdns": "voit käyttää <0>DNS Stamp -merkintöjä <1>DNSCrypt tai <2>DNS-over-HTTPS -resolvereille", + "example_upstream_tcp": "tavallinen DNS (TCP)", + "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", + "dns_test_not_ok_toast": "Palvelin \"{{key}}\": ei voitu käyttää, tarkista sen oikeinkirjoitus", + "unblock": "Salli", + "block": "Estä", + "disallow_this_client": "Estä tämä päätelaite", + "allow_this_client": "Salli tämä päätelaite", + "block_for_this_client_only": "Estä vain tältä päätelaitteelta", + "unblock_for_this_client_only": "Salli vain tälle päätelaitteelle", + "time_table_header": "Aika", + "date": "Päiväys", + "domain_name_table_header": "Verkkotunnus", + "domain_or_client": "Verkkotunnus tai päätelaite", + "type_table_header": "Tyyppi", + "response_table_header": "Vastaus", + "response_code": "Vastauksen koodi", + "client_table_header": "Asiakas", + "empty_response_status": "Tyhjä", + "show_all_filter_type": "Näytä kaikki", + "show_filtered_type": "Näytä suodatetut", + "no_logs_found": "Historiatietoja ei ole", + "refresh_btn": "Päivitä", + "previous_btn": "Edellinen", + "next_btn": "Seuraava", + "loading_table_status": "Ladataan...", + "page_table_footer_text": "Sivu", + "rows_table_footer_text": "riviä", + "updated_custom_filtering_toast": "Omat suodatussäännöt päivitettiin", + "rule_removed_from_custom_filtering_toast": "Sääntö poistettiin omista suodatussäännöistä: {{rule}}", + "rule_added_to_custom_filtering_toast": "Sääntö lisättiin omiin suodatussääntöihin: {{rule}}", + "query_log_response_status": "Tila: {{value}}", + "query_log_filtered": "Suodattanut {{filter}}", + "query_log_confirm_clear": "Haluatko varmasti tyhjentää pyyntöhistorian?", + "query_log_cleared": "Pyyntöhistoria tyhjennettiin", + "query_log_updated": "Pyyntöhistoria päivitettiin", + "query_log_clear": "Tyhjennä pyyntöhistoria", + "query_log_retention": "Pyyntöhistorian säilytys", + "query_log_enable": "Käytä historiaa", + "query_log_configuration": "Historian määritys", + "query_log_disabled": "Pyyntöhistoria ei ole käytössä. Voit ottaa sen käyttöön <0>asetuksissa", + "query_log_strict_search": "Käytä tarkalle haulle lainausmerkkejä", + "query_log_retention_confirm": "Haluatko varmasti muuttaa pyyntöhistoriasi säilytysaikaa? Jos lyhennät aikaa, joitakin tietoja menetetään", + "anonymize_client_ip": "Piilota päätelaitteen IP-osoite", + "anonymize_client_ip_desc": "Älä tallenna päätelaitteen täydellistä IP-osoitetta historiaan ja tilastoihin", + "dns_config": "DNS-palvelimen määritys", + "dns_cache_config": "DNS-välimuistin määritys", + "dns_cache_config_desc": "Täällä voit määrittää DNS-välimuistin asetukset", + "blocking_mode": "Estotila", + "default": "Oletus", + "nxdomain": "NXDOMAIN", + "refused": "REFUSED", + "null_ip": "Tyhjä IP", + "custom_ip": "Oma IP", + "blocking_ipv4": "IPv4-esto", + "blocking_ipv6": "IPv6-esto", + "dnscrypt": "DNSCrypt", + "dns_over_https": "DNS-over-HTTPS", + "dns_over_tls": "DNS-over-TLS", + "dns_over_quic": "DNS-over-QUIC", + "client_id": "Päätelaitteen ID", + "client_id_placeholder": "Syötä päätelaitteen ID", + "client_id_desc": "Eri päätelaitteet voidaan tunnistaa erityisillä tunnisteilla. Täältä löydät lisätietoja päätelaitteiden tunnistuksesta.", + "download_mobileconfig_doh": "Lataa .mobileconfig-tiedosto DNS-over-HTTPS -käytölle", + "download_mobileconfig_dot": "Lataa .mobileconfig-tiedosto DNS-over-TLS -käytölle", + "download_mobileconfig": "Lataa asetustiedosto", + "plain_dns": "Tavallinen DNS", + "form_enter_rate_limit": "Syötä rajoitus", + "rate_limit": "Pyyntöjen ajoitus", + "edns_enable": "Käytä EDNS-päätelaitealivekkoa", + "edns_cs_desc": "Lähetä päätelaitteiden aliverkot DNS-palvelimille.", + "rate_limit_desc": "Päätelaitteelle sallittu pyyntöjen enimmäismäärä sekunnissa. Arvo 0 tarkoittaa rajatonta.", + "blocking_ipv4_desc": "Estettyyn A-pyyntöön palautettava IP-osoite", + "blocking_ipv6_desc": "Estettyyn AAAA-pyyntöön palautettava IP-osoite", + "blocking_mode_default": "Oletus: Vastaa IP-nollaosoitteella (0.0.0.0 korvaa A; :: korvaa AAAA) kun estetään mainoseston säännöllä; vastaa säännön määrittämällä IP-osoitteella kun estetään /etc/hosts-tyyppisellä säännöllä", + "blocking_mode_refused": "REFUSED: Vastaa REFUSED-koodilla", + "blocking_mode_nxdomain": "NXDOMAIN: Vastaa NXDOMAIN-koodilla", + "blocking_mode_null_ip": "Tyhjä IP: Vastaa IP-nollaosoitteella (0.0.0.0 korvaa A; :: korvaa AAAA)", + "blocking_mode_custom_ip": "Oma IP: Vastaa itse määritetyllä IP-osoitteella", + "upstream_dns_client_desc": "Jos tämä on tyhjä, käyttää AdGuard Home <0>DNS-asetuksissa määritettyjä palvelimia.", + "tracker_source": "Seurannan lähde", + "source_label": "Lähde", + "found_in_known_domain_db": "Löytyi tunnettujen verkkotunnusten tietokannasta.", + "category_label": "Luokitus", + "rule_label": "Säännöt", + "list_label": "Lista", + "unknown_filter": "Tuntematon suodatin {{filterId}}", + "known_tracker": "Tunnettu seuranta", + "install_welcome_title": "Tervetuloa AdGuard Homeen!", + "install_welcome_desc": "AdGuard Home on verkonlaajuinen mainoksia ja seurantoja estävä DNS-palvelin. Sen tarkoitus on mahdollistaa verkon sekä siihen liitettyjen laitteiden hallinta ja valvonta, eikä se vaadi asiakasohjelmistojen asennusta päätelaitteille.", + "install_settings_title": "Hallintapaneeli", + "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", + "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", + "install_auth_title": "Tunnistautuminen", + "install_auth_desc": "AdGuard Homen hallinnalle on määritettävä salasanasuojaus. Vaikka se olisikin tavoitettavissa vain lähiverkon välityksellä, on silti tärkeää suojata se luvattomalta käytöltä.", + "install_auth_username": "Käyttäjätunnus", + "install_auth_password": "Salasana", + "install_auth_confirm": "Vahvista salasana", + "install_auth_username_enter": "Syötä käyttäjätunnus", + "install_auth_password_enter": "Syötä salasana", + "install_step": "Vaihe", + "install_devices_title": "Määritä laitteet", + "install_devices_desc": "AdGuard Homen käytön aloittamiseksi, on laitteet määritettävä käyttämään sitä.", + "install_submit_title": "Onnittelut!", + "install_submit_desc": "Asennus on valmis ja AdGuard Home on valmis käyttöön.", + "install_devices_router": "Reititin", + "install_devices_router_desc": "Asennus kattaa kaikki reitittimeen liitetyt laitteet, eikä niitä tarvitse määrittää erikseen yksitellen.", + "install_devices_address": "AdGuard Homen DNS-palvelin kuuntelee seuraavissa osoitteissa", + "install_devices_router_list_1": "Avaa reitittimesi hallinta. Yleensä se avautuu selaimen kautta, URL-osoitteella, kuten http://192.168.0.1 tai http://192.168.1.1. Saatat joutua syöttämään käyttäjätunnuksen ja salasanan. Jos et muista tai tiedä sitä, voit yleensä palauttaa salasanan (ja kaikki muut!) reitittimen asetukset oletusarvoihin painamalla laitteessa olevaa reset-painiketta muutaman sekunnin ajan. Jos reitittimen määritys vaatii erillisen sovelluksen käyttöä, asenna se mobiililaitteelle tai tietokoneelle ja käytä reitittimen hallintaa sen kautta. Tutustu reitittimen käyttöoppaaseen.", + "install_devices_router_list_2": "Etsi DHCP/DNS-asetukset. Etsi kirjainyhdistelmää DNS sellaisen kenttien vierestä, joihin voidaan syöttää kaksi tai kolme numerosarjaa, joista jokainen on eroteltu neljään ryhmään, joista jokainen sisältää yhdestä kolmeen numeroa.", + "install_devices_router_list_3": "Syötä sinne AdGuard Home -palvelimesi osoitteet.", + "install_devices_router_list_4": "Joissakin reitittimissä ei ole mahdollista määrittää omaa DNS-palvelinta. Tällöin AdGuard Homen määritys <0>DHCP-palvelimeksi voi auttaa. Muutoin on selvitettävä reitittimen käyttöohjeesta, miten sen DNS-palvelinasetukset muutetaan.", + "install_devices_windows_list_1": "Avaa \"Ohjauspaneeli\" Käynnistä-valikon tai Windowsin haun kautta.", + "install_devices_windows_list_2": "Avaa \"Verkko ja Internet\" -ryhmä ja sitten \"Verkko ja jakamiskeskus\".", + "install_devices_windows_list_3": "Etsi ikkunan vasemmasta laidasta \"Muuta sovittimen asetuksia\" ja klikkaa sitä.", + "install_devices_windows_list_4": "Valitse aktiivinen yhteytesi, klikkaa sitä hiiren kakkospainikkeella ja valitse valikosta \"Ominaisuudet\".", + "install_devices_windows_list_5": "Etsi listasta \"Internet protokolla versio 4 (TCP/IP)\", valitse se ja klikkaa 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": "Avaa Omenavalikko ja valitse \"Järjestelmäasetukset \".", + "install_devices_macos_list_2": "Klikkaa \"Verkko\".", + "install_devices_macos_list_3": "Valitse listan ensimmäinen yhteys ja klikkaa \"Lisävalinnat\".", + "install_devices_macos_list_4": "Valitse DNS-välilehti ja syötä AdGuard Home -palvelimesi osoitteet.", + "install_devices_android_list_1": "Napauta \"Asetukset\" -kuvaketta Android-laitteesi aloitusnäytöstä tai sovellusvalikosta.", + "install_devices_android_list_2": "Napauta \"Yhteydet\" ja sitten \"Wi-Fi\". Näytetään kaikki käytettävissä olevat langattomat verkot (mobiiliverkolle ei ole mahdollista määrittää omaa DNS-palvelinta).", + "install_devices_android_list_3": "Napauta yhdistetyn verkon vieressä olevaa asetuskuvaketta tai paina verkkoa pitkään ja valitse \"Muokkaa verkkoa\".", + "install_devices_android_list_4": "Saatat joutua napauttamaan \"Lisäasetukset\" nähdäksesi lisää valintoja. Muuttaaksesi DNS-asetuksia, on \"IP-asetukset\" -kohdan \"DHCP\" -valinta vaihdettava \"Staattinen\" -valintaan.", + "install_devices_android_list_5": "Syötä \"DNS 1\" ja \"DNS 2\" -kenttiin AdGuard Home -palvelimesi osoitteet.", + "install_devices_ios_list_1": "Valitse 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_4": "Syötä \"DNS\" -kenttään AdGuard Home -palvelimesi osoitteet.", + "get_started": "Aloita", + "next": "Seuraava", + "open_dashboard": "Avaa hallintapaneeli", + "install_saved": "Tallennettiin", + "encryption_title": "Salaus", + "encryption_desc": "Salaus (HTTPS/TLS) DNS-palvelimelle ja selaimen hallintasivulle", + "encryption_config_saved": "Salausasetukset tallennettiin", + "encryption_server": "Palvelimen nimi", + "encryption_server_enter": "Syötä verkkotunnuksesi", + "encryption_server_desc": "HTTPS-yhteyden käyttöä varten, on syötettävä SSL- tai jokerivarmennetta vastaava palvelimen nimi. Jos kenttä on tyhjä, sallitaan kaikkien verkkotunnusten TLS-yhteydet.", + "encryption_redirect": "Automaattinen HTTPS-ohjaus", + "encryption_redirect_desc": "Jos käytössä, AdGuard Home ohjaa HTTP-osoitteet automaattisesti HTTPS-osoitteisiin.", + "encryption_https": "HTTPS-portti", + "encryption_https_desc": "Jos HTTPS-portti on määritetty, on AdGuard Homen hallintapaneeli käytettävissä HTTPS-yhteydellä ja lisäksi tämä mahdollistaa myös DNS-over-HTTPS -yhteyden '/dns-query' -kohteessa.", + "encryption_dot": "DNS-over-TLS -portti", + "encryption_dot_desc": "Jos portti on määritetty, AdGuard Home suorittaa DNS-over-TLS -palvelimen tässä portissa.", + "encryption_doq": "DNS-over-QUIC -portti", + "encryption_doq_desc": "Jos portti on määritetty, AdGuard Home suorittaa DNS-over-QUIC -palvelimen tässä portissa. Ominaisuus on kokeellinen, eikä välttämättä luotettava. Lisäksi tätä tukevia päätelaitteita ei vielä ole kovin paljon.", + "encryption_certificates": "Varmenteet", + "encryption_certificates_desc": "Salauksen käyttämiseksi, on syötettävä verkkotunnuksellesi myönnetty, aito SSL-varmenneketju. Voit hankkia ilmaisen varmenteen osoitteesta <0>{{link}} tai ostaa sellaisen joltakin luotetulta varmentajalta.", + "encryption_certificates_input": "Kopioi/liitä PEM-koodatut varmenteesi tähän.", + "encryption_status": "Tila", + "encryption_expire": "Erääntyy", + "encryption_key": "Yksityinen avain", + "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 pätevä", + "encryption_chain_invalid": "Varmenneketju ei kelpaa", + "encryption_key_valid": "Yksityinen {{type}}-avain on pätevä", + "encryption_key_invalid": "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ää", + "reset_settings": "Tyhjennä asetukset", + "update_announcement": "AdGuard Home {{version}} on nyt saatavilla! <0>Klikkaa 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", + "down": "yhteydetön", + "fix": "Korjaa", + "dns_providers": "Katso <0>luettelo tunnetuista DNS-palveluista, joista valita.", + "update_now": "Päivitä nyt", + "update_failed": "Automaattinen päivitys epäonnistui. Seuraa näitä ohjeita päivittääksesi manuaalisesti.", + "processing_update": "Odota kun AdGuard Home päivittyy", + "clients_title": "Päätelaitteet", + "clients_desc": "Määritä AdGuard Homeen yhdistetyt päätelaitteet", + "settings_global": "Yleinen", + "settings_custom": "Oma", + "table_client": "Päätelaite", + "table_name": "Nimi", + "save_btn": "Tallenna", + "client_add": "Lisää päätelaite", + "client_new": "Uusi päätelaite", + "client_edit": "Muokkaa päätelaitetta", + "client_identifier": "Tunniste", + "ip_address": "IP-osoite", + "client_identifier_desc": "Päätelaitteet voidaan tunnistaa IP-osoitteista, CIDR-merkinnöistä, MAC-osoitteista tai erityisistä päätelaitteen ID-tunnisteista (voidaan käyttää DoT/DoH/DoQ kanssa). <0>Täältä voit lukea lisää päätelaitteiden tunnistuksesta.", + "form_enter_ip": "Syötä IP-osoite", + "form_enter_subnet_ip": "Syötä IP-osoite aliverkkoon \"{{cidr}}\"", + "form_enter_mac": "Syötä MAC-osoite", + "form_enter_id": "Muokkaa tunnistetta", + "form_add_id": "Lisää tunniste", + "form_client_name": "Syötä päätelaitteen nimi", + "name": "Nimi", + "client_global_settings": "Käytä yleisiä asetuksia", + "client_deleted": "Päätelaite \"{{key}}\" poistettiin", + "client_added": "Päätelaite \"{{key}}\" lisättiin", + "client_updated": "Päätelaite \"{{key}}\" päivitettiin", + "clients_not_found": "Päätelaitteita ei löytynyt", + "client_confirm_delete": "Haluatko varmasti poistaa päätelaitteen \"{{key}}\"?", + "list_confirm_delete": "Haluatko varmasti poistaa tämän listan?", + "auto_clients_title": "Päätelaitteet (määrittämättömät)", + "auto_clients_desc": "Tiedot niistä AdGuard Homea käyttävistä päätelaitteista, joita ei ole määritetty asetuksissa", + "access_title": "Käytön asetukset", + "access_desc": "Tässä voidaan määrittää AdGuard Homen DNS-palvelimen käyttöoikeussääntöjä.", + "access_allowed_title": "Sallitut päätelaitteet", + "access_allowed_desc": "Lista CIDR-merkinnöistä, IP-osoitteista tai päätelaitteiden ID-tunnisteista. Jos määritetty, hyväksyy AdGuard Home pyyntöjä vain näiltä päätelaitteilta.", + "access_disallowed_title": "Kielletyt päätelaitteet", + "access_disallowed_desc": "Lista CIDR-merkinnöistä, IP-osoitteista tai päätelaitteiden ID-tunnisteista. Jos määritetty, hylkää AdGuard Home näiden päätelaitteiden pyynnöt. Tätä kenttää ei huomioida, jos sallittuja päätelaitteita on määritetty.", + "access_blocked_title": "Kielletyt verkkotunnukset", + "access_blocked_desc": "Ei pidä sekoittaa suodattimiin. AdGuard Home hylkää näiden verkkotunnusten DNS-pyynnöt, eivätkä nämä pyynnöt näy edes pyyntöhistoriassa. Tähän voidaan syöttää tarkkoja verkkotunnuksia, jokerimerkkejä tai URL-suodatussääntöjä, kuten \"example.org\", \"*.example.org\" tai \"||example.org^\".", + "access_settings_saved": "Käytön asetukset tallennettiin", + "updates_checked": "Päivitykset tarkastettiin", + "updates_version_equal": "AdGuard Home on ajan tasalla", + "check_updates_now": "Tarkista päivitykset nyt", + "dns_privacy": "DNS-yksityisyys", + "setup_dns_privacy_1": "<0>DNS-over-TLS: Käytä merkkijonoa <1>{{address}}.", + "setup_dns_privacy_2": "<0>DNS-over-HTTPS: Käytä merkkijonoa <1>{{address}}.", + "setup_dns_privacy_3": "<0>Tässä on lista ohjelmistoista, joita voit käyttää.", + "setup_dns_privacy_4": "iOS 14 ja macOS Big Sur -laitteille voidaan ladata erityinen '.mobileconfig' -tiedosto, joka lisää DNS-asetuksiin DNS-over-HTTPS tai DNS-over-TLS -palvelimet.", + "setup_dns_privacy_android_1": "Android 9 tukee DNS-over-TLS -toteutusta natiivisti. Se määritetään syöttämällä oma verkkotunnus kohtaan \"Asetukset\" → \"Yhteydet\" → \"Lisää yhteysasetuksia\" → \"Yksityinen DNS\".", + "setup_dns_privacy_android_2": "<0>AdGuard Androidille tukee <1>DNS-over-HTTPS ja <1>DNS-over-TLS -toteutuksia.", + "setup_dns_privacy_android_3": "<0>Intra lisää <1>DNS-over-HTTPS tuen Androidiin.", + "setup_dns_privacy_ios_1": "<0>DNSCloak tukee <1>DNS-over-HTTPS, mutta oman palvelimen käyttö' varten sille on luotava <2>DNS Stamp -merkintä.", + "setup_dns_privacy_ios_2": "<0>AdGuard iOS:lle tukee <1>DNS-over-HTTPS ja <1>DNS-over-TLS -toteutuksia.", + "setup_dns_privacy_other_title": "Muita toteutuksia", + "setup_dns_privacy_other_1": "AdGuard Home voi itse olla turvallinen DNS-päätelaite millä tahansa alustalla.", + "setup_dns_privacy_other_2": "<0>dnsproxy tukee kaikkia tunnettuja turvallisia DNS-protokollia.", + "setup_dns_privacy_other_3": "<0>dnscrypt-proxy tukee <1>DNS-over-HTTPS -protokollaa.", + "setup_dns_privacy_other_4": "<0>Mozilla Firefox tukee <1>DNS-over-HTTPS -toteutusta.", + "setup_dns_privacy_other_5": "Löydät lisää toteutuksia <0>täältä ja <1>täältä.", + "setup_dns_privacy_ioc_mac": "iOS ja macOS -asetukset", + "setup_dns_notice": "<1>DNS-over-HTTPS tai <1>DNS-over-TLS -toteutuksia varten, on AdGuard Homen <0>Salausasetukset määritettävä.", + "rewrite_added": "Kohteen \"{{key}}\" DNS-uudelleenohjaus lisättiin", + "rewrite_deleted": "Kohteen \"{{key}}\" DNS-uudelleenohjaus poistettiin", + "rewrite_add": "Lisää DNS-uudelleenohjaus", + "rewrite_not_found": "DNS-uudelleenohjauksia ei löytynyt", + "rewrite_confirm_delete": "Haluatko varmasti poistaa DNS-uudelleenohjauksen kohteelle \"{{key}}\"?", + "rewrite_desc": "Mahdollistaa oman DNS-vastauksen helpon määrityksen tietylle verkkotunnukselle.", + "rewrite_applied": "Uudelleenohjattu säännöllä", + "rewrite_hosts_applied": "Hosts-tiedoston säännön korvaama", + "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", + "configure": "Määritä", + "main_settings": "Pääasetukset", + "block_services": "Estä tietyt palvelut", + "blocked_services": "Estetyt palvelut", + "blocked_services_desc": "Mahdollistaa suosittujen sivustojen ja palveluiden nopean eston.", + "blocked_services_saved": "Estetyt palvelut tallennettiin", + "blocked_services_global": "Käytä yleisiä estettyjä palveluita", + "blocked_service": "Estetty palvelu", + "block_all": "Estä kaikki", + "unblock_all": "Salli kaikki", + "encryption_certificate_path": "Varmenteen sijainti", + "encryption_private_key_path": "Yksityisen avaimen sijainti", + "encryption_certificates_source_path": "Määritä varmennetiedoston sijainti", + "encryption_certificates_source_content": "Liitä varmenteen sisältö", + "encryption_key_source_path": "Määritä yksityisen avaimen tiedosto", + "encryption_key_source_content": "Liitä yksityisen avaimen sisältö", + "stats_params": "Tilastoinnin määritys", + "config_successfully_saved": "Asetukset tallennettiin", + "interval_6_hour": "6 tuntia", + "interval_24_hour": "24 tuntia", + "interval_days": "{{count}} päivä", + "interval_days_plural": "{{count}} päivää", + "domain": "Verkkotunnus", + "punycode": "Punycode", + "answer": "Vastaus", + "filter_added_successfully": "Lista lisättiin", + "filter_removed_successfully": "Lista poistettiin", + "filter_updated": "Listan päivitettiin", + "statistics_configuration": "Tilastoinnin määritys", + "statistics_retention": "Tilastojen säilytys", + "statistics_retention_desc": "Jos aikaa lyhennetään, joitakin tietoja menetetään.", + "statistics_clear": "Tyhjennä tilastot", + "statistics_clear_confirm": "Haluatko varmasti tyhjentää tilastot?", + "statistics_retention_confirm": "Haluatko varmasti muuttaa tilastojen säilytysaikaa? Jos aikaa lyhennetään, joitakin tietoja menetetään.", + "statistics_cleared": "Tilastot tyhjennettiin", + "statistics_enable": "Ota tilastointi käyttöön", + "interval_hours": "{{count}} tunti", + "interval_hours_plural": "{{count}} tuntia", + "filters_configuration": "Suodatinten määritys", + "filters_enable": "Ota suodattimet käyttöön", + "filters_interval": "Suodatinpäivitysten tiheys", + "disabled": "Ei käytössä", + "username_label": "Käyttäjätunnus", + "username_placeholder": "Syötä käyttäjätunnus", + "password_label": "Salasana", + "password_placeholder": "Syötä salasana", + "sign_in": "Kirjaudu", + "sign_out": "Kirjaudu ulos", + "forgot_password": "Salasana unohtunut?", + "forgot_password_desc": "Luo käyttäjätilillesi uusi salasana seuraamalla <0>näitä ohjeita.", + "location": "Sijainti", + "orgname": "Organisaation nimi", + "netname": "Verkon nimi", + "network": "Verkko", + "descr": "Kuvaus", + "whois": "Whois", + "filtering_rules_learn_more": "<0>Lue lisää omien hosts-listojesi luonnista.", + "blocked_by_response": "Vastauksen sisältämän CNAME:n tai IP:n estämä", + "blocked_by_cname_or_ip": "CNAME:n tai IP:n estämä", + "try_again": "Yritä uudelleen", + "domain_desc": "Syötä korvattava verkkotunnus tai jokerimerkki.", + "example_rewrite_domain": "korvaa vain tämän verkkotunnuksen vastaukset", + "example_rewrite_wildcard": "korvaa verkkotunnuksen <0>example.org kaikkien aliverkkotunnusten vastaukset", + "rewrite_ip_address": "IP-osoite: käytä tätä IP-osoitetta A tai AAAA -vastauksessa.", + "rewrite_domain_name": "Verkkotunnus: lisää CNAME-tietue.", + "rewrite_A": "<0>A: erityinen arvo, säilytä ylävirran <0>A-tiedot", + "rewrite_AAAA": "<0>AAAA: erityinen arvo, säilytä ylävirran <0>AAAA-tiedot", + "disable_ipv6": "Älä selvitä IPv6-osoitteita", + "disable_ipv6_desc": "Hylkää kaikki IPv6-osoitteiden DNS-pyynnöt (tyyppi AAAA).", + "fastest_addr": "Nopein IP-osoite", + "fastest_addr_desc": "Lähetä pyynnöt kaikille DNS-palvelimille ja valitse vastauksista nopein IP-osoite. Tämä parantaa yleistä liitettävyyttä, joskin hidastaa DNS-pyyntöjä, koska AdGuard Homen on odotettava kaikkien DNS-palvelinten vastauksia.", + "autofix_warning_text": "Jos valitset \"Korjaa\", AdGuard Home määrittää järjestelmäsi käyttämään AdGuard Homen DNS-palvelinta.", + "autofix_warning_list": "Suorittaa toiminnot: <0>Poistaa käytöstä järjestelmän DNSStubListener-palvelun <0>Määrittää DNS-palvelimen osoitteeksi 127.0.0.1 <0>Muuttaa sijainnnin /etc/resolv.conf symbolisen linkin kohteeksi /run/systemd/resolve/resolv.conf <0>Pysäyttää DNSStubListener-palvelun (uudelleenlataa systemd-resolved -palvelu)", + "autofix_warning_result": "Tämän jälkeen järjestelmäsi kaikki DNS-pyynnöt käsittelee oletusarvoisesti AdGuard Home.", + "tags_title": "Tunnisteet", + "tags_desc": "Voit valita päätelaitteeseen viittaavia tunnisteita. Tunnisteet voidaan sisällyttää suodatussääntöihin ja näin voit kohdistaa niitä tarkemmin. <0>Lue lisää", + "form_select_tags": "Valitse päätelaitteen tunnisteet", + "check_title": "Tarkasta suodatus", + "check_desc": "Tarkasta suodatetaanko isäntänimeä", + "check": "Tarkasta", + "form_enter_host": "Syötä isäntänimi", + "filtered_custom_rules": "Suodatettu omilla suodatussäännöillä", + "choose_from_list": "Valitse listalta", + "add_custom_list": "Lisää oma lista", + "host_whitelisted": "Isäntä on sallittu", + "check_ip": "IP-osoitteet: {{ip}}", + "check_cname": "CNAME: {{cname}}", + "check_reason": "Syy: {{reason}}", + "check_service": "Palvelun nimi: {{service}}", + "service_name": "Palvelun nimi", + "check_not_found": "Ei löytynyt suodatinlistoilta", + "client_confirm_block": "Haluatko varmasti estää päätelaitteen \"{{ip}}\"?", + "client_confirm_unblock": "Haluatko varmasti sallia päätelaitteen \"{{ip}}\"?", + "client_blocked": "Päätelaite \"{{ip}}\" estettiin", + "client_unblocked": "Päätelaite \"{{ip}}\" sallittiin", + "static_ip": "Kiiteä IP-osoite", + "static_ip_desc": "AdGuard Home on palvelin, joten se tarvitsee kiinteän IP-osoitteen toimiakseen oikein. Muutoin reitittimesi saattaa määrittää sille jossakin vaiheessa uuden, dynaamisen IP-osoitteen.", + "set_static_ip": "Määritä kiinteä IP-osoite", + "install_static_ok": "Hyviä uutisia! Kiinteä IP-osoite on jo määritetty.", + "install_static_error": "AdGuard Home ei voi määrittää sitä tälle verkkosovittimelle automaattisesti. Etsi ohjeita tämän suorittamiseksi itse.", + "install_static_configure": "AdGuard Home havaitsi, että käytössä on dynaaminen IP-osoitteen <0>{{ip}}. Haluatko määrittää sen kiinteäksi osoitteeksi?", + "confirm_static_ip": "AdGuard Home määrittää IP-osoitteen {{ip}} kiinteäksi. Haluatko jatkaa?", + "list_updated": "{{count}} lista päivitettiin", + "list_updated_plural": "{{count}} listaa päivitettiin", + "dnssec_enable": "Ota DNSSEC käyttöön", + "dnssec_enable_desc": "Määritä DNSSEC-lippu ulos lähteville DNS-pyynnöille ja tarkasta tulos (vaatii DNSSEC-yhteensopivan resolverin).", + "validated_with_dnssec": "DNSSEC-vahvistettu", + "all_queries": "Kaikki pyynnöt", + "show_blocked_responses": "Estetty", + "show_whitelisted_responses": "Sallittu", + "show_processed_responses": "Käsitelty", + "blocked_safebrowsing": "Turvallisen selauksen estämät", + "blocked_adult_websites": "Estetyt aikuisille tarkoitetut sivustot", + "blocked_threats": "Estetyt uhat", + "allowed": "Sallitut", + "filtered": "Suodatetut", + "rewritten": "Uudelleenohjatut", + "safe_search": "Turvallinen haku", + "blocklist": "Estolista", + "milliseconds_abbreviation": "ms", + "cache_size": "Välimuistin koko", + "cache_size_desc": "DNS-välimuistin koko (tavuina)", + "cache_ttl_min_override": "Korvaa vähimmäis-TTL", + "cache_ttl_max_override": "Korvaa enimmäis-TTL", + "enter_cache_size": "Syötä välimuistin koko (tavuina)", + "enter_cache_ttl_min_override": "Syötä vähimmäis-TTL (sekunteina)", + "enter_cache_ttl_max_override": "Syötä enimmäis-TTL (sekunteina)", + "cache_ttl_min_override_desc": "Pidennä ylävirran palvelimelta vastaanotettuja, lyhyitä time-to-live -arvoja (sekunteina) tallennettaessa DNS-vastauksia välimuistiin.", + "cache_ttl_max_override_desc": "Määritä DNS-välimuistin kohteiden suurin time-to-live -arvo (sekunteina)", + "ttl_cache_validation": "Välimuistin TTL-vähimmäisarvon tulee olla pienempi tai sama kuin enimmäisarvon", + "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", + "filter_category_security": "Turvallisuus", + "filter_category_regional": "Alueelliset", + "filter_category_other": "Muut", + "filter_category_general_desc": "Listat, jotka estävät seurannan ja mainokset useimmilla laitteilla", + "filter_category_security_desc": "Tietojenkalastelu-, huijaus- ja muiden haitallisten verkkotunnusten estoon erikoistuneet listat", + "filter_category_regional_desc": "Listat, jotka painottavat alueellisia mainoksia ja seurantapalvelimia", + "filter_category_other_desc": "Muut estolistat", + "setup_config_to_enable_dhcp_server": "Määritä asetukset DHCP-palvelimen käyttöönottoa varten", + "original_response": "Alkuperäinen vastaus", + "click_to_view_queries": "Näytä pyynnöt", + "port_53_faq_link": "Portti 53 on usein \"DNSStubListener\" tai \"systemd-resolved\" -palveluiden varaama. Lue <0>nämä ohjeet tämän ratkaisemiseksi.", + "adg_will_drop_dns_queries": "AdGuard Home hylkää tämän päätelaitteen DNS-pyynnöt.", + "filter_allowlist": "VAROITUS: Toiminto ohittaa \"{{disallowed_rule}}\" -säännön sallittujen päätelaitteiden listalta.", + "last_rule_in_allowlist": "Et voi estää tätä päätelaitetta, koska säännön \"{{disallowed_rule}}\" ohitus POISTAA KÄYTÖSTÄ \"Sallitut päätelaitteet\" -listan.", + "experimental": "Kokeellinen", + "use_saved_key": "Käytä aiemmin tallennettua avainta" +} diff --git a/client/src/__locales/uk.json b/client/src/__locales/uk.json new file mode 100644 index 00000000..256ee9b3 --- /dev/null +++ b/client/src/__locales/uk.json @@ -0,0 +1,628 @@ +{ + "client_settings": "Налаштування клієнта", + "example_upstream_reserved": "Ви можете вказати DNS-сервер <0>для певних доменів", + "example_upstream_comment": "Ви можете вказати коментар", + "upstream_parallel": "Використовувати паралельні запити, щоб пришвидшити вирішення одночасною чергою всіх оригінальних серверів.", + "parallel_requests": "Паралельні запити", + "load_balancing": "Балансування навантаження", + "load_balancing_desc": "Запитувати один сервер за раз. AdGuard Home використовуватиме зважений випадковий алгоритм для вибору сервера, щоб найшвидший сервер використовувався частіше.", + "bootstrap_dns": "Bootstrap DNS-сервери", + "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_placeholder": "Вводьте одну адресу на рядок", + "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 тощо.", + "check_dhcp_servers": "Перевірити DHCP-сервери", + "save_config": "Зберегти конфігурацію", + "enabled_dhcp": "DHCP-сервер увімкнено", + "disabled_dhcp": "DHCP-сервер вимкнено", + "unavailable_dhcp": "DHCP недоступний", + "unavailable_dhcp_desc": "AdGuard Home не може запустити DHCP-сервер у вашій ОС", + "dhcp_title": "DHCP-сервер (експериментальний!)", + "dhcp_description": "Якщо ваш роутер не пропонує налаштування DHCP, ви можете використати власний вбудований DHCP-сервер AdGuard.", + "dhcp_enable": "Увімкнути DHCP-сервер", + "dhcp_disable": "Вимкнути DHCP-сервер", + "dhcp_not_found": "Можна безпечно увімкнути вбудований DHCP-сервер — ми не знайшли жодного активного DHCP-сервера в мережі. Однак, ми радимо вам ще раз перевірити вручну, тому що наш автоматичний тест наразі не дає 100% гарантії.", + "dhcp_found": "Не знайдено DHCP-сервера в мережі. Вмикати вбудований DHCP-сервер небезпечно.", + "dhcp_leases": "Оренда DHCP", + "dhcp_static_leases": "Статичні оренди DHCP", + "dhcp_leases_not_found": "Оренду DHCP не знайдено", + "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", + "form_error_negative": "Повинно дорівнювати 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-адрес", + "dhcp_form_range_start": "Початок діапазону", + "dhcp_form_range_end": "Кінець діапазону", + "dhcp_form_lease_title": "Час оренди DHCP (в секундах)", + "dhcp_form_lease_input": "Тривалість оренди", + "dhcp_interface_select": "Оберіть інтерфейс DHCP", + "dhcp_hardware_address": "Апаратна адреса", + "dhcp_ip_addresses": "IP-адреси", + "ip": "IP", + "dhcp_table_hostname": "Назва вузла", + "dhcp_table_expires": "Термін дії", + "dhcp_warning": "Якщо ви однаково хочете увімкнути DHCP-сервер, переконайтеся, що у вашій мережі немає інших активних DHCP-серверів. Інакше, це може порушити роботу інтернету на під'єднаних пристроях!", + "dhcp_error": "Не вдалося визначити, чи є в мережі інший 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}}» успішно додано", + "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}}»?", + "form_enter_hostname": "Введіть назву вузла", + "error_details": "Подробиці помилки", + "response_details": "Деталі відповіді", + "request_details": "Деталі запиту", + "client_details": "Подробиці про клієнта", + "details": "Подробиці", + "back": "Назад", + "dashboard": "Панель керування", + "settings": "Налаштування", + "filters": "Фільтри", + "filter": "Фільтр", + "query_log": "Журнал запитів", + "compact": "Стисло", + "nothing_found": "Нічого не знайдено...", + "faq": "Часті питання", + "version": "Версія", + "address": "Адреса", + "protocol": "Протокол", + "on": "УВІМК", + "off": "ВИМК", + "copyright": "Авторське право", + "homepage": "Домівка", + "report_an_issue": "Повідомити про проблему", + "privacy_policy": "Політика приватності", + "enable_protection": "Увімкнути захист", + "enabled_protection": "Захист увімкнено", + "disable_protection": "Вимкнути захист", + "disabled_protection": "Захист вимкнено", + "refresh_statics": "Оновити статистику", + "dns_query": "DNS-запити", + "blocked_by": "<0>Заблоковано фільтрами", + "stats_malware_phishing": "Заблоковано зловмисних/шахрайських програм", + "stats_adult": "Заблоковано вебсайтів для дорослих", + "stats_query_domain": "Найчастіші запити доменів", + "for_last_24_hours": "за останні 24 години", + "for_last_days": "за останній день", + "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-запитів, заблокованих фільтрами і списками блокування hosts", + "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": "Блокувати домени з використанням фільтрів та 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, що й веб-служба безпечного перегляду.", + "enforce_safe_search": "Використовувати безпечний пошук", + "enforce_save_search_hint": "AdGuard Home може примусово застосовувати безпечний пошук в таких пошукових системах: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.", + "no_servers_specified": "Не вказано сервери", + "general_settings": "Загальні налаштування", + "dns_settings": "Налаштування DNS", + "dns_blocklists": "Список блокування DNS", + "dns_allowlists": "Списки дозволів DNS", + "dns_blocklists_desc": "AdGuard Home блокуватиме домени зі списків блокування.", + "dns_allowlists_desc": "Домени зі списків дозволів DNS будуть дозволятися, навіть якщо вони знаходяться в будь-якому зі списків блокування.", + "custom_filtering_rules": "Власні правила фільтрування", + "encryption_settings": "Налаштування шифрування", + "dhcp_settings": "Налаштування DHCP", + "upstream_dns": "Upstream DNS-сервери", + "upstream_dns_help": "Введіть адреси серверів по одній на рядок. Докладніше про налаштування DNS-серверів.", + "upstream_dns_configured_in_file": "Налаштовано в {{path}}", + "test_upstream_btn": "Тест upstream серверів", + "upstreams": "Upstreams", + "apply_btn": "Застосувати", + "disabled_filtering_toast": "Фільтрування вимкнено", + "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": "Безпечний пошук увімкнено", + "enabled_table_header": "Увімкнено", + "name_table_header": "Назва", + "list_url_table_header": "URL списку", + "rules_count_table_header": "Кількість правил", + "last_time_updated_table_header": "Востаннє оновлено", + "actions_table_header": "Дії", + "request_table_header": "Запит", + "edit_table_action": "Редагувати", + "delete_table_action": "Видалити", + "elapsed": "Витрачений час", + "filters_and_hosts_hint": "AdGuard Home розуміє основні правила блокування і синтаксис файлів hosts.", + "no_blocklist_added": "Списків блокування не додано", + "no_whitelist_added": "Списків дозволів не додано", + "add_blocklist": "Додати список блокування", + "add_allowlist": "Додати список дозволів", + "cancel_btn": "Скасувати", + "enter_name_hint": "Введіть назву", + "enter_url_or_path_hint": "Уведіть URL-адресу чи абсолютний шлях до списку", + "check_updates_btn": "Перевірити оновлення", + "new_blocklist": "Новий список блокування", + "new_allowlist": "Новий список дозволів", + "edit_blocklist": "Змінити список блокування", + "edit_allowlist": "Змінити список дозволів", + "choose_blocklist": "Виберіть списки блокування", + "choose_allowlist": "Обрати списки дозволених сайтів", + "enter_valid_blocklist": "Введіть дійсну URL-адресу в список блокування.", + "enter_valid_allowlist": "Введіть дійсну URL-адресу в список дозволів.", + "form_error_url_format": "Неправильний формат URL", + "form_error_url_or_path_format": "Помилкова URL-адреса чи абсолютний шлях до списку", + "custom_filter_rules": "Власні правила фільтрування", + "custom_filter_rules_hint": "Вводьте одне правило на рядок. Ви можете використовувати правила блокування чи синтаксис файлів 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": "блокує доступ до доменів, що відповідають вказаному звичайному виразу", + "example_upstream_regular": "звичайний 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)", + "all_lists_up_to_date_toast": "Всі списки вже оновлені", + "updated_upstream_dns_toast": "DNS-сервери оновлено", + "dns_test_ok_toast": "Вказані DNS сервери працюють правильно", + "dns_test_not_ok_toast": "Сервер «{{key}}»: неможливо використати. Перевірте правильність введення", + "unblock": "Дозволити", + "block": "Заборонити", + "disallow_this_client": "Заборонити цього клієнта", + "allow_this_client": "Дозволити цей клієнт", + "block_for_this_client_only": "Заборонити тільки цей клієнт", + "unblock_for_this_client_only": "Дозволити тільки цей клієнт", + "time_table_header": "Час", + "date": "Дата", + "domain_name_table_header": "Назва домену", + "domain_or_client": "Домен чи клієнт", + "type_table_header": "Тип", + "response_table_header": "Відповідь", + "response_code": "Код відповіді", + "client_table_header": "Клієнт", + "empty_response_status": "Порожньо", + "show_all_filter_type": "Показати все", + "show_filtered_type": "Показати фільтровані", + "no_logs_found": "Немає записів", + "refresh_btn": "Оновити", + "previous_btn": "Назад", + "next_btn": "Далі", + "loading_table_status": "Завантаження...", + "page_table_footer_text": "Сторінка", + "rows_table_footer_text": "рядків", + "updated_custom_filtering_toast": "Власні правила фільтрування збережено", + "rule_removed_from_custom_filtering_toast": "Правило вилучено з власних правил фільтрування: {{rule}}", + "rule_added_to_custom_filtering_toast": "Правило додано до власних правил фільтрування: {{rule}}", + "query_log_response_status": "Стан: {{value}}", + "query_log_filtered": "Фільтровано з {{filter}}", + "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": "Ви дійсно хочете змінити час зберігання журналу? Якщо ви зменшите значення, деякі дані будуть втрачені", + "anonymize_client_ip": "Анонімізація IP-адреси клієнта", + "anonymize_client_ip_desc": "Не зберігайте повну IP-адресу клієнта в журналах і статистиці", + "dns_config": "Конфігурація DNS-сервера", + "dns_cache_config": "Конфігурація кешу DNS", + "dns_cache_config_desc": "Тут ви можете налаштувати кеш DNS", + "blocking_mode": "Режим блокування", + "default": "Типовий", + "nxdomain": "NXDOMAIN", + "refused": "REFUSED", + "null_ip": "Нульовий IP", + "custom_ip": "Власний IP", + "blocking_ipv4": "Блокування IPv4", + "blocking_ipv6": "Блокування IPv6", + "dnscrypt": "DNSCrypt", + "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": "Різні клієнти можуть бути розпізнані завдяки спеціальному ідентифікатору. Докладніше про ідентифікацію клієнтів.", + "download_mobileconfig_doh": "Завантажити .mobileconfig для DNS-over-HTTPS", + "download_mobileconfig_dot": "Завантажити .mobileconfig для DNS-over-TLS", + "download_mobileconfig": "Завантажити файл конфігурації", + "plain_dns": "Звичайний DNS", + "form_enter_rate_limit": "Уведіть обмеження швидкості", + "rate_limit": "Обмеження швидкості", + "edns_enable": "Увімкнути відправку EDNS Client Subnet", + "edns_cs_desc": "Надсилати підмережі клієнтів на DNS-сервери.", + "rate_limit_desc": "Кількість запитів в секунду, які може робити один клієнт. Встановлене значення «0» означатиме необмежену кількість.", + "blocking_ipv4_desc": "IP-адреса, яку потрібно видати для заблокованого A запиту", + "blocking_ipv6_desc": "IP-адреса, яку потрібно видати для заблокованого АААА запиту", + "blocking_mode_default": "Усталено: відповідь із нульовою IP-адресою (0.0.0.0 для A; :: для AAAA), якщо заблоковано правилом у Adblock-стилі; відповідь зазначеною у правилі IP-адресою, якщо заблокувано правилом у hosts-стилі", + "blocking_mode_refused": "ВІДМОВЛЕНО: Відповісти з кодом ВІДМОВЛЕНО", + "blocking_mode_nxdomain": "NXDOMAIN: Відповісти з кодом NXDOMAIN", + "blocking_mode_null_ip": "Нульовий IP: Відповісти з нульовою IP-адресою (0.0.0.0 для A; :: для AAAA)", + "blocking_mode_custom_ip": "Спеціальна IP-адреса: Відповісти із вручну встановленою 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": "Відомі трекери", + "install_welcome_title": "Вітаємо в AdGuard Home!", + "install_welcome_desc": "AdGuard Home — це мережевий DNS-сервер, що блокує рекламу та відстеження. Його мета — надати вам контроль над усією мережею та всіма пристроями в ній без потреби використання програми на стороні клієнта.", + "install_settings_title": "Веб-інтерфейс адміністратора", + "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": "Усі інтерфейси", + "install_auth_title": "Авторизація", + "install_auth_desc": "Необходно налаштувати автентифікацію паролем для вебінтерфейсу AdGuard Home. Навіть якщо він доступний лише у вашій локальній мережі, важливо захистити його від необмеженого доступу.\n\nДолжна быть настроена аутентификация паролем для веб-интерфейса AdGuard Home. Даже если он доступен только в вашей локальной сети, важно защитить его от неограниченного доступа.", + "install_auth_username": "Ім'я користувача", + "install_auth_password": "Пароль", + "install_auth_confirm": "Підтвердьте пароль", + "install_auth_username_enter": "Уведіть ім'я користувача", + "install_auth_password_enter": "Введіть пароль", + "install_step": "Крок", + "install_devices_title": "Налаштуйте ваші пристрої", + "install_devices_desc": "Щоби розпочати використовувати AdGuard Home, вам потрібно налаштувати ваші пристої для його використання.", + "install_submit_title": "Вітаємо!", + "install_submit_desc": "Процедура налаштування завершена і тепер все готово, аби почати користуватися AdGuard Home.", + "install_devices_router": "Роутер", + "install_devices_router_desc": "Це налаштування буде автоматично охоплювати всі пристрої, що під'єднано до домашнього маршрутизатора. Вам не потрібно буде налаштовувати кожен з них вручну.", + "install_devices_address": "DNS-сервер AdGuard Home прослуховує наступні адреси", + "install_devices_router_list_1": "Відкрийте налаштування маршрутизатора. Зазвичай ви можете отримати до нього доступ із браузера за допомогою URL-адреси, наприклад, http://192.168.0.1/ або http://192.168.1.1/. Можливо, треба буде ввести пароль. Якщо ви його не знаєте, часто можна скинути пароль, натиснувши кнопку на самому маршрутизаторі. Для деяких маршрутизаторів потрібна спеціальна програма, яка в такому випадку повинна бути вже встановлена на вашому комп’ютері чи телефоні.", + "install_devices_router_list_2": "Знайдіть налаштування DHCP/DNS. Шукайте літери DNS поруч із полем, в яке можна ввести два або три набори чисел, кожен з яких розбитий на чотири групи від однієї до трьох цифр.", + "install_devices_router_list_3": "Введіть туди адреси вашого домашнього сервера AdGuard.", + "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_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.", + "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": "На головному екрані меню Android торкніться Налаштування.", + "install_devices_android_list_2": "У меню торкніться Wi-Fi. З'явиться екран із переліком усіх доступних мереж (неможливо встановити власний DNS для мобільного з'єднання).", + "install_devices_android_list_3": "Довго натисніть на мережу, до якої ви приєднані, та торкніться «Змінити мережу».", + "install_devices_android_list_4": "На деяких пристроях вам може знадобитися встановити прапорець Додатково, щоб побачити подальші налаштування. Щоб відредагувати налаштування DNS для Android, вам потрібно буде переключити налаштування IP з DHCP на статичні.", + "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_4": "У полі DNS введіть адреси вашого сервера AdGuard Home.", + "get_started": "Розпочати", + "next": "Наступні", + "open_dashboard": "Відкрити інформаційну панель", + "install_saved": "Збережено успішно", + "encryption_title": "Шифрування", + "encryption_desc": "Підтримка шифрування (HTTPS/TLS) як для DNS так і для веб-інтерфейсу адміністратора", + "encryption_config_saved": "Конфігурацію шифрування збережено", + "encryption_server": "Назва сервера", + "encryption_server_enter": "Введіть ваше доменне ім'я", + "encryption_server_desc": "Для використання HTTPS вам потрібно ввести назву сервера, який відповідає вашому SSL-сертифікату або сертифікату з підтримкою піддоменів. Якщо значення не вказано, то сервер буде приймати TLS-з'єднання для будь-якого домену.", + "encryption_redirect": "Автоматично перенаправляти на HTTPS", + "encryption_redirect_desc": "Якщо встановлено, AdGuard Home автоматично перенаправить вас з HTTP на адреси HTTPS.", + "encryption_https": "Порт HTTPS", + "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_desc": "Якщо цей порт налаштовано, AdGuard Home запустить на цьому порту сервер DNS-over-QUIC. Це експериментально і може бути ненадійним. Крім того, зараз не так багато клієнтів, які це підтримують.", + "encryption_certificates": "Сертифікати", + "encryption_certificates_desc": "Для використання шифрування потрібно надати дійсний ланцюжок сертифікатів SSL для вашого домену. Ви можете отримати безкоштовний сертифікат на <0>{{link}} або придбати його в одному з надійних Центрів Сертифікації.", + "encryption_certificates_input": "Скопіюйте/вставте сюди свої кодовані PEM сертифікати.", + "encryption_status": "Статус", + "encryption_expire": "Закічнується", + "encryption_key": "Приватний ключ", + "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_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": "Пароль не співпадає", + "reset_settings": "Скинути налаштування", + "update_announcement": "AdGuard Home {{version}} тепер доступний! <0>Докладніше.", + "setup_guide": "Посібник з налаштування", + "dns_addresses": "DNS-адреси", + "dns_start": "DNS-сервер запускається", + "dns_status_error": "Помилка перевірки стану сервера DNS", + "down": "Недоступний", + "fix": "Виправити", + "dns_providers": "<0>Список відомих DNS-провайдерів на вибір.", + "update_now": "Оновити зараз", + "update_failed": "Помилка автоматичного оновлення. Будь ласка, виконайте ці кроки аби оновити вручну.", + "processing_update": "Зачекайте будь ласка, AdGuard Home оновлюється", + "clients_title": "Клієнти", + "clients_desc": "Налаштуйте пристрої, під'єднані до AdGuard Home", + "settings_global": "Загальні", + "settings_custom": "Власні", + "table_client": "Клієнт", + "table_name": "Назва", + "save_btn": "Зберегти", + "client_add": "Додати Клієнта", + "client_new": "Новий Клієнт", + "client_edit": "Редагувати Клієнта", + "client_identifier": "Ідентифікатор", + "ip_address": "IP-адреса", + "client_identifier_desc": "Клієнтів можна ідентифікувати за IP-, CIDR-, MAC-адресами або ж за спеціальним клієнтським ідентифікатором (можливий для DoT, DoH та DoQ). <0>Докладніше про ідентифікацію клієнтів.", + "form_enter_ip": "Введіть IP", + "form_enter_subnet_ip": "Введіть IP-адресу в підмережі «{{cidr}}»", + "form_enter_mac": "Введіть MAC", + "form_enter_id": "Введіть ідентифікатор", + "form_add_id": "Додати ідентифікатор", + "form_client_name": "Введіть ім'я клієнта", + "name": "Ім'я", + "client_global_settings": "Використати загальні налаштування", + "client_deleted": "Клієнта «{{key}}» успішно видалено", + "client_added": "Клієнта «{{key}}» успішно додано", + "client_updated": "Клієнта «{{key}}» успішно оновлено", + "clients_not_found": "Клієнтів не знайдено", + "client_confirm_delete": "Ви впевнені, що хочете видалити клієнта «{{key}}»?", + "list_confirm_delete": "Ви впевнені, що хочете видалити цей список?", + "auto_clients_title": "Клієнти (поза налаштуванням)", + "auto_clients_desc": "Дані про клієнтів, які використовують AdGuard Home, але не зберігаються в конфігурації", + "access_title": "Налаштування доступу", + "access_desc": "Тут ви можете налаштувати правила доступу для DNS-сервера AdGuard Home.", + "access_allowed_title": "Дозволені клієнти", + "access_allowed_desc": "Перелік CIDR-, IP-адрес та клієнтських ідентифікаторів. Якщо налаштовано, AdGuard Home прийматиме запити лише від цих клієнтів.", + "access_disallowed_title": "Заборонені клієнти", + "access_disallowed_desc": "Перелік CIDR-, IP-адрес та клієнтських ідентифікаторів. Якщо налаштовано, AdGuard Home буде скасовувати запити від цих клієнтів. Проте якщо налаштовано список дозволених клієнтів, то це поле проігнорується.", + "access_blocked_title": "Заборонені домени", + "access_blocked_desc": "Не плутайте з фільтрами. AdGuard Home буде ігнорувати DNS-запити з цими доменами, такі запити навіть не будуть записані до журналу. Ви можете вказати точні доменні імена, замінні знаки та правила фільтрування URL-адрес, наприклад, 'example.org', '*.example.org' або '||example.org^' відповідно.", + "access_settings_saved": "Налаштування доступу успішно збережено", + "updates_checked": "Оновлення успішно перевірені", + "updates_version_equal": "AdGuard Home останньої версії", + "check_updates_now": "Перевірити наявність оновлень", + "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>Ось перелік програмного забезпечення, яке можете використати.", + "setup_dns_privacy_4": "На пристрої iOS 14 або macOS Big Sur ви можете завантажити спеціальний файл .mobileconfig, який додасть до налаштувань DNS сервери DNS-over-HTTPS або DNS-over-TLS.", + "setup_dns_privacy_android_1": "Android 9 підтримує DNS-over-TLS. Щоб його налаштувати, перейдіть у Налаштування → Мережа та Інтернет → Додатково → Приватний DNS і введіть там свій домен.", + "setup_dns_privacy_android_2": "<0>AdGuard для Android підтримує <1>DNS-over-HTTPS і <1>DNS-over-TLS.", + "setup_dns_privacy_android_3": "<0>Intra додає підтримку <1>DNS-over-HTTPS для Android.", + "setup_dns_privacy_ios_1": "<0>DNSCloak підтримує <1>DNS-over-HTTPS, але для того, щоб налаштувати його на використання власного сервера, вам потрібно буде створити для нього <2>штамп DNS.", + "setup_dns_privacy_ios_2": "<0>AdGuard для iOS підтримує налаштування <1>DNS over-HTTPS і <1>DNS over over TLS.", + "setup_dns_privacy_other_title": "Інші реалізації", + "setup_dns_privacy_other_1": "Сам AdGuard Home може слугувати захищеним клієнтом DNS на будь-якій платформі.", + "setup_dns_privacy_other_2": "<0>dnsproxy підтримує всі відомі захищені протоколи DNS.", + "setup_dns_privacy_other_3": "<0>dnscrypt-proxy підтримує <1>DNS-over-HTTPS.", + "setup_dns_privacy_other_4": "<0>Mozilla Firefox підтримує <1>DNS-over-HTTPS.", + "setup_dns_privacy_other_5": "Ви знайдете більше реалізацій <0>тут та <1>тут.", + "setup_dns_privacy_ioc_mac": "Конфігурація для iOS та macOS", + "setup_dns_notice": "Для використання <1>DNS-over-HTTPS або <1>DNS-over-TLS, вам потрібно <0>налаштувати Шифрування в налаштуваннях AdGuard Home.", + "rewrite_added": "Перезапис DNS для «{{key}}» успішно додано", + "rewrite_deleted": "Перезапис DNS для «{{key}}» успішно видалено", + "rewrite_add": "Додати перезапис DNS", + "rewrite_not_found": "Перезаписів DNS не знайдено", + "rewrite_confirm_delete": "Ви впевнені, що хочете видалити перезапис DNS для «{{key}}»?", + "rewrite_desc": "Дозволяє легко налаштувати власну відповідь DNS для певного доменного імені.", + "rewrite_applied": "Застосовано правило перезапису", + "rewrite_hosts_applied": "Перезаписано правилом hosts-файлу", + "dns_rewrites": "DNS перезаписи", + "form_domain": "Введіть доменне ім’я або підстановний знак", + "form_answer": "Введіть IP-адресу або доменне ім'я", + "form_error_domain_format": "Неправильний формат домену", + "form_error_answer_format": "Неправильний формат відопвіді", + "configure": "Налаштувати", + "main_settings": "Головні налаштування", + "block_services": "Блокувати конкретні сервіси", + "blocked_services": "Заблоковані сервіси", + "blocked_services_desc": "Дозволяє швидко блокувати популярні сайти та сервіси.", + "blocked_services_saved": "Заблоковані сервіси успішно збережено", + "blocked_services_global": "Використовувати глобально заблоковані сервіси", + "blocked_service": "Заблокований сервіс", + "block_all": "Блокувати все", + "unblock_all": "Розблокувати все", + "encryption_certificate_path": "Шлях до сертифіката", + "encryption_private_key_path": "Шлях до приватного ключа", + "encryption_certificates_source_path": "Вказати шлях до сертифікату", + "encryption_certificates_source_content": "Вставити вміст сертифікату", + "encryption_key_source_path": "Вказати приватний ключ", + "encryption_key_source_content": "Вставити вміст приватного ключа", + "stats_params": "Налаштування статистики", + "config_successfully_saved": "Конфігурацію успішно збережено", + "interval_6_hour": "6 годин", + "interval_24_hour": "24 години", + "interval_days": "{{count}} день", + "interval_days_plural": "{{count}} днів", + "domain": "Домен", + "punycode": "Punycode", + "answer": "Відповідь", + "filter_added_successfully": "Фільтр успішно додано", + "filter_removed_successfully": "Фільтр успішно видалено", + "filter_updated": "Фільтр успішно оновлено", + "statistics_configuration": "Налаштування статистики", + "statistics_retention": "Збереження статистики", + "statistics_retention_desc": "Якщо зменшити значення інтервалу, деякі дані будуть втрачені", + "statistics_clear": "Очистити статистику", + "statistics_clear_confirm": "Ви впевнені, що хочете очистити статистику?", + "statistics_retention_confirm": "Ви впевнені, що хочете змінити тривалість статистики? Якщо зменшити значення інтервалу, деякі дані будуть втрачені", + "statistics_cleared": "Статистика успішно очищена", + "statistics_enable": "Увімкнути статистику", + "interval_hours": "{{count}} година", + "interval_hours_plural": "{{count}} годин(и)", + "filters_configuration": "Конфігурація фільтрів", + "filters_enable": "Увімкнути фільтри", + "filters_interval": "Інтервал оновлення фільтрів", + "disabled": "Вимкнено", + "username_label": "Ім'я користувача", + "username_placeholder": "Уведіть ім'я користувача", + "password_label": "Пароль", + "password_placeholder": "Введіть пароль", + "sign_in": "Увійти", + "sign_out": "Вийти", + "forgot_password": "Забули пароль?", + "forgot_password_desc": "Виконайте <0>ці кроки, щоб створити новий пароль для свого імені користувача.", + "location": "Місцезнаходження", + "orgname": "Назва організації", + "netname": "Назва мережі", + "network": "Мережа", + "descr": "Опис", + "whois": "Whois", + "filtering_rules_learn_more": "<0>Як створити власні списки блокування.", + "blocked_by_response": "У відповідь заблоковано по CNAME або IP", + "blocked_by_cname_or_ip": "Заблоковано по CNAME або IP", + "try_again": "Спробувати знову", + "domain_desc": "Введіть доменне ім’я або підстановний знак, який потрібно переписати.", + "example_rewrite_domain": "перепишіть відповіді лише для цього доменного імені.", + "example_rewrite_wildcard": "перепишіть відповіді для всіх субдоменів <0>example.org.", + "rewrite_ip_address": "IP-адреса: використайте цю IP-адресу у відповіді A або AAAA", + "rewrite_domain_name": "Доменне ім’я: додайте запис CNAME", + "rewrite_A": "<0>A: спеціальне значення, зберігайте <0>A записи із вищого сервера", + "rewrite_AAAA": "<0>AAAA: спеціальне значення, зберігайте <0>AAAA записи із вищого сервера", + "disable_ipv6": "Вимкнути вирішення IPv6-адрес", + "disable_ipv6_desc": "Ігнорувати DNS-запити для IPv6-адрес (тип AAAA).", + "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_result": "В результаті буде усталено, що усі DNS-запити вашої системи будуть опрацьовані AdGuard Home.", + "tags_title": "Теги", + "tags_desc": "Ви можете вибрати теги, які відповідають клієнту. Теги можна використати в правилах фільтрування, щоб точніше застосовувати їх. <0>Докладніше", + "form_select_tags": "Виберіть теги клієнта", + "check_title": "Перевірте фільтрування", + "check_desc": "Перевірте чи фільтрується назва вузла", + "check": "Перевірити", + "form_enter_host": "Введіть назву вузла", + "filtered_custom_rules": "Відфільтровано за власними правилами фільтрування", + "choose_from_list": "Виберіть зі списку", + "add_custom_list": "Додати власний список", + "host_whitelisted": "Вузол додано до списку дозволів", + "check_ip": "IP адреси: {{ip}}", + "check_cname": "CNAME: {{cname}}", + "check_reason": "Причина: {{reason}}", + "check_service": "Назва сервісу: {{service}}", + "service_name": "Назва сервісу", + "check_not_found": "Не знайдено у ваших списках фільтрів", + "client_confirm_block": "Ви впевнені, що хочете заблокувати клієнта «{{ip}}»?", + "client_confirm_unblock": "Ви впевнені, що хочете розблокувати клієнт «{{ip}}»?", + "client_blocked": "Клієнта «{{ip}}» успішно заблоковано", + "client_unblocked": "Клієнта «{{ip}}» успішно розблоковано", + "static_ip": "Статична IP-адреса", + "static_ip_desc": "AdGuard Home - це сервер, тому йому потрібна статична IP-адреса для нормальної роботи. В іншому випадку, в певний момент, ваш маршрутизатор може призначити іншу IP-адресу цьому пристрою.", + "set_static_ip": "Встановити статичну IP-адресу", + "install_static_ok": "Гарні новини! Статична IP-адреса вже налаштована", + "install_static_error": "AdGuard Home не може налаштувати його автоматично для цього мережевого інтерфейсу. Будь ласка, шукайте інструкції як це зробити вручну.", + "install_static_configure": "AdGuard Home виявив, що використовується динамічна IP-адреса — <0>{{ip}}. Ви хочете встановити її як свою статичну адресу?", + "confirm_static_ip": "AdGuard Home налаштує {{ip}} як вашу статичну IP-адресу. Ви хочете продовжити?", + "list_updated": "{{count}} список оновлено", + "list_updated_plural": "{{count}} списки оновлено", + "dnssec_enable": "Увімкнути 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_threats": "Заблоковано загроз", + "allowed": "Дозволено", + "filtered": "Відфільтровано", + "rewritten": "Перезаписано", + "safe_search": "Безпечний пошук", + "blocklist": "Список блокування", + "milliseconds_abbreviation": "мс", + "cache_size": "Розмір кешу", + "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": "Розширити короткі значення time-to-live (секунди) отримані від основного сервера під час кешування відповідей DNS", + "cache_ttl_max_override_desc": "Встановіть максимальне значення time-to-live (секунди) для записів у кеші DNS", + "ttl_cache_validation": "Мінімальне значення TTL кеш-пам'яті має бути меншим або рівним максимальному значенню", + "cache_optimistic": "Оптимістичне кешування", + "cache_optimistic_desc": "AdGuard Home буде відповідати з кешу, навіть якщо відповіді в ньому застарілі, а також спробує оновити їх.", + "filter_category_general": "Загальні", + "filter_category_security": "Безпека", + "filter_category_regional": "Регіональні", + "filter_category_other": "Інші", + "filter_category_general_desc": "Списки, які блокують відстеження та рекламу на більшості пристроїв", + "filter_category_security_desc": "Фільтри, які спеціалізуються на блокуванні зловмисних програм, фішингу та шахрайських доменів", + "filter_category_regional_desc": "Списки, орієнтовані на регіональні оголошення та сервери відстеження", + "filter_category_other_desc": "Інші списки блокувань", + "setup_config_to_enable_dhcp_server": "Налаштуйте конфігурацію для увімкнення DHCP-сервера", + "original_response": "Оригінальна відповідь", + "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}}» ВИМКНЕ режим списку дозволів.", + "experimental": "Експериментальний", + "use_saved_key": "Використати раніше збережений ключ" +} diff --git a/client/src/i18n.js b/client/src/i18n.js index 7e3ffc19..8f0e46ea 100644 --- a/client/src/i18n.js +++ b/client/src/i18n.js @@ -12,6 +12,7 @@ import de from './__locales/de.json'; import en from './__locales/en.json'; import es from './__locales/es.json'; import fa from './__locales/fa.json'; +import fi from './__locales/fi.json'; import fr from './__locales/fr.json'; import hr from './__locales/hr.json'; import hu from './__locales/hu.json'; @@ -33,6 +34,7 @@ import srCS from './__locales/sr-cs.json'; import sv from './__locales/sv.json'; import th from './__locales/th.json'; import tr from './__locales/tr.json'; +import uk from './__locales/uk.json'; import vi from './__locales/vi.json'; import zhCN from './__locales/zh-cn.json'; import zhHK from './__locales/zh-hk.json'; @@ -40,108 +42,42 @@ import zhTW from './__locales/zh-tw.json'; import { setHtmlLangAttr } from './helpers/helpers'; const resources = { - en: { - translation: en, - }, - enUS: { - translation: en, - }, - vi: { - translation: vi, - }, - ru: { - translation: ru, - }, - es: { - translation: es, - }, - fr: { - translation: fr, - }, - ja: { - translation: ja, - }, - sv: { - translation: sv, - }, - 'pt-br': { - translation: ptBR, - }, - 'zh-hk': { - translation: zhHK, - }, - 'zh-tw': { - translation: zhTW, - }, - bg: { - translation: bg, - }, - be: { - translation: be, - }, - 'zh-cn': { - translation: zhCN, - }, - cs: { - translation: cs, - }, - da: { - translation: da, - }, - de: { - translation: de, - }, - id: { - translation: id, - }, - it: { - translation: it, - }, - ko: { - translation: ko, - }, - no: { - translation: no, - }, - nl: { - translation: nl, - }, - pl: { - translation: pl, - }, - 'pt-pt': { - translation: ptPT, - }, - sk: { - translation: sk, - }, - sl: { - translation: sl, - }, - tr: { - translation: tr, - }, - 'sr-cs': { - translation: srCS, - }, - hr: { - translation: hr, - }, - hu: { - translation: hu, - }, - fa: { - translation: fa, - }, - th: { - translation: th, - }, - ro: { - translation: ro, - }, - 'si-lk': { - translation: siLk, - }, + be: { translation: be }, + bg: { translation: bg }, + cs: { translation: cs }, + da: { translation: da }, + de: { translation: de }, + en: { translation: en }, + 'en-us': { translation: en }, + es: { translation: es }, + fa: { translation: fa }, + fi: { translation: fi }, + fr: { translation: fr }, + hr: { translation: hr }, + hu: { translation: hu }, + id: { translation: id }, + it: { translation: it }, + ja: { translation: ja }, + ko: { translation: ko }, + nl: { translation: nl }, + no: { translation: no }, + pl: { translation: pl }, + 'pt-br': { translation: ptBR }, + 'pt-pt': { translation: ptPT }, + ro: { translation: ro }, + ru: { translation: ru }, + 'si-lk': { translation: siLk }, + sk: { translation: sk }, + sl: { translation: sl }, + 'sr-cs': { translation: srCS }, + sv: { translation: sv }, + th: { translation: th }, + tr: { translation: tr }, + uk: { translation: uk }, + vi: { translation: vi }, + 'zh-cn': { translation: zhCN }, + 'zh-hk': { translation: zhHK }, + 'zh-tw': { translation: zhTW }, }; const availableLanguages = Object.keys(LANGUAGES); diff --git a/internal/home/i18n.go b/internal/home/i18n.go index 26b8a3ac..d46bd6c6 100644 --- a/internal/home/i18n.go +++ b/internal/home/i18n.go @@ -10,7 +10,7 @@ import ( "github.com/AdguardTeam/golibs/stringutil" ) -// TODO(a.garipov): Get rid of a global variable? +// TODO(a.garipov): Get rid of a global or generate from .twosky.json. var allowedLanguages = stringutil.NewSet( "be", "bg", @@ -20,6 +20,7 @@ var allowedLanguages = stringutil.NewSet( "en", "es", "fa", + "fi", "fr", "hr", "hu", @@ -41,6 +42,7 @@ var allowedLanguages = stringutil.NewSet( "sv", "th", "tr", + "uk", "vi", "zh-cn", "zh-hk", From 9c8e087544d0497f1f4ec05d7fcabcb67c00ceff Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Mon, 15 Nov 2021 17:42:10 +0300 Subject: [PATCH 022/135] Pull request: 3842 ptr filtering Merge in DNS/adguard-home from 3842-fix-ptr-restrict to master Updates #3842. Squashed commit of the following: commit 77bbec41c5238f8fcb0d2bb8d11910d1ac521fcd Author: Eugene Burkov Date: Mon Nov 15 17:34:14 2021 +0300 dnsforward: imp docs commit c637276b5a53f5301387b7dc3035e265d0bc9418 Author: Eugene Burkov Date: Mon Nov 15 15:41:39 2021 +0300 dnsforward: fix local ptr blocking --- internal/dnsforward/dns.go | 64 +++++++++++++++---------------- internal/dnsforward/stats.go | 3 +- internal/dnsforward/stats_test.go | 15 ++++---- 3 files changed, 39 insertions(+), 43 deletions(-) diff --git a/internal/dnsforward/dns.go b/internal/dnsforward/dns.go index 204995fb..ec27dfd0 100644 --- a/internal/dnsforward/dns.go +++ b/internal/dnsforward/dns.go @@ -16,9 +16,6 @@ import ( // To transfer information between modules type dnsContext struct { - // TODO(a.garipov): Remove this and rewrite processors to be methods of - // *Server instead. - srv *Server proxyCtx *proxy.DNSContext // setts are the filtering settings for the client. setts *filtering.Settings @@ -28,7 +25,8 @@ type dnsContext struct { // response is modified by filters. origResp *dns.Msg // unreversedReqIP stores an IP address obtained from PTR request if it - // was successfully parsed. + // parsed successfully and belongs to one of locally-served IP ranges as per + // RFC 6303. unreversedReqIP net.IP // err is the error returned from a processing function. err error @@ -69,7 +67,6 @@ const ( // 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{ - srv: s, proxyCtx: d, result: &filtering.Result{}, startTime: time.Now(), @@ -84,7 +81,7 @@ func (s *Server) handleDNSRequest(_ *proxy.Proxy, d *proxy.DNSContext) error { // appropriate handler. mods := []modProcessFunc{ s.processRecursion, - processInitial, + s.processInitial, s.processDetermineLocal, s.processInternalHosts, s.processRestrictLocal, @@ -93,10 +90,10 @@ func (s *Server) handleDNSRequest(_ *proxy.Proxy, d *proxy.DNSContext) error { s.processFilteringBeforeRequest, s.processLocalPTR, s.processUpstream, - processDNSSECAfterResponse, - processFilteringAfterResponse, + s.processDNSSECAfterResponse, + s.processFilteringAfterResponse, s.ipset.process, - processQueryLogsAndStats, + s.processQueryLogsAndStats, } for _, process := range mods { r := process(ctx) @@ -135,8 +132,7 @@ func (s *Server) processRecursion(dctx *dnsContext) (rc resultCode) { } // Perform initial checks; process WHOIS & rDNS -func processInitial(ctx *dnsContext) (rc resultCode) { - s := ctx.srv +func (s *Server) processInitial(ctx *dnsContext) (rc resultCode) { d := ctx.proxyCtx if s.conf.AAAADisabled && d.Req.Question[0].Qtype == dns.TypeAAAA { _ = proxy.CheckDisabledAAAARequest(d, true) @@ -155,6 +151,9 @@ func processInitial(ctx *dnsContext) (rc resultCode) { return resultCodeFinish } + ctx.protectionEnabled = s.conf.ProtectionEnabled + ctx.setts = s.getClientRequestFilteringSettings(ctx) + return resultCodeSuccess } @@ -339,10 +338,16 @@ 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) && !ctx.isLocalClient { - log.Debug("dns: %q requests for internal ip", d.Addr) + // 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) { + log.Debug("dns: addr %s is not from locally-served network", ip) + + return resultCodeSuccess + } + + if !ctx.isLocalClient { + log.Debug("dns: %q requests an internal ip", d.Addr) d.Res = s.genNXDomain(req) // Do not even put into query log. @@ -352,13 +357,13 @@ func (s *Server) processRestrictLocal(ctx *dnsContext) (rc resultCode) { // Do not perform unreversing ever again. ctx.unreversedReqIP = ip - // Disable redundant filtering. - filterSetts := s.getClientRequestFilteringSettings(ctx) - filterSetts.ParentalEnabled = false - filterSetts.SafeBrowsingEnabled = false - filterSetts.SafeSearchEnabled = false - filterSetts.ServicesRules = nil - ctx.setts = filterSetts + // There is no need to filter request from external addresses since this + // code is only executed when the request is for locally-served ARPA + // hostname so disable redundant filters. + ctx.setts.ParentalEnabled = false + ctx.setts.SafeBrowsingEnabled = false + ctx.setts.SafeSearchEnabled = false + ctx.setts.ServicesRules = nil // Nothing to restrict. return resultCodeSuccess @@ -475,16 +480,10 @@ func (s *Server) processFilteringBeforeRequest(ctx *dnsContext) (rc resultCode) s.serverLock.RLock() defer s.serverLock.RUnlock() - ctx.protectionEnabled = s.conf.ProtectionEnabled - if s.dnsFilter == nil { return resultCodeSuccess } - if ctx.setts == nil { - ctx.setts = s.getClientRequestFilteringSettings(ctx) - } - var err error if ctx.result, err = s.filterDNSRequest(ctx); err != nil { ctx.err = err @@ -555,11 +554,11 @@ func (s *Server) processUpstream(ctx *dnsContext) (rc resultCode) { } // Process DNSSEC after response from upstream server -func processDNSSECAfterResponse(ctx *dnsContext) (rc resultCode) { +func (s *Server) processDNSSECAfterResponse(ctx *dnsContext) (rc resultCode) { d := ctx.proxyCtx - if !ctx.responseFromUpstream || // don't process response if it's not from upstream servers - !ctx.srv.conf.EnableDNSSEC { + // Don't process response if it's not from upstream servers. + if !ctx.responseFromUpstream || !s.conf.EnableDNSSEC { return resultCodeSuccess } @@ -601,8 +600,7 @@ func processDNSSECAfterResponse(ctx *dnsContext) (rc resultCode) { } // Apply filtering logic after we have received response from upstream servers -func processFilteringAfterResponse(ctx *dnsContext) (rc resultCode) { - s := ctx.srv +func (s *Server) processFilteringAfterResponse(ctx *dnsContext) (rc resultCode) { d := ctx.proxyCtx switch res := ctx.result; res.Reason { diff --git a/internal/dnsforward/stats.go b/internal/dnsforward/stats.go index 1714563f..b7760c68 100644 --- a/internal/dnsforward/stats.go +++ b/internal/dnsforward/stats.go @@ -13,9 +13,8 @@ import ( ) // Write Stats data and logs -func processQueryLogsAndStats(ctx *dnsContext) (rc resultCode) { +func (s *Server) processQueryLogsAndStats(ctx *dnsContext) (rc resultCode) { elapsed := time.Since(ctx.startTime) - s := ctx.srv pctx := ctx.proxyCtx shouldLog := true diff --git a/internal/dnsforward/stats_test.go b/internal/dnsforward/stats_test.go index 92985fd4..22780ef2 100644 --- a/internal/dnsforward/stats_test.go +++ b/internal/dnsforward/stats_test.go @@ -160,6 +160,12 @@ func TestProcessQueryLogsAndStats(t *testing.T) { require.NoError(t, err) for _, tc := range testCases { + ql := &testQueryLog{} + st := &testStats{} + srv := &Server{ + queryLog: ql, + stats: st, + } t.Run(tc.name, func(t *testing.T) { req := &dns.Msg{ Question: []dns.Question{{ @@ -173,14 +179,7 @@ func TestProcessQueryLogsAndStats(t *testing.T) { Addr: tc.addr, Upstream: ups, } - - ql := &testQueryLog{} - st := &testStats{} dctx := &dnsContext{ - srv: &Server{ - queryLog: ql, - stats: st, - }, proxyCtx: pctx, startTime: time.Now(), result: &filtering.Result{ @@ -189,7 +188,7 @@ func TestProcessQueryLogsAndStats(t *testing.T) { clientID: tc.clientID, } - code := processQueryLogsAndStats(dctx) + code := srv.processQueryLogsAndStats(dctx) assert.Equal(t, tc.wantCode, code) assert.Equal(t, tc.wantLogProto, ql.lastParams.ClientProto) assert.Equal(t, tc.wantStatClient, st.lastEntry.Client) From 4a4b4715ca3b028c3efc9169f949f9a65bf5364c Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Tue, 16 Nov 2021 16:16:38 +0300 Subject: [PATCH 023/135] Pull request: 3815 fix hosts container rewrites Merge in DNS/adguard-home from 3815-weird-rewrites to master Updates #3815. Squashed commit of the following: commit d217db9f5632a3fba5a37fc6ac7b90b8d97fe1cf Merge: 006b67b9 9c8e0875 Author: Eugene Burkov Date: Tue Nov 16 16:08:41 2021 +0300 Merge branch 'master' into 3815-weird-rewrites commit 006b67b93199f3818396ad782d90aba32da74092 Author: Eugene Burkov Date: Tue Nov 16 15:49:50 2021 +0300 filtering: fix doc commit 7ffafcedc7275b007977a539bd63ab20a758eecc Author: Eugene Burkov Date: Tue Nov 16 14:17:41 2021 +0300 all: imp hosts container more commit b60deddec988762c61060cabad1340a37b154dbb Author: Eugene Burkov Date: Sun Nov 14 19:06:16 2021 +0300 all: log changes commit 37c76f478e0db90b3840a931d79465eefeea7945 Author: Eugene Burkov Date: Sun Nov 14 18:14:21 2021 +0300 aghnet: imp hosts container commit 187251c364f6d23ba7166906b5394a0299657b76 Author: Eugene Burkov Date: Sun Nov 14 16:16:41 2021 +0300 all: merge hosts container more --- CHANGELOG.md | 3 + internal/aghnet/hostscontainer.go | 152 ++++++++++++++++++------- internal/aghnet/hostscontainer_test.go | 58 ++++++---- internal/dnsforward/filter.go | 22 +--- internal/filtering/dnsrewrite.go | 13 +-- internal/filtering/filtering.go | 44 +++---- internal/home/clients.go | 11 +- 7 files changed, 179 insertions(+), 124 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eed5f0f1..efb91061 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -122,6 +122,8 @@ In this release, the schema version has changed from 10 to 12. ### Fixed +- Incorrect `$dnsrewrite` results 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]). @@ -219,6 +221,7 @@ In this release, the schema version has changed from 10 to 12. [#3655]: https://github.com/AdguardTeam/AdGuardHome/issues/3655 [#3707]: https://github.com/AdguardTeam/AdGuardHome/issues/3707 [#3744]: https://github.com/AdguardTeam/AdGuardHome/issues/3744 +[#3815]: https://github.com/AdguardTeam/AdGuardHome/issues/3815 diff --git a/internal/aghnet/hostscontainer.go b/internal/aghnet/hostscontainer.go index 852bf299..67aad623 100644 --- a/internal/aghnet/hostscontainer.go +++ b/internal/aghnet/hostscontainer.go @@ -17,12 +17,13 @@ import ( "github.com/AdguardTeam/golibs/stringutil" "github.com/AdguardTeam/urlfilter" "github.com/AdguardTeam/urlfilter/filterlist" + "github.com/AdguardTeam/urlfilter/rules" "github.com/miekg/dns" ) // DefaultHostsPaths returns the slice of paths default for the operating system // to files and directories which are containing the hosts database. The result -// is intended to use within fs.FS so the initial slash is omitted. +// is intended to be used within fs.FS so the initial slash is omitted. func DefaultHostsPaths() (paths []string) { return defaultHostsPaths() } @@ -42,9 +43,10 @@ type HostsContainer struct { // engine serves rulesStrg. engine *urlfilter.DNSEngine - // Updates is the channel for receiving updated hosts. The receivable map's - // values has a type of slice of strings. + // updates is the channel for receiving updated hosts. updates chan *netutil.IPMap + // last is the set of hosts that was cached within last detected change. + last *netutil.IPMap // fsys is the working file system to read hosts files from. fsys fs.FS @@ -81,6 +83,7 @@ func NewHostsContainer( hc = &HostsContainer{ engLock: &sync.RWMutex{}, updates: make(chan *netutil.IPMap, 1), + last: &netutil.IPMap{}, fsys: fsys, w: w, patterns: patterns, @@ -127,17 +130,20 @@ func (hc *HostsContainer) MatchRequest( hc.engLock.RLock() defer hc.engLock.RUnlock() - return hc.engine.MatchRequest(req) + res, ok = hc.engine.MatchRequest(req) + + return res, ok } // Close implements the io.Closer interface for *HostsContainer. func (hc *HostsContainer) Close() (err error) { - log.Debug("%s: closing hosts container", hostsContainerPref) + log.Debug("%s: closing", hostsContainerPref) return errors.Annotate(hc.w.Close(), "%s: closing: %w", hostsContainerPref) } -// Upd returns the channel into which the updates are sent. +// Upd returns the channel into which the updates are sent. The receivable +// map's values are guaranteed to be of type of *stringutil.Set. func (hc *HostsContainer) Upd() (updates <-chan *netutil.IPMap) { return hc.updates } @@ -185,11 +191,18 @@ type hostsParser struct { table *netutil.IPMap } -// parseHostsFile is a aghtest.FileWalker for parsing the files with hosts -// syntax. It never signs to stop the walking. +func (hc *HostsContainer) newHostsParser() (hp *hostsParser) { + return &hostsParser{ + rules: &strings.Builder{}, + table: netutil.NewIPMap(hc.last.Len()), + } +} + +// parseFile is a aghos.FileWalker for parsing the files with hosts syntax. It +// never signs to stop walking and never returns any additional patterns. // // See man hosts(5). -func (hp hostsParser) parseHostsFile( +func (hp *hostsParser) parseFile( r io.Reader, ) (patterns []string, cont bool, err error) { s := bufio.NewScanner(r) @@ -208,7 +221,7 @@ func (hp hostsParser) parseHostsFile( } // parseLine parses the line having the hosts syntax ignoring invalid ones. -func (hp hostsParser) parseLine(line string) (ip net.IP, hosts []string) { +func (hp *hostsParser) parseLine(line string) (ip net.IP, hosts []string) { line = strings.TrimSpace(line) fields := strings.Fields(line) if len(fields) < 2 { @@ -240,20 +253,24 @@ loop: } // add returns true if the pair of ip and host wasn't added to the hp before. -func (hp hostsParser) add(ip net.IP, host string) (added bool) { +func (hp *hostsParser) add(ip net.IP, host string) (added bool) { v, ok := hp.table.Get(ip) - hosts, _ := v.([]string) - if ok && stringutil.InSlice(hosts, host) { + hosts, _ := v.(*stringutil.Set) + switch { + case ok && hosts.Has(host): return false + case hosts == nil: + hosts = stringutil.NewSet(host) + hp.table.Set(ip, hosts) + default: + hosts.Add(host) } - hp.table.Set(ip, append(hosts, host)) - return true } // addPair puts the pair of ip and host to the rules builder if needed. -func (hp hostsParser) addPair(ip net.IP, host string) { +func (hp *hostsParser) addPair(ip net.IP, host string) { arpa, err := netutil.IPToReversedAddr(ip) if err != nil { return @@ -269,61 +286,110 @@ func (hp hostsParser) addPair(ip net.IP, host string) { qtype = "A" } - stringutil.WriteToBuilder( - hp.rules, - "||", - host, - "^$dnsrewrite=NOERROR;", - qtype, - ";", - ip.String(), - "\n", - "||", - arpa, - "^$dnsrewrite=NOERROR;PTR;", - dns.Fqdn(host), - "\n", + const ( + nl = "\n" + sc = ";" + + rewriteSuccess = "$dnsrewrite=NOERROR" + sc + rewriteSuccessPTR = rewriteSuccess + "PTR" + sc ) + ipStr := ip.String() + fqdn := dns.Fqdn(host) + + for _, ruleData := range [...][]string{{ + // A/AAAA. + rules.MaskStartURL, + host, + rules.MaskSeparator, + rewriteSuccess, + qtype, + sc, + ipStr, + nl, + }, { + // PTR. + rules.MaskStartURL, + arpa, + rules.MaskSeparator, + rewriteSuccessPTR, + fqdn, + nl, + }} { + stringutil.WriteToBuilder(hp.rules, ruleData...) + } + log.Debug("%s: added ip-host pair %q/%q", hostsContainerPref, ip, host) } +// equalSet returns true if the internal hosts table just parsed equals target. +func (hp *hostsParser) equalSet(target *netutil.IPMap) (ok bool) { + if hp.table.Len() != target.Len() { + return false + } + + hp.table.Range(func(ip net.IP, val interface{}) (cont bool) { + v, hasIP := target.Get(ip) + // ok is set to true if the target doesn't contain ip or if the + // appropriate hosts set isn't equal to the checked one, i.e. the maps + // have at least one disperancy. + ok = !hasIP || !v.(*stringutil.Set).Equal(val.(*stringutil.Set)) + + // Continue only if maps has no discrepancies. + return !ok + }) + + // Return true if every value from the IP map has no disperancies with the + // appropriate one from the target. + return !ok +} + // sendUpd tries to send the parsed data to the ch. -func (hp hostsParser) sendUpd(ch chan *netutil.IPMap) { +func (hp *hostsParser) sendUpd(ch chan *netutil.IPMap) { log.Debug("%s: sending upd", hostsContainerPref) + + upd := hp.table select { - case ch <- hp.table: + case ch <- upd: // Updates are delivered. Go on. + case <-ch: + ch <- upd + log.Debug("%s: replaced the last update", hostsContainerPref) + case ch <- upd: + // The previous update was just read and the next one pushed. Go on. default: - log.Debug("%s: the buffer is full", hostsContainerPref) + log.Debug("%s: the channel is broken", hostsContainerPref) } } // newStrg creates a new rules storage from parsed data. -func (hp hostsParser) newStrg() (s *filterlist.RuleStorage, err error) { +func (hp *hostsParser) newStrg() (s *filterlist.RuleStorage, err error) { return filterlist.NewRuleStorage([]filterlist.RuleList{&filterlist.StringRuleList{ - ID: 1, + ID: -1, RulesText: hp.rules.String(), IgnoreCosmetic: true, }}) } -// refresh gets the data from specified files and propagates the updates. +// refresh gets the data from specified files and propagates the updates if +// needed. func (hc *HostsContainer) refresh() (err error) { log.Debug("%s: refreshing", hostsContainerPref) - hp := hostsParser{ - rules: &strings.Builder{}, - table: netutil.NewIPMap(0), + hp := hc.newHostsParser() + if _, err = aghos.FileWalker(hp.parseFile).Walk(hc.fsys, hc.patterns...); err != nil { + return fmt.Errorf("refreshing : %w", err) } - _, err = aghos.FileWalker(hp.parseHostsFile).Walk(hc.fsys, hc.patterns...) - if err != nil { - return fmt.Errorf("updating: %w", err) - } + if hp.equalSet(hc.last) { + log.Debug("%s: no updates detected", hostsContainerPref) + return nil + } defer hp.sendUpd(hc.updates) + hc.last = hp.table.ShallowClone() + var rulesStrg *filterlist.RuleStorage if rulesStrg, err = hp.newStrg(); err != nil { return fmt.Errorf("initializing rules storage: %w", err) diff --git a/internal/aghnet/hostscontainer_test.go b/internal/aghnet/hostscontainer_test.go index 213f4e7b..b30790a3 100644 --- a/internal/aghnet/hostscontainer_test.go +++ b/internal/aghnet/hostscontainer_test.go @@ -12,6 +12,7 @@ import ( "github.com/AdguardTeam/AdGuardHome/internal/aghtest" "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/netutil" + "github.com/AdguardTeam/golibs/stringutil" "github.com/AdguardTeam/urlfilter" "github.com/miekg/dns" "github.com/stretchr/testify/assert" @@ -164,11 +165,14 @@ func TestHostsContainer_Refresh(t *testing.T) { }, } - eventsCh := make(chan struct{}, 1) + // event is a convenient alias for an empty struct{} to emit test events. + type event = struct{} + + eventsCh := make(chan event, 1) t.Cleanup(func() { close(eventsCh) }) w := &aghtest.FSWatcher{ - OnEvents: func() (e <-chan struct{}) { return eventsCh }, + OnEvents: func() (e <-chan event) { return eventsCh }, OnAdd: func(name string) (err error) { assert.Equal(t, dirname, name) @@ -181,7 +185,7 @@ func TestHostsContainer_Refresh(t *testing.T) { require.NoError(t, err) t.Cleanup(func() { require.ErrorIs(t, hc.Close(), closeCalled) }) - checkRefresh := func(t *testing.T, wantHosts []string) { + checkRefresh := func(t *testing.T, wantHosts *stringutil.Set) { upd, ok := <-hc.Upd() require.True(t, ok) require.NotNil(t, upd) @@ -191,26 +195,30 @@ func TestHostsContainer_Refresh(t *testing.T) { v, ok := upd.Get(knownIP) require.True(t, ok) - var hosts []string - hosts, ok = v.([]string) + var hosts *stringutil.Set + hosts, ok = v.(*stringutil.Set) require.True(t, ok) - require.Len(t, hosts, len(wantHosts)) - assert.Equal(t, wantHosts, hosts) + assert.True(t, hosts.Equal(wantHosts)) } t.Run("initial_refresh", func(t *testing.T) { - checkRefresh(t, []string{knownHost}) + checkRefresh(t, stringutil.NewSet(knownHost)) }) testFS[p2] = &fstest.MapFile{ Data: []byte(strings.Join([]string{knownIP.String(), knownAlias}, sp) + nl), } - - eventsCh <- struct{}{} + eventsCh <- event{} t.Run("second_refresh", func(t *testing.T) { - checkRefresh(t, []string{knownHost, knownAlias}) + checkRefresh(t, stringutil.NewSet(knownHost, knownAlias)) + }) + + eventsCh <- event{} + + t.Run("no_changes_refresh", func(t *testing.T) { + assert.Empty(t, hc.Upd()) }) } @@ -218,7 +226,7 @@ func TestHostsContainer_MatchRequest(t *testing.T) { var ( ip4 = net.IP{127, 0, 0, 1} ip6 = net.IP{ - 0, 0, 0, 0, + 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, @@ -236,9 +244,9 @@ func TestHostsContainer_MatchRequest(t *testing.T) { gsfs := fstest.MapFS{ filename: &fstest.MapFile{Data: []byte( - strings.Join([]string{ip4.String(), hostname4, hostname4a}, sp) + nl + - strings.Join([]string{ip6.String(), hostname6}, sp) + nl + - strings.Join([]string{"256.256.256.256", "fakebroadcast"}, sp) + nl, + ip4.String() + " " + hostname4 + " " + hostname4a + nl + + ip6.String() + " " + hostname6 + nl + + `256.256.256.256 fakebroadcast` + nl, )}, } @@ -265,6 +273,15 @@ func TestHostsContainer_MatchRequest(t *testing.T) { Hostname: hostname4, DNSType: dns.TypeA, }, + }, { + name: "a_for_aaaa", + want: []interface{}{ + ip4.To16(), + }, + req: urlfilter.DNSRequest{ + Hostname: hostname4, + DNSType: dns.TypeAAAA, + }, }, { name: "aaaa", want: []interface{}{ip6}, @@ -408,7 +425,7 @@ func TestUniqueRules_AddPair(t *testing.T) { const knownHost = "host1" ipToHost := netutil.NewIPMap(0) - ipToHost.Set(knownIP, []string{knownHost}) + ipToHost.Set(knownIP, *stringutil.NewSet(knownHost)) testCases := []struct { name string @@ -422,10 +439,11 @@ func TestUniqueRules_AddPair(t *testing.T) { "||4.3.2.1.in-addr.arpa^$dnsrewrite=NOERROR;PTR;host2.\n", ip: knownIP, }, { - name: "existing_one", - host: knownHost, - wantRules: "", - ip: knownIP, + name: "existing_one", + host: knownHost, + wantRules: "||" + knownHost + "^$dnsrewrite=NOERROR;A;1.2.3.4\n" + + "||4.3.2.1.in-addr.arpa^$dnsrewrite=NOERROR;PTR;host1.\n", + ip: knownIP, }, { name: "new_ip", host: knownHost, diff --git a/internal/dnsforward/filter.go b/internal/dnsforward/filter.go index 7300b43c..471b463e 100644 --- a/internal/dnsforward/filter.go +++ b/internal/dnsforward/filter.go @@ -82,25 +82,7 @@ func (s *Server) filterDNSRequest(ctx *dnsContext) (*filtering.Result, error) { // original question is readded in processFilteringAfterResponse. ctx.origQuestion = q req.Question[0].Name = dns.Fqdn(res.CanonName) - case res.Reason == filtering.RewrittenAutoHosts && len(res.ReverseHosts) != 0: - resp := s.makeResponse(req) - hdr := dns.RR_Header{ - Name: q.Name, - Rrtype: dns.TypePTR, - Ttl: s.conf.BlockedResponseTTL, - Class: dns.ClassINET, - } - for _, h := range res.ReverseHosts { - ptr := &dns.PTR{ - Hdr: hdr, - Ptr: h, - } - - resp.Answer = append(resp.Answer, ptr) - } - - d.Res = resp - case res.Reason.In(filtering.Rewritten, filtering.RewrittenAutoHosts): + case res.Reason == filtering.Rewritten: resp := s.makeResponse(req) name := host @@ -123,7 +105,7 @@ func (s *Server) filterDNSRequest(ctx *dnsContext) (*filtering.Result, error) { } d.Res = resp - case res.Reason == filtering.RewrittenRule: + case res.Reason.In(filtering.RewrittenRule, filtering.RewrittenAutoHosts): if err = s.filterDNSRewrite(req, res, d); err != nil { return nil, err } diff --git a/internal/filtering/dnsrewrite.go b/internal/filtering/dnsrewrite.go index e98dfa3d..a6dda4a6 100644 --- a/internal/filtering/dnsrewrite.go +++ b/internal/filtering/dnsrewrite.go @@ -17,12 +17,8 @@ type DNSRewriteResultResponse map[rules.RRType][]rules.RRValue // processDNSRewrites processes DNS rewrite rules in dnsr. It returns an empty // result if dnsr is empty. Otherwise, the result will have either CanonName or -// DNSRewriteResult set. +// DNSRewriteResult set. dnsr is expected to be non-empty. func (d *DNSFilter) processDNSRewrites(dnsr []*rules.NetworkRule) (res Result) { - if len(dnsr) == 0 { - return Result{} - } - var rules []*ResultRule dnsrr := &DNSRewriteResult{ Response: DNSRewriteResultResponse{}, @@ -31,8 +27,7 @@ func (d *DNSFilter) processDNSRewrites(dnsr []*rules.NetworkRule) (res Result) { for _, nr := range dnsr { dr := nr.DNSRewrite if dr.NewCNAME != "" { - // NewCNAME rules have a higher priority than - // the other rules. + // NewCNAME rules have a higher priority than the other rules. rules = []*ResultRule{{ FilterListID: int64(nr.GetFilterListID()), Text: nr.RuleText, @@ -54,8 +49,8 @@ func (d *DNSFilter) processDNSRewrites(dnsr []*rules.NetworkRule) (res Result) { Text: nr.RuleText, }) default: - // RcodeRefused and other such codes have higher - // priority. Return immediately. + // RcodeRefused and other such codes have higher priority. Return + // immediately. rules = []*ResultRule{{ FilterListID: int64(nr.GetFilterListID()), Text: nr.RuleText, diff --git a/internal/filtering/filtering.go b/internal/filtering/filtering.go index defd9e2f..c4dd4c05 100644 --- a/internal/filtering/filtering.go +++ b/internal/filtering/filtering.go @@ -378,6 +378,10 @@ type Result struct { // ReverseHosts is the reverse lookup rewrite result. It is empty unless // Reason is set to RewrittenAutoHosts. + // + // TODO(e.burkov): There is no need for AutoHosts-related fields any more + // since the hosts container now uses $dnsrewrite rules. These fields are + // only used in query log to decode old format. ReverseHosts []string `json:",omitempty"` // IPList is the lookup rewrite result. It is empty unless Reason is set to @@ -450,53 +454,39 @@ func (d *DNSFilter) CheckHost( } // matchSysHosts tries to match the host against the operating system's hosts -// database. +// database. err is always nil. func (d *DNSFilter) matchSysHosts( host string, qtype uint16, setts *Settings, ) (res Result, err error) { if !setts.FilteringEnabled || d.EtcHosts == nil { - return Result{}, nil + return res, nil } dnsres, _ := d.EtcHosts.MatchRequest(urlfilter.DNSRequest{ Hostname: host, SortedClientTags: setts.ClientTags, - // TODO(e.burkov): Wait for urlfilter update to pass net.IP. + // TODO(e.burkov): Wait for urlfilter update to pass net.IP. ClientIP: setts.ClientIP.String(), ClientName: setts.ClientName, DNSType: qtype, }) if dnsres == nil { - return Result{}, nil + return res, nil } - dnsr := dnsres.DNSRewrites() - if len(dnsr) == 0 { - return Result{}, nil + if dnsr := dnsres.DNSRewrites(); len(dnsr) > 0 { + // Check DNS rewrites first, because the API there is a bit awkward. + res = d.processDNSRewrites(dnsr) + res.Reason = RewrittenAutoHosts + // TODO(e.burkov): Put real hosts-syntax rules. + // + // See https://github.com/AdguardTeam/AdGuardHome/issues/3846. + res.Rules = nil } - var ips []net.IP - var revHosts []string - for _, nr := range dnsr { - if nr.DNSRewrite == nil { - continue - } - - switch val := nr.DNSRewrite.Value.(type) { - case net.IP: - ips = append(ips, val) - case string: - revHosts = append(revHosts, val) - } - } - - return Result{ - Reason: RewrittenAutoHosts, - IPList: ips, - ReverseHosts: revHosts, - }, nil + return res, nil } // Process rewrites table diff --git a/internal/home/clients.go b/internal/home/clients.go index 85eec9fd..02c87f03 100644 --- a/internal/home/clients.go +++ b/internal/home/clients.go @@ -772,17 +772,18 @@ func (clients *clientsContainer) addFromHostsFile(hosts *netutil.IPMap) { n := 0 hosts.Range(func(ip net.IP, v interface{}) (cont bool) { - names, ok := v.([]string) + names, ok := v.(*stringutil.Set) if !ok { log.Error("dns: bad type %T in ipToRC for %s", v, ip) } - for _, name := range names { - ok = clients.addHostLocked(ip, name, ClientSourceHostsFile) - if ok { + names.Range(func(name string) (cont bool) { + if clients.addHostLocked(ip, name, ClientSourceHostsFile) { n++ } - } + + return true + }) return true }) From 9bac4b3db2416e05d5d6100e2815b806196fcc9b Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Wed, 17 Nov 2021 17:21:10 +0300 Subject: [PATCH 024/135] Pull request: 3845 hosts fatality Merge in DNS/adguard-home from 3845-hosts-fatality to master Updates #3845. Squashed commit of the following: commit 1447efcc4066e0226feaebde01fcc632cb7b7432 Author: Eugene Burkov Date: Wed Nov 17 17:14:35 2021 +0300 home: imp readability commit e934499072e983e1111b6c976eb93e1d6017981b Author: Eugene Burkov Date: Wed Nov 17 13:35:10 2021 +0300 aghnet: imp more commit ed9995ee52bd9ec3fa130f3f56989619184a6669 Author: Eugene Burkov Date: Wed Nov 17 13:05:56 2021 +0300 all: imp docs, code commit 7b0718a1a4a58a4fd5f1ba24c33792b0610c334f Author: Eugene Burkov Date: Tue Nov 16 20:32:24 2021 +0300 all: reduce hosts container fatality --- internal/aghnet/hostscontainer.go | 73 +++++++++++++++++--------- internal/aghnet/hostscontainer_test.go | 71 +++++++++++-------------- internal/aghos/fswatcher.go | 2 + internal/aghtest/testfs.go | 46 ++++++++++++++++ internal/dnsforward/dnsforward_test.go | 6 +-- internal/home/home.go | 56 ++++++++++++++------ 6 files changed, 171 insertions(+), 83 deletions(-) create mode 100644 internal/aghtest/testfs.go diff --git a/internal/aghnet/hostscontainer.go b/internal/aghnet/hostscontainer.go index 67aad623..a0b10520 100644 --- a/internal/aghnet/hostscontainer.go +++ b/internal/aghnet/hostscontainer.go @@ -43,6 +43,9 @@ type HostsContainer struct { // engine serves rulesStrg. engine *urlfilter.DNSEngine + // done is the channel to sign closing the container. + done chan struct{} + // updates is the channel for receiving updated hosts. updates chan *netutil.IPMap // last is the set of hosts that was cached within last detected change. @@ -57,12 +60,12 @@ type HostsContainer struct { patterns []string } -// errNoPaths is returned when there are no paths to watch passed to the -// HostsContainer. -const errNoPaths errors.Error = "hosts paths are empty" +// ErrNoHostsPaths is returned when there are no valid paths to watch passed to +// the HostsContainer. +const ErrNoHostsPaths errors.Error = "no valid paths to hosts files provided" // NewHostsContainer creates a container of hosts, that watches the paths with -// w. paths shouldn't be empty and each of them should locate either a file or +// w. paths shouldn't be empty and each of paths should locate either a file or // a directory in fsys. fsys and w must be non-nil. func NewHostsContainer( fsys fs.FS, @@ -72,16 +75,20 @@ func NewHostsContainer( defer func() { err = errors.Annotate(err, "%s: %w", hostsContainerPref) }() if len(paths) == 0 { - return nil, errNoPaths + return nil, ErrNoHostsPaths } - patterns, err := pathsToPatterns(fsys, paths) + var patterns []string + patterns, err = pathsToPatterns(fsys, paths) if err != nil { return nil, err + } else if len(patterns) == 0 { + return nil, ErrNoHostsPaths } hc = &HostsContainer{ engLock: &sync.RWMutex{}, + done: make(chan struct{}, 1), updates: make(chan *netutil.IPMap, 1), last: &netutil.IPMap{}, fsys: fsys, @@ -97,16 +104,13 @@ func NewHostsContainer( } for _, p := range paths { - err = w.Add(p) - if err == nil { - continue - } else if errors.Is(err, fs.ErrNotExist) { + if err = w.Add(p); err != nil { + if !errors.Is(err, fs.ErrNotExist) { + return nil, fmt.Errorf("adding path: %w", err) + } + log.Debug("%s: file %q expected to exist but doesn't", hostsContainerPref, p) - - continue } - - return nil, fmt.Errorf("adding path: %w", err) } go hc.handleEvents() @@ -130,16 +134,17 @@ func (hc *HostsContainer) MatchRequest( hc.engLock.RLock() defer hc.engLock.RUnlock() - res, ok = hc.engine.MatchRequest(req) - - return res, ok + return hc.engine.MatchRequest(req) } -// Close implements the io.Closer interface for *HostsContainer. +// Close implements the io.Closer interface for *HostsContainer. Close must +// only be called once. The returned err is always nil. func (hc *HostsContainer) Close() (err error) { log.Debug("%s: closing", hostsContainerPref) - return errors.Annotate(hc.w.Close(), "%s: closing: %w", hostsContainerPref) + close(hc.done) + + return nil } // Upd returns the channel into which the updates are sent. The receivable @@ -152,8 +157,14 @@ func (hc *HostsContainer) Upd() (updates <-chan *netutil.IPMap) { func pathsToPatterns(fsys fs.FS, paths []string) (patterns []string, err error) { for i, p := range paths { var fi fs.FileInfo - if fi, err = fs.Stat(fsys, p); err != nil { - return nil, fmt.Errorf("%q at index %d: %w", p, i, err) + fi, err = fs.Stat(fsys, p) + if err != nil { + if errors.Is(err, fs.ErrNotExist) { + continue + } + + // Don't put a filename here since it's already added by fs.Stat. + return nil, fmt.Errorf("path at index %d: %w", i, err) } if fi.IsDir() { @@ -173,9 +184,21 @@ func (hc *HostsContainer) handleEvents() { defer close(hc.updates) - for range hc.w.Events() { - if err := hc.refresh(); err != nil { - log.Error("%s: %s", hostsContainerPref, err) + ok, eventsCh := true, hc.w.Events() + for ok { + select { + case _, ok = <-eventsCh: + if !ok { + log.Debug("%s: watcher closed the events channel", hostsContainerPref) + + continue + } + + if err := hc.refresh(); err != nil { + log.Error("%s: %s", hostsContainerPref, err) + } + case _, ok = <-hc.done: + // Go on. } } } @@ -373,6 +396,8 @@ func (hp *hostsParser) newStrg() (s *filterlist.RuleStorage, err error) { // refresh gets the data from specified files and propagates the updates if // needed. +// +// TODO(e.burkov): Accept a parameter to specify the files to refresh. func (hc *HostsContainer) refresh() (err error) { log.Debug("%s: refreshing", hostsContainerPref) diff --git a/internal/aghnet/hostscontainer_test.go b/internal/aghnet/hostscontainer_test.go index b30790a3..5a08b24f 100644 --- a/internal/aghnet/hostscontainer_test.go +++ b/internal/aghnet/hostscontainer_test.go @@ -24,14 +24,6 @@ const ( sp = " " ) -const closeCalled errors.Error = "close method called" - -// fsWatcherOnCloseStub is a stub implementation of the Close method of -// aghos.FSWatcher. -func fsWatcherOnCloseStub() (err error) { - return closeCalled -} - func TestNewHostsContainer(t *testing.T) { const dirname = "dir" const filename = "file1" @@ -43,30 +35,25 @@ func TestNewHostsContainer(t *testing.T) { } testCases := []struct { - name string - paths []string - wantErr error - wantPatterns []string + wantErr error + name string + paths []string }{{ - name: "one_file", - paths: []string{p}, - wantErr: nil, - wantPatterns: []string{p}, + wantErr: nil, + name: "one_file", + paths: []string{p}, }, { - name: "no_files", - paths: []string{}, - wantErr: errNoPaths, - wantPatterns: nil, + wantErr: ErrNoHostsPaths, + name: "no_files", + paths: []string{}, }, { - name: "non-existent_file", - paths: []string{path.Join(dirname, filename+"2")}, - wantErr: fs.ErrNotExist, - wantPatterns: nil, + wantErr: ErrNoHostsPaths, + name: "non-existent_file", + paths: []string{path.Join(dirname, filename+"2")}, }, { - name: "whole_dir", - paths: []string{dirname}, - wantErr: nil, - wantPatterns: []string{path.Join(dirname, "*")}, + wantErr: nil, + name: "whole_dir", + paths: []string{dirname}, }} for _, tc := range testCases { @@ -88,7 +75,7 @@ func TestNewHostsContainer(t *testing.T) { hc, err := NewHostsContainer(testFS, &aghtest.FSWatcher{ OnEvents: onEvents, OnAdd: onAdd, - OnClose: fsWatcherOnCloseStub, + OnClose: func() (err error) { panic("not implemented") }, }, tc.paths...) if tc.wantErr != nil { require.ErrorIs(t, err, tc.wantErr) @@ -99,13 +86,8 @@ func TestNewHostsContainer(t *testing.T) { } require.NoError(t, err) - t.Cleanup(func() { - require.ErrorIs(t, hc.Close(), closeCalled) - }) - require.NotNil(t, hc) - assert.Equal(t, tc.wantPatterns, hc.patterns) assert.NotNil(t, <-hc.Upd()) eventsCh <- struct{}{} @@ -178,12 +160,11 @@ func TestHostsContainer_Refresh(t *testing.T) { return nil }, - OnClose: fsWatcherOnCloseStub, + OnClose: func() (err error) { panic("not implemented") }, } hc, err := NewHostsContainer(testFS, w, dirname) require.NoError(t, err) - t.Cleanup(func() { require.ErrorIs(t, hc.Close(), closeCalled) }) checkRefresh := func(t *testing.T, wantHosts *stringutil.Set) { upd, ok := <-hc.Upd() @@ -257,10 +238,9 @@ func TestHostsContainer_MatchRequest(t *testing.T) { return nil }, - OnClose: fsWatcherOnCloseStub, + OnClose: func() (err error) { panic("not implemented") }, }, filename) require.NoError(t, err) - t.Cleanup(func() { require.ErrorIs(t, hc.Close(), closeCalled) }) testCase := []struct { name string @@ -398,7 +378,7 @@ func TestHostsContainer_PathsToPatterns(t *testing.T) { paths: []string{fp1, path.Join(dir0, dir1)}, }, { name: "non-existing", - wantErr: fs.ErrNotExist, + wantErr: nil, want: nil, paths: []string{path.Join(dir0, "file_3")}, }} @@ -417,6 +397,19 @@ func TestHostsContainer_PathsToPatterns(t *testing.T) { assert.Equal(t, tc.want, patterns) }) } + + t.Run("bad_file", func(t *testing.T) { + const errStat errors.Error = "bad file" + + badFS := &aghtest.StatFS{ + OnStat: func(name string) (fs.FileInfo, error) { + return nil, errStat + }, + } + + _, err := pathsToPatterns(badFS, []string{""}) + assert.ErrorIs(t, err, errStat) + }) } func TestUniqueRules_AddPair(t *testing.T) { diff --git a/internal/aghos/fswatcher.go b/internal/aghos/fswatcher.go index a113610f..8f5d1d60 100644 --- a/internal/aghos/fswatcher.go +++ b/internal/aghos/fswatcher.go @@ -82,6 +82,8 @@ func (w *osWatcher) Events() (e <-chan event) { } // Add implements the FSWatcher interface for *osWatcher. +// +// TODO(e.burkov): Make it accept non-existing files to detect it's creating. func (w *osWatcher) Add(name string) (err error) { defer func() { err = errors.Annotate(err, "%s: %w", osWatcherPref) }() diff --git a/internal/aghtest/testfs.go b/internal/aghtest/testfs.go new file mode 100644 index 00000000..88203fec --- /dev/null +++ b/internal/aghtest/testfs.go @@ -0,0 +1,46 @@ +package aghtest + +import "io/fs" + +// type check +var _ fs.FS = &FS{} + +// FS is a mock fs.FS implementation to use in tests. +type FS struct { + OnOpen func(name string) (fs.File, error) +} + +// Open implements the fs.FS interface for *FS. +func (fsys *FS) Open(name string) (fs.File, error) { + return fsys.OnOpen(name) +} + +// type check +var _ fs.StatFS = &StatFS{} + +// StatFS is a mock fs.StatFS implementation to use in tests. +type StatFS struct { + // FS is embedded here to avoid implementing all it's methods. + FS + OnStat func(name string) (fs.FileInfo, error) +} + +// Stat implements the fs.StatFS interface for *StatFS. +func (fsys *StatFS) Stat(name string) (fs.FileInfo, error) { + return fsys.OnStat(name) +} + +// type check +var _ fs.GlobFS = &GlobFS{} + +// GlobFS is a mock fs.GlobFS implementation to use in tests. +type GlobFS struct { + // FS is embedded here to avoid implementing all it's methods. + FS + OnGlob func(pattern string) ([]string, error) +} + +// Glob implements the fs.GlobFS interface for *GlobFS. +func (fsys *GlobFS) Glob(pattern string) ([]string, error) { + return fsys.OnGlob(pattern) +} diff --git a/internal/dnsforward/dnsforward_test.go b/internal/dnsforward/dnsforward_test.go index 701d1c5d..6f0ccc70 100644 --- a/internal/dnsforward/dnsforward_test.go +++ b/internal/dnsforward/dnsforward_test.go @@ -1077,8 +1077,6 @@ func TestPTRResponseFromHosts(t *testing.T) { `)}, } - const closeCalled errors.Error = "close method called" - var eventsCalledCounter uint32 hc, err := aghnet.NewHostsContainer(testFS, &aghtest.FSWatcher{ OnEvents: func() (e <-chan struct{}) { @@ -1091,13 +1089,11 @@ func TestPTRResponseFromHosts(t *testing.T) { return nil }, - OnClose: func() (err error) { return closeCalled }, + OnClose: func() (err error) { panic("not implemented") }, }, hostsFilename) require.NoError(t, err) t.Cleanup(func() { assert.Equal(t, uint32(1), atomic.LoadUint32(&eventsCalledCounter)) - - require.ErrorIs(t, hc.Close(), closeCalled) }) flt := filtering.New(&filtering.Config{ diff --git a/internal/home/home.go b/internal/home/home.go index c5a6a5e6..1148ed6a 100644 --- a/internal/home/home.go +++ b/internal/home/home.go @@ -59,7 +59,10 @@ type homeContext struct { // etcHosts is an IP-hostname pairs set taken from system configuration // (e.g. /etc/hosts) files. etcHosts *aghnet.HostsContainer - updater *updater.Updater + // hostsWatcher is the watcher to detect changes in the hosts files. + hostsWatcher aghos.FSWatcher + + updater *updater.Updater subnetDetector *aghnet.SubnetDetector @@ -232,6 +235,33 @@ func configureOS(conf *configuration) (err error) { return nil } +// setupHostsContainer initializes the structures to keep up-to-date the hosts +// provided by the OS. +func setupHostsContainer() (err error) { + Context.hostsWatcher, err = aghos.NewOSWritesWatcher() + if err != nil { + return fmt.Errorf("initing hosts watcher: %w", err) + } + + Context.etcHosts, err = aghnet.NewHostsContainer( + aghos.RootDirFS(), + Context.hostsWatcher, + aghnet.DefaultHostsPaths()..., + ) + if err != nil { + cerr := Context.hostsWatcher.Close() + if errors.Is(err, aghnet.ErrNoHostsPaths) && cerr == nil { + log.Info("warning: initing hosts container: %s", err) + + return nil + } + + return errors.WithDeferred(fmt.Errorf("initing hosts container: %w", err), cerr) + } + + return nil +} + func setupConfig(args options) (err error) { config.DHCP.WorkDir = Context.workDir config.DHCP.HTTPRegister = httpRegister @@ -259,19 +289,8 @@ func setupConfig(args options) (err error) { }) if !args.noEtcHosts { - var osWritesWatcher aghos.FSWatcher - osWritesWatcher, err = aghos.NewOSWritesWatcher() - if err != nil { - return fmt.Errorf("initing os watcher: %w", err) - } - - Context.etcHosts, err = aghnet.NewHostsContainer( - aghos.RootDirFS(), - osWritesWatcher, - aghnet.DefaultHostsPaths()..., - ) - if err != nil { - return fmt.Errorf("initing hosts container: %w", err) + if err = setupHostsContainer(); err != nil { + return err } } Context.clients.Init(config.Clients, Context.dhcpServer, Context.etcHosts) @@ -661,8 +680,15 @@ func cleanup(ctx context.Context) { } if Context.etcHosts != nil { + // Currently Context.hostsWatcher is only used in Context.etcHosts and + // needs closing only in case of the successful initialization of + // Context.etcHosts. + if err = Context.hostsWatcher.Close(); err != nil { + log.Error("closing hosts watcher: %s", err) + } + if err = Context.etcHosts.Close(); err != nil { - log.Error("stopping hosts container: %s", err) + log.Error("closing hosts container: %s", err) } } From d41779cf88983549af7750abf17a5b920c88125d Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Mon, 22 Nov 2021 17:22:59 +0300 Subject: [PATCH 025/135] Pull request: 3851 empty hosts Merge in DNS/adguard-home from 3851-empty-hosts to master Updates #3851. Squashed commit of the following: commit e09aa8e1029748ba162950b087336fd71677da2d Author: Eugene Burkov Date: Mon Nov 22 16:19:08 2021 +0300 aghnet: imp code commit c9e45148a68193249c2d7096a15c7fee571ba5bd Author: Eugene Burkov Date: Mon Nov 22 15:33:27 2021 +0300 aghnet: fix hosts container empty engine --- internal/aghnet/hostscontainer.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/internal/aghnet/hostscontainer.go b/internal/aghnet/hostscontainer.go index a0b10520..cfa55dd0 100644 --- a/internal/aghnet/hostscontainer.go +++ b/internal/aghnet/hostscontainer.go @@ -90,7 +90,6 @@ func NewHostsContainer( engLock: &sync.RWMutex{}, done: make(chan struct{}, 1), updates: make(chan *netutil.IPMap, 1), - last: &netutil.IPMap{}, fsys: fsys, w: w, patterns: patterns, @@ -347,6 +346,11 @@ func (hp *hostsParser) addPair(ip net.IP, host string) { // equalSet returns true if the internal hosts table just parsed equals target. func (hp *hostsParser) equalSet(target *netutil.IPMap) (ok bool) { + if target == nil { + // hp.table shouldn't appear nil since it's initialized on each refresh. + return target == hp.table + } + if hp.table.Len() != target.Len() { return false } From ed868fa46a8e2e0809d6b1c067e934b175bd03b4 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Tue, 23 Nov 2021 14:21:02 +0300 Subject: [PATCH 026/135] Pull request: client: upd i18n Merge in DNS/adguard-home from upd-i18n to master Squashed commit of the following: commit 7d9aa25a5ec3e9779abda442fd68d057e7e5842e Author: Ainar Garipov Date: Tue Nov 23 14:04:17 2021 +0300 client: upd i18n --- client/src/__locales/be.json | 17 +++++++++++--- client/src/__locales/bg.json | 2 +- client/src/__locales/cs.json | 20 ++++++++++++----- client/src/__locales/da.json | 20 ++++++++++++----- client/src/__locales/de.json | 24 +++++++++++++------- client/src/__locales/es.json | 20 ++++++++++++----- client/src/__locales/fr.json | 7 +----- client/src/__locales/hr.json | 1 - client/src/__locales/hu.json | 2 -- client/src/__locales/id.json | 2 -- client/src/__locales/it.json | 20 ++++++++++++----- client/src/__locales/ja.json | 1 - client/src/__locales/ko.json | 1 - client/src/__locales/nl.json | 22 ++++++++++++------ client/src/__locales/no.json | 2 -- client/src/__locales/pl.json | 20 ++++++++++++----- client/src/__locales/pt-br.json | 20 ++++++++++++----- client/src/__locales/pt-pt.json | 20 ++++++++++++----- client/src/__locales/ro.json | 20 ++++++++++++----- client/src/__locales/ru.json | 20 ++++++++++++----- client/src/__locales/sk.json | 20 ++++++++++++----- client/src/__locales/sl.json | 20 ++++++++++++----- client/src/__locales/sr-cs.json | 2 -- client/src/__locales/sv.json | 4 ++-- client/src/__locales/tr.json | 40 ++++++++++++++++++++------------- client/src/__locales/uk.json | 2 +- client/src/__locales/vi.json | 1 - client/src/__locales/zh-cn.json | 1 - client/src/__locales/zh-hk.json | 2 -- client/src/__locales/zh-tw.json | 20 ++++++++++++----- 30 files changed, 242 insertions(+), 131 deletions(-) diff --git a/client/src/__locales/be.json b/client/src/__locales/be.json index 29e0c043..a5d45489 100644 --- a/client/src/__locales/be.json +++ b/client/src/__locales/be.json @@ -37,6 +37,9 @@ "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", @@ -45,7 +48,12 @@ "form_error_subnet": "Падсетка «{{cidr}}» не ўтрымвае IP-адраса «{{ip}}»", "form_error_positive": "Павінна быць больш 0", "form_error_negative": "Павінна быць не менш 0", - "range_end_error": "Павінен перавышаць пачатак дыяпазону", + "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-адрасоў", @@ -503,6 +511,7 @@ "statistics_clear_confirm": "Вы ўпэўнены, што хочаце ачысціць статыстыку?", "statistics_retention_confirm": "Вы ўпэўнены, што хочаце змяніць тэрмін захоўвання статыстыкі? Пры скарачэнні інтэрвалу дадзеныя могуць быць згублены", "statistics_cleared": "Статыстыка паспяхова вычышчана", + "statistics_enable": "Уключыць статыстыку", "interval_hours": "{{count}} гадзіна", "interval_hours_plural": "{{count}} гадзін", "filters_configuration": "Налада фільтраў", @@ -612,6 +621,8 @@ "click_to_view_queries": "Націсніце, каб прагледзець запыты", "port_53_faq_link": "Порт 53 часта заняты службамі \"DNSStubListener\" ці \"systemd-resolved\". Азнаёмцеся з <0>інструкцыяй пра тое, як гэта дазволіць.", "adg_will_drop_dns_queries": "AdGuard Home скіне ўсе DNS-запыты ад гэтага кліента.", - "client_not_in_allowed_clients": "Кліент не дазволены, бо яго няма ў спісе \"Дазволеных кліентаў\".", - "experimental": "Эксперыментальны" + "filter_allowlist": "УВАГА: Гэта дзеянне таксама выключыць правіла «{{disallowed_rule}}» са спіса дазволеных кліентаў.", + "last_rule_in_allowlist": "Няможна заблакаваць гэтага кліента, бо вынятак правіла «{{disallowed_rule}}» АДКЛЮЧЫЦЬ рэжым белага спіса.", + "experimental": "Эксперыментальны", + "use_saved_key": "Скарыстаць захаваны раней ключ" } diff --git a/client/src/__locales/bg.json b/client/src/__locales/bg.json index 458d93a9..a756b92b 100644 --- a/client/src/__locales/bg.json +++ b/client/src/__locales/bg.json @@ -10,7 +10,7 @@ "dhcp_leases": "DHCP раздадени адреси", "dhcp_leases_not_found": "Няма намерени активни DHCP адреси", "form_error_required": "Задължително поле", - "form_error_ip_format": "Невалиден IPv4 адрес", + "form_error_ip_format": "Невалиден IP адрес", "form_error_positive": "Проверете дали е положително число", "dhcp_form_gateway_input": "IP шлюз", "dhcp_form_subnet_input": "Мрежова маска", diff --git a/client/src/__locales/cs.json b/client/src/__locales/cs.json index fda58f14..f66c190e 100644 --- a/client/src/__locales/cs.json +++ b/client/src/__locales/cs.json @@ -36,16 +36,24 @@ "dhcp_ipv4_settings": "Nastavení DHCP IPv4", "dhcp_ipv6_settings": "Nastavení DHCP IPv6", "form_error_required": "Povinné pole", - "form_error_ip4_format": "Neplatný formát IPv4", - "form_error_ip6_format": "Neplatný formát IPv6", - "form_error_ip_format": "Neplatný formát IP", - "form_error_mac_format": "Neplatný formát MAC", - "form_error_client_id_format": "Neplatný formát ID klienta", + "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á adresa IP", + "form_error_mac_format": "Neplatná adresa MAC", + "form_error_client_id_format": "Neplatné ID klienta", "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", "form_error_negative": "Musí být rovno nebo větší než 0", - "range_end_error": "Musí být větší než začátek rozsahu", + "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", diff --git a/client/src/__locales/da.json b/client/src/__locales/da.json index d8c117d8..0825d84f 100644 --- a/client/src/__locales/da.json +++ b/client/src/__locales/da.json @@ -36,16 +36,24 @@ "dhcp_ipv4_settings": "DHCP IPv4-indstillinger", "dhcp_ipv6_settings": "DHCP IPv6-indstillinger", "form_error_required": "Obligatorisk felt", - "form_error_ip4_format": "Ugyldigt IPv4-format", - "form_error_ip6_format": "Ugyldigt IPv6-format", - "form_error_ip_format": "Ugyldigt IP-format", - "form_error_mac_format": "Ugyldigt MAC-format", - "form_error_client_id_format": "Ugyldigt klient-ID format", + "form_error_ip4_format": "Ugyldig IPv4-adresse", + "form_error_ip4_range_start_format": "Ugyldig IPv4-adresse for områdestart", + "form_error_ip4_range_end_format": "Ugyldig IPv4-adresse for områdeafslutning", + "form_error_ip4_gateway_format": "Ugyldig IPv4-adresse for gateway", + "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": "Ugyldigt klient-ID", "form_error_server_name": "Ugyldigt servernavn", "form_error_subnet": "Subnet \"{{cidr}}\" indeholder ikke IP-adressen \"{{ip}}\"", "form_error_positive": "Skal være større end 0", "form_error_negative": "Skal være lig med 0 eller større", - "range_end_error": "Skal være større end starten på ​​intervallet", + "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 slutningen på ​​området", + "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", "dhcp_form_range_title": "Interval af IP-adresser", diff --git a/client/src/__locales/de.json b/client/src/__locales/de.json index b49f891c..45e416dd 100644 --- a/client/src/__locales/de.json +++ b/client/src/__locales/de.json @@ -36,16 +36,24 @@ "dhcp_ipv4_settings": "DHCP-IPv4-Einstellungen", "dhcp_ipv6_settings": "DHCP-IPv6-Einstellungen", "form_error_required": "Pflichtfeld", - "form_error_ip4_format": "Ungültiges IPv4-Format", - "form_error_ip6_format": "Ungültiges IPv6-Format", - "form_error_ip_format": "Ungültiges IPv4-Format", - "form_error_mac_format": "Ungültiges MAC-Format", - "form_error_client_id_format": "Ungültiges Client-ID-Format", + "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ültiges Gateway-IPv4-Adresse", + "form_error_ip6_format": "Ungültige IPv6-Adresse", + "form_error_ip_format": "Ungültige IP-Adresse", + "form_error_mac_format": "Ungültiges Format der MAC-Adresse", + "form_error_client_id_format": "Ungültiges Client-ID", "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.", "form_error_negative": "Muss gleich oder größer als 0 (Null) sein", - "range_end_error": "Muss größer als der Bereichsbeginn 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", @@ -306,7 +314,7 @@ "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", "install_auth_title": "Authentifizierung", - "install_auth_desc": "Die Passwortauthentifizierung für Ihre AdGuard Home Administrator-Weboberfläche muss konfiguriert sein. Auch wenn AdGuard Home nur in Ihrem lokalen Netzwerk zugänglich ist, ist es dennoch wichtig, es vor unbefugtem Zugriff zu schützen.", + "install_auth_desc": "Die Passwort-Authentifizierung für Ihre AdGuard Home Admin-Web-Oberfläche muss konfiguriert werden. Auch wenn AdGuard Home nur in Ihrem lokalen Netzwerk zugänglich ist, ist es dennoch wichtig, es vor unberechtigtem Zugriff zu schützen.", "install_auth_username": "Benutzername", "install_auth_password": "Passwort", "install_auth_confirm": "Passwort bestätigen", @@ -598,7 +606,7 @@ "cache_ttl_min_override_desc": "Überschreibt den TTL-Minimalwert, der vom vorgeschalteten Server empfangen wurde. Dieser Wert darf nicht mehr als 3600 (Sek.) (≙ 1 Stunde) betragen.", "cache_ttl_max_override_desc": "Überschreibt den TLL-Maximalwert, der vom vorgeschalteten Server empfangen wurde.", "ttl_cache_validation": "Der minimale Cache des TTL-Wertes muss kleiner oder gleich dem maximalen Wert sein", - "cache_optimistic": "Optimistisches Caching", + "cache_optimistic": "Optimistisches Zwischenspeichern", "cache_optimistic_desc": "Sorgt dafür, dass AdGuard Home auch dann aus dem Zwischenspeicher antwortet, wenn die Einträge abgelaufen sind, und versucht zudem, diese zu aktualisieren.", "filter_category_general": "Allgemein", "filter_category_security": "Sicherheit", diff --git a/client/src/__locales/es.json b/client/src/__locales/es.json index ea429c60..ea031592 100644 --- a/client/src/__locales/es.json +++ b/client/src/__locales/es.json @@ -36,16 +36,24 @@ "dhcp_ipv4_settings": "Configuración DHCP IPv4", "dhcp_ipv6_settings": "Configuración DHCP IPv6", "form_error_required": "Campo obligatorio", - "form_error_ip4_format": "Formato IPv4 no válido", - "form_error_ip6_format": "Formato IPv6 no válido", - "form_error_ip_format": "Formato IP no válido", - "form_error_mac_format": "Formato MAC no válido", - "form_error_client_id_format": "Formato de ID de cliente no válido", + "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": "ID de cliente no válido", "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", "form_error_negative": "Debe ser igual o mayor que 0", - "range_end_error": "Debe ser mayor que el inicio de rango", + "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", diff --git a/client/src/__locales/fr.json b/client/src/__locales/fr.json index 9c9f5d33..745b4de9 100644 --- a/client/src/__locales/fr.json +++ b/client/src/__locales/fr.json @@ -36,16 +36,11 @@ "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": "Format IPv4 invalide", - "form_error_ip6_format": "Format IPv6 invalide", - "form_error_ip_format": "Format IPv4 invalide", - "form_error_mac_format": "Format MAC invalide", - "form_error_client_id_format": "Format d'ID client non valide", + "form_error_ip_format": "Adresse e-mail non valide", "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", "form_error_negative": "Doit être égal à 0 ou supérieur", - "range_end_error": "Doit être supérieur au début de la gamme", "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", diff --git a/client/src/__locales/hr.json b/client/src/__locales/hr.json index a8f51ab9..6288860e 100644 --- a/client/src/__locales/hr.json +++ b/client/src/__locales/hr.json @@ -45,7 +45,6 @@ "form_error_subnet": "Podmrežu \"{{cidr}}\" ne sadrži IP adresu \"{{ip}}\"", "form_error_positive": "Mora biti veće od 0", "form_error_negative": "Mora biti jednako ili veće od 0", - "range_end_error": "Mora biti veće od početne vrijednosti raspona", "dhcp_form_gateway_input": "Gateway IP", "dhcp_form_subnet_input": "Subnet maskiranje", "dhcp_form_range_title": "Raspon IP adresa", diff --git a/client/src/__locales/hu.json b/client/src/__locales/hu.json index f356dd48..9d8b97d4 100644 --- a/client/src/__locales/hu.json +++ b/client/src/__locales/hu.json @@ -45,7 +45,6 @@ "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", "form_error_negative": "Legalább 0-nak kell lennie", - "range_end_error": "Nagyobbnak kell lennie, mint a tartomány kezdete", "dhcp_form_gateway_input": "Átjáró IP", "dhcp_form_subnet_input": "Alhálózati maszk", "dhcp_form_range_title": "IP-címek tartománya", @@ -613,7 +612,6 @@ "click_to_view_queries": "Kattintson a lekérésekért", "port_53_faq_link": "Az 53-as portot gyakran a \"DNSStubListener\" vagy a \"systemd-resolved\" (rendszer által feloldott) szolgáltatások használják. Kérjük, olvassa el <0>ezt az útmutatót a probléma megoldásához.", "adg_will_drop_dns_queries": "Az AdGuard Home eldobja az összes DNS kérést erről a kliensről.", - "client_not_in_allowed_clients": "Ez a kliens nincs engedélyezve, mivel nincs rajta az \"Engedélyezett kliensek\" listáján.", "experimental": "Kísérleti", "use_saved_key": "Előzőleg mentett kulcs használata" } diff --git a/client/src/__locales/id.json b/client/src/__locales/id.json index 44bf04bd..419d531c 100644 --- a/client/src/__locales/id.json +++ b/client/src/__locales/id.json @@ -45,7 +45,6 @@ "form_error_subnet": "Subnet \"{{cidr}}\" tidak berisi alamat IP \"{{ip}}\"", "form_error_positive": "Harus lebih dari 0", "form_error_negative": "Harus berjumlah 0 atau lebih besar dari 0", - "range_end_error": "Harus lebih besar dari rentang awal", "dhcp_form_gateway_input": "IP gateway", "dhcp_form_subnet_input": "Subnet mask", "dhcp_form_range_title": "Rentang alamat IP", @@ -612,7 +611,6 @@ "click_to_view_queries": "Klik untuk lihat permintaan", "port_53_faq_link": "Port 53 sering ditempati oleh layanan \"DNSStubListener\" atau \"systemd-resolved\". Silakan baca <0>instruksi ini tentang cara menyelesaikan ini.", "adg_will_drop_dns_queries": "AdGuard Home akan menghapus semua permintaan DNS dari klien ini.", - "client_not_in_allowed_clients": "Klien tidak diizinkan karena tidak ada dalam daftar \"Klien yang diizinkan\".", "experimental": "Eksperimental", "use_saved_key": "Gunakan kunci yang disimpan sebelumnya" } diff --git a/client/src/__locales/it.json b/client/src/__locales/it.json index 663df040..86364d16 100644 --- a/client/src/__locales/it.json +++ b/client/src/__locales/it.json @@ -36,16 +36,24 @@ "dhcp_ipv4_settings": "Impostazioni DHCP IPv4", "dhcp_ipv6_settings": "Impostazioni DHCP IPv6", "form_error_required": "Campo richiesto", - "form_error_ip4_format": "Formato IPv4 non valido", - "form_error_ip6_format": "Formato IPv6 non valido", - "form_error_ip_format": "Formato IPv4 non valido", - "form_error_mac_format": "Formato MAC non valido", - "form_error_client_id_format": "Formato ID cliente non valido", + "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": "ID cliente non valido", "form_error_server_name": "Nome server non valido", "form_error_subnet": "La subnet \"{{cidr}}\" non contiene l\\'indirizzo IP \"{{ip}}\"", "form_error_positive": "Deve essere maggiore di 0", "form_error_negative": "Deve essere maggiore o uguale a 0 (zero)", - "range_end_error": "Deve essere maggiore dell'intervallo di inizio", + "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", diff --git a/client/src/__locales/ja.json b/client/src/__locales/ja.json index 1bd4cd08..29543a57 100644 --- a/client/src/__locales/ja.json +++ b/client/src/__locales/ja.json @@ -45,7 +45,6 @@ "form_error_subnet": "IPアドレス「{{ip}}」はサブネット「{{cidr}}」に含まれていません", "form_error_positive": "0より大きい必要があります", "form_error_negative": "0以上である必要があります", - "range_end_error": "範囲開始よりも大きくなければなりません", "dhcp_form_gateway_input": "ゲートウェイIP", "dhcp_form_subnet_input": "サブネットマスク", "dhcp_form_range_title": "IPアドレスの範囲", diff --git a/client/src/__locales/ko.json b/client/src/__locales/ko.json index 8d2f1aac..221f0391 100644 --- a/client/src/__locales/ko.json +++ b/client/src/__locales/ko.json @@ -45,7 +45,6 @@ "form_error_subnet": "서브넷 \"{{cidr}}\"에 \"{{ip}}\" IP 주소가 없습니다", "form_error_positive": "0보다 커야 합니다", "form_error_negative": "반드시 0 이상이여야 합니다", - "range_end_error": "입력 값은 범위의 시작 지점보다 큰 값 이여야 합니다.", "dhcp_form_gateway_input": "게이트웨이 IP", "dhcp_form_subnet_input": "서브넷 마스크", "dhcp_form_range_title": "IP 주소 범위", diff --git a/client/src/__locales/nl.json b/client/src/__locales/nl.json index 57bd6ca7..5404198e 100644 --- a/client/src/__locales/nl.json +++ b/client/src/__locales/nl.json @@ -24,7 +24,7 @@ "unavailable_dhcp": "DHCP is niet beschikbaar", "unavailable_dhcp_desc": "AdGuard Home kan geen DHCP-server draaien op uw OS", "dhcp_title": "DHCP server (experimenteel!)", - "dhcp_description": "Indien je router geen DHCP instellingen heeft,kan je AdGuard's eigen ingebouwde DHCP server gebruiken.", + "dhcp_description": "Indien je router geen DHCP instellingen heeft, kan je AdGuard's eigen ingebouwde DHCP server gebruiken.", "dhcp_enable": "DHCP server inschakelen", "dhcp_disable": "DHCP server uitschakelen", "dhcp_not_found": "Het is veilig om de ingebouwde DHCP server in te schakelen omdat AdGuard Home geen actieve DHCP servers vond op het netwerk. We raden je echter aan om het handmatig opnieuw te controleren, omdat onze automatische test momenteel geen 100% garantie geeft.", @@ -36,16 +36,24 @@ "dhcp_ipv4_settings": "DHCP IPv4 instellingen", "dhcp_ipv6_settings": "DHCP IPv6 instellingen", "form_error_required": "Vereist veld", - "form_error_ip4_format": "Ongeldig IPv4 formaat", - "form_error_ip6_format": "Ongeldig IPv6 formaat", - "form_error_ip_format": "Ongeldig IPv4 formaat", - "form_error_mac_format": "Ongeldig MAC formaat.", - "form_error_client_id_format": "Opmaak cliënt-ID is ongeldig", + "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": "Ongeldige cliënt-ID", "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", "form_error_negative": "Moet 0 of hoger dan 0 zijn", - "range_end_error": "Moet groter zijn dan het startbereik", + "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", diff --git a/client/src/__locales/no.json b/client/src/__locales/no.json index 5ab93a6f..1e627129 100644 --- a/client/src/__locales/no.json +++ b/client/src/__locales/no.json @@ -29,7 +29,6 @@ "form_error_server_name": "Ugyldig tjenernavn", "form_error_positive": "Må være høyere enn 0", "form_error_negative": "Må være ≥0", - "range_end_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", @@ -556,6 +555,5 @@ "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.", - "client_not_in_allowed_clients": "Klienten er ikke tillatt, fordi den ikke er i «Tillatte klienter»-listen.", "experimental": "Eksperimentell" } diff --git a/client/src/__locales/pl.json b/client/src/__locales/pl.json index 98106587..4d730b7d 100644 --- a/client/src/__locales/pl.json +++ b/client/src/__locales/pl.json @@ -36,16 +36,24 @@ "dhcp_ipv4_settings": "Ustawienia serwera DHCP IPv4", "dhcp_ipv6_settings": "Ustawienia serwera DHCP IPv6", "form_error_required": "Pole jest wymagane", - "form_error_ip4_format": "Nieprawidłowy format IPv4", - "form_error_ip6_format": "Nieprawidłowy format IPv6", - "form_error_ip_format": "Nieprawidłowy format IP", - "form_error_mac_format": "Nieprawidłowy format MAC", - "form_error_client_id_format": "Nieprawidłowy format identyfikatora klienta", + "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": "Nieprawidłowy ID klienta", "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", "form_error_negative": "Musi być równy 0 lub większy", - "range_end_error": "Zakres musi być większy niż początkowy", + "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", diff --git a/client/src/__locales/pt-br.json b/client/src/__locales/pt-br.json index 9e989cea..955e96e2 100644 --- a/client/src/__locales/pt-br.json +++ b/client/src/__locales/pt-br.json @@ -36,16 +36,24 @@ "dhcp_ipv4_settings": "Configurações DHCP IPv4", "dhcp_ipv6_settings": "Configurações DHCP IPv6", "form_error_required": "Campo obrigatório", - "form_error_ip4_format": "Formato de endereço IPv4 inválido", - "form_error_ip6_format": "Formato de endereço IPv6 inválido", - "form_error_ip_format": "Formato de endereço IPv inválido", - "form_error_mac_format": "Formato do endereço MAC inválido", - "form_error_client_id_format": "Formato do ID de cliente inválido", + "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_client_id_format": "ID de cliente inválido", "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", "form_error_negative": "Deve ser igual ou superior a 0", - "range_end_error": "Deve ser maior que o início do intervalo", + "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", diff --git a/client/src/__locales/pt-pt.json b/client/src/__locales/pt-pt.json index 72bd8934..94785e1b 100644 --- a/client/src/__locales/pt-pt.json +++ b/client/src/__locales/pt-pt.json @@ -36,16 +36,24 @@ "dhcp_ipv4_settings": "Definições DHCP IPv4", "dhcp_ipv6_settings": "Definições DHCP IPv6", "form_error_required": "Campo obrigatório", - "form_error_ip4_format": "Formato de endereço IPv4 inválido", - "form_error_ip6_format": "Formato de endereço IPv6 inválido", - "form_error_ip_format": "Formato de endereço IPv4 inválido", - "form_error_mac_format": "Formato do endereço MAC inválido", - "form_error_client_id_format": "Formato inválido", + "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_client_id_format": "ID de cliente inválido", "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", "form_error_negative": "Deve ser igual ou superior a 0", - "range_end_error": "Deve ser maior que o início do intervalo", + "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", diff --git a/client/src/__locales/ro.json b/client/src/__locales/ro.json index 0f793be5..ac5183ac 100644 --- a/client/src/__locales/ro.json +++ b/client/src/__locales/ro.json @@ -36,16 +36,24 @@ "dhcp_ipv4_settings": "Setări DHCP IPv4", "dhcp_ipv6_settings": "Setări DHCP IPv6", "form_error_required": "Câmp necesar", - "form_error_ip4_format": "Format IPv4 invalid", - "form_error_ip6_format": "Format IPv6 invalid", - "form_error_ip_format": "Format IP invalid", - "form_error_mac_format": "Format MAC invalid", - "form_error_client_id_format": "Format ID de client invalid", + "form_error_ip4_format": "Adresă IPv4 nevalidă", + "form_error_ip4_range_start_format": "Adresă IPv4 de început al intervalului nevalidă", + "form_error_ip4_range_end_format": "Adresa IPv4 de sfârșit al intervalului nevalidă", + "form_error_ip4_gateway_format": "Adresă IPv4 a gateway-ului nevalidă", + "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": "ID client nevalid", "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", "form_error_negative": "Trebuie să fie egală cu 0 sau mai mare", - "range_end_error": "Trebuie să fie mai mare decât începutul intervalului", + "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", diff --git a/client/src/__locales/ru.json b/client/src/__locales/ru.json index 931d1ca6..d7d4f040 100644 --- a/client/src/__locales/ru.json +++ b/client/src/__locales/ru.json @@ -36,16 +36,24 @@ "dhcp_ipv4_settings": "Настройки DHCP IPv4", "dhcp_ipv6_settings": "Настройки DHCP IPv6", "form_error_required": "Обязательное поле", - "form_error_ip4_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_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", "form_error_negative": "Должно быть не меньше 0", - "range_end_error": "Должно превышать начало диапазона", + "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-адресов", diff --git a/client/src/__locales/sk.json b/client/src/__locales/sk.json index efb3fb90..8b2c9ed8 100644 --- a/client/src/__locales/sk.json +++ b/client/src/__locales/sk.json @@ -36,16 +36,24 @@ "dhcp_ipv4_settings": "Nastavenia DHCP IPv4", "dhcp_ipv6_settings": "Nastavenia DHCP IPv6", "form_error_required": "Povinná položka", - "form_error_ip4_format": "Nesprávny formát IPv4", - "form_error_ip6_format": "Nesprávny formát IPv6", - "form_error_ip_format": "Nesprávny formát IPv4", - "form_error_mac_format": "Nesprávny MAC formát", - "form_error_client_id_format": "Neplatný formát client ID", + "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": "Neplatné ID klienta", "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", "form_error_negative": "Musí byť číslo 0 alebo viac", - "range_end_error": "Musí byť väčšie ako začiatok rozsahu", + "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", diff --git a/client/src/__locales/sl.json b/client/src/__locales/sl.json index dca1cd38..cd7ebe21 100644 --- a/client/src/__locales/sl.json +++ b/client/src/__locales/sl.json @@ -36,16 +36,24 @@ "dhcp_ipv4_settings": "Nastavitve DHCP IPv4", "dhcp_ipv6_settings": "Nastavitve DHCP IPv6", "form_error_required": "Zahtevano polje", - "form_error_ip4_format": "Neveljaven format IPv4", - "form_error_ip6_format": "Neveljaven format IPv6", - "form_error_ip_format": "Neveljaven format IP", - "form_error_mac_format": "Neveljaven MAC format", - "form_error_client_id_format": "Neveljaven format ID odjemalca", + "form_error_ip4_format": "Neveljaven naslov IPv4", + "form_error_ip4_range_start_format": "Neveljaven začetek oblike razpona IPv4", + "form_error_ip4_range_end_format": "Neveljaven konec oblike razpona 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": "Neveljaven ID odjemalca", "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", "form_error_negative": "Mora biti enako ali več kot 0", - "range_end_error": "Mora biti večji od začtka razpona", + "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", diff --git a/client/src/__locales/sr-cs.json b/client/src/__locales/sr-cs.json index 819e3056..a902c929 100644 --- a/client/src/__locales/sr-cs.json +++ b/client/src/__locales/sr-cs.json @@ -27,7 +27,6 @@ "form_error_client_id_format": "Nevažeći format klijenta", "form_error_positive": "Mora biti veće od 0", "form_error_negative": "Mora biti 0 ili veće", - "range_end_error": "Mora biti veće od početnog opsega", "dhcp_form_gateway_input": "IP mrežnog prolaza", "dhcp_form_subnet_input": "Subnet mask", "dhcp_form_range_title": "Opseg IP adresa", @@ -552,6 +551,5 @@ "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.", - "client_not_in_allowed_clients": "Klijent nije dozvoljen zato što se ne nalazi na spisku dozvoljenih klijenata.", "experimental": "Eksperimentalno" } diff --git a/client/src/__locales/sv.json b/client/src/__locales/sv.json index 70f75570..a021f67e 100644 --- a/client/src/__locales/sv.json +++ b/client/src/__locales/sv.json @@ -16,8 +16,8 @@ "dhcp_static_leases": "Statiska DHCP-leases", "dhcp_leases_not_found": "Ingen DHCP-lease hittad", "form_error_required": "Obligatoriskt fält", - "form_error_ip_format": "Ogiltigt IPv4-format", - "form_error_mac_format": "Ogiltigt MAC-format", + "form_error_ip_format": "Ogiltig IP-adress", + "form_error_mac_format": "Ogiltig MAC-adress", "form_error_positive": "Måste vara större än noll", "dhcp_form_gateway_input": "Gateway-IP", "dhcp_form_subnet_input": "Subnetmask", diff --git a/client/src/__locales/tr.json b/client/src/__locales/tr.json index d027c6ea..a2e2e518 100644 --- a/client/src/__locales/tr.json +++ b/client/src/__locales/tr.json @@ -36,21 +36,29 @@ "dhcp_ipv4_settings": "DHCP IPv4 Ayarları", "dhcp_ipv6_settings": "DHCP IPv6 Ayarları", "form_error_required": "Gerekli alan", - "form_error_ip4_format": "Geçersiz IPv4 biçimi", - "form_error_ip6_format": "Geçersiz IPv6 biçimi", - "form_error_ip_format": "Geçersiz IP biçimi", - "form_error_mac_format": "Geçersiz MAC biçimi", - "form_error_client_id_format": "Geçersiz istemci kimliği biçimi", + "form_error_ip4_format": "Geçersiz IPv4 adresi", + "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": "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": "Geçersiz istemci kimliği", "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", "form_error_negative": "0 veya daha büyük olmalıdır", - "range_end_error": "Başlangıç aralığından daha büyük olmalı", + "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'si", "dhcp_form_subnet_input": "Alt ağ maskesi", "dhcp_form_range_title": "IP adresi aralığı", - "dhcp_form_range_start": "Aralık başlangıcı", - "dhcp_form_range_end": "Aralık sonu", + "dhcp_form_range_start": "Başlangıç aralığı", + "dhcp_form_range_end": "Bitiş aralığı", "dhcp_form_lease_title": "DHCP kira süresi (saniye olarak)", "dhcp_form_lease_input": "Kira süresi", "dhcp_interface_select": "DHCP arayüzünü seç", @@ -58,7 +66,7 @@ "dhcp_ip_addresses": "IP adresleri", "ip": "IP", "dhcp_table_hostname": "Bilgisayar Adı", - "dhcp_table_expires": "Geçerlilik Tarihi", + "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_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.", @@ -316,7 +324,7 @@ "install_devices_title": "Cihazlarınızı yapılandırın", "install_devices_desc": "AdGuard Home'u kullanmaya başlamak için, cihazlarınızı onu kullanacak şekilde yapılandırmanız gerekir.", "install_submit_title": "Tebrikler!", - "install_submit_desc": "Kurulum işlemi tamamlandı ve artık AdGuard Home'u kullanmaya hazırsınız.", + "install_submit_desc": "Yükleme işlemi tamamlandı ve artık AdGuard Home'u kullanmaya hazırsınız.", "install_devices_router": "Yönlendirici", "install_devices_router_desc": "Bu kurulum, ev yönlendiricinize bağlı tüm cihazları otomatik olarak kapsar ve her birini elle yapılandırmanıza gerek yoktur.", "install_devices_address": "AdGuard Home DNS sunucusu şu adresi dinleyecektir", @@ -501,7 +509,7 @@ "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? Zaman değerini azaltırsanız, bazı veriler kaybolacaktır", + "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", "statistics_cleared": "İstatistikler başarıyla temizlendi", "statistics_enable": "İstatistikleri etkinleştir", "interval_hours": "{{count}} saat", @@ -576,13 +584,13 @@ "dnssec_enable_desc": "Giden DNS sorguları için DNSSEC özelliğini etkinleştir ve sonucu kontrol et (DNSSEC özellikli çözümleyici gerekli).", "validated_with_dnssec": "DNSSEC ile doğrulandı", "all_queries": "Tüm sorgular", - "show_blocked_responses": "Engellendi", + "show_blocked_responses": "Engellenen", "show_whitelisted_responses": "İzin verilen", - "show_processed_responses": "İşlendi", + "show_processed_responses": "İşlenen", "blocked_safebrowsing": "Güvenli gezinti tarafından engellendi", "blocked_adult_websites": "Engellenen yetişkin içerikli siteler", "blocked_threats": "Engellenen tehditler", - "allowed": "İzin verildi", + "allowed": "İzin verilen", "filtered": "Filtrelenen", "rewritten": "Yeniden yazılan", "safe_search": "Güvenli arama", @@ -590,8 +598,8 @@ "milliseconds_abbreviation": "ms", "cache_size": "Önbellek boyutu", "cache_size_desc": "DNS önbellek boyutu (bayt cinsinden)", - "cache_ttl_min_override": "Minimum TTL'yi değiştir", - "cache_ttl_max_override": "Maksimum TTL'yi değiştir", + "cache_ttl_min_override": "Minimum TTL'i değiştir", + "cache_ttl_max_override": "Maksimum TTL'i değiştir", "enter_cache_size": "Önbellek boyutunu girin (bayt)", "enter_cache_ttl_min_override": "Minimum TTL değerini girin (saniye)", "enter_cache_ttl_max_override": "Maksimum TTL değerini girin (saniye)", diff --git a/client/src/__locales/uk.json b/client/src/__locales/uk.json index 256ee9b3..c8e14d6b 100644 --- a/client/src/__locales/uk.json +++ b/client/src/__locales/uk.json @@ -497,7 +497,7 @@ "interval_6_hour": "6 годин", "interval_24_hour": "24 години", "interval_days": "{{count}} день", - "interval_days_plural": "{{count}} днів", + "interval_days_plural": "{{count}} дні(в)", "domain": "Домен", "punycode": "Punycode", "answer": "Відповідь", diff --git a/client/src/__locales/vi.json b/client/src/__locales/vi.json index 671bd555..7fbc82a4 100644 --- a/client/src/__locales/vi.json +++ b/client/src/__locales/vi.json @@ -45,7 +45,6 @@ "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", "form_error_negative": "Phải lớn hơn hoặc bằng 0", - "range_end_error": "Phải lớn hơn khoảng bắt đầu", "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", diff --git a/client/src/__locales/zh-cn.json b/client/src/__locales/zh-cn.json index fcba2942..cbb94485 100644 --- a/client/src/__locales/zh-cn.json +++ b/client/src/__locales/zh-cn.json @@ -45,7 +45,6 @@ "form_error_subnet": "子网 \"{{cidr}}\" 不包含 IP 地址 \"{{ip}}\"", "form_error_positive": "必须大于 0", "form_error_negative": "必须大于等于 0", - "range_end_error": "必须大于范围起始值", "dhcp_form_gateway_input": "网关 IP", "dhcp_form_subnet_input": "子网掩码", "dhcp_form_range_title": "IP 地址范围", diff --git a/client/src/__locales/zh-hk.json b/client/src/__locales/zh-hk.json index bed3f38e..d6745fa9 100644 --- a/client/src/__locales/zh-hk.json +++ b/client/src/__locales/zh-hk.json @@ -45,7 +45,6 @@ "form_error_subnet": "子網路 \"{{cidr}}\" 不包含 IP 位址 \"{{ip}}\"", "form_error_positive": "數值必須大於 0", "form_error_negative": "數值必須大於等於 0", - "range_end_error": "必須大於起始值", "dhcp_form_gateway_input": "閘道 IP 位址", "dhcp_form_subnet_input": "子網路遮罩", "dhcp_form_range_title": "IP 位址範圍", @@ -612,6 +611,5 @@ "click_to_view_queries": "按一下以檢視查詢結果", "port_53_faq_link": "連接埠 53 經常被「DNSStubListener」或「systemd-resolved」服務佔用。請閱讀下列有關解決<0>這個問題的說明", "adg_will_drop_dns_queries": "AdGuard Home 將停止回應此用戶端的所有 DNS 查詢。", - "client_not_in_allowed_clients": "此用戶端不被允許,它不在\"允許的用戶端\"列表中。", "experimental": "實驗性" } diff --git a/client/src/__locales/zh-tw.json b/client/src/__locales/zh-tw.json index 108cb666..18424502 100644 --- a/client/src/__locales/zh-tw.json +++ b/client/src/__locales/zh-tw.json @@ -36,16 +36,24 @@ "dhcp_ipv4_settings": "DHCP IPv4 設定", "dhcp_ipv6_settings": "DHCP IPv6 設定", "form_error_required": "必填的欄位", - "form_error_ip4_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_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", "form_error_negative": "必須等於或大於 0", - "range_end_error": "必須大於起始範圍", + "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 位址範圍", From 51f11d2f8efd77191e331a6c02af6948a556bc1c Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Tue, 23 Nov 2021 18:01:48 +0300 Subject: [PATCH 027/135] Pull request: 3846 hosts querylog Merge in DNS/adguard-home from 3846-hosts-querylog to master Updates #3846. Squashed commit of the following: commit 722e96628b1ccca1a5b5a716b8bcb1da2aefcc3b Merge: a20ad71e ed868fa4 Author: Eugene Burkov Date: Tue Nov 23 17:52:08 2021 +0300 Merge branch 'master' into 3846-hosts-querylog commit a20ad71e723dbfa3483c3bdf9e4c8fd15c8b0e3c Author: Ildar Kamalov Date: Tue Nov 23 17:28:12 2021 +0300 client: fix variable name commit 7013bff05d6cff75c6c25a38d614db8b4b2f0b87 Author: Ildar Kamalov Date: Tue Nov 23 17:03:26 2021 +0300 client: fix missing import commit 8e4a0fb047b4d39ab44a285f59420573d7ba5eec Author: Ildar Kamalov Date: Tue Nov 23 16:56:50 2021 +0300 client: handle system host filter id commit abbbf662d2f3ea3f5d3569a9c45418e356adbf3c Author: Eugene Burkov Date: Mon Nov 22 13:54:52 2021 +0300 all: imp code commit c2df63e46e75f84f70a610d18deccbeee672ebda Author: Eugene Burkov Date: Mon Nov 22 12:50:51 2021 +0300 querylog: rm unused test data commit 8a1d47d266254fd4aedd4c61c7ea9e48168ea375 Author: Eugene Burkov Date: Mon Nov 22 02:52:50 2021 +0300 aghnet: final imps commit ade3acb4bebc8bdd755e56f314cdf19bc9375557 Author: Eugene Burkov Date: Fri Nov 19 15:48:40 2021 +0300 all: add hosts container rule list support --- client/src/__locales/en.json | 1 + client/src/helpers/constants.js | 1 + client/src/helpers/helpers.js | 6 +- internal/aghio/limitedreader.go | 2 +- internal/aghnet/hostscontainer.go | 286 +++++++++++++++++-------- internal/aghnet/hostscontainer_test.go | 261 +++++++++------------- internal/aghnet/testdata/etc_hosts | 14 ++ internal/filtering/dnsrewrite.go | 2 +- internal/filtering/filtering.go | 45 ++-- internal/querylog/decode.go | 71 +++++- internal/querylog/decode_test.go | 73 ++++++- 11 files changed, 475 insertions(+), 287 deletions(-) create mode 100644 internal/aghnet/testdata/etc_hosts diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index 7107418a..d63552f2 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -201,6 +201,7 @@ "form_error_url_or_path_format": "Invalid URL or absolute path of the list", "custom_filter_rules": "Custom filtering rules", "custom_filter_rules_hint": "Enter one rule on a line. You can use either adblock rules or hosts files syntax.", + "system_host_files": "System hosts files", "examples_title": "Examples", "example_meaning_filter_block": "block access to the example.org domain and all its subdomains", "example_meaning_filter_whitelist": "unblock access to the example.org domain and all its subdomains", diff --git a/client/src/helpers/constants.js b/client/src/helpers/constants.js index 195efdb3..0109e030 100644 --- a/client/src/helpers/constants.js +++ b/client/src/helpers/constants.js @@ -529,6 +529,7 @@ export const DETAILED_DATE_FORMAT_OPTIONS = { }; export const CUSTOM_FILTERING_RULES_ID = 0; +export const SYSTEM_HOSTS_FILTER_ID = -1; export const BLOCK_ACTIONS = { BLOCK: 'block', diff --git a/client/src/helpers/helpers.js b/client/src/helpers/helpers.js index d6eaa061..f5271106 100644 --- a/client/src/helpers/helpers.js +++ b/client/src/helpers/helpers.js @@ -26,6 +26,7 @@ import { STANDARD_DNS_PORT, STANDARD_HTTPS_PORT, STANDARD_WEB_PORT, + SYSTEM_HOSTS_FILTER_ID, } from './constants'; /** @@ -791,9 +792,12 @@ export const getFilterName = ( return i18n.t(customFilterTranslationKey); } + if (filterId === SYSTEM_HOSTS_FILTER_ID) { + return i18n.t('system_host_files'); + } + const matchIdPredicate = (filter) => filter.id === filterId; const filter = filters.find(matchIdPredicate) || whitelistFilters.find(matchIdPredicate); - return resolveFilterName(filter); }; diff --git a/internal/aghio/limitedreader.go b/internal/aghio/limitedreader.go index 5b6c57d9..02905e76 100644 --- a/internal/aghio/limitedreader.go +++ b/internal/aghio/limitedreader.go @@ -35,7 +35,7 @@ func (lr *limitedReader) Read(p []byte) (n int, err error) { } if int64(len(p)) > lr.n { - p = p[0:lr.n] + p = p[:lr.n] } n, err = lr.r.Read(p) diff --git a/internal/aghnet/hostscontainer.go b/internal/aghnet/hostscontainer.go index cfa55dd0..d6ca93f4 100644 --- a/internal/aghnet/hostscontainer.go +++ b/internal/aghnet/hostscontainer.go @@ -28,6 +28,69 @@ func DefaultHostsPaths() (paths []string) { return defaultHostsPaths() } +// requestMatcher combines the logic for matching requests and translating the +// appropriate rules. +type requestMatcher struct { + // stateLock protects all the fields of requestMatcher. + stateLock *sync.RWMutex + + // rulesStrg stores the rules obtained from the hosts' file. + rulesStrg *filterlist.RuleStorage + // engine serves rulesStrg. + engine *urlfilter.DNSEngine + + // translator maps generated $dnsrewrite rules into hosts-syntax rules. + // + // TODO(e.burkov): Store the filename from which the rule was parsed. + translator map[string]string +} + +// MatchRequest processes the request rewriting hostnames and addresses read +// from the operating system's hosts files. +// +// res is nil for any request having not an A/AAAA or PTR type. Results +// containing CNAME information may be queried again with the same question type +// and the returned CNAME for Host field of request. Results are guaranteed to +// be direct, i.e. any returned CNAME resolves into actual address like an alias +// in hosts does, see man hosts (5). +// +// It's safe for concurrent use. +func (rm *requestMatcher) MatchRequest( + req urlfilter.DNSRequest, +) (res *urlfilter.DNSResult, ok bool) { + switch req.DNSType { + case dns.TypeA, dns.TypeAAAA, dns.TypePTR: + log.Debug("%s: handling the request", hostsContainerPref) + default: + return nil, false + } + + rm.stateLock.RLock() + defer rm.stateLock.RUnlock() + + return rm.engine.MatchRequest(req) +} + +// Translate returns the source hosts-syntax rule for the generated dnsrewrite +// rule or an empty string if the last doesn't exist. +func (rm *requestMatcher) Translate(rule string) (hostRule string) { + rm.stateLock.RLock() + defer rm.stateLock.RUnlock() + + return rm.translator[rule] +} + +// resetEng updates container's engine and the translation map. +func (rm *requestMatcher) resetEng(rulesStrg *filterlist.RuleStorage, tr map[string]string) { + rm.stateLock.Lock() + defer rm.stateLock.Unlock() + + rm.rulesStrg = rulesStrg + rm.engine = urlfilter.NewDNSEngine(rm.rulesStrg) + + rm.translator = tr +} + // hostsContainerPref is a prefix for logging and wrapping errors in // HostsContainer's methods. const hostsContainerPref = "hosts container" @@ -35,13 +98,9 @@ const hostsContainerPref = "hosts container" // HostsContainer stores the relevant hosts database provided by the OS and // processes both A/AAAA and PTR DNS requests for those. type HostsContainer struct { - // engLock protects rulesStrg and engine. - engLock *sync.RWMutex - - // rulesStrg stores the rules obtained from the hosts' file. - rulesStrg *filterlist.RuleStorage - // engine serves rulesStrg. - engine *urlfilter.DNSEngine + // requestMatcher matches the requests and translates the rules. It's + // embedded to implement MatchRequest and Translate for *HostsContainer. + requestMatcher // done is the channel to sign closing the container. done chan struct{} @@ -87,7 +146,9 @@ func NewHostsContainer( } hc = &HostsContainer{ - engLock: &sync.RWMutex{}, + requestMatcher: requestMatcher{ + stateLock: &sync.RWMutex{}, + }, done: make(chan struct{}, 1), updates: make(chan *netutil.IPMap, 1), fsys: fsys, @@ -117,25 +178,6 @@ func NewHostsContainer( return hc, nil } -// MatchRequest is the request processing method to resolve hostnames and -// addresses from the operating system's hosts files. res is nil for any -// request having not an A/AAAA or PTR type. It's safe for concurrent use. -func (hc *HostsContainer) MatchRequest( - req urlfilter.DNSRequest, -) (res *urlfilter.DNSResult, ok bool) { - switch req.DNSType { - case dns.TypeA, dns.TypeAAAA, dns.TypePTR: - log.Debug("%s: handling the request", hostsContainerPref) - default: - return nil, false - } - - hc.engLock.RLock() - defer hc.engLock.RUnlock() - - return hc.engine.MatchRequest(req) -} - // Close implements the io.Closer interface for *HostsContainer. Close must // only be called once. The returned err is always nil. func (hc *HostsContainer) Close() (err error) { @@ -203,10 +245,17 @@ func (hc *HostsContainer) handleEvents() { } // hostsParser is a helper type to parse rules from the operating system's hosts -// file. +// file. It exists for only a single refreshing session. type hostsParser struct { - // rules builds the resulting rules list content. - rules *strings.Builder + // rulesBuilder builds the resulting rulesBuilder list content. + rulesBuilder *strings.Builder + + // translations maps generated $dnsrewrite rules to the hosts-translations + // rules. + translations map[string]string + + // cnameSet prevents duplicating cname rules. + cnameSet *stringutil.Set // table stores only the unique IP-hostname pairs. It's also sent to the // updates channel afterwards. @@ -215,8 +264,11 @@ type hostsParser struct { func (hc *HostsContainer) newHostsParser() (hp *hostsParser) { return &hostsParser{ - rules: &strings.Builder{}, - table: netutil.NewIPMap(hc.last.Len()), + rulesBuilder: &strings.Builder{}, + // For A/AAAA and PTRs. + translations: make(map[string]string, hc.last.Len()*2), + cnameSet: stringutil.NewSet(), + table: netutil.NewIPMap(hc.last.Len()), } } @@ -234,9 +286,7 @@ func (hp *hostsParser) parseFile( continue } - for _, host := range hosts { - hp.addPair(ip, host) - } + hp.addPairs(ip, hosts) } return nil, true, s.Err() @@ -244,7 +294,6 @@ func (hp *hostsParser) parseFile( // parseLine parses the line having the hosts syntax ignoring invalid ones. func (hp *hostsParser) parseLine(line string) (ip net.IP, hosts []string) { - line = strings.TrimSpace(line) fields := strings.Fields(line) if len(fields) < 2 { return nil, nil @@ -274,74 +323,142 @@ loop: return ip, hosts } -// add returns true if the pair of ip and host wasn't added to the hp before. -func (hp *hostsParser) add(ip net.IP, host string) (added bool) { +// Simple types of hosts in hosts database. Zero value isn't used to be able +// quizzaciously emulate nil with 0. +const ( + _ = iota + hostAlias + hostMain +) + +// add tries to add the ip-host pair. It returns: +// +// hostAlias if the host is not the first one added for the ip. +// hostMain if the host is the first one added for the ip. +// 0 if the ip-host pair has already been added. +// +func (hp *hostsParser) add(ip net.IP, host string) (hostType int) { v, ok := hp.table.Get(ip) - hosts, _ := v.(*stringutil.Set) - switch { + switch hosts, _ := v.(*stringutil.Set); { case ok && hosts.Has(host): - return false + return 0 case hosts == nil: hosts = stringutil.NewSet(host) hp.table.Set(ip, hosts) + + return hostMain default: hosts.Add(host) - } - return true + return hostAlias + } } -// addPair puts the pair of ip and host to the rules builder if needed. -func (hp *hostsParser) addPair(ip net.IP, host string) { +// addPair puts the pair of ip and host to the rules builder if needed. For +// each ip the first member of hosts will become the main one. +func (hp *hostsParser) addPairs(ip net.IP, hosts []string) { + // Put the rule in a preproccesed format like: + // + // ip host1 host2 ... + // + hostsLine := strings.Join(append([]string{ip.String()}, hosts...), " ") + var mainHost string + for _, host := range hosts { + switch hp.add(ip, host) { + case 0: + continue + case hostMain: + mainHost = host + added, addedPtr := hp.writeMainHostRule(host, ip) + hp.translations[added], hp.translations[addedPtr] = hostsLine, hostsLine + case hostAlias: + pair := fmt.Sprint(host, " ", mainHost) + if hp.cnameSet.Has(pair) { + continue + } + // Since the hostAlias couldn't be returned from add before the + // hostMain the mainHost shouldn't appear empty. + hp.writeAliasHostRule(host, mainHost) + hp.cnameSet.Add(pair) + } + + log.Debug("%s: added ip-host pair %q-%q", hostsContainerPref, ip, host) + } +} + +// writeAliasHostRule writes the CNAME rule for the alias-host pair into +// internal builders. +func (hp *hostsParser) writeAliasHostRule(alias, host string) { + const ( + nl = "\n" + sc = ";" + + rwSuccess = rules.MaskSeparator + "$dnsrewrite=NOERROR" + sc + "CNAME" + sc + constLen = len(rules.MaskStartURL) + len(rwSuccess) + len(nl) + ) + + hp.rulesBuilder.Grow(constLen + len(host) + len(alias)) + stringutil.WriteToBuilder(hp.rulesBuilder, rules.MaskStartURL, alias, rwSuccess, host, nl) +} + +// writeMainHostRule writes the actual rule for the qtype and the PTR for the +// host-ip pair into internal builders. +func (hp *hostsParser) writeMainHostRule(host string, ip net.IP) (added, addedPtr string) { arpa, err := netutil.IPToReversedAddr(ip) if err != nil { return } - if !hp.add(ip, host) { - return - } - - qtype := "AAAA" - if ip.To4() != nil { - // Assume the validation of the IP address is performed already. - qtype = "A" - } - const ( nl = "\n" - sc = ";" - rewriteSuccess = "$dnsrewrite=NOERROR" + sc - rewriteSuccessPTR = rewriteSuccess + "PTR" + sc + rwSuccess = "^$dnsrewrite=NOERROR;" + rwSuccessPTR = "^$dnsrewrite=NOERROR;PTR;" + + modLen = len("||") + len(rwSuccess) + modLenPTR = len("||") + len(rwSuccessPTR) ) + var qtype string + // The validation of the IP address has been performed earlier so it is + // guaranteed to be either an IPv4 or an IPv6. + if ip.To4() != nil { + qtype = "A" + } else { + qtype = "AAAA" + } + ipStr := ip.String() fqdn := dns.Fqdn(host) - for _, ruleData := range [...][]string{{ - // A/AAAA. - rules.MaskStartURL, + ruleBuilder := &strings.Builder{} + ruleBuilder.Grow(modLen + len(host) + len(qtype) + len(ipStr)) + stringutil.WriteToBuilder( + ruleBuilder, + "||", host, - rules.MaskSeparator, - rewriteSuccess, + rwSuccess, qtype, - sc, + ";", ipStr, - nl, - }, { - // PTR. - rules.MaskStartURL, - arpa, - rules.MaskSeparator, - rewriteSuccessPTR, - fqdn, - nl, - }} { - stringutil.WriteToBuilder(hp.rules, ruleData...) - } + ) + added = ruleBuilder.String() - log.Debug("%s: added ip-host pair %q/%q", hostsContainerPref, ip, host) + ruleBuilder.Reset() + ruleBuilder.Grow(modLenPTR + len(arpa) + len(fqdn)) + stringutil.WriteToBuilder( + ruleBuilder, + "||", + arpa, + rwSuccessPTR, + fqdn, + ) + addedPtr = ruleBuilder.String() + + hp.rulesBuilder.Grow(len(added) + len(addedPtr) + 2*len(nl)) + stringutil.WriteToBuilder(hp.rulesBuilder, added, nl, addedPtr, nl) + + return added, addedPtr } // equalSet returns true if the internal hosts table just parsed equals target. @@ -385,15 +502,16 @@ func (hp *hostsParser) sendUpd(ch chan *netutil.IPMap) { case ch <- upd: // The previous update was just read and the next one pushed. Go on. default: - log.Debug("%s: the channel is broken", hostsContainerPref) + log.Error("%s: the updates channel is broken", hostsContainerPref) } } // newStrg creates a new rules storage from parsed data. func (hp *hostsParser) newStrg() (s *filterlist.RuleStorage, err error) { return filterlist.NewRuleStorage([]filterlist.RuleList{&filterlist.StringRuleList{ + // TODO(e.burkov): Make configurable. ID: -1, - RulesText: hp.rules.String(), + RulesText: hp.rulesBuilder.String(), IgnoreCosmetic: true, }}) } @@ -424,15 +542,7 @@ func (hc *HostsContainer) refresh() (err error) { return fmt.Errorf("initializing rules storage: %w", err) } - hc.resetEng(rulesStrg) + hc.resetEng(rulesStrg, hp.translations) return nil } - -func (hc *HostsContainer) resetEng(rulesStrg *filterlist.RuleStorage) { - hc.engLock.Lock() - defer hc.engLock.Unlock() - - hc.rulesStrg = rulesStrg - hc.engine = urlfilter.NewDNSEngine(hc.rulesStrg) -} diff --git a/internal/aghnet/hostscontainer_test.go b/internal/aghnet/hostscontainer_test.go index 5a08b24f..5686a11b 100644 --- a/internal/aghnet/hostscontainer_test.go +++ b/internal/aghnet/hostscontainer_test.go @@ -3,6 +3,7 @@ package aghnet import ( "io/fs" "net" + "os" "path" "strings" "sync/atomic" @@ -11,9 +12,9 @@ import ( "github.com/AdguardTeam/AdGuardHome/internal/aghtest" "github.com/AdguardTeam/golibs/errors" - "github.com/AdguardTeam/golibs/netutil" "github.com/AdguardTeam/golibs/stringutil" "github.com/AdguardTeam/urlfilter" + "github.com/AdguardTeam/urlfilter/rules" "github.com/miekg/dns" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -203,129 +204,6 @@ func TestHostsContainer_Refresh(t *testing.T) { }) } -func TestHostsContainer_MatchRequest(t *testing.T) { - var ( - ip4 = net.IP{127, 0, 0, 1} - ip6 = net.IP{ - 128, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 1, - } - - hostname4 = "localhost" - hostname6 = "localhostv6" - hostname4a = "abcd" - - reversed4, _ = netutil.IPToReversedAddr(ip4) - reversed6, _ = netutil.IPToReversedAddr(ip6) - ) - - const filename = "file1" - - gsfs := fstest.MapFS{ - filename: &fstest.MapFile{Data: []byte( - ip4.String() + " " + hostname4 + " " + hostname4a + nl + - ip6.String() + " " + hostname6 + nl + - `256.256.256.256 fakebroadcast` + nl, - )}, - } - - hc, err := NewHostsContainer(gsfs, &aghtest.FSWatcher{ - OnEvents: func() (e <-chan struct{}) { panic("not implemented") }, - OnAdd: func(name string) (err error) { - assert.Equal(t, filename, name) - - return nil - }, - OnClose: func() (err error) { panic("not implemented") }, - }, filename) - require.NoError(t, err) - - testCase := []struct { - name string - want []interface{} - req urlfilter.DNSRequest - }{{ - name: "a", - want: []interface{}{ip4.To16()}, - req: urlfilter.DNSRequest{ - Hostname: hostname4, - DNSType: dns.TypeA, - }, - }, { - name: "a_for_aaaa", - want: []interface{}{ - ip4.To16(), - }, - req: urlfilter.DNSRequest{ - Hostname: hostname4, - DNSType: dns.TypeAAAA, - }, - }, { - name: "aaaa", - want: []interface{}{ip6}, - req: urlfilter.DNSRequest{ - Hostname: hostname6, - DNSType: dns.TypeAAAA, - }, - }, { - name: "ptr", - want: []interface{}{ - dns.Fqdn(hostname4), - dns.Fqdn(hostname4a), - }, - req: urlfilter.DNSRequest{ - Hostname: reversed4, - DNSType: dns.TypePTR, - }, - }, { - name: "ptr_v6", - want: []interface{}{dns.Fqdn(hostname6)}, - req: urlfilter.DNSRequest{ - Hostname: reversed6, - DNSType: dns.TypePTR, - }, - }, { - name: "a_alias", - want: []interface{}{ip4.To16()}, - req: urlfilter.DNSRequest{ - Hostname: hostname4a, - DNSType: dns.TypeA, - }, - }} - - for _, tc := range testCase { - t.Run(tc.name, func(t *testing.T) { - res, ok := hc.MatchRequest(tc.req) - require.False(t, ok) - require.NotNil(t, res) - - rws := res.DNSRewrites() - require.Len(t, rws, len(tc.want)) - - for i, w := range tc.want { - require.NotNil(t, rws[i]) - - rw := rws[i].DNSRewrite - require.NotNil(t, rw) - - assert.Equal(t, w, rw.Value) - } - }) - } - - t.Run("cname", func(t *testing.T) { - res, ok := hc.MatchRequest(urlfilter.DNSRequest{ - Hostname: hostname4, - DNSType: dns.TypeCNAME, - }) - require.False(t, ok) - - assert.Nil(t, res) - }) -} - func TestHostsContainer_PathsToPatterns(t *testing.T) { const ( dir0 = "dir" @@ -412,53 +290,108 @@ func TestHostsContainer_PathsToPatterns(t *testing.T) { }) } -func TestUniqueRules_AddPair(t *testing.T) { - knownIP := net.IP{1, 2, 3, 4} +func TestHostsContainer(t *testing.T) { + testdata := os.DirFS("./testdata") - const knownHost = "host1" + nRewrites := func(t *testing.T, res *urlfilter.DNSResult, n int) (rws []*rules.DNSRewrite) { + t.Helper() - ipToHost := netutil.NewIPMap(0) - ipToHost.Set(knownIP, *stringutil.NewSet(knownHost)) + rewrites := res.DNSRewrites() + assert.Len(t, rewrites, n) - testCases := []struct { - name string - host string - wantRules string - ip net.IP - }{{ - name: "new_one", - host: "host2", - wantRules: "||host2^$dnsrewrite=NOERROR;A;1.2.3.4\n" + - "||4.3.2.1.in-addr.arpa^$dnsrewrite=NOERROR;PTR;host2.\n", - ip: knownIP, - }, { - name: "existing_one", - host: knownHost, - wantRules: "||" + knownHost + "^$dnsrewrite=NOERROR;A;1.2.3.4\n" + - "||4.3.2.1.in-addr.arpa^$dnsrewrite=NOERROR;PTR;host1.\n", - ip: knownIP, - }, { - name: "new_ip", - host: knownHost, - wantRules: "||" + knownHost + "^$dnsrewrite=NOERROR;A;1.2.3.5\n" + - "||5.3.2.1.in-addr.arpa^$dnsrewrite=NOERROR;PTR;" + knownHost + ".\n", - ip: net.IP{1, 2, 3, 5}, - }, { - name: "bad_ip", - host: knownHost, - wantRules: "", - ip: net.IP{1, 2, 3, 4, 5}, - }} + for _, rewrite := range rewrites { + rw := rewrite.DNSRewrite + require.NotNil(t, rw) - for _, tc := range testCases { - hp := hostsParser{ - rules: &strings.Builder{}, - table: ipToHost.ShallowClone(), + rws = append(rws, rw) } + return rws + } + + testCases := []struct { + testTail func(t *testing.T, res *urlfilter.DNSResult) + name string + req urlfilter.DNSRequest + }{{ + name: "simple", + req: urlfilter.DNSRequest{ + Hostname: "simplehost", + DNSType: dns.TypeA, + }, + testTail: func(t *testing.T, res *urlfilter.DNSResult) { + rws := nRewrites(t, res, 2) + + v, ok := rws[0].Value.(net.IP) + require.True(t, ok) + + assert.True(t, net.IP{1, 0, 0, 1}.Equal(v)) + + v, ok = rws[1].Value.(net.IP) + require.True(t, ok) + + // It's ::1. + assert.True(t, net.IP(append((&[15]byte{})[:], byte(1))).Equal(v)) + }, + }, { + name: "hello_alias", + req: urlfilter.DNSRequest{ + Hostname: "hello.world", + DNSType: dns.TypeA, + }, + testTail: func(t *testing.T, res *urlfilter.DNSResult) { + assert.Equal(t, "hello", nRewrites(t, res, 1)[0].NewCNAME) + }, + }, { + name: "lots_of_aliases", + req: urlfilter.DNSRequest{ + Hostname: "for.testing", + DNSType: dns.TypeA, + }, + testTail: func(t *testing.T, res *urlfilter.DNSResult) { + assert.Equal(t, "a.whole", nRewrites(t, res, 1)[0].NewCNAME) + }, + }, { + name: "reverse", + req: urlfilter.DNSRequest{ + Hostname: "1.0.0.1.in-addr.arpa", + DNSType: dns.TypePTR, + }, + testTail: func(t *testing.T, res *urlfilter.DNSResult) { + rws := nRewrites(t, res, 1) + + assert.Equal(t, dns.TypePTR, rws[0].RRType) + assert.Equal(t, "simplehost.", rws[0].Value) + }, + }, { + name: "non-existing", + req: urlfilter.DNSRequest{ + Hostname: "nonexisting", + DNSType: dns.TypeA, + }, + testTail: func(t *testing.T, res *urlfilter.DNSResult) { + require.NotNil(t, res) + + assert.Nil(t, res.DNSRewrites()) + }, + }} + + stubWatcher := aghtest.FSWatcher{ + OnEvents: func() (e <-chan struct{}) { return nil }, + OnAdd: func(name string) (err error) { return nil }, + OnClose: func() (err error) { panic("not implemented") }, + } + + hc, err := NewHostsContainer(testdata, &stubWatcher, "etc_hosts") + require.NoError(t, err) + + for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - hp.addPair(tc.ip, tc.host) - assert.Equal(t, tc.wantRules, hp.rules.String()) + res, ok := hc.MatchRequest(tc.req) + require.False(t, ok) + require.NotNil(t, res) + + tc.testTail(t, res) }) } } diff --git a/internal/aghnet/testdata/etc_hosts b/internal/aghnet/testdata/etc_hosts new file mode 100644 index 00000000..d3cabac2 --- /dev/null +++ b/internal/aghnet/testdata/etc_hosts @@ -0,0 +1,14 @@ +# +# Test /etc/hosts file +# + +1.0.0.1 simplehost +1.0.0.0 hello hello.world + +# See https://github.com/AdguardTeam/AdGuardHome/issues/3846. +1.0.0.2 a.whole lot.of aliases for.testing + +# Same for IPv6. +::1 simplehost +:: hello hello.world +::2 a.whole lot.of aliases for.testing diff --git a/internal/filtering/dnsrewrite.go b/internal/filtering/dnsrewrite.go index a6dda4a6..5263f252 100644 --- a/internal/filtering/dnsrewrite.go +++ b/internal/filtering/dnsrewrite.go @@ -27,7 +27,7 @@ func (d *DNSFilter) processDNSRewrites(dnsr []*rules.NetworkRule) (res Result) { for _, nr := range dnsr { dr := nr.DNSRewrite if dr.NewCNAME != "" { - // NewCNAME rules have a higher priority than the other rules. + // NewCNAME rules have a higher priority than other rules. rules = []*ResultRule{{ FilterListID: int64(nr.GetFilterListID()), Text: nr.RuleText, diff --git a/internal/filtering/filtering.go b/internal/filtering/filtering.go index c4dd4c05..156b08e1 100644 --- a/internal/filtering/filtering.go +++ b/internal/filtering/filtering.go @@ -376,16 +376,8 @@ type Result struct { // Rules are applied rules. If Rules are not empty, each rule is not nil. Rules []*ResultRule `json:",omitempty"` - // ReverseHosts is the reverse lookup rewrite result. It is empty unless - // Reason is set to RewrittenAutoHosts. - // - // TODO(e.burkov): There is no need for AutoHosts-related fields any more - // since the hosts container now uses $dnsrewrite rules. These fields are - // only used in query log to decode old format. - ReverseHosts []string `json:",omitempty"` - // IPList is the lookup rewrite result. It is empty unless Reason is set to - // RewrittenAutoHosts or Rewritten. + // Rewritten. IPList []net.IP `json:",omitempty"` // CanonName is the CNAME value from the lookup rewrite result. It is empty @@ -464,7 +456,7 @@ func (d *DNSFilter) matchSysHosts( return res, nil } - dnsres, _ := d.EtcHosts.MatchRequest(urlfilter.DNSRequest{ + return d.matchSysHostsIntl(&urlfilter.DNSRequest{ Hostname: host, SortedClientTags: setts.ClientTags, // TODO(e.burkov): Wait for urlfilter update to pass net.IP. @@ -472,18 +464,34 @@ func (d *DNSFilter) matchSysHosts( ClientName: setts.ClientName, DNSType: qtype, }) +} + +// matchSysHostsIntl actually matches the request. It's separated to avoid +// perfoming checks twice. +func (d *DNSFilter) matchSysHostsIntl( + req *urlfilter.DNSRequest, +) (res Result, err error) { + dnsres, _ := d.EtcHosts.MatchRequest(*req) if dnsres == nil { return res, nil } - if dnsr := dnsres.DNSRewrites(); len(dnsr) > 0 { - // Check DNS rewrites first, because the API there is a bit awkward. - res = d.processDNSRewrites(dnsr) - res.Reason = RewrittenAutoHosts - // TODO(e.burkov): Put real hosts-syntax rules. - // - // See https://github.com/AdguardTeam/AdGuardHome/issues/3846. - res.Rules = nil + dnsr := dnsres.DNSRewrites() + if len(dnsr) == 0 { + return res, nil + } + + res = d.processDNSRewrites(dnsr) + if cn := res.CanonName; cn != "" { + // Probably an alias. + req.Hostname = cn + + return d.matchSysHostsIntl(req) + } + + res.Reason = RewrittenAutoHosts + for _, r := range res.Rules { + r.Text = stringutil.Coalesce(d.EtcHosts.Translate(r.Text), r.Text) } return res, nil @@ -799,7 +807,6 @@ func (d *DNSFilter) matchHost( } dnsres, ok := d.filteringEngine.MatchRequest(ureq) - // Check DNS rewrites first, because the API there is a bit awkward. if dnsr := dnsres.DNSRewrites(); len(dnsr) > 0 { res = d.processDNSRewrites(dnsr) diff --git a/internal/querylog/decode.go b/internal/querylog/decode.go index 944994a8..d23fc526 100644 --- a/internal/querylog/decode.go +++ b/internal/querylog/decode.go @@ -291,10 +291,13 @@ func decodeResultRules(dec *json.Decoder, ent *logEntry) { } if d, ok := keyToken.(json.Delim); ok { - if d == '}' { + switch d { + case '}': i++ - } else if d == ']' { + case ']': return + default: + // Go on. } continue @@ -312,6 +315,11 @@ func decodeResultRules(dec *json.Decoder, ent *logEntry) { } } +// decodeResultReverseHosts parses the dec's tokens into ent interpreting it as +// the result of hosts container's $dnsrewrite rule. It assumes there are no +// other occurrences of DNSRewriteResult in the entry since hosts container's +// rewrites currently has the highest priority along the entire filtering +// pipeline. func decodeResultReverseHosts(dec *json.Decoder, ent *logEntry) { for { itemToken, err := dec.Token() @@ -335,7 +343,25 @@ func decodeResultReverseHosts(dec *json.Decoder, ent *logEntry) { return case string: - ent.Result.ReverseHosts = append(ent.Result.ReverseHosts, v) + v = dns.Fqdn(v) + if res := &ent.Result; res.DNSRewriteResult == nil { + res.DNSRewriteResult = &filtering.DNSRewriteResult{ + RCode: dns.RcodeSuccess, + Response: filtering.DNSRewriteResultResponse{ + dns.TypePTR: []rules.RRValue{v}, + }, + } + + continue + } else { + res.DNSRewriteResult.RCode = dns.RcodeSuccess + } + + if rres := ent.Result.DNSRewriteResult; rres.Response == nil { + rres.Response = filtering.DNSRewriteResultResponse{dns.TypePTR: []rules.RRValue{v}} + } else { + rres.Response[dns.TypePTR] = append(rres.Response[dns.TypePTR], v) + } default: continue } @@ -407,9 +433,9 @@ func decodeResultDNSRewriteResultKey(key string, dec *json.Decoder, ent *logEntr ent.Result.DNSRewriteResult.Response = filtering.DNSRewriteResultResponse{} } - // TODO(a.garipov): I give up. This whole file is a mess. - // Luckily, we can assume that this field is relatively rare and - // just use the normal decoding and correct the values. + // TODO(a.garipov): I give up. This whole file is a mess. Luckily, we + // can assume that this field is relatively rare and just use the normal + // decoding and correct the values. err = dec.Decode(&ent.Result.DNSRewriteResult.Response) if err != nil { log.Debug("decodeResultDNSRewriteResultKey response err: %s", err) @@ -463,7 +489,40 @@ func decodeResultDNSRewriteResult(dec *json.Decoder, ent *logEntry) { } } +// translateResult converts some fields of the ent.Result to the format +// consistent with current implementation. +func translateResult(ent *logEntry) { + res := &ent.Result + if res.Reason != filtering.RewrittenAutoHosts || len(res.IPList) == 0 { + return + } + + if res.DNSRewriteResult == nil { + res.DNSRewriteResult = &filtering.DNSRewriteResult{ + RCode: dns.RcodeSuccess, + } + } + + if res.DNSRewriteResult.Response == nil { + res.DNSRewriteResult.Response = filtering.DNSRewriteResultResponse{} + } + + resp := res.DNSRewriteResult.Response + for _, ip := range res.IPList { + qType := dns.TypeAAAA + if ip.To4() != nil { + qType = dns.TypeA + } + + resp[qType] = append(resp[qType], ip) + } + + res.IPList = nil +} + func decodeResult(dec *json.Decoder, ent *logEntry) { + defer translateResult(ent) + for { keyToken, err := dec.Token() if err != nil { diff --git a/internal/querylog/decode_test.go b/internal/querylog/decode_test.go index 3848d344..245681dd 100644 --- a/internal/querylog/decode_test.go +++ b/internal/querylog/decode_test.go @@ -36,7 +36,6 @@ func TestDecodeLogEntry(t *testing.T) { `"Result":{` + `"IsFiltered":true,` + `"Reason":3,` + - `"ReverseHosts":["example.net"],` + `"IPList":["127.0.0.2"],` + `"Rules":[{"FilterListID":42,"Text":"||an.yandex.ru","IP":"127.0.0.2"},` + `{"FilterListID":43,"Text":"||an2.yandex.ru","IP":"127.0.0.3"}],` + @@ -58,10 +57,9 @@ func TestDecodeLogEntry(t *testing.T) { ClientProto: "", Answer: ans, Result: filtering.Result{ - IsFiltered: true, - Reason: filtering.FilteredBlockList, - ReverseHosts: []string{"example.net"}, - IPList: []net.IP{net.IPv4(127, 0, 0, 2)}, + IsFiltered: true, + Reason: filtering.FilteredBlockList, + IPList: []net.IP{net.IPv4(127, 0, 0, 2)}, Rules: []*filtering.ResultRule{{ FilterListID: 42, Text: "||an.yandex.ru", @@ -170,8 +168,7 @@ func TestDecodeLogEntry(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - l := &logEntry{} - decodeLogEntry(l, tc.log) + decodeLogEntry(new(logEntry), tc.log) s := logOutput.String() if tc.want == "" { @@ -185,3 +182,65 @@ func TestDecodeLogEntry(t *testing.T) { }) } } + +func TestDecodeLogEntry_backwardCompatability(t *testing.T) { + var ( + a1, a2 = net.IP{127, 0, 0, 1}.To16(), net.IP{127, 0, 0, 2}.To16() + aaaa1, aaaa2 = net.ParseIP("::1"), net.ParseIP("::2") + ) + + testCases := []struct { + want *logEntry + entry string + name string + }{{ + entry: `{"Result":{"ReverseHosts":["example.net","example.org"]}`, + want: &logEntry{ + Result: filtering.Result{DNSRewriteResult: &filtering.DNSRewriteResult{ + RCode: dns.RcodeSuccess, + Response: filtering.DNSRewriteResultResponse{ + dns.TypePTR: []rules.RRValue{"example.net.", "example.org."}, + }, + }}, + }, + name: "reverse_hosts", + }, { + entry: `{"Result":{"IPList":["127.0.0.1","127.0.0.2","::1","::2"],"Reason":10}}`, + want: &logEntry{ + Result: filtering.Result{ + DNSRewriteResult: &filtering.DNSRewriteResult{ + RCode: dns.RcodeSuccess, + Response: filtering.DNSRewriteResultResponse{ + dns.TypeA: []rules.RRValue{a1, a2}, + dns.TypeAAAA: []rules.RRValue{aaaa1, aaaa2}, + }, + }, + Reason: filtering.RewrittenAutoHosts, + }, + }, + name: "iplist_autohosts", + }, { + entry: `{"Result":{"IPList":["127.0.0.1","127.0.0.2","::1","::2"],"Reason":9}}`, + want: &logEntry{ + Result: filtering.Result{ + IPList: []net.IP{ + a1, + a2, + aaaa1, + aaaa2, + }, + Reason: filtering.Rewritten, + }, + }, + name: "iplist_rewritten", + }} + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + e := &logEntry{} + decodeLogEntry(e, tc.entry) + + assert.Equal(t, tc.want, e) + }) + } +} From 322944073efacd6a4557a4b44b56627a7fd705a7 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Tue, 23 Nov 2021 20:45:14 +0300 Subject: [PATCH 028/135] Pull request: home: imp logs Closes #3869. Squashed commit of the following: commit 8ee0625ea2ac1f6615ad56c819fbb0c4974767e5 Author: Ainar Garipov Date: Tue Nov 23 20:33:14 2021 +0300 home: imp logs --- internal/home/service.go | 53 ++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/internal/home/service.go b/internal/home/service.go index 28bf4fd6..4d003584 100644 --- a/internal/home/service.go +++ b/internal/home/service.go @@ -97,7 +97,7 @@ func svcAction(s service.Service, action string) (err error) { // exist, find our PID using 'ps' command. func sendSigReload() { if runtime.GOOS == "windows" { - log.Error("not implemented on windows") + log.Error("service: not implemented on windows") return } @@ -107,25 +107,24 @@ func sendSigReload() { data, err := os.ReadFile(pidfile) if errors.Is(err, os.ErrNotExist) { if pid, err = aghos.PIDByCommand(serviceName, os.Getpid()); err != nil { - log.Error("finding AdGuardHome process: %s", err) + log.Error("service: finding AdGuardHome process: %s", err) return } } else if err != nil { - log.Error("reading pid file %s: %s", pidfile, err) + log.Error("service: reading pid file %s: %s", pidfile, err) return - } else { parts := strings.SplitN(string(data), "\n", 2) if len(parts) == 0 { - log.Error("can't read pid file %s: bad value", pidfile) + log.Error("service: parsing pid file %s: bad value", pidfile) return } if pid, err = strconv.Atoi(strings.TrimSpace(parts[0])); err != nil { - log.Error("can't read pid file %s: %s", pidfile, err) + log.Error("service: parsing pid from file %s: %s", pidfile, err) return } @@ -133,18 +132,18 @@ func sendSigReload() { var proc *os.Process if proc, err = os.FindProcess(pid); err != nil { - log.Error("can't send signal to pid %d: %s", pid, err) + log.Error("service: finding process for pid %d: %s", pid, err) return } if err = proc.Signal(syscall.SIGHUP); err != nil { - log.Error("Can't send signal to pid %d: %s", pid, err) + log.Error("service: sending signal HUP to pid %d: %s", pid, err) return } - log.Debug("sent signal to PID %d", pid) + log.Debug("service: sent signal to pid %d", pid) } // handleServiceControlAction one of the possible control actions: @@ -163,7 +162,7 @@ func handleServiceControlAction(opts options, clientBuildFS fs.FS) { chooseSystem() action := opts.serviceControlAction - log.Printf("Service control action: %s", action) + log.Printf("service: control action: %s", action) if action == "reload" { sendSigReload() @@ -173,7 +172,7 @@ func handleServiceControlAction(opts options, clientBuildFS fs.FS) { pwd, err := os.Getwd() if err != nil { - log.Fatal("Unable to find the path to the current directory") + log.Fatalf("service: getting current directory: %s", err) } runOpts := opts @@ -193,7 +192,7 @@ func handleServiceControlAction(opts options, clientBuildFS fs.FS) { } var s service.Service if s, err = service.New(prg, svcConfig); err != nil { - log.Fatal(err) + log.Fatalf("service: initializing service: %s", err) } switch action { @@ -201,7 +200,7 @@ func handleServiceControlAction(opts options, clientBuildFS fs.FS) { handleServiceStatusCommand(s) case "run": if err = s.Run(); err != nil { - log.Fatalf("Failed to run service: %s", err) + log.Fatalf("service: failed to run service: %s", err) } case "install": initConfigFilename(opts) @@ -211,27 +210,27 @@ func handleServiceControlAction(opts options, clientBuildFS fs.FS) { handleServiceUninstallCommand(s) default: if err = svcAction(s, action); err != nil { - log.Fatal(err) + log.Fatalf("service: executing action %q: %s", action, err) } } - log.Printf("action %s has been done successfully on %s", action, service.ChosenSystem()) + log.Printf("service: action %s has been done successfully on %s", action, service.ChosenSystem()) } // handleServiceStatusCommand handles service "status" command. func handleServiceStatusCommand(s service.Service) { status, errSt := svcStatus(s) if errSt != nil { - log.Fatalf("failed to get service status: %s", errSt) + log.Fatalf("service: failed to get service status: %s", errSt) } switch status { case service.StatusUnknown: - log.Printf("Service status is unknown") + log.Printf("service: status is unknown") case service.StatusStopped: - log.Printf("Service is stopped") + log.Printf("service: stopped") case service.StatusRunning: - log.Printf("Service is running") + log.Printf("service: running") } } @@ -239,7 +238,7 @@ func handleServiceStatusCommand(s service.Service) { func handleServiceInstallCommand(s service.Service) { err := svcAction(s, "install") if err != nil { - log.Fatal(err) + log.Fatalf("service: executing action %q: %s", "install", err) } if aghos.IsOpenWrt() { @@ -248,16 +247,16 @@ func handleServiceInstallCommand(s service.Service) { // startup. _, err = runInitdCommand("enable") if err != nil { - log.Fatal(err) + log.Fatalf("service: running init enable: %s", err) } } // Start automatically after install. err = svcAction(s, "start") if err != nil { - log.Fatalf("Failed to start the service: %s", err) + log.Fatalf("service: starting: %s", err) } - log.Printf("Service has been started") + log.Printf("service: started") if detectFirstRun() { log.Printf(`Almost ready! @@ -276,24 +275,24 @@ func handleServiceUninstallCommand(s service.Service) { // as it will remove the symlink _, err := runInitdCommand("disable") if err != nil { - log.Fatal(err) + log.Fatalf("service: running init disable: %s", err) } } if err := svcAction(s, "uninstall"); err != nil { - log.Fatal(err) + log.Fatalf("service: executing action %q: %s", "uninstall", err) } if runtime.GOOS == "darwin" { // Remove log files on cleanup and log errors. err := os.Remove(launchdStdoutPath) if err != nil && !errors.Is(err, os.ErrNotExist) { - log.Printf("removing stdout file: %s", err) + log.Info("service: warning: removing stdout file: %s", err) } err = os.Remove(launchdStderrPath) if err != nil && !errors.Is(err, os.ErrNotExist) { - log.Printf("removing stderr file: %s", err) + log.Info("service: warning: removing stderr file: %s", err) } } } From 936a7057fd17809bb3c8e49ec590abd48a12c0b3 Mon Sep 17 00:00:00 2001 From: Ildar Kamalov Date: Wed, 24 Nov 2021 13:57:50 +0300 Subject: [PATCH 029/135] Pull request: 3824 fix DHCP empty form validation Closes #3824 Squashed commit of the following: commit 24d5770e2f276f710c011bf94e36702881ccbf1a Merge: 8f539900 32294407 Author: Ildar Kamalov Date: Wed Nov 24 12:21:23 2021 +0300 Merge branch 'master' into 3824-empty-values commit 8f539900489c940c6d7068d672420a553a1da299 Merge: 4be77268 51f11d2f Author: Ildar Kamalov Date: Tue Nov 23 19:06:44 2021 +0300 Merge branch 'master' into 3824-empty-values commit 4be77268ab1b3dc99b754b8002320a615db2d99e Author: Eugene Burkov Date: Tue Nov 23 19:04:06 2021 +0300 all: use new consts commit 701fd9a2b82d69c6b813a4a1889c65404ac3571b Author: Ildar Kamalov Date: Tue Nov 23 18:58:03 2021 +0300 client: get status on reset commit a20734cbf26a57ec96fdb6e0f868a8656751e80a Author: Eugene Burkov Date: Tue Nov 23 18:31:59 2021 +0300 dhcpd: fix reset defaults commit e2cb0cb0995e7b2dd3e194c5bb9fe944cf7be8f5 Author: Ildar Kamalov Date: Tue Nov 23 17:33:22 2021 +0300 client: fix DHCP empty form validation --- client/src/components/Settings/Dhcp/index.js | 1 + client/src/helpers/validators.js | 4 +++ internal/dhcpd/http.go | 34 ++++++++++++++------ internal/home/config.go | 6 ++-- 4 files changed, 32 insertions(+), 13 deletions(-) diff --git a/client/src/components/Settings/Dhcp/index.js b/client/src/components/Settings/Dhcp/index.js index 6208d4a6..a84e0a93 100644 --- a/client/src/components/Settings/Dhcp/index.js +++ b/client/src/components/Settings/Dhcp/index.js @@ -102,6 +102,7 @@ const Dhcp = () => { Object.values(DHCP_FORM_NAMES) .forEach((formName) => dispatch(destroy(formName))); dispatch(resetDhcp()); + dispatch(getDhcpStatus()); } }; diff --git a/client/src/helpers/validators.js b/client/src/helpers/validators.js index 54bf0341..2ac98a6b 100644 --- a/client/src/helpers/validators.js +++ b/client/src/helpers/validators.js @@ -68,6 +68,10 @@ export const validateIpv4 = (value) => { * @param allValues */ export const validateNotInRange = (value, allValues) => { + if (!allValues.v4) { + return undefined; + } + const { range_start, range_end } = allValues.v4; if (range_start && validateIpv4(range_start)) { diff --git a/internal/dhcpd/http.go b/internal/dhcpd/http.go index 990d3c7c..e016dee8 100644 --- a/internal/dhcpd/http.go +++ b/internal/dhcpd/http.go @@ -8,10 +8,12 @@ import ( "net/http" "os" "strings" + "time" "github.com/AdguardTeam/AdGuardHome/internal/aghnet" "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/log" + "github.com/AdguardTeam/golibs/timeutil" ) func httpError(r *http.Request, w http.ResponseWriter, code int, format string, args ...interface{}) { @@ -533,6 +535,13 @@ func (s *Server) handleDHCPRemoveStaticLease(w http.ResponseWriter, r *http.Requ } } +const ( + // DefaultDHCPLeaseTTL is the default time-to-live for leases. + DefaultDHCPLeaseTTL = uint32(timeutil.Day / time.Second) + // DefaultDHCPTimeoutICMP is the default timeout for waiting ICMP responses. + DefaultDHCPTimeoutICMP = 1000 +) + func (s *Server) handleReset(w http.ResponseWriter, r *http.Request) { err := s.Stop() if err != nil { @@ -547,19 +556,24 @@ func (s *Server) handleReset(w http.ResponseWriter, r *http.Request) { } oldconf := s.conf - s.conf = ServerConfig{} - s.conf.WorkDir = oldconf.WorkDir - s.conf.HTTPRegister = oldconf.HTTPRegister - s.conf.ConfigModified = oldconf.ConfigModified - s.conf.DBFilePath = oldconf.DBFilePath + s.conf = ServerConfig{ + WorkDir: oldconf.WorkDir, + HTTPRegister: oldconf.HTTPRegister, + ConfigModified: oldconf.ConfigModified, + DBFilePath: oldconf.DBFilePath, + } - v4conf := V4ServerConf{} - v4conf.ICMPTimeout = 1000 - v4conf.notify = s.onNotify + v4conf := V4ServerConf{ + LeaseDuration: DefaultDHCPLeaseTTL, + ICMPTimeout: DefaultDHCPTimeoutICMP, + notify: s.onNotify, + } s.srv4, _ = v4Create(v4conf) - v6conf := V6ServerConf{} - v6conf.notify = s.onNotify + v6conf := V6ServerConf{ + LeaseDuration: DefaultDHCPLeaseTTL, + notify: s.onNotify, + } s.srv6, _ = v6Create(v6conf) s.conf.ConfigModified() diff --git a/internal/home/config.go b/internal/home/config.go index 44afe953..3465c26f 100644 --- a/internal/home/config.go +++ b/internal/home/config.go @@ -232,9 +232,9 @@ func initConfig() { config.DNS.DnsfilterConf.CacheTime = 30 config.Filters = defaultFilters() - config.DHCP.Conf4.LeaseDuration = 86400 - config.DHCP.Conf4.ICMPTimeout = 1000 - config.DHCP.Conf6.LeaseDuration = 86400 + config.DHCP.Conf4.LeaseDuration = dhcpd.DefaultDHCPLeaseTTL + config.DHCP.Conf4.ICMPTimeout = dhcpd.DefaultDHCPTimeoutICMP + config.DHCP.Conf6.LeaseDuration = dhcpd.DefaultDHCPLeaseTTL if ch := version.Channel(); ch == version.ChannelEdge || ch == version.ChannelDevelopment { config.BetaBindPort = 3001 From 4f50519b9f11dd03f7f8e61985f4567665885f9a Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Fri, 26 Nov 2021 18:25:43 +0300 Subject: [PATCH 030/135] Pull request: 3846 filter lists ids Merge in DNS/adguard-home from 3846-list-ids to master Closes #3846. Squashed commit of the following: commit 02a12fc27bc5d3cf1a17fd43c6f05e2c389bd71d Author: Ildar Kamalov Date: Fri Nov 26 16:58:13 2021 +0300 client: fix name commit 6220570e6e9c968f0d3fa9d02c12099ce66aaaad Author: Ildar Kamalov Date: Fri Nov 26 16:46:54 2021 +0300 client: handle special filter ids commit dcdeb2d7f4500aab6ce5ffe642bdaacf291f5951 Author: Eugene Burkov Date: Fri Nov 26 15:52:06 2021 +0300 all: mv constants, imp config commit 8ceb4a2b351e595929d8b2af564c6d0267afa230 Author: Eugene Burkov Date: Fri Nov 26 15:04:36 2021 +0300 all: fix custom list id, log changes commit acb8b456e7f41a556da34cf10647eecee058beec Author: Eugene Burkov Date: Thu Nov 25 20:04:37 2021 +0300 all: rm global ctx, add const flt ids --- client/src/__locales/en.json | 4 +- client/src/helpers/constants.js | 10 +- client/src/helpers/helpers.js | 37 ++++-- internal/aghnet/hostscontainer.go | 17 ++- internal/aghnet/hostscontainer_test.go | 16 ++- internal/dnsforward/dnsforward_test.go | 2 +- internal/filtering/blocked.go | 2 +- internal/filtering/dnsrewrite_test.go | 2 +- internal/filtering/filtering.go | 151 ++++++++++++------------ internal/filtering/filtering_test.go | 57 +++++---- internal/filtering/rewrites_test.go | 8 +- internal/filtering/safebrowsing.go | 10 +- internal/filtering/safebrowsing_test.go | 14 +-- internal/filtering/safesearch.go | 10 +- internal/home/filter.go | 1 + internal/home/home.go | 1 + openapi/CHANGELOG.md | 15 +++ 17 files changed, 211 insertions(+), 146 deletions(-) diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index d63552f2..9caf8845 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -625,5 +625,7 @@ "filter_allowlist": "WARNING: This action also will exclude the rule \"{{disallowed_rule}}\" from the list of allowed clients.", "last_rule_in_allowlist": "Cannot disallow this client because excluding the rule \"{{disallowed_rule}}\" will DISABLE \"Allowed clients\" list.", "experimental": "Experimental", - "use_saved_key": "Use the previously saved key" + "use_saved_key": "Use the previously saved key", + "parental_control": "Parental control", + "safe_browsing": "Safe browsing" } diff --git a/client/src/helpers/constants.js b/client/src/helpers/constants.js index 0109e030..ee0fd779 100644 --- a/client/src/helpers/constants.js +++ b/client/src/helpers/constants.js @@ -528,8 +528,14 @@ export const DETAILED_DATE_FORMAT_OPTIONS = { month: 'long', }; -export const CUSTOM_FILTERING_RULES_ID = 0; -export const SYSTEM_HOSTS_FILTER_ID = -1; +export const SPECIAL_FILTER_ID = { + CUSTOM_FILTERING_RULES: 0, + SYSTEM_HOSTS: -1, + BLOCKED_SERVICES: -2, + PARENTAL: -3, + SAFE_BROWSING: -4, + SAFE_SEARCH: -5, +}; export const BLOCK_ACTIONS = { BLOCK: 'block', diff --git a/client/src/helpers/helpers.js b/client/src/helpers/helpers.js index f5271106..4c9803ae 100644 --- a/client/src/helpers/helpers.js +++ b/client/src/helpers/helpers.js @@ -13,7 +13,6 @@ import { ADDRESS_TYPES, CHECK_TIMEOUT, COMMENT_LINE_DEFAULT_TOKEN, - CUSTOM_FILTERING_RULES_ID, DEFAULT_DATE_FORMAT_OPTIONS, DEFAULT_LANGUAGE, DEFAULT_TIME_FORMAT, @@ -26,7 +25,7 @@ import { STANDARD_DNS_PORT, STANDARD_HTTPS_PORT, STANDARD_WEB_PORT, - SYSTEM_HOSTS_FILTER_ID, + SPECIAL_FILTER_ID, } from './constants'; /** @@ -774,6 +773,30 @@ export const sortIp = (a, b) => { } }; + +/** + * @param {number} filterId + * @returns {string} + */ +export const getSpecialFilterName = (filterId) => { + switch (filterId) { + case SPECIAL_FILTER_ID.CUSTOM_FILTERING_RULES: + return i18n.t('custom_filter_rules'); + case SPECIAL_FILTER_ID.SYSTEM_HOSTS: + return i18n.t('system_host_files'); + case SPECIAL_FILTER_ID.BLOCKED_SERVICES: + return i18n.t('blocked_services'); + case SPECIAL_FILTER_ID.PARENTAL: + return i18n.t('parental_control'); + case SPECIAL_FILTER_ID.SAFE_BROWSING: + return i18n.t('safe_browsing'); + case SPECIAL_FILTER_ID.SAFE_SEARCH: + return i18n.t('safe_search'); + default: + return i18n.t('unknown_filter', { filterId }); + } +}; + /** * @param {array} filters * @param {array} whitelistFilters @@ -785,15 +808,11 @@ export const getFilterName = ( filters, whitelistFilters, filterId, - customFilterTranslationKey = 'custom_filter_rules', resolveFilterName = (filter) => (filter ? filter.name : i18n.t('unknown_filter', { filterId })), ) => { - if (filterId === CUSTOM_FILTERING_RULES_ID) { - return i18n.t(customFilterTranslationKey); - } - - if (filterId === SYSTEM_HOSTS_FILTER_ID) { - return i18n.t('system_host_files'); + const specialFilterIds = Object.values(SPECIAL_FILTER_ID); + if (specialFilterIds.includes(filterId)) { + return getSpecialFilterName(filterId); } const matchIdPredicate = (filter) => filter.id === filterId; diff --git a/internal/aghnet/hostscontainer.go b/internal/aghnet/hostscontainer.go index d6ca93f4..1e1808bc 100644 --- a/internal/aghnet/hostscontainer.go +++ b/internal/aghnet/hostscontainer.go @@ -102,6 +102,9 @@ type HostsContainer struct { // embedded to implement MatchRequest and Translate for *HostsContainer. requestMatcher + // listID is the identifier for the list of generated rules. + listID int + // done is the channel to sign closing the container. done chan struct{} @@ -124,9 +127,11 @@ type HostsContainer struct { const ErrNoHostsPaths errors.Error = "no valid paths to hosts files provided" // NewHostsContainer creates a container of hosts, that watches the paths with -// w. paths shouldn't be empty and each of paths should locate either a file or -// a directory in fsys. fsys and w must be non-nil. +// w. listID is used as an identifier of the underlying rules list. paths +// shouldn't be empty and each of paths should locate either a file or a +// directory in fsys. fsys and w must be non-nil. func NewHostsContainer( + listID int, fsys fs.FS, w aghos.FSWatcher, paths ...string, @@ -149,6 +154,7 @@ func NewHostsContainer( requestMatcher: requestMatcher{ stateLock: &sync.RWMutex{}, }, + listID: listID, done: make(chan struct{}, 1), updates: make(chan *netutil.IPMap, 1), fsys: fsys, @@ -507,10 +513,9 @@ func (hp *hostsParser) sendUpd(ch chan *netutil.IPMap) { } // newStrg creates a new rules storage from parsed data. -func (hp *hostsParser) newStrg() (s *filterlist.RuleStorage, err error) { +func (hp *hostsParser) newStrg(id int) (s *filterlist.RuleStorage, err error) { return filterlist.NewRuleStorage([]filterlist.RuleList{&filterlist.StringRuleList{ - // TODO(e.burkov): Make configurable. - ID: -1, + ID: id, RulesText: hp.rulesBuilder.String(), IgnoreCosmetic: true, }}) @@ -538,7 +543,7 @@ func (hc *HostsContainer) refresh() (err error) { hc.last = hp.table.ShallowClone() var rulesStrg *filterlist.RuleStorage - if rulesStrg, err = hp.newStrg(); err != nil { + if rulesStrg, err = hp.newStrg(hc.listID); err != nil { return fmt.Errorf("initializing rules storage: %w", err) } diff --git a/internal/aghnet/hostscontainer_test.go b/internal/aghnet/hostscontainer_test.go index 5686a11b..9d2b6a10 100644 --- a/internal/aghnet/hostscontainer_test.go +++ b/internal/aghnet/hostscontainer_test.go @@ -73,7 +73,7 @@ func TestNewHostsContainer(t *testing.T) { return eventsCh } - hc, err := NewHostsContainer(testFS, &aghtest.FSWatcher{ + hc, err := NewHostsContainer(0, testFS, &aghtest.FSWatcher{ OnEvents: onEvents, OnAdd: onAdd, OnClose: func() (err error) { panic("not implemented") }, @@ -98,7 +98,7 @@ func TestNewHostsContainer(t *testing.T) { t.Run("nil_fs", func(t *testing.T) { require.Panics(t, func() { - _, _ = NewHostsContainer(nil, &aghtest.FSWatcher{ + _, _ = NewHostsContainer(0, nil, &aghtest.FSWatcher{ // Those shouldn't panic. OnEvents: func() (e <-chan struct{}) { return nil }, OnAdd: func(name string) (err error) { return nil }, @@ -109,7 +109,7 @@ func TestNewHostsContainer(t *testing.T) { t.Run("nil_watcher", func(t *testing.T) { require.Panics(t, func() { - _, _ = NewHostsContainer(testFS, nil, p) + _, _ = NewHostsContainer(0, testFS, nil, p) }) }) @@ -122,7 +122,7 @@ func TestNewHostsContainer(t *testing.T) { OnClose: func() (err error) { panic("not implemented") }, } - hc, err := NewHostsContainer(testFS, errWatcher, p) + hc, err := NewHostsContainer(0, testFS, errWatcher, p) require.ErrorIs(t, err, errOnAdd) assert.Nil(t, hc) @@ -164,7 +164,7 @@ func TestHostsContainer_Refresh(t *testing.T) { OnClose: func() (err error) { panic("not implemented") }, } - hc, err := NewHostsContainer(testFS, w, dirname) + hc, err := NewHostsContainer(0, testFS, w, dirname) require.NoError(t, err) checkRefresh := func(t *testing.T, wantHosts *stringutil.Set) { @@ -291,6 +291,8 @@ func TestHostsContainer_PathsToPatterns(t *testing.T) { } func TestHostsContainer(t *testing.T) { + const listID = 1234 + testdata := os.DirFS("./testdata") nRewrites := func(t *testing.T, res *urlfilter.DNSResult, n int) (rws []*rules.DNSRewrite) { @@ -300,6 +302,8 @@ func TestHostsContainer(t *testing.T) { assert.Len(t, rewrites, n) for _, rewrite := range rewrites { + require.Equal(t, listID, rewrite.FilterListID) + rw := rewrite.DNSRewrite require.NotNil(t, rw) @@ -382,7 +386,7 @@ func TestHostsContainer(t *testing.T) { OnClose: func() (err error) { panic("not implemented") }, } - hc, err := NewHostsContainer(testdata, &stubWatcher, "etc_hosts") + hc, err := NewHostsContainer(listID, testdata, &stubWatcher, "etc_hosts") require.NoError(t, err) for _, tc := range testCases { diff --git a/internal/dnsforward/dnsforward_test.go b/internal/dnsforward/dnsforward_test.go index 6f0ccc70..512eb87a 100644 --- a/internal/dnsforward/dnsforward_test.go +++ b/internal/dnsforward/dnsforward_test.go @@ -1078,7 +1078,7 @@ func TestPTRResponseFromHosts(t *testing.T) { } var eventsCalledCounter uint32 - hc, err := aghnet.NewHostsContainer(testFS, &aghtest.FSWatcher{ + hc, err := aghnet.NewHostsContainer(0, testFS, &aghtest.FSWatcher{ OnEvents: func() (e <-chan struct{}) { assert.Equal(t, uint32(1), atomic.AddUint32(&eventsCalledCounter, 1)) diff --git a/internal/filtering/blocked.go b/internal/filtering/blocked.go index df50f739..a11b72c7 100644 --- a/internal/filtering/blocked.go +++ b/internal/filtering/blocked.go @@ -239,7 +239,7 @@ func initBlockedServices() { for _, s := range serviceRulesArray { netRules := []*rules.NetworkRule{} for _, text := range s.rules { - rule, err := rules.NewNetworkRule(text, 0) + rule, err := rules.NewNetworkRule(text, BlockedSvcsListID) if err != nil { log.Error("rules.NewNetworkRule: %s rule: %s", err, text) continue diff --git a/internal/filtering/dnsrewrite_test.go b/internal/filtering/dnsrewrite_test.go index c471aa5f..877b46a8 100644 --- a/internal/filtering/dnsrewrite_test.go +++ b/internal/filtering/dnsrewrite_test.go @@ -49,7 +49,7 @@ func TestDNSFilter_CheckHostRules_dnsrewrite(t *testing.T) { |1.2.3.5.in-addr.arpa^$dnsrewrite=NOERROR;PTR;new-ptr-with-dot. ` - f := newForTest(nil, []Filter{{ID: 0, Data: []byte(text)}}) + f := newForTest(t, nil, []Filter{{ID: 0, Data: []byte(text)}}) setts := &Settings{ FilteringEnabled: true, } diff --git a/internal/filtering/filtering.go b/internal/filtering/filtering.go index 156b08e1..ab0c427a 100644 --- a/internal/filtering/filtering.go +++ b/internal/filtering/filtering.go @@ -4,6 +4,7 @@ package filtering import ( "context" "fmt" + "io/fs" "net" "net/http" "os" @@ -16,6 +17,7 @@ import ( "github.com/AdguardTeam/AdGuardHome/internal/aghnet" "github.com/AdguardTeam/dnsproxy/upstream" "github.com/AdguardTeam/golibs/cache" + "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/stringutil" "github.com/AdguardTeam/urlfilter" @@ -24,6 +26,18 @@ import ( "github.com/miekg/dns" ) +// The IDs of built-in filter lists. +// +// Keep in sync with client/src/helpers/contants.js. +const ( + CustomListID = -iota + SysHostsListID + BlockedSvcsListID + ParentalListID + SafeBrowsingListID + SafeSearchListID +) + // ServiceEntry - blocked service array element type ServiceEntry struct { Name string @@ -125,6 +139,10 @@ type DNSFilter struct { parentalUpstream upstream.Upstream safeBrowsingUpstream upstream.Upstream + safebrowsingCache cache.Cache + parentalCache cache.Cache + safeSearchCache cache.Cache + Config // for direct access by library users, even a = assignment // confLock protects Config. confLock sync.RWMutex @@ -340,14 +358,6 @@ func (d *DNSFilter) reset() { } } -type dnsFilterContext struct { - safebrowsingCache cache.Cache - parentalCache cache.Cache - safeSearchCache cache.Cache -} - -var gctx dnsFilterContext - // ResultRule contains information about applied rules. type ResultRule struct { // Text is the text of the rule. @@ -598,71 +608,70 @@ func matchBlockedServicesRules( // Adding rule and matching against the rules // -// fileExists returns true if file exists. -func fileExists(fn string) bool { - _, err := os.Stat(fn) - return err == nil -} - -func createFilteringEngine(filters []Filter) (*filterlist.RuleStorage, *urlfilter.DNSEngine, error) { - listArray := []filterlist.RuleList{} +func newRuleStorage(filters []Filter) (rs *filterlist.RuleStorage, err error) { + lists := make([]filterlist.RuleList, 0, len(filters)) for _, f := range filters { - var list filterlist.RuleList - - if f.ID == 0 { - list = &filterlist.StringRuleList{ - ID: 0, + switch id := int(f.ID); { + case len(f.Data) != 0: + lists = append(lists, &filterlist.StringRuleList{ + ID: id, RulesText: string(f.Data), IgnoreCosmetic: true, - } - } else if !fileExists(f.FilePath) { - list = &filterlist.StringRuleList{ - ID: int(f.ID), - IgnoreCosmetic: true, - } - } else if runtime.GOOS == "windows" { - // On Windows we don't pass a file to urlfilter because - // it's difficult to update this file while it's being - // used. - data, err := os.ReadFile(f.FilePath) - if err != nil { - return nil, nil, fmt.Errorf("reading filter content: %w", err) + }) + case f.FilePath == "": + continue + case runtime.GOOS == "windows": + // On Windows we don't pass a file to urlfilter because it's + // difficult to update this file while it's being used. + var data []byte + data, err = os.ReadFile(f.FilePath) + if errors.Is(err, fs.ErrNotExist) { + continue + } else if err != nil { + return nil, fmt.Errorf("reading filter content: %w", err) } - list = &filterlist.StringRuleList{ - ID: int(f.ID), + lists = append(lists, &filterlist.StringRuleList{ + ID: id, RulesText: string(data), IgnoreCosmetic: true, + }) + default: + var list *filterlist.FileRuleList + list, err = filterlist.NewFileRuleList(id, f.FilePath, true) + if errors.Is(err, fs.ErrNotExist) { + continue + } else if err != nil { + return nil, fmt.Errorf("creating file rule list with %q: %w", f.FilePath, err) } - } else { - var err error - list, err = filterlist.NewFileRuleList(int(f.ID), f.FilePath, true) - if err != nil { - return nil, nil, fmt.Errorf("filterlist.NewFileRuleList(): %s: %w", f.FilePath, err) - } + + lists = append(lists, list) } - listArray = append(listArray, list) } - rulesStorage, err := filterlist.NewRuleStorage(listArray) + rs, err = filterlist.NewRuleStorage(lists) if err != nil { - return nil, nil, fmt.Errorf("filterlist.NewRuleStorage(): %w", err) + return nil, fmt.Errorf("creating rule stroage: %w", err) } - filteringEngine := urlfilter.NewDNSEngine(rulesStorage) - return rulesStorage, filteringEngine, nil + + return rs, nil } // Initialize urlfilter objects. func (d *DNSFilter) initFiltering(allowFilters, blockFilters []Filter) error { - rulesStorage, filteringEngine, err := createFilteringEngine(blockFilters) + rulesStorage, err := newRuleStorage(blockFilters) if err != nil { return err } - rulesStorageAllow, filteringEngineAllow, err := createFilteringEngine(allowFilters) + + rulesStorageAllow, err := newRuleStorage(allowFilters) if err != nil { return err } + filteringEngine := urlfilter.NewDNSEngine(rulesStorage) + filteringEngineAllow := urlfilter.NewDNSEngine(rulesStorageAllow) + func() { d.engineLock.Lock() defer d.engineLock.Unlock() @@ -855,43 +864,37 @@ func makeResult(matchedRules []rules.Rule, reason Reason) (res Result) { } } -// InitModule manually initializes blocked services map. +// InitModule manually initializes blocked services map using blockedSvcListID +// as list ID for the rules. func InitModule() { initBlockedServices() } // New creates properly initialized DNS Filter that is ready to be used. -func New(c *Config, blockFilters []Filter) *DNSFilter { - var resolver Resolver = net.DefaultResolver +func New(c *Config, blockFilters []Filter) (d *DNSFilter) { + d = &DNSFilter{ + resolver: net.DefaultResolver, + } if c != nil { - cacheConf := cache.Config{ + + d.safebrowsingCache = cache.New(cache.Config{ EnableLRU: true, - } - - if gctx.safebrowsingCache == nil { - cacheConf.MaxSize = c.SafeBrowsingCacheSize - gctx.safebrowsingCache = cache.New(cacheConf) - } - - if gctx.safeSearchCache == nil { - cacheConf.MaxSize = c.SafeSearchCacheSize - gctx.safeSearchCache = cache.New(cacheConf) - } - - if gctx.parentalCache == nil { - cacheConf.MaxSize = c.ParentalCacheSize - gctx.parentalCache = cache.New(cacheConf) - } + MaxSize: c.SafeBrowsingCacheSize, + }) + d.safeSearchCache = cache.New(cache.Config{ + EnableLRU: true, + MaxSize: c.SafeSearchCacheSize, + }) + d.parentalCache = cache.New(cache.Config{ + EnableLRU: true, + MaxSize: c.ParentalCacheSize, + }) if c.CustomResolver != nil { - resolver = c.CustomResolver + d.resolver = c.CustomResolver } } - d := &DNSFilter{ - resolver: resolver, - } - d.hostCheckers = []hostChecker{{ check: d.matchSysHosts, name: "hosts container", diff --git a/internal/filtering/filtering_test.go b/internal/filtering/filtering_test.go index b389b386..79c4d040 100644 --- a/internal/filtering/filtering_test.go +++ b/internal/filtering/filtering_test.go @@ -27,11 +27,11 @@ var setts = Settings{ // Helpers. -func purgeCaches() { +func purgeCaches(d *DNSFilter) { for _, c := range []cache.Cache{ - gctx.safebrowsingCache, - gctx.parentalCache, - gctx.safeSearchCache, + d.safebrowsingCache, + d.parentalCache, + d.safeSearchCache, } { if c != nil { c.Clear() @@ -39,7 +39,7 @@ func purgeCaches() { } } -func newForTest(c *Config, filters []Filter) *DNSFilter { +func newForTest(t testing.TB, c *Config, filters []Filter) *DNSFilter { setts = Settings{ ProtectionEnabled: true, FilteringEnabled: true, @@ -54,7 +54,8 @@ func newForTest(c *Config, filters []Filter) *DNSFilter { setts.ParentalEnabled = c.ParentalEnabled } d := New(c, filters) - purgeCaches() + purgeCaches(d) + return d } @@ -105,7 +106,7 @@ func TestEtcHostsMatching(t *testing.T) { filters := []Filter{{ ID: 0, Data: []byte(text), }} - d := newForTest(nil, filters) + d := newForTest(t, nil, filters) t.Cleanup(d.Close) d.checkMatchIP(t, "google.com", addr, dns.TypeA) @@ -170,7 +171,7 @@ func TestSafeBrowsing(t *testing.T) { aghtest.ReplaceLogWriter(t, logOutput) aghtest.ReplaceLogLevel(t, log.DEBUG) - d := newForTest(&Config{SafeBrowsingEnabled: true}, nil) + d := newForTest(t, &Config{SafeBrowsingEnabled: true}, nil) t.Cleanup(d.Close) const matching = "wmconvirus.narod.ru" d.SetSafeBrowsingUpstream(&aghtest.TestBlockUpstream{ @@ -193,7 +194,7 @@ func TestSafeBrowsing(t *testing.T) { } func TestParallelSB(t *testing.T) { - d := newForTest(&Config{SafeBrowsingEnabled: true}, nil) + d := newForTest(t, &Config{SafeBrowsingEnabled: true}, nil) t.Cleanup(d.Close) const matching = "wmconvirus.narod.ru" d.SetSafeBrowsingUpstream(&aghtest.TestBlockUpstream{ @@ -217,7 +218,7 @@ func TestParallelSB(t *testing.T) { // Safe Search. func TestSafeSearch(t *testing.T) { - d := newForTest(&Config{SafeSearchEnabled: true}, nil) + d := newForTest(t, &Config{SafeSearchEnabled: true}, nil) t.Cleanup(d.Close) val, ok := d.SafeSearchDomain("www.google.com") require.True(t, ok) @@ -226,7 +227,9 @@ func TestSafeSearch(t *testing.T) { } func TestCheckHostSafeSearchYandex(t *testing.T) { - d := newForTest(&Config{SafeSearchEnabled: true}, nil) + d := newForTest(t, &Config{ + SafeSearchEnabled: true, + }, nil) t.Cleanup(d.Close) yandexIP := net.IPv4(213, 180, 193, 56) @@ -249,13 +252,14 @@ func TestCheckHostSafeSearchYandex(t *testing.T) { require.Len(t, res.Rules, 1) assert.Equal(t, yandexIP, res.Rules[0].IP) + assert.EqualValues(t, SafeSearchListID, res.Rules[0].FilterListID) }) } } func TestCheckHostSafeSearchGoogle(t *testing.T) { resolver := &aghtest.TestResolver{} - d := newForTest(&Config{ + d := newForTest(t, &Config{ SafeSearchEnabled: true, CustomResolver: resolver, }, nil) @@ -282,12 +286,13 @@ func TestCheckHostSafeSearchGoogle(t *testing.T) { require.Len(t, res.Rules, 1) assert.Equal(t, ip, res.Rules[0].IP) + assert.EqualValues(t, SafeSearchListID, res.Rules[0].FilterListID) }) } } func TestSafeSearchCacheYandex(t *testing.T) { - d := newForTest(nil, nil) + d := newForTest(t, nil, nil) t.Cleanup(d.Close) const domain = "yandex.ru" @@ -301,7 +306,7 @@ func TestSafeSearchCacheYandex(t *testing.T) { yandexIP := net.IPv4(213, 180, 193, 56) - d = newForTest(&Config{SafeSearchEnabled: true}, nil) + d = newForTest(t, &Config{SafeSearchEnabled: true}, nil) t.Cleanup(d.Close) res, err = d.CheckHost(domain, dns.TypeA, &setts) @@ -312,7 +317,7 @@ func TestSafeSearchCacheYandex(t *testing.T) { assert.Equal(t, res.Rules[0].IP, yandexIP) // Check cache. - cachedValue, isFound := getCachedResult(gctx.safeSearchCache, domain) + cachedValue, isFound := getCachedResult(d.safeSearchCache, domain) require.True(t, isFound) require.Len(t, cachedValue.Rules, 1) @@ -321,7 +326,7 @@ func TestSafeSearchCacheYandex(t *testing.T) { func TestSafeSearchCacheGoogle(t *testing.T) { resolver := &aghtest.TestResolver{} - d := newForTest(&Config{ + d := newForTest(t, &Config{ CustomResolver: resolver, }, nil) t.Cleanup(d.Close) @@ -334,7 +339,7 @@ func TestSafeSearchCacheGoogle(t *testing.T) { require.Empty(t, res.Rules) - d = newForTest(&Config{SafeSearchEnabled: true}, nil) + d = newForTest(t, &Config{SafeSearchEnabled: true}, nil) t.Cleanup(d.Close) d.resolver = resolver @@ -361,7 +366,7 @@ func TestSafeSearchCacheGoogle(t *testing.T) { assert.True(t, res.Rules[0].IP.Equal(ip)) // Check cache. - cachedValue, isFound := getCachedResult(gctx.safeSearchCache, domain) + cachedValue, isFound := getCachedResult(d.safeSearchCache, domain) require.True(t, isFound) require.Len(t, cachedValue.Rules, 1) @@ -375,7 +380,7 @@ func TestParentalControl(t *testing.T) { aghtest.ReplaceLogWriter(t, logOutput) aghtest.ReplaceLogLevel(t, log.DEBUG) - d := newForTest(&Config{ParentalEnabled: true}, nil) + d := newForTest(t, &Config{ParentalEnabled: true}, nil) t.Cleanup(d.Close) const matching = "pornhub.com" d.SetParentalUpstream(&aghtest.TestBlockUpstream{ @@ -679,7 +684,7 @@ func TestMatching(t *testing.T) { for _, tc := range testCases { t.Run(fmt.Sprintf("%s-%s", tc.name, tc.host), func(t *testing.T) { filters := []Filter{{ID: 0, Data: []byte(tc.rules)}} - d := newForTest(nil, filters) + d := newForTest(t, nil, filters) t.Cleanup(d.Close) res, err := d.CheckHost(tc.host, tc.wantDNSType, &setts) @@ -705,7 +710,7 @@ func TestWhitelist(t *testing.T) { whiteFilters := []Filter{{ ID: 0, Data: []byte(whiteRules), }} - d := newForTest(nil, filters) + d := newForTest(t, nil, filters) err := d.SetFilters(filters, whiteFilters, false) require.NoError(t, err) @@ -750,7 +755,7 @@ func applyClientSettings(setts *Settings) { } func TestClientSettings(t *testing.T) { - d := newForTest( + d := newForTest(t, &Config{ ParentalEnabled: true, SafeBrowsingEnabled: false, @@ -829,7 +834,7 @@ func TestClientSettings(t *testing.T) { // Benchmarks. func BenchmarkSafeBrowsing(b *testing.B) { - d := newForTest(&Config{SafeBrowsingEnabled: true}, nil) + d := newForTest(b, &Config{SafeBrowsingEnabled: true}, nil) b.Cleanup(d.Close) blocked := "wmconvirus.narod.ru" d.SetSafeBrowsingUpstream(&aghtest.TestBlockUpstream{ @@ -845,7 +850,7 @@ func BenchmarkSafeBrowsing(b *testing.B) { } func BenchmarkSafeBrowsingParallel(b *testing.B) { - d := newForTest(&Config{SafeBrowsingEnabled: true}, nil) + d := newForTest(b, &Config{SafeBrowsingEnabled: true}, nil) b.Cleanup(d.Close) blocked := "wmconvirus.narod.ru" d.SetSafeBrowsingUpstream(&aghtest.TestBlockUpstream{ @@ -863,7 +868,7 @@ func BenchmarkSafeBrowsingParallel(b *testing.B) { } func BenchmarkSafeSearch(b *testing.B) { - d := newForTest(&Config{SafeSearchEnabled: true}, nil) + d := newForTest(b, &Config{SafeSearchEnabled: true}, nil) b.Cleanup(d.Close) for n := 0; n < b.N; n++ { val, ok := d.SafeSearchDomain("www.google.com") @@ -874,7 +879,7 @@ func BenchmarkSafeSearch(b *testing.B) { } func BenchmarkSafeSearchParallel(b *testing.B) { - d := newForTest(&Config{SafeSearchEnabled: true}, nil) + d := newForTest(b, &Config{SafeSearchEnabled: true}, nil) b.Cleanup(d.Close) b.RunParallel(func(pb *testing.PB) { for pb.Next() { diff --git a/internal/filtering/rewrites_test.go b/internal/filtering/rewrites_test.go index 551a7faf..f02582c1 100644 --- a/internal/filtering/rewrites_test.go +++ b/internal/filtering/rewrites_test.go @@ -12,7 +12,7 @@ import ( // TODO(e.burkov): All the tests in this file may and should me merged together. func TestRewrites(t *testing.T) { - d := newForTest(nil, nil) + d := newForTest(t, nil, nil) t.Cleanup(d.Close) d.Rewrites = []RewriteEntry{{ @@ -163,7 +163,7 @@ func TestRewrites(t *testing.T) { } func TestRewritesLevels(t *testing.T) { - d := newForTest(nil, nil) + d := newForTest(t, nil, nil) t.Cleanup(d.Close) // Exact host, wildcard L2, wildcard L3. d.Rewrites = []RewriteEntry{{ @@ -209,7 +209,7 @@ func TestRewritesLevels(t *testing.T) { } func TestRewritesExceptionCNAME(t *testing.T) { - d := newForTest(nil, nil) + d := newForTest(t, nil, nil) t.Cleanup(d.Close) // Wildcard and exception for a sub-domain. d.Rewrites = []RewriteEntry{{ @@ -257,7 +257,7 @@ func TestRewritesExceptionCNAME(t *testing.T) { } func TestRewritesExceptionIP(t *testing.T) { - d := newForTest(nil, nil) + d := newForTest(t, nil, nil) t.Cleanup(d.Close) // Exception for AAAA record. d.Rewrites = []RewriteEntry{{ diff --git a/internal/filtering/safebrowsing.go b/internal/filtering/safebrowsing.go index ec626315..495a9067 100644 --- a/internal/filtering/safebrowsing.go +++ b/internal/filtering/safebrowsing.go @@ -318,7 +318,7 @@ func (d *DNSFilter) checkSafeBrowsing( sctx := &sbCtx{ host: host, svc: "SafeBrowsing", - cache: gctx.safebrowsingCache, + cache: d.safebrowsingCache, cacheTime: d.Config.CacheTime, } @@ -326,7 +326,8 @@ func (d *DNSFilter) checkSafeBrowsing( IsFiltered: true, Reason: FilteredSafeBrowsing, Rules: []*ResultRule{{ - Text: "adguard-malware-shavar", + Text: "adguard-malware-shavar", + FilterListID: SafeBrowsingListID, }}, } @@ -351,7 +352,7 @@ func (d *DNSFilter) checkParental( sctx := &sbCtx{ host: host, svc: "Parental", - cache: gctx.parentalCache, + cache: d.parentalCache, cacheTime: d.Config.CacheTime, } @@ -359,7 +360,8 @@ func (d *DNSFilter) checkParental( IsFiltered: true, Reason: FilteredParental, Rules: []*ResultRule{{ - Text: "parental CATEGORY_BLACKLISTED", + Text: "parental CATEGORY_BLACKLISTED", + FilterListID: ParentalListID, }}, } diff --git a/internal/filtering/safebrowsing_test.go b/internal/filtering/safebrowsing_test.go index c88576f1..2dec3668 100644 --- a/internal/filtering/safebrowsing_test.go +++ b/internal/filtering/safebrowsing_test.go @@ -108,7 +108,7 @@ func TestSafeBrowsingCache(t *testing.T) { } func TestSBPC_checkErrorUpstream(t *testing.T) { - d := newForTest(&Config{SafeBrowsingEnabled: true}, nil) + d := newForTest(t, &Config{SafeBrowsingEnabled: true}, nil) t.Cleanup(d.Close) ups := &aghtest.TestErrUpstream{} @@ -130,7 +130,7 @@ func TestSBPC_checkErrorUpstream(t *testing.T) { } func TestSBPC(t *testing.T) { - d := newForTest(&Config{SafeBrowsingEnabled: true}, nil) + d := newForTest(t, &Config{SafeBrowsingEnabled: true}, nil) t.Cleanup(d.Close) const hostname = "example.org" @@ -147,22 +147,22 @@ func TestSBPC(t *testing.T) { name string block bool }{{ - testCache: gctx.safebrowsingCache, + testCache: d.safebrowsingCache, testFunc: d.checkSafeBrowsing, name: "sb_no_block", block: false, }, { - testCache: gctx.safebrowsingCache, + testCache: d.safebrowsingCache, testFunc: d.checkSafeBrowsing, name: "sb_block", block: true, }, { - testCache: gctx.parentalCache, + testCache: d.parentalCache, testFunc: d.checkParental, name: "pc_no_block", block: false, }, { - testCache: gctx.parentalCache, + testCache: d.parentalCache, testFunc: d.checkParental, name: "pc_block", block: true, @@ -217,6 +217,6 @@ func TestSBPC(t *testing.T) { assert.Equal(t, 1, ups.RequestsCount()) }) - purgeCaches() + purgeCaches(d) } } diff --git a/internal/filtering/safesearch.go b/internal/filtering/safesearch.go index ff89b950..c67ac735 100644 --- a/internal/filtering/safesearch.go +++ b/internal/filtering/safesearch.go @@ -84,7 +84,7 @@ func (d *DNSFilter) checkSafeSearch( } // Check cache. Return cached result if it was found - cachedValue, isFound := getCachedResult(gctx.safeSearchCache, host) + cachedValue, isFound := getCachedResult(d.safeSearchCache, host) if isFound { // atomic.AddUint64(&gctx.stats.Safesearch.CacheHits, 1) log.Tracef("SafeSearch: found in cache: %s", host) @@ -99,12 +99,14 @@ func (d *DNSFilter) checkSafeSearch( res = Result{ IsFiltered: true, Reason: FilteredSafeSearch, - Rules: []*ResultRule{{}}, + Rules: []*ResultRule{{ + FilterListID: SafeSearchListID, + }}, } if ip := net.ParseIP(safeHost); ip != nil { res.Rules[0].IP = ip - valLen := d.setCacheResult(gctx.safeSearchCache, host, res) + valLen := d.setCacheResult(d.safeSearchCache, host, res) log.Debug("SafeSearch: stored in cache: %s (%d bytes)", host, valLen) return res, nil @@ -123,7 +125,7 @@ func (d *DNSFilter) checkSafeSearch( res.Rules[0].IP = ip - l := d.setCacheResult(gctx.safeSearchCache, host, res) + l := d.setCacheResult(d.safeSearchCache, host, res) log.Debug("SafeSearch: stored in cache: %s (%d bytes)", host, l) return res, nil diff --git a/internal/home/filter.go b/internal/home/filter.go index 74f85356..e7688f3f 100644 --- a/internal/home/filter.go +++ b/internal/home/filter.go @@ -711,6 +711,7 @@ func enableFilters(async bool) { func enableFiltersLocked(async bool) { filters := []filtering.Filter{{ + ID: filtering.CustomListID, Data: []byte(strings.Join(config.UserRules, "\n")), }} diff --git a/internal/home/home.go b/internal/home/home.go index 1148ed6a..ec103b1f 100644 --- a/internal/home/home.go +++ b/internal/home/home.go @@ -244,6 +244,7 @@ func setupHostsContainer() (err error) { } Context.etcHosts, err = aghnet.NewHostsContainer( + filtering.SysHostsListID, aghos.RootDirFS(), Context.hostsWatcher, aghnet.DefaultHostsPaths()..., diff --git a/openapi/CHANGELOG.md b/openapi/CHANGELOG.md index ef450844..7fceb418 100644 --- a/openapi/CHANGELOG.md +++ b/openapi/CHANGELOG.md @@ -4,6 +4,21 @@ ## v0.107: API changes +### New constant values for `filter_list_id` field in `ResultRule` + +* Value of `0` is now used for custom filtering rules list. + +* Value of `-1` is now used for rules generated from the operating system hosts + files. + +* Value of `-2` is now used for blocked services' rules. + +* Value of `-3` is now used for rules generated by parental control web service. + +* Value of `-4` is now used for rules generated by safe browsing web service. + +* Value of `-5` is now used for rules generated by safe search web service. + ### New possible value of `"name"` field in `QueryLogItemClient` * The value of `"name"` field in `GET /control/querylog` method is never empty: From b92b5fb46ac55f6f81a71b5927af7af94d7f1b25 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Mon, 29 Nov 2021 20:53:04 +0300 Subject: [PATCH 031/135] Pull request: client: imp ru i18n Merge in DNS/adguard-home from imp-ru-i18n to master Squashed commit of the following: commit e45e1fa4027f01c73c428b35679cac901d02e307 Merge: 33a9e1e3 4f50519b Author: Ainar Garipov Date: Mon Nov 29 20:38:35 2021 +0300 Merge branch 'master' into imp-ru-i18n commit 33a9e1e3de08de4779d3ca46404157388be12365 Author: Ainar Garipov Date: Mon Nov 29 19:27:37 2021 +0300 client: imp more commit 80eb407dad469155a21ff8f2d898d7fc86799ded Author: Ainar Garipov Date: Mon Nov 29 19:19:52 2021 +0300 client: imp ru i18n --- client/src/__locales/ru.json | 40 ++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/client/src/__locales/ru.json b/client/src/__locales/ru.json index d7d4f040..73dc1a27 100644 --- a/client/src/__locales/ru.json +++ b/client/src/__locales/ru.json @@ -36,15 +36,15 @@ "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_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", "form_error_negative": "Должно быть не меньше 0", @@ -197,8 +197,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.", "examples_title": "Примеры", @@ -322,9 +322,9 @@ "install_auth_password_enter": "Введите пароль", "install_step": "Шаг", "install_devices_title": "Настройте ваши устройства", - "install_devices_desc": "Для того, чтобы использовать AdGuard Home, вам нужно настроить ваши устройства на его использование.", + "install_devices_desc": "Чтобы использовать AdGuard Home, настройте ваши устройства на его использование.", "install_submit_title": "Поздравляем!", - "install_submit_desc": "Процедура настройки завершена, AdGuard Home готов к использованию.", + "install_submit_desc": "Настройка завершена, AdGuard Home готов к использованию.", "install_devices_router": "Роутер", "install_devices_router_desc": "Эта настройка покроет все устройства, подключенные к вашему домашнему роутеру, и вам не нужно будет настраивать каждое вручную.", "install_devices_address": "DNS-сервер AdGuard Home доступен по следующим адресам", @@ -370,7 +370,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": "Истекает", @@ -378,10 +378,10 @@ "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": "Имена хостов", @@ -474,8 +474,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": "Выбрать заблокированные сервисы", From 9c6d13991306d9a74e6a59954f507d37b15af6c3 Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Wed, 1 Dec 2021 16:26:46 +0300 Subject: [PATCH 032/135] Pull request: 3906 filewalker read limit Merge in DNS/adguard-home from 3906-filewalker-constraint to master Updates #3906. Squashed commit of the following: commit e1b654420a5031dbfe69d86c3fcf16a95a9ca935 Author: Eugene Burkov Date: Wed Dec 1 15:45:26 2021 +0300 aghos: rm filewalker limit --- internal/aghos/filewalker.go | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/internal/aghos/filewalker.go b/internal/aghos/filewalker.go index a72e2f5c..97f966af 100644 --- a/internal/aghos/filewalker.go +++ b/internal/aghos/filewalker.go @@ -5,7 +5,6 @@ import ( "io" "io/fs" - "github.com/AdguardTeam/AdGuardHome/internal/aghio" "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/stringutil" ) @@ -13,18 +12,15 @@ import ( // FileWalker is the signature of a function called for files in the file tree. // As opposed to filepath.Walk it only walk the files (not directories) matching // the provided pattern and those returned by function itself. All patterns -// should be valid for fs.Glob. If cont is false, the walking terminates. Each -// opened file is also limited for reading to MaxWalkedFileSize. +// should be valid for fs.Glob. If FileWalker returns false for cont then +// walking terminates. Prefer using bufio.Scanner to read the r since the input +// is not limited. // -// TODO(e.burkov, a.garipov): Move into another package like aghfs. +// TODO(e.burkov, a.garipov): Move into another package like aghfs. // // TODO(e.burkov): Think about passing filename or any additional data. type FileWalker func(r io.Reader) (patterns []string, cont bool, err error) -// MaxWalkedFileSize is the maximum length of the file that FileWalker can -// check. -const MaxWalkedFileSize = 1024 * 1024 - // checkFile tries to open and process a single file located on sourcePath in // the specified fsys. The path is skipped if it's a directory. func checkFile( @@ -48,20 +44,12 @@ func checkFile( var fi fs.FileInfo if fi, err = f.Stat(); err != nil { return nil, true, err - } - if fi.IsDir() { + } else if fi.IsDir() { // Skip the directories. return nil, true, nil } - var r io.Reader - // Ignore the error since LimitReader function returns error only if passed - // limit value is less than zero, but the constant used. - // - // TODO(e.burkov): Make variable. - r, _ = aghio.LimitReader(f, MaxWalkedFileSize) - - return c(r) + return c(f) } // handlePatterns parses the patterns in fsys and ignores duplicates using From 0122710750ae3c8c5039886cd27ec14c9579c85b Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Fri, 3 Dec 2021 16:20:10 +0300 Subject: [PATCH 033/135] Pull request: scripts: imp i18n upload script Merge in DNS/adguard-home from imp-i18n-script to master Squashed commit of the following: commit 2ea88dcfaf24722f2b7568802a54cbe4f8ebc084 Author: Ainar Garipov Date: Fri Dec 3 16:05:00 2021 +0300 scripts: imp i18n upload script --- scripts/README.md | 32 ++++++++++++++++++++++++++++++++ scripts/translations/upload.js | 9 ++++++--- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/scripts/README.md b/scripts/README.md index ac99892f..19cdd496 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -6,6 +6,8 @@ Run `make init` from the project root. + + ## `querylog/`: Query Log Helpers ### Usage @@ -14,12 +16,16 @@ Run `make init` from the project root. * `npm run anonymize `: read the query log from the `` and write anonymized version to ``. + + ## `make/`: Makefile Scripts The release channels are: `development` (the default), `edge`, `beta`, and `release`. If verbosity levels aren't documented here, there are only two: `0`, don't print anything, and `1`, be verbose. + + ### `build-docker.sh`: Build A Multi-Architecture Docker Image Required environment: @@ -38,6 +44,8 @@ Optional environment: * `SUDO`: allow users to use `sudo` or `doas` with `docker`. By default none is used. + + ### `build-release.sh`: Build A Release For All Platforms Required environment: @@ -67,6 +75,8 @@ Optional environment: * `VERSION`: release version. Will be set by `version.sh` if it is unset or if it has the default `Makefile` value of `v0.0.0`. + + ### `clean.sh`: Cleanup Optional environment: @@ -75,6 +85,8 @@ Optional environment: Required environment: * `DIST_DIR`: the directory where a release has previously been built. + + ### `go-build.sh`: Build The Backend Optional environment: @@ -95,6 +107,8 @@ Optional environment: Required environment: * `CHANNEL`: release channel, see above. + + ### `go-deps.sh`: Install Backend Dependencies Optional environment: @@ -103,6 +117,8 @@ Optional environment: Go package that is processed. `2` also shows subcommands and environment. The default value is `0`, don't be verbose. + + ### `go-lint.sh`: Run Backend Static Analyzers Don't forget to run `make go-tools` once first! @@ -114,6 +130,8 @@ Optional environment: * `VERBOSE`: verbosity level. `1` shows every command that is run. `2` also shows subcommands. The default value is `0`, don't be verbose. + + ### `go-test.sh`: Run Backend Tests Optional environment: @@ -126,6 +144,8 @@ Optional environment: Go package that is processed. `2` also shows subcommands. The default value is `0`, don't be verbose. + + ### `go-tools.sh`: Install Backend Tooling Installs the Go static analysis and other tools into `${PWD}/bin`. Either add @@ -135,16 +155,22 @@ directly, or use the commands through `make` (for example, `make go-lint`). Optional environment: * `GO`: set an alternative name for the Go compiler. + + ### `version.sh`: Generate And Print The Current Version Required environment: * `CHANNEL`: release channel, see above. + + ## `snap/`: Snap GUI Files App icons (see https://github.com/AdguardTeam/AdGuardHome/pull/1836), Snap manifest file templates, and helper scripts. + + ## `translations/`: Twosky Integration Script ### Usage @@ -158,6 +184,12 @@ manifest file templates, and helper scripts. After the download you'll find the output locales in the `client/src/__locales/` directory. +Optional environment: + * `UPLOAD_LANGUAGE`: set an alternative language for `locales:upload` to + upload. + + + ## `whotracksme/`: Whotracks.me Database Converter A simple script that converts the Ghostery/Cliqz trackers database to a json format. diff --git a/scripts/translations/upload.js b/scripts/translations/upload.js index 38d23794..702b251b 100644 --- a/scripts/translations/upload.js +++ b/scripts/translations/upload.js @@ -3,7 +3,7 @@ const fs = require('fs'); const request = require('request-promise'); const twoskyConfig = require('../../.twosky.json')[0]; -const { project_id: TWOSKY_PROJECT_ID, base_locale: LANGUAGE } = twoskyConfig; +const { project_id: TWOSKY_PROJECT_ID, base_locale: DEFAULT_LANGUAGE } = twoskyConfig; const LOCALES_DIR = '../../client/src/__locales'; const BASE_FILE = 'en.json'; const TWOSKY_URI = process.env.TWOSKY_URI; @@ -12,14 +12,17 @@ const TWOSKY_URI = process.env.TWOSKY_URI; * Prepare post params */ const getRequestData = (url, projectId) => { + const language = process.env.UPLOAD_LANGUAGE || DEFAULT_LANGUAGE; const formData = { format: 'json', - language: LANGUAGE, + language: language, filename: BASE_FILE, project: projectId, - file: fs.createReadStream(path.resolve(LOCALES_DIR, `${LANGUAGE}.json`)), + file: fs.createReadStream(path.resolve(LOCALES_DIR, `${language}.json`)), }; + console.log(`uploading ${language}`); + return { url: `${url}/upload`, formData From 90e65b662c495755be7bb8b338340ebcc9b5500e Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Fri, 3 Dec 2021 17:56:07 +0300 Subject: [PATCH 034/135] Pull request: 3914 fix lack of client name Merge in DNS/adguard-home from 3914-fix-client-name to master Closes #3914. Squashed commit of the following: commit 6bd06d277ec5e64fc548245eee75edd8da67fa2c Author: Eugene Burkov Date: Fri Dec 3 17:13:15 2021 +0300 dnsforward: fix lack of client name --- internal/dnsforward/clientid.go | 17 ----------------- internal/dnsforward/dns.go | 14 ++++++++++++-- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/internal/dnsforward/clientid.go b/internal/dnsforward/clientid.go index 3e92e8de..1580e416 100644 --- a/internal/dnsforward/clientid.go +++ b/internal/dnsforward/clientid.go @@ -2,7 +2,6 @@ package dnsforward import ( "crypto/tls" - "encoding/binary" "fmt" "path" "strings" @@ -172,19 +171,3 @@ func (s *Server) clientIDFromDNSContext(pctx *proxy.DNSContext) (clientID string return clientID, nil } - -// processClientID puts the clientID into the DNS context, if there is one. -func (s *Server) processClientID(dctx *dnsContext) (rc resultCode) { - pctx := dctx.proxyCtx - - var key [8]byte - binary.BigEndian.PutUint64(key[:], pctx.RequestID) - clientIDData := s.clientIDCache.Get(key[:]) - if clientIDData == nil { - return resultCodeSuccess - } - - dctx.clientID = string(clientIDData) - - return resultCodeSuccess -} diff --git a/internal/dnsforward/dns.go b/internal/dnsforward/dns.go index ec27dfd0..d498fcf8 100644 --- a/internal/dnsforward/dns.go +++ b/internal/dnsforward/dns.go @@ -1,6 +1,7 @@ package dnsforward import ( + "encoding/binary" "net" "strings" "time" @@ -86,7 +87,6 @@ func (s *Server) handleDNSRequest(_ *proxy.Proxy, d *proxy.DNSContext) error { s.processInternalHosts, s.processRestrictLocal, s.processInternalIPAddrs, - s.processClientID, s.processFilteringBeforeRequest, s.processLocalPTR, s.processUpstream, @@ -131,7 +131,10 @@ func (s *Server) processRecursion(dctx *dnsContext) (rc resultCode) { return resultCodeSuccess } -// Perform initial checks; process WHOIS & rDNS +// processInitial terminates the following processing for some requests if +// needed and enriches the ctx with some client-specific information. +// +// TODO(e.burkov): Decompose into less general processors. func (s *Server) processInitial(ctx *dnsContext) (rc resultCode) { d := ctx.proxyCtx if s.conf.AAAADisabled && d.Req.Question[0].Qtype == dns.TypeAAAA { @@ -151,6 +154,13 @@ func (s *Server) processInitial(ctx *dnsContext) (rc resultCode) { return resultCodeFinish } + // Get the client's ID if any. It should be performed before getting + // client-specific filtering settings. + var key [8]byte + binary.BigEndian.PutUint64(key[:], d.RequestID) + ctx.clientID = string(s.clientIDCache.Get(key[:])) + + // Get the client-specific filtering settings. ctx.protectionEnabled = s.conf.ProtectionEnabled ctx.setts = s.getClientRequestFilteringSettings(ctx) From d2cf3233b8fc65538bdc052d600f224a7126f2e0 Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Mon, 6 Dec 2021 17:26:43 +0300 Subject: [PATCH 035/135] Pull request: 3890 fix anonymization Merge in DNS/adguard-home from 3890-fix-stats to master Updates #3890. Squashed commit of the following: commit a77a6204bc8a58f62a4fac70efdcae4267a64810 Merge: 834493a2 90e65b66 Author: Eugene Burkov Date: Mon Dec 6 17:22:16 2021 +0300 Merge branch 'master' into 3890-fix-stats commit 834493a22ae79199efcc44e0715e2ac6f6272963 Author: Eugene Burkov Date: Mon Dec 6 17:09:30 2021 +0300 querylog: load once commit b8000e7ba7a998fcd4553230ec5e5f9c90106e31 Author: Eugene Burkov Date: Mon Dec 6 16:54:41 2021 +0300 querylog: fix docs commit 7db99ccfa19b58100950c11d67b23bca7af3e5cb Author: Eugene Burkov Date: Mon Dec 6 16:51:31 2021 +0300 querylog: imp docs commit 2a84650bd7ac5195730a7ab47b9562a83f721499 Author: Eugene Burkov Date: Mon Dec 6 15:48:09 2021 +0300 querylog: imp anonyization commit 0f63feb1ff5f006fc528c3b681ef3b9d2199581e Author: Eugene Burkov Date: Mon Dec 6 14:44:37 2021 +0300 all: imp code & docs commit c4ccdcbb7248897edd178fd5cb77127e39ada73d Author: Eugene Burkov Date: Mon Dec 6 14:24:30 2021 +0300 all: log changes commit 60bb777a5aff36bba129a078fa11ae566298178a Author: Eugene Burkov Date: Mon Dec 6 14:08:41 2021 +0300 all: use atomic value commit c45886bd20eee2212b42686ff369830d8c08fe36 Author: Eugene Burkov Date: Tue Nov 30 18:50:02 2021 +0300 all: anonymize separately --- CHANGELOG.md | 3 ++ internal/aghnet/ipmut.go | 43 +++++++++++++++++++ internal/dnsforward/dns.go | 4 +- internal/dnsforward/dnsforward.go | 8 ++++ internal/dnsforward/stats.go | 27 ++++++++---- internal/dnsforward/stats_test.go | 6 ++- internal/home/controlinstall.go | 26 +++++++----- internal/home/dns.go | 25 +++++++---- internal/home/web.go | 10 +++-- internal/querylog/decode_test.go | 56 +++++++++++++++++++++++++ internal/querylog/http.go | 55 ++++++++++++++++++++---- internal/querylog/json.go | 39 +++++++---------- internal/querylog/qlog.go | 5 ++- internal/querylog/querylog.go | 7 +++- internal/stats/stats.go | 7 ++-- internal/stats/unit.go | 69 ++++++++++++++----------------- 16 files changed, 279 insertions(+), 111 deletions(-) create mode 100644 internal/aghnet/ipmut.go diff --git a/CHANGELOG.md b/CHANGELOG.md index efb91061..6fb63881 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -122,6 +122,8 @@ In this release, the schema version has changed from 10 to 12. ### Fixed +- 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]). - Matching against rules with `|` at the end of the domain name ([#3371]). @@ -222,6 +224,7 @@ In this release, the schema version has changed from 10 to 12. [#3707]: https://github.com/AdguardTeam/AdGuardHome/issues/3707 [#3744]: https://github.com/AdguardTeam/AdGuardHome/issues/3744 [#3815]: https://github.com/AdguardTeam/AdGuardHome/issues/3815 +[#3890]: https://github.com/AdguardTeam/AdGuardHome/issues/3890 diff --git a/internal/aghnet/ipmut.go b/internal/aghnet/ipmut.go new file mode 100644 index 00000000..f227fc9a --- /dev/null +++ b/internal/aghnet/ipmut.go @@ -0,0 +1,43 @@ +package aghnet + +import ( + "net" + "sync/atomic" +) + +// IPMutFunc is the signature of a function which modifies the IP address +// instance. It should be safe for concurrent use. +type IPMutFunc func(ip net.IP) + +// nopIPMutFunc is the IPMutFunc that does nothing. +func nopIPMutFunc(net.IP) {} + +// IPMut is a type-safe wrapper of atomic.Value to store the IPMutFunc. +type IPMut struct { + f atomic.Value +} + +// NewIPMut returns the new properly initialized *IPMut. The m is guaranteed to +// always store non-nil IPMutFunc which is safe to call. +func NewIPMut(f IPMutFunc) (m *IPMut) { + m = &IPMut{ + f: atomic.Value{}, + } + m.Store(f) + + return m +} + +// Store sets the IPMutFunc to return from Func. It's safe for concurrent use. +// If f is nil, the stored function is the no-op one. +func (m *IPMut) Store(f IPMutFunc) { + if f == nil { + f = nopIPMutFunc + } + m.f.Store(f) +} + +// Load returns the previously stored IPMutFunc. +func (m *IPMut) Load() (f IPMutFunc) { + return m.f.Load().(IPMutFunc) +} diff --git a/internal/dnsforward/dns.go b/internal/dnsforward/dns.go index d498fcf8..b6bafa97 100644 --- a/internal/dnsforward/dns.go +++ b/internal/dnsforward/dns.go @@ -307,8 +307,8 @@ func (s *Server) processInternalHosts(dctx *dnsContext) (rc resultCode) { ip, ok := s.hostToIP(host) if !ok { - // TODO(e.burkov): Inspect special cases when user want to apply - // some rules handled by other processors to the hosts with TLD. + // TODO(e.burkov): Inspect special cases when user want to apply some + // rules handled by other processors to the hosts with TLD. d.Res = s.genNXDomain(req) return resultCodeFinish diff --git a/internal/dnsforward/dnsforward.go b/internal/dnsforward/dnsforward.go index a62a6614..e4547307 100644 --- a/internal/dnsforward/dnsforward.go +++ b/internal/dnsforward/dnsforward.go @@ -79,6 +79,9 @@ type Server struct { sysResolvers aghnet.SystemResolvers recDetector *recursionDetector + // anonymizer masks the client's IP addresses if needed. + anonymizer *aghnet.IPMut + tableHostToIP hostToIPTable tableHostToIPLock sync.Mutex @@ -113,6 +116,7 @@ type DNSCreateParams struct { QueryLog querylog.QueryLog DHCPServer dhcpd.ServerInterface SubnetDetector *aghnet.SubnetDetector + Anonymizer *aghnet.IPMut LocalDomain string } @@ -150,6 +154,9 @@ func NewServer(p DNSCreateParams) (s *Server, err error) { localDomainSuffix = domainNameToSuffix(p.LocalDomain) } + if p.Anonymizer == nil { + p.Anonymizer = aghnet.NewIPMut(nil) + } s = &Server{ dnsFilter: p.DNSFilter, stats: p.Stats, @@ -161,6 +168,7 @@ func NewServer(p DNSCreateParams) (s *Server, err error) { EnableLRU: true, MaxCount: defaultClientIDCacheCount, }), + anonymizer: p.Anonymizer, } // TODO(e.burkov): Enable the refresher after the actual implementation diff --git a/internal/dnsforward/stats.go b/internal/dnsforward/stats.go index b7760c68..abdb519e 100644 --- a/internal/dnsforward/stats.go +++ b/internal/dnsforward/stats.go @@ -1,6 +1,7 @@ package dnsforward import ( + "net" "strings" "time" @@ -8,6 +9,7 @@ import ( "github.com/AdguardTeam/AdGuardHome/internal/querylog" "github.com/AdguardTeam/AdGuardHome/internal/stats" "github.com/AdguardTeam/dnsproxy/proxy" + "github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/netutil" "github.com/miekg/dns" ) @@ -28,10 +30,16 @@ func (s *Server) processQueryLogsAndStats(ctx *dnsContext) (rc resultCode) { s.serverLock.RLock() defer s.serverLock.RUnlock() - // Synchronize access to s.queryLog and s.stats so they won't be suddenly uninitialized while in use. - // This can happen after proxy server has been stopped, but its workers haven't yet exited. + ip, _ := netutil.IPAndPortFromAddr(pctx.Addr) + ip = netutil.CloneIP(ip) + s.anonymizer.Load()(ip) + + log.Debug("client ip: %s", ip) + + // Synchronize access to s.queryLog and s.stats so they won't be suddenly + // uninitialized while in use. This can happen after proxy server has been + // stopped, but its workers haven't yet exited. if shouldLog && s.queryLog != nil { - ip, _ := netutil.IPAndPortFromAddr(pctx.Addr) p := querylog.AddParams{ Question: msg, Answer: pctx.Res, @@ -63,12 +71,17 @@ func (s *Server) processQueryLogsAndStats(ctx *dnsContext) (rc resultCode) { s.queryLog.Add(p) } - s.updateStats(ctx, elapsed, *ctx.result) + s.updateStats(ctx, elapsed, *ctx.result, ip) return resultCodeSuccess } -func (s *Server) updateStats(ctx *dnsContext, elapsed time.Duration, res filtering.Result) { +func (s *Server) updateStats( + ctx *dnsContext, + elapsed time.Duration, + res filtering.Result, + clientIP net.IP, +) { if s.stats == nil { return } @@ -80,8 +93,8 @@ func (s *Server) updateStats(ctx *dnsContext, elapsed time.Duration, res filteri if clientID := ctx.clientID; clientID != "" { e.Client = clientID - } else if ip, _ := netutil.IPAndPortFromAddr(pctx.Addr); ip != nil { - e.Client = ip.String() + } else if clientIP != nil { + e.Client = clientIP.String() } e.Time = uint32(elapsed / 1000) diff --git a/internal/dnsforward/stats_test.go b/internal/dnsforward/stats_test.go index 22780ef2..aa98a387 100644 --- a/internal/dnsforward/stats_test.go +++ b/internal/dnsforward/stats_test.go @@ -5,6 +5,7 @@ import ( "testing" "time" + "github.com/AdguardTeam/AdGuardHome/internal/aghnet" "github.com/AdguardTeam/AdGuardHome/internal/filtering" "github.com/AdguardTeam/AdGuardHome/internal/querylog" "github.com/AdguardTeam/AdGuardHome/internal/stats" @@ -163,8 +164,9 @@ func TestProcessQueryLogsAndStats(t *testing.T) { ql := &testQueryLog{} st := &testStats{} srv := &Server{ - queryLog: ql, - stats: st, + queryLog: ql, + stats: st, + anonymizer: aghnet.NewIPMut(nil), } t.Run(tc.name, func(t *testing.T) { req := &dns.Msg{ diff --git a/internal/home/controlinstall.go b/internal/home/controlinstall.go index ff532ff6..84996017 100644 --- a/internal/home/controlinstall.go +++ b/internal/home/controlinstall.go @@ -270,15 +270,13 @@ func copyInstallSettings(dst, src *configuration) { // shutdownTimeout is the timeout for shutting HTTP server down operation. const shutdownTimeout = 5 * time.Second -func shutdownSrv(ctx context.Context, cancel context.CancelFunc, srv *http.Server) { +func shutdownSrv(ctx context.Context, srv *http.Server) { defer log.OnPanic("") if srv == nil { return } - defer cancel() - err := srv.Shutdown(ctx) if err != nil { log.Error("error while shutting down http server %q: %s", srv.Addr, err) @@ -354,14 +352,22 @@ func (web *Web) handleInstallConfigure(w http.ResponseWriter, r *http.Request) { f.Flush() } - // Method http.(*Server).Shutdown needs to be called in a separate - // goroutine and with its own context, because it waits until all - // requests are handled and will be blocked by it's own caller. - if restartHTTP { - ctx, cancel := context.WithTimeout(context.Background(), shutdownTimeout) - go shutdownSrv(ctx, cancel, web.httpServer) - go shutdownSrv(ctx, cancel, web.httpServerBeta) + if !restartHTTP { + return } + + // Method http.(*Server).Shutdown needs to be called in a separate goroutine + // and with its own context, because it waits until all requests are handled + // and will be blocked by it's own caller. + go func(timeout time.Duration) { + defer log.OnPanic("web") + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + shutdownSrv(ctx, web.httpServer) + shutdownSrv(ctx, web.httpServerBeta) + }(shutdownTimeout) } // decodeApplyConfigReq decodes the configuration, validates some parameters, diff --git a/internal/home/dns.go b/internal/home/dns.go index 4b120581..dfd133eb 100644 --- a/internal/home/dns.go +++ b/internal/home/dns.go @@ -7,6 +7,7 @@ import ( "os" "path/filepath" + "github.com/AdguardTeam/AdGuardHome/internal/aghnet" "github.com/AdguardTeam/AdGuardHome/internal/dnsforward" "github.com/AdguardTeam/AdGuardHome/internal/filtering" "github.com/AdguardTeam/AdGuardHome/internal/querylog" @@ -36,16 +37,20 @@ func onConfigModified() { // initDNSServer creates an instance of the dnsforward.Server // Please note that we must do it even if we don't start it // so that we had access to the query log and the stats -func initDNSServer() error { - var err error +func initDNSServer() (err error) { baseDir := Context.getDataDir() + var anonFunc aghnet.IPMutFunc + if config.DNS.AnonymizeClientIP { + anonFunc = querylog.AnonymizeIP + } + anonymizer := aghnet.NewIPMut(anonFunc) + statsConf := stats.Config{ - Filename: filepath.Join(baseDir, "stats.db"), - LimitDays: config.DNS.StatsInterval, - AnonymizeClientIP: config.DNS.AnonymizeClientIP, - ConfigModified: onConfigModified, - HTTPRegister: httpRegister, + Filename: filepath.Join(baseDir, "stats.db"), + LimitDays: config.DNS.StatsInterval, + ConfigModified: onConfigModified, + HTTPRegister: httpRegister, } Context.stats, err = stats.New(statsConf) if err != nil { @@ -62,6 +67,7 @@ func initDNSServer() error { Enabled: config.DNS.QueryLogEnabled, FileEnabled: config.DNS.QueryLogFileEnabled, AnonymizeClientIP: config.DNS.AnonymizeClientIP, + Anonymizer: anonymizer, } Context.queryLog = querylog.New(conf) @@ -76,6 +82,7 @@ func initDNSServer() error { Stats: Context.stats, QueryLog: Context.queryLog, SubnetDetector: Context.subnetDetector, + Anonymizer: anonymizer, LocalDomain: config.DNS.LocalDomainName, } if Context.dhcpServer != nil { @@ -90,7 +97,8 @@ func initDNSServer() error { } Context.clients.dnsServer = Context.dnsServer - dnsConfig, err := generateServerConfig() + var dnsConfig dnsforward.ServerConfig + dnsConfig, err = generateServerConfig() if err != nil { closeDNSServer() @@ -100,6 +108,7 @@ func initDNSServer() error { err = Context.dnsServer.Prepare(&dnsConfig) if err != nil { closeDNSServer() + return fmt.Errorf("dnsServer.Prepare: %w", err) } diff --git a/internal/home/web.go b/internal/home/web.go index 9be037cc..23e629b9 100644 --- a/internal/home/web.go +++ b/internal/home/web.go @@ -151,7 +151,8 @@ func (web *Web) TLSConfigChanged(ctx context.Context, tlsConf tlsConfigSettings) if web.httpsServer.server != nil { var cancel context.CancelFunc ctx, cancel = context.WithTimeout(ctx, shutdownTimeout) - shutdownSrv(ctx, cancel, web.httpsServer.server) + shutdownSrv(ctx, web.httpsServer.server) + cancel() } web.httpsServer.enabled = enabled @@ -222,10 +223,11 @@ func (web *Web) Close(ctx context.Context) { var cancel context.CancelFunc ctx, cancel = context.WithTimeout(ctx, shutdownTimeout) + defer cancel() - shutdownSrv(ctx, cancel, web.httpsServer.server) - shutdownSrv(ctx, cancel, web.httpServer) - shutdownSrv(ctx, cancel, web.httpServerBeta) + shutdownSrv(ctx, web.httpsServer.server) + shutdownSrv(ctx, web.httpServer) + shutdownSrv(ctx, web.httpServerBeta) log.Info("stopped http server") } diff --git a/internal/querylog/decode_test.go b/internal/querylog/decode_test.go index 245681dd..0a1b41fe 100644 --- a/internal/querylog/decode_test.go +++ b/internal/querylog/decode_test.go @@ -244,3 +244,59 @@ func TestDecodeLogEntry_backwardCompatability(t *testing.T) { }) } } + +func BenchmarkAnonymizeIP(b *testing.B) { + benchCases := []struct { + name string + ip net.IP + want net.IP + }{{ + name: "v4", + ip: net.IP{1, 2, 3, 4}, + want: net.IP{1, 2, 0, 0}, + }, { + name: "v4_mapped", + ip: net.IP{1, 2, 3, 4}.To16(), + want: net.IP{1, 2, 0, 0}.To16(), + }, { + name: "v6", + ip: net.IP{ + 0xa, 0xb, 0x0, 0x0, + 0x0, 0xb, 0xa, 0x9, + 0x8, 0x7, 0x6, 0x5, + 0x4, 0x3, 0x2, 0x1, + }, + want: net.IP{ + 0xa, 0xb, 0x0, 0x0, + 0x0, 0xb, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + }, + }, { + name: "invalid", + ip: net.IP{1, 2, 3}, + want: net.IP{1, 2, 3}, + }} + + for _, bc := range benchCases { + b.Run(bc.name, func(b *testing.B) { + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + AnonymizeIP(bc.ip) + } + + assert.Equal(b, bc.want, bc.ip) + }) + + b.Run(bc.name+"_slow", func(b *testing.B) { + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + anonymizeIPSlow(bc.ip) + } + + assert.Equal(b, bc.want, bc.ip) + }) + } +} diff --git a/internal/querylog/http.go b/internal/querylog/http.go index 7d7c0493..73bdbe56 100644 --- a/internal/querylog/http.go +++ b/internal/querylog/http.go @@ -3,6 +3,7 @@ package querylog import ( "encoding/json" "fmt" + "net" "net/http" "net/url" "strconv" @@ -12,6 +13,7 @@ import ( "github.com/AdguardTeam/golibs/jsonutil" "github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/stringutil" + "github.com/AdguardTeam/golibs/timeutil" "golang.org/x/net/idna" ) @@ -88,23 +90,59 @@ func (l *queryLog) handleQueryLogInfo(w http.ResponseWriter, r *http.Request) { } } +// anonymizeIPSlow masks ip to anonymize the client if the ip is a valid one. +// It only exists in purposes of benchmark demonstration. +func anonymizeIPSlow(ip net.IP) { + if ip4 := ip.To4(); ip4 != nil { + copy(ip4[net.IPv4len-2:], []byte{0, 0}) + } else if len(ip) == net.IPv6len { + copy(ip[net.IPv6len-10:], []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) + } +} + +// AnonymizeIP masks ip to anonymize the client if the ip is a valid one. +func AnonymizeIP(ip net.IP) { + // We use an assignment operator here since it compiles into more efficient + // code than copy(). See BenchmarkAnonymizeIP. + if ip4 := ip.To4(); ip4 != nil { + ip4[net.IPv4len-2], ip4[net.IPv4len-1] = 0, 0 + } else if len(ip) == net.IPv6len { + ip[net.IPv6len-10], + ip[net.IPv6len-9], + ip[net.IPv6len-8], + ip[net.IPv6len-7], + ip[net.IPv6len-6], + ip[net.IPv6len-5], + ip[net.IPv6len-4], + ip[net.IPv6len-3], + ip[net.IPv6len-2], + ip[net.IPv6len-1] = + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + } +} + // Set configuration func (l *queryLog) handleQueryLogConfig(w http.ResponseWriter, r *http.Request) { - d := qlogConfig{} - req, err := jsonutil.DecodeObject(&d, r.Body) + d := &qlogConfig{} + req, err := jsonutil.DecodeObject(d, r.Body) if err != nil { httpError(r, w, http.StatusBadRequest, "%s", err) return } - ivl := time.Duration(24*d.Interval) * time.Hour + ivl := time.Duration(float64(timeutil.Day) * d.Interval) if req.Exists("interval") && !checkInterval(ivl) { httpError(r, w, http.StatusBadRequest, "Unsupported interval") return } + defer l.conf.ConfigModified() + l.lock.Lock() - // copy data, modify it, then activate. Other threads (readers) don't need to use this lock. + defer l.lock.Unlock() + + // Copy data, modify it, then activate. Other threads (readers) don't need + // to use this lock. conf := *l.conf if req.Exists("enabled") { conf.Enabled = d.Enabled @@ -113,12 +151,13 @@ func (l *queryLog) handleQueryLogConfig(w http.ResponseWriter, r *http.Request) conf.RotationIvl = ivl } if req.Exists("anonymize_client_ip") { - conf.AnonymizeClientIP = d.AnonymizeClientIP + if conf.AnonymizeClientIP = d.AnonymizeClientIP; conf.AnonymizeClientIP { + l.anonymizer.Store(AnonymizeIP) + } else { + l.anonymizer.Store(nil) + } } l.conf = &conf - l.lock.Unlock() - - l.conf.ConfigModified() } // "value" -> value, return TRUE diff --git a/internal/querylog/json.go b/internal/querylog/json.go index 2dfaf68b..23953f80 100644 --- a/internal/querylog/json.go +++ b/internal/querylog/json.go @@ -2,46 +2,30 @@ package querylog import ( "fmt" - "net" "strconv" "strings" "time" + "github.com/AdguardTeam/AdGuardHome/internal/aghnet" "github.com/AdguardTeam/AdGuardHome/internal/filtering" "github.com/AdguardTeam/golibs/log" + "github.com/AdguardTeam/golibs/netutil" "github.com/miekg/dns" "golang.org/x/net/idna" ) // TODO(a.garipov): Use a proper structured approach here. -// Get Client IP address -func (l *queryLog) getClientIP(ip net.IP) (clientIP net.IP) { - if l.conf.AnonymizeClientIP && ip != nil { - const AnonymizeClientIPv4Mask = 16 - const AnonymizeClientIPv6Mask = 112 - - if ip.To4() != nil { - return ip.Mask(net.CIDRMask(AnonymizeClientIPv4Mask, 32)) - } - - return ip.Mask(net.CIDRMask(AnonymizeClientIPv6Mask, 128)) - } - - return ip -} - // jobject is a JSON object alias. type jobject = map[string]interface{} // entriesToJSON converts query log entries to JSON. func (l *queryLog) entriesToJSON(entries []*logEntry, oldest time.Time) (res jobject) { - data := []jobject{} + data := make([]jobject, 0, len(entries)) - // the elements order is already reversed (from newer to older) - for i := 0; i < len(entries); i++ { - entry := entries[i] - jsonEntry := l.logEntryToJSONEntry(entry) + // The elements order is already reversed to be from newer to older. + for _, entry := range entries { + jsonEntry := l.entryToJSON(entry, l.anonymizer.Load()) data = append(data, jsonEntry) } @@ -56,7 +40,7 @@ func (l *queryLog) entriesToJSON(entries []*logEntry, oldest time.Time) (res job return res } -func (l *queryLog) logEntryToJSONEntry(entry *logEntry) (jsonEntry jobject) { +func (l *queryLog) entryToJSON(entry *logEntry, anonFunc aghnet.IPMutFunc) (jsonEntry jobject) { var msg *dns.Msg if len(entry.Answer) > 0 { @@ -81,16 +65,21 @@ func (l *queryLog) logEntryToJSONEntry(entry *logEntry) (jsonEntry jobject) { log.Debug("translating %q into unicode: %s", hostname, err) } + eip := netutil.CloneIP(entry.IP) + anonFunc(eip) + jsonEntry = jobject{ "reason": entry.Result.Reason.String(), "elapsedMs": strconv.FormatFloat(entry.Elapsed.Seconds()*1000, 'f', -1, 64), "time": entry.Time.Format(time.RFC3339Nano), - "client": l.getClientIP(entry.IP), - "client_info": entry.client, + "client": eip, "client_proto": entry.ClientProto, "upstream": entry.Upstream, "question": question, } + if eip.Equal(entry.IP) { + jsonEntry["client_info"] = entry.client + } if entry.ClientID != "" { jsonEntry["client_id"] = entry.ClientID diff --git a/internal/querylog/qlog.go b/internal/querylog/qlog.go index c3cdedfa..48f0d351 100644 --- a/internal/querylog/qlog.go +++ b/internal/querylog/qlog.go @@ -9,6 +9,7 @@ import ( "sync" "time" + "github.com/AdguardTeam/AdGuardHome/internal/aghnet" "github.com/AdguardTeam/AdGuardHome/internal/filtering" "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/log" @@ -36,6 +37,8 @@ type queryLog struct { fileFlushLock sync.Mutex // synchronize a file-flushing goroutine and main thread flushPending bool // don't start another goroutine while the previous one is still running fileWriteLock sync.Mutex + + anonymizer *aghnet.IPMut } // ClientProto values are names of the client protocols. @@ -162,7 +165,7 @@ func (l *queryLog) Add(params AddParams) { now := time.Now() entry := logEntry{ - IP: l.getClientIP(params.ClientIP), + IP: params.ClientIP, Time: now, Result: *params.Result, diff --git a/internal/querylog/querylog.go b/internal/querylog/querylog.go index 0ab20a27..58b5a8e0 100644 --- a/internal/querylog/querylog.go +++ b/internal/querylog/querylog.go @@ -6,6 +6,7 @@ import ( "path/filepath" "time" + "github.com/AdguardTeam/AdGuardHome/internal/aghnet" "github.com/AdguardTeam/AdGuardHome/internal/filtering" "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/log" @@ -67,6 +68,9 @@ type Config struct { // AnonymizeClientIP tells if the query log should anonymize clients' IP // addresses. AnonymizeClientIP bool + + // Anonymizer proccesses the IP addresses to anonymize those if needed. + Anonymizer *aghnet.IPMut } // AddParams - parameters for Add() @@ -115,7 +119,8 @@ func newQueryLog(conf Config) (l *queryLog) { l = &queryLog{ findClient: findClient, - logFile: filepath.Join(conf.BaseDir, queryLogFileName), + logFile: filepath.Join(conf.BaseDir, queryLogFileName), + anonymizer: conf.Anonymizer, } l.conf = &Config{} diff --git a/internal/stats/stats.go b/internal/stats/stats.go index 7ed1d320..2944a163 100644 --- a/internal/stats/stats.go +++ b/internal/stats/stats.go @@ -16,10 +16,9 @@ type DiskConfig struct { // Config - module configuration type Config struct { - Filename string // database file name - LimitDays uint32 // time limit (in days) - UnitID unitIDCallback // user function to get the current unit ID. If nil, the current time hour is used. - AnonymizeClientIP bool // anonymize clients' IP addresses + Filename string // database file name + LimitDays uint32 // time limit (in days) + UnitID unitIDCallback // user function to get the current unit ID. If nil, the current time hour is used. // Called when the configuration is changed by HTTP request ConfigModified func() diff --git a/internal/stats/unit.go b/internal/stats/unit.go index 71752137..43119907 100644 --- a/internal/stats/unit.go +++ b/internal/stats/unit.go @@ -26,11 +26,13 @@ const ( // statsCtx - global context type statsCtx struct { + // mu protects unit. + mu *sync.Mutex + // current is the actual statistics collection result. + current *unit + db *bolt.DB conf *Config - - unit *unit // the current unit - unitLock sync.Mutex // protect 'unit' } // data for 1 time unit @@ -66,7 +68,9 @@ type unitDB struct { } func createObject(conf Config) (s *statsCtx, err error) { - s = &statsCtx{} + s = &statsCtx{ + mu: &sync.Mutex{}, + } if !checkInterval(conf.LimitDays) { conf.LimitDays = 1 } @@ -112,7 +116,7 @@ func createObject(conf Config) (s *statsCtx, err error) { if udb != nil { deserialize(&u, udb) } - s.unit = &u + s.current = &u log.Debug("stats: initialized") @@ -178,11 +182,13 @@ func (s *statsCtx) dbOpen() bool { // Atomically swap the currently active unit with a new value // Return old value -func (s *statsCtx) swapUnit(new *unit) *unit { - s.unitLock.Lock() - u := s.unit - s.unit = new - s.unitLock.Unlock() +func (s *statsCtx) swapUnit(new *unit) (u *unit) { + s.mu.Lock() + defer s.mu.Unlock() + + u = s.current + s.current = new + return u } @@ -250,6 +256,13 @@ func unitNameToID(name []byte) (id uint32, ok bool) { return uint32(binary.BigEndian.Uint64(name)), true } +func (s *statsCtx) ongoing() (u *unit) { + s.mu.Lock() + defer s.mu.Unlock() + + return s.current +} + // Flush the current unit to DB and delete an old unit when a new hour is started // If a unit must be flushed: // . lock DB @@ -260,10 +273,7 @@ func unitNameToID(name []byte) (id uint32, ok bool) { // . unlock DB func (s *statsCtx) periodicFlush() { for { - s.unitLock.Lock() - ptr := s.unit - s.unitLock.Unlock() - + ptr := s.ongoing() if ptr == nil { break } @@ -491,22 +501,6 @@ func (s *statsCtx) clear() { log.Debug("stats: cleared") } -// Get Client IP address -func (s *statsCtx) getClientIP(ip net.IP) (clientIP net.IP) { - if s.conf.AnonymizeClientIP && ip != nil { - const AnonymizeClientIP4Mask = 16 - const AnonymizeClientIP6Mask = 112 - - if ip.To4() != nil { - return ip.Mask(net.CIDRMask(AnonymizeClientIP4Mask, 32)) - } - - return ip.Mask(net.CIDRMask(AnonymizeClientIP6Mask, 128)) - } - - return ip -} - func (s *statsCtx) Update(e Entry) { if s.conf.limit == 0 { return @@ -521,14 +515,13 @@ func (s *statsCtx) Update(e Entry) { clientID := e.Client if ip := net.ParseIP(clientID); ip != nil { - ip = s.getClientIP(ip) clientID = ip.String() } - s.unitLock.Lock() - defer s.unitLock.Unlock() + s.mu.Lock() + defer s.mu.Unlock() - u := s.unit + u := s.current u.nResult[e.Result]++ @@ -549,10 +542,8 @@ func (s *statsCtx) loadUnits(limit uint32) ([]*unitDB, uint32) { return nil, 0 } - s.unitLock.Lock() - curUnit := serialize(s.unit) - curID := s.unit.id - s.unitLock.Unlock() + cur := s.ongoing() + curID := cur.id // Per-hour units. units := []*unitDB{} @@ -568,7 +559,7 @@ func (s *statsCtx) loadUnits(limit uint32) ([]*unitDB, uint32) { _ = tx.Rollback() - units = append(units, curUnit) + units = append(units, serialize(cur)) if len(units) != int(limit) { log.Fatalf("len(units) != limit: %d %d", len(units), limit) From 2d328ea840df18ba1891b36db7592baaab991d71 Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Tue, 7 Dec 2021 14:12:59 +0300 Subject: [PATCH 036/135] Pull request: improve anonymizer performance Merge in DNS/adguard-home from imp-anonymizer to master Squashed commit of the following: commit 340237d747ede620756e8d213c9da825d038d691 Author: Eugene Burkov Date: Tue Dec 7 12:43:27 2021 +0300 querylog: mv slow version commit 96daf498200d0de86f62a3a1c1502f928fba2b0a Author: Eugene Burkov Date: Mon Dec 6 21:21:13 2021 +0300 querylog: imp anonymizer --- internal/querylog/decode_test.go | 10 ++++++++++ internal/querylog/http.go | 31 +++++++------------------------ 2 files changed, 17 insertions(+), 24 deletions(-) diff --git a/internal/querylog/decode_test.go b/internal/querylog/decode_test.go index 0a1b41fe..d57b24f0 100644 --- a/internal/querylog/decode_test.go +++ b/internal/querylog/decode_test.go @@ -245,6 +245,16 @@ func TestDecodeLogEntry_backwardCompatability(t *testing.T) { } } +// anonymizeIPSlow masks ip to anonymize the client if the ip is a valid one. +// It only exists in purposes of benchmark comparison, see BenchmarkAnonymizeIP. +func anonymizeIPSlow(ip net.IP) { + if ip4 := ip.To4(); ip4 != nil { + copy(ip4[net.IPv4len-2:net.IPv4len], []byte{0, 0}) + } else if len(ip) == net.IPv6len { + copy(ip[net.IPv6len-10:net.IPv6len], []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) + } +} + func BenchmarkAnonymizeIP(b *testing.B) { benchCases := []struct { name string diff --git a/internal/querylog/http.go b/internal/querylog/http.go index 73bdbe56..f5ddf7c0 100644 --- a/internal/querylog/http.go +++ b/internal/querylog/http.go @@ -90,34 +90,17 @@ func (l *queryLog) handleQueryLogInfo(w http.ResponseWriter, r *http.Request) { } } -// anonymizeIPSlow masks ip to anonymize the client if the ip is a valid one. -// It only exists in purposes of benchmark demonstration. -func anonymizeIPSlow(ip net.IP) { - if ip4 := ip.To4(); ip4 != nil { - copy(ip4[net.IPv4len-2:], []byte{0, 0}) - } else if len(ip) == net.IPv6len { - copy(ip[net.IPv6len-10:], []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) - } -} - // AnonymizeIP masks ip to anonymize the client if the ip is a valid one. func AnonymizeIP(ip net.IP) { - // We use an assignment operator here since it compiles into more efficient - // code than copy(). See BenchmarkAnonymizeIP. + // zeroes is a slice of zero bytes from which the IP address tail is copied. + // Using constant string as source of copying is more efficient than byte + // slice, see https://github.com/golang/go/issues/49997. + const zeroes = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + if ip4 := ip.To4(); ip4 != nil { - ip4[net.IPv4len-2], ip4[net.IPv4len-1] = 0, 0 + copy(ip4[net.IPv4len-2:net.IPv4len], zeroes) } else if len(ip) == net.IPv6len { - ip[net.IPv6len-10], - ip[net.IPv6len-9], - ip[net.IPv6len-8], - ip[net.IPv6len-7], - ip[net.IPv6len-6], - ip[net.IPv6len-5], - ip[net.IPv6len-4], - ip[net.IPv6len-3], - ip[net.IPv6len-2], - ip[net.IPv6len-1] = - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + copy(ip[net.IPv6len-10:net.IPv6len], zeroes) } } From 434032f8e300d9ed97886596b839458179bc038c Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Tue, 7 Dec 2021 17:43:51 +0300 Subject: [PATCH 037/135] Pull request: 3772 cache upstreams Merge in DNS/adguard-home from 3772-cache-upstreams to master Updates #3772. Squashed commit of the following: commit 809e874fe8847fdbd7f8a7221f18393509f41339 Merge: 5774798c 2d328ea8 Author: Eugene Burkov Date: Tue Dec 7 17:15:59 2021 +0300 Merge branch 'master' into 3772-cache-upstreams commit 5774798ce1897bf292be49410794ce06cd084f93 Author: Ildar Kamalov Date: Tue Dec 7 16:48:38 2021 +0300 client: fix formatting commit 4b4bb668c762c9b4d47cf40a007f34fe47a6e260 Author: Ildar Kamalov Date: Tue Dec 7 16:47:18 2021 +0300 client: remove comment commit a2a9f904a6ab52194bb811a2a83967660a25f2cc Author: Ildar Kamalov Date: Tue Dec 7 16:45:31 2021 +0300 client: handle cached upstream commit a56804c4910da838cb10c8ef0af2a525e9722b1c Author: Eugene Burkov Date: Fri Nov 26 15:33:43 2021 +0300 querylog: rm todo commit 16c0a62ad2dfc7fcb5a6adbc868b296b7840fd27 Author: Eugene Burkov Date: Fri Nov 26 15:31:53 2021 +0300 all: revise log of changes commit 9f4b793205f17b6e85d74e83126093ed09eb24e3 Author: Eugene Burkov Date: Thu Nov 25 17:23:42 2021 +0300 WIP commit 7fbc6d596295570d2c61c3e507160f65c9adccb8 Author: Eugene Burkov Date: Thu Nov 25 17:03:42 2021 +0300 all: imp upstream info in querylog --- CHANGELOG.md | 4 +++ client/src/__locales/en.json | 4 +-- .../src/components/Logs/Cells/ResponseCell.js | 27 ++++++++++++------- client/src/components/Logs/Cells/index.js | 7 ++++- client/src/helpers/helpers.js | 2 ++ client/src/helpers/validators.js | 11 -------- go.mod | 4 +-- go.sum | 9 +++---- internal/dnsforward/stats.go | 11 +++++--- internal/querylog/decode.go | 25 +++++++++++++++++ internal/querylog/decode_test.go | 6 ++++- internal/querylog/json.go | 1 + internal/querylog/qlog.go | 4 ++- internal/querylog/querylog.go | 26 +++++++++++------- openapi/CHANGELOG.md | 5 ++++ openapi/openapi.yaml | 4 +++ 16 files changed, 104 insertions(+), 46 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fb63881..044b9688 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ and this project adheres to ### Added +- Upstream server information for responses from cache ([#3772]). Note that old + log entries concerning cached responses won't include that information. - Finnish and Ukrainian translations. - Setting the timeout for IP address pinging in the "Fastest IP address" mode through the new `fastest_timeout` field in the configuration file ([#1992]). @@ -47,6 +49,7 @@ and this project adheres to ### Changed +- Responses from cache are now labeled ([#3772]). - Better error message for ED25519 private keys, which are not widely supported ([#3737]). - Cache now follows RFC more closely for negative answers ([#3707]). @@ -223,6 +226,7 @@ In this release, the schema version has changed from 10 to 12. [#3655]: https://github.com/AdguardTeam/AdGuardHome/issues/3655 [#3707]: https://github.com/AdguardTeam/AdGuardHome/issues/3707 [#3744]: https://github.com/AdguardTeam/AdGuardHome/issues/3744 +[#3772]: https://github.com/AdguardTeam/AdGuardHome/issues/3772 [#3815]: https://github.com/AdguardTeam/AdGuardHome/issues/3815 [#3890]: https://github.com/AdguardTeam/AdGuardHome/issues/3890 diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index 9caf8845..edf63255 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -47,7 +47,6 @@ "form_error_server_name": "Invalid server name", "form_error_subnet": "Subnet \"{{cidr}}\" does not contain the IP address \"{{ip}}\"", "form_error_positive": "Must be greater than 0", - "form_error_negative": "Must be equal to 0 or greater", "out_of_range_error": "Must be out of range \"{{start}}\"-\"{{end}}\"", "lower_range_start_error": "Must be lower than range start", "greater_range_start_error": "Must be greater than range start", @@ -627,5 +626,6 @@ "experimental": "Experimental", "use_saved_key": "Use the previously saved key", "parental_control": "Parental control", - "safe_browsing": "Safe browsing" + "safe_browsing": "Safe browsing", + "served_from_cache": "{{value}} (served from cache)" } diff --git a/client/src/components/Logs/Cells/ResponseCell.js b/client/src/components/Logs/Cells/ResponseCell.js index 3a3aeb60..772b89e5 100644 --- a/client/src/components/Logs/Cells/ResponseCell.js +++ b/client/src/components/Logs/Cells/ResponseCell.js @@ -21,6 +21,7 @@ const ResponseCell = ({ upstream, rules, service_name, + cached, }) => { const { t } = useTranslation(); const filters = useSelector((state) => state.filtering.filters, shallowEqual); @@ -36,6 +37,9 @@ const ResponseCell = ({ const statusLabel = t(isBlockedByResponse ? 'blocked_by_cname_or_ip' : FILTERED_STATUS_TO_META_MAP[reason]?.LABEL || reason); const boldStatusLabel = {statusLabel}; + const upstreamString = cached + ? t('served_from_cache', { value: upstream, i: }) + : upstream; const renderResponses = (responseArr) => { if (!responseArr || responseArr.length === 0) { @@ -53,7 +57,7 @@ const ResponseCell = ({ const COMMON_CONTENT = { encryption_status: boldStatusLabel, - install_settings_dns: upstream, + install_settings_dns: upstreamString, elapsed: formattedElapsedMs, response_code: status, ...(service_name @@ -90,8 +94,9 @@ const ResponseCell = ({ const detailedInfo = getDetailedInfo(reason); - return
- + -
-
{statusLabel}
- {isDetailed &&
{detailedInfo}
} + /> +
+
{statusLabel}
+ {isDetailed &&
{detailedInfo}
} +
-
; + ); }; ResponseCell.propTypes = { @@ -117,6 +123,7 @@ ResponseCell.propTypes = { response: propTypes.array.isRequired, status: propTypes.string.isRequired, upstream: propTypes.string.isRequired, + cached: propTypes.bool.isRequired, rules: propTypes.arrayOf(propTypes.shape({ text: propTypes.string.isRequired, filter_list_id: propTypes.number.isRequired, diff --git a/client/src/components/Logs/Cells/index.js b/client/src/components/Logs/Cells/index.js index df36f1d2..2287f8d1 100644 --- a/client/src/components/Logs/Cells/index.js +++ b/client/src/components/Logs/Cells/index.js @@ -76,6 +76,7 @@ const Row = memo(({ originalResponse, status, service_name, + cached, } = rowProps; const hasTracker = !!tracker; @@ -116,6 +117,9 @@ const Row = memo(({ const blockingForClientKey = isFiltered ? 'unblock_for_this_client_only' : 'block_for_this_client_only'; const clientNameBlockingFor = getBlockingClientName(clients, client); + const upstreamString = cached + ? t('served_from_cache', { value: upstream, i: }) + : upstream; const onBlockingForClientClick = () => { dispatch(toggleBlockingForClient(buttonType, domain, clientNameBlockingFor)); @@ -175,7 +179,7 @@ const Row = memo(({ className="link--green">{sourceData.name} , response_details: 'title', - install_settings_dns: upstream, + install_settings_dns: upstreamString, elapsed: formattedElapsedMs, ...(rules.length > 0 && { rule_label: getRulesToFilterList(rules, filters, whitelistFilters) } @@ -230,6 +234,7 @@ Row.propTypes = { time: propTypes.string.isRequired, tracker: propTypes.object, upstream: propTypes.string.isRequired, + cached: propTypes.bool.isRequired, type: propTypes.string.isRequired, client_proto: propTypes.string.isRequired, client_id: propTypes.string, diff --git a/client/src/helpers/helpers.js b/client/src/helpers/helpers.js index 4c9803ae..8f4344ee 100644 --- a/client/src/helpers/helpers.js +++ b/client/src/helpers/helpers.js @@ -75,6 +75,7 @@ export const normalizeLogs = (logs) => logs.map((log) => { service_name, original_answer, upstream, + cached, } = log; const { name: domain, unicode_name: unicodeName, type } = question; @@ -116,6 +117,7 @@ export const normalizeLogs = (logs) => logs.map((log) => { answer_dnssec, elapsedMs, upstream, + cached, }; }); diff --git a/client/src/helpers/validators.js b/client/src/helpers/validators.js index 2ac98a6b..2ebf6a30 100644 --- a/client/src/helpers/validators.js +++ b/client/src/helpers/validators.js @@ -230,17 +230,6 @@ export const validateMac = (value) => { return undefined; }; -/** - * @param value {number} - * @returns {boolean|*} - */ -export const validateBiggerOrEqualZeroValue = (value) => { - if (value < 0) { - return 'form_error_negative'; - } - return false; -}; - /** * @param value {number} * @returns {undefined|string} diff --git a/go.mod b/go.mod index 7c032047..9d4593ca 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module github.com/AdguardTeam/AdGuardHome go 1.16 require ( - github.com/AdguardTeam/dnsproxy v0.39.9 - github.com/AdguardTeam/golibs v0.10.2 + github.com/AdguardTeam/dnsproxy v0.39.12 + github.com/AdguardTeam/golibs v0.10.3 github.com/AdguardTeam/urlfilter v0.15.0 github.com/NYTimes/gziphandler v1.1.1 github.com/ameshkov/dnscrypt/v2 v2.2.2 diff --git a/go.sum b/go.sum index 6db8fa82..969ec191 100644 --- a/go.sum +++ b/go.sum @@ -9,13 +9,13 @@ dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= github.com/AdguardTeam/dhcp v0.0.0-20210519141215-51808c73c0bf h1:gc042VRSIRSUzZ+Px6xQCRWNJZTaPkomisDfUZmoFNk= github.com/AdguardTeam/dhcp v0.0.0-20210519141215-51808c73c0bf/go.mod h1:TKl4jN3Voofo4UJIicyNhWGp/nlQqQkFxmwIFTvBkKI= -github.com/AdguardTeam/dnsproxy v0.39.9 h1:lH4lKA7KHKFJZgzlij1YAVX6v7eIQpUFpYh9qV+WfGw= -github.com/AdguardTeam/dnsproxy v0.39.9/go.mod h1:eDpJKAdkHORRwAedjuERv+7SWlcz4cn+5uwrbUAWHRY= +github.com/AdguardTeam/dnsproxy v0.39.12 h1:BxAfdQLGnu0rqhD23K5nNw09sKQeqpT2AkFEE78WOqU= +github.com/AdguardTeam/dnsproxy v0.39.12/go.mod h1:g7zjF1TWpKNeDVh6h3YrjQN8565zsWRd7zo++C/935c= 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.9.2/go.mod h1:fCAMwPBJ8S7YMYbTWvYS+eeTLblP5E04IDtNAo7y7IY= -github.com/AdguardTeam/golibs v0.10.2 h1:TAwnS4Y49sSUa4UX1yz/MWNGbIlXHqafrWr9MxdIh9A= -github.com/AdguardTeam/golibs v0.10.2/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw= +github.com/AdguardTeam/golibs v0.10.3 h1:FBgk17zf35ESVWQKIqEUiqqB2bDaCBC8X5vMU760yB4= +github.com/AdguardTeam/golibs v0.10.3/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw= github.com/AdguardTeam/gomitmproxy v0.2.0/go.mod h1:Qdv0Mktnzer5zpdpi5rAwixNJzW2FN91LjKJCkVbYGU= github.com/AdguardTeam/urlfilter v0.15.0 h1:K3WWZE0K5nPTHe2l+TRXDFpYWJJnvkHdlWidt6NQUTk= github.com/AdguardTeam/urlfilter v0.15.0/go.mod h1:EwXwrYhowP7bedqmOrmKKmQtpBYFyDNEBFQ+lxdUgQU= @@ -64,7 +64,6 @@ github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY= github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ping/ping v0.0.0-20210506233800-ff8be3320020 h1:mdi6AbCEoKCA1xKCmp7UtRB5fvGFlP92PvlhxgdvXEw= github.com/go-ping/ping v0.0.0-20210506233800-ff8be3320020/go.mod h1:KmHOjTUmJh/l04ukqPoBWPEZr9jwN05h5NXQl5C+DyY= -github.com/go-test/deep v1.0.5 h1:AKODKU3pDH1RzZzm6YZu77YWtEAq6uh1rLIAQlay2qc= github.com/go-test/deep v1.0.5/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= diff --git a/internal/dnsforward/stats.go b/internal/dnsforward/stats.go index abdb519e..67af8ff9 100644 --- a/internal/dnsforward/stats.go +++ b/internal/dnsforward/stats.go @@ -27,11 +27,12 @@ func (s *Server) processQueryLogsAndStats(ctx *dnsContext) (rc resultCode) { shouldLog = false } + ip, _ := netutil.IPAndPortFromAddr(pctx.Addr) + ip = netutil.CloneIP(ip) + s.serverLock.RLock() defer s.serverLock.RUnlock() - ip, _ := netutil.IPAndPortFromAddr(pctx.Addr) - ip = netutil.CloneIP(ip) s.anonymizer.Load()(ip) log.Debug("client ip: %s", ip) @@ -60,12 +61,14 @@ func (s *Server) processQueryLogsAndStats(ctx *dnsContext) (rc resultCode) { case proxy.ProtoDNSCrypt: p.ClientProto = querylog.ClientProtoDNSCrypt default: - // Consider this a plain DNS-over-UDP or DNS-over-TCP - // request. + // Consider this a plain DNS-over-UDP or DNS-over-TCP request. } if pctx.Upstream != nil { p.Upstream = pctx.Upstream.Address() + } else if cachedUps := pctx.CachedUpstreamAddr; cachedUps != "" { + p.Upstream = pctx.CachedUpstreamAddr + p.Cached = true } s.queryLog.Add(p) diff --git a/internal/querylog/decode.go b/internal/querylog/decode.go index d23fc526..65c8ada1 100644 --- a/internal/querylog/decode.go +++ b/internal/querylog/decode.go @@ -44,8 +44,10 @@ var logEntryHandlers = map[string]logEntryHandler{ if !ok { return nil } + var err error ent.Time, err = time.Parse(time.RFC3339, v) + return err }, "QH": func(t json.Token, ent *logEntry) error { @@ -69,7 +71,9 @@ var logEntryHandlers = map[string]logEntryHandler{ if !ok { return nil } + ent.QClass = v + return nil }, "CP": func(t json.Token, ent *logEntry) error { @@ -77,8 +81,10 @@ var logEntryHandlers = map[string]logEntryHandler{ if !ok { return nil } + var err error ent.ClientProto, err = NewClientProto(v) + return err }, "Answer": func(t json.Token, ent *logEntry) error { @@ -86,8 +92,10 @@ var logEntryHandlers = map[string]logEntryHandler{ if !ok { return nil } + var err error ent.Answer, err = base64.StdEncoding.DecodeString(v) + return err }, "OrigAnswer": func(t json.Token, ent *logEntry) error { @@ -95,16 +103,30 @@ var logEntryHandlers = map[string]logEntryHandler{ if !ok { return nil } + var err error ent.OrigAnswer, err = base64.StdEncoding.DecodeString(v) + return err }, + "Cached": func(t json.Token, ent *logEntry) error { + v, ok := t.(bool) + if !ok { + return nil + } + + ent.Cached = v + + return nil + }, "Upstream": func(t json.Token, ent *logEntry) error { v, ok := t.(string) if !ok { return nil } + ent.Upstream = v + return nil }, "Elapsed": func(t json.Token, ent *logEntry) error { @@ -112,11 +134,14 @@ var logEntryHandlers = map[string]logEntryHandler{ if !ok { return nil } + i, err := v.Int64() if err != nil { return err } + ent.Elapsed = time.Duration(i) + return nil }, } diff --git a/internal/querylog/decode_test.go b/internal/querylog/decode_test.go index d57b24f0..fe4e085e 100644 --- a/internal/querylog/decode_test.go +++ b/internal/querylog/decode_test.go @@ -33,6 +33,7 @@ func TestDecodeLogEntry(t *testing.T) { `"QC":"IN",` + `"CP":"",` + `"Answer":"` + ansStr + `",` + + `"Cached":true,` + `"Result":{` + `"IsFiltered":true,` + `"Reason":3,` + @@ -42,6 +43,7 @@ func TestDecodeLogEntry(t *testing.T) { `"CanonName":"example.com",` + `"ServiceName":"example.org",` + `"DNSRewriteResult":{"RCode":0,"Response":{"1":["127.0.0.2"]}}},` + + `"Upstream":"https://some.upstream",` + `"Elapsed":837429}` ans, err := base64.StdEncoding.DecodeString(ansStr) @@ -56,6 +58,7 @@ func TestDecodeLogEntry(t *testing.T) { ClientID: "cli42", ClientProto: "", Answer: ans, + Cached: true, Result: filtering.Result{ IsFiltered: true, Reason: filtering.FilteredBlockList, @@ -78,7 +81,8 @@ func TestDecodeLogEntry(t *testing.T) { }, }, }, - Elapsed: 837429, + Upstream: "https://some.upstream", + Elapsed: 837429, } got := &logEntry{} diff --git a/internal/querylog/json.go b/internal/querylog/json.go index 23953f80..6f59f1d5 100644 --- a/internal/querylog/json.go +++ b/internal/querylog/json.go @@ -74,6 +74,7 @@ func (l *queryLog) entryToJSON(entry *logEntry, anonFunc aghnet.IPMutFunc) (json "time": entry.Time.Format(time.RFC3339Nano), "client": eip, "client_proto": entry.ClientProto, + "cached": entry.Cached, "upstream": entry.Upstream, "question": question, } diff --git a/internal/querylog/qlog.go b/internal/querylog/qlog.go index 48f0d351..f04eecb5 100644 --- a/internal/querylog/qlog.go +++ b/internal/querylog/qlog.go @@ -87,10 +87,11 @@ type logEntry struct { Answer []byte `json:",omitempty"` // sometimes empty answers happen like binerdunt.top or rev2.globalrootservers.net OrigAnswer []byte `json:",omitempty"` + Cached bool `json:",omitempty"` Result filtering.Result Elapsed time.Duration - Upstream string `json:",omitempty"` // if empty, means it was cached + Upstream string `json:",omitempty"` } func (l *queryLog) Start() { @@ -171,6 +172,7 @@ func (l *queryLog) Add(params AddParams) { Result: *params.Result, Elapsed: params.Elapsed, Upstream: params.Upstream, + Cached: params.Cached, ClientID: params.ClientID, ClientProto: params.ClientProto, } diff --git a/internal/querylog/querylog.go b/internal/querylog/querylog.go index 58b5a8e0..0b39c01e 100644 --- a/internal/querylog/querylog.go +++ b/internal/querylog/querylog.go @@ -73,16 +73,24 @@ type Config struct { Anonymizer *aghnet.IPMut } -// AddParams - parameters for Add() +// AddParams is the parameters for adding an entry. type AddParams struct { - Question *dns.Msg - Answer *dns.Msg // The response we sent to the client (optional) - OrigAnswer *dns.Msg // The response from an upstream server (optional) - Result *filtering.Result // Filtering result (optional) - Elapsed time.Duration // Time spent for processing the request - ClientID string - ClientIP net.IP - Upstream string // Upstream server URL + Question *dns.Msg + // Answer is the response which is sent to the client, if any. + Answer *dns.Msg + // OrigAnswer is the response from an upstream server. It's only set if the + // answer has been modified by filtering. + OrigAnswer *dns.Msg + // Cached indicates if the response is served from cache. + Cached bool + // 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 } diff --git a/openapi/CHANGELOG.md b/openapi/CHANGELOG.md index 7fceb418..558490f2 100644 --- a/openapi/CHANGELOG.md +++ b/openapi/CHANGELOG.md @@ -4,6 +4,11 @@ ## v0.107: API changes +## The new field `"cached"` in `QueryLogItem` + +* The new field `"cached"` in `GET /control/querylog` is true if the response is + served from cache instead of being resolved by an upstream server. + ### New constant values for `filter_list_id` field in `ResultRule` * Value of `0` is now used for custom filtering rules list. diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index aa2d5aa3..ea5aa05b 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -1868,6 +1868,10 @@ 'description': 'Answer from upstream server (optional)' 'items': '$ref': '#/components/schemas/DnsAnswer' + 'cached': + 'type': 'boolean' + 'description': > + Defines if the response has been served from cache. 'upstream': 'type': 'string' 'description': > From 25fd34c51459d9b3b9d5fde4060902228a5569ec Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Thu, 9 Dec 2021 18:26:56 +0300 Subject: [PATCH 038/135] Pull request: all: get rid of labels Merge in DNS/adguard-home from rm-labels to master Squashed commit of the following: commit 5e3688ed92b0f76a47078a55bc22c401422c914c Author: Eugene Burkov Date: Thu Dec 9 17:46:50 2021 +0300 all: imp code, docs commit 123d1ec52d0037315e8de94ab5a26b48cf0bf984 Author: Eugene Burkov Date: Thu Dec 9 17:14:05 2021 +0300 all: get rid of labels --- internal/aghnet/hostscontainer.go | 15 ++++++++------- internal/aghos/os.go | 24 ++++++++++++++---------- internal/aghos/os_test.go | 6 +++--- 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/internal/aghnet/hostscontainer.go b/internal/aghnet/hostscontainer.go index 1e1808bc..ca8631c2 100644 --- a/internal/aghnet/hostscontainer.go +++ b/internal/aghnet/hostscontainer.go @@ -309,21 +309,22 @@ func (hp *hostsParser) parseLine(line string) (ip net.IP, hosts []string) { return nil, nil } -loop: for _, f := range fields[1:] { switch hashIdx := strings.IndexByte(f, '#'); hashIdx { - case 0: - // The rest of the fields are a part of the comment so skip - // immediately. - break loop case -1: hosts = append(hosts, f) + + continue + case 0: + // Go on. default: // Only a part of the field is a comment. hosts = append(hosts, f[:hashIdx]) - - break loop } + + // The rest of the fields are a part of the comment so skip + // immediately. + break } return ip, hosts diff --git a/internal/aghos/os.go b/internal/aghos/os.go index 1723e001..5adb65b1 100644 --- a/internal/aghos/os.go +++ b/internal/aghos/os.go @@ -91,7 +91,7 @@ func PIDByCommand(command string, except ...int) (pid int, err error) { } var instNum int - pid, instNum, err = parsePSOutput(stdout, command, except...) + pid, instNum, err = parsePSOutput(stdout, command, except) if err != nil { return 0, err } @@ -125,9 +125,8 @@ func PIDByCommand(command string, except ...int) (pid int, err error) { // 1230 some/base/path/example-cmd // 3210 example-cmd // -func parsePSOutput(r io.Reader, cmdName string, ignore ...int) (largest, instNum int, err error) { +func parsePSOutput(r io.Reader, cmdName string, ignore []int) (largest, instNum int, err error) { s := bufio.NewScanner(r) -ScanLoop: for s.Scan() { fields := strings.Fields(s.Text()) if len(fields) != 2 || path.Base(fields[1]) != cmdName { @@ -135,16 +134,10 @@ ScanLoop: } cur, aerr := strconv.Atoi(fields[0]) - if aerr != nil || cur < 0 { + if aerr != nil || cur < 0 || intIn(cur, ignore) { continue } - for _, pid := range ignore { - if cur == pid { - continue ScanLoop - } - } - instNum++ if cur > largest { largest = cur @@ -157,6 +150,17 @@ ScanLoop: return largest, instNum, nil } +// intIn returns true if nums contains n. +func intIn(n int, nums []int) (ok bool) { + for _, nn := range nums { + if n == nn { + return true + } + } + + return false +} + // IsOpenWrt returns true if host OS is OpenWrt. func IsOpenWrt() (ok bool) { return isOpenWrt() diff --git a/internal/aghos/os_test.go b/internal/aghos/os_test.go index 0ca567d8..f56a93ac 100644 --- a/internal/aghos/os_test.go +++ b/internal/aghos/os_test.go @@ -63,7 +63,7 @@ func TestLargestLabeled(t *testing.T) { r := bytes.NewReader(tc.data) t.Run(tc.name, func(t *testing.T) { - pid, instNum, err := parsePSOutput(r, comm) + pid, instNum, err := parsePSOutput(r, comm, nil) require.NoError(t, err) assert.Equal(t, tc.wantPID, pid) @@ -76,7 +76,7 @@ func TestLargestLabeled(t *testing.T) { require.NoError(t, err) target := &aghio.LimitReachedError{} - _, _, err = parsePSOutput(lr, "") + _, _, err = parsePSOutput(lr, "", nil) require.ErrorAs(t, err, &target) assert.EqualValues(t, 0, target.Limit) @@ -89,7 +89,7 @@ func TestLargestLabeled(t *testing.T) { `3` + comm + nl, )) - pid, instances, err := parsePSOutput(r, comm, 1, 3) + pid, instances, err := parsePSOutput(r, comm, []int{1, 3}) require.NoError(t, err) assert.Equal(t, 2, pid) From 86cffcd168415f92a452b3e275679c36f0fd00ef Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Fri, 10 Dec 2021 17:20:15 +0300 Subject: [PATCH 039/135] Pull request: all: upd go, minor imp Merge in DNS/adguard-home from minor-imp to master Squashed commit of the following: commit c5b9e2a15290760b2782acc0c08df3fe57356500 Author: Ainar Garipov Date: Fri Dec 10 14:23:28 2021 +0300 all: upd go, minor imp --- bamboo-specs/release.yaml | 6 +++--- bamboo-specs/test.yaml | 2 +- internal/aghos/os.go | 4 ++-- internal/dnsforward/dnsforward.go | 2 +- internal/filtering/filtering.go | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/bamboo-specs/release.yaml b/bamboo-specs/release.yaml index 86b3f0aa..325705ae 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:3.6' + 'dockerGo': 'adguard/golang-ubuntu:3.8' 'stages': - 'Make release': @@ -266,7 +266,7 @@ # need to build a few of these. 'variables': 'channel': 'beta' - 'dockerGo': 'adguard/golang-ubuntu:3.6' + 'dockerGo': 'adguard/golang-ubuntu:3.8' # release-vX.Y.Z branches are the branches from which the actual final release # is built. - '^release-v[0-9]+\.[0-9]+\.[0-9]+': @@ -276,4 +276,4 @@ # are the ones that actually get released. 'variables': 'channel': 'release' - 'dockerGo': 'adguard/golang-ubuntu:3.6' + 'dockerGo': 'adguard/golang-ubuntu:3.8' diff --git a/bamboo-specs/test.yaml b/bamboo-specs/test.yaml index e34a1a09..9b427e5a 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:3.6' + 'dockerGo': 'adguard/golang-ubuntu:3.8' 'stages': - 'Tests': diff --git a/internal/aghos/os.go b/internal/aghos/os.go index 5adb65b1..29eb1afc 100644 --- a/internal/aghos/os.go +++ b/internal/aghos/os.go @@ -118,8 +118,8 @@ func PIDByCommand(command string, except ...int) (pid int, err error) { } // parsePSOutput scans the output of ps searching the largest PID of the process -// associated with cmdName ignoring PIDs from ignore. Valid r's line shoud be -// like: +// associated with cmdName ignoring PIDs from ignore. A valid line from +// r should look like these: // // 123 ./example-cmd // 1230 some/base/path/example-cmd diff --git a/internal/dnsforward/dnsforward.go b/internal/dnsforward/dnsforward.go index e4547307..ab2d8a82 100644 --- a/internal/dnsforward/dnsforward.go +++ b/internal/dnsforward/dnsforward.go @@ -559,7 +559,7 @@ func (s *Server) IsRunning() bool { return s.isRunning } -// srvClosedErr is returned when the method can't complete without unacessible +// srvClosedErr is returned when the method can't complete without inacessible // data from the closing server. const srvClosedErr errors.Error = "server is closed" diff --git a/internal/filtering/filtering.go b/internal/filtering/filtering.go index ab0c427a..0e0bb0ab 100644 --- a/internal/filtering/filtering.go +++ b/internal/filtering/filtering.go @@ -651,7 +651,7 @@ func newRuleStorage(filters []Filter) (rs *filterlist.RuleStorage, err error) { rs, err = filterlist.NewRuleStorage(lists) if err != nil { - return nil, fmt.Errorf("creating rule stroage: %w", err) + return nil, fmt.Errorf("creating rule storage: %w", err) } return rs, nil From 774937728b13aba0a1c7e7b8acaea9edb362926a Mon Sep 17 00:00:00 2001 From: Keith Collister Date: Sun, 12 Dec 2021 11:46:13 +0100 Subject: [PATCH 040/135] Prevent spurious diffs in config file by sorting Client objects before writing --- internal/home/clients.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/internal/home/clients.go b/internal/home/clients.go index 02c87f03..09472fbd 100644 --- a/internal/home/clients.go +++ b/internal/home/clients.go @@ -222,6 +222,9 @@ func (clients *clientsContainer) addFromConfig(objects []clientObject) { // WriteDiskConfig - write configuration func (clients *clientsContainer) WriteDiskConfig(objects *[]clientObject) { clients.lock.Lock() + defer clients.lock.Unlock() + + clientObjects := []clientObject{} for _, cli := range clients.list { cy := clientObject{ Name: cli.Name, @@ -238,9 +241,17 @@ func (clients *clientsContainer) WriteDiskConfig(objects *[]clientObject) { cy.BlockedServices = stringutil.CloneSlice(cli.BlockedServices) cy.Upstreams = stringutil.CloneSlice(cli.Upstreams) - *objects = append(*objects, cy) + clientObjects = append(clientObjects, cy) } - clients.lock.Unlock() + + // Maps aren't guaranteed to iterate in the same order each time, so the + // above loop can generate different orderings when writing to the + // config file: this produces lots of diffs in config files, so sort + // objects by name before writing. + sort.Slice(clientObjects, func(i, j int) bool { + return clientObjects[i].Name < clientObjects[j].Name + }) + *objects = append(*objects, clientObjects...) } func (clients *clientsContainer) periodicUpdate() { From a396865869adc8da415ff2f24d5f5108fe9bac7f Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Mon, 13 Dec 2021 13:48:08 +0300 Subject: [PATCH 041/135] Pull request: all: do not redirect to https if not necessary Merge in DNS/adguard-home from 3558-https-redirect to master Squashed commit of the following: commit f656563c0b0db6275748de28bc890dcf85b0e398 Author: Ainar Garipov Date: Fri Dec 10 20:44:00 2021 +0300 all: do not redirect to https if not necessary --- CHANGELOG.md | 3 +++ client/src/helpers/helpers.js | 4 ++-- internal/home/config.go | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 044b9688..e27fab44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -125,6 +125,8 @@ In this release, the schema version has changed from 10 to 12. ### Fixed +- Invalid redirection to the HTTPS web interface after saving enabled encryption + 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 @@ -217,6 +219,7 @@ In this release, the schema version has changed from 10 to 12. [#3529]: https://github.com/AdguardTeam/AdGuardHome/issues/3529 [#3538]: https://github.com/AdguardTeam/AdGuardHome/issues/3538 [#3551]: https://github.com/AdguardTeam/AdGuardHome/issues/3551 +[#3558]: https://github.com/AdguardTeam/AdGuardHome/issues/3558 [#3564]: https://github.com/AdguardTeam/AdGuardHome/issues/3564 [#3567]: https://github.com/AdguardTeam/AdGuardHome/issues/3567 [#3568]: https://github.com/AdguardTeam/AdGuardHome/issues/3568 diff --git a/client/src/helpers/helpers.js b/client/src/helpers/helpers.js index 8f4344ee..6753062a 100644 --- a/client/src/helpers/helpers.js +++ b/client/src/helpers/helpers.js @@ -301,10 +301,10 @@ export const redirectToCurrentProtocol = (values, httpPort = 80) => { const { protocol, hostname, hash, port, } = window.location; - const { enabled, port_https } = values; + const { enabled, force_https, port_https } = values; const httpsPort = port_https !== STANDARD_HTTPS_PORT ? `:${port_https}` : ''; - if (protocol !== 'https:' && enabled && port_https) { + if (protocol !== 'https:' && enabled && force_https && port_https) { checkRedirect(`https://${hostname}${httpsPort}/${hash}`); } else if (protocol === 'https:' && enabled && port_https && port_https !== parseInt(port, 10)) { checkRedirect(`https://${hostname}${httpsPort}/${hash}`); diff --git a/internal/home/config.go b/internal/home/config.go index 3465c26f..5d329fe2 100644 --- a/internal/home/config.go +++ b/internal/home/config.go @@ -140,7 +140,7 @@ type dnsConfig struct { type tlsConfigSettings struct { Enabled bool `yaml:"enabled" json:"enabled"` // Enabled is the encryption (DoT/DoH/HTTPS) status ServerName string `yaml:"server_name" json:"server_name,omitempty"` // ServerName is the hostname of your HTTPS/TLS server - ForceHTTPS bool `yaml:"force_https" json:"force_https,omitempty"` // ForceHTTPS: if true, forces HTTP->HTTPS redirect + ForceHTTPS bool `yaml:"force_https" json:"force_https"` // ForceHTTPS: if true, forces HTTP->HTTPS redirect PortHTTPS int `yaml:"port_https" json:"port_https,omitempty"` // HTTPS port. If 0, HTTPS will be disabled PortDNSOverTLS int `yaml:"port_dns_over_tls" json:"port_dns_over_tls,omitempty"` // DNS-over-TLS port. If 0, DoT will be disabled PortDNSOverQUIC int `yaml:"port_dns_over_quic" json:"port_dns_over_quic,omitempty"` // DNS-over-QUIC port. If 0, DoQ will be disabled From 0bd436f4b0f1196c49d788804310b8ef79970ca5 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Mon, 13 Dec 2021 13:55:41 +0300 Subject: [PATCH 042/135] Pull request: querylog: fix logic Merge in DNS/adguard-home from fix-querylog-logs to master Squashed commit of the following: commit db6edb86f1f024c85efd3bca3ceb6dfc6ce04edd Merge: d1981696 a3968658 Author: Ainar Garipov Date: Mon Dec 13 13:48:25 2021 +0300 Merge branch 'master' into fix-querylog-logs commit d1981696782ca9adc5213f76cdbe2dc9f859f921 Author: Ainar Garipov Date: Fri Dec 10 21:14:04 2021 +0300 querylog: fix logic --- internal/aghnet/interfaces.go | 2 ++ internal/querylog/qlogfile.go | 4 +-- internal/querylog/qlogfile_test.go | 6 ++-- internal/querylog/qlogreader.go | 51 ++++++++++++++++------------ internal/querylog/qlogreader_test.go | 4 +-- internal/querylog/search.go | 2 +- 6 files changed, 40 insertions(+), 29 deletions(-) diff --git a/internal/aghnet/interfaces.go b/internal/aghnet/interfaces.go index ce7f217c..c8efc57b 100644 --- a/internal/aghnet/interfaces.go +++ b/internal/aghnet/interfaces.go @@ -92,6 +92,8 @@ func IfaceDNSIPAddrs( time.Sleep(backoff) } + n-- + switch len(addrs) { case 0: // Don't return errors in case the users want to try and enable diff --git a/internal/querylog/qlogfile.go b/internal/querylog/qlogfile.go index f0c7b7c4..fd6c5226 100644 --- a/internal/querylog/qlogfile.go +++ b/internal/querylog/qlogfile.go @@ -54,7 +54,7 @@ func NewQLogFile(path string) (*QLogFile, error) { }, nil } -// SeekTS performs binary search in the query log file looking for a record +// seekTS performs binary search in the query log file looking for a record // with the specified timestamp. Once the record is found, it sets // "position" so that the next ReadNext call returned that record. // @@ -71,7 +71,7 @@ func NewQLogFile(path string) (*QLogFile, error) { // so that when we call "ReadNext" this line was returned. // * Depth of the search (how many times we compared timestamps). // * If we could not find it, it returns one of the errors described above. -func (q *QLogFile) SeekTS(timestamp int64) (int64, int, error) { +func (q *QLogFile) seekTS(timestamp int64) (int64, int, error) { q.lock.Lock() defer q.lock.Unlock() diff --git a/internal/querylog/qlogfile_test.go b/internal/querylog/qlogfile_test.go index b85eb049..ff1a53b3 100644 --- a/internal/querylog/qlogfile_test.go +++ b/internal/querylog/qlogfile_test.go @@ -175,7 +175,7 @@ func TestQLogFile_SeekTS_good(t *testing.T) { assert.NotEqualValues(t, 0, ts) // Try seeking to that line now. - pos, _, err := q.SeekTS(ts) + pos, _, err := q.seekTS(ts) require.NoError(t, err) assert.NotEqualValues(t, 0, pos) @@ -228,7 +228,7 @@ func TestQLogFile_SeekTS_bad(t *testing.T) { assert.NotEqualValues(t, 0, tc.ts) var depth int - _, depth, err = q.SeekTS(tc.ts) + _, depth, err = q.seekTS(tc.ts) assert.NotEmpty(t, l.num) require.Error(t, err) @@ -340,7 +340,7 @@ func TestQLog_Seek(t *testing.T) { q := NewTestQLogFileData(t, data) - _, depth, err := q.SeekTS(timestamp.Add(time.Second * time.Duration(tc.delta)).UnixNano()) + _, depth, err := q.seekTS(timestamp.Add(time.Second * time.Duration(tc.delta)).UnixNano()) require.Truef(t, errors.Is(err, tc.wantErr), "%v", err) assert.Equal(t, tc.wantDepth, depth) }) diff --git a/internal/querylog/qlogreader.go b/internal/querylog/qlogreader.go index 7735eb67..704dc5ca 100644 --- a/internal/querylog/qlogreader.go +++ b/internal/querylog/qlogreader.go @@ -53,35 +53,44 @@ func NewQLogReader(files []string) (*QLogReader, error) { }, nil } -// SeekTS performs binary search of a query log record with the specified +// seekTS performs binary search of a query log record with the specified // timestamp. If the record is found, it sets QLogReader's position to point to // that line, so that the next ReadNext call returned this line. -func (r *QLogReader) SeekTS(timestamp int64) (err error) { +func (r *QLogReader) seekTS(timestamp int64) (err error) { for i := len(r.qFiles) - 1; i >= 0; i-- { q := r.qFiles[i] - _, _, err = q.SeekTS(timestamp) - if err == nil { - // Search is finished, and the searched element have - // been found. Update currentFile only, position is - // already set properly in QLogFile. - r.currentFile = i + _, _, err = q.seekTS(timestamp) + if err != nil { + if errors.Is(err, ErrTSTooEarly) { + // Look at the next file, since we've reached the end of this + // one. If there is no next file, it's not found. + err = ErrTSNotFound - return nil - } else if errors.Is(err, ErrTSTooEarly) { - // Look at the next file, since we've reached the end of - // this one. - continue - } else if errors.Is(err, ErrTSTooLate) { - // Just seek to the start then. timestamp is probably - // between the end of the previous one and the start of - // this one. - return r.SeekStart() - } else if errors.Is(err, ErrTSNotFound) { - break + continue + } else if errors.Is(err, ErrTSTooLate) { + // Just seek to the start then. timestamp is probably between + // the end of the previous one and the start of this one. + return r.SeekStart() + } else if errors.Is(err, ErrTSNotFound) { + return err + } else { + return fmt.Errorf("seekts: file at index %d: %w", i, err) + } } + + // The search is finished, and the searched element has been found. + // Update currentFile only, position is already set properly in + // QLogFile. + r.currentFile = i + + return nil } - return fmt.Errorf("querylog: %w", err) + if err != nil { + return fmt.Errorf("seekts: %w", err) + } + + return nil } // SeekStart changes the current position to the end of the newest file diff --git a/internal/querylog/qlogreader_test.go b/internal/querylog/qlogreader_test.go index 564508f7..ffdc285b 100644 --- a/internal/querylog/qlogreader_test.go +++ b/internal/querylog/qlogreader_test.go @@ -97,7 +97,7 @@ func TestQLogReader_Seek(t *testing.T) { }, { name: "non-existent_long_ago", time: "2000-02-19T01:23:16.920973+03:00", - want: ErrTSTooEarly, + want: ErrTSNotFound, }, { name: "non-existent_far_ahead", time: "2100-02-19T01:23:16.920973+03:00", @@ -113,7 +113,7 @@ func TestQLogReader_Seek(t *testing.T) { ts, err := time.Parse(time.RFC3339Nano, tc.time) require.NoError(t, err) - err = r.SeekTS(ts.UnixNano()) + err = r.seekTS(ts.UnixNano()) assert.ErrorIs(t, err, tc.want) }) } diff --git a/internal/querylog/search.go b/internal/querylog/search.go index 2181ab04..d387c938 100644 --- a/internal/querylog/search.go +++ b/internal/querylog/search.go @@ -152,7 +152,7 @@ func (l *queryLog) searchFiles( if params.olderThan.IsZero() { err = r.SeekStart() } else { - err = r.SeekTS(params.olderThan.UnixNano()) + err = r.seekTS(params.olderThan.UnixNano()) if err == nil { // Read to the next record, because we only need the one // that goes after it. From 0e1015a4ee7f4101ef21cb2b2688beb50a11dc83 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Mon, 13 Dec 2021 14:56:48 +0300 Subject: [PATCH 043/135] all: doc changes, imp names --- CHANGELOG.md | 2 ++ internal/home/clients.go | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 044b9688..b0a6d96d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,7 @@ and this project adheres to ### Changed +- Client objects in the configuration file are now sorted ([#3933]). - Responses from cache are now labeled ([#3772]). - Better error message for ED25519 private keys, which are not widely supported ([#3737]). @@ -229,6 +230,7 @@ In this release, the schema version has changed from 10 to 12. [#3772]: https://github.com/AdguardTeam/AdGuardHome/issues/3772 [#3815]: https://github.com/AdguardTeam/AdGuardHome/issues/3815 [#3890]: https://github.com/AdguardTeam/AdGuardHome/issues/3890 +[#3933]: https://github.com/AdguardTeam/AdGuardHome/pull/3933 diff --git a/internal/home/clients.go b/internal/home/clients.go index 09472fbd..78cc7101 100644 --- a/internal/home/clients.go +++ b/internal/home/clients.go @@ -224,9 +224,9 @@ func (clients *clientsContainer) WriteDiskConfig(objects *[]clientObject) { clients.lock.Lock() defer clients.lock.Unlock() - clientObjects := []clientObject{} + var clientObjects []clientObject for _, cli := range clients.list { - cy := clientObject{ + cliObj := clientObject{ Name: cli.Name, UseGlobalSettings: !cli.UseOwnSettings, FilteringEnabled: cli.FilteringEnabled, @@ -236,18 +236,18 @@ func (clients *clientsContainer) WriteDiskConfig(objects *[]clientObject) { UseGlobalBlockedServices: !cli.UseOwnBlockedServices, } - cy.Tags = stringutil.CloneSlice(cli.Tags) - cy.IDs = stringutil.CloneSlice(cli.IDs) - cy.BlockedServices = stringutil.CloneSlice(cli.BlockedServices) - cy.Upstreams = stringutil.CloneSlice(cli.Upstreams) + cliObj.Tags = stringutil.CloneSlice(cli.Tags) + cliObj.IDs = stringutil.CloneSlice(cli.IDs) + cliObj.BlockedServices = stringutil.CloneSlice(cli.BlockedServices) + cliObj.Upstreams = stringutil.CloneSlice(cli.Upstreams) - clientObjects = append(clientObjects, cy) + clientObjects = append(clientObjects, cliObj) } // Maps aren't guaranteed to iterate in the same order each time, so the - // above loop can generate different orderings when writing to the - // config file: this produces lots of diffs in config files, so sort - // objects by name before writing. + // above loop can generate different orderings when writing to the config + // file: this produces lots of diffs in config files, so sort objects by + // name before writing. sort.Slice(clientObjects, func(i, j int) bool { return clientObjects[i].Name < clientObjects[j].Name }) From 39da2f9eaa7ba858b7857da34a6ba498b9c9c46a Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Mon, 13 Dec 2021 15:18:21 +0300 Subject: [PATCH 044/135] home: imp client handling --- internal/home/clients.go | 85 ++++++++++++++++++++-------------------- internal/home/config.go | 12 +++--- internal/home/home.go | 2 +- 3 files changed, 50 insertions(+), 49 deletions(-) diff --git a/internal/home/clients.go b/internal/home/clients.go index 78cc7101..ba5b5161 100644 --- a/internal/home/clients.go +++ b/internal/home/clients.go @@ -106,7 +106,7 @@ type clientsContainer struct { // dhcpServer: optional // Note: this function must be called only once func (clients *clientsContainer) Init( - objects []clientObject, + objects []*clientObject, dhcpServer *dhcpd.Server, etcHosts *aghnet.HostsContainer, ) { @@ -175,59 +175,64 @@ type clientObject struct { UseGlobalBlockedServices bool `yaml:"use_global_blocked_services"` } -func (clients *clientsContainer) tagKnown(tag string) (ok bool) { - return clients.allTags.Has(tag) -} - -func (clients *clientsContainer) addFromConfig(objects []clientObject) { - for _, cy := range objects { +// addFromConfig initializes the clients containter with objects from the +// configuration file. +func (clients *clientsContainer) addFromConfig(objects []*clientObject) { + for _, o := range objects { cli := &Client{ - Name: cy.Name, - IDs: cy.IDs, - UseOwnSettings: !cy.UseGlobalSettings, - FilteringEnabled: cy.FilteringEnabled, - ParentalEnabled: cy.ParentalEnabled, - SafeSearchEnabled: cy.SafeSearchEnabled, - SafeBrowsingEnabled: cy.SafeBrowsingEnabled, + Name: o.Name, - UseOwnBlockedServices: !cy.UseGlobalBlockedServices, + IDs: o.IDs, + Upstreams: o.Upstreams, - Upstreams: cy.Upstreams, + UseOwnSettings: !o.UseGlobalSettings, + FilteringEnabled: o.FilteringEnabled, + ParentalEnabled: o.ParentalEnabled, + SafeSearchEnabled: o.SafeSearchEnabled, + SafeBrowsingEnabled: o.SafeBrowsingEnabled, + UseOwnBlockedServices: !o.UseGlobalBlockedServices, } - for _, s := range cy.BlockedServices { - if !filtering.BlockedSvcKnown(s) { - log.Debug("clients: skipping unknown blocked-service %q", s) - continue + for _, s := range o.BlockedServices { + if filtering.BlockedSvcKnown(s) { + cli.BlockedServices = append(cli.BlockedServices, s) + } else { + log.Info("clients: skipping unknown blocked service %q", s) } - cli.BlockedServices = append(cli.BlockedServices, s) } - for _, t := range cy.Tags { - if !clients.tagKnown(t) { - log.Debug("clients: skipping unknown tag %q", t) - continue + for _, t := range o.Tags { + if clients.allTags.Has(t) { + cli.Tags = append(cli.Tags, t) + } else { + log.Info("clients: skipping unknown tag %q", t) } - cli.Tags = append(cli.Tags, t) } + sort.Strings(cli.Tags) _, err := clients.Add(cli) if err != nil { - log.Tracef("clientAdd: %s", err) + log.Error("clients: adding clients %s: %s", cli.Name, err) } } } -// WriteDiskConfig - write configuration -func (clients *clientsContainer) WriteDiskConfig(objects *[]clientObject) { +// forConfig returns all currently known persistent clients as objects for the +// configuration file. +func (clients *clientsContainer) forConfig() (objs []*clientObject) { clients.lock.Lock() defer clients.lock.Unlock() - var clientObjects []clientObject for _, cli := range clients.list { - cliObj := clientObject{ - Name: cli.Name, + o := &clientObject{ + Name: cli.Name, + + Tags: stringutil.CloneSlice(cli.Tags), + IDs: stringutil.CloneSlice(cli.IDs), + BlockedServices: stringutil.CloneSlice(cli.BlockedServices), + Upstreams: stringutil.CloneSlice(cli.Upstreams), + UseGlobalSettings: !cli.UseOwnSettings, FilteringEnabled: cli.FilteringEnabled, ParentalEnabled: cli.ParentalEnabled, @@ -236,22 +241,16 @@ func (clients *clientsContainer) WriteDiskConfig(objects *[]clientObject) { UseGlobalBlockedServices: !cli.UseOwnBlockedServices, } - cliObj.Tags = stringutil.CloneSlice(cli.Tags) - cliObj.IDs = stringutil.CloneSlice(cli.IDs) - cliObj.BlockedServices = stringutil.CloneSlice(cli.BlockedServices) - cliObj.Upstreams = stringutil.CloneSlice(cli.Upstreams) - - clientObjects = append(clientObjects, cliObj) + objs = append(objs, o) } // Maps aren't guaranteed to iterate in the same order each time, so the // above loop can generate different orderings when writing to the config // file: this produces lots of diffs in config files, so sort objects by // name before writing. - sort.Slice(clientObjects, func(i, j int) bool { - return clientObjects[i].Name < clientObjects[j].Name - }) - *objects = append(*objects, clientObjects...) + sort.Slice(objs, func(i, j int) bool { return objs[i].Name < objs[j].Name }) + + return objs } func (clients *clientsContainer) periodicUpdate() { @@ -537,7 +536,7 @@ func (clients *clientsContainer) check(c *Client) (err error) { } for _, t := range c.Tags { - if !clients.tagKnown(t) { + if !clients.allTags.Has(t) { return fmt.Errorf("invalid tag: %q", t) } } diff --git a/internal/home/config.go b/internal/home/config.go index 3465c26f..368a4b51 100644 --- a/internal/home/config.go +++ b/internal/home/config.go @@ -84,8 +84,11 @@ type configuration struct { DHCP dhcpd.ServerConfig `yaml:"dhcp"` - // Note: this array is filled only before file read/write and then it's cleared - Clients []clientObject `yaml:"clients"` + // Note: this array is filled only before file read/write and then it's + // cleared. + // + // TODO(a.garipov): Do something with this. + Clients []*clientObject `yaml:"clients"` logSettings `yaml:",inline"` @@ -316,8 +319,6 @@ func (c *configuration) write() error { c.Lock() defer c.Unlock() - Context.clients.WriteDiskConfig(&config.Clients) - if Context.auth != nil { config.Users = Context.auth.GetUsers() } @@ -365,10 +366,11 @@ func (c *configuration) write() error { config.DHCP = c } + config.Clients = Context.clients.forConfig() + configFile := config.getConfigFilename() log.Debug("Writing YAML file: %s", configFile) yamlText, err := yaml.Marshal(&config) - config.Clients = nil if err != nil { log.Error("Couldn't generate YAML file: %s", err) diff --git a/internal/home/home.go b/internal/home/home.go index ec103b1f..1238aaec 100644 --- a/internal/home/home.go +++ b/internal/home/home.go @@ -294,8 +294,8 @@ func setupConfig(args options) (err error) { return err } } + Context.clients.Init(config.Clients, Context.dhcpServer, Context.etcHosts) - config.Clients = nil // override bind host/port from the console if args.bindHost != nil { From 0d6f4f013902bbaea130335fbf5080575a958dc6 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Mon, 13 Dec 2021 15:24:35 +0300 Subject: [PATCH 045/135] home: imp docs, opt --- internal/home/config.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/internal/home/config.go b/internal/home/config.go index 368a4b51..a6be26d9 100644 --- a/internal/home/config.go +++ b/internal/home/config.go @@ -84,10 +84,9 @@ type configuration struct { DHCP dhcpd.ServerConfig `yaml:"dhcp"` - // Note: this array is filled only before file read/write and then it's - // cleared. - // - // TODO(a.garipov): Do something with this. + // 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"` logSettings `yaml:",inline"` From 6a6f926bd04fb05232dab628f5fc877d9307f175 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Mon, 13 Dec 2021 15:28:12 +0300 Subject: [PATCH 046/135] all: imp hooks, opt --- internal/home/clients.go | 1 + scripts/hooks/pre-commit | 69 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/internal/home/clients.go b/internal/home/clients.go index ba5b5161..7a478679 100644 --- a/internal/home/clients.go +++ b/internal/home/clients.go @@ -224,6 +224,7 @@ func (clients *clientsContainer) forConfig() (objs []*clientObject) { clients.lock.Lock() defer clients.lock.Unlock() + objs = make([]*clientObject, 0, len(clients.list)) for _, cli := range clients.list { o := &clientObject{ Name: cli.Name, diff --git a/scripts/hooks/pre-commit b/scripts/hooks/pre-commit index b52735b1..9866e3ed 100755 --- a/scripts/hooks/pre-commit +++ b/scripts/hooks/pre-commit @@ -2,9 +2,72 @@ set -e -f -u -# Show all temporary todos to the programmer but don't fail the commit -# if there are any, because the commit could be in a temporary branch. -git grep -e 'TODO.*!!' -- ':!scripts/hooks/pre-commit' | cat || : +# Only show interactive prompts if there is a terminal attached. This +# should work on all of our supported Unix systems. +is_tty='0' +if [ -e /dev/tty ] +then + is_tty='1' +fi +readonly is_tty + +# prompt is a helper that prompts the user for interactive input if that +# can be done. If there is no terminal attached, it sleeps for two +# seconds, giving the programmer some time to react, and returns with +# a zero exit code. +prompt() { + if [ "$is_tty" -eq '0' ] + then + sleep 2 + + return 0 + fi + + while true + do + printf 'commit anyway? y/[n]: ' + read -r ans < /dev/tty + + case "$ans" + in + ('y'|'Y') + break + ;; + (''|'n'|'N') + exit 1 + ;; + (*) + continue + ;; + esac + done +} + +# Warn the programmer about unstaged changes and untracked files, but do +# not fail the commit, because those changes might be temporary or for +# a different branch. +awk_prog='substr($2, 2, 1) != "." { print $9; } $1 == "?" { print $2; }' +readonly awk_prog + +unstaged="$( git status --porcelain=2 | awk "$awk_prog" )" +readonly unstaged + +if [ "$unstaged" != "" ] +then + printf 'WARNING: you have unstaged changes:\n\n%s\n\n' "$unstaged" + prompt +fi + +# Warn the programmer about temporary todos, but do not fail the commit, +# because the commit could be in a temporary branch. +temp_todos="$( git grep -e 'TODO.*!!' -- ':!scripts/hooks/pre-commit' || : )" +readonly temp_todos + +if [ "$temp_todos" != "" ] +then + printf 'WARNING: you have temporary todos:\n\n%s\n\n' "$temp_todos" + prompt +fi verbose="${VERBOSE:-0}" readonly verbose From f315601a9fd8311efd3353bf5c79faec401e12c9 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Mon, 13 Dec 2021 18:06:01 +0300 Subject: [PATCH 047/135] Pull request: all: simplify dnssec logic Closes #3904. Squashed commit of the following: commit 5948f0d3519299a1253e388f4bc83e2e55847f68 Author: Ainar Garipov Date: Mon Dec 13 17:53:40 2021 +0300 querylog: imp commit 852cc7dbdb495a17ff51b99ab12901b846f8be09 Author: Ainar Garipov Date: Mon Dec 13 17:44:41 2021 +0300 querylog: fix entry write commit 9d58046899f35162596bfc94fe88fa944309b2fd Author: Ainar Garipov Date: Mon Dec 13 16:45:56 2021 +0300 all: simplify dnssec logic --- CHANGELOG.md | 3 + internal/dnsforward/config.go | 2 +- internal/dnsforward/dns.go | 107 +++++++++++------------------- internal/dnsforward/stats.go | 25 +++---- internal/dnsforward/stats_test.go | 4 +- internal/querylog/decode.go | 10 +++ internal/querylog/decode_test.go | 6 +- internal/querylog/json.go | 105 +++++++++++++++-------------- internal/querylog/qlog.go | 40 ++++++----- internal/querylog/qlog_test.go | 5 +- internal/querylog/querylog.go | 22 ++++-- internal/querylog/search_test.go | 6 +- openapi/openapi.yaml | 2 + 13 files changed, 176 insertions(+), 161 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e0a0ae7..f86cb6e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,8 @@ and this project adheres to ### Changed +- The DNSSEC check now simply checks against the AD flag in the response + ([#3904]). - Client objects in the configuration file are now sorted ([#3933]). - Responses from cache are now labeled ([#3772]). - Better error message for ED25519 private keys, which are not widely supported @@ -233,6 +235,7 @@ In this release, the schema version has changed from 10 to 12. [#3772]: https://github.com/AdguardTeam/AdGuardHome/issues/3772 [#3815]: https://github.com/AdguardTeam/AdGuardHome/issues/3815 [#3890]: https://github.com/AdguardTeam/AdGuardHome/issues/3890 +[#3904]: https://github.com/AdguardTeam/AdGuardHome/issues/3904 [#3933]: https://github.com/AdguardTeam/AdGuardHome/pull/3933 diff --git a/internal/dnsforward/config.go b/internal/dnsforward/config.go index 0fdbf00b..3834f79d 100644 --- a/internal/dnsforward/config.go +++ b/internal/dnsforward/config.go @@ -118,7 +118,7 @@ type FilteringConfig struct { BogusNXDomain []string `yaml:"bogus_nxdomain"` // transform responses with these IP addresses to NXDOMAIN AAAADisabled bool `yaml:"aaaa_disabled"` // Respond with an empty answer to all AAAA requests - EnableDNSSEC bool `yaml:"enable_dnssec"` // Set DNSSEC flag in outcoming DNS request + 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 diff --git a/internal/dnsforward/dns.go b/internal/dnsforward/dns.go index b6bafa97..20c86c9f 100644 --- a/internal/dnsforward/dns.go +++ b/internal/dnsforward/dns.go @@ -18,33 +18,44 @@ import ( // To transfer information between modules type dnsContext struct { proxyCtx *proxy.DNSContext + // setts are the filtering settings for the client. - setts *filtering.Settings - startTime time.Time - result *filtering.Result + setts *filtering.Settings + + result *filtering.Result // origResp is the response received from upstream. It is set when the // response is modified by filters. origResp *dns.Msg + // unreversedReqIP stores an IP address obtained from PTR request if it // parsed successfully and belongs to one of locally-served IP ranges as per // RFC 6303. unreversedReqIP net.IP + // err is the error returned from a processing function. err error + // clientID is the clientID from DoH, DoQ, or DoT, if provided. clientID string + // origQuestion is the question received from the client. It is set // when the request is modified by rewrites. origQuestion dns.Question + + // startTime is the time at which the processing of the request has started. + startTime time.Time + // protectionEnabled shows if the filtering is enabled, and if the // server's DNS filter is ready. protectionEnabled bool + // responseFromUpstream shows if the response is received from the // upstream servers. responseFromUpstream bool - // origReqDNSSEC shows if the DNSSEC flag in the original request from - // the client is set. - origReqDNSSEC bool + + // responseAD shows if the response had the AD bit set. + responseAD bool + // isLocalClient shows if client's IP address is from locally-served // network. isLocalClient bool @@ -90,7 +101,6 @@ func (s *Server) handleDNSRequest(_ *proxy.Proxy, d *proxy.DNSContext) error { s.processFilteringBeforeRequest, s.processLocalPTR, s.processUpstream, - s.processDNSSECAfterResponse, s.processFilteringAfterResponse, s.ipset.process, s.processQueryLogsAndStats, @@ -514,96 +524,53 @@ func ipStringFromAddr(addr net.Addr) (ipStr string) { } // processUpstream passes request to upstream servers and handles the response. -func (s *Server) processUpstream(ctx *dnsContext) (rc resultCode) { - d := ctx.proxyCtx - if d.Res != nil { - return resultCodeSuccess // response is already set - nothing to do +func (s *Server) processUpstream(dctx *dnsContext) (rc resultCode) { + pctx := dctx.proxyCtx + if pctx.Res != nil { + // The response has already been set. + return resultCodeSuccess } - if d.Addr != nil && s.conf.GetCustomUpstreamByClient != nil { + if pctx.Addr != nil && s.conf.GetCustomUpstreamByClient != nil { // Use the clientID first, since it has a higher priority. - id := stringutil.Coalesce(ctx.clientID, ipStringFromAddr(d.Addr)) + id := stringutil.Coalesce(dctx.clientID, ipStringFromAddr(pctx.Addr)) upsConf, err := s.conf.GetCustomUpstreamByClient(id) if err != nil { log.Error("dns: getting custom upstreams for client %s: %s", id, err) } else if upsConf != nil { log.Debug("dns: using custom upstreams for client %s", id) - d.CustomUpstreamConfig = upsConf + pctx.CustomUpstreamConfig = upsConf } } - req := d.Req + req := pctx.Req + origReqAD := false if s.conf.EnableDNSSEC { - opt := req.IsEdns0() - if opt == nil { - log.Debug("dns: adding OPT record with DNSSEC flag") - req.SetEdns0(4096, true) - } else if !opt.Do() { - opt.SetDo(true) + if req.AuthenticatedData { + origReqAD = true } else { - ctx.origReqDNSSEC = true + req.AuthenticatedData = true } } // Process the request further since it wasn't filtered. - prx := s.proxy() if prx == nil { - ctx.err = srvClosedErr + dctx.err = srvClosedErr return resultCodeError } - if ctx.err = prx.Resolve(d); ctx.err != nil { + if dctx.err = prx.Resolve(pctx); dctx.err != nil { return resultCodeError } - ctx.responseFromUpstream = true + dctx.responseFromUpstream = true + dctx.responseAD = pctx.Res.AuthenticatedData - return resultCodeSuccess -} - -// Process DNSSEC after response from upstream server -func (s *Server) processDNSSECAfterResponse(ctx *dnsContext) (rc resultCode) { - d := ctx.proxyCtx - - // Don't process response if it's not from upstream servers. - if !ctx.responseFromUpstream || !s.conf.EnableDNSSEC { - return resultCodeSuccess - } - - if !ctx.origReqDNSSEC { - optResp := d.Res.IsEdns0() - if optResp != nil && !optResp.Do() { - return resultCodeSuccess - } - - // Remove RRSIG records from response - // because there is no DO flag in the original request from client, - // but we have EnableDNSSEC set, so we have set DO flag ourselves, - // and now we have to clean up the DNS records our client didn't ask for. - - answers := []dns.RR{} - for _, a := range d.Res.Answer { - switch a.(type) { - case *dns.RRSIG: - log.Debug("Removing RRSIG record from response: %v", a) - default: - answers = append(answers, a) - } - } - d.Res.Answer = answers - - answers = []dns.RR{} - for _, a := range d.Res.Ns { - switch a.(type) { - case *dns.RRSIG: - log.Debug("Removing RRSIG record from response: %v", a) - default: - answers = append(answers, a) - } - } - d.Res.Ns = answers + if s.conf.EnableDNSSEC && !origReqAD { + pctx.Req.AuthenticatedData = false + pctx.Res.AuthenticatedData = false } return resultCodeSuccess diff --git a/internal/dnsforward/stats.go b/internal/dnsforward/stats.go index 67af8ff9..d113a5fd 100644 --- a/internal/dnsforward/stats.go +++ b/internal/dnsforward/stats.go @@ -15,9 +15,9 @@ import ( ) // Write Stats data and logs -func (s *Server) processQueryLogsAndStats(ctx *dnsContext) (rc resultCode) { - elapsed := time.Since(ctx.startTime) - pctx := ctx.proxyCtx +func (s *Server) processQueryLogsAndStats(dctx *dnsContext) (rc resultCode) { + elapsed := time.Since(dctx.startTime) + pctx := dctx.proxyCtx shouldLog := true msg := pctx.Req @@ -41,14 +41,15 @@ func (s *Server) processQueryLogsAndStats(ctx *dnsContext) (rc resultCode) { // uninitialized while in use. This can happen after proxy server has been // stopped, but its workers haven't yet exited. if shouldLog && s.queryLog != nil { - p := querylog.AddParams{ - Question: msg, - Answer: pctx.Res, - OrigAnswer: ctx.origResp, - Result: ctx.result, - Elapsed: elapsed, - ClientIP: ip, - ClientID: ctx.clientID, + p := &querylog.AddParams{ + Question: msg, + Answer: pctx.Res, + OrigAnswer: dctx.origResp, + Result: dctx.result, + Elapsed: elapsed, + ClientID: dctx.clientID, + ClientIP: ip, + AuthenticatedData: dctx.responseAD, } switch pctx.Proto { @@ -74,7 +75,7 @@ func (s *Server) processQueryLogsAndStats(ctx *dnsContext) (rc resultCode) { s.queryLog.Add(p) } - s.updateStats(ctx, elapsed, *ctx.result, ip) + s.updateStats(dctx, elapsed, *dctx.result, ip) return resultCodeSuccess } diff --git a/internal/dnsforward/stats_test.go b/internal/dnsforward/stats_test.go index aa98a387..bdd4f4f5 100644 --- a/internal/dnsforward/stats_test.go +++ b/internal/dnsforward/stats_test.go @@ -22,11 +22,11 @@ type testQueryLog struct { // a querylog.QueryLog without actually implementing all methods. querylog.QueryLog - lastParams querylog.AddParams + lastParams *querylog.AddParams } // Add implements the querylog.QueryLog interface for *testQueryLog. -func (l *testQueryLog) Add(p querylog.AddParams) { +func (l *testQueryLog) Add(p *querylog.AddParams) { l.lastParams = p } diff --git a/internal/querylog/decode.go b/internal/querylog/decode.go index 65c8ada1..a9810629 100644 --- a/internal/querylog/decode.go +++ b/internal/querylog/decode.go @@ -119,6 +119,16 @@ var logEntryHandlers = map[string]logEntryHandler{ return nil }, + "AD": func(t json.Token, ent *logEntry) error { + v, ok := t.(bool) + if !ok { + return nil + } + + ent.AuthenticatedData = v + + return nil + }, "Upstream": func(t json.Token, ent *logEntry) error { v, ok := t.(string) if !ok { diff --git a/internal/querylog/decode_test.go b/internal/querylog/decode_test.go index fe4e085e..3d651c81 100644 --- a/internal/querylog/decode_test.go +++ b/internal/querylog/decode_test.go @@ -34,6 +34,7 @@ func TestDecodeLogEntry(t *testing.T) { `"CP":"",` + `"Answer":"` + ansStr + `",` + `"Cached":true,` + + `"AD":true,` + `"Result":{` + `"IsFiltered":true,` + `"Reason":3,` + @@ -81,8 +82,9 @@ func TestDecodeLogEntry(t *testing.T) { }, }, }, - Upstream: "https://some.upstream", - Elapsed: 837429, + Upstream: "https://some.upstream", + Elapsed: 837429, + AuthenticatedData: true, } got := &logEntry{} diff --git a/internal/querylog/json.go b/internal/querylog/json.go index 6f59f1d5..e4bb63aa 100644 --- a/internal/querylog/json.go +++ b/internal/querylog/json.go @@ -40,29 +40,19 @@ func (l *queryLog) entriesToJSON(entries []*logEntry, oldest time.Time) (res job return res } +// entryToJSON converts a log entry's data into an entry for the JSON API. func (l *queryLog) entryToJSON(entry *logEntry, anonFunc aghnet.IPMutFunc) (jsonEntry jobject) { - var msg *dns.Msg - - if len(entry.Answer) > 0 { - msg = new(dns.Msg) - if err := msg.Unpack(entry.Answer); err != nil { - log.Debug("Failed to unpack dns message answer: %s: %s", err, string(entry.Answer)) - msg = nil - } - } - hostname := entry.QHost question := jobject{ "type": entry.QType, "class": entry.QClass, "name": hostname, } - if qhost, err := idna.ToUnicode(hostname); err == nil { - if qhost != hostname && qhost != "" { - question["unicode_name"] = qhost - } - } else { - log.Debug("translating %q into unicode: %s", hostname, err) + + if qhost, err := idna.ToUnicode(hostname); err != nil { + log.Debug("querylog: translating %q into unicode: %s", hostname, err) + } else if qhost != hostname && qhost != "" { + question["unicode_name"] = qhost } eip := netutil.CloneIP(entry.IP) @@ -77,7 +67,9 @@ func (l *queryLog) entryToJSON(entry *logEntry, anonFunc aghnet.IPMutFunc) (json "cached": entry.Cached, "upstream": entry.Upstream, "question": question, + "rules": resultRulesToJSONRules(entry.Result.Rules), } + if eip.Equal(entry.IP) { jsonEntry["client_info"] = entry.client } @@ -86,50 +78,65 @@ func (l *queryLog) entryToJSON(entry *logEntry, anonFunc aghnet.IPMutFunc) (json jsonEntry["client_id"] = entry.ClientID } - if msg != nil { - jsonEntry["status"] = dns.RcodeToString[msg.Rcode] - - opt := msg.IsEdns0() - dnssecOk := false - if opt != nil { - dnssecOk = opt.Do() + if len(entry.Result.Rules) > 0 { + if r := entry.Result.Rules[0]; len(r.Text) > 0 { + jsonEntry["rule"] = r.Text + jsonEntry["filterId"] = r.FilterListID } - - jsonEntry["answer_dnssec"] = dnssecOk - } - - jsonEntry["rules"] = resultRulesToJSONRules(entry.Result.Rules) - - if len(entry.Result.Rules) > 0 && len(entry.Result.Rules[0].Text) > 0 { - jsonEntry["rule"] = entry.Result.Rules[0].Text - jsonEntry["filterId"] = entry.Result.Rules[0].FilterListID } if len(entry.Result.ServiceName) != 0 { jsonEntry["service_name"] = entry.Result.ServiceName } - answers := answerToMap(msg) - if answers != nil { - jsonEntry["answer"] = answers - } - - if len(entry.OrigAnswer) != 0 { - a := new(dns.Msg) - err := a.Unpack(entry.OrigAnswer) - if err == nil { - answers = answerToMap(a) - if answers != nil { - jsonEntry["original_answer"] = answers - } - } else { - log.Debug("Querylog: msg.Unpack(entry.OrigAnswer): %s: %s", err, string(entry.OrigAnswer)) - } - } + l.setMsgData(entry, jsonEntry) + l.setOrigAns(entry, jsonEntry) return jsonEntry } +// setMsgData sets the message data in jsonEntry. +func (l *queryLog) setMsgData(entry *logEntry, jsonEntry jobject) { + if len(entry.Answer) == 0 { + return + } + + msg := &dns.Msg{} + if err := msg.Unpack(entry.Answer); err != nil { + log.Debug("querylog: failed to unpack dns msg answer: %v: %s", entry.Answer, err) + + return + } + + jsonEntry["status"] = dns.RcodeToString[msg.Rcode] + // Old query logs may still keep AD flag value in the message. Try to get + // it from there as well. + jsonEntry["answer_dnssec"] = entry.AuthenticatedData || msg.AuthenticatedData + + if a := answerToMap(msg); a != nil { + jsonEntry["answer"] = a + } +} + +// setOrigAns sets the original answer data in jsonEntry. +func (l *queryLog) setOrigAns(entry *logEntry, jsonEntry jobject) { + if len(entry.OrigAnswer) == 0 { + return + } + + orig := &dns.Msg{} + err := orig.Unpack(entry.OrigAnswer) + if err != nil { + log.Debug("querylog: orig.Unpack(entry.OrigAnswer): %v: %s", entry.OrigAnswer, err) + + return + } + + if a := answerToMap(orig); a != nil { + jsonEntry["original_answer"] = a + } +} + func resultRulesToJSONRules(rules []*filtering.ResultRule) (jsonRules []jobject) { jsonRules = make([]jobject, len(rules)) for i, r := range rules { diff --git a/internal/querylog/qlog.go b/internal/querylog/qlog.go index f04eecb5..1ca84455 100644 --- a/internal/querylog/qlog.go +++ b/internal/querylog/qlog.go @@ -75,7 +75,6 @@ type logEntry struct { // client is the found client information, if any. client *Client - IP net.IP `json:"IP"` // Client IP Time time.Time `json:"T"` QHost string `json:"QH"` @@ -87,11 +86,16 @@ type logEntry struct { Answer []byte `json:",omitempty"` // sometimes empty answers happen like binerdunt.top or rev2.globalrootservers.net OrigAnswer []byte `json:",omitempty"` - Cached bool `json:",omitempty"` Result filtering.Result - Elapsed time.Duration Upstream string `json:",omitempty"` + + IP net.IP `json:"IP"` + + Elapsed time.Duration + + Cached bool `json:",omitempty"` + AuthenticatedData bool `json:"AD,omitempty"` } func (l *queryLog) Start() { @@ -146,14 +150,12 @@ func (l *queryLog) clear() { log.Debug("Query log: cleared") } -func (l *queryLog) Add(params AddParams) { - var err error - +func (l *queryLog) Add(params *AddParams) { if !l.conf.Enabled { return } - err = params.validate() + err := params.validate() if err != nil { log.Error("querylog: adding record: %s, skipping", err) @@ -165,21 +167,27 @@ func (l *queryLog) Add(params AddParams) { } now := time.Now() + q := params.Question.Question[0] entry := logEntry{ - IP: params.ClientIP, Time: now, - Result: *params.Result, - Elapsed: params.Elapsed, - Upstream: params.Upstream, - Cached: params.Cached, + QHost: strings.ToLower(q.Name[:len(q.Name)-1]), + QType: dns.Type(q.Qtype).String(), + QClass: dns.Class(q.Qclass).String(), + ClientID: params.ClientID, ClientProto: params.ClientProto, + + Result: *params.Result, + Upstream: params.Upstream, + + IP: params.ClientIP, + + Elapsed: params.Elapsed, + + Cached: params.Cached, + AuthenticatedData: params.AuthenticatedData, } - q := params.Question.Question[0] - entry.QHost = strings.ToLower(q.Name[:len(q.Name)-1]) // remove the last dot - entry.QType = dns.Type(q.Qtype).String() - entry.QClass = dns.Class(q.Qclass).String() if params.Answer != nil { var a []byte diff --git a/internal/querylog/qlog_test.go b/internal/querylog/qlog_test.go index 1990d08f..4e6b76b6 100644 --- a/internal/querylog/qlog_test.go +++ b/internal/querylog/qlog_test.go @@ -269,6 +269,7 @@ func addEntry(l *queryLog, host string, answerStr, client net.IP) { A: answerStr, }}, } + res := filtering.Result{ IsFiltered: true, Reason: filtering.Rewritten, @@ -278,7 +279,8 @@ func addEntry(l *queryLog, host string, answerStr, client net.IP) { Text: "SomeRule", }}, } - params := AddParams{ + + params := &AddParams{ Question: &q, Answer: &a, OrigAnswer: &a, @@ -286,6 +288,7 @@ func addEntry(l *queryLog, host string, answerStr, client net.IP) { ClientIP: client, Upstream: "upstream", } + l.Add(params) } diff --git a/internal/querylog/querylog.go b/internal/querylog/querylog.go index 0b39c01e..f3de2aaf 100644 --- a/internal/querylog/querylog.go +++ b/internal/querylog/querylog.go @@ -22,7 +22,7 @@ type QueryLog interface { Close() // Add a log entry - Add(params AddParams) + Add(params *AddParams) // WriteDiskConfig - write configuration WriteDiskConfig(c *Config) @@ -76,22 +76,34 @@ type Config struct { // AddParams is the parameters for adding an entry. type AddParams struct { Question *dns.Msg + // Answer is the response which is sent to the client, if any. Answer *dns.Msg + // OrigAnswer is the response from an upstream server. It's only set if the // answer has been modified by filtering. OrigAnswer *dns.Msg - // Cached indicates if the response is served from cache. - Cached bool + // Result is the filtering result (optional). Result *filtering.Result + // Elapsed is the time spent for processing the request. - Elapsed time.Duration + Elapsed time.Duration + ClientID string + ClientIP net.IP + // Upstream is the URL of the upstream DNS server. - Upstream string + Upstream string + ClientProto ClientProto + + // Cached indicates if the response is served from cache. + Cached bool + + // AuthenticatedData shows if the response had the AD bit set. + AuthenticatedData bool } // validate returns an error if the parameters aren't valid. diff --git a/internal/querylog/search_test.go b/internal/querylog/search_test.go index 7d5444ba..dbea24a8 100644 --- a/internal/querylog/search_test.go +++ b/internal/querylog/search_test.go @@ -52,20 +52,20 @@ func TestQueryLog_Search_findClient(t *testing.T) { }}, } - l.Add(AddParams{ + l.Add(&AddParams{ Question: q, ClientID: knownClientID, ClientIP: net.IP{1, 2, 3, 4}, }) // Add the same thing again to test the cache. - l.Add(AddParams{ + l.Add(&AddParams{ Question: q, ClientID: knownClientID, ClientIP: net.IP{1, 2, 3, 4}, }) - l.Add(AddParams{ + l.Add(&AddParams{ Question: q, ClientID: unknownClientID, ClientIP: net.IP{1, 2, 3, 5}, diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index ea5aa05b..ef530663 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -1878,6 +1878,8 @@ Upstream URL starting with tcp://, tls://, https://, or with an IP address. 'answer_dnssec': + 'description': > + If true, the response had the Authenticated Data (AD) flag set. 'type': 'boolean' 'client': 'description': > From 8c5090d89f71e98e770ef0ebbad5ccff69fa80de Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Mon, 13 Dec 2021 21:12:27 +0300 Subject: [PATCH 048/135] Pull request: querylog: opt mem buf Merge in DNS/adguard-home from opt-querylog to master Squashed commit of the following: commit b4f02c3e5059833a696c0a3ddac24295a99b735a Author: Ainar Garipov Date: Mon Dec 13 21:04:54 2021 +0300 querylog: imp docs commit 4d9356a684491814afd2037eccb8791f7f37bac4 Author: Ainar Garipov Date: Mon Dec 13 21:01:40 2021 +0300 querylog: opt mem buf --- internal/querylog/qlog.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/querylog/qlog.go b/internal/querylog/qlog.go index 1ca84455..7dc38824 100644 --- a/internal/querylog/qlog.go +++ b/internal/querylog/qlog.go @@ -220,6 +220,10 @@ func (l *queryLog) Add(params *AddParams) { if !l.conf.FileEnabled { if len(l.buffer) > int(l.conf.MemSize) { // writing to file is disabled - just remove the oldest entry from array + // + // TODO(a.garipov): This should be replaced by a proper ring buffer, + // but it's currently difficult to do that. + l.buffer[0] = nil l.buffer = l.buffer[1:] } } else if !l.flushPending { From 8b0d974e432bc3ed577de8f496a6c2c0a1f5eb16 Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Tue, 14 Dec 2021 13:35:26 +0300 Subject: [PATCH 049/135] Pull request: 3887 upd dnsproxy Merge in DNS/adguard-home from 3887-ecs-length to master Updates #3887. Squashed commit of the following: commit cfd454fd0ace57a8b07931910fc707eaa2602d56 Author: Eugene Burkov Date: Tue Dec 14 13:23:42 2021 +0300 all: upd dnsproxy --- CHANGELOG.md | 3 +++ go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f86cb6e6..60733eab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -128,6 +128,8 @@ In this release, the schema version has changed from 10 to 12. ### Fixed +- The length of the EDNS client subnet option appearing too long for some + upstream servers ([#3887]). - Invalid redirection to the HTTPS web interface after saving enabled encryption settings ([#3558]). - Incomplete propagation of the client's IP anonymization setting to the @@ -234,6 +236,7 @@ In this release, the schema version has changed from 10 to 12. [#3744]: https://github.com/AdguardTeam/AdGuardHome/issues/3744 [#3772]: https://github.com/AdguardTeam/AdGuardHome/issues/3772 [#3815]: https://github.com/AdguardTeam/AdGuardHome/issues/3815 +[#3887]: https://github.com/AdguardTeam/AdGuardHome/issues/3887 [#3890]: https://github.com/AdguardTeam/AdGuardHome/issues/3890 [#3904]: https://github.com/AdguardTeam/AdGuardHome/issues/3904 [#3933]: https://github.com/AdguardTeam/AdGuardHome/pull/3933 diff --git a/go.mod b/go.mod index 9d4593ca..2bdb70d5 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/AdguardTeam/AdGuardHome go 1.16 require ( - github.com/AdguardTeam/dnsproxy v0.39.12 + github.com/AdguardTeam/dnsproxy v0.39.13 github.com/AdguardTeam/golibs v0.10.3 github.com/AdguardTeam/urlfilter v0.15.0 github.com/NYTimes/gziphandler v1.1.1 diff --git a/go.sum b/go.sum index 969ec191..1160e146 100644 --- a/go.sum +++ b/go.sum @@ -9,8 +9,8 @@ dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= github.com/AdguardTeam/dhcp v0.0.0-20210519141215-51808c73c0bf h1:gc042VRSIRSUzZ+Px6xQCRWNJZTaPkomisDfUZmoFNk= github.com/AdguardTeam/dhcp v0.0.0-20210519141215-51808c73c0bf/go.mod h1:TKl4jN3Voofo4UJIicyNhWGp/nlQqQkFxmwIFTvBkKI= -github.com/AdguardTeam/dnsproxy v0.39.12 h1:BxAfdQLGnu0rqhD23K5nNw09sKQeqpT2AkFEE78WOqU= -github.com/AdguardTeam/dnsproxy v0.39.12/go.mod h1:g7zjF1TWpKNeDVh6h3YrjQN8565zsWRd7zo++C/935c= +github.com/AdguardTeam/dnsproxy v0.39.13 h1:7YM5Mr4EpFZ8UO4/4xd6zBG3lZ6AzZO6Xq29Cr4ydOY= +github.com/AdguardTeam/dnsproxy v0.39.13/go.mod h1:g7zjF1TWpKNeDVh6h3YrjQN8565zsWRd7zo++C/935c= 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.9.2/go.mod h1:fCAMwPBJ8S7YMYbTWvYS+eeTLblP5E04IDtNAo7y7IY= From 72a160ac59395cd700d270eaf7234c95c62533ea Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Tue, 14 Dec 2021 18:20:25 +0300 Subject: [PATCH 050/135] Pull request: all: do not apply $denyallow to ip addrs Closes #3175. Squashed commit of the following: commit e80e4610a1ce70787d758c718cc7171570bcdd72 Author: Ainar Garipov Date: Tue Dec 14 18:03:26 2021 +0300 all: imp docs commit 3c73a727e91f7da3d4bbbbf9c019997af4bebd33 Author: Ainar Garipov Date: Tue Dec 14 17:57:01 2021 +0300 all: do not apply $denyallow to ip addrs --- CHANGELOG.md | 3 +++ go.mod | 5 +++-- go.sum | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60733eab..5b81fe94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -128,6 +128,8 @@ In this release, the schema version has changed from 10 to 12. ### Fixed +- Rules with the `$denyallow` modifier applying to IP addresses when they + shouldn't ([#3175]). - The length of the EDNS client subnet option appearing too long for some upstream servers ([#3887]). - Invalid redirection to the HTTPS web interface after saving enabled encryption @@ -197,6 +199,7 @@ In this release, the schema version has changed from 10 to 12. [#3162]: https://github.com/AdguardTeam/AdGuardHome/issues/3162 [#3166]: https://github.com/AdguardTeam/AdGuardHome/issues/3166 [#3172]: https://github.com/AdguardTeam/AdGuardHome/issues/3172 +[#3175]: https://github.com/AdguardTeam/AdGuardHome/issues/3175 [#3184]: https://github.com/AdguardTeam/AdGuardHome/issues/3184 [#3185]: https://github.com/AdguardTeam/AdGuardHome/issues/3185 [#3186]: https://github.com/AdguardTeam/AdGuardHome/issues/3186 diff --git a/go.mod b/go.mod index 2bdb70d5..4e54143a 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.16 require ( github.com/AdguardTeam/dnsproxy v0.39.13 github.com/AdguardTeam/golibs v0.10.3 - github.com/AdguardTeam/urlfilter v0.15.0 + github.com/AdguardTeam/urlfilter v0.15.1 github.com/NYTimes/gziphandler v1.1.1 github.com/ameshkov/dnscrypt/v2 v2.2.2 github.com/digineo/go-ipset/v2 v2.2.1 @@ -22,7 +22,6 @@ require ( github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf github.com/miekg/dns v1.1.43 github.com/satori/go.uuid v1.2.0 - github.com/stretchr/objx v0.1.1 // indirect github.com/stretchr/testify v1.7.0 github.com/ti-mo/netfilter v0.4.0 go.etcd.io/bbolt v1.3.6 @@ -34,5 +33,7 @@ require ( howett.net/plist v0.0.0-20201203080718-1454fab16a06 ) +require github.com/stretchr/objx v0.1.1 // indirect + // TODO(e.burkov): Get rid of the fork in v0.108.0. replace github.com/insomniacslk/dhcp => github.com/AdguardTeam/dhcp v0.0.0-20210519141215-51808c73c0bf diff --git a/go.sum b/go.sum index 1160e146..8e838a0c 100644 --- a/go.sum +++ b/go.sum @@ -17,8 +17,8 @@ github.com/AdguardTeam/golibs v0.9.2/go.mod h1:fCAMwPBJ8S7YMYbTWvYS+eeTLblP5E04I github.com/AdguardTeam/golibs v0.10.3 h1:FBgk17zf35ESVWQKIqEUiqqB2bDaCBC8X5vMU760yB4= github.com/AdguardTeam/golibs v0.10.3/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw= github.com/AdguardTeam/gomitmproxy v0.2.0/go.mod h1:Qdv0Mktnzer5zpdpi5rAwixNJzW2FN91LjKJCkVbYGU= -github.com/AdguardTeam/urlfilter v0.15.0 h1:K3WWZE0K5nPTHe2l+TRXDFpYWJJnvkHdlWidt6NQUTk= -github.com/AdguardTeam/urlfilter v0.15.0/go.mod h1:EwXwrYhowP7bedqmOrmKKmQtpBYFyDNEBFQ+lxdUgQU= +github.com/AdguardTeam/urlfilter v0.15.1 h1:dP6S7J6eFAk8MN4IDpUq2fZoBo8K8fmc6pXpxNIv84M= +github.com/AdguardTeam/urlfilter v0.15.1/go.mod h1:EwXwrYhowP7bedqmOrmKKmQtpBYFyDNEBFQ+lxdUgQU= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= From ed5f827191f3be2b4480f21fd08bc6c794dd5037 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Wed, 15 Dec 2021 14:45:05 +0300 Subject: [PATCH 051/135] Pull request: all: fix edns0 keepalive Merge in DNS/adguard-home from 3778-edns-keepalive to master Squashed commit of the following: commit 00599280d7c5d6b70dc35a4d7d1920a84634758d Author: Ainar Garipov Date: Wed Dec 15 14:29:15 2021 +0300 all: fix edns0 keepalive --- CHANGELOG.md | 4 +++- go.mod | 3 +++ go.sum | 13 ++++++------- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b81fe94..8b0f572a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -128,9 +128,10 @@ 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 shouldn't ([#3175]). -- The length of the EDNS client subnet option appearing too long for some +- The length of the EDNS0 client subnet option appearing too long for some upstream servers ([#3887]). - Invalid redirection to the HTTPS web interface after saving enabled encryption settings ([#3558]). @@ -238,6 +239,7 @@ In this release, the schema version has changed from 10 to 12. [#3707]: https://github.com/AdguardTeam/AdGuardHome/issues/3707 [#3744]: https://github.com/AdguardTeam/AdGuardHome/issues/3744 [#3772]: https://github.com/AdguardTeam/AdGuardHome/issues/3772 +[#3778]: https://github.com/AdguardTeam/AdGuardHome/issues/3778 [#3815]: https://github.com/AdguardTeam/AdGuardHome/issues/3815 [#3887]: https://github.com/AdguardTeam/AdGuardHome/issues/3887 [#3890]: https://github.com/AdguardTeam/AdGuardHome/issues/3890 diff --git a/go.mod b/go.mod index 4e54143a..d6e82e5c 100644 --- a/go.mod +++ b/go.mod @@ -37,3 +37,6 @@ require github.com/stretchr/objx v0.1.1 // indirect // TODO(e.burkov): Get rid of the fork in v0.108.0. replace github.com/insomniacslk/dhcp => github.com/AdguardTeam/dhcp v0.0.0-20210519141215-51808c73c0bf + +// TODO(a.garipov): Return to the main repo once miekg/dns#1317 is merged. +replace github.com/miekg/dns => github.com/ameshkov/dns v1.1.32-0.20211214123418-7a5e0dc5f1b0 diff --git a/go.sum b/go.sum index 8e838a0c..03737110 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/ameshkov/dns v1.1.32-0.20211214123418-7a5e0dc5f1b0 h1:a6ca3WlDG4zvUWqVFpVu48b9NZJ0fUFlRhiZKKkq+aw= +github.com/ameshkov/dns v1.1.32-0.20211214123418-7a5e0dc5f1b0/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/ameshkov/dnscrypt/v2 v2.2.2 h1:lxtS1iSA2EjTOMToSi+2+rwspNA+b/wG5/JpccvE9CU= github.com/ameshkov/dnscrypt/v2 v2.2.2/go.mod h1:+8SbPbVXpxxcUsgGi8eodkqWPo1MyNHxKYC8hDpqLSo= github.com/ameshkov/dnsstamps v1.0.1/go.mod h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaEZZ4gKyIH5A= @@ -168,9 +170,6 @@ github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZ github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf h1:InctQoB89TIkmgIFQeIL4KXNvWc1iebQXdZggqPSwL8= github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= 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 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg= -github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= 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= @@ -273,6 +272,7 @@ golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTk golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 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= @@ -288,7 +288,6 @@ golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn 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= @@ -333,7 +332,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-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -357,11 +355,11 @@ golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7w 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-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-20210630005230-0f9fa26af87c/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-20210909193231-528a39cd75f3 h1:3Ad41xy2WCESpufXwgs7NpDSu+vjxqLt2UFqUV+20bI= golang.org/x/sys v0.0.0-20210909193231-528a39cd75f3/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -384,9 +382,10 @@ 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.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2 h1:BonxutuHCTL0rBDnZlKjpGIQFTjyUVTexFOdWkB6Fg0= +golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 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= From 49eb62aeb59a9364231f8872a2eecd690655a3af Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Wed, 15 Dec 2021 14:55:56 +0300 Subject: [PATCH 052/135] Pull request: client: upd i18n Merge in DNS/adguard-home from 2643-upd-i18n to master Squashed commit of the following: commit 2efafe2b4c5e88b527375aa1f98d92ddd04efaed Merge: 7a9a2f3a ed5f8271 Author: Ainar Garipov Date: Wed Dec 15 14:45:28 2021 +0300 Merge branch 'master' into 2643-upd-i18n commit 7a9a2f3af3a44f66e46c2131d28e07a8204cd3bb Author: Ainar Garipov Date: Wed Dec 15 14:41:03 2021 +0300 client: upd i18n --- client/src/__locales/be.json | 4 +- client/src/__locales/cs.json | 7 +- client/src/__locales/da.json | 7 +- client/src/__locales/de.json | 81 +++++++++++---------- client/src/__locales/es.json | 7 +- client/src/__locales/fa.json | 4 +- client/src/__locales/fi.json | 45 ++++++------ client/src/__locales/fr.json | 22 +++++- client/src/__locales/hr.json | 16 +++- client/src/__locales/hu.json | 4 +- client/src/__locales/id.json | 12 +-- client/src/__locales/it.json | 125 ++++++++++++++++---------------- client/src/__locales/ja.json | 26 +++++-- client/src/__locales/ko.json | 16 +++- client/src/__locales/nl.json | 7 +- client/src/__locales/no.json | 4 +- client/src/__locales/pl.json | 7 +- client/src/__locales/pt-br.json | 7 +- client/src/__locales/pt-pt.json | 7 +- client/src/__locales/ro.json | 6 +- client/src/__locales/ru.json | 27 ++++--- client/src/__locales/sk.json | 7 +- client/src/__locales/sl.json | 7 +- client/src/__locales/sr-cs.json | 4 +- client/src/__locales/sv.json | 5 +- client/src/__locales/th.json | 4 +- client/src/__locales/tr.json | 26 ++++--- client/src/__locales/uk.json | 9 ++- client/src/__locales/vi.json | 4 +- client/src/__locales/zh-cn.json | 26 +++++-- client/src/__locales/zh-hk.json | 1 - client/src/__locales/zh-tw.json | 9 ++- 32 files changed, 325 insertions(+), 218 deletions(-) diff --git a/client/src/__locales/be.json b/client/src/__locales/be.json index a5d45489..33ceba4f 100644 --- a/client/src/__locales/be.json +++ b/client/src/__locales/be.json @@ -47,7 +47,6 @@ "form_error_server_name": "Няслушнае імя сервера", "form_error_subnet": "Падсетка «{{cidr}}» не ўтрымвае IP-адраса «{{ip}}»", "form_error_positive": "Павінна быць больш 0", - "form_error_negative": "Павінна быць не менш 0", "out_of_range_error": "Павінна быць па-за дыяпазонам «{{start}}»-«{{end}}»", "lower_range_start_error": "Павінна быць менш за пачатак дыяпазону", "greater_range_start_error": "Павінна быць больш за пачатак дыяпазону", @@ -624,5 +623,6 @@ "filter_allowlist": "УВАГА: Гэта дзеянне таксама выключыць правіла «{{disallowed_rule}}» са спіса дазволеных кліентаў.", "last_rule_in_allowlist": "Няможна заблакаваць гэтага кліента, бо вынятак правіла «{{disallowed_rule}}» АДКЛЮЧЫЦЬ рэжым белага спіса.", "experimental": "Эксперыментальны", - "use_saved_key": "Скарыстаць захаваны раней ключ" + "use_saved_key": "Скарыстаць захаваны раней ключ", + "parental_control": "Бацькоўскі кантроль" } diff --git a/client/src/__locales/cs.json b/client/src/__locales/cs.json index f66c190e..7912163b 100644 --- a/client/src/__locales/cs.json +++ b/client/src/__locales/cs.json @@ -47,7 +47,6 @@ "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", - "form_error_negative": "Musí být rovno nebo 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", @@ -201,6 +200,7 @@ "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ů", "examples_title": "Příklady", "example_meaning_filter_block": "zablokovat přístup k doméně example.org a všem jejím subdoménám", "example_meaning_filter_whitelist": "odblokovat přístup k doméně example.org a všem jejím subdoménám", @@ -624,5 +624,8 @@ "filter_allowlist": "VAROVÁNÍ: Tato akce také vyloučí pravidlo \"{{disallowed_rule}}\" ze seznamu povolených klientů.", "last_rule_in_allowlist": "Nelze zakázat tohoto klienta, protože vyloučení pravidla \"{{disallowed_rule}}\" ZRUŠÍ seznam \"Povolených klientů\".", "experimental": "Experimentální", - "use_saved_key": "Použít dříve uložený klíče" + "use_saved_key": "Použít dříve uložený klíče", + "parental_control": "Rodičovská kontrola", + "safe_browsing": "Bezpečné prohlížení", + "served_from_cache": "{{value}} (převzato z mezipaměti)" } diff --git a/client/src/__locales/da.json b/client/src/__locales/da.json index 0825d84f..0d254144 100644 --- a/client/src/__locales/da.json +++ b/client/src/__locales/da.json @@ -47,7 +47,6 @@ "form_error_server_name": "Ugyldigt servernavn", "form_error_subnet": "Subnet \"{{cidr}}\" indeholder ikke IP-adressen \"{{ip}}\"", "form_error_positive": "Skal være større end 0", - "form_error_negative": "Skal være lig med 0 eller større", "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", @@ -201,6 +200,7 @@ "form_error_url_or_path_format": "Ugyldig URL eller absolut listesti", "custom_filter_rules": "Tilpassede filtreringsregler", "custom_filter_rules_hint": "Angiv én regel pr. linje. Du kan bruge enten adblockingregler eller værtsfilsyntaks.", + "system_host_files": "System hosts-filer", "examples_title": "Eksempler", "example_meaning_filter_block": "blokér adgang til example.org-domænet samt alle underdomæner", "example_meaning_filter_whitelist": "afblokér adgang til example.ord-domænet samt alle underdomæner", @@ -624,5 +624,8 @@ "filter_allowlist": "ADVARSEL: Denne handling udelukker også reglen \"{{disallowed_rule}}\" fra listen over tilladte klienter.", "last_rule_in_allowlist": "Kan ikke afvise denne klient, da udelukkelse af reglen \"{{disallowed_rule}}\" DEAKTIVERER listen \"Tilladte klienter\".", "experimental": "Eksperimentel", - "use_saved_key": "Brug den tidligere gemte nøgle" + "use_saved_key": "Brug den tidligere gemte nøgle", + "parental_control": "Forældrekontrol", + "safe_browsing": "Sikker browsing", + "served_from_cache": "{{value}} (leveret fra cache)" } diff --git a/client/src/__locales/de.json b/client/src/__locales/de.json index 45e416dd..cffa94a4 100644 --- a/client/src/__locales/de.json +++ b/client/src/__locales/de.json @@ -2,21 +2,21 @@ "client_settings": "Client-Einstellungen", "example_upstream_reserved": "Sie können DNS-Upstream <0>für bestimmte Domain(s) angeben", "example_upstream_comment": "Sie können den Kommentar angeben", - "upstream_parallel": "Parallele Abfragen verwenden, um die Lösung zu beschleunigen, indem Sie alle Upstream-Server gleichzeitig abfragen", - "parallel_requests": "Parallele Abfragen", + "upstream_parallel": "Parallele Abfragen verwenden, um das Auflösen zu beschleunigen, indem alle Upstream-Server gleichzeitig abgefragt werden.", + "parallel_requests": "Paralleles Abfragen", "load_balancing": "Lastverteilung", "load_balancing_desc": "Einen Server nach dem anderen abfragen. AdGuard Home verwendet den gewichteten Zufallsalgorithmus, um den Server so auszuwählen, dass der schnellste Server häufiger verwendet wird.", "bootstrap_dns": "Bootstrap DNS-Server starten", "bootstrap_dns_desc": "Bootstrap-DNS-Server werden verwendet, um IP-Adressen der DoH/DoT-Resolver aufzulösen, die Sie als Upstreams angeben.", - "local_ptr_title": "Eigene DNS-Server", - "local_ptr_desc": "Die DNS-Server, die AdGuard Home für lokale PTR-Abfragen verwendet. Diese Server werden verwendet, um die Hostnamen von Clients mit privaten IP-Adressen, z. B. „192.168.12.34“, mithilfe von rDNS aufzulösen. Wenn nicht festgelegt, verwendet AdGuard Home die Adressen der standardmäßigen DNS-Resolver Ihres Betriebssystems, mit Ausnahme der Adressen von AdGuard Home selbst.", + "local_ptr_title": "Private inverse DNS-Server", + "local_ptr_desc": "Die DNS-Server, die AdGuard Home für lokale PTR-Abfragen verwendet. Diese Server werden verwendet, um die Hostnamen von Clients mit privaten IP-Adressen, z. B. „192.168.12.34“, per inverse DNS-Anfragen aufzulösen. Wenn nicht festgelegt, verwendet AdGuard Home die Adressen der Standard-DNS-Auflöser Ihres Betriebssystems mit Ausnahme der Adressen von AdGuard Home selbst.", "local_ptr_default_resolver": "Standardmäßig verwendet AdGuard Home die folgenden Invers-DNS-Resolver: {{ip}}.", "local_ptr_no_default_resolver": "AdGuard Home konnte keine geeigneten privaten Invers-DNS-Resolver für dieses System ermitteln.", "local_ptr_placeholder": "Eine Serveradresse pro Zeile eingeben", "resolve_clients_title": "Hostnamenauflösung der Clients aktivieren", - "resolve_clients_desc": "Lösen Sie die IP-Adressen der Clients umgekehrt in ihre Hostnamen auf, indem Sie PTR-Anfragen an entsprechende Resolver senden (private DNS-Server für lokale Clients, Upstream-Server für Clients mit öffentlichen IP-Adressen).", + "resolve_clients_desc": "Inverses Auflösen der IP-Adressen der Clients in ihre Hostnamen durch Senden von PTR-Anfragen an die entsprechenden Resolver (private DNS-Server für lokale Kunden, Upstream-Server für Kunden mit öffentlichen IP-Adressen).", "use_private_ptr_resolvers_title": "Private Reverse-DNS-Resolver verwenden", - "use_private_ptr_resolvers_desc": "Führen Sie mithilfe dieser Upstream-Server Reverse DNS-Lookups für lokal bereitgestellte Adressen durch. Wenn diese Option deaktiviert ist, antwortet AdGuard Home mit NXDOMAIN auf alle derartigen PTR-Anfragen mit Ausnahme von Clients, die von DHCP, /etc/hosts usw. bekannt sind.", + "use_private_ptr_resolvers_desc": "Führt inverse DNS-Abfragen für lokal bereitgestellte Adressen mit diesen Upstream-Servern durch. Wenn deaktiviert, antwortet AdGuard Home mit NXDOMAIN auf alle solchen PTR-Anfragen, außer für Clients, die über DHCP, /etc/hosts usw. bekannt sind.", "check_dhcp_servers": "Auf DHCP-Server prüfen", "save_config": "Konfiguration speichern", "enabled_dhcp": "DHCP-Server aktiviert", @@ -27,11 +27,11 @@ "dhcp_description": "Wenn Ihr Router keine DHCP-Einstellungen bietet, können Sie den integrierten DHCP-Server von AdGuard verwenden.", "dhcp_enable": "DHCP-Server aktivieren", "dhcp_disable": "DHCP-Server deaktivieren", - "dhcp_not_found": "Keine aktiven DHCP-Server im Netzwerk gefunden. Es ist sicher, den integrierten DHCP-Server zu aktivieren.", - "dhcp_found": "Einige aktive DHCP-Server im Netzwerk gefunden. Es ist nicht sicher, den integrierten DHCP-Server zu aktivieren.", - "dhcp_leases": "DHCP-Leasingverträge", - "dhcp_static_leases": "DHCP statische Leases", - "dhcp_leases_not_found": "Keine DHCP-Leasingverträge gefunden\n", + "dhcp_not_found": "Es ist sicherer, den integrierten DHCP-Server zu aktivieren, da AdGuard Home keine aktiven DHCP-Server im Netzwerk vorgefunden hat. Sie sollten dies jedoch noch einmal manuell überprüfen, da die automatische Überprüfung derzeit keine 100%ige Garantie bietet.", + "dhcp_found": "Es wurde ein aktiver DHCP-Server im Netzwerk gefunden. Es wird nicht empfohlen, den integrierten DHCP-Server zu aktivieren.", + "dhcp_leases": "DHCP-Zuweisungen", + "dhcp_static_leases": "DHCP statische Zuweisungen", + "dhcp_leases_not_found": "Keine DHCP-Zuweisungen gefunden", "dhcp_config_saved": "DHCP-Konfiguration erfolgreich gespeichert", "dhcp_ipv4_settings": "DHCP-IPv4-Einstellungen", "dhcp_ipv6_settings": "DHCP-IPv6-Einstellungen", @@ -42,12 +42,11 @@ "form_error_ip4_gateway_format": "Ungültiges Gateway-IPv4-Adresse", "form_error_ip6_format": "Ungültige IPv6-Adresse", "form_error_ip_format": "Ungültige IP-Adresse", - "form_error_mac_format": "Ungültiges Format der MAC-Adresse", + "form_error_mac_format": "Ungültige MAC-Adresse", "form_error_client_id_format": "Ungültiges Client-ID", "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.", - "form_error_negative": "Muss gleich oder größer als 0 (Null) sein", + "form_error_positive": "Muss größer als 0 (Null) 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", @@ -57,28 +56,28 @@ "dhcp_form_gateway_input": "Gateway-IP", "dhcp_form_subnet_input": "Subnetz-Maske", "dhcp_form_range_title": "Bereich von IP-Adressen", - "dhcp_form_range_start": "Bereichsanfang", + "dhcp_form_range_start": "Bereichsbeginn", "dhcp_form_range_end": "Bereichsende", - "dhcp_form_lease_title": "DHCP-Leasingdauer (in Sekunden)", - "dhcp_form_lease_input": "Leasingdauer", + "dhcp_form_lease_title": "DHCP-Zuweisungs-Dauer (in Sekunden)", + "dhcp_form_lease_input": "Dauer der Zuweisung", "dhcp_interface_select": "DHCP-Benutzeroberfläche auswählen", "dhcp_hardware_address": "Hardware-Adresse", "dhcp_ip_addresses": "IP-Adressen", "ip": "IP", "dhcp_table_hostname": "Hostname", - "dhcp_table_expires": "Läuft ab", + "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": "Es konnte nicht ermittelt werden, ob es einen anderen DHCP-Server im Netzwerk gibt.", + "dhcp_error": "AdGuard Home konnte nicht ermitteln, ob es einen anderen aktiven DHCP-Server im Netzwerk gibt.", "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": "Statischer Lease „{{key}}“ erfolgreich hinzugefügt", - "dhcp_lease_deleted": "Statischer Lease „{{key}}“ erfolgreich entfernt", - "dhcp_new_static_lease": "Neuer statischer Lease", - "dhcp_static_leases_not_found": "Keine statischen DHCP-Leases gefunden", - "dhcp_add_static_lease": "Statischen Lease hinzufügen", - "dhcp_reset_leases": "Setzen Sie alle Leases zurück", - "dhcp_reset_leases_confirm": "Möchten Sie wirklich alle Leases zurücksetzen?", - "dhcp_reset_leases_success": "DHCP-Leases erfolgreich zurückgesetzt", + "dhcp_lease_added": "Statischer Zuweisung „{{key}}“ erfolgreich hinzugefügt", + "dhcp_lease_deleted": "Statische Zuweisung „{{key}}“ erfolgreich entfernt", + "dhcp_new_static_lease": "Neuer statischer Zuweisung", + "dhcp_static_leases_not_found": "Keine statischen DHCP-Zuweisungen gefunden", + "dhcp_add_static_lease": "Statische Zuweisung hinzufügen", + "dhcp_reset_leases": "Alle Zuweisungen zurücksetzen", + "dhcp_reset_leases_confirm": "Möchten Sie wirklich alle Zuweisungen zurücksetzen?", + "dhcp_reset_leases_success": "DHCP-Zuweisungen erfolgreich zurückgesetzt", "dhcp_reset": "Möchten Sie die DHCP-Konfiguration wirklich zurücksetzen?", "country": "Land", "city": "Stadt", @@ -104,7 +103,7 @@ "on": "AN", "off": "AUS", "copyright": "Urheberrecht", - "homepage": "Homepage", + "homepage": "Startseite", "report_an_issue": "Fehlerbericht senden", "privacy_policy": "Datenschutzerklärung", "enable_protection": "Schutz aktivieren", @@ -114,8 +113,8 @@ "refresh_statics": "Statistiken aktualisieren", "dns_query": "DNS-Anfragen", "blocked_by": "<0>Durch Filter gesperrt", - "stats_malware_phishing": "Gesperrte Schädliche/Phishing-Webseiten", - "stats_adult": "Gesperrte jugendgefährdende Webseiten", + "stats_malware_phishing": "Gesperrte Schädliche/Phishing-Websites", + "stats_adult": "Gesperrte jugendgefährdende Websites", "stats_query_domain": "Am häufigsten angefragte Domains", "for_last_24_hours": "für die letzten 24 Stunden", "for_last_days": "am letzten {{count}} Tag", @@ -133,7 +132,7 @@ "number_of_dns_query_24_hours": "Anzahl der in den letzten 24 Stunden durchgeführten DNS-Anfragen", "number_of_dns_query_blocked_24_hours": "Anzahl der durch Werbefilter und Host-Sperrlisten abgelehnte DNS-Anfragen", "number_of_dns_query_blocked_24_hours_by_sec": "Anzahl der durch das AdGuard-Modul „Internetsicherheit“ gesperrten DNS-Anfragen", - "number_of_dns_query_blocked_24_hours_adult": "Anzahl der gesperrten Webseiten mit jugendgefährdenden Inhalten", + "number_of_dns_query_blocked_24_hours_adult": "Anzahl der gesperrten Websites mit jugendgefährdenden Inhalten", "enforced_save_search": "SafeSearch erzwungen", "number_of_dns_query_to_safe_search": "Anzahl der DNS-Anfragen bei denen SafeSearch für Suchanfragen erzwungen wurde", "average_processing_time": "Durchschnittliche Bearbeitungsdauer", @@ -173,7 +172,7 @@ "enabled_table_header": "Aktiviert", "name_table_header": "Name", "list_url_table_header": "Adressliste", - "rules_count_table_header": "Anzahl Regeln", + "rules_count_table_header": "Regeln total", "last_time_updated_table_header": "Letztes Update", "actions_table_header": "Aktionen", "request_table_header": "Anfrage", @@ -201,6 +200,7 @@ "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.", + "system_host_files": "Hosts-Datei des Systems", "examples_title": "Beispiele", "example_meaning_filter_block": "blockiert den Zugang zur Domain example.org und all ihren Subdomains", "example_meaning_filter_whitelist": "entblockt den Zugang zur Domain example.org und all ihren Subdomains", @@ -208,7 +208,7 @@ "example_comment": "! Hier steht ein Kommentar", "example_comment_meaning": "Nur ein Kommentar", "example_comment_hash": "# Auch ein Kommentar", - "example_regex_meaning": "Zugriff auf die Domains sperren, die dem <0>angegebenen regulärem Ausdruck entsprechen", + "example_regex_meaning": "Zugriff auf die Domains sperren, die dem <0>angegebenen regulären Ausdruck entsprechen", "example_upstream_regular": "regulärer DNS (über UDP)", "example_upstream_dot": "verschlüsseltes <0>DNS-over-TLS", "example_upstream_doh": "verschlüsseltes <0>DNS-over-HTTPS", @@ -323,7 +323,7 @@ "install_step": "Schritt", "install_devices_title": "Konfigurieren Sie Ihre Geräte", "install_devices_desc": "Um AdGuard Home nutzen zu können, müssen Sie Ihre Geräte so konfigurieren, dass sie es auch wirklich nutzen.", - "install_submit_title": "Herzlichen Glückwunsch!", + "install_submit_title": "Gratulation!", "install_submit_desc": "Die Einrichtung ist abgeschlossen und Sie können mit der Verwendung von AdGuard Home beginnen.", "install_devices_router": "Router", "install_devices_router_desc": "Diese Einrichtung deckt automatisch alle an Ihren Heimrouter angeschlossenen Geräte ab, und Sie müssen nicht jedes einzelne davon manuell konfigurieren.", @@ -455,12 +455,12 @@ "setup_dns_privacy_android_3": "„<0>Intra“ fügt <1>DNS-over-HTTPS-Unterstützung zu Android hinzu.", "setup_dns_privacy_ios_1": "„<0>DNSCloak“ unterstützt <1>DNS-over-HTTPS, aber um es so zu konfigurieren, dass es Ihren eigenen Server verwendet, müssen Sie einen <2>DNS-Stempel dafür generieren.", "setup_dns_privacy_ios_2": "<0>AdGuard für iOS unterstützt die Einrichtung von <1>DNS-over-HTTTPS und <1>DNS-over-TLS.", - "setup_dns_privacy_other_title": "Weitere Umsetzungen", + "setup_dns_privacy_other_title": "Weitere Implementierungen", "setup_dns_privacy_other_1": "AdGuard Home selbst kann ein sicherer DNS-Client auf jeder Plattform sein.", "setup_dns_privacy_other_2": "<0>dnsproxy unterstützt alle bekannten sicheren DNS-Protokolle.", "setup_dns_privacy_other_3": "<0>dnscrypt-proxy unterstützt <1>DNS-over-HTTPS.", "setup_dns_privacy_other_4": "<0>Mozilla Firefox unterstützt <1>DNS-over-HTTPS.", - "setup_dns_privacy_other_5": "Weitere Umsetzungen finden Sie <0>hier und <1>hier.", + "setup_dns_privacy_other_5": "Weitere Implementierungen finden Sie <0>hier und <1>hier.", "setup_dns_privacy_ioc_mac": "Konfiguration für iOS und macOS", "setup_dns_notice": "Um <1>DNS-over-HTTTPS oder <1>DNS-over-TLS verwenden zu können, müssen Sie in den AdGuard Home Einstellungen die <0>Verschlüsselung konfigurieren.", "rewrite_added": "DNS-Umschreibung für „{{key}}“ erfolgreich hinzugefügt", @@ -587,8 +587,8 @@ "show_blocked_responses": "Gesperrt", "show_whitelisted_responses": "Auf der Positivliste", "show_processed_responses": "Verarbeitet", - "blocked_safebrowsing": "Durch Internetsicherheit gesperrt", - "blocked_adult_websites": "Gesperrte jugendgefährdende Webseiten", + "blocked_safebrowsing": "Gesperrt durch Internetsicherheit", + "blocked_adult_websites": "Gesperrte jugendgefährdende Websites", "blocked_threats": "Gesperrte Bedrohungen", "allowed": "Zugelassen", "filtered": "Gefiltert", @@ -624,5 +624,8 @@ "filter_allowlist": "Warnhinweis: Durch diese Aktion wird außerdem die Regel „{{disallowed_rule}}“ aus der Liste der zugelassenen Clients ausgeschlossen.", "last_rule_in_allowlist": "Dieser Client kann nicht gesperrt werden, da das Ausschließen der Regel „{{disallowed_rule}}“ die Liste „Zugelassene Clients“ deaktivieren würde.", "experimental": "Experimentell", - "use_saved_key": "Zuvor gespeicherten Schlüssel verwenden" + "use_saved_key": "Zuvor gespeicherten Schlüssel verwenden", + "parental_control": "Kindersicherung", + "safe_browsing": "Sicheres Surfen", + "served_from_cache": "{{value}} (aus dem Zwischenspeicher abgerufen)" } diff --git a/client/src/__locales/es.json b/client/src/__locales/es.json index ea031592..4a70020a 100644 --- a/client/src/__locales/es.json +++ b/client/src/__locales/es.json @@ -47,7 +47,6 @@ "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", - "form_error_negative": "Debe ser igual o 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", @@ -201,6 +200,7 @@ "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", "examples_title": "Ejemplos", "example_meaning_filter_block": "bloquea el acceso al dominio ejemplo.org y a todos sus subdominios", "example_meaning_filter_whitelist": "desbloquea el acceso al dominio ejemplo.org y a todos sus subdominios", @@ -624,5 +624,8 @@ "filter_allowlist": "ADVERTENCIA: Esta acción también excluirá la regla \"{{disallowed_rule}}\" de la lista de clientes permitidos.", "last_rule_in_allowlist": "No se puede desautorizar a este cliente porque al excluir la regla \"{{disallowed_rule}}\" DESHABILITARÁ la lista de \"Clientes permitidos\".", "experimental": "experimental", - "use_saved_key": "Usar la clave guardada previamente" + "use_saved_key": "Usar la clave guardada previamente", + "parental_control": "Control parental", + "safe_browsing": "Navegación segura", + "served_from_cache": "{{value}} (servido desde la caché)" } diff --git a/client/src/__locales/fa.json b/client/src/__locales/fa.json index 20ccaf83..2a0177f7 100644 --- a/client/src/__locales/fa.json +++ b/client/src/__locales/fa.json @@ -21,7 +21,6 @@ "form_error_mac_format": "فرمت مَک نامعتبر است", "form_error_client_id_format": "فرمت شناسه کلاینت نامعتبر است", "form_error_positive": "باید بزرگتر از 0 باشد", - "form_error_negative": "باید برابر با 0 یا بزرگتر باشد", "dhcp_form_gateway_input": "آی پی دروازه", "dhcp_form_subnet_input": "ماسک زیر شبکه", "dhcp_form_range_title": "دامنه آدرس های آی پی", @@ -489,5 +488,6 @@ "milliseconds_abbreviation": "هـ ثـ", "filter_category_general": "General", "filter_category_security": "مسدودسازی بدافزار و فیشینگ", - "filter_category_other": "ساير" + "filter_category_other": "ساير", + "parental_control": "نظارت والدین" } diff --git a/client/src/__locales/fi.json b/client/src/__locales/fi.json index d6f9ce5b..a9d8eda9 100644 --- a/client/src/__locales/fi.json +++ b/client/src/__locales/fi.json @@ -47,7 +47,6 @@ "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", - "form_error_negative": "Oltava yhtä suuri tai 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", @@ -104,7 +103,7 @@ "on": "Käytössä", "off": "Ei käytössä", "copyright": "Tekijänoikeus", - "homepage": "Kotisivu", + "homepage": "Verkkosivusto", "report_an_issue": "Ilmoita ongelmasta", "privacy_policy": "Tietosuojakäytäntö", "enable_protection": "Ota suojaus käyttöön", @@ -141,9 +140,9 @@ "block_domain_use_filters_and_hosts": "Estä verkkotunnuksia suodattimilla ja hosts-tiedostoilla", "filters_block_toggle_hint": "Voit määrittää estosääntöjä suodatinasetuksissa.", "use_adguard_browsing_sec": "Käytä AdGuardin turvallisen selauksen palvelua", - "use_adguard_browsing_sec_hint": "AdGuard Home tarkistaa onko verkkotunnus turvallisen selauksen verkkopalvelun estämä. Se käyttää tarkastukseen yksityisyyspainotteista rajapintaa: palvelimelle lähetetään vain pieni osa verkkotunnuksen SHA256-hajautusarvosta.", + "use_adguard_browsing_sec_hint": "AdGuard Home tarkistaa onko verkkotunnus turvallisen selauksen verkkopalvelun estämä. Se käyttää tarkastukseen tietosuojapainotteista rajapintaa: palvelimelle lähetetään vain pieni osa verkkotunnuksen SHA256-hajautusarvosta.", "use_adguard_parental": "Käytä AdGuardin lapsilukko-palvelua", - "use_adguard_parental_hint": "AdGuard Home tarkistaa, sisältääkö verkkotunnus aikuisille tarkoitettua sisältöä. Se käyttää samaa yksityisyyspainotteista rajapintaa, kuin turvallisen selauksen palvelu.", + "use_adguard_parental_hint": "AdGuard Home tarkistaa, sisältääkö verkkotunnus aikuisille tarkoitettua sisältöä. Se käyttää samaa tietosuojapainotteista rajapintaa, kuin turvallisen selauksen palvelu.", "enforce_safe_search": "Pakota turvallinen haku", "enforce_save_search_hint": "AdGuard Home voi pakottaa turvallisen haun käyttöön seuraavissa hakukoneissa: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.", "no_servers_specified": "Palvelimia ei ole määritetty", @@ -201,6 +200,7 @@ "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", "examples_title": "Esimerkkejä", "example_meaning_filter_block": "estä pääsy verkkotunnukseen example.org ja sen aliverkkotunnuksiin", "example_meaning_filter_whitelist": "salli pääsy verkkotunnukseen example.org ja sen aliverkkotunnuksiin", @@ -334,27 +334,27 @@ "install_devices_router_list_4": "Joissakin reitittimissä ei ole mahdollista määrittää omaa DNS-palvelinta. Tällöin AdGuard Homen määritys <0>DHCP-palvelimeksi voi auttaa. Muutoin on selvitettävä reitittimen käyttöohjeesta, miten sen DNS-palvelinasetukset muutetaan.", "install_devices_windows_list_1": "Avaa \"Ohjauspaneeli\" Käynnistä-valikon tai Windowsin haun kautta.", "install_devices_windows_list_2": "Avaa \"Verkko ja Internet\" -ryhmä ja sitten \"Verkko ja jakamiskeskus\".", - "install_devices_windows_list_3": "Etsi ikkunan vasemmasta laidasta \"Muuta sovittimen asetuksia\" ja klikkaa sitä.", - "install_devices_windows_list_4": "Valitse aktiivinen yhteytesi, klikkaa sitä hiiren kakkospainikkeella ja valitse valikosta \"Ominaisuudet\".", - "install_devices_windows_list_5": "Etsi listasta \"Internet protokolla versio 4 (TCP/IP)\", valitse se ja klikkaa jälleen \"Ominaisuudet\".", + "install_devices_windows_list_3": "Etsi ikkunan vasemmasta laidasta \"Muuta sovittimen asetuksia\" ja paina sitä.", + "install_devices_windows_list_4": "Valitse aktiivinen yhteytesi, paina sitä hiiren kakkospainikkeella ja valitse valikosta \"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_6": "Valitse \"Käytä seuraavia DNS-palvelinten osoitteita\" ja syötä AdGuard Home -palvelimesi osoitteet.", "install_devices_macos_list_1": "Avaa Omenavalikko ja valitse \"Järjestelmäasetukset \".", - "install_devices_macos_list_2": "Klikkaa \"Verkko\".", - "install_devices_macos_list_3": "Valitse listan ensimmäinen yhteys ja klikkaa \"Lisävalinnat\".", + "install_devices_macos_list_2": "Paina \"Verkko\".", + "install_devices_macos_list_3": "Valitse listan ensimmäinen yhteys ja paina \"Lisävalinnat\".", "install_devices_macos_list_4": "Valitse DNS-välilehti ja syötä AdGuard Home -palvelimesi osoitteet.", - "install_devices_android_list_1": "Napauta \"Asetukset\" -kuvaketta Android-laitteesi aloitusnäytöstä tai sovellusvalikosta.", + "install_devices_android_list_1": "Napauta Android-laitteesi aloitusnäytöstä tai sovellusvalikosta \"Asetukset\".", "install_devices_android_list_2": "Napauta \"Yhteydet\" ja sitten \"Wi-Fi\". Näytetään kaikki käytettävissä olevat langattomat verkot (mobiiliverkolle ei ole mahdollista määrittää omaa DNS-palvelinta).", "install_devices_android_list_3": "Napauta yhdistetyn verkon vieressä olevaa asetuskuvaketta tai paina verkkoa pitkään ja valitse \"Muokkaa verkkoa\".", "install_devices_android_list_4": "Saatat joutua napauttamaan \"Lisäasetukset\" nähdäksesi lisää valintoja. Muuttaaksesi DNS-asetuksia, on \"IP-asetukset\" -kohdan \"DHCP\" -valinta vaihdettava \"Staattinen\" -valintaan.", "install_devices_android_list_5": "Syötä \"DNS 1\" ja \"DNS 2\" -kenttiin AdGuard Home -palvelimesi osoitteet.", - "install_devices_ios_list_1": "Valitse aloitusnäytöstä \"Asetukset\".", + "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_4": "Syötä \"DNS\" -kenttään AdGuard Home -palvelimesi osoitteet.", "get_started": "Aloita", "next": "Seuraava", "open_dashboard": "Avaa hallintapaneeli", - "install_saved": "Tallennettiin", + "install_saved": "Tallenus onnistui", "encryption_title": "Salaus", "encryption_desc": "Salaus (HTTPS/TLS) DNS-palvelimelle ja selaimen hallintasivulle", "encryption_config_saved": "Salausasetukset tallennettiin", @@ -393,7 +393,7 @@ "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>Klikkaa tästä saadaksesi lisätietoja.", + "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", @@ -445,7 +445,7 @@ "updates_checked": "Päivitykset tarkastettiin", "updates_version_equal": "AdGuard Home on ajan tasalla", "check_updates_now": "Tarkista päivitykset nyt", - "dns_privacy": "DNS-yksityisyys", + "dns_privacy": "DNS-tietosuoja", "setup_dns_privacy_1": "<0>DNS-over-TLS: Käytä merkkijonoa <1>{{address}}.", "setup_dns_privacy_2": "<0>DNS-over-HTTPS: Käytä merkkijonoa <1>{{address}}.", "setup_dns_privacy_3": "<0>Tässä on lista ohjelmistoista, joita voit käyttää.", @@ -459,7 +459,7 @@ "setup_dns_privacy_other_1": "AdGuard Home voi itse olla turvallinen DNS-päätelaite millä tahansa alustalla.", "setup_dns_privacy_other_2": "<0>dnsproxy tukee kaikkia tunnettuja turvallisia DNS-protokollia.", "setup_dns_privacy_other_3": "<0>dnscrypt-proxy tukee <1>DNS-over-HTTPS -protokollaa.", - "setup_dns_privacy_other_4": "<0>Mozilla Firefox tukee <1>DNS-over-HTTPS -toteutusta.", + "setup_dns_privacy_other_4": "<0>Mozilla Firefox tukee <1>DNS-over-HTTPS-toteutusta.", "setup_dns_privacy_other_5": "Löydät lisää toteutuksia <0>täältä ja <1>täältä.", "setup_dns_privacy_ioc_mac": "iOS ja macOS -asetukset", "setup_dns_notice": "<1>DNS-over-HTTPS tai <1>DNS-over-TLS -toteutuksia varten, on AdGuard Homen <0>Salausasetukset määritettävä.", @@ -547,7 +547,7 @@ "disable_ipv6_desc": "Hylkää kaikki IPv6-osoitteiden DNS-pyynnöt (tyyppi AAAA).", "fastest_addr": "Nopein IP-osoite", "fastest_addr_desc": "Lähetä pyynnöt kaikille DNS-palvelimille ja valitse vastauksista nopein IP-osoite. Tämä parantaa yleistä liitettävyyttä, joskin hidastaa DNS-pyyntöjä, koska AdGuard Homen on odotettava kaikkien DNS-palvelinten vastauksia.", - "autofix_warning_text": "Jos valitset \"Korjaa\", AdGuard Home määrittää järjestelmäsi käyttämään AdGuard Homen DNS-palvelinta.", + "autofix_warning_text": "Jos painat \"Korjaa\", AdGuard Home määrittää järjestelmäsi käyttämään AdGuard Homen DNS-palvelinta.", "autofix_warning_list": "Suorittaa toiminnot: <0>Poistaa käytöstä järjestelmän DNSStubListener-palvelun <0>Määrittää DNS-palvelimen osoitteeksi 127.0.0.1 <0>Muuttaa sijainnnin /etc/resolv.conf symbolisen linkin kohteeksi /run/systemd/resolve/resolv.conf <0>Pysäyttää DNSStubListener-palvelun (uudelleenlataa systemd-resolved -palvelu)", "autofix_warning_result": "Tämän jälkeen järjestelmäsi kaikki DNS-pyynnöt käsittelee oletusarvoisesti AdGuard Home.", "tags_title": "Tunnisteet", @@ -556,7 +556,7 @@ "check_title": "Tarkasta suodatus", "check_desc": "Tarkasta suodatetaanko isäntänimeä", "check": "Tarkasta", - "form_enter_host": "Syötä isäntänimi", + "form_enter_host": "Syötä osoite", "filtered_custom_rules": "Suodatettu omilla suodatussäännöillä", "choose_from_list": "Valitse listalta", "add_custom_list": "Lisää oma lista", @@ -584,8 +584,8 @@ "dnssec_enable_desc": "Määritä DNSSEC-lippu ulos lähteville DNS-pyynnöille ja tarkasta tulos (vaatii DNSSEC-yhteensopivan resolverin).", "validated_with_dnssec": "DNSSEC-vahvistettu", "all_queries": "Kaikki pyynnöt", - "show_blocked_responses": "Estetty", - "show_whitelisted_responses": "Sallittu", + "show_blocked_responses": "Estetyt", + "show_whitelisted_responses": "Sallitut", "show_processed_responses": "Käsitelty", "blocked_safebrowsing": "Turvallisen selauksen estämät", "blocked_adult_websites": "Estetyt aikuisille tarkoitetut sivustot", @@ -618,11 +618,14 @@ "filter_category_other_desc": "Muut estolistat", "setup_config_to_enable_dhcp_server": "Määritä asetukset DHCP-palvelimen käyttöönottoa varten", "original_response": "Alkuperäinen vastaus", - "click_to_view_queries": "Näytä pyynnöt", + "click_to_view_queries": "Paina näyttääksesi pyynnöt", "port_53_faq_link": "Portti 53 on usein \"DNSStubListener\" tai \"systemd-resolved\" -palveluiden varaama. Lue <0>nämä ohjeet tämän ratkaisemiseksi.", "adg_will_drop_dns_queries": "AdGuard Home hylkää tämän päätelaitteen DNS-pyynnöt.", "filter_allowlist": "VAROITUS: Toiminto ohittaa \"{{disallowed_rule}}\" -säännön sallittujen päätelaitteiden listalta.", "last_rule_in_allowlist": "Et voi estää tätä päätelaitetta, koska säännön \"{{disallowed_rule}}\" ohitus POISTAA KÄYTÖSTÄ \"Sallitut päätelaitteet\" -listan.", "experimental": "Kokeellinen", - "use_saved_key": "Käytä aiemmin tallennettua avainta" + "use_saved_key": "Käytä aiemmin tallennettua avainta", + "parental_control": "Lapsilukko", + "safe_browsing": "Turvallinen selaus", + "served_from_cache": "{{value}} (jaettu välimuistista)" } diff --git a/client/src/__locales/fr.json b/client/src/__locales/fr.json index 745b4de9..d0dee4c9 100644 --- a/client/src/__locales/fr.json +++ b/client/src/__locales/fr.json @@ -36,11 +36,23 @@ "dhcp_ipv4_settings": "Paramètres IPv4 du DHCP", "dhcp_ipv6_settings": "Paramètres IPv6 du DHCP", "form_error_required": "Champ requis", - "form_error_ip_format": "Adresse e-mail non valide", + "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": "Identifiant de client invalide", "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", - "form_error_negative": "Doit être égal à 0 ou supérieur", + "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", @@ -188,6 +200,7 @@ "form_error_url_or_path_format": "Entrez une URL ou le chemin absolu de la liste", "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", "examples_title": "Exemples", "example_meaning_filter_block": "bloque l’accès au domaine example.org et à tous ses sous-domaines", "example_meaning_filter_whitelist": "débloque l’accès au domaine example.org et à tous ses sous-domaines", @@ -611,5 +624,8 @@ "filter_allowlist": "ATTENTION : Cette action exclura également la règle « {{disallowed_rule}} » de la liste des clients autorisés.", "last_rule_in_allowlist": "Impossible d’interdire ce client, car l’exclusion de la règle « {{disallowed_rule}} » DÉSACTIVERA la liste des « clients autorisés ».", "experimental": "Expérimental", - "use_saved_key": "Utiliser la clef précédemment enregistrée" + "use_saved_key": "Utiliser la clef précédemment enregistrée", + "parental_control": "Contrôle parental", + "safe_browsing": "Navigation sécurisée", + "served_from_cache": "{{value}} (depuis le cache)" } diff --git a/client/src/__locales/hr.json b/client/src/__locales/hr.json index 6288860e..cfc193b4 100644 --- a/client/src/__locales/hr.json +++ b/client/src/__locales/hr.json @@ -37,6 +37,9 @@ "dhcp_ipv6_settings": "DHCP IPv6 postavke", "form_error_required": "Obavezno polje", "form_error_ip4_format": "Nevažeći IPv4 format", + "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", @@ -44,7 +47,12 @@ "form_error_server_name": "Nevažeće ime poslužitelja", "form_error_subnet": "Podmrežu \"{{cidr}}\" ne sadrži IP adresu \"{{ip}}\"", "form_error_positive": "Mora biti veće od 0", - "form_error_negative": "Mora biti jednako ili veće od 0", + "out_of_range_error": "Mora biti izvan ranga \"{{start}}\"-\"{{end}}\"", + "lower_range_start_error": "Mora biti niže od početnog ranga", + "greater_range_start_error": "Mora biti veće od krajnjeg ranga", + "greater_range_end_error": "Mora biti veće od krajnjeg ranga", + "subnet_error": "Adrese moraju biti iz iste podmreže", + "gateway_or_subnet_invalid": "Maska podmreže je neprvilna", "dhcp_form_gateway_input": "Gateway IP", "dhcp_form_subnet_input": "Subnet maskiranje", "dhcp_form_range_title": "Raspon IP adresa", @@ -192,6 +200,7 @@ "form_error_url_or_path_format": "Nevažeći URL ili putanja od liste", "custom_filter_rules": "Prilagođena pravila filtriranja", "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", @@ -615,5 +624,8 @@ "filter_allowlist": "UPOZORENJE: Ova akcija će također isključiti pravilo \"{{disallowed_rule}}\" s popisa dopuštenih klijenata.", "last_rule_in_allowlist": "Ovaj klijent nije moguće onemogućiti jer će isključivanje pravila \"{{disallowed_rule}}\" ONEMOGUĆITI popis \"Dopušteni klijenti\".", "experimental": "Eksperimentalno", - "use_saved_key": "Korištenje prethodno spremljenog ključa" + "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)" } diff --git a/client/src/__locales/hu.json b/client/src/__locales/hu.json index 9d8b97d4..581557b0 100644 --- a/client/src/__locales/hu.json +++ b/client/src/__locales/hu.json @@ -44,7 +44,6 @@ "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", - "form_error_negative": "Legalább 0-nak kell lennie", "dhcp_form_gateway_input": "Átjáró IP", "dhcp_form_subnet_input": "Alhálózati maszk", "dhcp_form_range_title": "IP-címek tartománya", @@ -613,5 +612,6 @@ "port_53_faq_link": "Az 53-as portot gyakran a \"DNSStubListener\" vagy a \"systemd-resolved\" (rendszer által feloldott) szolgáltatások használják. Kérjük, olvassa el <0>ezt az útmutatót a probléma megoldásához.", "adg_will_drop_dns_queries": "Az AdGuard Home eldobja az összes DNS kérést erről a kliensről.", "experimental": "Kísérleti", - "use_saved_key": "Előzőleg mentett kulcs használata" + "use_saved_key": "Előzőleg mentett kulcs használata", + "parental_control": "Szülői felügyelet" } diff --git a/client/src/__locales/id.json b/client/src/__locales/id.json index 419d531c..87f244ac 100644 --- a/client/src/__locales/id.json +++ b/client/src/__locales/id.json @@ -36,15 +36,10 @@ "dhcp_ipv4_settings": "Pengaturan DHCP IPv4", "dhcp_ipv6_settings": "Pengaturan DHCP IPv6", "form_error_required": "Kolom yang harus diisi", - "form_error_ip4_format": "Format IPv4 tidak valid", - "form_error_ip6_format": "Format IPv6 tidak valid", - "form_error_ip_format": "Format IPv4 tidak valid", - "form_error_mac_format": "Format MAC tidak valid", - "form_error_client_id_format": "Format client ID tidak valid", + "form_error_ip_format": "Alamat IP salah", "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", - "form_error_negative": "Harus berjumlah 0 atau lebih besar dari 0", "dhcp_form_gateway_input": "IP gateway", "dhcp_form_subnet_input": "Subnet mask", "dhcp_form_range_title": "Rentang alamat IP", @@ -207,7 +202,6 @@ "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)", "all_lists_up_to_date_toast": "Semua daftar sudah diperbarui", - "updated_upstream_dns_toast": "Server DNS hulu terbarui", "dns_test_ok_toast": "Server DNS yang ditentukan bekerja dengan benar", "dns_test_not_ok_toast": "Server \"{{key}}\": tidak dapat digunakan, mohon cek bahwa Anda telah menulisnya dengan benar", "unblock": "Buka Blokir", @@ -305,7 +299,6 @@ "install_settings_dns_desc": "Anda perlu mengkonfigurasi perangkat atau router anda untuk menggunakan server DNS berikut ini", "install_settings_all_interfaces": "Semua antarmuka", "install_auth_title": "Otentikasi", - "install_auth_desc": "Sangat disarankan untuk mengkonfigurasi otentikasi kata sandi ke antarmuka web admin AdGuard Home Anda. Meskipun hanya dapat diakses di jaringan lokal Anda, tetap penting untuk melindunginya dari akses tak terbatas.", "install_auth_username": "Nama Pengguna", "install_auth_password": "Kata Sandi", "install_auth_confirm": "Konfirmasi kata sandi", @@ -612,5 +605,6 @@ "port_53_faq_link": "Port 53 sering ditempati oleh layanan \"DNSStubListener\" atau \"systemd-resolved\". Silakan baca <0>instruksi ini tentang cara menyelesaikan ini.", "adg_will_drop_dns_queries": "AdGuard Home akan menghapus semua permintaan DNS dari klien ini.", "experimental": "Eksperimental", - "use_saved_key": "Gunakan kunci yang disimpan sebelumnya" + "use_saved_key": "Gunakan kunci yang disimpan sebelumnya", + "parental_control": "Kontrol orang tua" } diff --git a/client/src/__locales/it.json b/client/src/__locales/it.json index 86364d16..4ab291da 100644 --- a/client/src/__locales/it.json +++ b/client/src/__locales/it.json @@ -27,7 +27,7 @@ "dhcp_description": "Se il tuo router non supporta la configurazione delle impostazioni del DHCP puoi utilizzare il server DHCP incluso in AdGuard.", "dhcp_enable": "Attiva server DHCP", "dhcp_disable": "Disattiva server DHCP", - "dhcp_not_found": "È sicuro attivare il server DHCP integrato poiché AdGuard Home non ha rilevato alcun server DHCP attivo sulla rete. Tuttavia, dovresti effettuare un ricontrollo manuale poiché la ricerca automatica attualmente non garantisce un\\'affidabilità del 100%.", + "dhcp_not_found": "È sicuro attivare il server DHCP integrato poiché AdGuard Home non ha rilevato alcun server DHCP attivo sulla rete. Tuttavia, dovresti effettuare un ricontrollo manuale poiché la ricerca automatica attualmente non garantisce un'affidabilità del 100%.", "dhcp_found": "Trovati server DHCP attivi nella rete. Non è consigliato attivare il server DHCP built-in", "dhcp_leases": "Leases DHCP", "dhcp_static_leases": "Leases DHCP statici", @@ -45,13 +45,12 @@ "form_error_mac_format": "Indirizzo MAC non valido", "form_error_client_id_format": "ID cliente non valido", "form_error_server_name": "Nome server non valido", - "form_error_subnet": "La subnet \"{{cidr}}\" non contiene l\\'indirizzo IP \"{{ip}}\"", + "form_error_subnet": "La subnet \"{{cidr}}\" non contiene l'indirizzo IP \"{{ip}}\"", "form_error_positive": "Deve essere maggiore di 0", - "form_error_negative": "Deve essere maggiore o uguale a 0 (zero)", "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", + "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", @@ -70,7 +69,7 @@ "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_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_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", "dhcp_lease_deleted": "Lease statico \"{{key}}\" eliminato correttamente", "dhcp_new_static_lease": "Nuovo lease statico", @@ -131,7 +130,7 @@ "number_of_dns_query_days": "Numero di richieste DNS elaborate negli ultimi {{count}} giorni", "number_of_dns_query_days_plural": "Numero di richieste DNS elaborate negli ultimi {{count}} giorni", "number_of_dns_query_24_hours": "Numero di richieste DNS elaborate nelle ultime 24 ore", - "number_of_dns_query_blocked_24_hours": "Numero di richieste DNS bloccate dai filtri per annunci e dalle liste di blocco host", + "number_of_dns_query_blocked_24_hours": "Numero di richieste DNS bloccate dai filtri per annunci e dagli elenchi di blocco host", "number_of_dns_query_blocked_24_hours_by_sec": "Numero di richieste DNS bloccate dal modulo sicurezza di navigazione di AdGuard", "number_of_dns_query_blocked_24_hours_adult": "Numero di siti web per adulti bloccati", "enforced_save_search": "Ricerca sicura forzata", @@ -141,7 +140,7 @@ "block_domain_use_filters_and_hosts": "Blocca domini utilizzando filtri e file hosts", "filters_block_toggle_hint": "Puoi impostare le regole di blocco nelle impostazioni dei Filtri.", "use_adguard_browsing_sec": "Utilizza il servizio web AdGuard 'sicurezza di navigazione'", - "use_adguard_browsing_sec_hint": "AdGuard Home verificherà se il dominio è bloccato dal servizio web di sicurezza della navigazione. Utilizzerà l\\'API di ricerca rispettosa della privacy per eseguire il controllo: solo un breve prefisso hash SHA256 del nome di dominio viene inviato al server.", + "use_adguard_browsing_sec_hint": "AdGuard Home verificherà se il dominio è bloccato dal servizio web di sicurezza della navigazione. Utilizzerà l'API di ricerca rispettosa della privacy per eseguire il controllo: solo un breve prefisso hash SHA256 del nome di dominio viene inviato al server.", "use_adguard_parental": "Utilizza il Controllo Parentale di AdGuard", "use_adguard_parental_hint": "AdGuard Home verificherà se il dominio contiene materiale per adulti. Utilizza le stesse API privacy-friendly del servizio web 'sicurezza di navigazione'.", "enforce_safe_search": "Utilizza ricerca sicura", @@ -149,7 +148,7 @@ "no_servers_specified": "Nessun server specificato", "general_settings": "Impostazioni generali", "dns_settings": "Impostazioni DNS", - "dns_blocklists": "Lista nera DNS", + "dns_blocklists": "Liste nere DNS", "dns_allowlists": "Liste bianche DNS", "dns_blocklists_desc": "AdGuard Home bloccherà i domini che corrispondenti alla lista nera.", "dns_allowlists_desc": "I domini DNS nelle liste bianche saranno consentiti anche fossero presenti in una delle liste nere.", @@ -181,29 +180,30 @@ "delete_table_action": "Elimina", "elapsed": "Trascorso", "filters_and_hosts_hint": "AdGuard Home è in grado di comprendere la sintassi delle regole blocca-annunci o quelle dei file hosts.", - "no_blocklist_added": "Non è stata aggiunta alcuna lista di blocco", - "no_whitelist_added": "Non è stata aggiunta alcuna Lista bianca", - "add_blocklist": "Aggiungi lista di blocco", - "add_allowlist": "Aggiungi Lista bianca", + "no_blocklist_added": "Non è stata aggiunta alcuna lista nera", + "no_whitelist_added": "Non è stata aggiunta alcuna lista bianca", + "add_blocklist": "Aggiungi lista nera", + "add_allowlist": "Aggiungi lista bianca", "cancel_btn": "Annulla", "enter_name_hint": "Inserisci nome", - "enter_url_or_path_hint": "Inmetti un URL o il percorso assoluto della lista", + "enter_url_or_path_hint": "Inmetti un URL o il percorso assoluto dell'elenco", "check_updates_btn": "Ricerca aggiornamenti", - "new_blocklist": "Nuova lista di blocco", - "new_allowlist": "Nuova Lista bianca", - "edit_blocklist": "Modifica lista di blocco", - "edit_allowlist": "Modifica Lista bianca", - "choose_blocklist": "Scegli liste di blocco", + "new_blocklist": "Nuova lista nera", + "new_allowlist": "Nuova lista bianca", + "edit_blocklist": "Modifica lista nera", + "edit_allowlist": "Modifica lista bianca", + "choose_blocklist": "Scegli liste nere", "choose_allowlist": "Scegli liste bianche", - "enter_valid_blocklist": "Inserisci un URL valido nella lista di blocco.", - "enter_valid_allowlist": "Inserisci un URL valido nella Lista bianca.", + "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 della lista 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", "examples_title": "Esempi", "example_meaning_filter_block": "blocca accesso al dominio example.org e a tutti i suoi sottodomini", - "example_meaning_filter_whitelist": "consente l\\'accesso al dominio esempio.org e a tutti i relativi sottodomini", + "example_meaning_filter_whitelist": "consente l'accesso al dominio esempio.org e a tutti i relativi sottodomini", "example_meaning_host_block": "AdGuard Home restituirà 127.0.0.1 come indirizzo per il dominio example.org (ma non per i suoi sottodomini)", "example_comment": "! Qui va un commento", "example_comment_meaning": "un commento", @@ -215,7 +215,7 @@ "example_upstream_doq": "<0>DNS su QUIC crittografato", "example_upstream_sdns": "puoi utilizzare <0>DNS Stamps per <1>DNSCrypt oppure dei risolutori <2>DNS-over-HTTPS", "example_upstream_tcp": "DNS regolari (via TCP)", - "all_lists_up_to_date_toast": "Tutte le liste sono aggiornate", + "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", "dns_test_not_ok_toast": "Server \"{{key}}\": non può essere utilizzato, assicurati di averlo digitato correttamente", @@ -289,7 +289,7 @@ "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", - "blocking_mode_default": "Risponde con un indirizzo IP pari a zero (0.0.0.0 per A; :: per AAAA) quando bloccato da una regola in stile Blocca-annunci; risponde con l\\'indirizzo IP specificato nella regola quando bloccato da una regola in stile /etc/hosts", + "blocking_mode_default": "Risponde con un indirizzo IP pari a zero (0.0.0.0 per A; :: per AAAA) quando bloccato da una regola in stile Blocca-annunci; risponde con l'indirizzo IP specificato nella regola quando bloccato da una regola in stile /etc/hosts", "blocking_mode_refused": "REFUSED: Risposta con codice di REFUSED", "blocking_mode_nxdomain": "NXDOMAIN: Rispondi con il codice NXDOMAIN", "blocking_mode_null_ip": "IP nullo: Rispondi con indirizzo IP zero (0.0.0.0 per A; :: per AAAA)", @@ -300,7 +300,7 @@ "found_in_known_domain_db": "Trovato nel database dei domini conosciuti.", "category_label": "Categoria", "rule_label": "Regola(e)", - "list_label": "Lista", + "list_label": "Elenco", "unknown_filter": "Filtro sconosciuto {{filterId}}", "known_tracker": "Tracker conosciuto", "install_welcome_title": "Benvenuto nella Home di AdGuard!", @@ -314,7 +314,7 @@ "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", "install_auth_title": "Autenticazione", - "install_auth_desc": "L\\'autenticazione con password sulla tua interfaccia web da amministratore di AdGuard Home dev\\'esser configurata. Anche se AdGuard Home è accessibile solo dalla tua rete locale, è comunque importante proteggerlo da accessi non limitati.", + "install_auth_desc": "L'autenticazione con password sulla tua interfaccia web da amministratore di AdGuard Home dev'esser configurata. Anche se AdGuard Home è accessibile solo dalla tua rete locale, è comunque importante proteggerlo da accessi non limitati.", "install_auth_username": "Nome utente", "install_auth_password": "Password", "install_auth_confirm": "Conferma password", @@ -328,7 +328,7 @@ "install_devices_router": "Router", "install_devices_router_desc": "Questa configurazione copre automaticamente tutti i dispositivi collegati al router di casa, non è necessario configurarli manualmente.", "install_devices_address": "Il server DNS di AdGuard Home sta ascoltando sui seguenti indirizzi", - "install_devices_router_list_1": "Accedi alle preferenze del tuo router. Di solito, puoi farlo dal tuo browser tramite un URL, come http://192.168.0.1/ o http://192.168.1.1/. Potrebbe esserti chiesto di inserire una password. Se non dovessi ricordarla, puoi reimpostare la password premendo un pulsante presente sullo stesso router, ma tieni presente che scegliendo questa procedura, probabilmente perderai l\\'intera configurazione del router. Se il tuo router necessitasse di un\\'app per configurarlo, installala sul tuo telefono o PC e utilizzala per accedere alle impostazioni del router.", + "install_devices_router_list_1": "Accedi alle preferenze del tuo router. Di solito, puoi farlo dal tuo browser tramite un URL, come http://192.168.0.1/ o http://192.168.1.1/. Potrebbe esserti chiesto di inserire una password. Se non dovessi ricordarla, puoi reimpostare la password premendo un pulsante presente sullo stesso router, ma tieni presente che scegliendo questa procedura, probabilmente perderai l'intera configurazione del router. Se il tuo router necessitasse di un'app per configurarlo, installala sul tuo telefono o PC e utilizzala per accedere alle impostazioni del router.", "install_devices_router_list_2": "Trova le impostazioni DHCP / DNS. Cerca le lettere DNS accanto a un campo che consente due o tre serie di numeri, ciascuno suddiviso in quattro gruppi di 1-3 cifre.", "install_devices_router_list_3": "Inserisci qui gli indirizzi del tuo server AdGuard Home.", "install_devices_router_list_4": "Su alcuni tipi di router, non è possibile configurare un server DNS personalizzato. In tal caso, configurare AdGuard Home come un <0>server DHCP potrebbe aiutare. In alternativa, dovresti leggere il manuale di istruzioni per capire come personalizzare i server DNS sul tuo specifico modello di router.", @@ -336,20 +336,20 @@ "install_devices_windows_list_2": "Vai a Rete e categoria Internet e poi a Centro connessioni di rete e condivisione.", "install_devices_windows_list_3": "Sul lato sinistro dello schermo, trova \"Cambia impostazioni adattatore\" e clicca su di esso.", "install_devices_windows_list_4": "Seleziona la tua connessione attiva, fai clic destro su di essa e scegli Proprietà.", - "install_devices_windows_list_5": "Trova \"Protocollo Internet versione 4 (TCP/IPv4)\" (o, per IPv6, \"Protocollo Internet versione 6 (TCP/IPv6)\" nella lista, selezionalo e quindi clicca nuovamente su Proprietà.", + "install_devices_windows_list_5": "Trova \"Protocollo Internet versione 4 (TCP/IPv4)\" (o, per IPv6, \"Protocollo Internet versione 6 (TCP/IPv6)\" nell'elenco, selezionalo e quindi clicca nuovamente su Proprietà.", "install_devices_windows_list_6": "Scegli \"Utilizza i seguenti indirizzi server DNS\" ed inserisci i tuoi indirizzi server AdGuard Home.", "install_devices_macos_list_1": "Fai clic sull'icona Apple e vai su Preferenze di Sistema.", "install_devices_macos_list_2": "Clicca sulla rete.", - "install_devices_macos_list_3": "Seleziona la prima connessione nel tuo elenco e fai clic su Avanzate.", + "install_devices_macos_list_3": "Seleziona la prima connessione nel tuo elenco e clicca su Avanzate.", "install_devices_macos_list_4": "Seleziona la scheda DNS e inserisci gli indirizzi del tuo server AdGuard Home", - "install_devices_android_list_1": "Dalla schermata Home Menu di Android, tocca Impostazioni.", - "install_devices_android_list_2": "Tocca Wi-Fi nel menu. Verrà visualizzata la schermata che elenca tutte le reti disponibili (impossibile impostare il DNS personalizzato per la connessione mobile).", - "install_devices_android_list_3": "Premi a lungo la rete a cui sei connesso e tocca Modifica rete.", + "install_devices_android_list_1": "Dalla schermata Home Menu di Android, clicca Impostazioni.", + "install_devices_android_list_2": "Clicca sulla voce Wi-Fi nel menu. Verrà visualizzata una schermata che elencherà tutte le reti disponibili (sarà impossibile impostare il DNS personalizzato per la connessione mobile).", + "install_devices_android_list_3": "Premi a lungo la rete a cui sei connesso e clicca Modifica rete.", "install_devices_android_list_4": "Su alcuni dispositivi, potrebbe essere necessario selezionare la casella Avanzate per visualizzare ulteriori impostazioni. Per regolare le impostazioni del tuo DNS Android, dovrai cambiare le impostazioni IP da DHCP a Statico.", "install_devices_android_list_5": "Cambia i valori DNS 1 e DNS 2 negli indirizzi del tuo server AdGuard Home.", - "install_devices_ios_list_1": "Dalla schermata principale, tocca Impostazioni.", + "install_devices_ios_list_1": "Dalla schermata principale, clicca Impostazioni.", "install_devices_ios_list_2": "Scegli Wi-Fi nel menu a sinistra (impossibile configurare DNS per reti mobile).", - "install_devices_ios_list_3": "Toccare il nome della rete attualmente attiva.", + "install_devices_ios_list_3": "Clicca sul nome della rete attualmente attiva.", "install_devices_ios_list_4": "Nel campo DNS inserisci gli indirizzi del tuo server AdGuard Home.", "get_started": "Inizia", "next": "Prossimo", @@ -388,7 +388,7 @@ "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_range": "Immettere il valore della porta nell'intervallo 80-65535", "form_error_port_unsafe": "Questa è una porta non sicura", "form_error_equal": "Non dovrebbe essere uguale", "form_error_password": "Password non corrispondente", @@ -400,7 +400,7 @@ "dns_status_error": "Errore nel recupero dello stato del server DNS", "down": "Spenta", "fix": "Risolvi", - "dns_providers": "Qui c\\'è una <0>lista di provider DNS da cui scegliere.", + "dns_providers": "Qui c'è un <0>elenco di fornitori DNS conosciuti da cui scegliere.", "update_now": "Aggiorna ora", "update_failed": "Aggiornamento automatico non riuscito. Ti suggeriamo di seguire questi passaggi per aggiornare manualmente.", "processing_update": "Perfavore aspetta, AdGuard Home si sta aggiornando", @@ -430,15 +430,15 @@ "client_updated": "Client \"{{key}}\" aggiornato correttamente", "clients_not_found": "Nessun client trovato", "client_confirm_delete": "Sei sicuro di voler eliminare il client \"{{key}}\"?", - "list_confirm_delete": "Sei sicuro di voler eliminare questa lista?", + "list_confirm_delete": "Sei sicuro di voler eliminare questo elenco?", "auto_clients_title": "Clienti (tempo di esecuzione)", "auto_clients_desc": "Dati dei clienti che utilizzano AdGuard Home, ma che non sono salvati nella configurazione", "access_title": "Impostazioni di accesso", "access_desc": "Qui puoi configurare le regole d'accesso per il server DNS di AdGuard Home.", "access_allowed_title": "Client permessi", - "access_allowed_desc": "Una lista di CIDR, indirizzi IP o ID client. Se configurata AdGuard Home accetterà richieste solo da questi client.", + "access_allowed_desc": "Un elenco di CIDR, indirizzi IP o ID client. Se configurata AdGuard Home accetterà richieste solo da questi client.", "access_disallowed_title": "Client non permessi", - "access_disallowed_desc": "Una lista di CIDR, indirizzi IP o ID client. Se configurata, AdGuard Home rifiuterà richieste da questi client. Se i client consentiti risulteranno configurati, questo campo verrà ignorato.", + "access_disallowed_desc": "Un elenco di CIDR, indirizzi IP o ID client. Se configurata, AdGuard Home rifiuterà richieste da questi client. Se i client consentiti risulteranno configurati, questo campo verrà ignorato.", "access_blocked_title": "Domini bloccati", "access_blocked_desc": "Da non confondere con i filtri. AdGuard Home eliminerà le richieste DNS corrispondenti a questi domini e queste richieste non verranno visualizzate nel relativo registro. Puoi specificare nomi di dominio esatti, caratteri jolly o regole di filtraggio URL, ad esempio \"esempio.org\", \"*.esempio.org\" o \"||esempio.org^\".", "access_settings_saved": "Impostazioni di accesso salvate correttamente", @@ -501,9 +501,9 @@ "domain": "Dominio", "punycode": "Punycode", "answer": "Risposta", - "filter_added_successfully": "Il filtro è stato aggiunto correttamente", - "filter_removed_successfully": "La lista è stata correttamente rimossa", - "filter_updated": "Il filtro è stato aggiornato correttamente", + "filter_added_successfully": "L'elenco è stato aggiunto correttamente", + "filter_removed_successfully": "L'elenco è stata correttamente rimosso", + "filter_updated": "L'elenco è stato aggiornato correttamente", "statistics_configuration": "Configurazione delle statistiche", "statistics_retention": "Conservazione delle statistiche", "statistics_retention_desc": "Se il valore di intervallo dovesse diminuire, alcuni dati andranno persi", @@ -532,7 +532,7 @@ "network": "Rete", "descr": "Descrizione", "whois": "Chi è", - "filtering_rules_learn_more": "<0>Leggi altro su come creare le tue liste host.", + "filtering_rules_learn_more": "<0>Leggi altro su come creare i tuoi elenchi host.", "blocked_by_response": "Bloccato per CNAME o IP in risposta", "blocked_by_cname_or_ip": "Bloccato da CNAME o IP", "try_again": "Riprova", @@ -546,7 +546,7 @@ "disable_ipv6": "Disattiva risoluzione indirizzi IPv6", "disable_ipv6_desc": "Elimina tutte le richieste DNS per gli indirizzi IPv6 (tipo AAAA).", "fastest_addr": "Indirizzo IP più veloce", - "fastest_addr_desc": "Interroga tutti i server DNS e restituisci l\\'indirizzo IP più veloce tra tutte le risposte. Ciò rallenterà le richieste DNS poiché AdGuard Home dovrà attendere le risposte da tutti i server DNS, ma ciò migliorerà complessivamente la connettività.", + "fastest_addr_desc": "Interroga tutti i server DNS e restituisci l'indirizzo IP più veloce tra tutte le risposte. Ciò rallenterà le richieste DNS poiché AdGuard Home dovrà attendere le risposte da tutti i server DNS, ma ciò migliorerà complessivamente la connettività.", "autofix_warning_text": "Se fai clic su \"Correggi\", AdGuardHome configurerà il tuo sistema per utilizzare il server DNS AdGuardHome.", "autofix_warning_list": "Eseguirà queste attività: <0> Disattiva DNSStubListener di sistema <0> Imposta l'indirizzo del server DNS su 127.0.0.1 <0> Sostituisci la destinazione del collegamento simbolico di /etc/resolv.conf su / run / systemd /resolve/resolv.conf <0> Arresta DNSStubListener (ricarica il servizio systemd-resolved) ", "autofix_warning_result": "Di conseguenza, tutte le richieste DNS dal sistema verranno elaborate da AdGuardHome per impostazione predefinita.", @@ -558,9 +558,9 @@ "check": "Controlla", "form_enter_host": "Inserisci un nome per l'host", "filtered_custom_rules": "Filtrato dalle regole filtro personalizzate", - "choose_from_list": "Scegli dalla lista", - "add_custom_list": "Aggiungi lista personalizzata", - "host_whitelisted": "L\\'host è stato aggiunto alla Lista bianca", + "choose_from_list": "Scegli dall'elenco", + "add_custom_list": "Aggiungi elenco personalizzato", + "host_whitelisted": "L'host è stato aggiunto alla lista bianca", "check_ip": "Indirizzi IP: {{ip}}", "check_cname": "CNAME: {{cname}}", "check_reason": "Motivo: {{reason}}", @@ -576,16 +576,16 @@ "set_static_ip": "Imposta un indirizzo IP statico", "install_static_ok": "Buone notizie! L'indirizzo IP statico è già configurato", "install_static_error": "AdGuard Home non può configurarlo automaticamente per questa interfaccia di rete. Ti suggeriamo di cercare un metodo alternativo per effettuare tale operazione manualmente.", - "install_static_configure": "AdGuard Home ha rilevato l\\'utilizzo dell\\'indirizzo IP dinamico <0> {{ip}} . Desideri impostarlo come indirizzo statico?", + "install_static_configure": "AdGuard Home ha rilevato l'utilizzo dell'indirizzo IP dinamico <0> {{ip}} . Desideri impostarlo come indirizzo statico?", "confirm_static_ip": "AdGuard Home configurerà {{ip}} come indirizzo IP statico. Desideri procedere?", - "list_updated": "{{count}} lista aggiornata", - "list_updated_plural": "{{count}} liste aggiornate", + "list_updated": "{{count}} elenco aggiornato", + "list_updated_plural": "{{count}} elenchi aggiornati", "dnssec_enable": "Attiva DNSSEC", "dnssec_enable_desc": "Imposta il flag DNSSEC sulle richieste DNS in uscita e ne verifica il risultato (è richiesto un risolutore attivo per DNSSEC).", "validated_with_dnssec": "Verificato con DNSSEC", "all_queries": "Tutte le richieste", "show_blocked_responses": "Bloccato", - "show_whitelisted_responses": "Aggiunto alla Lista bianca", + "show_whitelisted_responses": "Consentito", "show_processed_responses": "Processato", "blocked_safebrowsing": "Blocco Navigazione sicura", "blocked_adult_websites": "Siti per adulti bloccati", @@ -594,7 +594,7 @@ "filtered": "Filtrato", "rewritten": "Riscritto", "safe_search": "Ricerca sicura", - "blocklist": "Lista di blocco", + "blocklist": "Lista nera", "milliseconds_abbreviation": "ms", "cache_size": "Dimensioni cache", "cache_size_desc": "Dimensioni cache DNS (in byte)", @@ -612,17 +612,20 @@ "filter_category_security": "Sicurezza", "filter_category_regional": "Regionale", "filter_category_other": "Altro", - "filter_category_general_desc": "Liste per il blocco dei traccianti e degli annunci sulla maggioranza dei dispositivi", + "filter_category_general_desc": "Elenchi per il blocco dei traccianti e degli annunci sulla maggioranza dei dispositivi", "filter_category_security_desc": "Elenchi progettati specificamente per bloccare domini malevoli, di phishing o truffa", - "filter_category_regional_desc": "Liste focalizzate su annunci regionali e server traccianti", - "filter_category_other_desc": "Altre liste di blocco", - "setup_config_to_enable_dhcp_server": "Configurazione dell\\'installazione per l\\'attivazione del server DHCP", + "filter_category_regional_desc": "Elenchi focalizzati su annunci regionali e server traccianti", + "filter_category_other_desc": "Altre liste nere", + "setup_config_to_enable_dhcp_server": "Configurazione dell'installazione per l'attivazione del server DHCP", "original_response": "Responso originale", "click_to_view_queries": "Clicca per visualizzare le richieste", "port_53_faq_link": "La Porta 53 è spesso occupata dai servizi \"DNSStubListener\" o \"systemd-resolved\". Ti suggeriamo di leggere <0>queste istruzioni per risolvere il problema.", "adg_will_drop_dns_queries": "AdGuard Home eliminerà tutte le richieste DNS da questo client.", - "filter_allowlist": "ATTENZIONE: Quest\\'azione escluderà anche la regola \"{{disallowed_rule}}\" dall\\'elenco di clienti consentiti.", - "last_rule_in_allowlist": "Impossibile bloccare questo client perché escludere la regola \"{{disallowed_rule}}\" DISATIVERÁ l\\'elenco \"Clienti consentiti\".", + "filter_allowlist": "ATTENZIONE: Quest'azione escluderà anche la regola \"{{disallowed_rule}}\" dall'elenco di clienti consentiti.", + "last_rule_in_allowlist": "Impossibile bloccare questo client perché escludere la regola \"{{disallowed_rule}}\" DISATIVERÁ l'elenco \"Clienti consentiti\".", "experimental": "Sperimentale", - "use_saved_key": "Utilizza la chiave salvata in precedenza" + "use_saved_key": "Utilizza la chiave salvata in precedenza", + "parental_control": "Controllo parentale", + "safe_browsing": "Navigazione sicura", + "served_from_cache": "{{value}} (fornito dalla cache)" } diff --git a/client/src/__locales/ja.json b/client/src/__locales/ja.json index 29543a57..2ad01136 100644 --- a/client/src/__locales/ja.json +++ b/client/src/__locales/ja.json @@ -36,15 +36,23 @@ "dhcp_ipv4_settings": "DHCP IPv4 設定", "dhcp_ipv6_settings": "DHCP IPv6 設定", "form_error_required": "必須項目", - "form_error_ip4_format": "IPv4フォーマットではありません", - "form_error_ip6_format": "IPv6フォーマットではありません", - "form_error_ip_format": "IPv4フォーマットではありません", - "form_error_mac_format": "MACフォーマットではありません", - "form_error_client_id_format": "Client IDの形式が無効です", + "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": "IPアドレス「{{ip}}」はサブネット「{{cidr}}」に含まれていません", "form_error_positive": "0より大きい必要があります", - "form_error_negative": "0以上である必要があります", + "out_of_range_error": "\"{{start}}\"-\"{{end}}\" の範囲外である必要があります", + "lower_range_start_error": "範囲開始よりも低い値である必要があります", + "greater_range_start_error": "範囲開始より大きい必要があります", + "greater_range_end_error": "範囲終了より大きい必要があります", + "subnet_error": "アドレスは1つのサブネット内にある必要があります", + "gateway_or_subnet_invalid": "サブネットマスクが無効です", "dhcp_form_gateway_input": "ゲートウェイIP", "dhcp_form_subnet_input": "サブネットマスク", "dhcp_form_range_title": "IPアドレスの範囲", @@ -192,6 +200,7 @@ "form_error_url_or_path_format": "リストのURLまたは絶対パスが無効です", "custom_filter_rules": "カスタム・フィルタリングルール", "custom_filter_rules_hint": "1つの行に1つのルールを入力してください。 広告ブロックルールやhostsファイル構文を使用できます。", + "system_host_files": "システムのhostsファイル", "examples_title": "例", "example_meaning_filter_block": "example.orgドメインとそのすべてのサブドメインへのアクセスをブロックする", "example_meaning_filter_whitelist": "example.orgドメインとそのすべてのサブドメインへのアクセスのブロックを解除する", @@ -615,5 +624,8 @@ "filter_allowlist": "【注意】このアクションは、許可されたクライアントのリストから「{{disallowed_rule}}」というルールも除外します。", "last_rule_in_allowlist": "ルール「{{disallowed_rule}}」を除外すると「許可されたクライアント」リストが無効になるため、このクライアントを拒否することはできません。", "experimental": "実験用", - "use_saved_key": "以前に保存したキーを使用する" + "use_saved_key": "以前に保存したキーを使用する", + "parental_control": "ペアレンタルコントロール", + "safe_browsing": "セーフブラウジング", + "served_from_cache": "{{value}} (キャッシュから応答)" } diff --git a/client/src/__locales/ko.json b/client/src/__locales/ko.json index 221f0391..d44603f1 100644 --- a/client/src/__locales/ko.json +++ b/client/src/__locales/ko.json @@ -37,6 +37,9 @@ "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 형식", @@ -44,7 +47,12 @@ "form_error_server_name": "유효하지 않은 서버 이름입니다", "form_error_subnet": "서브넷 \"{{cidr}}\"에 \"{{ip}}\" IP 주소가 없습니다", "form_error_positive": "0보다 커야 합니다", - "form_error_negative": "반드시 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 주소 범위", @@ -192,6 +200,7 @@ "form_error_url_or_path_format": "올바른 URL 또는 목록의 절대 경로가 아닙니다", "custom_filter_rules": "커스텀 필터링 규칙", "custom_filter_rules_hint": "한 라인에 한 규칙만 입력하세요. 광고 차단 규칙과 호스트 파일 문법 중 하나를 사용할 수 있습니다", + "system_host_files": "시스템 호스트 파일", "examples_title": "예시", "example_meaning_filter_block": "example.org 을 포함한 모든 서브 도메인 접근을 차단합니다", "example_meaning_filter_whitelist": "example.org 을 포함한 모든 서브 도메인 접근을 차단 해제합니다.", @@ -615,5 +624,8 @@ "filter_allowlist": "경고: 이 경우 허용된 클라이언트 목록에서 '{{disallowed_rule}}' 규칙 또한 제외됩니다.", "last_rule_in_allowlist": "'{{disallowed_rule}}' 규칙을 제외하면 '허용된 클라이언트' 목록이 꺼지므로 해당 클라이언트를 제외할 수 없습니다.", "experimental": "실험", - "use_saved_key": "이전에 저장했던 키 사용하기" + "use_saved_key": "이전에 저장했던 키 사용하기", + "parental_control": "자녀 보호", + "safe_browsing": "안전한 브라우징", + "served_from_cache": "{{value}} (캐시에서 제공)" } diff --git a/client/src/__locales/nl.json b/client/src/__locales/nl.json index 5404198e..c470bcef 100644 --- a/client/src/__locales/nl.json +++ b/client/src/__locales/nl.json @@ -47,7 +47,6 @@ "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", - "form_error_negative": "Moet 0 of hoger dan 0 zijn", "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", @@ -201,6 +200,7 @@ "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", "examples_title": "Voorbeelden", "example_meaning_filter_block": "blokkeer toegang tot het example.org domein en alle subdomeinen", "example_meaning_filter_whitelist": "deblokkering van toegang tot het example.org-domein en alle bijbehorende subdomeinen", @@ -624,5 +624,8 @@ "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.", "experimental": "Experimenteel", - "use_saved_key": "De eerder opgeslagen sleutel gebruiken" + "use_saved_key": "De eerder opgeslagen sleutel gebruiken", + "parental_control": "Ouderlijk toezicht", + "safe_browsing": "Veilig surfen", + "served_from_cache": "{{value}} (geleverd vanuit cache)" } diff --git a/client/src/__locales/no.json b/client/src/__locales/no.json index 1e627129..5eaac514 100644 --- a/client/src/__locales/no.json +++ b/client/src/__locales/no.json @@ -28,7 +28,6 @@ "form_error_client_id_format": "Ugyldig ID-klientformat", "form_error_server_name": "Ugyldig tjenernavn", "form_error_positive": "Må være høyere enn 0", - "form_error_negative": "Må være ≥0", "dhcp_form_gateway_input": "Gateway-IP", "dhcp_form_subnet_input": "Nettverksmaske", "dhcp_form_range_title": "Spennvidden til IP-adressene", @@ -555,5 +554,6 @@ "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.", - "experimental": "Eksperimentell" + "experimental": "Eksperimentell", + "parental_control": "Foreldrekontroll" } diff --git a/client/src/__locales/pl.json b/client/src/__locales/pl.json index 4d730b7d..fbd15cbb 100644 --- a/client/src/__locales/pl.json +++ b/client/src/__locales/pl.json @@ -47,7 +47,6 @@ "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", - "form_error_negative": "Musi być równy 0 lub większy", "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", @@ -201,6 +200,7 @@ "form_error_url_or_path_format": "Adres URL lub bezwzględna ścieżka listy jest nieprawidłowa", "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", "examples_title": "Przykłady", "example_meaning_filter_block": "zablokuj dostęp do domeny example.org i wszystkich jej subdomen", "example_meaning_filter_whitelist": "odblokuj dostęp do domeny example.org i wszystkich jej subdomen", @@ -624,5 +624,8 @@ "filter_allowlist": "OSTRZEŻENIE: To działanie spowoduje również wykluczenie reguły \"{{disallowed_rule}}\" z listy dozwolonych klientów.", "last_rule_in_allowlist": "Nie można odrzucić tego klienta, ponieważ wykluczenie reguły \"{{disallowed_rule}}\" spowoduje WYŁĄCZENIE listy „Dozwolonych klientów”.", "experimental": "Funkcja eksperymentalna", - "use_saved_key": "Użyj wcześniej zapisanego klucza" + "use_saved_key": "Użyj wcześniej zapisanego klucza", + "parental_control": "Kontrola rodzicielska", + "safe_browsing": "Bezpieczne przeglądanie", + "served_from_cache": "{{value}} (podawane z pamięci podręcznej)" } diff --git a/client/src/__locales/pt-br.json b/client/src/__locales/pt-br.json index 955e96e2..ac425153 100644 --- a/client/src/__locales/pt-br.json +++ b/client/src/__locales/pt-br.json @@ -47,7 +47,6 @@ "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", - "form_error_negative": "Deve ser igual ou superior a 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", @@ -201,6 +200,7 @@ "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", "examples_title": "Exemplos", "example_meaning_filter_block": "bloqueia o acesso ao domínio exemplo.org e a todos os seus subdomínios", "example_meaning_filter_whitelist": "desbloqueia o acesso ao domínio exemplo.org e a todos os seus subdomínios", @@ -624,5 +624,8 @@ "filter_allowlist": "AVISO: Esta ação também excluirá a regra \"{{disallowed_rule}}\" da lista de clientes permitidos.", "last_rule_in_allowlist": "Não é possível desautorizar este cliente porque excluir a regra \"{{disallowed_rule}}\" DESATIVARÁ a lista de \"Clientes permitidos\".", "experimental": "Experimental", - "use_saved_key": "Use a chave salva anteriormente" + "use_saved_key": "Use a chave salva anteriormente", + "parental_control": "Controle parental", + "safe_browsing": "Navegação segura", + "served_from_cache": "{{value}} (servido do cache)" } diff --git a/client/src/__locales/pt-pt.json b/client/src/__locales/pt-pt.json index 94785e1b..3e1bdbbd 100644 --- a/client/src/__locales/pt-pt.json +++ b/client/src/__locales/pt-pt.json @@ -47,7 +47,6 @@ "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", - "form_error_negative": "Deve ser igual ou superior a 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", @@ -201,6 +200,7 @@ "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", "examples_title": "Exemplos", "example_meaning_filter_block": "bloqueia o acesso ao domínio exemplo.org e a todos os seus subdomínios", "example_meaning_filter_whitelist": "desbloqueia o acesso ao domínio exemplo.org e a todos os seus subdomínios", @@ -624,5 +624,8 @@ "filter_allowlist": "AVISO: Esta ação também excluirá a regra \"{{disallowed_rule}}\" da lista de clientes permitidos.", "last_rule_in_allowlist": "Não é possível desautorizar este cliente porque excluir a regra \"{{disallowed_rule}}\" DESATIVARÁ a lista de \"Clientes permitidos\".", "experimental": "Experimental", - "use_saved_key": "Use a chave guardada anteriormente" + "use_saved_key": "Use a chave guardada anteriormente", + "parental_control": "Controle parental", + "safe_browsing": "Navegação segura", + "served_from_cache": "{{value}} (servido do cache)" } diff --git a/client/src/__locales/ro.json b/client/src/__locales/ro.json index ac5183ac..162e4491 100644 --- a/client/src/__locales/ro.json +++ b/client/src/__locales/ro.json @@ -47,7 +47,6 @@ "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", - "form_error_negative": "Trebuie să fie egală cu 0 sau mai mare", "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", @@ -201,6 +200,7 @@ "form_error_url_or_path_format": "Invalid URL sau o cale 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", "examples_title": "Exemple", "example_meaning_filter_block": "blochează accesul la domeniul exemplu.org și la toate subdomeniile sale", "example_meaning_filter_whitelist": "deblochează accesul la domeniul exemplu.org și la toate subdomeniile sale", @@ -624,5 +624,7 @@ "filter_allowlist": "AVERTISMENT: Această acțiune va exclude și regula „{{disallowed_rule}}” din lista de clienți permiși.", "last_rule_in_allowlist": "Acest client nu poate fi exclus deoarece excluderea regulii „{{disallowed_rule}}” va DEZACTIVA lista „Clienți acceptați”.", "experimental": "Experimental", - "use_saved_key": "Folosiți cheia salvată anterior" + "use_saved_key": "Folosiți cheia salvată anterior", + "parental_control": "Control parental", + "safe_browsing": "Navigare sigura" } diff --git a/client/src/__locales/ru.json b/client/src/__locales/ru.json index 73dc1a27..15fc274c 100644 --- a/client/src/__locales/ru.json +++ b/client/src/__locales/ru.json @@ -47,7 +47,6 @@ "form_error_server_name": "Некорректное имя сервера", "form_error_subnet": "Подсеть «{{cidr}}» не содержит IP-адрес «{{ip}}»", "form_error_positive": "Должно быть больше 0", - "form_error_negative": "Должно быть не меньше 0", "out_of_range_error": "Должно быть вне диапазона «{{start}}»-«{{end}}»", "lower_range_start_error": "Должно быть меньше начала диапазона", "greater_range_start_error": "Должно быть больше начала диапазона", @@ -201,6 +200,7 @@ "form_error_url_or_path_format": "Некорректный URL или абсолютный путь к списку", "custom_filter_rules": "Пользовательское правило фильтрации", "custom_filter_rules_hint": "Вводите по одному правилу на строчку. Вы можете использовать правила блокировки или синтаксис файлов hosts.", + "system_host_files": "Системные hosts-файлы", "examples_title": "Примеры", "example_meaning_filter_block": "заблокировать доступ к домену example.org и всем его поддоменам", "example_meaning_filter_whitelist": "разблокировать доступ к домену example.org и всем его поддоменам", @@ -463,15 +463,15 @@ "setup_dns_privacy_other_5": "Вы можете найти ещё варианты <0>тут и <1>тут.", "setup_dns_privacy_ioc_mac": "Конфигурация для iOS и macOS", "setup_dns_notice": "Чтобы использовать <1>DNS-over-HTTPS или <1>DNS-over-TLS, вам нужно <0>настроить шифрование в настройках AdGuard Home.", - "rewrite_added": "Правило перенаправления DNS для «{{key}}» успешно добавлено", - "rewrite_deleted": "Правило перенаправления DNS для «{{key}}» успешно удалено", - "rewrite_add": "Добавить правило перенаправления DNS", - "rewrite_not_found": "Не найдено правил перенаправления DNS", - "rewrite_confirm_delete": "Вы уверены, что хотите удалить правило перенаправления DNS для «{{key}}»?", + "rewrite_added": "Правило перезаписи DNS-запросов для «{{key}}» успешно добавлено", + "rewrite_deleted": "Правило перезаписи DNS-запросов для «{{key}}» успешно удалено", + "rewrite_add": "Добавить правило перезаписи DNS-запросов", + "rewrite_not_found": "Не найдено правил перезаписи DNS-запросов", + "rewrite_confirm_delete": "Вы уверены, что хотите удалить правило перезаписи DNS-запросов для «{{key}}»?", "rewrite_desc": "Позволяет легко настроить пользовательский DNS-ответ для определеннного домена.", - "rewrite_applied": "Применено правило перенаправления", + "rewrite_applied": "Применено правило перезаписи", "rewrite_hosts_applied": "Переписано по правилу файла hosts", - "dns_rewrites": "Перенаправления DNS", + "dns_rewrites": "Перезапись DNS-запросов", "form_domain": "Введите домен", "form_answer": "Введите IP адрес или домен", "form_error_domain_format": "Некорректный домен", @@ -537,9 +537,9 @@ "blocked_by_cname_or_ip": "Заблокировано с помощью CNAME или IP", "try_again": "Попробовать ещё раз", "domain_desc": "Введите имя или маску домена, который вы хотите перенаправить.", - "example_rewrite_domain": "перенаправляет ответы только для этого домена.", - "example_rewrite_wildcard": "перенаправляет ответы для всех поддоменов <0>example.org.", - "rewrite_ip_address": "IP-адрес: используйте этот IP для А или АААА ответов", + "example_rewrite_domain": "переписывать ответы только для этого домена.", + "example_rewrite_wildcard": "переписывать ответы для всех поддоменов <0>example.org.", + "rewrite_ip_address": "IP-адрес: использовать этот IP для А или АААА ответов", "rewrite_domain_name": "Доменное имя: добавить запись CNAME", "rewrite_A": "<0>A: специальное значение, хранить записи <0>A с upstream-сервера", "rewrite_AAAA": "<0>AAAA: специальное значение, хранить записи <0>AAAA с upstream-сервера", @@ -624,5 +624,8 @@ "filter_allowlist": "ВНИМАНИЕ: Это действие также исключит правило «{{disallowed_rule}}» из списка разрешённых клиентов.", "last_rule_in_allowlist": "Нельзя заблокировать этого клиента, так как исключение правила «{{disallowed_rule}}» ОТКЛЮЧИТ режим белого списка.", "experimental": "Экспериментальный", - "use_saved_key": "Использовать сохранённый ранее ключ" + "use_saved_key": "Использовать сохранённый ранее ключ", + "parental_control": "Родительский контроль", + "safe_browsing": "Безопасный интернет", + "served_from_cache": "{{value}} (получено из кеша)" } diff --git a/client/src/__locales/sk.json b/client/src/__locales/sk.json index 8b2c9ed8..80a23c77 100644 --- a/client/src/__locales/sk.json +++ b/client/src/__locales/sk.json @@ -47,7 +47,6 @@ "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", - "form_error_negative": "Musí byť číslo 0 alebo viac", "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", @@ -201,6 +200,7 @@ "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", "examples_title": "Príklady", "example_meaning_filter_block": "zablokovať prístup k doméne example.org a všetkým jej subdoménam", "example_meaning_filter_whitelist": "odblokovať prístup k doméne example.org a všetkým jej subdoménam", @@ -624,5 +624,8 @@ "filter_allowlist": "UPOZORNENIE: Táto akcia tiež vylúči pravidlo \"\"{{disallowed_rule}}\"\" zo zoznamu povolených klientov.", "last_rule_in_allowlist": "Nemôžete zakázať tohto klienta, pretože vylúčenie pravidla \"{{disallowed_rule}}\" zakáže zoznam \"povolených klientov\".", "experimental": "Experimentálne", - "use_saved_key": "Použiť predtým uložený kľúč" + "use_saved_key": "Použiť predtým uložený kľúč", + "parental_control": "Rodičovská kontrola", + "safe_browsing": "Bezpečné prehliadanie", + "served_from_cache": "{{value}} (prevzatá z cache pamäte)" } diff --git a/client/src/__locales/sl.json b/client/src/__locales/sl.json index cd7ebe21..9c9fa766 100644 --- a/client/src/__locales/sl.json +++ b/client/src/__locales/sl.json @@ -47,7 +47,6 @@ "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", - "form_error_negative": "Mora biti enako ali več kot 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", @@ -201,6 +200,7 @@ "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.", + "system_host_files": "Sistemske gostiteljske datooteke", "examples_title": "Primeri", "example_meaning_filter_block": "onemogoči dostop do domene example.org in vseh njenih poddomen", "example_meaning_filter_whitelist": "omogoči dostop do domene example.org in vseh njenih poddomen", @@ -624,5 +624,8 @@ "filter_allowlist": "OPOZORILO: S to akcijo bo pravilo \"{{disallowed_rule}}\" izključeno s seznama dovoljenih odjemalcev.", "last_rule_in_allowlist": "Tega odjemalca ni mogoče onemogočiti, ker izključitev pravila \"{{disallowed_rule}}\" bo ONEMOGOČILO seznam 'Dovoljeni odjemalci'.", "experimental": "Eksperimentalno", - "use_saved_key": "Uporabi prej shranjeni ključ" + "use_saved_key": "Uporabi prej shranjeni ključ", + "parental_control": "Starševski nadzor", + "safe_browsing": "Varno brskanje", + "served_from_cache": "{{value}} (postreženo iz predpomnilnika)" } diff --git a/client/src/__locales/sr-cs.json b/client/src/__locales/sr-cs.json index a902c929..082e031f 100644 --- a/client/src/__locales/sr-cs.json +++ b/client/src/__locales/sr-cs.json @@ -26,7 +26,6 @@ "form_error_mac_format": "Nevažeći MAC format", "form_error_client_id_format": "Nevažeći format klijenta", "form_error_positive": "Mora biti veće od 0", - "form_error_negative": "Mora biti 0 ili veće", "dhcp_form_gateway_input": "IP mrežnog prolaza", "dhcp_form_subnet_input": "Subnet mask", "dhcp_form_range_title": "Opseg IP adresa", @@ -551,5 +550,6 @@ "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.", - "experimental": "Eksperimentalno" + "experimental": "Eksperimentalno", + "parental_control": "Roditeljska kontrola" } diff --git a/client/src/__locales/sv.json b/client/src/__locales/sv.json index a021f67e..5e50e357 100644 --- a/client/src/__locales/sv.json +++ b/client/src/__locales/sv.json @@ -358,6 +358,7 @@ "safe_search": "Säker surf", "filter_category_general": "General", "filter_category_security": "säkerhet", - "filter_category_other": "Annat", - "use_saved_key": "Använd den tidigare sparade nyckeln" + "filter_category_other": "Övrigt", + "use_saved_key": "Använd den tidigare sparade nyckeln", + "parental_control": "Föräldrakontroll" } diff --git a/client/src/__locales/th.json b/client/src/__locales/th.json index 14e69757..f76fbaff 100644 --- a/client/src/__locales/th.json +++ b/client/src/__locales/th.json @@ -20,7 +20,6 @@ "form_error_mac_format": "รูปแบบ MAC ไม่ถูกต้อง", "form_error_client_id_format": "รูปแบบ ID ลูกค้าไม่ถูกต้อง", "form_error_positive": "ต้องมากกว่า 0", - "form_error_negative": "ต้องเท่ากับ 0 หรือมากกว่า", "dhcp_form_gateway_input": "IP ของเกตเวย์", "dhcp_form_subnet_input": "ซับเน็ตมาสก์", "dhcp_form_range_title": "ช่วงของที่อยู่ IP", @@ -392,5 +391,6 @@ "form_enter_host": "ป้อนชื่อโฮสต์", "show_processed_responses": "การประมวลผล", "safe_search": "ค้นหาอย่างปลอดภัย", - "filter_category_other": "อื่น ๆ" + "filter_category_other": "อื่น ๆ", + "parental_control": "ควบคุมโดยผู้ปกครอง" } diff --git a/client/src/__locales/tr.json b/client/src/__locales/tr.json index a2e2e518..36059379 100644 --- a/client/src/__locales/tr.json +++ b/client/src/__locales/tr.json @@ -7,7 +7,7 @@ "load_balancing": "Yük dengeleme", "load_balancing_desc": "Her seferde bir üst sunucuyu sorgulayın. AdGuard Home, sunucuyu seçmek için ağırlıklı rastgele algoritmasını kullanır, böylece en hızlı sunucu daha sık kullanılır.", "bootstrap_dns": "DNS Önyükleme sunucuları", - "bootstrap_dns_desc": "DNS Önyükleme sunucuları, belirttiğiniz üst sunucuların DoH/DoT çözücülerine ait IP adreslerinin çözülmesi için kullanılır.", + "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_default_resolver": "AdGuard Home, varsayılan olarak aşağıdaki ters DNS çözümleyicilerini kullanır: {{ip}}.", @@ -36,18 +36,17 @@ "dhcp_ipv4_settings": "DHCP IPv4 Ayarları", "dhcp_ipv6_settings": "DHCP IPv6 Ayarları", "form_error_required": "Gerekli alan", - "form_error_ip4_format": "Geçersiz IPv4 adresi", + "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": "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": "Geçersiz istemci kimliği", - "form_error_server_name": "Geçersiz sunucu adı", + "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 geçersiz", + "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", - "form_error_negative": "0 veya daha 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", @@ -197,10 +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": "Geçersiz URL biçimi", + "form_error_url_format": "URL biçimi geçersiz", "form_error_url_or_path_format": "Listenin URL adresi veya dosya konumu geçersiz", "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ı", "examples_title": "Örnekler", "example_meaning_filter_block": "example.org alan adına ve tüm alt alan adlarına olan erişimi engeller", "example_meaning_filter_whitelist": "example.org alan adına ve tüm alt alan adlarına olan erişim engelini kaldırır", @@ -474,8 +474,8 @@ "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": "Geçersiz alan adı biçimi", - "form_error_answer_format": "Geçersiz yanıt biçimi", + "form_error_domain_format": "Alan adı biçimi geçersiz", + "form_error_answer_format": "Yanıt biçimi geçersiz", "configure": "Yapılandır", "main_settings": "Ana ayarlar", "block_services": "Belirli hizmetleri engelle", @@ -624,5 +624,7 @@ "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.", "experimental": "Deneysel", - "use_saved_key": "Önceden kaydedilmiş anahtarı kullan" + "use_saved_key": "Önceden kaydedilmiş anahtarı kullan", + "parental_control": "Ebeveyn denetimi", + "safe_browsing": "Güvenli gezinti" } diff --git a/client/src/__locales/uk.json b/client/src/__locales/uk.json index c8e14d6b..a7adcbd3 100644 --- a/client/src/__locales/uk.json +++ b/client/src/__locales/uk.json @@ -47,7 +47,6 @@ "form_error_server_name": "Неправильна назва сервера", "form_error_subnet": "Підмережа «{{cidr}}» не містить IP-адресу «{{ip}}»", "form_error_positive": "Повинно бути більше 0", - "form_error_negative": "Повинно дорівнювати 0 або більше", "out_of_range_error": "Не повинна бути в діапазоні «{{start}}»−«{{end}}»", "lower_range_start_error": "Має бути меншим за початкову адресу", "greater_range_start_error": "Має бути більшим за початкову адресу", @@ -104,7 +103,7 @@ "on": "УВІМК", "off": "ВИМК", "copyright": "Авторське право", - "homepage": "Домівка", + "homepage": "Домашня сторінка", "report_an_issue": "Повідомити про проблему", "privacy_policy": "Політика приватності", "enable_protection": "Увімкнути захист", @@ -201,6 +200,7 @@ "form_error_url_or_path_format": "Помилкова URL-адреса чи абсолютний шлях до списку", "custom_filter_rules": "Власні правила фільтрування", "custom_filter_rules_hint": "Вводьте одне правило на рядок. Ви можете використовувати правила блокування чи синтаксис файлів hosts.", + "system_host_files": "Системні hosts-файли", "examples_title": "Зразки", "example_meaning_filter_block": "блокує доступ до домену example.org та всіх його піддоменів", "example_meaning_filter_whitelist": "розблоковує доступ до домену example.org та всіх його піддоменів", @@ -624,5 +624,8 @@ "filter_allowlist": "ПОПЕРЕДЖЕННЯ: Таким чином ви також виключите правило «{{disallowed_rule}}» зі списку дозволених клієнтів.", "last_rule_in_allowlist": "Неможливо заблокувати цього клієнта, тому що правило «{{disallowed_rule}}» ВИМКНЕ режим списку дозволів.", "experimental": "Експериментальний", - "use_saved_key": "Використати раніше збережений ключ" + "use_saved_key": "Використати раніше збережений ключ", + "parental_control": "Батьківський контроль", + "safe_browsing": "Безпечний інтернет", + "served_from_cache": "{{value}} (отримано з кешу)" } diff --git a/client/src/__locales/vi.json b/client/src/__locales/vi.json index 7fbc82a4..7f24b861 100644 --- a/client/src/__locales/vi.json +++ b/client/src/__locales/vi.json @@ -44,7 +44,6 @@ "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", - "form_error_negative": "Phải lớn hơn hoặc bằng 0", "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", @@ -612,5 +611,6 @@ "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\".", - "experimental": "Thử nghiệm" + "experimental": "Thử nghiệm", + "parental_control": "Quản lý của phụ huynh" } diff --git a/client/src/__locales/zh-cn.json b/client/src/__locales/zh-cn.json index cbb94485..b434c6ed 100644 --- a/client/src/__locales/zh-cn.json +++ b/client/src/__locales/zh-cn.json @@ -36,15 +36,23 @@ "dhcp_ipv4_settings": "DHCP IPv4设置", "dhcp_ipv6_settings": "DHCP IPv6设置", "form_error_required": "必填字段", - "form_error_ip4_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_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", - "form_error_negative": "必须大于等于 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 地址范围", @@ -192,6 +200,7 @@ "form_error_url_or_path_format": "无效的URL或列表的绝对路径", "custom_filter_rules": "自定义过滤器规则", "custom_filter_rules_hint": "请确保每行只输入一条规则。你可以输入符合 adblock 语法或 Hosts 语法的规则。", + "system_host_files": "系统主机文件", "examples_title": "范例", "example_meaning_filter_block": "拦截 example.org 域名及其所有子域名", "example_meaning_filter_whitelist": "放行 example.org 及其所有子域名", @@ -615,5 +624,8 @@ "filter_allowlist": "警告:此操作将把规则 \"{{disallowed_rule}}\" 排除在允许客户端的列表之外。", "last_rule_in_allowlist": "无法禁止此客户端,因为排除 “{{disallowed_rule}}” 规则将禁用“允许客户端”的列表。", "experimental": "实验性的", - "use_saved_key": "使用之前保存的密钥" + "use_saved_key": "使用之前保存的密钥", + "parental_control": "家长控制", + "safe_browsing": "安全浏览", + "served_from_cache": "{{value}}(由缓存提供)" } diff --git a/client/src/__locales/zh-hk.json b/client/src/__locales/zh-hk.json index d6745fa9..a60ceab1 100644 --- a/client/src/__locales/zh-hk.json +++ b/client/src/__locales/zh-hk.json @@ -44,7 +44,6 @@ "form_error_server_name": "無效伺服器名稱", "form_error_subnet": "子網路 \"{{cidr}}\" 不包含 IP 位址 \"{{ip}}\"", "form_error_positive": "數值必須大於 0", - "form_error_negative": "數值必須大於等於 0", "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 18424502..66c4ce35 100644 --- a/client/src/__locales/zh-tw.json +++ b/client/src/__locales/zh-tw.json @@ -47,7 +47,6 @@ "form_error_server_name": "無效的伺服器名稱", "form_error_subnet": "子網路 \"{{cidr}}\" 不包含該 IP 位址 \"{{ip}}\"", "form_error_positive": "必須大於 0", - "form_error_negative": "必須等於或大於 0", "out_of_range_error": "必須在\"{{start}}\"-\"{{end}}\"範圍之外", "lower_range_start_error": "必須低於起始範圍", "greater_range_start_error": "必須大於起始範圍", @@ -201,6 +200,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 網域及其所有的子網域之存取", @@ -328,7 +328,7 @@ "install_devices_router": "路由器", "install_devices_router_desc": "此設置將自動地涵蓋所有被連線到您的家庭路由器之裝置,而您將無需手動地配置它們。", "install_devices_address": "AdGuard Home DNS 伺服器正在監聽下列的位址", - "install_devices_router_list_1": "開啟用於您的路由器之偏好設定。通常地,您可透過網址,諸如 http://192.168.0.1/ 或 http://192.168.1.1/,從您的瀏覽器中存取它。您可能被提醒輸入密碼。如果您不記得它,您經常可透過按壓於該路由器本身上的按鈕來重置密碼,但請明白如果此步驟被選擇,您將可能失去整個路由器配置。如果您的路由器需要應用程式去設置它,請於您的手機或個人電腦上安裝該應用程式,並使用它來存取該路由器的設定。", + "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 作為 <0>DHCP 伺服器可能有所幫助。否則,您應查明有關如何對您的特定路由器型號自訂 DNS 伺服器之路由器用法說明。", @@ -624,5 +624,8 @@ "filter_allowlist": "警告:此操作將把 \"{{disallowed_rule}}\" 規則排除在已允許用戶端的清單之外。", "last_rule_in_allowlist": "無法禁止此用戶端,因為排除 “{{disallowed_rule}}” 規則將禁用“已允許用戶端”的清單。", "experimental": "實驗性的", - "use_saved_key": "使用該先前已儲存的金鑰" + "use_saved_key": "使用該先前已儲存的金鑰", + "parental_control": "家長監控", + "safe_browsing": "安全瀏覽", + "served_from_cache": "{{value}} (由快取提供)" } From 72db014905561ba9c539b97641c66800c3a1aaa2 Mon Sep 17 00:00:00 2001 From: Andrey Meshkov Date: Wed, 15 Dec 2021 16:44:28 +0300 Subject: [PATCH 053/135] Pull request: added companiesdb script, fix #2793 Merge in DNS/adguard-home from 2793-whotracksme to master Squashed commit of the following: commit eff9de98b389ba087eb529c12e3ec916842aa8c3 Merge: bf9bc6a4 49eb62ae Author: Andrey Meshkov Date: Wed Dec 15 16:38:53 2021 +0300 Merge branch 'master' into 2793-whotracksme commit bf9bc6a4f5c1d7e4b6265f1c33bd532ec5b58cc7 Author: Andrey Meshkov Date: Wed Dec 15 16:04:57 2021 +0300 scripts: fix review comments commit 5a035cabc1a75a3c750a4a7a36af38ad9f33959b Author: Andrey Meshkov Date: Wed Dec 15 15:47:41 2021 +0300 added companiesdb script, fix #2793 --- README.md | 16 +- client/src/helpers/trackers/adguard.json | 3 +- client/src/helpers/trackers/whotracksme.json | 3024 +++++++++--------- scripts/README.md | 12 +- scripts/companiesdb/download.sh | 14 + scripts/whotracksme/.gitignore | 2 - scripts/whotracksme/index.js | 101 - scripts/whotracksme/package.json | 15 - scripts/whotracksme/yarn.lock | 698 ---- 9 files changed, 1546 insertions(+), 2339 deletions(-) create mode 100755 scripts/companiesdb/download.sh delete mode 100644 scripts/whotracksme/.gitignore delete mode 100644 scripts/whotracksme/index.js delete mode 100644 scripts/whotracksme/package.json delete mode 100644 scripts/whotracksme/yarn.lock diff --git a/README.md b/README.md index 5e411885..e50bac89 100644 --- a/README.md +++ b/README.md @@ -322,10 +322,18 @@ Here is a link to AdGuard Home project: https://crowdin.com/project/adguard-appl Here's what you can also do to contribute: -1. [Look for issues](https://github.com/AdguardTeam/AdGuardHome/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22+) marked as "help wanted". -2. Actualize the list of *Blocked services*. It can be found in [filtering/blocked.go](https://github.com/AdguardTeam/AdGuardHome/blob/master/internal/filtering/blocked.go). -3. Actualize the list of known *trackers*. It it can be found in [client/src/helpers/trackers/adguard.json](https://github.com/AdguardTeam/AdGuardHome/blob/master/client/src/helpers/trackers/adguard.json). -4. Actualize the list of vetted *blocklists*. It it can be found in [client/src/helpers/filters/filters.json](https://github.com/AdguardTeam/AdGuardHome/blob/master/client/src/helpers/filters/filters.json). +1. [Look for issues][helpissues] marked as "help wanted". +2. Actualize the list of *Blocked services*. It can be found in + [filtering/blocked.go][blocked.go]. +3. Actualize the list of known *trackers*. It it can be found in [this repo] + [companiesdb]. +4. Actualize the list of vetted *blocklists*. It it can be found in + [client/src/helpers/filters/filters.json][filters.json]. + +[helpissues]: https://github.com/AdguardTeam/AdGuardHome/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22+ +[blocked.go]: https://github.com/AdguardTeam/AdGuardHome/blob/master/internal/filtering/blocked.go +[companiesdb]: https://github.com/AdguardTeam/companiesdb +[filters.json]: https://github.com/AdguardTeam/AdGuardHome/blob/master/client/src/helpers/filters/filters.json ## Projects that use AdGuard Home diff --git a/client/src/helpers/trackers/adguard.json b/client/src/helpers/trackers/adguard.json index 3fb582b1..82831aef 100644 --- a/client/src/helpers/trackers/adguard.json +++ b/client/src/helpers/trackers/adguard.json @@ -1,5 +1,5 @@ { - "timeUpdated": "2018-10-14", + "timeUpdated": "2021-12-15", "categories": { "0": "audio_video_player", "1": "comments", @@ -14,6 +14,7 @@ "10": "hosting", "11": "unknown", "12": "extensions", + "13": "email", "101": "mobile_analytics" }, "trackers": { diff --git a/client/src/helpers/trackers/whotracksme.json b/client/src/helpers/trackers/whotracksme.json index 2185a60c..26e4327d 100644 --- a/client/src/helpers/trackers/whotracksme.json +++ b/client/src/helpers/trackers/whotracksme.json @@ -1,5 +1,5 @@ { - "timeUpdated": "2020-01-30T15:39:59.447Z", + "timeUpdated": "2021-12-15T12:50:00.512Z", "categories": { "0": "audio_video_player", "1": "comments", @@ -13,7 +13,8 @@ "9": "cdn", "10": "hosting", "11": "unknown", - "12": "extensions" + "12": "extensions", + "13": "email" }, "trackers": { "163": { @@ -66,6 +67,11 @@ "categoryId": 4, "url": "http://www.24-ads.com/" }, + "24_7": { + "name": "[24]7", + "categoryId": 2, + "url": "http://www.247-inc.com/" + }, "24log": { "name": "24log", "categoryId": 6, @@ -76,11 +82,6 @@ "categoryId": 8, "url": "https://24smi.org/" }, - "24_7": { - "name": "[24]7", - "categoryId": 2, - "url": "http://www.247-inc.com/" - }, "2leep": { "name": "2leep", "categoryId": 4, @@ -176,16 +177,16 @@ "categoryId": 4, "url": "https://aax.media/" }, - "ablida": { - "name": "ablida", - "categoryId": 4, - "url": "https://www.ablida.de/" - }, "ab_tasty": { "name": "AB Tasty", "categoryId": 6, "url": "https://en.abtasty.com" }, + "ablida": { + "name": "ablida", + "categoryId": 4, + "url": "https://www.ablida.de/" + }, "accelia": { "name": "Accelia", "categoryId": 4, @@ -206,16 +207,16 @@ "categoryId": 4, "url": "http://accesstrade.net/" }, - "accordant_media": { - "name": "Accordant Media", - "categoryId": 4, - "url": "http://www.accordantmedia.com/" - }, "accord_group": { "name": "Accord Group", "categoryId": 4, "url": "http://www.accordgroup.co.uk/" }, + "accordant_media": { + "name": "Accordant Media", + "categoryId": 4, + "url": "http://www.accordantmedia.com/" + }, "accuen_media": { "name": "Accuen Media", "categoryId": 4, @@ -256,6 +257,21 @@ "categoryId": 4, "url": "http://actionpay.ru/" }, + "active_agent": { + "name": "Active Agent", + "categoryId": 4, + "url": "http://www.active-agent.com/" + }, + "active_campaign": { + "name": "Active Campaign", + "categoryId": 6, + "url": "https://www.activecampaign.com" + }, + "active_performance": { + "name": "Active Performance", + "categoryId": 4, + "url": "http://www.active-performance.de/" + }, "activeconversion": { "name": "ActiveConversion", "categoryId": 4, @@ -276,21 +292,6 @@ "categoryId": 2, "url": "http://www.activengage.com" }, - "active_agent": { - "name": "Active Agent", - "categoryId": 4, - "url": "http://www.active-agent.com/" - }, - "active_campaign": { - "name": "Active Campaign", - "categoryId": 6, - "url": "https://www.activecampaign.com" - }, - "active_performance": { - "name": "Active Performance", - "categoryId": 4, - "url": "http://www.active-performance.de/" - }, "acton": { "name": "Act-On Beacon", "categoryId": 4, @@ -304,7 +305,7 @@ "acxiom": { "name": "Acxiom", "categoryId": 4, - "url": "https://www.acxiom.com/" + "url": "http://www.acxiom.com" }, "ad-blocker.org": { "name": "ad-blocker.org", @@ -361,16 +362,46 @@ "categoryId": 4, "url": "https://www.ad6media.fr/" }, - "adacado": { - "name": "Adacado", + "ad_decisive": { + "name": "Ad Decisive", "categoryId": 4, - "url": "http://www.adacado.com/" + "url": "http://www.lagardere-global-advertising.com/" + }, + "ad_dynamo": { + "name": "Ad Dynamo", + "categoryId": 4, + "url": "http://www.addynamo.com/" + }, + "ad_ebis": { + "name": "AD EBiS", + "categoryId": 4, + "url": "http://www.ebis.ne.jp/en/" + }, + "ad_lightning": { + "name": "Ad Lightning", + "categoryId": 4, + "url": "https://www.adlightning.com/" + }, + "ad_magnet": { + "name": "Ad Magnet", + "categoryId": 4, + "url": "http://www.admagnet.com/" + }, + "ad_spirit": { + "name": "Ad Spirit", + "categoryId": 4, + "url": "http://www.adspirit.de" }, "adac_de": { "name": "adac.de", "categoryId": 8, "url": "http://adac.de/" }, + "adacado": { + "name": "Adacado", + "categoryId": 4, + "url": "http://www.adacado.com/" + }, "adadyn": { "name": "Adadyn", "categoryId": 4, @@ -461,6 +492,11 @@ "categoryId": 4, "url": "https://www.adbutler.com/d" }, + "adc_media": { + "name": "ad:C media", + "categoryId": 4, + "url": "http://www.adcmedia.de/en/" + }, "adcash": { "name": "Adcash", "categoryId": 4, @@ -526,10 +562,10 @@ "categoryId": 4, "url": "http://www.shop2market.com/" }, - "adc_media": { - "name": "ad:C media", - "categoryId": 4, - "url": "http://www.adcmedia.de/en/" + "add_to_calendar": { + "name": "Add To Calendar", + "categoryId": 2, + "url": "http://addtocalendar.com/" }, "addaptive": { "name": "Addaptive", @@ -571,11 +607,6 @@ "categoryId": 4, "url": "http://www.addyon.com/homepage.php" }, - "add_to_calendar": { - "name": "Add To Calendar", - "categoryId": 2, - "url": "http://addtocalendar.com/" - }, "adeasy": { "name": "AdEasy", "categoryId": 4, @@ -696,6 +727,11 @@ "categoryId": 4, "url": "http://adgoto.com/" }, + "adguard": { + "name": "Adguard", + "categoryId": 12, + "url": "https://adguard.com/" + }, "adhands": { "name": "AdHands", "categoryId": 4, @@ -826,16 +862,16 @@ "categoryId": 4, "url": "http://www.adman.gr/" }, - "admantx.com": { - "name": "ADmantX", - "categoryId": 4, - "url": "http://www.admantx.com/" - }, "adman_media": { "name": "ADman Media", "categoryId": 4, "url": "http://www.admanmedia.com/" }, + "admantx.com": { + "name": "ADmantX", + "categoryId": 4, + "url": "http://www.admantx.com/" + }, "admaster": { "name": "AdMaster", "categoryId": 4, @@ -961,6 +997,11 @@ "categoryId": 4, "url": "http://www.adnet.de" }, + "adnet_media": { + "name": "Adnet Media", + "categoryId": 4, + "url": "http://www.adnetmedia.lt/" + }, "adnetwork.net": { "name": "AdNetwork.net", "categoryId": 4, @@ -971,11 +1012,6 @@ "categoryId": 11, "url": null }, - "adnet_media": { - "name": "Adnet Media", - "categoryId": 4, - "url": "http://www.adnetmedia.lt/" - }, "adnexio": { "name": "AdNexio", "categoryId": 4, @@ -1006,11 +1042,21 @@ "categoryId": 4, "url": "http://www.demdex.com/" }, + "adobe_dynamic_media": { + "name": "Adobe Dynamic Media", + "categoryId": 4, + "url": "http://www.adobe.com/" + }, "adobe_dynamic_tag_management": { "name": "Adobe Dynamic Tag Management", "categoryId": 5, "url": "https://dtm.adobe.com/sign_in" }, + "adobe_experience_cloud": { + "name": "Adobe Experience Cloud", + "categoryId": 6, + "url": "https://www.adobe.com/experience-cloud.html" + }, "adobe_login": { "name": "Adobe Login", "categoryId": 2, @@ -1022,9 +1068,14 @@ "url": "https://www.adobe.com/" }, "adobe_test_and_target": { - "name": "Adobe Test & Target", + "name": "Adobe Target", "categoryId": 4, - "url": "http://www.adobe.com/" + "url": "https://www.adobe.com/marketing/target.html" + }, + "adobe_typekit": { + "name": "Adobe Typekit", + "categoryId": 5, + "url": "https://www.adobe.com/" }, "adocean": { "name": "AdOcean", @@ -1041,6 +1092,11 @@ "categoryId": 4, "url": null }, + "adon_network": { + "name": "AdOn Network", + "categoryId": 4, + "url": "http://www.adonnetwork.com/" + }, "adonion": { "name": "AdOnion", "categoryId": 4, @@ -1051,11 +1107,6 @@ "categoryId": 4, "url": "https://gloadmarket.com/" }, - "adon_network": { - "name": "AdOn Network", - "categoryId": 4, - "url": "http://www.adonnetwork.com/" - }, "adoperator": { "name": "AdOperator", "categoryId": 4, @@ -1401,16 +1452,16 @@ "categoryId": 4, "url": "http://adtube.ir/" }, - "adultadworld": { - "name": "AdultAdWorld", - "categoryId": 3, - "url": "http://adultadworld.com/" - }, "adult_webmaster_empire": { "name": "Adult Webmaster Empire", "categoryId": 3, "url": "http://www.awempire.com/" }, + "adultadworld": { + "name": "AdultAdWorld", + "categoryId": 3, + "url": "http://adultadworld.com/" + }, "adup-tech.com": { "name": "AdUp Technology", "categoryId": 4, @@ -1477,9 +1528,9 @@ "url": "http://www.advertisespace.com/" }, "advertising.com": { - "name": "Advertising.com", + "name": "Verizon Media", "categoryId": 4, - "url": "https://www.verizonmedia.com/insights/accessing-your-ad-platform-account" + "url": "https://www.verizonmedia.com/" }, "advertlets": { "name": "Advertlets", @@ -1496,11 +1547,6 @@ "categoryId": 4, "url": "http://advidi.com/" }, - "adview_(agora)": { - "name": "Adview (Agora)", - "categoryId": 4, - "url": "http://www.agora.pl/" - }, "advmaker.ru": { "name": "advmaker.ru", "categoryId": 4, @@ -1566,36 +1612,6 @@ "categoryId": 4, "url": "http://www.adzly.com/" }, - "ad_decisive": { - "name": "Ad Decisive", - "categoryId": 4, - "url": "http://www.lagardere-global-advertising.com/" - }, - "ad_dynamo": { - "name": "Ad Dynamo", - "categoryId": 4, - "url": "http://www.addynamo.com/" - }, - "ad_ebis": { - "name": "AD EBiS", - "categoryId": 4, - "url": "http://www.ebis.ne.jp/en/" - }, - "ad_lightning": { - "name": "Ad Lightning", - "categoryId": 4, - "url": "https://www.adlightning.com/" - }, - "ad_magnet": { - "name": "Ad Magnet", - "categoryId": 4, - "url": "http://www.admagnet.com/" - }, - "ad_spirit": { - "name": "Ad Spirit", - "categoryId": 4, - "url": "http://www.adspirit.de " - }, "aemediatraffic": { "name": "Aemediatraffic", "categoryId": 6, @@ -1608,18 +1624,13 @@ }, "aeris_weather": { "name": "Aeris Weather", - "categoryId": 4, - "url": "http://www.hamweather.com/" - }, - "affec.tv": { - "name": "Affec.tv", - "categoryId": 4, - "url": "https://affectv.com/" + "categoryId": 2, + "url": "https://www.aerisweather.com/" }, "affectv": { - "name": "Affectv", + "name": "Hybrid Theory", "categoryId": 4, - "url": "http://affectv.co.uk/" + "url": "https://hybridtheory.com/" }, "affiliate-b": { "name": "Affiliate-B", @@ -1726,21 +1737,26 @@ "categoryId": 6, "url": "http://www.agilone.com/" }, + "agora": { + "name": "Agora", + "categoryId": 4, + "url": "https://www.agora.pl/" + }, "ahalogy": { "name": "Ahalogy", "categoryId": 7, "url": "http://www.ahalogy.com/" }, + "ai_media_group": { + "name": "Ai Media Group", + "categoryId": 4, + "url": "http://aimediagroup.com/" + }, "aidata": { "name": "Aidata", "categoryId": 4, "url": "http://aidata.me/" }, - "aidata.io": { - "name": "AiData", - "categoryId": 4, - "url": "http://www.aidata.me/" - }, "aim4media": { "name": "Aim4Media", "categoryId": 4, @@ -1766,11 +1782,6 @@ "categoryId": 4, "url": "http://www.airpush.com/" }, - "ai_media_group": { - "name": "Ai Media Group", - "categoryId": 4, - "url": "http://aimediagroup.com/" - }, "akamai_technologies": { "name": "Akamai Technologies", "categoryId": 9, @@ -1796,6 +1807,11 @@ "categoryId": 4, "url": "http://www.akavita.by/en" }, + "al_bawaba_advertising": { + "name": "Al Bawaba Advertising", + "categoryId": 4, + "url": "http://www.albawaba.com/advertising" + }, "albacross": { "name": "Albacross", "categoryId": 4, @@ -1891,11 +1907,6 @@ "categoryId": 4, "url": "http://www.altitudedigital.com/" }, - "al_bawaba_advertising": { - "name": "Al Bawaba Advertising", - "categoryId": 4, - "url": "http://www.albawaba.com/advertising" - }, "amadesa": { "name": "Amadesa", "categoryId": 4, @@ -1966,6 +1977,11 @@ "categoryId": 4, "url": "https://www.amobee.com/" }, + "amp_platform": { + "name": "AMP Platform", + "categoryId": 4, + "url": "http://www.collective.com/" + }, "amplitude": { "name": "Amplitude", "categoryId": 6, @@ -1976,11 +1992,6 @@ "categoryId": 8, "url": "https://www.ampproject.org/" }, - "amp_platform": { - "name": "AMP Platform", - "categoryId": 4, - "url": "http://www.collective.com/" - }, "anametrix": { "name": "Anametrix", "categoryId": 6, @@ -2086,11 +2097,6 @@ "categoryId": 4, "url": "http://www.appier.com/en/index.html" }, - "apple": { - "name": "Apple", - "categoryId": 4, - "url": "http://www.apple.com/" - }, "applifier": { "name": "Applifier", "categoryId": 4, @@ -2141,6 +2147,11 @@ "categoryId": 6, "url": "https://areyouahuman.com/" }, + "arkoselabs.com": { + "name": "Arkose Labs", + "categoryId": 6, + "url": "https://www.arkoselabs.com/" + }, "art19": { "name": "Art19", "categoryId": 4, @@ -2186,6 +2197,11 @@ "categoryId": 6, "url": "https://www.astronomer.io" }, + "at_internet": { + "name": "AT Internet", + "categoryId": 6, + "url": "http://www.xiti.com/" + }, "atedra": { "name": "Atedra", "categoryId": 4, @@ -2211,6 +2227,11 @@ "categoryId": 4, "url": "https://atlassolutions.com" }, + "atlas_profitbuilder": { + "name": "Atlas ProfitBuilder", + "categoryId": 4, + "url": "http://www.atlassolutions.com/" + }, "atlassian.net": { "name": "Atlassian", "categoryId": 2, @@ -2221,11 +2242,6 @@ "categoryId": 9, "url": "https://marketplace.atlassian.com/" }, - "atlas_profitbuilder": { - "name": "Atlas ProfitBuilder", - "categoryId": 4, - "url": "http://www.atlassolutions.com/" - }, "atomz_search": { "name": "Atomz Search", "categoryId": 2, @@ -2234,7 +2250,7 @@ "atsfi_de": { "name": "atsfi.de", "categoryId": 11, - "url": null + "url": "http://www.axelspringer.de/en/index.html" }, "attracta": { "name": "Attracta", @@ -2246,26 +2262,11 @@ "categoryId": 6, "url": "http://www.locayta.com/" }, - "at_internet": { - "name": "AT Internet", - "categoryId": 6, - "url": "http://www.xiti.com/" - }, "audience2media": { "name": "Audience2Media", "categoryId": 4, "url": "http://www.audience2media.com/" }, - "audiencerate": { - "name": "AudienceRate", - "categoryId": 4, - "url": "http://www.audiencerate.com/" - }, - "audiencesquare.com": { - "name": "Audience Square", - "categoryId": 4, - "url": "http://www.audiencesquare.fr/" - }, "audience_ad_network": { "name": "Audience Ad Network", "categoryId": 4, @@ -2276,6 +2277,16 @@ "categoryId": 4, "url": "http://www.audiencescience.com/" }, + "audiencerate": { + "name": "AudienceRate", + "categoryId": 4, + "url": "http://www.audiencerate.com/" + }, + "audiencesquare.com": { + "name": "Audience Square", + "categoryId": 4, + "url": "http://www.audiencesquare.fr/" + }, "auditude": { "name": "Auditude", "categoryId": 0, @@ -2351,16 +2362,16 @@ "categoryId": 2, "url": "http://www.avanser.com.au/" }, - "avantlink": { - "name": "AvantLink", - "categoryId": 4, - "url": "http://www.avantlink.com/" - }, "avant_metrics": { "name": "Avant Metrics", "categoryId": 6, "url": "http://www.avantlink.com/" }, + "avantlink": { + "name": "AvantLink", + "categoryId": 4, + "url": "http://www.avantlink.com/" + }, "avazu_network": { "name": "Avazu Network", "categoryId": 4, @@ -2421,16 +2432,16 @@ "categoryId": 6, "url": "https://www.babator.com/" }, - "backtype_widgets": { - "name": "BackType Widgets", - "categoryId": 4, - "url": "http://www.backtype.com/widgets" - }, "back_beat_media": { "name": "Back Beat Media", "categoryId": 4, "url": "http://www.backbeatmedia.com" }, + "backtype_widgets": { + "name": "BackType Widgets", + "categoryId": 4, + "url": "http://www.backtype.com/widgets" + }, "bahn_de": { "name": "Deutsche Bahn", "categoryId": 8, @@ -2461,6 +2472,11 @@ "categoryId": 4, "url": "https://www.bankrate.com/" }, + "banner_connect": { + "name": "Banner Connect", + "categoryId": 4, + "url": "http://www.bannerconnect.net/" + }, "bannerflow.com": { "name": "Bannerflow", "categoryId": 4, @@ -2476,11 +2492,6 @@ "categoryId": 4, "url": "http://www.bannersnack.com/" }, - "banner_connect": { - "name": "Banner Connect", - "categoryId": 4, - "url": "http://www.bannerconnect.net/" - }, "barilliance": { "name": "Barilliance", "categoryId": 4, @@ -2536,6 +2547,11 @@ "categoryId": 4, "url": "https://bd4travel.com/" }, + "be_opinion": { + "name": "Be Opinion", + "categoryId": 2, + "url": "http://beopinion.com/" + }, "beachfront": { "name": "Beachfront Media", "categoryId": 4, @@ -2626,16 +2642,16 @@ "categoryId": 4, "url": "http://betweendigital.ru/ssp" }, - "be_opinion": { - "name": "Be Opinion", - "categoryId": 2, - "url": "http://beopinion.com/" - }, "bid.run": { "name": "Bid Run", "categoryId": 4, "url": "http://bid.run/" }, + "bidgear": { + "name": "BidGear", + "categoryId": 6, + "url": "https://bidgear.com/" + }, "bidswitch": { "name": "Bidswitch", "categoryId": 4, @@ -2656,6 +2672,11 @@ "categoryId": 4, "url": "http://www.bidvertiser.com/" }, + "big_mobile": { + "name": "Big Mobile", + "categoryId": 4, + "url": "http://www.bigmobile.com/" + }, "bigcommerce.com": { "name": "BigCommerce", "categoryId": 6, @@ -2671,11 +2692,6 @@ "categoryId": 8, "url": null }, - "big_mobile": { - "name": "Big Mobile", - "categoryId": 4, - "url": "http://www.bigmobile.com/" - }, "bild": { "name": "Bild.de", "categoryId": 8, @@ -2811,6 +2827,16 @@ "categoryId": 4, "url": "https://www.bloomreach.com/en" }, + "blue_cherry_group": { + "name": "Blue Cherry Group", + "categoryId": 4, + "url": "http://www.bluecherrygroup.com" + }, + "blue_seed": { + "name": "Blue Seed", + "categoryId": 4, + "url": "http://blueseed.tv/#/en/platform" + }, "blueconic.net": { "name": "BlueConic Plugin", "categoryId": 6, @@ -2851,21 +2877,16 @@ "categoryId": 6, "url": "https://www.bluetriangle.com/" }, - "blue_cherry_group": { - "name": "Blue Cherry Group", - "categoryId": 4, - "url": "http://www.bluecherrygroup.com" - }, - "blue_seed": { - "name": "Blue Seed", - "categoryId": 4, - "url": "http://blueseed.tv/#/en/platform" - }, "bodelen.com": { "name": "bodelen.com", "categoryId": 4, "url": null }, + "bol_affiliate_program": { + "name": "BOL Affiliate Program", + "categoryId": 4, + "url": "http://www.bol.com" + }, "bold": { "name": "Bold", "categoryId": 4, @@ -2881,11 +2902,6 @@ "categoryId": 11, "url": null }, - "bol_affiliate_program": { - "name": "BOL Affiliate Program", - "categoryId": 4, - "url": "http://www.bol.com" - }, "bombora": { "name": "Bombora", "categoryId": 6, @@ -2911,16 +2927,16 @@ "categoryId": 8, "url": null }, - "booster_video": { - "name": "Booster Video", - "categoryId": 0, - "url": "https://boostervideo.ru/" - }, "boost_box": { "name": "Boost Box", "categoryId": 6, "url": "http://www.boostbox.com.br/" }, + "booster_video": { + "name": "Booster Video", + "categoryId": 0, + "url": "https://boostervideo.ru/" + }, "bootstrap": { "name": "Bootstrap CDN", "categoryId": 9, @@ -2941,26 +2957,26 @@ "categoryId": 11, "url": null }, - "bouncex": { - "name": "BounceX", - "categoryId": 4, - "url": "https://www.bouncex.com/" - }, "bounce_exchange": { "name": "Bounce Exchange", "categoryId": 4, "url": "http://bounceexchange.com" }, - "boxever": { - "name": "Boxever", + "bouncex": { + "name": "BounceX", "categoryId": 4, - "url": "https://www.boxever.com/" + "url": "https://www.bouncex.com/" }, "box_uk": { "name": "Box UK", "categoryId": 6, "url": "http://www.clickdensity.com" }, + "boxever": { + "name": "Boxever", + "categoryId": 4, + "url": "https://www.boxever.com/" + }, "brainient": { "name": "Brainient", "categoryId": 4, @@ -2976,6 +2992,16 @@ "categoryId": 4, "url": "https://branch.io/" }, + "brand_affinity": { + "name": "Brand Affinity", + "categoryId": 4, + "url": "http://brandaffinity.net/about" + }, + "brand_networks": { + "name": "Brand Networks", + "categoryId": 4, + "url": "http://www.xa.net/" + }, "brandmetrics.com": { "name": "Brandmetrics.com", "categoryId": 4, @@ -2996,16 +3022,6 @@ "categoryId": 4, "url": "https://brandwire.tv/" }, - "brand_affinity": { - "name": "Brand Affinity", - "categoryId": 4, - "url": "http://brandaffinity.net/about " - }, - "brand_networks": { - "name": "Brand Networks", - "categoryId": 4, - "url": "http://www.xa.net/" - }, "branica": { "name": "Branica", "categoryId": 4, @@ -3096,11 +3112,6 @@ "categoryId": 9, "url": null }, - "btttag.com": { - "name": "Btttag", - "categoryId": 6, - "url": "https://www.bluetriangletech.com/" - }, "bubblestat": { "name": "Bubblestat", "categoryId": 4, @@ -3221,6 +3232,11 @@ "categoryId": 4, "url": "http://www.cadreon.com/" }, + "call_page": { + "name": "Call Page", + "categoryId": 2, + "url": "https://www.callpage.io/" + }, "callbackhunter": { "name": "CallbackHunter", "categoryId": 2, @@ -3246,11 +3262,6 @@ "categoryId": 2, "url": "https://calltracking.ru" }, - "call_page": { - "name": "Call Page", - "categoryId": 2, - "url": "https://www.callpage.io/" - }, "caltat.com": { "name": "Caltat", "categoryId": 2, @@ -3311,6 +3322,11 @@ "categoryId": 4, "url": "https://www.carbonads.net/" }, + "cardinal": { + "name": "Cardinal", + "categoryId": 6, + "url": "https://www.cardinalcommerce.com/" + }, "cardlytics": { "name": "Cardlytics", "categoryId": 6, @@ -3346,11 +3362,6 @@ "categoryId": 2, "url": "http://cbox.ws" }, - "cbsi.com": { - "name": "CBS Interactive", - "categoryId": 8, - "url": "https://www.cbsinteractive.com/" - }, "cbs_interactive": { "name": "CBS Interactive", "categoryId": 0, @@ -3471,16 +3482,6 @@ "categoryId": 4, "url": "http://www.chango.com/" }, - "channeladvisor": { - "name": "ChannelAdvisor", - "categoryId": 4, - "url": "http://www.channeladvisor.com/" - }, - "channelfinder": { - "name": "ChannelFinder", - "categoryId": 4, - "url": "http://www.kpicentral.com/" - }, "channel_intelligence": { "name": "Channel Intelligence", "categoryId": 4, @@ -3491,6 +3492,16 @@ "categoryId": 6, "url": "https://www.channelpilot.de/" }, + "channeladvisor": { + "name": "ChannelAdvisor", + "categoryId": 4, + "url": "http://www.channeladvisor.com/" + }, + "channelfinder": { + "name": "ChannelFinder", + "categoryId": 4, + "url": "http://www.kpicentral.com/" + }, "chaordic": { "name": "Chaordic", "categoryId": 4, @@ -3506,6 +3517,11 @@ "categoryId": 2, "url": "http://chaser.ru/" }, + "chat_beacon": { + "name": "Chat Beacon", + "categoryId": 2, + "url": "https://www.chatbeacon.io/" + }, "chatango": { "name": "Chatango", "categoryId": 2, @@ -3526,11 +3542,6 @@ "categoryId": 2, "url": "http://chatwing.com/" }, - "chat_beacon": { - "name": "Chat Beacon", - "categoryId": 2, - "url": "https://www.chatbeacon.io/" - }, "checkmystats": { "name": "CheckMyStats", "categoryId": 4, @@ -3541,16 +3552,16 @@ "categoryId": 8, "url": "http://chefkoch.de/" }, - "chinesean": { - "name": "ChineseAN", - "categoryId": 4, - "url": "http://www.chinesean.com/" - }, "chin_media": { "name": "Chin Media", "categoryId": 4, "url": "http://www.chinmedia.vn/#" }, + "chinesean": { + "name": "ChineseAN", + "categoryId": 4, + "url": "http://www.chinesean.com/" + }, "chitika": { "name": "Chitika", "categoryId": 4, @@ -3576,16 +3587,16 @@ "categoryId": 6, "url": "http://circulate.com/" }, - "cityads": { - "name": "CityAds", - "categoryId": 4, - "url": "http://cityads.ru/" - }, "city_spark": { "name": "City Spark", "categoryId": 4, "url": "http://www.cityspark.com/" }, + "cityads": { + "name": "CityAds", + "categoryId": 4, + "url": "http://cityads.ru/" + }, "ciuvo.com": { "name": "ciuvo.com", "categoryId": 12, @@ -3611,6 +3622,11 @@ "categoryId": 3, "url": null }, + "clear_pier": { + "name": "ClearPier", + "categoryId": 4, + "url": "http://clearpier.com/" + }, "clearbit.com": { "name": "Clearbit", "categoryId": 6, @@ -3626,21 +3642,11 @@ "categoryId": 4, "url": "http://clearstream.tv/" }, - "clear_pier": { - "name": "ClearPier", - "categoryId": 4, - "url": "http://clearpier.com/" - }, "clerk.io": { "name": "Clerk.io", "categoryId": 4, "url": "https://clerk.io/" }, - "cleversite": { - "name": "Cleversite", - "categoryId": 2, - "url": "http://cleversite.ru/" - }, "clever_push": { "name": "Clever Push", "categoryId": 6, @@ -3651,11 +3657,26 @@ "categoryId": 6, "url": "https://clevertap.com/" }, + "cleversite": { + "name": "Cleversite", + "categoryId": 2, + "url": "http://cleversite.ru/" + }, "click360": { "name": "Click360", "categoryId": 6, "url": "https://www.click360.io/" }, + "click_and_chat": { + "name": "Click and Chat", + "categoryId": 2, + "url": "http://www.clickandchat.com/" + }, + "click_back": { + "name": "Click Back", + "categoryId": 4, + "url": "http://www.clickback.com/" + }, "clickaider": { "name": "ClickAider", "categoryId": 4, @@ -3751,16 +3772,16 @@ "categoryId": 6, "url": "http://clickreport.com/" }, - "clicksor": { - "name": "Clicksor", - "categoryId": 4, - "url": "http://clicksor.com/" - }, "clicks_thru_networks": { "name": "Clicks Thru Networks", "categoryId": 4, "url": "http://www.clicksthrunetwork.com/" }, + "clicksor": { + "name": "Clicksor", + "categoryId": 4, + "url": "http://clicksor.com/" + }, "clicktale": { "name": "ClickTale", "categoryId": 6, @@ -3786,16 +3807,6 @@ "categoryId": 4, "url": "https://www.clickyab.com/" }, - "click_and_chat": { - "name": "Click and Chat", - "categoryId": 2, - "url": "http://www.clickandchat.com/" - }, - "click_back": { - "name": "Click Back", - "categoryId": 4, - "url": "http://www.clickback.com/" - }, "clicmanager": { "name": "ClicManager", "categoryId": 4, @@ -3891,16 +3902,6 @@ "categoryId": 4, "url": "http://www.cogocast.com" }, - "coinhive": { - "name": "Coinhive", - "categoryId": 8, - "url": "https://coinhive.com/" - }, - "coinurl": { - "name": "CoinURL", - "categoryId": 4, - "url": "https://coinurl.com/" - }, "coin_have": { "name": "Coin Have", "categoryId": 4, @@ -3911,6 +3912,16 @@ "categoryId": 2, "url": "https://cointraffic.io/" }, + "coinhive": { + "name": "Coinhive", + "categoryId": 8, + "url": "https://coinhive.com/" + }, + "coinurl": { + "name": "CoinURL", + "categoryId": 4, + "url": "https://coinurl.com/" + }, "coll1onf.com": { "name": "coll1onf.com", "categoryId": 11, @@ -3946,16 +3957,16 @@ "categoryId": 2, "url": "http://www.comm100.com/" }, - "commercehub": { - "name": "CommerceHub", - "categoryId": 4, - "url": "http://www.mercent.com/" - }, "commerce_sciences": { "name": "Commerce Sciences", "categoryId": 4, "url": "http://commercesciences.com/" }, + "commercehub": { + "name": "CommerceHub", + "categoryId": 4, + "url": "http://www.mercent.com/" + }, "commercialvalue.org": { "name": "commercialvalue.org", "categoryId": 11, @@ -3982,9 +3993,9 @@ "url": "http://www.compete.com/help/s12" }, "complex_media_network": { - "name": "Complex Media Network", + "name": "Complex Media", "categoryId": 4, - "url": "http://www.complexmedianetwork.com/" + "url": "https://www.complex.com/" }, "comprigo": { "name": "comprigo", @@ -4056,11 +4067,6 @@ "categoryId": 4, "url": "http://consumable.com/index.html" }, - "contactme": { - "name": "ContactMe", - "categoryId": 4, - "url": "http://www.contactme.com" - }, "contact_at_once": { "name": "Contact At Once!", "categoryId": 2, @@ -4071,6 +4077,11 @@ "categoryId": 4, "url": "https://www.contactimpact.de/" }, + "contactme": { + "name": "ContactMe", + "categoryId": 4, + "url": "http://www.contactme.com" + }, "contaxe": { "name": "Contaxe", "categoryId": 5, @@ -4081,6 +4092,11 @@ "categoryId": 4, "url": "https://www.content.ad/" }, + "content_insights": { + "name": "Content Insights", + "categoryId": 6, + "url": "https://contentinsights.com/" + }, "contentexchange.me": { "name": "Content Exchange", "categoryId": 6, @@ -4106,11 +4122,6 @@ "categoryId": 6, "url": "http://contentwrx.com/" }, - "content_insights": { - "name": "Content Insights", - "categoryId": 6, - "url": "https://contentinsights.com/" - }, "context": { "name": "C|ON|TEXT", "categoryId": 4, @@ -4142,9 +4153,14 @@ "url": "https://www.conversantmedia.eu/" }, "conversio": { - "name": "Conversio", + "name": "CM Commerce", "categoryId": 6, - "url": "https://conversio.com/" + "url": "https://cm-commerce.com/" + }, + "conversion_logic": { + "name": "Conversion Logic", + "categoryId": 6, + "url": "http://www.conversionlogic.com/" }, "conversionruler": { "name": "ConversionRuler", @@ -4161,11 +4177,6 @@ "categoryId": 5, "url": "https://www.conversionsondemand.com/" }, - "conversion_logic": { - "name": "Conversion Logic", - "categoryId": 6, - "url": "http://www.conversionlogic.com/" - }, "conversive": { "name": "Conversive", "categoryId": 4, @@ -4191,6 +4202,16 @@ "categoryId": 6, "url": "http://www.conviva.com/" }, + "cookie_consent": { + "name": "Cookie Consent", + "categoryId": 5, + "url": "https://silktide.com/" + }, + "cookie_script": { + "name": "Cookie Script", + "categoryId": 5, + "url": "https://cookie-script.com/" + }, "cookiebot": { "name": "Cookiebot", "categoryId": 5, @@ -4201,16 +4222,6 @@ "categoryId": 5, "url": "http://cookieq.com/CookieQ" }, - "cookie_consent": { - "name": "Cookie Consent", - "categoryId": 5, - "url": "https://silktide.com/" - }, - "cookie_script": { - "name": "Cookie Script", - "categoryId": 6, - "url": "https://cookie-script.com/" - }, "cooliris": { "name": "Cooliris", "categoryId": 2, @@ -4236,6 +4247,11 @@ "categoryId": 4, "url": "http://coull.com/" }, + "cpm_rocket": { + "name": "CPM Rocket", + "categoryId": 4, + "url": "http://www.cpmrocket.com/" + }, "cpmprofit": { "name": "CPMProfit", "categoryId": 4, @@ -4246,16 +4262,16 @@ "categoryId": 4, "url": "http://www.cpmstar.com" }, - "cpm_rocket": { - "name": "CPM Rocket", - "categoryId": 4, - "url": "http://www.cpmrocket.com/" - }, "cpx.to": { "name": "Captify", "categoryId": 4, "url": "https://www.captify.co.uk/" }, + "cq_counter": { + "name": "CQ Counter", + "categoryId": 6, + "url": "http://www.cqcounter.com/" + }, "cqq5id8n.com": { "name": "cqq5id8n.com", "categoryId": 11, @@ -4266,11 +4282,6 @@ "categoryId": 6, "url": "https://www.demandware.com/#cquotient" }, - "cq_counter": { - "name": "CQ Counter", - "categoryId": 6, - "url": "http://www.cqcounter.com/" - }, "craftkeys": { "name": "CraftKeys", "categoryId": 4, @@ -4307,9 +4318,9 @@ "url": "https://creativecommons.org/" }, "crimsonhexagon_com": { - "name": "Crimson Hexagon", + "name": "Brandwatch", "categoryId": 6, - "url": "http://crimsonhexagon.com/" + "url": "https://www.brandwatch.com/" }, "crimtan": { "name": "Crimtan", @@ -4351,16 +4362,6 @@ "categoryId": 4, "url": "http://crossss.ru/" }, - "crowdprocess": { - "name": "CrowdProcess", - "categoryId": 2, - "url": "https://crowdprocess.com" - }, - "crowdynews": { - "name": "Crowdynews", - "categoryId": 7, - "url": "http://www.crowdynews.com/" - }, "crowd_ignite": { "name": "Crowd Ignite", "categoryId": 4, @@ -4371,6 +4372,16 @@ "categoryId": 4, "url": "http://www.crowdscience.com/" }, + "crowdprocess": { + "name": "CrowdProcess", + "categoryId": 2, + "url": "https://crowdprocess.com" + }, + "crowdynews": { + "name": "Crowdynews", + "categoryId": 7, + "url": "http://www.crowdynews.com/" + }, "crownpeak": { "name": "Crownpeak", "categoryId": 5, @@ -4441,6 +4452,11 @@ "categoryId": 4, "url": "http://www.cyberwing.co.jp/" }, + "cybersource": { + "name": "CyberSource", + "categoryId": 6, + "url": "https://www.cybersource.com/en-gb.html" + }, "cygnus": { "name": "Cygnus", "categoryId": 4, @@ -4571,6 +4587,11 @@ "categoryId": 8, "url": "https://dawanda.com/" }, + "dc_stormiq": { + "name": "DC StormIQ", + "categoryId": 4, + "url": "http://www.dc-storm.com/" + }, "dcbap.com": { "name": "dcbap.com", "categoryId": 12, @@ -4581,10 +4602,10 @@ "categoryId": 4, "url": "https://www.dcmn.com/" }, - "dc_stormiq": { - "name": "DC StormIQ", + "de_persgroep": { + "name": "De Persgroep", "categoryId": 4, - "url": "http://www.dc-storm.com/" + "url": "https://www.persgroep.nl" }, "deadline_funnel": { "name": "Deadline Funnel", @@ -4686,11 +4707,6 @@ "categoryId": 4, "url": "http://blueadvertise.com/" }, - "de_persgroep": { - "name": "De Persgroep", - "categoryId": 4, - "url": "https://www.persgroep.nl" - }, "dgm": { "name": "dgm", "categoryId": 4, @@ -4801,7 +4817,12 @@ "categoryId": 8, "url": null }, - "direct/advert": { + "direct_keyword_link": { + "name": "Direct Keyword Link", + "categoryId": 4, + "url": "http://www.keywordsconnect.com/" + }, + "directadvert": { "name": "Direct/ADVERT", "categoryId": 4, "url": "http://www.directadvert.ru/" @@ -4811,11 +4832,6 @@ "categoryId": 4, "url": "http://www.directrev.com/" }, - "direct_keyword_link": { - "name": "Direct Keyword Link", - "categoryId": 4, - "url": "http://www.keywordsconnect.com/" - }, "discord": { "name": "Discord", "categoryId": 2, @@ -4959,12 +4975,12 @@ "doubleclick_bid_manager": { "name": "DoubleClick Bid Manager", "categoryId": 4, - "url": "http://www.google.com" + "url": "http://www.invitemedia.com" }, "doubleclick_floodlight": { "name": "DoubleClick Floodlight", "categoryId": 4, - "url": "http://www.google.com" + "url": "http://www.google.com/support/dfa/partner/bin/topic.py?topic=23943" }, "doubleclick_spotlight": { "name": "DoubleClick Spotlight", @@ -5019,7 +5035,7 @@ "dsnr_media_group": { "name": "DSNR Media Group", "categoryId": 4, - "url": "http://www.dsnrmg.com/ " + "url": "http://www.dsnrmg.com/" }, "dsp_rambler": { "name": "Rambler DSP", @@ -5079,7 +5095,7 @@ "dynamic_yield_analytics": { "name": "Dynamic Yield Analytics", "categoryId": 6, - "url": null + "url": "http://www.dynamicyield.com/" }, "dynata": { "name": "Dynata", @@ -5149,7 +5165,7 @@ "ebay_partner_network": { "name": "eBay Partner Network", "categoryId": 4, - "url": "https://partnernetwork.ebay.com/" + "url": "https://www.ebaypartnernetwork.com/files/hub/en-US/index.html" }, "ebuzzing": { "name": "eBuzzing", @@ -5301,16 +5317,16 @@ "categoryId": 6, "url": "http://www.enecto.com/en/" }, - "engageya_widget": { - "name": "Engageya Widget", - "categoryId": 4, - "url": "http://www.engageya.com/home/" - }, "engage_sciences": { "name": "Engage Sciences", "categoryId": 6, "url": "http://www.engagesciences.com/" }, + "engageya_widget": { + "name": "Engageya Widget", + "categoryId": 4, + "url": "http://www.engageya.com/home/" + }, "engagio": { "name": "Engagio", "categoryId": 6, @@ -5511,31 +5527,21 @@ "categoryId": 5, "url": "https://www.evidon.com/" }, - "evidon_ad_notice": { - "name": "Evidon Ad Notice", - "categoryId": 5, - "url": "https://www.evidon.com/" - }, - "evidon_notice": { - "name": "Evidon Site Notice", - "categoryId": 5, - "url": "https://www.evidon.com/" - }, "evisit_analyst": { "name": "eVisit Analyst", "categoryId": 4, "url": "http://www.evisitanalyst.com" }, - "exactag": { - "name": "Exactag", - "categoryId": 6, - "url": "http://www.exactag.com" - }, "exact_drive": { "name": "Exact Drive", "categoryId": 4, "url": "http://www.exactdrive.com/" }, + "exactag": { + "name": "Exactag", + "categoryId": 6, + "url": "http://www.exactag.com" + }, "exelate": { "name": "eXelate", "categoryId": 4, @@ -5601,6 +5607,11 @@ "categoryId": 6, "url": "http://www.extremetracking.com/" }, + "eye_newton": { + "name": "Eye Newton", + "categoryId": 2, + "url": "http://eyenewton.ru/" + }, "eyeota": { "name": "Eyeota", "categoryId": 4, @@ -5616,11 +5627,6 @@ "categoryId": 4, "url": "http://www.eyeviewdigital.com/" }, - "eye_newton": { - "name": "Eye Newton", - "categoryId": 2, - "url": "http://eyenewton.ru/" - }, "ezakus": { "name": "Ezakus", "categoryId": 4, @@ -5639,7 +5645,7 @@ "facebook_beacon": { "name": "Facebook Beacon", "categoryId": 7, - "url": "https://www.facebook.com/" + "url": "http://www.facebook.com/beacon/faq.php" }, "facebook_cdn": { "name": "Facebook CDN", @@ -5654,7 +5660,7 @@ "facebook_conversion_tracking": { "name": "Facebook Conversion Tracking", "categoryId": 4, - "url": "https://www.facebook.com/" + "url": "http://www.facebook.com/" }, "facebook_custom_audience": { "name": "Facebook Custom Audience", @@ -5706,16 +5712,16 @@ "categoryId": 8, "url": null }, - "fastlylb.net": { - "name": "Fastly", - "categoryId": 9, - "url": "https://www.fastly.com/" - }, "fastly_insights": { "name": "Fastly Insights", "categoryId": 6, "url": "https://insights.fastlylabs.com/" }, + "fastlylb.net": { + "name": "Fastly", + "categoryId": 9, + "url": "https://www.fastly.com/" + }, "fastpic.ru": { "name": "FastPic", "categoryId": 10, @@ -5911,11 +5917,6 @@ "categoryId": 6, "url": "http://www.flurry.com/" }, - "flux": { - "name": "Flux", - "categoryId": 7, - "url": "http://www.mtv.com/" - }, "flxone": { "name": "FLXONE", "categoryId": 4, @@ -6001,6 +6002,11 @@ "categoryId": 4, "url": "https://www.fout.co.jp/" }, + "fox_audience_network": { + "name": "Fox Audience Network", + "categoryId": 4, + "url": "https://publishers.foxaudiencenetwork.com/" + }, "foxnews_static": { "name": "Fox News CDN", "categoryId": 9, @@ -6016,16 +6022,26 @@ "categoryId": 12, "url": "https://www.foxydeal.de" }, - "fox_audience_network": { - "name": "Fox Audience Network", - "categoryId": 4, - "url": "https://publishers.foxaudiencenetwork.com/" - }, "fraudlogix": { "name": "FraudLogix", "categoryId": 4, "url": "https://www.fraudlogix.com/" }, + "free_counter": { + "name": "Free Counter", + "categoryId": 6, + "url": "http://www.statcounterfree.com/" + }, + "free_online_users": { + "name": "Free Online Users", + "categoryId": 6, + "url": "http://www.freeonlineusers.com" + }, + "free_pagerank": { + "name": "Free PageRank", + "categoryId": 6, + "url": "http://www.free-pagerank.com/" + }, "freedom_mortgage": { "name": "Freedom Mortgage", "categoryId": 6, @@ -6046,21 +6062,6 @@ "categoryId": 4, "url": "http://www.freewheel.tv/" }, - "free_counter": { - "name": "Free Counter", - "categoryId": 6, - "url": "http://www.statcounterfree.com/" - }, - "free_online_users": { - "name": "Free Online Users", - "categoryId": 6, - "url": "http://www.freeonlineusers.com" - }, - "free_pagerank": { - "name": "Free PageRank", - "categoryId": 6, - "url": "http://www.free-pagerank.com/" - }, "fresh8": { "name": "Fresh8", "categoryId": 6, @@ -6126,6 +6127,16 @@ "categoryId": 4, "url": "https://www.fyber.com/" }, + "ga_audiences": { + "name": "GA Audiences", + "categoryId": 6, + "url": "http://www.google.com" + }, + "game_advertising_online": { + "name": "Game Advertising Online", + "categoryId": 4, + "url": "http://www.game-advertising-online.com/" + }, "gamedistribution.com": { "name": "Gamedistribution.com", "categoryId": 8, @@ -6136,15 +6147,10 @@ "categoryId": 7, "url": "http://www.gamerdnamedia.com/" }, - "game_advertising_online": { - "name": "Game Advertising Online", - "categoryId": 4, - "url": "http://www.game-advertising-online.com/" - }, "gannett": { "name": "Gannett Media", "categoryId": 0, - "url": " https://www.gannett.com/" + "url": "https://www.gannett.com/" }, "gaug.es": { "name": "Gaug.es", @@ -6156,11 +6162,6 @@ "categoryId": 0, "url": "http://www.gpm-digital.com/" }, - "ga_audiences": { - "name": "GA Audiences", - "categoryId": 6, - "url": "http://www.google.com" - }, "gb-world": { "name": "GB-World", "categoryId": 7, @@ -6241,6 +6242,16 @@ "categoryId": 4, "url": "http://www.gestionpub.com/" }, + "get_response": { + "name": "Get Response", + "categoryId": 2, + "url": "https://www.getresponse.com/?marketing_gv=v2" + }, + "get_site_control": { + "name": "Get Site Control", + "categoryId": 4, + "url": "https://getsitecontrol.com/" + }, "getconversion": { "name": "GetConversion", "categoryId": 2, @@ -6276,16 +6287,6 @@ "categoryId": 8, "url": "https://www.gettyimages.com/" }, - "get_response": { - "name": "Get Response", - "categoryId": 2, - "url": "https://www.getresponse.com/?marketing_gv=v2" - }, - "get_site_control": { - "name": "Get Site Control", - "categoryId": 4, - "url": "https://getsitecontrol.com/" - }, "gfk": { "name": "GfK", "categoryId": 4, @@ -6296,16 +6297,16 @@ "categoryId": 7, "url": "https://gfycat.com/" }, - "giantmedia": { - "name": "GiantMedia", - "categoryId": 4, - "url": "http://giantmedia.com/" - }, "giant_realm": { "name": "Giant Realm", "categoryId": 4, "url": "http://corp.giantrealm.com/" }, + "giantmedia": { + "name": "GiantMedia", + "categoryId": 4, + "url": "http://giantmedia.com/" + }, "giga": { "name": "Giga", "categoryId": 4, @@ -6319,17 +6320,17 @@ "gigya_beacon": { "name": "Gigya Beacon", "categoryId": 2, - "url": "https://www.sap.com/index.html" + "url": "http://www.gigya.com" }, "gigya_socialize": { "name": "Gigya Socialize", "categoryId": 2, - "url": "https://www.sap.com/index.html" + "url": "http://www.gigya.com" }, "gigya_toolbar": { "name": "Gigya Toolbar", "categoryId": 2, - "url": "https://www.sap.com/index.html" + "url": "http://www.gigya.com/" }, "giosg": { "name": "Giosg", @@ -6381,6 +6382,11 @@ "categoryId": 12, "url": null }, + "global_web_index": { + "name": "GlobalWebIndex", + "categoryId": 6, + "url": "https://www.globalwebindex.com/" + }, "globalnotifier.com": { "name": "globalnotifier.com", "categoryId": 11, @@ -6396,11 +6402,6 @@ "categoryId": 4, "url": "http://www.globaltakeoff.net/" }, - "global_web_index": { - "name": "GlobalWebIndex", - "categoryId": 6, - "url": "https://www.globalwebindex.com/" - }, "glomex.com": { "name": "Glomex", "categoryId": 0, @@ -6411,6 +6412,11 @@ "categoryId": 11, "url": null }, + "gm_delivery": { + "name": "GM Delivery", + "categoryId": 4, + "url": "http://a.gmdelivery.com/" + }, "gmo": { "name": "GMO", "categoryId": 4, @@ -6421,11 +6427,6 @@ "categoryId": 8, "url": null }, - "gm_delivery": { - "name": "GM Delivery", - "categoryId": 4, - "url": "http://a.gmdelivery.com/" - }, "go.com": { "name": "go.com", "categoryId": 8, @@ -6471,10 +6472,10 @@ "categoryId": 4, "url": "https://www.google.com/" }, - "googleapis.com": { - "name": "Google APIs", - "categoryId": 9, - "url": "https://www.googleapis.com/" + "google_ads_measurement": { + "name": "Google Ads Measurement", + "categoryId": 4, + "url": "http://www.google.com" }, "google_adsense": { "name": "Google Adsense", @@ -6486,11 +6487,6 @@ "categoryId": 4, "url": "http://www.google.com" }, - "google_ads_measurement": { - "name": "Google Ads Measurement", - "categoryId": 4, - "url": "http://www.google.com" - }, "google_adwords_conversion": { "name": "Google AdWords Conversion", "categoryId": 4, @@ -6517,9 +6513,14 @@ "url": "https://developers.google.com/custom-search-ads/" }, "google_custom_search_engine": { - "name": "Google Custom Search Engine", + "name": "Google Programmable Search Engine", "categoryId": 5, - "url": "https://www.google.com/coop/cse/" + "url": "https://programmablesearchengine.google.com/about/" + }, + "google_email": { + "name": "Google Email", + "categoryId": 13, + "url": "http://www.google.com" }, "google_fonts": { "name": "Google Fonts", @@ -6611,6 +6612,11 @@ "categoryId": 2, "url": "http://www.google.com" }, + "googleapis.com": { + "name": "Google APIs", + "categoryId": 9, + "url": "https://www.googleapis.com/" + }, "goooal": { "name": "Goooal", "categoryId": 6, @@ -6681,11 +6687,6 @@ "categoryId": 4, "url": "http://greatviews.de/" }, - "greentube.com": { - "name": "Greentube Internet Entertainment Solutions", - "categoryId": 7, - "url": "https://www.greentube.com/" - }, "green_and_red": { "name": "Green and Red", "categoryId": 4, @@ -6696,6 +6697,16 @@ "categoryId": 2, "url": "http://www.advenity.com/" }, + "green_story": { + "name": "Green Story", + "categoryId": 6, + "url": "https://greenstory.ca/" + }, + "greentube.com": { + "name": "Greentube Internet Entertainment Solutions", + "categoryId": 7, + "url": "https://www.greentube.com/" + }, "greystripe": { "name": "Greystripe", "categoryId": 4, @@ -6826,20 +6837,20 @@ "categoryId": 8, "url": "http://www.heimspiel.de" }, - "hellosociety": { - "name": "HelloSociety", - "categoryId": 6, - "url": "http://hellosociety.com" - }, "hello_bar": { "name": "Hello Bar", "categoryId": 7, "url": "https://www.hellobar.com/" }, - "here__formerly_navteq_media_solutions_": { - "name": "HERE (formerly Navteq Media Solutions)", + "hellosociety": { + "name": "HelloSociety", + "categoryId": 6, + "url": "http://hellosociety.com" + }, + "here": { + "name": "HERE", "categoryId": 8, - "url": null + "url": "https://www.here.com/" }, "heroku": { "name": "Heroku", @@ -6996,11 +7007,6 @@ "categoryId": 4, "url": "https://hqentertainmentnetwork.com/" }, - "hsleadflows.net": { - "name": "Leadin", - "categoryId": 6, - "url": "https://www.hubspot.com/" - }, "hsoub": { "name": "Hsoub", "categoryId": 4, @@ -7056,16 +7062,16 @@ "categoryId": 4, "url": "https://hybrid.ai/" }, - "hypercomments": { - "name": "HyperComments", - "categoryId": 1, - "url": "http://www.hypercomments.com/" - }, "hype_exchange": { "name": "Hype Exchange", "categoryId": 4, "url": "http://www.hypeexchange.com/" }, + "hypercomments": { + "name": "HyperComments", + "categoryId": 1, + "url": "http://www.hypercomments.com/" + }, "hyves_widgets": { "name": "Hyves Widgets", "categoryId": 4, @@ -7151,16 +7157,21 @@ "categoryId": 4, "url": "https://www.ippen-digital.de/" }, - "idealo_com": { - "name": "idealo.com", - "categoryId": 4, - "url": "http://idealo.com/" + "id_services": { + "name": "ID Services", + "categoryId": 6, + "url": "https://id.services/" }, "ideal_media": { "name": "Ideal Media", "categoryId": 4, "url": "http://idealmedia.com/" }, + "idealo_com": { + "name": "idealo.com", + "categoryId": 4, + "url": "http://idealo.com/" + }, "ideoclick": { "name": "IdeoClick", "categoryId": 4, @@ -7171,11 +7182,6 @@ "categoryId": 4, "url": "https://www.idio.ai/" }, - "id_services": { - "name": "ID Services", - "categoryId": 6, - "url": "https://id.services/" - }, "ie8eamus.com": { "name": "ie8eamus.com", "categoryId": 11, @@ -7194,7 +7200,7 @@ "ignitionone": { "name": "IgnitionOne", "categoryId": 6, - "url": "http://www.ignitionone.com/" + "url": "https://www.ignitionone.com/" }, "igodigital": { "name": "iGoDigital", @@ -7281,16 +7287,16 @@ "categoryId": 4, "url": "http://www.iw-advertising.com/" }, - "improvely": { - "name": "Improvely", - "categoryId": 6, - "url": "https://www.improvely.com/" - }, "improve_digital": { "name": "Improve Digital", "categoryId": 4, "url": "http://www.improvedigital.com/" }, + "improvely": { + "name": "Improvely", + "categoryId": 6, + "url": "https://www.improvely.com/" + }, "inbenta": { "name": "Inbenta", "categoryId": 6, @@ -7306,7 +7312,7 @@ "categoryId": 4, "url": "http://www.indeed.com/" }, - "index_exchange_": { + "index_exchange": { "name": "Index Exchange", "categoryId": 4, "url": "http://www.casalemedia.com/" @@ -7357,9 +7363,9 @@ "url": "http://www.informer.com/" }, "infusionsoft": { - "name": "Infusionsoft", + "name": "Infusionsoft by Keap", "categoryId": 4, - "url": "http://www.infusionsoft.com/" + "url": "https://keap.com/" }, "innity": { "name": "Innity", @@ -7429,7 +7435,12 @@ "instinctive": { "name": "Instinctive", "categoryId": 4, - "url": "https://instinctive.io/ " + "url": "https://instinctive.io/" + }, + "intango": { + "name": "Intango", + "categoryId": 4, + "url": "https://intango.com/" }, "integral_ad_science": { "name": "Integral Ad Science", @@ -7464,7 +7475,7 @@ "intent_iq": { "name": "Intent IQ", "categoryId": 4, - "url": "https://www.intentiq.com/" + "url": "http://datonics.com/" }, "intent_media": { "name": "Intent", @@ -7496,6 +7507,11 @@ "categoryId": 4, "url": "http://intermundomedia.com/" }, + "internet_billboard": { + "name": "Internet BillBoard", + "categoryId": 4, + "url": "http://www.ibillboard.com/en/" + }, "internetaudioads": { "name": "InternetAudioAds", "categoryId": 0, @@ -7506,11 +7522,6 @@ "categoryId": 7, "url": "http://www.internetbrands.com/" }, - "internet_billboard": { - "name": "Internet BillBoard", - "categoryId": 4, - "url": "http://www.ibillboard.com/en/" - }, "interpolls": { "name": "Interpolls", "categoryId": 4, @@ -7551,11 +7562,6 @@ "categoryId": 6, "url": "http://www.invodo.com/" }, - "iogous": { - "name": "iogous", - "categoryId": 4, - "url": "http://www.iogous.com/" - }, "ionicframework.com": { "name": "Ionic", "categoryId": 8, @@ -7576,6 +7582,16 @@ "categoryId": 6, "url": "http://www.ip-label.co.uk/" }, + "ip_targeting": { + "name": "IP Targeting", + "categoryId": 6, + "url": "https://www.iptargeting.com/" + }, + "ip_tracker": { + "name": "IP Tracker", + "categoryId": 6, + "url": "http://www.ip-tracker.org/" + }, "iperceptions": { "name": "iPerceptions", "categoryId": 2, @@ -7621,15 +7637,10 @@ "categoryId": 4, "url": "http://www.iprospect.com/" }, - "ip_tracker": { - "name": "IP Tracker", - "categoryId": 6, - "url": "http://www.ip-tracker.org/" - }, "ironsource": { "name": "ironSource", "categoryId": 4, - "url": "http://www.afterdownload.com/" + "url": "https://www.ironsrc.com/" }, "isocket": { "name": "isocket", @@ -7716,6 +7727,11 @@ "categoryId": 4, "url": "https://jeeng.com/" }, + "jet_interactive": { + "name": "Jet Interactive", + "categoryId": 6, + "url": "http://www.jetinteractive.com.au/" + }, "jetlore": { "name": "Jetlore", "categoryId": 6, @@ -7731,11 +7747,6 @@ "categoryId": 6, "url": "http://www.jetpack.com/" }, - "jet_interactive": { - "name": "Jet Interactive", - "categoryId": 6, - "url": "http://www.jetinteractive.com.au/" - }, "jimdo.com": { "name": "jimdo.com", "categoryId": 10, @@ -7781,6 +7792,11 @@ "categoryId": 9, "url": "https://jquery.org/" }, + "js_communications": { + "name": "JS Communications", + "categoryId": 4, + "url": "http://www.jssearch.net/" + }, "jsdelivr": { "name": "jsDelivr", "categoryId": 9, @@ -7796,11 +7812,6 @@ "categoryId": 4, "url": null }, - "js_communications": { - "name": "JS Communications", - "categoryId": 4, - "url": "http://www.jssearch.net/" - }, "juggcash": { "name": "JuggCash", "categoryId": 3, @@ -7824,7 +7835,7 @@ "jumpstart_tagging_solutions": { "name": "Jumpstart Tagging Solutions", "categoryId": 6, - "url": " http://www.hearst.com/" + "url": "http://www.hearst.com/" }, "jumptap": { "name": "Jumptap", @@ -7884,7 +7895,7 @@ "kalooga_widget": { "name": "Kalooga Widget", "categoryId": 4, - "url": "https://www.kalooga.com/" + "url": "http://kalooga.com/" }, "kaltura": { "name": "Kaltura", @@ -8096,8 +8107,13 @@ "categoryId": 6, "url": "http://www.kortx.io/" }, + "kount": { + "name": "Kount", + "categoryId": 6, + "url": "https://kount.com/" + }, "krux_digital": { - "name": "Krux Digital", + "name": "Salesforce DMP", "categoryId": 4, "url": "https://www.salesforce.com/products/marketing-cloud/data-management/?mc=DMP" }, @@ -8131,16 +8147,16 @@ "categoryId": 8, "url": "http://www.latimes.com/" }, - "launchbit": { - "name": "LaunchBit", - "categoryId": 4, - "url": "https://www.launchbit.com/" - }, "launch_darkly": { "name": "Launch Darkly", "categoryId": 5, "url": "https://launchdarkly.com/index.html" }, + "launchbit": { + "name": "LaunchBit", + "categoryId": 4, + "url": "https://www.launchbit.com/" + }, "layer-ad.org": { "name": "Layer-ADS.net", "categoryId": 4, @@ -8156,6 +8172,16 @@ "categoryId": 4, "url": "http://www.lcx.com/" }, + "le_monde.fr": { + "name": "Le Monde.fr", + "categoryId": 8, + "url": "http://www.lemonde.fr/" + }, + "lead_liaison": { + "name": "Lead Liaison", + "categoryId": 6, + "url": "https://www.leadliaison.com" + }, "leadback": { "name": "Leadback", "categoryId": 6, @@ -8216,6 +8242,11 @@ "categoryId": 6, "url": "https://temelio.com" }, + "leads_by_web.com": { + "name": "Leads by Web.com", + "categoryId": 4, + "url": "http://www.leadsbyweb.com" + }, "leadscoreapp": { "name": "LeadScoreApp", "categoryId": 2, @@ -8226,21 +8257,11 @@ "categoryId": 4, "url": "http://www.leadsius.com/" }, - "leads_by_web.com": { - "name": "Leads by Web.com", - "categoryId": 4, - "url": "http://www.leadsbyweb.com" - }, "leady": { "name": "Leady", "categoryId": 4, "url": "http://www.leady.cz/" }, - "lead_liaison": { - "name": "Lead Liaison", - "categoryId": 6, - "url": "https://www.leadliaison.com" - }, "leiki": { "name": "Leiki", "categoryId": 4, @@ -8266,26 +8287,21 @@ "categoryId": 4, "url": "http://lenua.de/" }, - "letv": { - "name": "LeTV", - "categoryId": 6, - "url": "http://www.le.com/" - }, "let_reach": { "name": "Let Reach", "categoryId": 2, "url": "https://letreach.com/" }, + "letv": { + "name": "LeTV", + "categoryId": 6, + "url": "http://www.le.com/" + }, "level3_communications": { "name": "Level 3 Communications, Inc.", "categoryId": 8, "url": "http://www.level3.com/en/" }, - "le_monde.fr": { - "name": "Le Monde.fr", - "categoryId": 8, - "url": "http://www.lemonde.fr/" - }, "licensebuttons.net": { "name": "licensebuttons.net", "categoryId": 9, @@ -8306,16 +8322,16 @@ "categoryId": 4, "url": "https://limk.com/" }, - "linezing": { - "name": "LineZing", - "categoryId": 4, - "url": "http://www.linezing.com/" - }, "line_apps": { "name": "Line", "categoryId": 6, "url": "https://line.me/en-US/" }, + "linezing": { + "name": "LineZing", + "categoryId": 4, + "url": "http://www.linezing.com/" + }, "linkbucks": { "name": "Linkbucks", "categoryId": 4, @@ -8334,7 +8350,7 @@ "linkedin_ads": { "name": "LinkedIn Ads", "categoryId": 4, - "url": "https://www.microsoft.com/" + "url": "http://www.linkedin.com/" }, "linkedin_analytics": { "name": "LinkedIn Analytics", @@ -8353,8 +8369,8 @@ }, "linker": { "name": "Linker", - "categoryId": 6, - "url": "http://linker.hr/" + "categoryId": 4, + "url": "https://linker.hr/" }, "linkprice": { "name": "LinkPrice", @@ -8431,6 +8447,26 @@ "categoryId": 2, "url": "http://live800.com" }, + "live_agent": { + "name": "Live Agent", + "categoryId": 2, + "url": "https://www.ladesk.com/" + }, + "live_help_now": { + "name": "Live Help Now", + "categoryId": 2, + "url": "http://www.livehelpnow.net/" + }, + "live_intent": { + "name": "Live Intent", + "categoryId": 6, + "url": "http://www.liveintent.com/" + }, + "live_journal": { + "name": "Live Journal", + "categoryId": 6, + "url": "http://www.livejournal.com/" + }, "liveadexchanger.com": { "name": "liveadexchanger.com", "categoryId": 11, @@ -8496,26 +8532,6 @@ "categoryId": 2, "url": "https://livetex.ru/" }, - "live_agent": { - "name": "Live Agent", - "categoryId": 2, - "url": "https://www.ladesk.com/" - }, - "live_help_now": { - "name": "Live Help Now", - "categoryId": 2, - "url": "http://www.livehelpnow.net/" - }, - "live_intent": { - "name": "Live Intent", - "categoryId": 6, - "url": "http://www.liveintent.com/" - }, - "live_journal": { - "name": "Live Journal", - "categoryId": 6, - "url": "http://www.livejournal.com/" - }, "lkqd": { "name": "LKQD", "categoryId": 4, @@ -8584,7 +8600,7 @@ "longtail_video_analytics": { "name": "JW Player Analytics", "categoryId": 4, - "url": "https://www.jwplayer.com/" + "url": "http://www.longtailvideo.com/" }, "loomia": { "name": "Loomia", @@ -8626,16 +8642,16 @@ "categoryId": 4, "url": "http://www.lucinilucini.com/" }, - "luckypushh.com": { - "name": "luckypushh.com", - "categoryId": 11, - "url": null - }, "lucky_orange": { "name": "Lucky Orange", "categoryId": 6, "url": "http://www.luckyorange.com/" }, + "luckypushh.com": { + "name": "luckypushh.com", + "categoryId": 11, + "url": null + }, "lxr100": { "name": "LXR100", "categoryId": 4, @@ -8671,6 +8687,11 @@ "categoryId": 4, "url": "http://www.zanox.com/us/" }, + "mad_ads_media": { + "name": "Mad Ads Media", + "categoryId": 4, + "url": "http://www.madadsmedia.com/" + }, "madeleine.de": { "name": "madeleine.de", "categoryId": 4, @@ -8691,11 +8712,6 @@ "categoryId": 4, "url": "http://www.mads.com/" }, - "mad_ads_media": { - "name": "Mad Ads Media", - "categoryId": 4, - "url": "http://www.madadsmedia.com/" - }, "magna_advertise": { "name": "Magna Advertise", "categoryId": 4, @@ -8736,11 +8752,6 @@ "categoryId": 7, "url": "http://mail.ru/" }, - "mailchimp": { - "name": "MailChimp", - "categoryId": 4, - "url": "https://mailchimp.com/" - }, "mailchimp_tracking": { "name": "MailChimp Tracking", "categoryId": 4, @@ -8816,6 +8827,16 @@ "categoryId": 4, "url": "http://www.marinsoftware.com/" }, + "mark_+_mini": { + "name": "Mark & Mini", + "categoryId": 4, + "url": "http://www.markandmini.com/index.cfm" + }, + "market_thunder": { + "name": "Market Thunder", + "categoryId": 4, + "url": "https://www.makethunder.com/" + }, "marketgid": { "name": "MarketGid", "categoryId": 4, @@ -8831,11 +8852,6 @@ "categoryId": 4, "url": "http://www.marketo.com/" }, - "market_thunder": { - "name": "Market Thunder", - "categoryId": 4, - "url": "https://www.makethunder.com/" - }, "markmonitor": { "name": "MarkMonitor", "categoryId": 4, @@ -8846,11 +8862,6 @@ "categoryId": 4, "url": "http://www.marktest.com/" }, - "mark_+_mini": { - "name": "Mark & Mini", - "categoryId": 4, - "url": "http://www.markandmini.com/index.cfm" - }, "marshadow.io": { "name": "marshadow.io", "categoryId": 4, @@ -8871,16 +8882,16 @@ "categoryId": 6, "url": "https://www.marvellousmachine.net/" }, - "mastertarget": { - "name": "MasterTarget", - "categoryId": 4, - "url": "http://mastertarget.ru/" - }, "master_banner_network": { "name": "Master Banner Network", "categoryId": 4, "url": "http://www.mbn.com.ua/" }, + "mastertarget": { + "name": "MasterTarget", + "categoryId": 4, + "url": "http://mastertarget.ru/" + }, "matelso": { "name": "Matelso", "categoryId": 6, @@ -8899,7 +8910,7 @@ "matiro": { "name": "Matiro", "categoryId": 6, - "url": " http://matiro.com/" + "url": "http://matiro.com/" }, "matomo": { "name": "Matomo", @@ -8991,16 +9002,26 @@ "categoryId": 4, "url": "http://www.media.net/" }, + "media_impact": { + "name": "Media Impact", + "categoryId": 4, + "url": "https://mediaimpact.de/index.html" + }, + "media_innovation_group": { + "name": "Xaxis", + "categoryId": 4, + "url": "https://www.xaxis.com/" + }, + "media_today": { + "name": "Media Today", + "categoryId": 4, + "url": "http://mediatoday.ru/" + }, "mediaad": { "name": "MediaAd", "categoryId": 4, "url": "https://mediaad.org" }, - "mediadesk": { - "name": "MediaDesk", - "categoryId": 4, - "url": null - }, "mediaglu": { "name": "Mediaglu", "categoryId": 4, @@ -9081,21 +9102,6 @@ "categoryId": 4, "url": "http://www.mediawhiz.com/" }, - "media_impact": { - "name": "Media Impact", - "categoryId": 4, - "url": "https://mediaimpact.de/index.html" - }, - "media_innovation_group": { - "name": "Xaxis", - "categoryId": 4, - "url": "https://www.xaxis.com/" - }, - "media_today": { - "name": "Media Today", - "categoryId": 4, - "url": " http://mediatoday.ru/" - }, "medigo": { "name": "Medigo", "categoryId": 4, @@ -9186,6 +9192,11 @@ "categoryId": 7, "url": "https://messenger.com" }, + "meta_network": { + "name": "Meta Network", + "categoryId": 7, + "url": "http://www.metanetwork.com/" + }, "metaffiliation.com": { "name": "Netaffiliation", "categoryId": 4, @@ -9196,11 +9207,6 @@ "categoryId": 4, "url": "http://www.metapeople.com/us/" }, - "meta_network": { - "name": "Meta Network", - "categoryId": 7, - "url": "http://www.metanetwork.com/" - }, "metrigo": { "name": "Metrigo", "categoryId": 4, @@ -9229,12 +9235,12 @@ "microsoft_adcenter_conversion": { "name": "Microsoft adCenter Conversion", "categoryId": 4, - "url": "https://www.microsoft.com/" + "url": "https://adcenter.microsoft.com/" }, "microsoft_analytics": { "name": "Microsoft Analytics", "categoryId": 4, - "url": "https://www.microsoft.com/" + "url": "https://adcenter.microsoft.com" }, "mindset_media": { "name": "Mindset Media", @@ -9341,16 +9347,16 @@ "categoryId": 2, "url": "http://www.mochapp.com/" }, - "modernus": { - "name": "Modernus", - "categoryId": 6, - "url": "http://www.modernus.is" - }, "modern_impact": { "name": "Modern Impact", "categoryId": 4, "url": "http://www.modernimpact.com/" }, + "modernus": { + "name": "Modernus", + "categoryId": 6, + "url": "http://www.modernus.is" + }, "modulepush.com": { "name": "modulepush.com", "categoryId": 4, @@ -9436,16 +9442,16 @@ "categoryId": 4, "url": "https://www.mopub.com/" }, - "moreads": { - "name": "moreAds", - "categoryId": 4, - "url": "https://www.moras.jp" - }, "more_communication": { "name": "More Communication", "categoryId": 4, "url": "http://www.more-com.co.jp/" }, + "moreads": { + "name": "moreAds", + "categoryId": 4, + "url": "https://www.moras.jp" + }, "motigo_webstats": { "name": "Motigo Webstats", "categoryId": 7, @@ -9471,7 +9477,7 @@ "categoryId": 6, "url": "http://www.mousetrace.com/" }, - "mov.ad_": { + "mov.ad": { "name": "Mov.ad ", "categoryId": 8, "url": null @@ -9586,21 +9592,26 @@ "categoryId": 4, "url": "http://nakanohito.jp/" }, + "namogoo": { + "name": "Namoogoo", + "categoryId": 4, + "url": "https://www.namogoo.com/" + }, "nanigans": { "name": "Nanigans", "categoryId": 4, "url": "http://www.nanigans.com/" }, - "nanorep": { - "name": "nanoRep", - "categoryId": 2, - "url": "http://www.nanorep.com/" - }, "nano_interactive": { "name": "Nano Interactive", "categoryId": 4, "url": "http://www.nanointeractive.com/home/de" }, + "nanorep": { + "name": "nanoRep", + "categoryId": 2, + "url": "http://www.nanorep.com/" + }, "narando": { "name": "Narando", "categoryId": 0, @@ -9676,7 +9687,7 @@ "categoryId": 4, "url": "http://neodatagroup.com/" }, - "neory_": { + "neory": { "name": "NEORY ", "categoryId": 4, "url": "https://www.neory.com/" @@ -9696,6 +9707,21 @@ "categoryId": 4, "url": "http://www.net-results.com/" }, + "net_avenir": { + "name": "Net Avenir", + "categoryId": 4, + "url": "http://www.netavenir.com/" + }, + "net_communities": { + "name": "Net Communities", + "categoryId": 4, + "url": "http://www.netcommunities.com/" + }, + "net_visibility": { + "name": "NET Visibility", + "categoryId": 4, + "url": "http://www.netvisibility.co.uk" + }, "netbiscuits": { "name": "Netbiscuits", "categoryId": 6, @@ -9761,26 +9787,16 @@ "categoryId": 7, "url": "http://w.networkedblogs.com/" }, - "net_avenir": { - "name": "Net Avenir", - "categoryId": 4, - "url": "http://www.netavenir.com/" - }, - "net_communities": { - "name": "Net Communities", - "categoryId": 4, - "url": "http://www.netcommunities.com/" - }, - "net_visibility": { - "name": "NET Visibility", - "categoryId": 4, - "url": "http://www.netvisibility.co.uk" - }, "neustar_adadvisor": { "name": "Neustar AdAdvisor", "categoryId": 4, "url": "http://www.targusinfo.com/" }, + "new_relic": { + "name": "New Relic", + "categoryId": 6, + "url": "http://newrelic.com/" + }, "newscgp.com": { "name": "News Connect", "categoryId": 4, @@ -9811,11 +9827,6 @@ "categoryId": 4, "url": "http://www.newtention.de/" }, - "new_relic": { - "name": "New Relic", - "categoryId": 6, - "url": "http://newrelic.com/" - }, "nexage": { "name": "Nexage", "categoryId": 4, @@ -9826,6 +9837,16 @@ "categoryId": 4, "url": "http://nexeps.com/" }, + "next_performance": { + "name": "Next Performance", + "categoryId": 4, + "url": "http://www.nextperformance.com/" + }, + "next_user": { + "name": "Next User", + "categoryId": 4, + "url": "https://www.nextuser.com/" + }, "nextag_roi_optimizer": { "name": "Nextag ROI Optimizer", "categoryId": 4, @@ -9841,16 +9862,6 @@ "categoryId": 6, "url": "http://www.nextstat.com/" }, - "next_performance": { - "name": "Next Performance", - "categoryId": 4, - "url": "http://www.nextperformance.com/" - }, - "next_user": { - "name": "Next User", - "categoryId": 4, - "url": "https://www.nextuser.com/" - }, "neytiv": { "name": "Neytiv", "categoryId": 6, @@ -9899,7 +9910,7 @@ "noddus": { "name": "Noddus", "categoryId": 4, - "url": " https://www.enterprise.noddus.com/" + "url": "https://www.enterprise.noddus.com/" }, "nolix": { "name": "Nolix", @@ -9951,6 +9962,11 @@ "categoryId": 2, "url": "http://nrelate.com/" }, + "ns8": { + "name": "NS8", + "categoryId": 4, + "url": "https://www.ns8.com/" + }, "nt.vc": { "name": "Next Tuesday GmbH", "categoryId": 8, @@ -9991,6 +10007,11 @@ "categoryId": 5, "url": "http://www.channeliq.com/" }, + "ny_times_tagx": { + "name": "NY Times TagX", + "categoryId": 6, + "url": "https://www.nytimes.com/" + }, "nyacampwk.com": { "name": "nyacampwk.com", "categoryId": 11, @@ -10006,11 +10027,6 @@ "categoryId": 8, "url": "https://www.nytimes.com/" }, - "ny_times_tagx": { - "name": "NY Times TagX", - "categoryId": 6, - "url": "https://www.nytimes.com/" - }, "o12zs3u2n.com": { "name": "o12zs3u2n.com", "categoryId": 11, @@ -10076,16 +10092,16 @@ "categoryId": 11, "url": null }, - "ohana_advertising_network": { - "name": "Ohana Advertising Network", - "categoryId": 4, - "url": "http://adohana.com/" - }, "oh_my_stats": { "name": "Oh My Stats", "categoryId": 6, "url": "https://ohmystats.com/" }, + "ohana_advertising_network": { + "name": "Ohana Advertising Network", + "categoryId": 4, + "url": "http://adohana.com/" + }, "olapic": { "name": "Olapic", "categoryId": 4, @@ -10126,11 +10142,6 @@ "categoryId": 4, "url": "http://www.omniscienta.com/" }, - "omniture__adobe_analytics_": { - "name": "Adobe Analytics", - "categoryId": 6, - "url": "https://www.adobe.com/experience-cloud.html" - }, "oms": { "name": "OMS", "categoryId": 4, @@ -10166,6 +10177,11 @@ "categoryId": 8, "url": "https://www.onet.pl/" }, + "onetag": { + "name": "OneTag", + "categoryId": 4, + "url": "https://www.onetag.com/" + }, "onetrust": { "name": "OneTrust", "categoryId": 5, @@ -10206,6 +10222,21 @@ "categoryId": 6, "url": "https://www.telstraglobal.com/" }, + "open_adexchange": { + "name": "Open AdExchange", + "categoryId": 4, + "url": "http://openadex.dk/" + }, + "open_adstream": { + "name": "Open Adstream", + "categoryId": 4, + "url": "https://www.appnexus.com/en" + }, + "open_share_count": { + "name": "Open Share Count", + "categoryId": 4, + "url": "http://opensharecount.com/" + }, "openload": { "name": "Openload", "categoryId": 9, @@ -10231,21 +10262,6 @@ "categoryId": 4, "url": "https://www.openx.com" }, - "open_adexchange": { - "name": "Open AdExchange", - "categoryId": 4, - "url": "http://openadex.dk/" - }, - "open_adstream": { - "name": "Open Adstream", - "categoryId": 4, - "url": "https://www.appnexus.com/en" - }, - "open_share_count": { - "name": "Open Share Count", - "categoryId": 4, - "url": "http://opensharecount.com/" - }, "operative_media": { "name": "Operative Media", "categoryId": 4, @@ -10366,16 +10382,16 @@ "categoryId": 4, "url": "http://www.orange142.com/" }, - "orangesoda": { - "name": "OrangeSoda", - "categoryId": 4, - "url": "http://www.orangesoda.com/" - }, "orange_france": { "name": "Orange France", "categoryId": 8, "url": "https://www.orange.fr/" }, + "orangesoda": { + "name": "OrangeSoda", + "categoryId": 4, + "url": "http://www.orangesoda.com/" + }, "orc_international": { "name": "ORC International", "categoryId": 4, @@ -10606,6 +10622,11 @@ "categoryId": 4, "url": "http://perfectmarket.com/" }, + "perform_group": { + "name": "Perform Group", + "categoryId": 5, + "url": "http://www.performgroup.co.uk/" + }, "performable": { "name": "Performable", "categoryId": 6, @@ -10621,11 +10642,6 @@ "categoryId": 4, "url": "https://www.performax.cz/" }, - "perform_group": { - "name": "Perform Group", - "categoryId": 5, - "url": "http://www.performgroup.co.uk/" - }, "perimeterx.net": { "name": "Perimeterx", "categoryId": 6, @@ -10761,16 +10777,16 @@ "categoryId": 4, "url": "https://www.platform-one.co.jp/" }, - "playbuzz.com": { - "name": "Playbuzz", - "categoryId": 2, - "url": "https://www.playbuzz.com/" - }, "play_by_mamba": { "name": "Play by Mamba", "categoryId": 4, "url": "http://play.mamba.ru/" }, + "playbuzz.com": { + "name": "Playbuzz", + "categoryId": 2, + "url": "https://www.playbuzz.com/" + }, "plenty_of_fish": { "name": "Plenty Of Fish", "categoryId": 6, @@ -10923,7 +10939,7 @@ }, "powerreviews": { "name": "PowerReviews", - "categoryId": 4, + "categoryId": 2, "url": "http://www.powerreviews.com/" }, "powr.io": { @@ -10991,6 +11007,11 @@ "categoryId": 4, "url": "http://www.proclivitysystems.com/" }, + "prodperfect": { + "name": "ProdPerfect", + "categoryId": 6, + "url": "https://prodperfect.com/" + }, "productsup": { "name": "ProductsUp", "categoryId": 4, @@ -11021,16 +11042,16 @@ "categoryId": 4, "url": "http://www.projectwonderful.com/" }, - "propeller_ads": { - "name": "Propeller Ads", - "categoryId": 4, - "url": "http://www.propellerads.com/" - }, "propel_marketing": { "name": "Propel Marketing", "categoryId": 4, "url": "http://propelmarketing.com/" }, + "propeller_ads": { + "name": "Propeller Ads", + "categoryId": 4, + "url": "http://www.propellerads.com/" + }, "propermedia": { "name": "Proper Media", "categoryId": 4, @@ -11121,16 +11142,16 @@ "categoryId": 4, "url": "http://pubgears.com/" }, - "publicidad.net": { - "name": "Publicidad.net", - "categoryId": 4, - "url": "http://www.en.publicidad.net/" - }, "public_ideas": { "name": "Public Ideas", "categoryId": 4, "url": "http://www.publicidees.co.uk/" }, + "publicidad.net": { + "name": "Publicidad.net", + "categoryId": 4, + "url": "http://www.en.publicidad.net/" + }, "publir": { "name": "Publir", "categoryId": 4, @@ -11166,16 +11187,16 @@ "categoryId": 4, "url": "http://www.pulse360.com" }, - "pulsepoint": { - "name": "PulsePoint", - "categoryId": 4, - "url": "http://www.contextweb.com/" - }, "pulse_insights": { "name": "Pulse Insights", "categoryId": 6, "url": "http://pulseinsights.com/" }, + "pulsepoint": { + "name": "PulsePoint", + "categoryId": 4, + "url": "http://www.contextweb.com/" + }, "punchtab": { "name": "PunchTab", "categoryId": 4, @@ -11186,16 +11207,16 @@ "categoryId": 4, "url": "http://www.purch.com/" }, - "pureprofile": { - "name": "Pureprofile", - "categoryId": 6, - "url": "https://www.pureprofile.com/us/" - }, "pure_chat": { "name": "Pure Chat", "categoryId": 2, "url": "https://www.purechat.com" }, + "pureprofile": { + "name": "Pureprofile", + "categoryId": 6, + "url": "https://www.pureprofile.com/us/" + }, "purlive": { "name": "PurLive", "categoryId": 4, @@ -11211,6 +11232,11 @@ "categoryId": 2, "url": "https://push.world/en" }, + "push_engage": { + "name": "Push Engage", + "categoryId": 2, + "url": "https://www.pushengage.com/" + }, "pushame.com": { "name": "pushame.com", "categoryId": 11, @@ -11222,9 +11248,9 @@ "url": "https://www.pushbullet.com/" }, "pushcrew": { - "name": "Pushcrew", + "name": "VWO Engage", "categoryId": 2, - "url": "https://pushcrew.com/" + "url": "https://vwo.com/engage/" }, "pusher.com": { "name": "Pusher", @@ -11256,11 +11282,6 @@ "categoryId": 2, "url": "https://www.pushwoosh.com/" }, - "push_engage": { - "name": "Push Engage", - "categoryId": 2, - "url": "https://www.pushengage.com/" - }, "pvclouds.com": { "name": "pvclouds.com", "categoryId": 11, @@ -11271,6 +11292,11 @@ "categoryId": 4, "url": "http://q1media.com/" }, + "q_division": { + "name": "Q-Division", + "categoryId": 4, + "url": "https://q-division.de/" + }, "qbaka": { "name": "Qbaka", "categoryId": 6, @@ -11381,10 +11407,10 @@ "categoryId": 7, "url": "https://quora.com/" }, - "q_division": { - "name": "Q-Division", + "r_advertising": { + "name": "R-Advertising", "categoryId": 4, - "url": "https://q-division.de/" + "url": "http://www.r-advertising.com/" }, "rackcdn.com": { "name": "Rackspace", @@ -11446,6 +11472,11 @@ "categoryId": 6, "url": "https://www.rapidspike.com" }, + "ravelin": { + "name": "Ravelin", + "categoryId": 6, + "url": "https://www.ravelin.com/" + }, "rawgit": { "name": "RawGit", "categoryId": 9, @@ -11506,6 +11537,11 @@ "categoryId": 7, "url": "http://www.readrboard.com" }, + "readme": { + "name": "ReadMe", + "categoryId": 6, + "url": "https://readme.com/" + }, "readspeaker.com": { "name": "ReadSpeaker", "categoryId": 2, @@ -11531,11 +11567,6 @@ "categoryId": 6, "url": "https://www.realytics.io/" }, - "realytics.io": { - "name": "realytics.io", - "categoryId": 6, - "url": "https://www.realytics.io/" - }, "rebel_mouse": { "name": "Rebel Mouse", "categoryId": 6, @@ -11561,6 +11592,11 @@ "categoryId": 6, "url": "http://recruitics.com/" }, + "red_ventures": { + "name": "Red Ventures", + "categoryId": 6, + "url": "https://www.redventures.com/" + }, "redblue_de": { "name": "redblue", "categoryId": 6, @@ -11601,11 +11637,6 @@ "categoryId": 4, "url": "http://reduxmedia.com/" }, - "red_ventures": { - "name": "Red Ventures", - "categoryId": 6, - "url": "https://www.redventures.com/" - }, "reed_business_information": { "name": "Reed Business Information", "categoryId": 6, @@ -11661,6 +11692,11 @@ "categoryId": 4, "url": "http://convert.us/" }, + "reklam_store": { + "name": "Reklam Store", + "categoryId": 4, + "url": "http://www.reklamstore.com" + }, "reklamport": { "name": "Reklamport", "categoryId": 4, @@ -11671,11 +11707,6 @@ "categoryId": 4, "url": "http://www.reklamz.com/" }, - "reklam_store": { - "name": "Reklam Store", - "categoryId": 4, - "url": "http://www.reklamstore.com" - }, "rekmob": { "name": "Rekmob", "categoryId": 4, @@ -11746,21 +11777,26 @@ "categoryId": 4, "url": "http://www.adinsight.eu/" }, - "resultspage.com": { - "name": "SLI Systems", - "categoryId": 6, - "url": "https://www.sli-systems.com/" - }, "result_links": { "name": "Result Links", "categoryId": 4, "url": "http://www.resultlinks.com/" }, + "resultspage.com": { + "name": "SLI Systems", + "categoryId": 6, + "url": "https://www.sli-systems.com/" + }, "retailrocket.net": { "name": "Retail Rocket", "categoryId": 4, "url": "https://retailrocket.net/" }, + "retarget_app": { + "name": "Retarget App", + "categoryId": 4, + "url": "https://retargetapp.com/" + }, "retargeter_beacon": { "name": "ReTargeter Beacon", "categoryId": 4, @@ -11771,11 +11807,6 @@ "categoryId": 4, "url": "http://retargeting.cl/" }, - "retarget_app": { - "name": "Retarget App", - "categoryId": 4, - "url": "https://retargetapp.com/" - }, "retention_science": { "name": "Retention Science", "categoryId": 4, @@ -11791,6 +11822,11 @@ "categoryId": 4, "url": "https://www.revcontent.com/" }, + "reve_marketing": { + "name": "Reve Marketing", + "categoryId": 4, + "url": "http://tellafriend.socialtwist.com/" + }, "revenue": { "name": "Revenue", "categoryId": 4, @@ -11806,16 +11842,6 @@ "categoryId": 4, "url": "http://www.revenuemantra.com/" }, - "revenue_hits": { - "name": "RevenueHits", - "categoryId": 4, - "url": "https://www.revenuehits.com/" - }, - "reve_marketing": { - "name": "Reve Marketing", - "categoryId": 4, - "url": "http://tellafriend.socialtwist.com/" - }, "revive_adserver": { "name": "Revive Adserver", "categoryId": 4, @@ -11851,16 +11877,16 @@ "categoryId": 8, "url": "https://ria.ru/" }, - "richrelevance": { - "name": "RichRelevance", - "categoryId": 2, - "url": "http://www.richrelevance.com/" - }, "rich_media_banner_network": { "name": "Rich Media Banner Network", "categoryId": 4, "url": "http://rmbn.ru/" }, + "richrelevance": { + "name": "RichRelevance", + "categoryId": 2, + "url": "http://www.richrelevance.com/" + }, "ringier.ch": { "name": "Ringier", "categoryId": 6, @@ -11872,7 +11898,7 @@ "url": "http://www.meteorsolutions.com" }, "riskfield.com": { - "name": "Riskfield", + "name": "Riskified", "categoryId": 2, "url": "https://www.riskified.com/" }, @@ -11901,21 +11927,16 @@ "categoryId": 4, "url": "https://rocket.la/" }, - "rocket_fuel": { - "name": "Rocket Fuel", + "roi_trax": { + "name": "ROI trax", "categoryId": 4, - "url": "http://rocketfuelinc.com/" + "url": "http://www.oneupweb.com/" }, "roistat": { "name": "Roistat", "categoryId": 6, "url": "https://roistat.com" }, - "roi_trax": { - "name": "ROI trax", - "categoryId": 4, - "url": "http://www.oneupweb.com/" - }, "rollad": { "name": "Rollad", "categoryId": 4, @@ -11961,6 +11982,11 @@ "categoryId": 2, "url": "http://www.rsspump.com" }, + "rtb_house": { + "name": "RTB House", + "categoryId": 4, + "url": "http://en.adpilot.com/" + }, "rtblab": { "name": "RTBmarkt", "categoryId": 4, @@ -11971,15 +11997,10 @@ "categoryId": 4, "url": null }, - "rtb_house": { - "name": "RTB House", - "categoryId": 4, - "url": "http://en.adpilot.com/" - }, "rtl_group": { "name": "RTL Group", "categoryId": 8, - "url": null + "url": "http://www.rtlgroup.com/www/htm/home.aspx" }, "rtmark.net": { "name": "Advertising Technologies Ltd", @@ -12026,11 +12047,6 @@ "categoryId": 0, "url": "https://www.rhythmone.com/" }, - "r_advertising": { - "name": "R-Advertising", - "categoryId": 4, - "url": "http://www.r-advertising.com/" - }, "s24_com": { "name": "Shopping24 internet group", "categoryId": 4, @@ -12061,6 +12077,16 @@ "categoryId": 4, "url": "http://www.salecycle.com/" }, + "sales_feed": { + "name": "Sales Feed", + "categoryId": 4, + "url": "https://www.salesfeed.com/" + }, + "sales_manago": { + "name": "SALESmanago", + "categoryId": 6, + "url": "https://www.salesmanago.com/" + }, "salesforce.com": { "name": "Salesforce", "categoryId": 4, @@ -12076,11 +12102,6 @@ "categoryId": 4, "url": "http://salesfusion.com/" }, - "salesmanago.pl": { - "name": "SALESmanago", - "categoryId": 4, - "url": "https://www.salesmanago.com/" - }, "salespider_media": { "name": "SaleSpider Media", "categoryId": 4, @@ -12091,16 +12112,6 @@ "categoryId": 6, "url": "https://www.salesviewer.com/" }, - "sales_feed": { - "name": "Sales Feed", - "categoryId": 4, - "url": "https://www.salesfeed.com/" - }, - "sales_mango": { - "name": "Sales Mango", - "categoryId": 6, - "url": "https://www.salesmanago.pl/welcome.htm?language=en" - }, "samba.tv": { "name": "Samba TV", "categoryId": 4, @@ -12111,16 +12122,6 @@ "categoryId": 4, "url": "https://sanoma.com/" }, - "sape.ru": { - "name": "Sape", - "categoryId": 6, - "url": "https://www.sape.ru/en" - }, - "sapo_ads": { - "name": "SAPO Ads", - "categoryId": 4, - "url": "http://www.sapo.pt/" - }, "sap_crm": { "name": "SAP CRM", "categoryId": 6, @@ -12136,6 +12137,16 @@ "categoryId": 4, "url": "http://sapexchange.media/" }, + "sape.ru": { + "name": "Sape", + "categoryId": 6, + "url": "https://www.sape.ru/en" + }, + "sapo_ads": { + "name": "SAPO Ads", + "categoryId": 4, + "url": "http://www.sapo.pt/" + }, "sas": { "name": "SAS", "categoryId": 6, @@ -12146,26 +12157,21 @@ "categoryId": 4, "url": "http://say.ac" }, - "sayyac": { - "name": "Sayyac", - "categoryId": 6, - "url": "http://www.sayyac.com/" - }, "say_media": { "name": "Say Media", "categoryId": 4, "url": "http://www.saymedia.com/" }, + "sayyac": { + "name": "Sayyac", + "categoryId": 6, + "url": "http://www.sayyac.com/" + }, "scarabresearch": { "name": "Scarab Research", "categoryId": 4, "url": "https://www.scarabresearch.com/" }, - "scene7.com": { - "name": "Adobe Dynamic Media (Scene7)", - "categoryId": 4, - "url": "http://www.adobe.com/" - }, "schibsted": { "name": "Schibsted Media Group", "categoryId": 8, @@ -12229,7 +12235,7 @@ "searchignite": { "name": "SearchIgnite", "categoryId": 4, - "url": "http://about.searchignite.com/" + "url": "https://searchignite.com/" }, "searchrev": { "name": "SearchRev", @@ -12241,6 +12247,11 @@ "categoryId": 4, "url": "http://www.secondmedia.com/" }, + "securedtouch": { + "name": "SecuredTouch", + "categoryId": 6, + "url": "https://www.securedtouch.com/" + }, "securedvisit": { "name": "SecuredVisit", "categoryId": 4, @@ -12436,6 +12447,11 @@ "categoryId": 6, "url": "http://www.shinystat.com/" }, + "shop_target": { + "name": "Shop Target", + "categoryId": 4, + "url": "http://shoptarget.com.br/" + }, "shopauskunft.de": { "name": "ShopAuskunft.de", "categoryId": 2, @@ -12446,6 +12462,11 @@ "categoryId": 2, "url": "https://www.shopgate.com/" }, + "shopify_stats": { + "name": "Shopify Stats", + "categoryId": 4, + "url": "http://www.shopify.com/" + }, "shopifycdn.com": { "name": "Shopify CDN", "categoryId": 9, @@ -12456,11 +12477,6 @@ "categoryId": 2, "url": "https://www.shopify.com/" }, - "shopify_stats": { - "name": "Shopify Stats", - "categoryId": 4, - "url": "http://www.shopify.com/" - }, "shopper_approved": { "name": "Shopper Approved", "categoryId": 2, @@ -12491,11 +12507,6 @@ "categoryId": 4, "url": "http://www.shopzilla.com/" }, - "shop_target": { - "name": "Shop Target", - "categoryId": 4, - "url": "http://shoptarget.com.br/" - }, "shortnews": { "name": "ShortNews.de", "categoryId": 8, @@ -12556,11 +12567,6 @@ "categoryId": 4, "url": "http://www.simpli.fi" }, - "simply": { - "name": "Simply", - "categoryId": 4, - "url": "http://www.simply.com/" - }, "sina": { "name": "Sina", "categoryId": 6, @@ -12586,6 +12592,16 @@ "categoryId": 6, "url": "https://www.site24x7.com/" }, + "site_booster": { + "name": "Site Booster", + "categoryId": 7, + "url": "https://sitebooster.com/" + }, + "site_stratos": { + "name": "Site Stratos", + "categoryId": 4, + "url": "http://www.infocube.co.jp/" + }, "siteapps": { "name": "SiteApps", "categoryId": 2, @@ -12636,30 +12652,15 @@ "categoryId": 4, "url": "http://www.sitewit.com/" }, - "site_booster": { - "name": "Site Booster", - "categoryId": 7, - "url": "https://sitebooster.com/" - }, - "site_stratos": { - "name": "Site Stratos", - "categoryId": 4, - "url": "http://www.infocube.co.jp/" - }, - "sixt-neuwagen.de": { - "name": "sixt-neuwagen.de", - "categoryId": 8, - "url": null - }, "six_apart_advertising": { "name": "Six Apart Advertising", "categoryId": 4, "url": "http://www.sixapart.com/advertising/" }, - "sizmek": { - "name": "Sizmek", - "categoryId": 4, - "url": "http://www.mediamind.com/" + "sixt-neuwagen.de": { + "name": "sixt-neuwagen.de", + "categoryId": 8, + "url": null }, "skadtec.com": { "name": "GP One GmbH", @@ -12706,6 +12707,11 @@ "categoryId": 2, "url": "https://sleeknote.com/" }, + "sli_systems": { + "name": "SLI Systems", + "categoryId": 2, + "url": "http://www.sli-systems.com" + }, "slice_factory": { "name": "Slice Factory", "categoryId": 2, @@ -12721,11 +12727,6 @@ "categoryId": 4, "url": "http://slingpic.com/" }, - "sli_systems": { - "name": "SLI Systems", - "categoryId": 2, - "url": "http://www.sli-systems.com" - }, "smaato": { "name": "Smaato", "categoryId": 4, @@ -12736,71 +12737,6 @@ "categoryId": 4, "url": "http://www.smart4ads.com" }, - "smartad": { - "name": "smartAD", - "categoryId": 4, - "url": "http://smartad.eu/" - }, - "smartbn": { - "name": "SmartBN", - "categoryId": 4, - "url": "http://smartbn.ru/" - }, - "smartclick.net": { - "name": "SmartClick", - "categoryId": 4, - "url": "http://smartclick.net/" - }, - "smartclip": { - "name": "SmartClip", - "categoryId": 4, - "url": "http://www.smartclip.com/" - }, - "smartcontext": { - "name": "SmartContext", - "categoryId": 4, - "url": "http://smartcontext.pl/" - }, - "smarterclick": { - "name": "Smarterclick", - "categoryId": 4, - "url": "http://www.smarterclick.co.uk/" - }, - "smartertrack": { - "name": "SmarterTrack", - "categoryId": 4, - "url": "http://www.smartertrack.com/" - }, - "smarter_remarketer": { - "name": "SmarterHQ", - "categoryId": 4, - "url": "https://smarterhq.com" - }, - "smarter_travel": { - "name": "Smarter Travel Media", - "categoryId": 4, - "url": "https://www.smartertravel.com/" - }, - "smartlink.cool": { - "name": "smartlink.cool", - "categoryId": 11, - "url": null - }, - "smartlook": { - "name": "Smartlook", - "categoryId": 2, - "url": "https://www.smartlook.com/" - }, - "smartstream.tv": { - "name": "SmartStream.TV", - "categoryId": 4, - "url": "https://www.smartstream.tv/en" - }, - "smartsupp_chat": { - "name": "Smartsupp Chat", - "categoryId": 2, - "url": "https://www.smartsupp.com/" - }, "smart_adserver": { "name": "SMART AdServer", "categoryId": 4, @@ -12831,6 +12767,71 @@ "categoryId": 2, "url": "https://smartselling.cz/" }, + "smartad": { + "name": "smartAD", + "categoryId": 4, + "url": "http://smartad.eu/" + }, + "smartbn": { + "name": "SmartBN", + "categoryId": 4, + "url": "http://smartbn.ru/" + }, + "smartclick.net": { + "name": "SmartClick", + "categoryId": 4, + "url": "http://smartclick.net/" + }, + "smartclip": { + "name": "SmartClip", + "categoryId": 4, + "url": "http://www.smartclip.com/" + }, + "smartcontext": { + "name": "SmartContext", + "categoryId": 4, + "url": "http://smartcontext.pl/" + }, + "smarter_remarketer": { + "name": "SmarterHQ", + "categoryId": 4, + "url": "https://smarterhq.com" + }, + "smarter_travel": { + "name": "Smarter Travel Media", + "categoryId": 4, + "url": "https://www.smartertravel.com/" + }, + "smarterclick": { + "name": "Smarterclick", + "categoryId": 4, + "url": "http://www.smarterclick.co.uk/" + }, + "smartertrack": { + "name": "SmarterTrack", + "categoryId": 4, + "url": "http://www.smartertrack.com/" + }, + "smartlink.cool": { + "name": "smartlink.cool", + "categoryId": 11, + "url": null + }, + "smartlook": { + "name": "Smartlook", + "categoryId": 2, + "url": "https://www.smartlook.com/" + }, + "smartstream.tv": { + "name": "SmartStream.TV", + "categoryId": 4, + "url": "https://www.smartstream.tv/en" + }, + "smartsupp_chat": { + "name": "Smartsupp Chat", + "categoryId": 2, + "url": "https://www.smartsupp.com/" + }, "smi2.ru": { "name": "smi2.ru", "categoryId": 6, @@ -12871,16 +12872,16 @@ "categoryId": 2, "url": "http://www.snap.com/" }, - "snapchat": { - "name": "Snapchat For Business", - "categoryId": 4, - "url": "https://www.snapchat.com/" - }, "snap_engage": { "name": "Snap Engage", "categoryId": 2, "url": "https://snapengage.com/" }, + "snapchat": { + "name": "Snapchat For Business", + "categoryId": 4, + "url": "https://www.snapchat.com/" + }, "snigelweb": { "name": "SnigelWeb, Inc.", "categoryId": 4, @@ -12911,16 +12912,6 @@ "categoryId": 4, "url": "http://www.sociablelabs.com/" }, - "socialbeat": { - "name": "socialbeat", - "categoryId": 4, - "url": "http://www.socialbeat.it/" - }, - "socialrms": { - "name": "SocialRMS", - "categoryId": 7, - "url": "http://socialinterface.com/socialrms/" - }, "social_amp": { "name": "Social Amp", "categoryId": 4, @@ -12936,6 +12927,16 @@ "categoryId": 7, "url": "https://socialminer.com/" }, + "socialbeat": { + "name": "socialbeat", + "categoryId": 4, + "url": "http://www.socialbeat.it/" + }, + "socialrms": { + "name": "SocialRMS", + "categoryId": 7, + "url": "http://socialinterface.com/socialrms/" + }, "sociaplus.com": { "name": "SociaPlus", "categoryId": 6, @@ -12994,7 +12995,7 @@ "sophus3": { "name": "Sophus3", "categoryId": 4, - "url": "http://www.sophus3.com/ " + "url": "http://www.sophus3.com/" }, "sortable": { "name": "Sortable", @@ -13021,26 +13022,21 @@ "categoryId": 4, "url": "https://www.sovrn.com/" }, - "sovrn_onetag": { - "name": "Sovrn OneTag", - "categoryId": 4, - "url": "https://community.sovrn.com/s/article/OneTag-Implementation-Guide?language=en_US" - }, "sovrn_viewability_solutions": { "name": "Sovrn Signal", "categoryId": 4, "url": "https://www.sovrn.com/publishers/signal/" }, - "sparkasse.de": { - "name": "sparkasse.de", - "categoryId": 8, - "url": null - }, "spark_studios": { "name": "Spark Studios", "categoryId": 0, "url": "http://www.sparkstudios.com/" }, + "sparkasse.de": { + "name": "sparkasse.de", + "categoryId": 8, + "url": null + }, "speakpipe": { "name": "SpeakPipe", "categoryId": 2, @@ -13056,6 +13052,11 @@ "categoryId": 6, "url": "http://spectate.com/" }, + "speed_shift_media": { + "name": "Speed Shift Media", + "categoryId": 4, + "url": "http://www.speedshiftmedia.com/" + }, "speedcurve": { "name": "SpeedCurve", "categoryId": 6, @@ -13066,11 +13067,6 @@ "categoryId": 4, "url": "http://www.entireweb.com/speedyads/" }, - "speed_shift_media": { - "name": "Speed Shift Media", - "categoryId": 4, - "url": "http://www.speedshiftmedia.com/" - }, "speee": { "name": "Speee", "categoryId": 4, @@ -13334,7 +13330,7 @@ "strava": { "name": "Strava", "categoryId": 6, - "url": "https://www.strava.com/" + "url": "https://strava.com" }, "streak": { "name": "Streak", @@ -13369,7 +13365,7 @@ "stroer_digital_media": { "name": "Stroer Digital Media", "categoryId": 4, - "url": " http://www.stroeer.de/" + "url": "http://www.stroeer.de/" }, "strossle": { "name": "Strossle", @@ -13526,6 +13522,11 @@ "categoryId": 4, "url": "http://www.tacoda.com/" }, + "tag_commander": { + "name": "Commanders Act", + "categoryId": 5, + "url": "https://www.commandersact.com/en/" + }, "tagcade": { "name": "Tagcade", "categoryId": 4, @@ -13546,21 +13547,16 @@ "categoryId": 5, "url": "http://www.tagman.com/" }, - "tag_commander": { - "name": "Commanders Act", - "categoryId": 5, - "url": "https://www.commandersact.com/en/" + "tail_target": { + "name": "Tail", + "categoryId": 6, + "url": "https://www.tail.digital/" }, "tailsweep": { "name": "Tailsweep", "categoryId": 4, "url": "http://www.tailsweep.se/" }, - "tail_target": { - "name": "Tail", - "categoryId": 6, - "url": "https://www.tail.digital/" - }, "tamedia.ch": { "name": "Tamedia", "categoryId": 4, @@ -13579,7 +13575,7 @@ "tapad": { "name": "Tapad", "categoryId": 4, - "url": "http://www.tapad.com/ " + "url": "http://www.tapad.com/" }, "tapinfluence": { "name": "TapInfluence", @@ -13681,11 +13677,6 @@ "categoryId": 8, "url": "https://www.teufel.de/" }, - "themoviedb": { - "name": "The Movie DB", - "categoryId": 8, - "url": "https://www.themoviedb.org/" - }, "the_adex": { "name": "The ADEX", "categoryId": 4, @@ -13721,6 +13712,11 @@ "categoryId": 4, "url": "http://www.theweathercompany.com/" }, + "themoviedb": { + "name": "The Movie DB", + "categoryId": 8, + "url": "https://www.themoviedb.org/" + }, "thinglink": { "name": "ThingLink", "categoryId": 4, @@ -13771,11 +13767,6 @@ "categoryId": 6, "url": "http://www.tnsglobal.com/" }, - "tom's_native_ads": { - "name": "Tom's Native Ads", - "categoryId": 4, - "url": "http://static.natoms.com/doc/" - }, "tomnewsupdate.info": { "name": "tomnewsupdate.info", "categoryId": 12, @@ -13791,6 +13782,11 @@ "categoryId": 4, "url": "http://www.tonefuse.com/" }, + "top_mail": { + "name": "Top Mail", + "categoryId": 6, + "url": "https://corp.megafon.com/" + }, "toplist.cz": { "name": "toplist.cz", "categoryId": 11, @@ -13806,11 +13802,6 @@ "categoryId": 4, "url": "http://topsy.com/" }, - "top_mail": { - "name": "Top Mail", - "categoryId": 6, - "url": "https://corp.megafon.com/" - }, "torbit": { "name": "Torbit", "categoryId": 6, @@ -13861,6 +13852,11 @@ "categoryId": 6, "url": "http://www.appneta.com/" }, + "track_duck": { + "name": "Track Duck", + "categoryId": 6, + "url": "https://trackduck.com/" + }, "trackjs": { "name": "TrackJS", "categoryId": 6, @@ -13876,11 +13872,6 @@ "categoryId": 2, "url": "http://www.trackuity.com/" }, - "track_duck": { - "name": "Track Duck", - "categoryId": 6, - "url": "https://trackduck.com/" - }, "tradedesk": { "name": "TradeDesk", "categoryId": 4, @@ -13906,6 +13897,21 @@ "categoryId": 4, "url": "https://traffective.com/" }, + "traffic_fuel": { + "name": "Traffic Fuel", + "categoryId": 4, + "url": "https://trafficfuel.com/" + }, + "traffic_revenue": { + "name": "Traffic Revenue", + "categoryId": 4, + "url": "http://www.trafficrevenue.net/" + }, + "traffic_stars": { + "name": "Traffic Stars", + "categoryId": 3, + "url": "https://trafficstars.com/#index_page" + }, "trafficbroker": { "name": "TrafficBroker", "categoryId": 4, @@ -13936,21 +13942,6 @@ "categoryId": 3, "url": "http://www.trafficjunky.net/" }, - "traffic_fuel": { - "name": "Traffic Fuel", - "categoryId": 4, - "url": "https://trafficfuel.com/" - }, - "traffic_revenue": { - "name": "Traffic Revenue", - "categoryId": 4, - "url": "http://www.trafficrevenue.net/" - }, - "traffic_stars": { - "name": "Traffic Stars", - "categoryId": 3, - "url": "https://trafficstars.com/#index_page" - }, "traffiliate": { "name": "Traffiliate", "categoryId": 4, @@ -13989,7 +13980,7 @@ "tremor_video": { "name": "Tremor Video", "categoryId": 0, - "url": "http://www.tremorvideo.com/en" + "url": "http://www.tremormedia.com/" }, "trendcounter": { "name": "trendcounter", @@ -14009,23 +14000,23 @@ "tribal_fusion_notice": { "name": "Tribal Fusion Notice", "categoryId": 4, - "url": "http://www.exponential.com/" + "url": "http://www.tribalfusion.com" }, "triblio": { "name": "Triblio", "categoryId": 6, "url": "https://triblio.com/" }, - "triggerbee": { - "name": "Triggerbee", - "categoryId": 2, - "url": "https://triggerbee.com/" - }, "trigger_mail_marketing": { "name": "Trigger Mail Marketing", "categoryId": 4, "url": "http://www.triggeremailmarketing.com/" }, + "triggerbee": { + "name": "Triggerbee", + "categoryId": 2, + "url": "https://triggerbee.com/" + }, "tripadvisor": { "name": "TripAdvisor", "categoryId": 8, @@ -14043,7 +14034,7 @@ }, "triton_digital": { "name": "Triton Digital", - "categoryId": 4, + "categoryId": 0, "url": "http://www.tritondigital.com/" }, "trovus_revelations": { @@ -14056,6 +14047,11 @@ "categoryId": 11, "url": null }, + "true_fit": { + "name": "True Fit", + "categoryId": 4, + "url": "https://www.truefit.com/" + }, "trueanthem": { "name": "True Anthem", "categoryId": 4, @@ -14071,11 +14067,6 @@ "categoryId": 6, "url": "http://truehits.net/" }, - "true_fit": { - "name": "True Fit", - "categoryId": 4, - "url": "https://www.truefit.com/" - }, "trumba": { "name": "Trumba", "categoryId": 4, @@ -14091,16 +14082,6 @@ "categoryId": 5, "url": "http://www.trustarc.com/" }, - "trusted_shops": { - "name": "Trusted Shops", - "categoryId": 5, - "url": "http://www.trustedshops.com/" - }, - "trustev": { - "name": "Trustev", - "categoryId": 6, - "url": "http://www.trustev.com/" - }, "truste_consent": { "name": "Truste Consent", "categoryId": 5, @@ -14116,6 +14097,16 @@ "categoryId": 5, "url": "http://www.truste.com/" }, + "trusted_shops": { + "name": "Trusted Shops", + "categoryId": 5, + "url": "http://www.trustedshops.com/" + }, + "trustev": { + "name": "Trustev", + "categoryId": 6, + "url": "http://www.trustev.com/" + }, "trustlogo": { "name": "TrustLogo", "categoryId": 5, @@ -14159,7 +14150,7 @@ "tumblr_dashboard": { "name": "Tumblr Dashboard", "categoryId": 7, - "url": "https://www.verizon.com/" + "url": "http://www.tumblr.com/" }, "tune_in": { "name": "Tune In", @@ -14171,10 +14162,15 @@ "categoryId": 4, "url": "http://www.turboadv.com/" }, + "turn_inc.": { + "name": "Turn Inc.", + "categoryId": 4, + "url": "https://www.amobee.com/company/" + }, "turner": { - "name": "Turner", - "categoryId": 9, - "url": "https://www.turner.com/" + "name": "Warner Media", + "categoryId": 6, + "url": "https://www.warnermedia.com/" }, "turnsocial": { "name": "TurnSocial", @@ -14186,11 +14182,6 @@ "categoryId": 2, "url": "http://www.turntonetworks.com/" }, - "turn_inc.": { - "name": "Turn Inc.", - "categoryId": 4, - "url": "https://www.amobee.com/company/" - }, "tvsquared.com": { "name": "TVSquared", "categoryId": 4, @@ -14236,11 +14227,6 @@ "categoryId": 7, "url": "https://twitter.com" }, - "twittercounter": { - "name": "TwitterCounter", - "categoryId": 6, - "url": "http://twittercounter.com/" - }, "twitter_ads": { "name": "Twitter Advertising", "categoryId": 4, @@ -14254,12 +14240,12 @@ "twitter_badge": { "name": "Twitter Badge", "categoryId": 7, - "url": "https://twitter.com/" + "url": "http://twitter.com/widgets" }, "twitter_button": { "name": "Twitter Button", "categoryId": 7, - "url": "https://twitter.com/" + "url": "http://twitter.com" }, "twitter_conversion_tracking": { "name": "Twitter Conversion Tracking", @@ -14276,6 +14262,11 @@ "categoryId": 7, "url": "https://twitter.com" }, + "twittercounter": { + "name": "TwitterCounter", + "categoryId": 6, + "url": "http://twittercounter.com/" + }, "twyn": { "name": "Twyn", "categoryId": 4, @@ -14296,11 +14287,6 @@ "categoryId": 2, "url": "https://www.typeform.com/" }, - "typekit_by_adobe": { - "name": "Typekit by Adobe", - "categoryId": 5, - "url": "https://www.adobe.com/" - }, "typepad_stats": { "name": "Typepad Stats", "categoryId": 6, @@ -14326,21 +14312,16 @@ "categoryId": 12, "url": "https://www.ubersetzung-app.com/" }, - "ubertags": { - "name": "UberTags", - "categoryId": 5, - "url": "http://ubertags.com/" + "ucfunnel": { + "name": "ucfunnel", + "categoryId": 4, + "url": "https://www.ucfunnel.com/" }, "ucoz": { "name": "uCoz", "categoryId": 6, "url": "http://www.ucoz.net/" }, - "ucoz.net": { - "name": "uCoz", - "categoryId": 6, - "url": "http://www.ucoz.net/" - }, "uliza": { "name": "Uliza", "categoryId": 4, @@ -14641,6 +14622,11 @@ "categoryId": 4, "url": "http://mobile.vdopia.com/" }, + "ve_interactive": { + "name": "Ve Interactive", + "categoryId": 4, + "url": "https://www.veinteractive.com" + }, "vee24": { "name": "VEE24", "categoryId": 0, @@ -14674,7 +14660,7 @@ "veoxa": { "name": "Veoxa", "categoryId": 4, - "url": "http://www.veoxa.com/ " + "url": "http://www.veoxa.com/" }, "vergic.com": { "name": "Vergic", @@ -14686,16 +14672,6 @@ "categoryId": 4, "url": "http://www.getvero.com/" }, - "verticalresponse": { - "name": "VerticalResponse", - "categoryId": 4, - "url": "http://www.verticalresponse.com" - }, - "verticalscope": { - "name": "VerticalScope", - "categoryId": 4, - "url": "http://www.verticalscope.com" - }, "vertical_acuity": { "name": "Vertical Acuity", "categoryId": 4, @@ -14706,6 +14682,16 @@ "categoryId": 4, "url": "http://www.vertical-leap.co.uk/" }, + "verticalresponse": { + "name": "VerticalResponse", + "categoryId": 4, + "url": "http://www.verticalresponse.com" + }, + "verticalscope": { + "name": "VerticalScope", + "categoryId": 4, + "url": "http://www.verticalscope.com" + }, "vertoz": { "name": "Vertoz", "categoryId": 4, @@ -14721,11 +14707,6 @@ "categoryId": 4, "url": "http://www.vervemobile.com/" }, - "ve_interactive": { - "name": "Ve Interactive", - "categoryId": 4, - "url": "https://www.veinteractive.com" - }, "vg_wort": { "name": "VG Wort", "categoryId": 6, @@ -14761,6 +14742,16 @@ "categoryId": 4, "url": "https://www.vidazoo.com/" }, + "video_desk": { + "name": "Video Desk", + "categoryId": 0, + "url": "https://www.videodesk.com/" + }, + "video_potok": { + "name": "Video Potok", + "categoryId": 0, + "url": "http://videopotok.pro/" + }, "videoadex.com": { "name": "VideoAdX", "categoryId": 4, @@ -14791,16 +14782,6 @@ "categoryId": 4, "url": "https://www.videostep.com/" }, - "video_desk": { - "name": "Video Desk", - "categoryId": 0, - "url": "https://www.videodesk.com/" - }, - "video_potok": { - "name": "Video Potok", - "categoryId": 0, - "url": "http://videopotok.pro/" - }, "vidgyor": { "name": "Vidgyor", "categoryId": 0, @@ -14846,16 +14827,6 @@ "categoryId": 8, "url": "https://www.vinted.com/" }, - "viralgains": { - "name": "ViralGains", - "categoryId": 4, - "url": "https://www.viralgains.com/" - }, - "viralmint": { - "name": "ViralMint", - "categoryId": 7, - "url": "http://www.viralmint.com" - }, "viral_ad_network": { "name": "Viral Ad Network", "categoryId": 4, @@ -14866,6 +14837,16 @@ "categoryId": 2, "url": "https://viral-loops.com/" }, + "viralgains": { + "name": "ViralGains", + "categoryId": 4, + "url": "https://www.viralgains.com/" + }, + "viralmint": { + "name": "ViralMint", + "categoryId": 7, + "url": "http://www.viralmint.com" + }, "virgul": { "name": "Virgul", "categoryId": 4, @@ -14891,6 +14872,11 @@ "categoryId": 6, "url": "http://visioncritical.com/" }, + "visit_streamer": { + "name": "Visit Streamer", + "categoryId": 6, + "url": "http://www.visitstreamer.com/" + }, "visitortrack": { "name": "VisitorTrack", "categoryId": 4, @@ -14901,16 +14887,26 @@ "categoryId": 6, "url": "http://www.visitorville.com" }, - "visit_streamer": { - "name": "Visit Streamer", - "categoryId": 6, - "url": "http://www.visitstreamer.com/" - }, "visscore": { "name": "VisScore", "categoryId": 4, "url": "http://withcubed.com/" }, + "visual_iq": { + "name": "Visual IQ", + "categoryId": 6, + "url": "http://visualiq.com/" + }, + "visual_revenue": { + "name": "Visual Revenue", + "categoryId": 6, + "url": "http://visualrevenue.com/" + }, + "visual_website_optimizer": { + "name": "VWO", + "categoryId": 6, + "url": "https://vwo.com/" + }, "visualdna": { "name": "VisualDNA", "categoryId": 4, @@ -14926,21 +14922,6 @@ "categoryId": 6, "url": "http://www.visualvisitor.com/" }, - "visual_iq": { - "name": "Visual IQ", - "categoryId": 6, - "url": "http://visualiq.com/" - }, - "visual_revenue": { - "name": "Visual Revenue", - "categoryId": 6, - "url": "http://visualrevenue.com/" - }, - "visual_website_optimizer": { - "name": "Visual Website Optimizer", - "categoryId": 6, - "url": "http://visualwebsiteoptimizer.com/" - }, "vivalu": { "name": "VIVALU", "categoryId": 4, @@ -15121,6 +15102,21 @@ "categoryId": 6, "url": "http://webstat.net/" }, + "web_service_award": { + "name": "Web Service Award", + "categoryId": 6, + "url": "http://webserviceaward.com/english/" + }, + "web_traxs": { + "name": "Web Traxs", + "categoryId": 6, + "url": "http://websolutions.thomasnet.com/web-traxs-analytics.php" + }, + "web_wipe_analytics": { + "name": "Web Wipe Analytics", + "categoryId": 6, + "url": "http://tensquare.de" + }, "webads": { "name": "WebAds", "categoryId": 4, @@ -15241,21 +15237,6 @@ "categoryId": 6, "url": "http://webvisor.ru" }, - "web_service_award": { - "name": "Web Service Award", - "categoryId": 6, - "url": "http://webserviceaward.com/english/" - }, - "web_traxs": { - "name": "Web Traxs", - "categoryId": 6, - "url": "http://websolutions.thomasnet.com/web-traxs-analytics.php" - }, - "web_wipe_analytics": { - "name": "Web Wipe Analytics", - "categoryId": 6, - "url": "http://tensquare.de" - }, "wedcs": { "name": "WEDCS", "categoryId": 4, @@ -15326,11 +15307,6 @@ "categoryId": 2, "url": "http://www.widgetbox.com/" }, - "widgetbucks": { - "name": "WidgetBucks", - "categoryId": 4, - "url": "http://www.widgebucks.com/" - }, "wiget_media": { "name": "Wiget Media", "categoryId": 4, @@ -15344,7 +15320,7 @@ "wikia-services.com": { "name": "Wikia Services", "categoryId": 8, - "url": " http://www.wikia.com/fandom" + "url": "http://www.wikia.com/fandom" }, "wikia_beacon": { "name": "Wikia Beacon", @@ -15354,7 +15330,7 @@ "wikia_cdn": { "name": "Wikia CDN", "categoryId": 9, - "url": " http://www.wikia.com/fandom" + "url": "http://www.wikia.com/fandom" }, "wikimedia.org": { "name": "WikiMedia", @@ -15581,16 +15557,6 @@ "categoryId": 6, "url": "https://yahoo.com" }, - "yahoo!_overture": { - "name": "Yahoo! Overture", - "categoryId": 4, - "url": "http://searchmarketing.yahoo.com" - }, - "yahoo!_small_business": { - "name": "Yahoo! Small Business", - "categoryId": 4, - "url": "http://www.pixazza.com/" - }, "yahoo_ad_exchange": { "name": "Yahoo! Ad Exchange", "categoryId": 4, @@ -15616,15 +15582,20 @@ "categoryId": 4, "url": "https://www.verizon.com/" }, - "yahoo_japan": { - "name": "Yahoo! Japan", - "categoryId": 8, - "url": "https://www.yahoo.co.jp/" - }, - "yahoo_retargetting": { - "name": "Yahoo! Retargetting", + "yahoo_japan_retargeting": { + "name": "Yahoo! Japan Retargeting", "categoryId": 4, - "url": "https://www.yahoo.co.jp/" + "url": "http://www.yahoo.com/" + }, + "yahoo_overture": { + "name": "Yahoo! Overture", + "categoryId": 4, + "url": "http://searchmarketing.yahoo.com" + }, + "yahoo_small_business": { + "name": "Yahoo! Small Business", + "categoryId": 4, + "url": "http://www.pixazza.com/" }, "yandex": { "name": "Yandex", @@ -15766,6 +15737,11 @@ "categoryId": 11, "url": null }, + "yo_button": { + "name": "Yo Button", + "categoryId": 2, + "url": "http://www.justyo.co/" + }, "yodle": { "name": "Yodle", "categoryId": 4, @@ -15824,17 +15800,12 @@ "youtube_subscription": { "name": "YouTube Subscription", "categoryId": 2, - "url": "http://www.google.com" - }, - "yo_button": { - "name": "Yo Button", - "categoryId": 2, - "url": "http://www.justyo.co/" + "url": "http://www.youtube.com/" }, "yp": { - "name": "YP", + "name": "YellowPages", "categoryId": 4, - "url": "http://corporate.yp.com/" + "url": "https://www.yellowpages.com/" }, "ysance": { "name": "YSance", @@ -15844,7 +15815,7 @@ "yume": { "name": "YuMe", "categoryId": 4, - "url": null + "url": "http://www.yume.com/" }, "yume,_inc.": { "name": "YuMe, Inc.", @@ -15929,7 +15900,7 @@ "zeta": { "name": "Zeta", "categoryId": 2, - "url": "http://www.zetainteractive.com/index.php/what-we-do/our-technologies/zeta-search.html" + "url": "https://zetaglobal.com/" }, "zeusclicks": { "name": "ZeusClicks", @@ -16017,11 +15988,11 @@ "uicdn.com": "1und1", "website-start.de": "1und1", "24-ads.com": "24-ads.com", + "247-inc.net": "24_7", + "d1af033869koo7.cloudfront.net": "24_7", "counter.24log.ru": "24log", "24smi.net": "24smi", "24smi.org": "24smi", - "247-inc.net": "24_7", - "d1af033869koo7.cloudfront.net": "24_7", "2leep.com": "2leep", "33across.com": "33across", "3dstats.com": "3dstats", @@ -16042,16 +16013,16 @@ "a3cloud.net": "a3cloud_net", "a8.net": "a8", "aaxads.com": "aaxads.com", - "ablida.de": "ablida", - "ablida.net": "ablida", "abtasty.com": "ab_tasty", "d1447tq2m68ekg.cloudfront.net": "ab_tasty", + "ablida.de": "ablida", + "ablida.net": "ablida", "durasite.net": "accelia", "accengage.net": "accengage", "ax.xrea.com": "accessanalyzer", "accesstrade.net": "accesstrade", - "accmgr.com": "accordant_media", "agcdn.com": "accord_group", + "accmgr.com": "accordant_media", "p-td.com": "accuen_media", "acestream.net": "acestream.net", "acint.net": "acint.net", @@ -16062,14 +16033,14 @@ "actionpay.ru": "actionpay", "adnwb.ru": "actionpay", "adonweb.ru": "actionpay", - "activeconversion.com": "activeconversion", - "a-cast.jp": "activecore", - "activemeter.com": "activemeter", - "go.activengage.com": "activengage", "active-agent.com": "active_agent", "trackcmp.net": "active_campaign", "active-srv02.de": "active_performance", "active-tracking.de": "active_performance", + "activeconversion.com": "activeconversion", + "a-cast.jp": "activecore", + "activemeter.com": "activemeter", + "go.activengage.com": "activengage", "actonsoftware.com": "acton", "acuityplatform.com": "acuity_ads", "acxiom-online.com": "acxiom", @@ -16113,8 +16084,16 @@ "ad6media.com": "ad6media", "ad6media.es": "ad6media", "ad6media.fr": "ad6media", - "adacado.com": "adacado", + "a2dfp.net": "ad_decisive", + "addynamo.net": "ad_dynamo", + "ebis.ne.jp": "ad_ebis", + "adlightning.com": "ad_lightning", + "admagnet.net": "ad_magnet", + "amimg.net": "ad_magnet", + "adspirit.de": "ad_spirit", + "adspirit.net": "ad_spirit", "adac.de": "adac_de", + "adacado.com": "adacado", "ozonemedia.com": "adadyn", "adrtx.net": "adality_gmbh", "adalliance.io": "adalliance.io", @@ -16134,6 +16113,8 @@ "adbrite.com": "adbrite", "adbull.com": "adbull", "adbutler.com": "adbutler", + "adc-serv.net": "adc_media", + "adc-srv.net": "adc_media", "adcash.com": "adcash", "vuroll.in": "adchakra", "acs86.com": "adchina", @@ -16152,8 +16133,7 @@ "amgdgt.com": "adconion", "adcrowd.com": "adcrowd", "shop2market.com": "adcurve", - "adc-serv.net": "adc_media", - "adc-srv.net": "adc_media", + "addtocalendar.com": "add_to_calendar", "dpmsrv.com": "addaptive", "yagiay.com": "addefend", "addfreestats.com": "addfreestats", @@ -16165,7 +16145,6 @@ "addthisedge.com": "addthis", "b2btracking.addvalue.de": "addvalue", "addyon.com": "addyon", - "addtocalendar.com": "add_to_calendar", "adeasy.ru": "adeasy", "ipredictive.com": "adelphic", "adengage.com": "adengage", @@ -16196,6 +16175,7 @@ "smartredirect.de": "adgoal", "adgorithms.com": "adgorithms", "adgoto.com": "adgoto", + "adguard.com": "adguard", "adhands.ru": "adhands", "adhese.be": "adhese", "adhese.com": "adhese", @@ -16236,8 +16216,8 @@ "adx1.com": "admachine", "adman.gr": "adman", "adman.in.gr": "adman", - "admantx.com": "admantx.com", "admanmedia.com": "adman_media", + "admantx.com": "admantx.com", "admaster.net": "admaster", "cdnmaster.com": "admaster", "admaster.com.cn": "admaster.cn", @@ -16275,10 +16255,10 @@ "adnet.vn": "adnet", "adnet.biz": "adnet.de", "adnet.de": "adnet.de", - "ad.adnetwork.net": "adnetwork.net", - "adnetworkperformance.com": "adnetworkperformance.com", "adclick.lt": "adnet_media", "adnet.lt": "adnet_media", + "ad.adnetwork.net": "adnetwork.net", + "adnetworkperformance.com": "adnetworkperformance.com", "adserver.adnexio.com": "adnexio", "adnium.com": "adnium.com", "heias.com": "adnologies", @@ -16289,14 +16269,22 @@ "demdex.net": "adobe_audience_manager", "everestjs.net": "adobe_audience_manager", "everesttech.net": "adobe_audience_manager", + "scene7.com": "adobe_dynamic_media", "adobedtm.com": "adobe_dynamic_tag_management", + "2o7.net": "adobe_experience_cloud", + "du8783wkf05yr.cloudfront.net": "adobe_experience_cloud", + "hitbox.com": "adobe_experience_cloud", + "imageg.net": "adobe_experience_cloud", + "nedstat.com": "adobe_experience_cloud", + "omtrdc.net": "adobe_experience_cloud", + "sitestat.com": "adobe_experience_cloud", "adobelogin.com": "adobe_login", "adobetag.com": "adobe_tagmanager", + "typekit.com": "adobe_typekit", + "typekit.net": "adobe_typekit", "adocean.pl": "adocean", "dmtry.com": "adometry", "adomik.com": "adomik", - "adonion.com": "adonion", - "t.adonly.com": "adonly", "adcde.com": "adon_network", "addlvr.com": "adon_network", "adfeedstrk.com": "adon_network", @@ -16309,6 +16297,8 @@ "popcde.com": "adon_network", "sdfje.com": "adon_network", "urtbk.com": "adon_network", + "adonion.com": "adonion", + "t.adonly.com": "adonly", "adoperator.com": "adoperator", "adoric.com": "adoric", "adorika.com": "adorika", @@ -16392,11 +16382,11 @@ "adtrue.com": "adtrue", "adtrustmedia.com": "adtrustmedia", "ad.adtube.ir": "adtube", - "adultadworld.com": "adultadworld", - "adworldmedia.com": "adultadworld", "awempire.com": "adult_webmaster_empire", "dditscdn.com": "adult_webmaster_empire", "livejasmin.com": "adult_webmaster_empire", + "adultadworld.com": "adultadworld", + "adworldmedia.com": "adultadworld", "adup-tech.com": "adup-tech.com", "advaction.ru": "advaction", "aucourant.info": "advaction", @@ -16422,10 +16412,10 @@ "aol.com": "advertising.com", "atwola.com": "advertising.com", "pictela.net": "advertising.com", + "verizonmedia.com": "advertising.com", "advertlets.com": "advertlets", "advertserve.com": "advertserve", "advidi.com": "advidi", - "adview.pl": "adview_(agora)", "am10.ru": "advmaker.ru", "am15.net": "advmaker.ru", "advolution.de": "advolution", @@ -16443,20 +16433,14 @@ "omnitagjs.com": "adyoulike", "adzerk.net": "adzerk", "adzly.com": "adzly", - "a2dfp.net": "ad_decisive", - "addynamo.net": "ad_dynamo", - "ebis.ne.jp": "ad_ebis", - "adlightning.com": "ad_lightning", - "admagnet.net": "ad_magnet", - "amimg.net": "ad_magnet", - "adspirit.de": "ad_spirit", - "adspirit.net": "ad_spirit", "aemediatraffic.com": "aemediatraffic", "hprofits.com": "aemediatraffic", "amxdt.com": "aerify_media", "aerisapi.com": "aeris_weather", - "affectv.com": "affec.tv", + "aerisweather.com": "aeris_weather", + "affectv.com": "affectv", "go.affec.tv": "affectv", + "hybridtheory.com": "affectv", "track.affiliate-b.com": "affiliate-b", "affiliate4you.nl": "affiliate4you", "ads.affbuzzads.com": "affiliatebuzz", @@ -16479,16 +16463,17 @@ "aftv-serving.bid": "aftv-serving.bid", "agkn.com": "aggregate_knowledge", "agilone.com": "agilone", + "adview.pl": "agora", "pingagenow.com": "ahalogy", + "aimediagroup.com": "ai_media_group", "advombat.ru": "aidata", - "aidata.io": "aidata.io", + "aidata.io": "aidata", "aim4media.com": "aim4media", "muscache.com": "airbnb", "musthird.com": "airbnb", "airbrake.io": "airbrake", "airpr.com": "airpr.com", "ab.airpush.com": "airpush", - "aimediagroup.com": "ai_media_group", "abmr.net": "akamai_technologies", "akamai.net": "akamai_technologies", "akamaihd.net": "akamai_technologies", @@ -16501,6 +16486,7 @@ "adn-d.sp.gmossp-sp.jp": "akane", "akanoo.com": "akanoo", "akavita.com": "akavita", + "ads.albawaba.com": "al_bawaba_advertising", "serve.albacross.com": "albacross", "aldi-international.com": "aldi-international.com", "alenty.com": "alenty", @@ -16528,7 +16514,6 @@ "allyes.com": "allyes", "inputs.alooma.com": "alooma", "arena.altitude-arena.com": "altitude_digital", - "ads.albawaba.com": "al_bawaba_advertising", "amadesa.com": "amadesa", "amazon.ca": "amazon", "amazon.co.jp": "amazon", @@ -16540,6 +16525,7 @@ "amazon.it": "amazon", "d3io1k5o0zdpqr.cloudfront.net": "amazon", "amazon-adsystem.com": "amazon_adsystem", + "sizmek.com": "amazon_adsystem", "assoc-amazon.ca": "amazon_associates", "assoc-amazon.co.uk": "amazon_associates", "assoc-amazon.com": "amazon_associates", @@ -16565,10 +16551,10 @@ "ad.amgdgt.com": "amobee", "ads.amgdgt.com": "amobee", "amobee.com": "amobee", + "collective-media.net": "amp_platform", "amplitude.com": "amplitude", "d24n15hnbwhuhn.cloudfront.net": "amplitude", "ampproject.org": "ampproject.org", - "collective-media.net": "amp_platform", "anametrix.net": "anametrix", "ancestrycdn.com": "ancestry_cdn", "ancoraplatform.com": "ancora", @@ -16585,6 +16571,7 @@ "player.anyclip.com": "anyclip", "video-loader.com": "aol_be_on", "aolcdn.com": "aol_cdn", + "isp.netscape.com": "aol_cdn", "apa.at": "apa.at", "apester.com": "apester", "apicit.net": "apicit.net", @@ -16594,7 +16581,6 @@ "de8of677fyt0b.cloudfront.net": "appdynamics", "eum-appdynamics.com": "appdynamics", "jscdn.appier.net": "appier", - "apple.com": "apple", "applifier.com": "applifier", "assets.applovin.com": "applovin", "appmetrx.com": "appmetrx", @@ -16607,6 +16593,7 @@ "arcpublishing.com": "arcpublishing", "ard.de": "ard.de", "areyouahuman.com": "are_you_a_human", + "arkoselabs.com": "arkoselabs.com", "art19.com": "art19", "banners.advsnx.net": "artimedia", "artlebedev.ru": "artlebedev.ru", @@ -16617,6 +16604,9 @@ "ask.com": "ask.com", "aspnetcdn.com": "aspnetcdn", "cdn.astronomer.io": "astronomer", + "ati-host.net": "at_internet", + "aticdn.net": "at_internet", + "xiti.com": "at_internet", "atedra.com": "atedra", "oadts.com": "atg_group", "as00.estara.com": "atg_optimization", @@ -16624,26 +16614,23 @@ "adbureau.net": "atlas", "atdmt.com": "atlas", "atlassbx.com": "atlas", + "track.roiservice.com": "atlas_profitbuilder", "atl-paas.net": "atlassian.net", "atlassian.com": "atlassian.net", "atlassian.net": "atlassian.net", "d12ramskps3070.cloudfront.net": "atlassian.net", "d1xfq2052q7thw.cloudfront.net": "atlassian_marketplace", "marketplace.atlassian.com": "atlassian_marketplace", - "track.roiservice.com": "atlas_profitbuilder", "atomz.com": "atomz_search", "atsfi.de": "atsfi_de", "cdn.attracta.com": "attracta", "locayta.com": "attraqt", - "ati-host.net": "at_internet", - "aticdn.net": "at_internet", - "xiti.com": "at_internet", "ads.audience2media.com": "audience2media", - "12mlbe.com": "audiencerate", - "audiencesquare.com": "audiencesquare.com", "qwobl.net": "audience_ad_network", "revsci.net": "audience_science", "wunderloop.net": "audience_science", + "12mlbe.com": "audiencerate", + "audiencesquare.com": "audiencesquare.com", "auditude.com": "auditude", "audtd.com": "audtd.com", "cdn.augur.io": "augur", @@ -16661,8 +16648,8 @@ "autoscout24.net": "autoscout24.com", "avail.net": "avail", "analytics.avanser.com.au": "avanser", - "avantlink.com": "avantlink", "avmws.com": "avant_metrics", + "avantlink.com": "avantlink", "ads.avazu.net": "avazu_network", "avenseo.com": "avenseo", "adspdbl.com": "avid_media", @@ -16677,8 +16664,8 @@ "b2bcontext.ru": "b2bcontext", "b2bvideo.ru": "b2bvideo", "babator.com": "babator.com", - "widgets.backtype.com": "backtype_widgets", "backbeatmedia.com": "back_beat_media", + "widgets.backtype.com": "backtype_widgets", "bahn.de": "bahn_de", "img-bahn.de": "bahn_de", "baidu.com": "baidu_ads", @@ -16688,10 +16675,10 @@ "baletingo.com": "baletingo.com", "bangdom.com": "bangdom.com", "widgets.bankrate.com": "bankrate", + "bannerconnect.net": "banner_connect", "bannerflow.com": "bannerflow.com", "bannerplay.com": "bannerplay", "cdn.bannersnack.com": "bannersnack", - "bannerconnect.net": "banner_connect", "dn3y71tq7jf07.cloudfront.net": "barilliance", "getbarometer.s3.amazonaws.com": "barometer", "basilic.io": "basilic.io", @@ -16703,6 +16690,7 @@ "bazaarvoice.com": "bazaarvoice", "bbci.co.uk": "bbci", "tracking.bd4travel.com": "bd4travel", + "beopinion.com": "be_opinion", "bfmio.com": "beachfront", "beaconads.com": "beacon_ad_network", "beampulse.com": "beampulse.com", @@ -16726,13 +16714,14 @@ "betterttv.net": "betterttv", "betweendigital.com": "betweendigital.com", "intencysrv.com": "betweendigital.com", - "beopinion.com": "be_opinion", "bid.run": "bid.run", + "bidgear.com": "bidgear", "bidswitch.net": "bidswitch", "exe.bid": "bidswitch", "bttrack.com": "bidtellect", "bidtheatre.com": "bidtheatre", "bidvertiser.com": "bidvertiser", + "bigmobileads.com": "big_mobile", "bigcommerce.com": "bigcommerce.com", "bigmir.net": "bigmir.net", "bigpoint-payment.com": "bigpoint", @@ -16740,7 +16729,6 @@ "bigpoint.net": "bigpoint", "bpcdn.net": "bigpoint", "bpsecure.com": "bigpoint", - "bigmobileads.com": "big_mobile", "bildstatic.de": "bild", "ad-cdn.bilgin.pro": "bilgin_pro", "pixel.bilinmedia.net": "bilin", @@ -16779,6 +16767,8 @@ "brcdn.com": "bloomreach", "brsrvr.com": "bloomreach", "brtstats.com": "bloomreach", + "offerpoint.net": "blue_cherry_group", + "blueserving.com": "blue_seed", "blueconic.net": "blueconic.net", "bluecore.com": "bluecore", "triggeredmail.appspot.com": "bluecore", @@ -16790,15 +16780,14 @@ "japanmetrix.jp": "bluemetrix", "bluenewsupdate.info": "bluenewsupdate.info", "bluestreak.com": "bluestreak", + "bluetriangletech.com": "bluetriangle", "btttag.com": "bluetriangle", - "offerpoint.net": "blue_cherry_group", - "blueserving.com": "blue_seed", "bodelen.com": "bodelen.com", + "tracking.bol.com": "bol_affiliate_program", "qb.boldapps.net": "bold", "secure.apps.shappify.com": "bold", "boldchat.com": "boldchat", "boltdns.net": "boltdns.net", - "tracking.bol.com": "bol_affiliate_program", "ml314.com": "bombora", "bongacams.com": "bongacams.com", "bonial.com": "bonial", @@ -16807,29 +16796,29 @@ "boo-box.com": "boo-box", "booking.com": "booking.com", "bstatic.com": "booking.com", - "boostervideo.ru": "booster_video", "boostbox.com.br": "boost_box", + "boostervideo.ru": "booster_video", "bootstrapcdn.com": "bootstrap", "borrango.com": "borrango.com", "scan.botscanner.com": "botscanner", "boudja.com": "boudja.com", + "bounceexchange.com": "bounce_exchange", "bouncex.com": "bouncex", "bouncex.net": "bouncex", - "bounceexchange.com": "bounce_exchange", - "boxever.com": "boxever", "j.clickdensity.com": "box_uk", + "boxever.com": "boxever", "brainient.com": "brainient", "brainsins.com": "brainsins", "d2xkqxdy6ewr93.cloudfront.net": "brainsins", "app.link": "branch_metrics", "branch.io": "branch_metrics", + "brandaffinity.net": "brand_affinity", + "go.cpmadvisors.com": "brand_networks", + "optorb.com": "brand_networks", "brandmetrics.com": "brandmetrics.com", "brandreachsys.com": "brandreach", "rtbidder.net": "brandscreen", "brandwire.tv": "brandwire.tv", - "brandaffinity.net": "brand_affinity", - "go.cpmadvisors.com": "brand_networks", - "optorb.com": "brand_networks", "branica.com": "branica", "appboycdn.com": "braze", "brealtime.com": "brealtime", @@ -16848,7 +16837,6 @@ "browser-statistik.de": "browser-statistik", "browser-update.org": "browser_update", "btncdn.com": "btncdn.com", - "bluetriangletech.com": "btttag.com", "in.bubblestat.com": "bubblestat", "brighteroption.com": "buddy_media", "bufferapp.com": "buffer_button", @@ -16882,12 +16870,12 @@ "cackle.me": "cackle.me", "d1cerpgff739r9.cloudfront.net": "cadreon", "d1qpxk1wfeh8v1.cloudfront.net": "cadreon", + "callpage.io": "call_page", "callbackhunter.com": "callbackhunter", "callmeasurement.com": "callbox", "callibri.ru": "callibri", "callrail.com": "callrail", "calltracking.ru": "calltracking", - "callpage.io": "call_page", "caltat.com": "caltat.com", "cam-content.com": "cam-content.com", "camakaroda.com": "camakaroda.com", @@ -16904,6 +16892,7 @@ "carbonads.com": "carbonads", "carbonads.net": "carbonads", "fusionads.net": "carbonads", + "cardinalcommerce.com": "cardinal", "cardlytics.com": "cardlytics", "cdn.carrotquest.io": "carrot_quest", "api.cartstack.com": "cartstack", @@ -16911,8 +16900,8 @@ "t.castle.io": "castle", "3gl.net": "catchpoint", "cbox.ws": "cbox", - "cbsinteractive.com": "cbsi.com", "adlog.com.com": "cbs_interactive", + "cbsinteractive.com": "cbs_interactive", "dw.com.com": "cbs_interactive", "ccmbg.com": "ccm_benchmark", "admission.net": "cdk_digital_marketing", @@ -16945,48 +16934,50 @@ "gsn.chameleon.ad": "chameleon", "chango.ca": "chango", "chango.com": "chango", + "channelintelligence.com": "channel_intelligence", + "cptrack.de": "channel_pilot_solutions", "channeladvisor.com": "channeladvisor", "searchmarketing.com": "channeladvisor", "channelfinder.net": "channelfinder", - "channelintelligence.com": "channel_intelligence", - "cptrack.de": "channel_pilot_solutions", "chaordicsystems.com": "chaordic", "chartbeat.com": "chartbeat", "chartbeat.net": "chartbeat", "chaser.ru": "chaser", + "cloud.chatbeacon.io": "chat_beacon", "chatango.com": "chatango", "call.chatra.io": "chatra", "chaturbate.com": "chaturbate.com", "chatwing.com": "chatwing", - "cloud.chatbeacon.io": "chat_beacon", "checkmystats.com.au": "checkmystats", "chefkoch-cdn.de": "chefkoch_de", "chefkoch.de": "chefkoch_de", - "chinesean.com": "chinesean", "tracker.chinmedia.vn": "chin_media", + "chinesean.com": "chinesean", "chitika.net": "chitika", "choicestream.com": "choicestream", "api.getchute.com": "chute", "media.chute.io": "chute", "iqcontentplatform.de": "circit", "data.circulate.com": "circulate", + "p.cityspark.com": "city_spark", "cityads.ru": "cityads", "gameleads.ru": "cityads", - "p.cityspark.com": "city_spark", "ciuvo.com": "ciuvo.com", "widget.civey.com": "civey_widgets", "civicscience.com": "civicscience.com", "ciweb.ciwebgroup.com": "ciwebgroup", "clcknads.pro": "clcknads.pro", + "pulseradius.com": "clear_pier", "clearbit.com": "clearbit.com", "clearsale.com.br": "clearsale", "tag.clrstm.com": "clearstream.tv", - "pulseradius.com": "clear_pier", "api.clerk.io": "clerk.io", - "cleversite.ru": "cleversite", "cleverpush.com": "clever_push", "wzrkt.com": "clever_tap", + "cleversite.ru": "cleversite", "script.click360.io": "click360", + "clickandchat.com": "click_and_chat", + "software.clickback.com": "click_back", "hit.clickaider.com": "clickaider", "clickbank.net": "clickbank", "cbproads.com": "clickbank_proads", @@ -17016,11 +17007,11 @@ "clickprotector.com": "clickprotector", "clickreport.com": "clickreport", "doogleonduty.com": "clickreport", + "ctn.go2cloud.org": "clicks_thru_networks", "clicksor.com": "clicksor", "hatid.com": "clicksor", "lzjl.com": "clicksor", "myroitracking.com": "clicksor", - "ctn.go2cloud.org": "clicks_thru_networks", "clicktale.com": "clicktale", "clicktale.net": "clicktale", "clicktale.pantherssl.com": "clicktale", @@ -17030,8 +17021,6 @@ "getclicky.com": "clicky", "staticstuff.net": "clicky", "clickyab.com": "clickyab", - "clickandchat.com": "click_and_chat", - "software.clickback.com": "click_back", "clicmanager.fr": "clicmanager", "eplayer.clipsyndicate.com": "clip_syndicate", "www.is1.clixgalore.com": "clixgalore", @@ -17053,12 +17042,12 @@ "client.cobrowser.net": "cobrowser", "codeonclick.com": "codeonclick.com", "cogocast.net": "cogocast", + "coin-have.com": "coin_have", + "appsha1.cointraffic.io": "coin_traffic", "authedmine.com": "coinhive", "coin-hive.com": "coinhive", "coinhive.com": "coinhive", "coinurl.com": "coinurl", - "coin-have.com": "coin_have", - "appsha1.cointraffic.io": "coin_traffic", "coll1onf.com": "coll1onf.com", "coll2onf.com": "coll2onf.com", "service.collarity.com": "collarity", @@ -17067,9 +17056,9 @@ "pdk.theplatform.com": "comcast_technology_solutions", "comm100.cn": "comm100", "comm100.com": "comm100", + "cdn-cs.com": "commerce_sciences", "cdn.mercent.com": "commercehub", "link.mercent.com": "commercehub", - "cdn-cs.com": "commerce_sciences", "commercialvalue.org": "commercialvalue.org", "afcyhf.com": "commission_junction", "anrdoezrs.net": "commission_junction", @@ -17106,14 +17095,15 @@ "connextra.com": "connextra", "rs6.net": "constant_contact", "serverbid.com": "consumable", - "d1uwd25yvxu96k.cloudfront.net": "contactme", - "static.contactme.com": "contactme", "contactatonce.com": "contact_at_once", "adrolays.de": "contact_impact", "c-i.as": "contact_impact", "df-srv.de": "contact_impact", + "d1uwd25yvxu96k.cloudfront.net": "contactme", + "static.contactme.com": "contactme", "contaxe.com": "contaxe", "content.ad": "content.ad", + "ingestion.contentinsights.com": "content_insights", "contentexchange.me": "contentexchange.me", "ctfassets.net": "contentful_gmbh", "contentpass.de": "contentpass", @@ -17121,7 +17111,6 @@ "contentsquare.net": "contentsquare.net", "d1aug3dv5magti.cloudfront.net": "contentwrx", "d39se0h2uvfakd.cloudfront.net": "contentwrx", - "ingestion.contentinsights.com": "content_insights", "c-on-text.com": "context", "intext.contextad.pl": "context.ad", "continum.net": "continum_net", @@ -17130,34 +17119,35 @@ "fastclick.net": "conversant", "mediaplex.com": "conversant", "mplxtms.com": "conversant", + "cm-commerce.com": "conversio", "media.conversio.com": "conversio", + "c.conversionlogic.net": "conversion_logic", "conversionruler.com": "conversionruler", "conversionsbox.com": "conversions_box", "conversionsondemand.com": "conversions_on_demand", - "c.conversionlogic.net": "conversion_logic", "ant.conversive.nl": "conversive", "convertexperiments.com": "convert", "d3sjgucddk68ji.cloudfront.net": "convertfox", "convertro.com": "convertro", "d1ivexoxmp59q7.cloudfront.net": "convertro", "conviva.com": "conviva", - "cookiebot.com": "cookiebot", - "cookieq.com": "cookieq", "cookieconsent.silktide.com": "cookie_consent", "cookie-script.com": "cookie_script", + "cookiebot.com": "cookiebot", + "cookieq.com": "cookieq", "lite.piclens.com": "cooliris", "copacet.com": "copacet", "raasnet.com": "coreaudience", "coremotives.com": "coremotives", "coull.com": "coull", + "cpmrocket.com": "cpm_rocket", "cpmprofit.com": "cpmprofit", "cpmstar.com": "cpmstar", - "cpmrocket.com": "cpm_rocket", "captifymedia.com": "cpx.to", "cpx.to": "cpx.to", + "cqcounter.com": "cq_counter", "cqq5id8n.com": "cqq5id8n.com", "cquotient.com": "cquotient.com", - "cqcounter.com": "cq_counter", "craftkeys.com": "craftkeys", "ads.crakmedia.com": "crakmedia_network", "craktraffic.com": "crakmedia_network", @@ -17168,6 +17158,7 @@ "creafi-online-media.com": "creafi", "createjs.com": "createjs", "creativecommons.org": "creative_commons", + "brandwatch.com": "crimsonhexagon_com", "crimsonhexagon.com": "crimsonhexagon_com", "hexagon-analytics.com": "crimsonhexagon_com", "ctnsnet.com": "crimtan", @@ -17181,12 +17172,12 @@ "crsspxl.com": "crosspixel", "crosssell.info": "crosssell.info", "crossss.com": "crossss", + "widget.crowdignite.com": "crowd_ignite", + "static.crowdscience.com": "crowd_science", "ss.crowdprocess.com": "crowdprocess", "our.glossip.nl": "crowdynews", "widget.breakingburner.com": "crowdynews", "widget.crowdynews.com": "crowdynews", - "widget.crowdignite.com": "crowd_ignite", - "static.crowdscience.com": "crowd_science", "searchg2.crownpeak.net": "crownpeak", "snippet.omm.crownpeak.com": "crownpeak", "cryptoloot.pro": "cryptoloot_miner", @@ -17202,6 +17193,7 @@ "cxense.com": "cxense", "cxo.name": "cxo.name", "cyberwing.co.jp": "cyber_wing", + "cybersource.com": "cybersource", "cygnus.com": "cygnus", "da-ads.com": "da-ads.com", "dailymail.co.uk": "dailymail.co.uk", @@ -17234,12 +17226,13 @@ "displaymarketplace.com": "datran", "davebestdeals.com": "davebestdeals.com", "dawandastatic.com": "dawandastatic.com", - "dcbap.com": "dcbap.com", - "dcmn.com": "dcmn.com", "dc-storm.com": "dc_stormiq", "h4k5.com": "dc_stormiq", "stormcontainertag.com": "dc_stormiq", "stormiq.com": "dc_stormiq", + "dcbap.com": "dcbap.com", + "dcmn.com": "dcmn.com", + "statslogger.rocket.persgroep.cloud": "de_persgroep", "deadlinefunnel.com": "deadline_funnel", "cc2.dealer.com": "dealer.com", "d9lq0o81skkdj.cloudfront.net": "dealer.com", @@ -17267,7 +17260,6 @@ "dapxl.com": "deviantart.net", "deviantart.net": "deviantart.net", "my.blueadvertise.com": "dex_platform", - "statslogger.rocket.persgroep.cloud": "de_persgroep", "dgm-au.com": "dgm", "s2d6.com": "dgm", "d31y97ze264gaa.cloudfront.net": "dialogtech", @@ -17299,9 +17291,9 @@ "digitru.st": "digitrust", "widget.dihitt.com.br": "dihitt_badge", "dimml.io": "dimml", - "directadvert.ru": "direct/advert", - "directrev.com": "directrev", "keywordsconnect.com": "direct_keyword_link", + "directadvert.ru": "directadvert", + "directrev.com": "directrev", "discordapp.com": "discord", "d81mfvml8p5ml.cloudfront.net": "display_block", "disqus.com": "disqus", @@ -17430,8 +17422,8 @@ "sitecompass.com": "encore_metrics", "enectoanalytics.com": "enecto_analytics", "trk.enecto.com": "enecto_analytics", - "widget.engageya.com": "engageya_widget", "track.engagesciences.com": "engage_sciences", + "widget.engageya.com": "engageya_widget", "engagio.com": "engagio", "engineseeker.com": "engineseeker", "enquisite.com": "enquisite", @@ -17488,8 +17480,8 @@ "evisitanalyst.com": "evisit_analyst", "evisitcs.com": "evisit_analyst", "websiteperform.com": "evisit_analyst", - "exactag.com": "exactag", "ads.exactdrive.com": "exact_drive", + "exactag.com": "exactag", "exelator.com": "exelate", "dynamicoxygen.com": "exitjunction", "exitjunction.com": "exitjunction", @@ -17508,10 +17500,10 @@ "express.co.uk": "express.co.uk", "d1lp05q4sghme9.cloudfront.net": "expressvpn", "extreme-dm.com": "extreme_tracker", + "eyenewton.ru": "eye_newton", "eyeota.net": "eyeota", "eyereturn.com": "eyereturnmarketing", "eyeviewads.com": "eyeview", - "eyenewton.ru": "eye_newton", "ezakus.net": "ezakus", "f11-ads.com": "f11-ads.com", "facebook.com": "facebook", @@ -17528,9 +17520,9 @@ "thefancy.com": "fancy_widget", "d1q7pknmpq2wkm.cloudfront.net": "fanplayr", "fap.to": "fap.to", + "fastly-insights.com": "fastly_insights", "fastly.net": "fastlylb.net", "fastlylb.net": "fastlylb.net", - "fastly-insights.com": "fastly_insights", "fastpic.ru": "fastpic.ru", "fmpub.net": "federated_media", "fby.s3.amazonaws.com": "feedbackify", @@ -17576,7 +17568,6 @@ "fluidsurveys.com": "fluidsurveys", "cdn.flurry.com": "flurry", "data.flurry.com": "flurry", - "flux.com": "flux", "flx1.com": "flxone", "flxpxl.com": "flxone", "api.flyertown.ca": "flyertown", @@ -17599,17 +17590,12 @@ "fortlachanhecksof.info": "fortlachanhecksof.info", "platform.foursquare.com": "foursquare_widget", "fout.jp": "fout.jp", + "fimserve.com": "fox_audience_network", "fncstatic.com": "foxnews_static", "cdn.foxpush.net": "foxpush", "foxpush.com": "foxpush", "foxydeal.com": "foxydeal_com", - "fimserve.com": "fox_audience_network", "yabidos.com": "fraudlogix", - "freedom.com": "freedom_mortgage", - "freegeoip.net": "freegeoip_net", - "freenet.de": "freenet_de", - "freent.de": "freenet_de", - "fwmrm.net": "freewheel", "besucherstatistiken.com": "free_counter", "compteurdevisite.com": "free_counter", "contadorvisitasgratis.com": "free_counter", @@ -17622,6 +17608,11 @@ "freeonlineusers.com": "free_online_users", "atoomic.com": "free_pagerank", "free-pagerank.com": "free_pagerank", + "freedom.com": "freedom_mortgage", + "freegeoip.net": "freegeoip_net", + "freenet.de": "freenet_de", + "freent.de": "freenet_de", + "fwmrm.net": "freewheel", "heimdall.fresh8.co": "fresh8", "d36mpcpuzc4ztk.cloudfront.net": "freshdesk", "freshdesk.com": "freshdesk", @@ -17648,9 +17639,9 @@ "track.funnelytics.io": "funnelytics", "angsrvr.com": "fyber", "fyber.com": "fyber", + "game-advertising-online.com": "game_advertising_online", "gamedistribution.com": "gamedistribution.com", "gamerdna.com": "gamerdna", - "game-advertising-online.com": "game_advertising_online", "gannett-cdn.com": "gannett", "gaug.es": "gaug.es", "gpm-digital.com": "gazprom-media_digital", @@ -17671,6 +17662,8 @@ "geotrust.com": "geotrust", "geovisite.com": "geovisite", "gestionpub.com": "gestionpub", + "app.getresponse.com": "get_response", + "getsitecontrol.com": "get_site_control", "getconversion.net": "getconversion", "widgets.getglue.com": "getglue", "adhigh.net": "getintent", @@ -17678,12 +17671,10 @@ "yottos.com": "getmyad", "gsfn.us": "getsatisfaction", "gettyimages.com": "gettyimages", - "app.getresponse.com": "get_response", - "getsitecontrol.com": "get_site_control", "sensic.net": "gfk", "gfycat.com": "gfycat.com", - "videostat.com": "giantmedia", "a.giantrealm.com": "giant_realm", + "videostat.com": "giantmedia", "gigaonclick.com": "giga", "analytics.gigyahosting1.com": "gigya", "gigcount.com": "gigya", @@ -17700,17 +17691,17 @@ "gittip.com": "gittip", "sitest.jp": "glad_cube", "glganltcs.space": "glganltcs.space", + "globalwebindex.net": "global_web_index", "globalnotifier.com": "globalnotifier.com", "globalsign.com": "globalsign", "ad.globaltakeoff.net": "globaltakeoff", - "globalwebindex.net": "global_web_index", "glomex.cloud": "glomex.com", "glomex.com": "glomex.com", "glotgrx.com": "glotgrx.com", + "a.gmdelivery.com": "gm_delivery", "ad.atown.jp": "gmo", "gmx.net": "gmx_net", "gmxpro.net": "gmx_net", - "a.gmdelivery.com": "gm_delivery", "go.com": "go.com", "affiliate.godaddy.com": "godaddy_affiliate_program", "trafficfacts.com": "godaddy_site_analytics", @@ -17757,11 +17748,11 @@ "google.ru": "google", "google.se": "google", "google.tn": "google", - "googleapis.com": "googleapis.com", "googleadservices.com": "google_adservices", "google-analytics.com": "google_analytics", "appspot.com": "google_appspot", "adsensecustomsearchads.com": "google_custom_search", + "mail-ads.google.com": "google_email", "fonts.googleapis.com": "google_fonts", "ggpht.com": "google_photos", "1e100cdn.net": "google_servers", @@ -17773,6 +17764,7 @@ "googlecommerce.com": "google_trusted_stores", "googleusercontent.com": "google_users", "gmodules.com": "google_widgets", + "googleapis.com": "googleapis.com", "gooal.herokuapp.com": "goooal", "gooo.al": "goooal", "cdn.triggertag.gorillanation.com": "gorilla_nation", @@ -17795,11 +17787,12 @@ "gravity.com": "gravity_insights", "grvcdn.com": "gravity_insights", "greatviews.de": "greatviews.de", - "greentube.com": "greentube.com", - "gt-cdn.net": "greentube.com", "gandrad.org": "green_and_red", "green-red.com": "green_and_red", "co2stats.com": "green_certified_site", + "greenstory.ca": "green_story", + "greentube.com": "greentube.com", + "gt-cdn.net": "greentube.com", "greystripe.com": "greystripe", "groovehq.com": "groove", "groovinads.com": "groovinads", @@ -17831,9 +17824,9 @@ "heapanalytics.com": "heap", "heatmap.it": "heatmap", "weltsport.net": "heimspiel", - "hellosociety.com": "hellosociety", "hellobar.com": "hello_bar", - "here.com": "here__formerly_navteq_media_solutions_", + "hellosociety.com": "hellosociety", + "here.com": "here", "herokuapp.com": "heroku", "heureka.cz": "heureka-widget", "heybubble.com": "heybubble", @@ -17872,7 +17865,6 @@ "howtank.com": "howtank.com", "hqentertainmentnetwork.com": "hqentertainmentnetwork.com", "justservingfiles.net": "hqentertainmentnetwork.com", - "hsleadflows.net": "hsleadflows.net", "hsoub.com": "hsoub", "hstrck.com": "hstrck.com", "httpool.com": "httpool", @@ -17880,6 +17872,7 @@ "hubrus.com": "hubrus", "hs-analytics.net": "hubspot", "hs-scripts.com": "hubspot", + "hsleadflows.net": "hubspot", "hubapi.com": "hubspot", "hubspot.com": "hubspot", "forms.hubspot.com": "hubspot_forms", @@ -17889,8 +17882,8 @@ "hurra.com": "hurra_tracker", "hybrid.ai": "hybrid.ai", "targetix.net": "hybrid.ai", - "hypercomments.com": "hypercomments", "hypeads.org": "hype_exchange", + "hypercomments.com": "hypercomments", "hyves.nl": "hyves_widgets", "hyvyd.com": "hyvyd", "ib-ibi.com": "i-behavior", @@ -17912,11 +17905,11 @@ "icuazeczpeoohx.com": "icuazeczpeoohx.com", "id-news.net": "id-news.net", "idcdn.de": "id-news.net", - "idealo.com": "idealo_com", + "cdn.id.services": "id_services", "e-generator.com": "ideal_media", + "idealo.com": "idealo_com", "ideoclick.com": "ideoclick", "s.idio.co": "idio", - "cdn.id.services": "id_services", "ie8eamus.com": "ie8eamus.com", "600z.com": "ientry", "api.iflychat.com": "iflychat", @@ -17947,13 +17940,13 @@ "ojrq.net": "impact_radius", "r7ls.net": "impact_radius", "impresionesweb.com": "impresiones_web", - "iljmp.com": "improvely", "360yield.com": "improve_digital", + "iljmp.com": "improvely", "inbenta.com": "inbenta", "inboxsdk.com": "inboxsdk.com", "indeed.com": "indeed", - "casalemedia.com": "index_exchange_", - "indexww.com": "index_exchange_", + "casalemedia.com": "index_exchange", + "indexww.com": "index_exchange", "indieclick.com": "indieclick", "industrybrains.com": "industry_brains", "impdesk.com": "infectious_media", @@ -17968,6 +17961,7 @@ "ivwbox.de": "infonline", "informer.com": "informer_technologies", "infusionsoft.com": "infusionsoft", + "keap.com": "infusionsoft", "innity.com": "innity", "innity.net": "innity", "innogames.com": "innogames.de", @@ -17987,6 +17981,7 @@ "sdad.guru": "instart_logic", "insticator.com": "insticator", "load.instinctiveads.com": "instinctive", + "intango.com": "intango", "adsafeprotected.com": "integral_ad_science", "iasds01.com": "integral_ad_science", "integral-marketing.com": "integral_marketing", @@ -17997,6 +17992,7 @@ "intensedebate.com": "intense_debate", "intentiq.com": "intent_iq", "intentmedia.net": "intent_media", + "intercom.com": "intercom", "intercom.io": "intercom", "intercomassets.com": "intercom", "intercomcdn.com": "intercom", @@ -18004,13 +18000,13 @@ "ads.intergi.com": "intergi", "intermarkets.net": "intermarkets.net", "intermundomedia.com": "intermundo_media", - "voice2page.com": "internetaudioads", - "ibpxl.com": "internetbrands", - "ibsrv.net": "internetbrands", "bbelements.com": "internet_billboard", "goadservices.com": "internet_billboard", "ibillboard.com": "internet_billboard", "mediainter.net": "internet_billboard", + "voice2page.com": "internetaudioads", + "ibpxl.com": "internetbrands", + "ibsrv.net": "internetbrands", "interpolls.com": "interpolls", "ps7894.com": "interyield", "intilery-analytics.com": "intilery", @@ -18020,12 +18016,15 @@ "js12.invoca.net": "invoca", "ringrevenue.com": "invoca", "invodo.com": "invodo", - "iogous.com": "iogous", "ionicframework.com": "ionicframework.com", "dsp.io": "iotec", "iesnare.com": "iovation", "iovation.com": "iovation", "ip-label.net": "ip-label", + "eltoro.com": "ip_targeting", + "iptargeting.com": "ip_targeting", + "ip-tracker.org": "ip_tracker", + "iptrack.io": "ip_tracker", "iperceptions.com": "iperceptions", "dust.ipfingerprint.com": "ipfingerprint", "mbww.com": "ipg_mediabrands", @@ -18036,8 +18035,6 @@ "iprom.net": "iprom", "ipromote.com": "ipromote", "clickmanage.com": "iprospect", - "ip-tracker.org": "ip_tracker", - "iptrack.io": "ip_tracker", "addelive.com": "ironsource", "afdads.com": "ironsource", "delivery47.com": "ironsource", @@ -18045,6 +18042,7 @@ "isocket.com": "isocket", "ispot.tv": "ispot.tv", "itineraire.info": "itineraire.info", + "apple.com": "itunes_link_maker", "autolinkmaker.itunes.apple.com": "itunes_link_maker", "ity.im": "ity.im", "iubenda.com": "iubenda.com", @@ -18060,11 +18058,11 @@ "rpxnow.com": "janrain", "jeeng.com": "jeeng", "api.jeeng.com": "jeeng_widgets", + "phone-analytics.com": "jet_interactive", "jetlore.com": "jetlore", "pixel.wp.com": "jetpack", "stats.wp.com": "jetpack", "jetpackdigital.com": "jetpack_digital", - "phone-analytics.com": "jet_interactive", "jimcdn.com": "jimdo.com", "jimdo.com": "jimdo.com", "jimstatic.com": "jimdo.com", @@ -18078,10 +18076,10 @@ "d1tprjo2w7krrh.cloudfront.net": "jornaya", "cdnjquery.com": "jquery", "jquery.com": "jquery", + "cjmooter.xcache.kinxcdn.com": "js_communications", "jsdelivr.net": "jsdelivr", "jsecoin.com": "jse_coin", "jsuol.com.br": "jsuol.com.br", - "cjmooter.xcache.kinxcdn.com": "js_communications", "contentabc.com": "juggcash", "mofos.com": "juggcash", "juiceadv.com": "juiceadv", @@ -18160,6 +18158,7 @@ "cleanrm.net": "korrelate", "korrelate.net": "korrelate", "trackit.ktxlytics.io": "kortx", + "kaptcha.com": "kount", "krxd.net": "krux_digital", "d31bfnnwekbny6.cloudfront.net": "kupona", "kpcustomer.de": "kupona", @@ -18171,11 +18170,13 @@ "ladsp.com": "ladsp.com", "lanistaads.com": "lanista_concepts", "latimes.com": "latimes", - "launchbit.com": "launchbit", "events.launchdarkly.com": "launch_darkly", + "launchbit.com": "launchbit", "layer-ad.org": "layer-ad.org", "ph-live.slatic.net": "lazada", "lcxdigital.com": "lcx_digital", + "lemde.fr": "le_monde.fr", + "t1.llanalytics.com": "lead_liaison", "leadback.ru": "leadback", "leaddyno.com": "leaddyno", "123-tracker.com": "leadforensics", @@ -18234,21 +18235,19 @@ "analytics.leadlifesolutions.net": "leadlife", "my.leadpages.net": "leadpages", "leadplace.fr": "leadplace", + "scorecard.wspisp.net": "leads_by_web.com", "www.leadscoreapp.dk": "leadscoreapp", "tracker.leadsius.com": "leadsius", - "scorecard.wspisp.net": "leads_by_web.com", "leady.com": "leady", "leady.cz": "leady", - "t1.llanalytics.com": "lead_liaison", "leiki.com": "leiki", "lengow.com": "lengow", "lenmit.com": "lenmit.com", "lentainform.com": "lentainform.com", "lenua.de": "lenua.de", - "js.letvcdn.com": "letv", "letreach.com": "let_reach", + "js.letvcdn.com": "letv", "footprint.net": "level3_communications", - "lemde.fr": "le_monde.fr", "licensebuttons.net": "licensebuttons.net", "lfstmedia.com": "lifestreet_media", "content-recommendation.net": "ligatus", @@ -18257,10 +18256,10 @@ "ligatus.de": "ligatus", "veeseo.com": "ligatus", "limk.com": "limk", - "tongji.linezing.com": "linezing", "line-apps.com": "line_apps", "line-scdn.net": "line_apps", "line.me": "line_apps", + "tongji.linezing.com": "linezing", "linkbucks.com": "linkbucks", "linkconnector.com": "linkconnector", "bizo.com": "linkedin", @@ -18289,6 +18288,10 @@ "listrakbi.com": "listrak", "live2support.com": "live2support", "live800.com": "live800", + "ladesk.com": "live_agent", + "livehelpnow.net": "live_help_now", + "liadm.com": "live_intent", + "l-stat.livejournal.net": "live_journal", "liveadexchanger.com": "liveadexchanger.com", "livechat.s3.amazonaws.com": "livechat", "livechatinc.com": "livechat", @@ -18310,10 +18313,6 @@ "livesportmedia.eu": "livesportmedia.eu", "analytics.livestream.com": "livestream", "livetex.ru": "livetex.ru", - "ladesk.com": "live_agent", - "livehelpnow.net": "live_help_now", - "liadm.com": "live_intent", - "l-stat.livejournal.net": "live_journal", "lkqd.net": "lkqd", "loadbee.com": "loadbee.com", "loadercdn.com": "loadercdn.com", @@ -18335,10 +18334,10 @@ "tracker.samplicio.us": "lucid", "lucidmedia.com": "lucid_media", "lead.adsender.us": "lucini", - "luckypushh.com": "luckypushh.com", "livestatserver.com": "lucky_orange", "luckyorange.com": "lucky_orange", "luckyorange.net": "lucky_orange", + "luckypushh.com": "luckypushh.com", "adelixir.com": "lxr100", "lypn.com": "lynchpin_analytics", "lypn.net": "lynchpin_analytics", @@ -18347,12 +18346,12 @@ "m-pathy.com": "m-pathy", "mpnrs.com": "m._p._newmedia", "m4n.nl": "m4n", + "madadsmedia.com": "mad_ads_media", "madeleine.de": "madeleine.de", "dinclinx.com": "madison_logic", "madisonlogic.com": "madison_logic", "madnet.ru": "madnet", "eu2.madsone.com": "mads", - "madadsmedia.com": "mad_ads_media", "magna.ru": "magna_advertise", "d3ezl4ajpp2zy8.cloudfront.net": "magnetic", "domdex.com": "magnetic", @@ -18366,9 +18365,9 @@ "mradx.net": "mail.ru_group", "odnoklassniki.ru": "mail.ru_group", "ok.ru": "mail.ru_group", - "chimpstatic.com": "mailchimp", - "list-manage.com": "mailchimp", - "mailchimp.com": "mailchimp", + "chimpstatic.com": "mailchimp_tracking", + "list-manage.com": "mailchimp_tracking", + "mailchimp.com": "mailchimp_tracking", "mailerlite.com": "mailerlite.com", "mailtrack.io": "mailtrack.io", "mainadv.com": "mainadv", @@ -18387,6 +18386,8 @@ "qadserve.com": "marimedia", "qadservice.com": "marimedia", "marinsm.com": "marin_search_marketer", + "markandmini.com": "mark_+_mini", + "ak-cdn.placelocal.com": "market_thunder", "dt00.net": "marketgid", "dt07.net": "marketgid", "marketgid.com": "marketgid", @@ -18395,17 +18396,15 @@ "marketo.com": "marketo", "marketo.net": "marketo", "mktoresp.com": "marketo", - "ak-cdn.placelocal.com": "market_thunder", "caanalytics.com": "markmonitor", "mmstat.com": "markmonitor", "netscope.data.marktest.pt": "marktest", - "markandmini.com": "mark_+_mini", "marshadow.io": "marshadow.io", "martiniadnetwork.com": "martini_media", "edigitalsurvey.com": "maru-edu", "marvellousmachine.net": "marvellous_machine", - "mastertarget.ru": "mastertarget", "mbn.com.ua": "master_banner_network", + "mastertarget.ru": "mastertarget", "rns.matelso.de": "matelso", "matheranalytics.com": "mather_analytics", "mathjax.org": "mathjax.org", @@ -18434,8 +18433,10 @@ "media-clic.com": "media-clic", "media-imdb.com": "media-imdb.com", "media.net": "media.net", + "mediaimpact.de": "media_impact", + "mookie1.com": "media_innovation_group", + "idntfy.ru": "media_today", "s1.mediaad.org": "mediaad", - "ads.mediade.sk": "mediadesk", "mlnadvertising.com": "mediaglu", "fhserve.com": "mediahub", "adnet.ru": "medialand", @@ -18455,9 +18456,6 @@ "mediav.com": "mediav", "adnetinteractive.com": "mediawhiz", "adnetinteractive.net": "mediawhiz", - "mediaimpact.de": "media_impact", - "mookie1.com": "media_innovation_group", - "idntfy.ru": "media_today", "mediego.com": "medigo", "medleyads.com": "medley", "adnet.com.tr": "medyanet", @@ -18482,11 +18480,11 @@ "cdn.merklesearch.com": "merkle_research", "rkdms.com": "merkle_rkg", "messenger.com": "messenger.com", + "ad.metanetwork.com": "meta_network", "metaffiliation.com": "metaffiliation.com", "netaffiliation.com": "metaffiliation.com", "metalyzer.com": "metapeople", "mlsat02.de": "metapeople", - "ad.metanetwork.com": "meta_network", "metrigo.com": "metrigo", "metriweb.be": "metriweb", "miaozhen.com": "miaozhen", @@ -18538,8 +18536,8 @@ "ads.mocean.mobi": "mocean_mobile", "ads.moceanads.com": "mocean_mobile", "chat.mochapp.com": "mochapp", - "teljari.is": "modernus", "intelligentpixel.modernimpact.com": "modern_impact", + "teljari.is": "modernus", "modulepush.com": "modulepush.com", "mogointeractive.com": "mogo_interactive", "mokonocdn.com": "mokono_analytics", @@ -18557,16 +18555,16 @@ "mooxar.com": "mooxar", "mopinion.com": "mopinion.com", "mopub.com": "mopub", - "moras.jp": "moreads", "ad.ad-arata.com": "more_communication", + "moras.jp": "moreads", "nedstatbasic.net": "motigo_webstats", "webstats.motigo.com": "motigo_webstats", "analytics.convertlanguage.com": "motionpoint", "mouseflow.com": "mouseflow", "mousestats.com": "mousestats", "s.mousetrace.com": "mousetrace", - "movad.de": "mov.ad_", - "movad.net": "mov.ad_", + "movad.de": "mov.ad", + "movad.net": "mov.ad", "micpn.com": "movable_ink", "mvb.me": "movable_media", "moz.com": "moz", @@ -18591,9 +18589,10 @@ "mythings.com": "mythings", "mystat-in.net": "mytop_counter", "nakanohito.jp": "nakanohito.jp", + "namogoo.coom": "namogoo", "nanigans.com": "nanigans", - "nanorep.com": "nanorep", "audiencemanager.de": "nano_interactive", + "nanorep.com": "nanorep", "narando.com": "narando", "static.bam-x.com": "narrativ", "narrative.io": "narrative_io", @@ -18610,14 +18609,17 @@ "needle.com": "needle", "nekudo.com": "nekudo.com", "neodatagroup.com": "neodata", - "ad-srv.net": "neory_", - "contentspread.net": "neory_", - "neory-tm.com": "neory_", - "simptrack.com": "neory_", + "ad-srv.net": "neory", + "contentspread.net": "neory", + "neory-tm.com": "neory", + "simptrack.com": "neory", "nerfherdersolo.com": "nerfherdersolo_com", "wemfbox.ch": "net-metrix", "cdnma.com": "net-results", "nr7.us": "net-results", + "netavenir.com": "net_avenir", + "netcommunities.com": "net_communities", + "visibility-stats.com": "net_visibility", "netbiscuits.net": "netbiscuits", "bbtrack.net": "netbooster_group", "netbooster.com": "netbooster_group", @@ -18639,10 +18641,10 @@ "netshelter.net": "netshelter", "nsaudience.pl": "netsprint_audience", "nwidget.networkedblogs.com": "networkedblogs", - "netavenir.com": "net_avenir", - "netcommunities.com": "net_communities", - "visibility-stats.com": "net_visibility", "adadvisor.net": "neustar_adadvisor", + "d1ros97qkrwjf5.cloudfront.net": "new_relic", + "newrelic.com": "new_relic", + "nr-data.net": "new_relic", "newscgp.com": "newscgp.com", "nmcdn.us": "newsmax", "newstogram.com": "newstogram", @@ -18650,16 +18652,13 @@ "newsupdatewe.info": "newsupdatewe.info", "ads.newtention.net": "newtention", "ads.newtentionassets.net": "newtention", - "d1ros97qkrwjf5.cloudfront.net": "new_relic", - "newrelic.com": "new_relic", - "nr-data.net": "new_relic", "nexage.com": "nexage", "nexeps.com": "nexeps.com", + "nxtck.com": "next_performance", + "track.nextuser.com": "next_user", "imgsrv.nextag.com": "nextag_roi_optimizer", "nextclick.pl": "nextclick", "nextstat.com": "nextstat", - "nxtck.com": "next_performance", - "track.nextuser.com": "next_user", "d1d8vn0fpluuz7.cloudfront.net": "neytiv", "ads.ngageinc.com": "ngage_inc.", "nice264.com": "nice264.com", @@ -18683,6 +18682,7 @@ "npario-inc.net": "npario", "nplexmedia.com": "nplexmedia", "nrelate.com": "nrelate", + "ns8.com": "ns8", "nt.vc": "nt.vc", "featurelink.com": "ntent", "tracer.jp": "nttcom_online_marketing_solutions", @@ -18708,8 +18708,8 @@ "office.net": "office.net", "office365.com": "office365.com", "oghub.io": "oghub.io", - "adohana.com": "ohana_advertising_network", "ohmystats.com": "oh_my_stats", + "adohana.com": "ohana_advertising_network", "photorank.me": "olapic", "olark.com": "olark", "olx-st.com": "olx-st.com", @@ -18719,13 +18719,6 @@ "omgpm.com": "omg", "omniconvert.com": "omniconvert.com", "omnidsp.com": "omniscienta", - "2o7.net": "omniture__adobe_analytics_", - "du8783wkf05yr.cloudfront.net": "omniture__adobe_analytics_", - "hitbox.com": "omniture__adobe_analytics_", - "imageg.net": "omniture__adobe_analytics_", - "nedstat.com": "omniture__adobe_analytics_", - "omtrdc.net": "omniture__adobe_analytics_", - "sitestat.com": "omniture__adobe_analytics_", "oms.eu": "oms", "omsnative.de": "oms", "onaudience.com": "onaudience", @@ -18736,6 +18729,8 @@ "stat.onestat.com": "onestat", "ocdn.eu": "onet.pl", "onet.pl": "onet.pl", + "onetag.com": "onetag", + "s-onetag.com": "onetag", "onetrust.com": "onetrust", "fogl1onf.com": "onfocus.io", "onfocus.io": "onfocus.io", @@ -18746,6 +18741,12 @@ "moon-ray.com": "ontraport_autopilot", "moonraymarketing.com": "ontraport_autopilot", "ooyala.com": "ooyala.com", + "openadex.dk": "open_adexchange", + "247realmedia.com": "open_adstream", + "oaserve.com": "open_adstream", + "realmedia.com": "open_adstream", + "realmediadigital.com": "open_adstream", + "opensharecount.com": "open_share_count", "oloadcdn.net": "openload", "openload.co": "openload", "openstat.net": "openstat", @@ -18758,12 +18759,6 @@ "openx.org": "openx", "openxenterprise.com": "openx", "servedbyopenx.com": "openx", - "openadex.dk": "open_adexchange", - "247realmedia.com": "open_adstream", - "oaserve.com": "open_adstream", - "realmedia.com": "open_adstream", - "realmediadigital.com": "open_adstream", - "opensharecount.com": "open_share_count", "adsummos.net": "operative_media", "opinary.com": "opinary", "opinionbar.com": "opinionbar", @@ -18791,8 +18786,8 @@ "orange.fr": "orange", "orangeads.fr": "orange", "ads.orange142.com": "orange142", - "otracking.com": "orangesoda", "wanadoo.fr": "orange_france", + "otracking.com": "orangesoda", "emxdgt.com": "orc_international", "static.ordergroove.com": "order_groove", "orelsite.ru": "orel_site", @@ -18833,6 +18828,7 @@ "paypal.com": "paypal", "paypalobjects.com": "paypal", "pcvark.com": "pcvark.com", + "peer39.com": "peer39", "peer39.net": "peer39", "peer5.com": "peer5.com", "peerius.com": "peerius", @@ -18849,10 +18845,10 @@ "perfectaudience.com": "perfect_audience", "prfct.co": "perfect_audience", "perfectmarket.com": "perfect_market", + "performgroup.com": "perform_group", "analytics.performable.com": "performable", "performancing.com": "performancing_metrics", "performax.cz": "performax", - "performgroup.com": "perform_group", "perimeterx.net": "perimeterx.net", "permutive.com": "permutive", "persgroep.net": "persgroep", @@ -18883,8 +18879,8 @@ "tag.bi.serviceplan.com": "plan.net_experience_cloud", "pfrm.co": "platform360", "impact-ad.jp": "platformone", - "playbuzz.com": "playbuzz.com", "loveadvert.ru": "play_by_mamba", + "playbuzz.com": "playbuzz.com", "pof.com": "plenty_of_fish", "analytics.plex.tv": "plex_metrics", "metrics.plex.tv": "plex_metrics", @@ -18940,19 +18936,20 @@ "prismamediadigital.com": "prismamediadigital.com", "privy.com": "privy.com", "pswec.com": "proclivity", + "prodperfect.com": "prodperfect", "lib.productsup.io": "productsup", "proadsnet.com": "profiliad", "profitshare.ro": "profitshare", "tracking.proformics.com": "proformics", "programattik.com": "programattik", "projectwonderful.com": "project_wonderful", + "propelmarketing.com": "propel_marketing", "oclaserver.com": "propeller_ads", "onclasrv.com": "propeller_ads", "onclickads.net": "propeller_ads", "onclkds.com": "propeller_ads", "propellerads.com": "propeller_ads", "propellerpops.com": "propeller_ads", - "propelmarketing.com": "propel_marketing", "proper.io": "propermedia", "st-a.props.id": "props", "propvideo.net": "propvideo_net", @@ -18972,8 +18969,8 @@ "pubble.co": "pubble", "pubdirecte.com": "pubdirecte", "pubgears.com": "pubgears", - "publicidad.net": "publicidad.net", "publicidees.com": "public_ideas", + "publicidad.net": "publicidad.net", "intgr.net": "publir", "pubmatic.com": "pubmatic", "pubnub.com": "pubnub.com", @@ -18981,17 +18978,18 @@ "pulpix.com": "pulpix.com", "tentaculos.net": "pulpo_media", "pulse360.com": "pulse360", + "pulseinsights.com": "pulse_insights", "contextweb.com": "pulsepoint", "pulsepoint.com": "pulsepoint", - "pulseinsights.com": "pulse_insights", "punchtab.com": "punchtab", "purch.com": "purch", "servebom.com": "purch", - "cdn.pprl.io": "pureprofile", "purechat.com": "pure_chat", + "cdn.pprl.io": "pureprofile", "oopt.fr": "purlive", "puserving.com": "puserving.com", "push.world": "push.world", + "pushengage.com": "push_engage", "pushame.com": "pushame.com", "zebra.pushbullet.com": "pushbullet", "pushcrew.com": "pushcrew", @@ -19002,10 +19000,10 @@ "pushno.com": "pushno.com", "pushwhy.com": "pushwhy.com", "pushwoosh.com": "pushwoosh.com", - "pushengage.com": "push_engage", "pvclouds.com": "pvclouds.com", "ads.q1media.com": "q1media", "q1mediahydraplatform.com": "q1media", + "q-divisioncdn.de": "q_division", "qbaka.net": "qbaka", "track.qcri.org": "qcri_analytics", "collect.qeado.com": "qeado", @@ -19034,7 +19032,7 @@ "qservz.com": "quisma", "quisma.com": "quisma", "quora.com": "quora.com", - "q-divisioncdn.de": "q_division", + "ads-digitalkeys.com": "r_advertising", "rackcdn.com": "rackcdn.com", "radarurl.com": "radarurl", "dsa.csdata1.com": "radial", @@ -19050,6 +19048,7 @@ "rambler.ru": "rambler", "top100.ru": "rambler", "rapidspike.com": "rapidspike", + "ravelin.com": "ravelin", "rawgit.com": "rawgit", "raygun.io": "raygun", "count.rbc.ru": "rbc_counter", @@ -19067,6 +19066,8 @@ "reactivpub.fr": "reactivpub", "skinected.com": "reactx", "readrboard.com": "readerboard", + "readme.com": "readme", + "readme.io": "readme", "readspeaker.com": "readspeaker.com", "realclick.co.kr": "realclick", "realperson.de": "realperson.de", @@ -19074,12 +19075,14 @@ "realtime.co": "realtime", "webspectator.com": "realtime", "dcniko1cv0rz.cloudfront.net": "realytics", - "realytics.io": "realytics.io", + "realytics.io": "realytics", "static.rbl.ms": "rebel_mouse", "recettes.net": "recettes.net", "static.recopick.com": "recopick", "recreativ.ru": "recreativ", "analytics.recruitics.com": "recruitics", + "analytics.cohesionapps.com": "red_ventures", + "cdn.cohesionapps.com": "red_ventures", "redblue.de": "redblue_de", "atendesoftware.pl": "redcdn.pl", "redd.it": "reddit", @@ -19097,8 +19100,6 @@ "redtube.com": "redtube.com", "reduxmedia.com": "redux_media", "reduxmediagroup.com": "redux_media", - "analytics.cohesionapps.com": "red_ventures", - "cdn.cohesionapps.com": "red_ventures", "reedbusiness.net": "reed_business_information", "reembed.com": "reembed.com", "reevoo.com": "reevoo.com", @@ -19112,9 +19113,9 @@ "convertglobal.com": "rekko", "convertglobal.s3.amazonaws.com": "rekko", "dnhgz729v27ca.cloudfront.net": "rekko", + "reklamstore.com": "reklam_store", "ad.reklamport.com": "reklamport", "delivery.reklamz.com": "reklamz", - "reklamstore.com": "reklam_store", "adimg.rekmob.com": "rekmob", "relap.io": "relap", "svtrd.com": "relay42", @@ -19133,26 +19134,26 @@ "adinsight.com": "responsetap", "adinsight.eu": "responsetap", "responsetap.com": "responsetap", - "sli-system.com": "resultspage.com", "data.resultlinks.com": "result_links", + "sli-system.com": "resultspage.com", "retailrocket.net": "retailrocket.net", "retailrocket.ru": "retailrocket.net", + "shopify.retargetapp.com": "retarget_app", "retargeter.com": "retargeter_beacon", "retargeting.cl": "retargeting.cl", - "shopify.retargetapp.com": "retarget_app", "d1stxfv94hrhia.cloudfront.net": "retention_science", "waves.retentionscience.com": "retention_science", "reutersmedia.net": "reuters_media", "revcontent.com": "revcontent", + "socialtwist.com": "reve_marketing", "revenue.com": "revenue", "clkads.com": "revenuehits", "clkmon.com": "revenuehits", "clkrev.com": "revenuehits", + "clksite.com": "revenuehits", "eclkspbn.com": "revenuehits", + "imageshack.host": "revenuehits", "revenuemantra.com": "revenuemantra", - "clksite.com": "revenue_hits", - "imageshack.host": "revenue_hits", - "socialtwist.com": "reve_marketing", "revive-adserver.com": "revive_adserver", "revolvermaps.com": "revolver_maps", "cts.tradepub.com": "revresponse", @@ -19162,23 +19163,19 @@ "addesktop.com": "rhythmone", "1rx.io": "rhythmone_beacon", "ria.ru": "ria.ru", + "rmbn.ru": "rich_media_banner_network", "ics0.com": "richrelevance", "richrelevance.com": "richrelevance", - "rmbn.ru": "rich_media_banner_network", "ringier.ch": "ringier.ch", "meteorsolutions.com": "rio_seo", - "riskfield.com": "riskfield.com", + "riskified.com": "riskfield.com", "rncdn3.com": "rncdn3.com", "ro2.biz": "ro2.biz", "rbxcdn.com": "roblox", "getrockerbox.com": "rockerbox", "rocket.la": "rocket.ia", - "rfihub.com": "rocket_fuel", - "rfihub.net": "rocket_fuel", - "ru4.com": "rocket_fuel", - "xplusone.com": "rocket_fuel", - "collector.roistat.com": "roistat", "trk.sodoit.com": "roi_trax", + "collector.roistat.com": "roistat", "rollad.ru": "rollad", "d37gvrvc0wt4s1.cloudfront.net": "rollbar", "get.roost.me": "roost", @@ -19188,9 +19185,9 @@ "routenplaner-karten.com": "routenplaner-karten.com", "rovion.com": "rovion", "rsspump.com": "rsspump", + "creativecdn.com": "rtb_house", "rvty.net": "rtblab", "rtbsuperhub.com": "rtbsuperhub.com", - "creativecdn.com": "rtb_house", "rtl.de": "rtl_group", "static-fra.de": "rtl_group", "technical-service.net": "rtl_group", @@ -19207,7 +19204,6 @@ "cdn.secretrune.com": "rune", "runmewivel.com": "runmewivel.com", "rhythmxchange.com": "rythmxchange", - "ads-digitalkeys.com": "r_advertising", "s24.com": "s24_com", "s3xified.com": "s3xified.com", "camp.sabavision.com": "sabavision", @@ -19217,21 +19213,19 @@ "sailthru.com": "sailthru_horizon", "d16fk4ms6rqz1v.cloudfront.net": "salecycle", "salecycle.com": "salecycle", + "api.salesfeed.com": "sales_feed", + "salesmanago.com": "sales_manago", + "salesmanago.pl": "sales_manago", "force.com": "salesforce.com", "salesforce.com": "salesforce.com", "liveagentforsalesforce.com": "salesforce_live_agent", "salesforceliveagent.com": "salesforce_live_agent", "msgapp.com": "salesfusion", - "salesmanago.com": "salesmanago.pl", "salespidermedia.com": "salespider_media", "salesviewer.com": "salesviewer", - "api.salesfeed.com": "sales_feed", - "salesmanago.pl": "sales_mango", "samba.tv": "samba.tv", "ilsemedia.nl": "sanoma.fi", "sanoma.fi": "sanoma.fi", - "sape.ru": "sape.ru", - "js.sl.pt": "sapo_ads", "d13im3ek7neeqp.cloudfront.net": "sap_crm", "d28ethi6slcjbm.cloudfront.net": "sap_crm", "d2uevgmgh16uk4.cloudfront.net": "sap_crm", @@ -19240,13 +19234,14 @@ "leadforce1.com": "sap_sales_cloud", "vlog.leadformix.com": "sap_sales_cloud", "sap-xm.org": "sap_xm", + "sape.ru": "sape.ru", + "js.sl.pt": "sapo_ads", "aimatch.com": "sas", "sas.com": "sas", "say.ac": "say.ac", - "srv.sayyac.net": "sayyac", "ads.saymedia.com": "say_media", + "srv.sayyac.net": "sayyac", "scarabresearch.com": "scarabresearch", - "scene7.com": "scene7.com", "schibsted.com": "schibsted", "schibsted.io": "schibsted", "schneevonmorgen.com": "schneevonmorgen.com", @@ -19267,6 +19262,7 @@ "searchignite.com": "searchignite", "srtk.net": "searchrev", "tacticalrepublic.com": "second_media", + "securedtouch.com": "securedtouch", "securedvisit.com": "securedvisit", "bacontent.de": "seeding_alliance", "nativendo.de": "seeding_alliance", @@ -19322,19 +19318,19 @@ "services.sheerid.com": "sheerid", "shinystat.com": "shinystat", "shinystat.it": "shinystat", + "app.shoptarget.com.br": "shop_target", + "retargeter.com.br": "shop_target", "shopauskunft.de": "shopauskunft.de", "shopgate.com": "shopgate.com", + "shopify.com": "shopify_stats", "shopifycdn.com": "shopifycdn.com", "shopifycloud.com": "shopifycloud.com", - "shopify.com": "shopify_stats", "shopperapproved.com": "shopper_approved", "shoppingshadow.com": "shopping_com", "tracking.shopping-flux.com": "shopping_flux", "shoprunner.com": "shoprunner", "shopsocially.com": "shopsocially", "shopzilla.com": "shopzilla", - "app.shoptarget.com.br": "shop_target", - "retargeter.com.br": "shop_target", "shortnews.de": "shortnews", "shink.in": "shrink", "shutterstock.com": "shutterstock", @@ -19347,6 +19343,7 @@ "signal.co": "signal", "thebrighttag.com": "signal", "cdn-scripts.signifyd.com": "signifyd", + "signifyd.com": "signifyd", "gw-services.vtrenz.net": "silverpop", "mkt51.net": "silverpop", "mkt912.com": "silverpop", @@ -19360,13 +19357,14 @@ "d8rk54i4mohrb.cloudfront.net": "simplereach", "simplereach.com": "simplereach", "simpli.fi": "simpli.fi", - "simply.com": "simply", "sina.com.cn": "sina", "sinaimg.cn": "sina_cdn", "reporting.singlefeed.com": "singlefeed", "sddan.com": "sirdata", "site24x7rum.com": "site24x7", "site24x7rum.eu": "site24x7", + "sitebooster-fjfmworld-production.azureedge.net": "site_booster", + "a5.ogt.jp": "site_stratos", "siteapps.com": "siteapps", "sitebro.com": "sitebro", "sitebro.com.tw": "sitebro", @@ -19382,11 +19380,8 @@ "ad.sitemaji.com": "sitetag", "sitetag.us": "sitetag", "analytics.sitewit.com": "sitewit", - "sitebooster-fjfmworld-production.azureedge.net": "site_booster", - "a5.ogt.jp": "site_stratos", - "sixt-neuwagen.de": "sixt-neuwagen.de", "ads.sixapart.com": "six_apart_advertising", - "serving-sys.com": "sizmek", + "sixt-neuwagen.de": "sixt-neuwagen.de", "skadtec.com": "skadtec.com", "redirectingat.com": "skimlinks", "skimlinks.com": "skimlinks", @@ -19399,28 +19394,12 @@ "skyscnr.com": "skyscnr.com", "slashdot.org": "slashdot_widget", "sleeknotestaticcontent.sleeknote.com": "sleeknote", + "resultspage.com": "sli_systems", "builder.extensionfactory.com": "slice_factory", "freeskreen.com": "slimcutmedia", "slingpic.com": "slingpic", - "resultspage.com": "sli_systems", "smaato.net": "smaato", "smart4ads.com": "smart4ads", - "bepolite.eu": "smartad", - "smartbn.ru": "smartbn", - "smartclick.net": "smartclick.net", - "smartclip.net": "smartclip", - "smartcontext.pl": "smartcontext", - "smct.co": "smarterclick", - "smartertrack.com": "smartertrack", - "d1n00d49gkbray.cloudfront.net": "smarter_remarketer", - "dhxtx5wtu812h.cloudfront.net": "smarter_remarketer", - "smartertravel.com": "smarter_travel", - "travelsmarter.net": "smarter_travel", - "smartlink.cool": "smartlink.cool", - "getsmartlook.com": "smartlook", - "smartlook.com": "smartlook", - "smartstream.tv": "smartstream.tv", - "smartsuppchat.com": "smartsupp_chat", "sascdn.com": "smart_adserver", "smartadserver.com": "smart_adserver", "styria-digital.com": "smart_adserver", @@ -19430,6 +19409,22 @@ "smartdevicemedia.com": "smart_device_media", "x.cnt.my": "smart_leads", "tracking.smartselling.cz": "smart_selling", + "bepolite.eu": "smartad", + "smartbn.ru": "smartbn", + "smartclick.net": "smartclick.net", + "smartclip.net": "smartclip", + "smartcontext.pl": "smartcontext", + "d1n00d49gkbray.cloudfront.net": "smarter_remarketer", + "dhxtx5wtu812h.cloudfront.net": "smarter_remarketer", + "smartertravel.com": "smarter_travel", + "travelsmarter.net": "smarter_travel", + "smct.co": "smarterclick", + "smartertrack.com": "smartertrack", + "smartlink.cool": "smartlink.cool", + "getsmartlook.com": "smartlook", + "smartlook.com": "smartlook", + "smartstream.tv": "smartstream.tv", + "smartsuppchat.com": "smartsupp_chat", "smi2.net": "smi2.ru", "smi2.ru": "smi2.ru", "stat.media": "smi2.ru", @@ -19439,9 +19434,9 @@ "smyte.com": "smyte", "snacktv.de": "snacktv", "snap.com": "snap", + "snapengage.com": "snap_engage", "sc-static.net": "snapchat", "snapchat.com": "snapchat", - "snapengage.com": "snap_engage", "h-bid.com": "snigelweb", "eu2.snoobi.eu": "snoobi", "snoobi.com": "snoobi_analytics", @@ -19454,11 +19449,11 @@ "mpstat.us": "soasta_mpulse", "tiaa-cref.org": "soasta_mpulse", "sociablelabs.com": "sociable_labs", - "duu8lzqdm8tsz.cloudfront.net": "socialbeat", - "ratevoice.com": "socialrms", "socialamp.com": "social_amp", "socialannex.com": "social_annex", "soclminer.com.br": "social_miner", + "duu8lzqdm8tsz.cloudfront.net": "socialbeat", + "ratevoice.com": "socialrms", "sociaplus.com": "sociaplus.com", "sociomantic.com": "sociomantic", "images.sohu.com": "sohu", @@ -19479,20 +19474,19 @@ "summerhamster.com": "sourcepoint", "d3pkae9owd2lcf.cloudfront.net": "sovrn", "lijit.com": "sovrn", - "s-onetag.com": "sovrn_onetag", "onscroll.com": "sovrn_viewability_solutions", - "sparkasse.de": "sparkasse.de", "rts.sparkstudios.com": "spark_studios", + "sparkasse.de": "sparkasse.de", "speakpipe.com": "speakpipe", "adviva.net": "specific_media", "specificclick.net": "specific_media", "specificmedia.com": "specific_media", "spectate.com": "spectate", + "speedshiftmedia.com": "speed_shift_media", "speedcurve.com": "speedcurve", "admarket.entireweb.com": "speedyads", "affiliate.entireweb.com": "speedyads", "sa.entireweb.com": "speedyads", - "speedshiftmedia.com": "speed_shift_media", "speee-ad.akamaized.net": "speee", "sphere.com": "sphere", "surphace.com": "sphere", @@ -19617,14 +19611,14 @@ "taboola.com": "taboola", "taboolasyndication.com": "taboola", "tacoda.net": "tacoda", + "commander1.com": "tag_commander", + "tagcommander.com": "tag_commander", "tags.tagcade.com": "tagcade", "taggify.net": "taggify", "taggyad.jp": "taggy", "levexis.com": "tagman", - "commander1.com": "tag_commander", - "tagcommander.com": "tag_commander", - "tailsweep.com": "tailsweep", "tailtarget.com": "tail_target", + "tailsweep.com": "tailsweep", "tamedia.ch": "tamedia.ch", "tanx.com": "tanx", "alipcsec.com": "taobao", @@ -19653,7 +19647,6 @@ "watch.teroti.com": "teroti", "webterren.com": "terren", "teufel.de": "teufel.de", - "tmdb.org": "themoviedb", "theadex.com": "the_adex", "connect.decknetwork.net": "the_deck", "gu-web.net": "the_guardian", @@ -19667,6 +19660,7 @@ "w-x.co": "the_weather_company", "weather.com": "the_weather_company", "wfxtriggers.com": "the_weather_company", + "tmdb.org": "themoviedb", "thinglink.com": "thinglink", "online-metrix.net": "threatmetrix", "tidbit.co.in": "tidbit", @@ -19686,7 +19680,6 @@ "statistik-gallup.net": "tns", "tns-cs.net": "tns", "tns-gallup.dk": "tns", - "natoms.com": "tom's_native_ads", "tomnewsupdate.info": "tomnewsupdate.info", "tfag.de": "tomorrow_focus", "srv.clickfuse.com": "tonefuse", @@ -19709,28 +19702,28 @@ "tracemyip.org": "tracemyip", "d2gfdmu30u15x7.cloudfront.net": "traceview", "tracelytics.com": "traceview", + "cdn.trackduck.com": "track_duck", "d2zah9y47r7bi2.cloudfront.net": "trackjs", "dl1d2m8ri9v3j.cloudfront.net": "trackjs", "trackjs.com": "trackjs", "conversionlab.trackset.com": "trackset_conversionlab", "trackuity.com": "trackuity", - "cdn.trackduck.com": "track_duck", "adsrvr.org": "tradedesk", "tradedoubler.com": "tradedoubler", "tradelab.fr": "tradelab", "tradetracker.net": "tradetracker", "cdntrf.com": "traffective", "traffective.com": "traffective", + "my.trafficfuel.com": "traffic_fuel", + "trafficrevenue.net": "traffic_revenue", + "trafficstars.com": "traffic_stars", + "tsyndicate.com": "traffic_stars", "trafficbroker.com": "trafficbroker", "trafficfabrik.com": "trafficfabrik.com", "trafficfactory.biz": "trafficfactory", "trafficforce.com": "trafficforce", "traffichaus.com": "traffichaus", "trafficjunky.net": "trafficjunky", - "my.trafficfuel.com": "traffic_fuel", - "trafficrevenue.net": "traffic_revenue", - "trafficstars.com": "traffic_stars", - "tsyndicate.com": "traffic_stars", "traffiliate.com": "traffiliate", "storage.trafic.ro": "trafic", "trafmag.com": "trafmag.com", @@ -19749,8 +19742,8 @@ "exponential.com": "tribal_fusion", "tribalfusion.com": "tribal_fusion", "tribl.io": "triblio", - "t.myvisitors.se": "triggerbee", "api.temails.com": "trigger_mail_marketing", + "t.myvisitors.se": "triggerbee", "jscache.com": "tripadvisor", "tacdn.com": "tripadvisor", "tamgrt.com": "tripadvisor", @@ -19765,22 +19758,22 @@ "tritondigital.com": "triton_digital", "revelations.trovus.co.uk": "trovus_revelations", "trsv3.com": "trsv3.com", + "truefitcorp.com": "true_fit", "tru.am": "trueanthem", "adlegend.com": "trueffect", "addoer.com": "truehits.net", "truehits.in.th": "truehits.net", "truehits.net": "truehits.net", - "truefitcorp.com": "true_fit", "trumba.com": "trumba", "truoptik.com": "truoptik", "trustarc.com": "trustarc", "truste.com": "trustarc", - "trustedshops.com": "trusted_shops", - "trustev.com": "trustev", "consent.truste.com": "truste_consent", "choices-or.truste.com": "truste_notice", "choices.truste.com": "truste_notice", "privacy-policy.truste.com": "truste_seal", + "trustedshops.com": "trusted_shops", + "trustev.com": "trustev", "secure.comodo.net": "trustlogo", "trustlogo.com": "trustlogo", "trustpilot.com": "trustpilot", @@ -19793,10 +19786,12 @@ "platform.tumblr.com": "tumblr_buttons", "lib.tunein.com": "tune_in", "adagio.turboadv.com": "turbo", + "turn.com": "turn_inc.", + "ngtv.io": "turner", "turner.com": "turner", + "warnermedia.com": "turner", "turnsocial.com": "turnsocial", "turnto.com": "turnto", - "turn.com": "turn_inc.", "tvsquared.com": "tvsquared.com", "tweetboard.com": "tweetboard", "tweetmeme.com": "tweetmeme", @@ -19812,27 +19807,26 @@ "t.co": "twitter", "twimg.com": "twitter", "twitter.com": "twitter", - "twittercounter.com": "twittercounter", "ads-twitter.com": "twitter_ads", "analytics.twitter.com": "twitter_analytics", "tellapart.com": "twitter_for_business", "syndication.twitter.com": "twitter_syndication", + "twittercounter.com": "twittercounter", "twyn.com": "twyn", "txxx.com": "txxx.com", "tynt.com": "tynt", "typeform.com": "typeform", - "typekit.com": "typekit_by_adobe", - "typekit.net": "typekit_by_adobe", "typepad.com": "typepad_stats", "typography.com": "typography.com", "tyroodirect.com": "tyroo", "tyroodr.com": "tyroo", "tzetze.it": "tzetze", "ubersetzung-app.com": "ubersetzung-app.com", - "app.ubertags.com": "ubertags", + "aralego.net": "ucfunnel", + "ucfunnel.com": "ucfunnel", "at.ua": "ucoz", "do.am": "ucoz", - "ucoz.net": "ucoz.net", + "ucoz.net": "ucoz", "ad-api-v01.uliza.jp": "uliza", "api.umbel.com": "umbel", "umebiggestern.club": "umebiggestern.club", @@ -19908,6 +19902,7 @@ "vcita.com": "vcita", "tracking.vcommission.com": "vcommission", "vdopia.com": "vdopia", + "veinteractive.com": "ve_interactive", "vee24.com": "vee24", "velocecdn.com": "velocecdn.com", "mdcn.mobi": "velti_mgage_visualize", @@ -19919,15 +19914,14 @@ "vergic.com": "vergic.com", "d3qxef4rp70elm.cloudfront.net": "vero", "getvero.com": "vero", - "cts.vresp.com": "verticalresponse", - "verticalscope.com": "verticalscope", "verticalacuity.com": "vertical_acuity", "roi.vertical-leap.co.uk": "vertical_leap", + "cts.vresp.com": "verticalresponse", + "verticalscope.com": "verticalscope", "ads.vertoz.com": "vertoz", "banner.vrtzads.com": "vertoz", "veruta.com": "veruta", "vrvm.com": "verve_mobile", - "veinteractive.com": "ve_interactive", "vgwort.de": "vg_wort", "digitaltarget.ru": "vi", "btg.mtvnservices.com": "viacom_tag_container", @@ -19936,14 +19930,14 @@ "intellitxt.com": "vibrant_ads", "vicomi.com": "vicomi.com", "vidazoo.com": "vidazoo.com", + "module-videodesk.com": "video_desk", + "vidtok.ru": "video_potok", "videoadex.com": "videoadex.com", "tidaltv.com": "videology", "videonow.ru": "videonow", "videoplayerhub.com": "videoplayerhub.com", "videoplaza.tv": "videoplaza", "kweb.videostep.com": "videostep", - "module-videodesk.com": "video_desk", - "vidtok.ru": "video_potok", "content.vidgyor.com": "vidgyor", "vidible.tv": "vidible", "assets.vidora.com": "vidora", @@ -19955,29 +19949,29 @@ "vimeocdn.com": "vimeo", "vindicosuite.com": "vindico_group", "vinted.net": "vinted", - "viralgains.com": "viralgains", - "viralmint.com": "viralmint", "viraladnetwork.net": "viral_ad_network", "app.viral-loops.com": "viral_loops", + "viralgains.com": "viralgains", + "viralmint.com": "viralmint", "virgul.com": "virgul", "ssp.virool.com": "virool_player", "virtusize.com": "virtusize", "viewablemedia.net": "visible_measures", "visiblemeasures.com": "visible_measures", "visioncriticalpanels.com": "vision_critical", + "visitstreamer.com": "visit_streamer", "visitortracklog.com": "visitortrack", "visitorville.com": "visitorville", - "visitstreamer.com": "visit_streamer", "d2hkbi3gan6yg6.cloudfront.net": "visscore", - "vdna-assets.com": "visualdna", - "visualdna.com": "visualdna", - "visualstudio.com": "visualstudio.com", - "id-visitors.com": "visualvisitor", "myvisualiq.net": "visual_iq", "visualrevenue.com": "visual_revenue", "d5phz18u4wuww.cloudfront.net": "visual_website_optimizer", "visualwebsiteoptimizer.com": "visual_website_optimizer", "wingify.com": "visual_website_optimizer", + "vdna-assets.com": "visualdna", + "visualdna.com": "visualdna", + "visualstudio.com": "visualstudio.com", + "id-visitors.com": "visualvisitor", "vi-tag.net": "vivalu", "vivistats.com": "vivistats", "vizury.com": "vizury", @@ -20022,6 +20016,9 @@ "web.de": "web.de", "webde.de": "web.de", "webstat.net": "web.stat", + "ssl.webserviceaward.com": "web_service_award", + "webtraxs.com": "web_traxs", + "wipe.de": "web_wipe_analytics", "webads.nl": "webads", "tr.webantenna.info": "webantenna", "webclicks24.com": "webclicks24_com", @@ -20063,9 +20060,6 @@ "webtrendslive.com": "webtrends", "rd.clickshift.com": "webtrends_ads", "web-visor.com": "webvisor", - "ssl.webserviceaward.com": "web_service_award", - "webtraxs.com": "web_traxs", - "wipe.de": "web_wipe_analytics", "weebly.com": "weebly_ads", "widget.weibo.com": "weibo_widget", "westlotto.com": "westlotto_com", @@ -20081,7 +20075,6 @@ "widerplanet.com": "widerplanet", "widespace.com": "widespace", "widgetserver.com": "widgetbox", - "api.widgetbucks.com": "widgetbucks", "3c45d848d99.se": "wiget_media", "wigetmedia.com": "wiget_media", "tracker.wigzopush.com": "wigzo", @@ -20155,21 +20148,21 @@ "yahoo.com": "yahoo", "yahooapis.com": "yahoo", "yimg.com": "yahoo", - "ov.yahoo.co.jp": "yahoo!_overture", - "overture.com": "yahoo!_overture", - "luminate.com": "yahoo!_small_business", - "pixazza.com": "yahoo!_small_business", "ads.yahoo.com": "yahoo_ad_exchange", "yads.yahoo.com": "yahoo_ad_exchange", "yieldmanager.com": "yahoo_ad_exchange", "pr-bh.ybp.yahoo.com": "yahoo_ad_manager", "analytics.yahoo.com": "yahoo_analytics", "np.lexity.com": "yahoo_commerce_central", - "storage-yahoo.jp": "yahoo_japan", - "yahoo.co.jp": "yahoo_japan", - "yahooapis.jp": "yahoo_japan", - "yimg.jp": "yahoo_japan", - "yjtag.jp": "yahoo_japan", + "storage-yahoo.jp": "yahoo_japan_retargeting", + "yahoo.co.jp": "yahoo_japan_retargeting", + "yahooapis.jp": "yahoo_japan_retargeting", + "yimg.jp": "yahoo_japan_retargeting", + "yjtag.jp": "yahoo_japan_retargeting", + "ov.yahoo.co.jp": "yahoo_overture", + "overture.com": "yahoo_overture", + "luminate.com": "yahoo_small_business", + "pixazza.com": "yahoo_small_business", "awaps.yandex.ru": "yandex", "d31j93rd8oukbv.cloudfront.net": "yandex", "webvisor.org": "yandex", @@ -20216,6 +20209,7 @@ "yllix.com": "yllixmedia", "ymetrica1.com": "ymetrica1.com", "ymzrrizntbhde.com": "ymzrrizntbhde.com", + "yoapp.s3.amazonaws.com": "yo_button", "natpal.com": "yodle", "analytics.yola.net": "yola_analytics", "pixel.yola.net": "yola_analytics", @@ -20233,9 +20227,9 @@ "youtube-nocookie.com": "youtube", "youtube.com": "youtube", "ytimg.com": "youtube", - "yoapp.s3.amazonaws.com": "yo_button", "c.ypcdn.com": "yp", "i1.ypcdn.com": "yp", + "yellowpages.com": "yp", "prod-js.aws.y-track.com": "ysance", "y-track.com": "ysance", "yume.com": "yume", @@ -20261,8 +20255,14 @@ "zergnet.com": "zergnet", "zero.kz": "zero.kz", "app.insightgrit.com": "zeta", + "app.ubertags.com": "zeta", "cdn.boomtrain.com": "zeta", "events.api.boomtrain.com": "zeta", + "rfihub.com": "zeta", + "rfihub.net": "zeta", + "ru4.com": "zeta", + "serving-sys.com": "zeta", + "xplusone.com": "zeta", "zeusclicks.com": "zeusclicks", "webtest.net": "ziff_davis", "zdbb.net": "ziff_davis", diff --git a/scripts/README.md b/scripts/README.md index 19cdd496..1ca2e471 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -190,16 +190,16 @@ Optional environment: -## `whotracksme/`: Whotracks.me Database Converter +## `companiesdb/`: Whotracks.me Database Converter -A simple script that converts the Ghostery/Cliqz trackers database to a json format. +A simple script that downloads and updates the companies DB in the `client` +code from [the repo][companiesrepo]. ### Usage ```sh -yarn install -node index.js +cd scripts/companiesdb +./download.sh ``` -You'll find the output in the `whotracksmedb.json` file. Then, move it to -`client/src/helpers/trackers`. +[companiesrepo]: https://github.com/AdguardTeam/companiesdb diff --git a/scripts/companiesdb/download.sh b/scripts/companiesdb/download.sh new file mode 100755 index 00000000..dfa278f0 --- /dev/null +++ b/scripts/companiesdb/download.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +set -e -f -u -x + +# This script syncs companies DB that we bundle with AdGuard Home. The source +# for this database is https://github.com/AdguardTeam/companiesdb. + +whotracksme='https://raw.githubusercontent.com/AdguardTeam/companiesdb/main/dist/whotracksme.json' +adguard='https://raw.githubusercontent.com/AdguardTeam/companiesdb/main/dist/adguard.json' +base_path='../../client/src/helpers/trackers' +readonly whotracksme adguard base_path + +curl "$whotracksme" --output "${base_path}/whotracksme.json" +curl "$adguard" --output "${base_path}/adguard.json" diff --git a/scripts/whotracksme/.gitignore b/scripts/whotracksme/.gitignore deleted file mode 100644 index ffcf3678..00000000 --- a/scripts/whotracksme/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -whotracksme.json \ No newline at end of file diff --git a/scripts/whotracksme/index.js b/scripts/whotracksme/index.js deleted file mode 100644 index ca2f9e72..00000000 --- a/scripts/whotracksme/index.js +++ /dev/null @@ -1,101 +0,0 @@ -const fs = require('fs'); -const sqlite3 = require('sqlite3').verbose(); -const axios = require('axios'); - -const INPUT_SQL_URL = 'https://raw.githubusercontent.com/cliqz-oss/whotracks.me/master/whotracksme/data/assets/trackerdb.sql'; -const OUTPUT_PATH = 'whotracksme.json'; - -async function runScript() { - console.log('Downloading ' + INPUT_SQL_URL); - let response = await axios.get(INPUT_SQL_URL); - let trackersDbSql = response.data; - - let transformToSqlite = function (sql) { - sql = sql.trim(); - - if (sql.indexOf("CREATE TABLE") >= 0) { - sql = sql.replace(/UNIQUE/g, ''); - } - - return sql; - } - - let whotracksme = { - timeUpdated: new Date().toISOString(), - categories: {}, - trackers: {}, - trackerDomains: {} - }; - - console.log('Initializing the in-memory trackers database'); - let db = new sqlite3.Database(':memory:'); - db.serialize(function () { - trackersDbSql.split(/;\s*$/gm).forEach(function (sql) { - sql = transformToSqlite(sql); - db.run(sql, function () { }); - }); - - db.each("SELECT * FROM categories", function (err, row) { - if (err) { - console.error(err); - return; - } - - whotracksme.categories[row.id] = row.name; - }); - - const companies = {}; - db.each("SELECT * FROM companies", function (err, row) { - if (err) { - console.error(err); - return; - } - - companies[row.id] = { - "id": row.id, - "name": row.name, - "website_url": row.website_url - }; - }); - - db.each("SELECT * FROM trackers", function (err, row) { - if (err) { - console.error(err); - return; - } - - const company = companies[row.company_id]; - let url = row.website_url; - if (!url && company) { - url = company.website_url; - } - - whotracksme.trackers[row.id] = { - "name": row.name, - "categoryId": row.category_id, - "url": url, - }; - }); - - db.each("SELECT * FROM tracker_domains", function (err, row) { - if (err) { - console.error(err); - return; - } - - whotracksme.trackerDomains[row.domain] = row.tracker; - }); - }); - - db.close(function (err) { - if (err) { - console.error(err); - return; - } - - fs.writeFileSync(OUTPUT_PATH, JSON.stringify(whotracksme, 0, 4)); - console.log('Trackers json file has been updated: ' + OUTPUT_PATH); - }); -} - -runScript(); \ No newline at end of file diff --git a/scripts/whotracksme/package.json b/scripts/whotracksme/package.json deleted file mode 100644 index f7e24223..00000000 --- a/scripts/whotracksme/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "whotracksme-converter", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "", - "license": "ISC", - "dependencies": { - "axios": "^0.19.2", - "sqlite3": "^4.1.0" - } -} diff --git a/scripts/whotracksme/yarn.lock b/scripts/whotracksme/yarn.lock deleted file mode 100644 index 2456158f..00000000 --- a/scripts/whotracksme/yarn.lock +++ /dev/null @@ -1,698 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - -ajv@^5.3.0: - version "5.5.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" - dependencies: - co "^4.6.0" - fast-deep-equal "^1.0.0" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.3.0" - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - -aproba@^1.0.3: - version "1.2.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" - -are-we-there-yet@~1.1.2: - version "1.1.5" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" - dependencies: - delegates "^1.0.0" - readable-stream "^2.0.6" - -asn1@~0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - dependencies: - safer-buffer "~2.1.0" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - -aws4@^1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" - -axios@^0.19.2: - version "0.19.2" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27" - integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA== - dependencies: - follow-redirects "1.5.10" - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - -bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - dependencies: - tweetnacl "^0.14.3" - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - -chownr@^1.0.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - -combined-stream@1.0.6: - version "1.0.6" - resolved "http://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" - dependencies: - delayed-stream "~1.0.0" - -combined-stream@~1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" - dependencies: - delayed-stream "~1.0.0" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - -console-control-strings@^1.0.0, console-control-strings@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - -core-util-is@1.0.2, core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - dependencies: - assert-plus "^1.0.0" - -debug@=3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" - -debug@^2.1.2: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - dependencies: - ms "2.0.0" - -deep-extend@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - -detect-libc@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - -download-file-sync@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/download-file-sync/-/download-file-sync-1.0.4.tgz#d3e3c543f836f41039455b9034c72e355b036019" - -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - -extend@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - -fast-deep-equal@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" - -fast-json-stable-stringify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - -follow-redirects@1.5.10: - version "1.5.10" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" - integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== - dependencies: - debug "=3.1.0" - -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - -form-data@~2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099" - dependencies: - asynckit "^0.4.0" - combined-stream "1.0.6" - mime-types "^2.1.12" - -fs-minipass@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" - dependencies: - minipass "^2.2.1" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - -gauge@~2.7.3: - version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - dependencies: - aproba "^1.0.3" - console-control-strings "^1.0.0" - has-unicode "^2.0.0" - object-assign "^4.1.0" - signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - wide-align "^1.1.0" - -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - dependencies: - assert-plus "^1.0.0" - -glob@^7.0.5: - version "7.1.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - -har-validator@~5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.0.tgz#44657f5688a22cfd4b72486e81b3a3fb11742c29" - dependencies: - ajv "^5.3.0" - har-schema "^2.0.0" - -has-unicode@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -iconv-lite@^0.4.4: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - dependencies: - safer-buffer ">= 2.1.2 < 3" - -ignore-walk@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" - dependencies: - minimatch "^3.0.4" - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - -ini@~1.3.0: - version "1.3.5" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - -json-schema-traverse@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - -mime-db@~1.36.0: - version "1.36.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.36.0.tgz#5020478db3c7fe93aad7bbcc4dcf869c43363397" - -mime-types@^2.1.12, mime-types@~2.1.19: - version "2.1.20" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.20.tgz#930cb719d571e903738520f8470911548ca2cc19" - dependencies: - mime-db "~1.36.0" - -minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - dependencies: - brace-expansion "^1.1.7" - -minimist@0.0.8: - version "0.0.8" - resolved "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - -minimist@^1.2.0: - version "1.2.0" - resolved "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - -minipass@^2.2.1, minipass@^2.3.3: - version "2.3.4" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.4.tgz#4768d7605ed6194d6d576169b9e12ef71e9d9957" - dependencies: - safe-buffer "^5.1.2" - yallist "^3.0.0" - -minizlib@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.1.tgz#6734acc045a46e61d596a43bb9d9cd326e19cc42" - dependencies: - minipass "^2.2.1" - -mkdirp@^0.5.0, mkdirp@^0.5.1: - version "0.5.1" - resolved "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - dependencies: - minimist "0.0.8" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - -nan@^2.12.1: - version "2.14.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" - integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== - -needle@^2.2.1: - version "2.2.4" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.4.tgz#51931bff82533b1928b7d1d69e01f1b00ffd2a4e" - dependencies: - debug "^2.1.2" - iconv-lite "^0.4.4" - sax "^1.2.4" - -node-pre-gyp@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz#db1f33215272f692cd38f03238e3e9b47c5dd054" - integrity sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q== - dependencies: - detect-libc "^1.0.2" - mkdirp "^0.5.1" - needle "^2.2.1" - nopt "^4.0.1" - npm-packlist "^1.1.6" - npmlog "^4.0.2" - rc "^1.2.7" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^4" - -nopt@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" - dependencies: - abbrev "1" - osenv "^0.1.4" - -npm-bundled@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.5.tgz#3c1732b7ba936b3a10325aef616467c0ccbcc979" - -npm-packlist@^1.1.6: - version "1.1.12" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.12.tgz#22bde2ebc12e72ca482abd67afc51eb49377243a" - dependencies: - ignore-walk "^3.0.1" - npm-bundled "^1.0.1" - -npmlog@^4.0.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" - dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.3" - set-blocking "~2.0.0" - -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - -object-assign@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - dependencies: - wrappy "1" - -os-homedir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - -os-tmpdir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - -osenv@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.0" - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - -process-nextick-args@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" - -psl@^1.1.24: - version "1.1.29" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.29.tgz#60f580d360170bb722a797cc704411e6da850c67" - -punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - -qs@~6.5.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - -rc@^1.2.7: - version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" - dependencies: - deep-extend "^0.6.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - -readable-stream@^2.0.6: - version "2.3.6" - resolved "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -request@^2.87.0: - version "2.88.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.0" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.4.3" - tunnel-agent "^0.6.0" - uuid "^3.3.2" - -rimraf@^2.6.1: - version "2.6.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" - dependencies: - glob "^7.0.5" - -safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - -"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - -sax@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - -semver@^5.3.0: - version "5.6.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" - -set-blocking@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - -signal-exit@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - -sqlite3@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-4.1.0.tgz#e051fb9c133be15726322a69e2e37ec560368380" - integrity sha512-RvqoKxq+8pDHsJo7aXxsFR18i+dU2Wp5o12qAJOV5LNcDt+fgJsc2QKKg3sIRfXrN9ZjzY1T7SNe/DFVqAXjaw== - dependencies: - nan "^2.12.1" - node-pre-gyp "^0.11.0" - request "^2.87.0" - -sshpk@^1.7.0: - version "1.15.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.15.1.tgz#b79a089a732e346c6e0714830f36285cd38191a2" - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -"string-width@^1.0.2 || 2": - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - dependencies: - safe-buffer "~5.1.0" - -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - dependencies: - ansi-regex "^3.0.0" - -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - -tar@^4: - version "4.4.6" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.6.tgz#63110f09c00b4e60ac8bcfe1bf3c8660235fbc9b" - dependencies: - chownr "^1.0.1" - fs-minipass "^1.2.5" - minipass "^2.3.3" - minizlib "^1.1.0" - mkdirp "^0.5.0" - safe-buffer "^5.1.2" - yallist "^3.0.2" - -tough-cookie@~2.4.3: - version "2.4.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" - dependencies: - psl "^1.1.24" - punycode "^1.4.1" - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - -util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - -uuid@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -wide-align@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - dependencies: - string-width "^1.0.2 || 2" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - -yallist@^3.0.0, yallist@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" From 7ee8142b38603ec4e02b91762061b8778442d22d Mon Sep 17 00:00:00 2001 From: Andrey Meshkov Date: Wed, 15 Dec 2021 16:51:03 +0300 Subject: [PATCH 054/135] Pull request: revise vetted lists, fix #2644 Merge in DNS/adguard-home from 2644-reviselists to master Squashed commit of the following: commit 162985aed01742ec19db2f5ba4c642d005cd905f Merge: c7e7f701 72db0149 Author: Andrey Meshkov Date: Wed Dec 15 16:44:39 2021 +0300 Merge branch 'master' into 2644-reviselists commit c7e7f701abd4fbbb4c8eec9b068f895b7ecf69da Author: Andrey Meshkov Date: Wed Dec 15 16:39:29 2021 +0300 revise vetted lists, fix #2644 --- client/src/helpers/filters/filters.json | 30 +++++++++++++++---------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/client/src/helpers/filters/filters.json b/client/src/helpers/filters/filters.json index 37b286bb..565cd74d 100644 --- a/client/src/helpers/filters/filters.json +++ b/client/src/helpers/filters/filters.json @@ -42,6 +42,12 @@ "homepage": "https://someonewhocares.org/", "source": "https://someonewhocares.org/hosts/zero/hosts" }, + "oisd": { + "name": "OISD Blocklist Basic", + "categoryId": "general", + "homepage": "https://oisd.nl/", + "source": "https://abp.oisd.nl/basic/" + }, "game-console-adblock-list": { "name": "Game Console Adblock List", "categoryId": "general", @@ -54,12 +60,6 @@ "homepage": "https://github.com/Perflyst/PiHoleBlocklist", "source": "https://raw.githubusercontent.com/Perflyst/PiHoleBlocklist/master/SmartTV-AGH.txt" }, - "windows-spy-blocker" : { - "name": "WindowsSpyBlocker - Hosts spy rules", - "categoryId": "general", - "homepage": "https://github.com/crazy-max/WindowsSpyBlocker", - "source": "https://raw.githubusercontent.com/crazy-max/WindowsSpyBlocker/master/data/hosts/spy.txt" - }, "nocoin-filter-list": { "name": "NoCoin Filter List", "categoryId": "security", @@ -84,18 +84,18 @@ "homepage": "https://gitlab.com/curben/urlhaus-filter", "source": "https://curben.gitlab.io/malware-filter/urlhaus-filter-agh-online.txt" }, + "dandelion-sprouts-anti-malware-list": { + "name": "Dandelion Sprout's Anti-Malware List", + "categoryId": "security", + "homepage": "https://github.com/DandelionSprout/adfilt", + "source": "https://raw.githubusercontent.com/DandelionSprout/adfilt/master/Alternate%20versions%20Anti-Malware%20List/AntiMalwareAdGuardHome.txt" + }, "NOR-dandelion-sprouts-nordiske-filtre": { "name": "NOR: Dandelion Sprouts nordiske filtre", "categoryId": "regional", "homepage": "https://github.com/DandelionSprout/adfilt", "source": "https://raw.githubusercontent.com/DandelionSprout/adfilt/master/NorwegianExperimentalList%20alternate%20versions/NordicFiltersAdGuardHome.txt" }, - "TUR-nurcan-turk-ad-list": { - "name": "TUR: nurcan Türk ad-list", - "categoryId": "regional", - "homepage": "https://github.com/DandelionSprout/adfilt", - "source": "https://raw.githubusercontent.com/xorcan/hosts/master/xhosts.txt" - }, "POL-polish-filters-for-pihole": { "name": "POL: Polish filters for Pi hole", "categoryId": "regional", @@ -155,6 +155,12 @@ "categoryId": "regional", "homepage": "https://forums.lanik.us/viewforum.php?f=100", "source": "https://easylist-downloads.adblockplus.org/easylistdutch.txt" + }, + "windows-spy-blocker" : { + "name": "WindowsSpyBlocker - Hosts spy rules", + "categoryId": "other", + "homepage": "https://github.com/crazy-max/WindowsSpyBlocker", + "source": "https://raw.githubusercontent.com/crazy-max/WindowsSpyBlocker/master/data/hosts/spy.txt" } } } From da0d1cb754339eed125a5b0ee22386efbef7bb3f Mon Sep 17 00:00:00 2001 From: Matt <5032824+mdawsonuk@users.noreply.github.com> Date: Wed, 15 Dec 2021 23:05:51 +0000 Subject: [PATCH 055/135] Log successful login attempts in addition to failed ones --- internal/home/auth.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/internal/home/auth.go b/internal/home/auth.go index bfcc7267..f3001153 100644 --- a/internal/home/auth.go +++ b/internal/home/auth.go @@ -455,10 +455,11 @@ func handleLogin(w http.ResponseWriter, r *http.Request) { return } + + var ip net.IP + ip, err = realIP(r) if len(cookie) == 0 { - var ip net.IP - ip, err = realIP(r) if err != nil { log.Info("auth: getting real ip from request: %s", err) } else if ip == nil { @@ -473,6 +474,15 @@ func handleLogin(w http.ResponseWriter, r *http.Request) { return } + + if err != nil { + log.Info("auth: getting real ip from request: %s", err) + } else if ip == nil { + // Technically shouldn't happen. + log.Info("auth: user %q successfully logged in from unknown ip", req.Name) + } else { + log.Info("auth: user %q successfully logged in from ip %q", req.Name, ip) + } w.Header().Set("Set-Cookie", cookie) From 4be69d35eb276266b846a8a01481894f35d244dd Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Thu, 16 Dec 2021 15:58:54 +0300 Subject: [PATCH 056/135] Pull request: aghnet: do not turn bad etc/hosts entries into rules Updates #3946. Squashed commit of the following: commit 5d632dc4c49325308570adbfbc0fe333528989b5 Author: Ainar Garipov Date: Thu Dec 16 15:49:51 2021 +0300 aghnet: imp code commit 4da620ee625718f5cd7549277c483631f22b977b Author: Ainar Garipov Date: Thu Dec 16 15:33:39 2021 +0300 aghnet: do not turn bad etc/hosts entries into rules --- internal/aghnet/hostscontainer.go | 41 ++++++++++++++++++------------ internal/aghnet/testdata/etc_hosts | 6 +++++ 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/internal/aghnet/hostscontainer.go b/internal/aghnet/hostscontainer.go index ca8631c2..e4c1678b 100644 --- a/internal/aghnet/hostscontainer.go +++ b/internal/aghnet/hostscontainer.go @@ -100,16 +100,16 @@ const hostsContainerPref = "hosts container" type HostsContainer struct { // requestMatcher matches the requests and translates the rules. It's // embedded to implement MatchRequest and Translate for *HostsContainer. + // + // TODO(a.garipov, e.burkov): Consider fully merging into HostsContainer. requestMatcher - // listID is the identifier for the list of generated rules. - listID int - // done is the channel to sign closing the container. done chan struct{} // updates is the channel for receiving updated hosts. updates chan *netutil.IPMap + // last is the set of hosts that was cached within last detected change. last *netutil.IPMap @@ -118,8 +118,12 @@ type HostsContainer struct { // w tracks the changes in specified files and directories. w aghos.FSWatcher + // patterns stores specified paths in the fs.Glob-compatible form. patterns []string + + // listID is the identifier for the list of generated rules. + listID int } // ErrNoHostsPaths is returned when there are no valid paths to watch passed to @@ -288,7 +292,7 @@ func (hp *hostsParser) parseFile( s := bufio.NewScanner(r) for s.Scan() { ip, hosts := hp.parseLine(s.Text()) - if ip == nil { + if ip == nil || len(hosts) == 0 { continue } @@ -310,21 +314,26 @@ func (hp *hostsParser) parseLine(line string) (ip net.IP, hosts []string) { } for _, f := range fields[1:] { - switch hashIdx := strings.IndexByte(f, '#'); hashIdx { - case -1: - hosts = append(hosts, f) - - continue - case 0: - // Go on. - default: + hashIdx := strings.IndexByte(f, '#') + if hashIdx == 0 { + // The rest of the fields are a part of the comment so return. + break + } else if hashIdx > 0 { // Only a part of the field is a comment. - hosts = append(hosts, f[:hashIdx]) + f = f[:hashIdx] } - // The rest of the fields are a part of the comment so skip - // immediately. - break + // Make sure that invalid hosts aren't turned into rules. + // + // See https://github.com/AdguardTeam/AdGuardHome/issues/3946. + err := netutil.ValidateDomainName(f) + if err != nil { + log.Error("%s: host %q is invalid, ignoring", hostsContainerPref, f) + + continue + } + + hosts = append(hosts, f) } return ip, hosts diff --git a/internal/aghnet/testdata/etc_hosts b/internal/aghnet/testdata/etc_hosts index d3cabac2..15e07566 100644 --- a/internal/aghnet/testdata/etc_hosts +++ b/internal/aghnet/testdata/etc_hosts @@ -8,7 +8,13 @@ # See https://github.com/AdguardTeam/AdGuardHome/issues/3846. 1.0.0.2 a.whole lot.of aliases for.testing +# See https://github.com/AdguardTeam/AdGuardHome/issues/3946. +1.0.0.3 * +1.0.0.4 *.com + # Same for IPv6. ::1 simplehost :: hello hello.world ::2 a.whole lot.of aliases for.testing +::3 * +::4 *.com From b3210cfa7ea079676a877f6aaea3fc6210dfe286 Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Thu, 16 Dec 2021 20:54:59 +0300 Subject: [PATCH 057/135] Pull request: 3835 check ports properly Merge in DNS/adguard-home from 3835-imp-error-msg to master Updates #3835. Squashed commit of the following: commit ba31cb67833df9f293fe13be96a35c2a823f115b Merge: 19c7dfc9 4be69d35 Author: Eugene Burkov Date: Thu Dec 16 20:07:25 2021 +0300 Merge branch 'master' into 3835-imp-error-msg commit 19c7dfc96284a271d30d7111c86c439be3461389 Author: Eugene Burkov Date: Thu Dec 16 19:42:10 2021 +0300 all: imp more commit 5b9c6a3e357238bf44ef800a6033a7671f27d469 Author: Eugene Burkov Date: Thu Dec 16 18:57:02 2021 +0300 all: introduce aghhttp commit 29caa17200957aad2b98461573bb33d80931adcf Author: Eugene Burkov Date: Thu Dec 16 14:23:53 2021 +0300 all: imp more commit 754c020191d7b9518cb0e789f3f5741ba38c3cf4 Author: Eugene Burkov Date: Wed Dec 15 20:53:41 2021 +0300 all: imp code, log changes commit ec712dd562f31fcc2fbc27e7035f926c79827444 Author: Eugene Burkov Date: Wed Dec 15 18:40:54 2021 +0300 home: check ports properly --- CHANGELOG.md | 2 + internal/aghhttp/aghhttp.go | 24 ++++++ internal/aghnet/hostscontainer.go | 2 +- internal/aghnet/interfaces.go | 8 ++ internal/aghnet/net.go | 65 +++++----------- internal/aghnet/net_others.go | 20 ----- internal/aghnet/net_unix.go | 21 ++++-- internal/aghnet/net_windows.go | 45 +++++++++++ internal/dhcpd/http.go | 94 ++++++++++++++--------- internal/dnsforward/access.go | 9 ++- internal/dnsforward/http.go | 61 +++++++++------ internal/filtering/blocked.go | 7 +- internal/filtering/filtering.go | 3 +- internal/filtering/rewrites.go | 10 ++- internal/filtering/safebrowsing.go | 13 +--- internal/filtering/safesearch.go | 10 ++- internal/home/auth.go | 12 +-- internal/home/clientshttp.go | 37 ++++++--- internal/home/config.go | 47 ++++++++---- internal/home/control.go | 28 ++----- internal/home/controlfiltering.go | 85 +++++++++++++++------ internal/home/controlinstall.go | 116 ++++++++++++++++++++--------- internal/home/controlupdate.go | 26 +++++-- internal/home/home.go | 45 +++++++---- internal/home/i18n.go | 3 +- internal/home/portsmap.go | 63 ++++++++++++++++ internal/home/tls.go | 90 +++++++++++++++++----- internal/home/web.go | 13 +--- internal/querylog/http.go | 35 +++++---- internal/stats/http.go | 25 +++---- main.go | 4 + 31 files changed, 675 insertions(+), 348 deletions(-) create mode 100644 internal/aghhttp/aghhttp.go delete mode 100644 internal/aghnet/net_others.go create mode 100644 internal/aghnet/net_windows.go create mode 100644 internal/home/portsmap.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b0f572a..c4b7ccad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,7 @@ and this project adheres to ### Changed +- Port bindings are now checked for uniqueness ([#3835]). - The DNSSEC check now simply checks against the AD flag in the response ([#3904]). - Client objects in the configuration file are now sorted ([#3933]). @@ -241,6 +242,7 @@ In this release, the schema version has changed from 10 to 12. [#3772]: https://github.com/AdguardTeam/AdGuardHome/issues/3772 [#3778]: https://github.com/AdguardTeam/AdGuardHome/issues/3778 [#3815]: https://github.com/AdguardTeam/AdGuardHome/issues/3815 +[#3835]: https://github.com/AdguardTeam/AdGuardHome/issues/3835 [#3887]: https://github.com/AdguardTeam/AdGuardHome/issues/3887 [#3890]: https://github.com/AdguardTeam/AdGuardHome/issues/3890 [#3904]: https://github.com/AdguardTeam/AdGuardHome/issues/3904 diff --git a/internal/aghhttp/aghhttp.go b/internal/aghhttp/aghhttp.go new file mode 100644 index 00000000..666342ea --- /dev/null +++ b/internal/aghhttp/aghhttp.go @@ -0,0 +1,24 @@ +// Package aghhttp provides some common methods to work with HTTP. +package aghhttp + +import ( + "fmt" + "io" + "net/http" + + "github.com/AdguardTeam/golibs/log" +) + +// OK responds with word OK. +func OK(w http.ResponseWriter) { + if _, err := io.WriteString(w, "OK\n"); err != nil { + log.Error("couldn't write body: %s", err) + } +} + +// Error writes formatted message to w and also logs it. +func Error(r *http.Request, w http.ResponseWriter, code int, format string, args ...interface{}) { + text := fmt.Sprintf(format, args...) + log.Error("%s %s: %s", r.Method, r.URL, text) + http.Error(w, text, code) +} diff --git a/internal/aghnet/hostscontainer.go b/internal/aghnet/hostscontainer.go index e4c1678b..85d6103d 100644 --- a/internal/aghnet/hostscontainer.go +++ b/internal/aghnet/hostscontainer.go @@ -431,7 +431,7 @@ func (hp *hostsParser) writeMainHostRule(host string, ip net.IP) (added, addedPt rwSuccess = "^$dnsrewrite=NOERROR;" rwSuccessPTR = "^$dnsrewrite=NOERROR;PTR;" - modLen = len("||") + len(rwSuccess) + modLen = len("||") + len(rwSuccess) + len(";") modLenPTR = len("||") + len(rwSuccessPTR) ) diff --git a/internal/aghnet/interfaces.go b/internal/aghnet/interfaces.go index c8efc57b..b0511b0d 100644 --- a/internal/aghnet/interfaces.go +++ b/internal/aghnet/interfaces.go @@ -118,3 +118,11 @@ func IfaceDNSIPAddrs( return addrs, nil } + +// interfaceName is a string containing network interface's name. The name is +// used in file walking methods. +type interfaceName string + +// Use interfaceName in the OS-independent code since it's actually only used in +// several OS-dependent implementations which causes linting issues. +var _ = interfaceName("") diff --git a/internal/aghnet/net.go b/internal/aghnet/net.go index 393778ad..f8e36406 100644 --- a/internal/aghnet/net.go +++ b/internal/aghnet/net.go @@ -4,13 +4,11 @@ package aghnet import ( "encoding/json" "fmt" + "io" "net" - "os" "os/exec" - "runtime" "strings" "syscall" - "time" "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/log" @@ -189,57 +187,30 @@ func GetSubnet(ifaceName string) *net.IPNet { return nil } -// CheckPortAvailable - check if TCP port is available -func CheckPortAvailable(host net.IP, port int) error { - ln, err := net.Listen("tcp", netutil.JoinHostPort(host.String(), port)) - if err != nil { - return err +// CheckPort checks if the port is available for binding. +func CheckPort(network string, ip net.IP, port int) (err error) { + var c io.Closer + addr := netutil.IPPort{IP: ip, Port: port}.String() + switch network { + case "tcp": + c, err = net.Listen(network, addr) + case "udp": + c, err = net.ListenPacket(network, addr) + default: + return nil } - _ = ln.Close() - // It seems that net.Listener.Close() doesn't close file descriptors right away. - // We wait for some time and hope that this fd will be closed. - time.Sleep(100 * time.Millisecond) - return nil + return errors.WithDeferred(err, closePortChecker(c)) } -// CheckPacketPortAvailable - check if UDP port is available -func CheckPacketPortAvailable(host net.IP, port int) error { - ln, err := net.ListenPacket("udp", netutil.JoinHostPort(host.String(), port)) - if err != nil { - return err - } - _ = ln.Close() - - // It seems that net.Listener.Close() doesn't close file descriptors right away. - // We wait for some time and hope that this fd will be closed. - time.Sleep(100 * time.Millisecond) - return err -} - -// ErrorIsAddrInUse - check if error is "address already in use" -func ErrorIsAddrInUse(err error) bool { - errOpError, ok := err.(*net.OpError) - if !ok { +// IsAddrInUse checks if err is about unsuccessful address binding. +func IsAddrInUse(err error) (ok bool) { + var sysErr syscall.Errno + if !errors.As(err, &sysErr) { return false } - errSyscallError, ok := errOpError.Err.(*os.SyscallError) - if !ok { - return false - } - - errErrno, ok := errSyscallError.Err.(syscall.Errno) - if !ok { - return false - } - - if runtime.GOOS == "windows" { - const WSAEADDRINUSE = 10048 - return errErrno == WSAEADDRINUSE - } - - return errErrno == syscall.EADDRINUSE + return isAddrInUse(sysErr) } // SplitHost is a wrapper for net.SplitHostPort for the cases when the hostport diff --git a/internal/aghnet/net_others.go b/internal/aghnet/net_others.go deleted file mode 100644 index de88ed80..00000000 --- a/internal/aghnet/net_others.go +++ /dev/null @@ -1,20 +0,0 @@ -//go:build !(linux || darwin || freebsd || openbsd) -// +build !linux,!darwin,!freebsd,!openbsd - -package aghnet - -import ( - "github.com/AdguardTeam/AdGuardHome/internal/aghos" -) - -func canBindPrivilegedPorts() (can bool, err error) { - return aghos.HaveAdminRights() -} - -func ifaceHasStaticIP(string) (ok bool, err error) { - return false, aghos.Unsupported("checking static ip") -} - -func ifaceSetStaticIP(string) (err error) { - return aghos.Unsupported("setting static ip") -} diff --git a/internal/aghnet/net_unix.go b/internal/aghnet/net_unix.go index efca131b..9f0f5011 100644 --- a/internal/aghnet/net_unix.go +++ b/internal/aghnet/net_unix.go @@ -1,8 +1,19 @@ -//go:build openbsd || freebsd || linux -// +build openbsd freebsd linux +//go:build openbsd || freebsd || linux || darwin +// +build openbsd freebsd linux darwin package aghnet -// interfaceName is a string containing network interface's name. The name is -// used in file walking methods. -type interfaceName string +import ( + "io" + "syscall" + + "github.com/AdguardTeam/golibs/errors" +) + +func closePortChecker(c io.Closer) (err error) { + return c.Close() +} + +func isAddrInUse(err syscall.Errno) (ok bool) { + return errors.Is(err, syscall.EADDRINUSE) +} diff --git a/internal/aghnet/net_windows.go b/internal/aghnet/net_windows.go new file mode 100644 index 00000000..bbbb81d7 --- /dev/null +++ b/internal/aghnet/net_windows.go @@ -0,0 +1,45 @@ +//go:build !(linux || darwin || freebsd || openbsd) +// +build !linux,!darwin,!freebsd,!openbsd + +package aghnet + +import ( + "io" + "syscall" + "time" + + "github.com/AdguardTeam/AdGuardHome/internal/aghos" + "github.com/AdguardTeam/golibs/errors" + "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") +} + +func ifaceSetStaticIP(string) (err error) { + return aghos.Unsupported("setting static ip") +} + +func closePortChecker(c io.Closer) (err error) { + if err = c.Close(); err != nil { + return err + } + + // It seems that net.Listener.Close() doesn't close file descriptors right + // away. We wait for some time and hope that this fd will be closed. + // + // TODO(e.burkov): Investigate the purpose of the line and perhaps use more + // reliable approach. + time.Sleep(100 * time.Millisecond) + + return nil +} + +func isAddrInUse(err syscall.Errno) (ok bool) { + return errors.Is(err, windows.WSAEADDRINUSE) +} diff --git a/internal/dhcpd/http.go b/internal/dhcpd/http.go index e016dee8..78016010 100644 --- a/internal/dhcpd/http.go +++ b/internal/dhcpd/http.go @@ -10,18 +10,13 @@ import ( "strings" "time" + "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/AdGuardHome/internal/aghnet" "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/timeutil" ) -func httpError(r *http.Request, w http.ResponseWriter, code int, format string, args ...interface{}) { - text := fmt.Sprintf(format, args...) - log.Info("DHCP: %s %s: %s", r.Method, r.URL, text) - http.Error(w, text, code) -} - type v4ServerConfJSON struct { GatewayIP net.IP `json:"gateway_ip"` SubnetMask net.IP `json:"subnet_mask"` @@ -87,8 +82,13 @@ func (s *Server) handleDHCPStatus(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") err := json.NewEncoder(w).Encode(status) if err != nil { - httpError(r, w, http.StatusInternalServerError, "Unable to marshal DHCP status json: %s", err) - return + aghhttp.Error( + r, + w, + http.StatusInternalServerError, + "Unable to marshal DHCP status json: %s", + err, + ) } } @@ -211,36 +211,34 @@ func (s *Server) handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) { err := json.NewDecoder(r.Body).Decode(conf) if err != nil { - httpError(r, w, http.StatusBadRequest, - "failed to parse new dhcp config json: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "failed to parse new dhcp config json: %s", err) return } srv4, v4Enabled, err := s.handleDHCPSetConfigV4(conf) if err != nil { - httpError(r, w, http.StatusBadRequest, "bad dhcpv4 configuration: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "bad dhcpv4 configuration: %s", err) return } srv6, v6Enabled, err := s.handleDHCPSetConfigV6(conf) if err != nil { - httpError(r, w, http.StatusBadRequest, "bad dhcpv6 configuration: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "bad dhcpv6 configuration: %s", err) return } if conf.Enabled == nbTrue && !v4Enabled && !v6Enabled { - httpError(r, w, http.StatusBadRequest, - "dhcpv4 or dhcpv6 configuration must be complete") + aghhttp.Error(r, w, http.StatusBadRequest, "dhcpv4 or dhcpv6 configuration must be complete") return } err = s.Stop() if err != nil { - httpError(r, w, http.StatusInternalServerError, "stopping dhcp: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "stopping dhcp: %s", err) return } @@ -265,7 +263,7 @@ func (s *Server) handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) { err = s.dbLoad() if err != nil { - httpError(r, w, http.StatusInternalServerError, "loading leases db: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "loading leases db: %s", err) return } @@ -274,9 +272,7 @@ func (s *Server) handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) { var code int code, err = s.enableDHCP(conf.InterfaceName) if err != nil { - httpError(r, w, code, "enabling dhcp: %s", err) - - return + aghhttp.Error(r, w, code, "enabling dhcp: %s", err) } } } @@ -295,7 +291,8 @@ func (s *Server) handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) { ifaces, err := net.Interfaces() if err != nil { - httpError(r, w, http.StatusInternalServerError, "Couldn't get interfaces: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "Couldn't get interfaces: %s", err) + return } @@ -312,7 +309,15 @@ func (s *Server) handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) { var addrs []net.Addr addrs, err = iface.Addrs() if err != nil { - httpError(r, w, http.StatusInternalServerError, "Failed to get addresses for interface %s: %s", iface.Name, err) + aghhttp.Error( + r, + w, + http.StatusInternalServerError, + "Failed to get addresses for interface %s: %s", + iface.Name, + err, + ) + return } @@ -329,7 +334,13 @@ func (s *Server) handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) { ipnet, ok := addr.(*net.IPNet) if !ok { // not an IPNet, should not happen - httpError(r, w, http.StatusInternalServerError, "SHOULD NOT HAPPEN: got iface.Addrs() element %s that is not net.IPNet, it is %T", addr, addr) + aghhttp.Error( + r, + w, + http.StatusInternalServerError, + "got iface.Addrs() element %[1]s that is not net.IPNet, it is %[1]T", + addr) + return } // ignore link-local @@ -350,8 +361,13 @@ func (s *Server) handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) { err = json.NewEncoder(w).Encode(response) if err != nil { - httpError(r, w, http.StatusInternalServerError, "Failed to marshal json with available interfaces: %s", err) - return + aghhttp.Error( + r, + w, + http.StatusInternalServerError, + "Failed to marshal json with available interfaces: %s", + err, + ) } } @@ -455,9 +471,13 @@ func (s *Server) handleDHCPFindActiveServer(w http.ResponseWriter, r *http.Reque w.Header().Set("Content-Type", "application/json") err = json.NewEncoder(w).Encode(result) if err != nil { - httpError(r, w, http.StatusInternalServerError, "Failed to marshal DHCP found json: %s", err) - - return + aghhttp.Error( + r, + w, + http.StatusInternalServerError, + "Failed to marshal DHCP found json: %s", + err, + ) } } @@ -465,13 +485,13 @@ func (s *Server) handleDHCPAddStaticLease(w http.ResponseWriter, r *http.Request l := &Lease{} err := json.NewDecoder(r.Body).Decode(l) if err != nil { - httpError(r, w, http.StatusBadRequest, "json.Decode: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "json.Decode: %s", err) return } if l.IP == nil { - httpError(r, w, http.StatusBadRequest, "invalid IP") + aghhttp.Error(r, w, http.StatusBadRequest, "invalid IP") return } @@ -483,7 +503,7 @@ func (s *Server) handleDHCPAddStaticLease(w http.ResponseWriter, r *http.Request err = s.srv6.AddStaticLease(l) if err != nil { - httpError(r, w, http.StatusBadRequest, "%s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "%s", err) } return @@ -492,7 +512,7 @@ func (s *Server) handleDHCPAddStaticLease(w http.ResponseWriter, r *http.Request l.IP = ip4 err = s.srv4.AddStaticLease(l) if err != nil { - httpError(r, w, http.StatusBadRequest, "%s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "%s", err) return } @@ -502,13 +522,13 @@ func (s *Server) handleDHCPRemoveStaticLease(w http.ResponseWriter, r *http.Requ l := &Lease{} err := json.NewDecoder(r.Body).Decode(l) if err != nil { - httpError(r, w, http.StatusBadRequest, "json.Decode: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "json.Decode: %s", err) return } if l.IP == nil { - httpError(r, w, http.StatusBadRequest, "invalid IP") + aghhttp.Error(r, w, http.StatusBadRequest, "invalid IP") return } @@ -520,7 +540,7 @@ func (s *Server) handleDHCPRemoveStaticLease(w http.ResponseWriter, r *http.Requ err = s.srv6.RemoveStaticLease(l) if err != nil { - httpError(r, w, http.StatusBadRequest, "%s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "%s", err) } return @@ -529,7 +549,7 @@ func (s *Server) handleDHCPRemoveStaticLease(w http.ResponseWriter, r *http.Requ l.IP = ip4 err = s.srv4.RemoveStaticLease(l) if err != nil { - httpError(r, w, http.StatusBadRequest, "%s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "%s", err) return } @@ -545,7 +565,7 @@ const ( func (s *Server) handleReset(w http.ResponseWriter, r *http.Request) { err := s.Stop() if err != nil { - httpError(r, w, http.StatusInternalServerError, "stopping dhcp: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "stopping dhcp: %s", err) return } @@ -583,7 +603,7 @@ func (s *Server) handleResetLeases(w http.ResponseWriter, r *http.Request) { err := s.resetLeases() if err != nil { msg := "resetting leases: %s" - httpError(r, w, http.StatusInternalServerError, msg, err) + aghhttp.Error(r, w, http.StatusInternalServerError, msg, err) return } diff --git a/internal/dnsforward/access.go b/internal/dnsforward/access.go index efa3bf8c..79f6c2b7 100644 --- a/internal/dnsforward/access.go +++ b/internal/dnsforward/access.go @@ -7,6 +7,7 @@ import ( "net/http" "strings" + "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/netutil" @@ -187,7 +188,7 @@ func (s *Server) handleAccessList(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") err := json.NewEncoder(w).Encode(j) if err != nil { - httpError(r, w, http.StatusInternalServerError, "encoding response: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "encoding response: %s", err) return } @@ -251,14 +252,14 @@ func (s *Server) handleAccessSet(w http.ResponseWriter, r *http.Request) { list := accessListJSON{} err := json.NewDecoder(r.Body).Decode(&list) if err != nil { - httpError(r, w, http.StatusBadRequest, "decoding request: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "decoding request: %s", err) return } err = validateAccessSet(list) if err != nil { - httpError(r, w, http.StatusBadRequest, err.Error()) + aghhttp.Error(r, w, http.StatusBadRequest, err.Error()) return } @@ -266,7 +267,7 @@ func (s *Server) handleAccessSet(w http.ResponseWriter, r *http.Request) { var a *accessCtx a, err = newAccessCtx(list.AllowedClients, list.DisallowedClients, list.BlockedHosts) if err != nil { - httpError(r, w, http.StatusBadRequest, "creating access ctx: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "creating access ctx: %s", err) return } diff --git a/internal/dnsforward/http.go b/internal/dnsforward/http.go index 3623de71..42a81946 100644 --- a/internal/dnsforward/http.go +++ b/internal/dnsforward/http.go @@ -9,6 +9,7 @@ import ( "strings" "time" + "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/dnsproxy/proxy" "github.com/AdguardTeam/dnsproxy/upstream" "github.com/AdguardTeam/golibs/errors" @@ -18,12 +19,6 @@ import ( "github.com/miekg/dns" ) -func httpError(r *http.Request, w http.ResponseWriter, code int, format string, args ...interface{}) { - text := fmt.Sprintf(format, args...) - log.Info("dns: %s %s: %s", r.Method, r.URL, text) - http.Error(w, text, code) -} - type dnsConfig struct { Upstreams *[]string `json:"upstream_dns"` UpstreamsFile *string `json:"upstream_dns_file"` @@ -119,7 +114,8 @@ func (s *Server) handleGetConfig(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") if err = json.NewEncoder(w).Encode(resp); err != nil { - httpError(r, w, http.StatusInternalServerError, "json.Encoder: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "json.Encoder: %s", err) + return } } @@ -198,34 +194,52 @@ func (s *Server) handleSetConfig(w http.ResponseWriter, r *http.Request) { req := dnsConfig{} dec := json.NewDecoder(r.Body) if err := dec.Decode(&req); err != nil { - httpError(r, w, http.StatusBadRequest, "json Encode: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "json Encode: %s", err) + return } if req.Upstreams != nil { if err := ValidateUpstreams(*req.Upstreams); err != nil { - httpError(r, w, http.StatusBadRequest, "wrong upstreams specification: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "wrong upstreams specification: %s", err) + return } } if errBoot, err := req.checkBootstrap(); err != nil { - httpError(r, w, http.StatusBadRequest, "%s can not be used as bootstrap dns cause: %s", errBoot, err) + aghhttp.Error( + r, + w, + http.StatusBadRequest, + "%s can not be used as bootstrap dns cause: %s", + errBoot, + err, + ) + return } if !req.checkBlockingMode() { - httpError(r, w, http.StatusBadRequest, "blocking_mode: incorrect value") + aghhttp.Error(r, w, http.StatusBadRequest, "blocking_mode: incorrect value") + return } if !req.checkUpstreamsMode() { - httpError(r, w, http.StatusBadRequest, "upstream_mode: incorrect value") + aghhttp.Error(r, w, http.StatusBadRequest, "upstream_mode: incorrect value") + return } if !req.checkCacheTTL() { - httpError(r, w, http.StatusBadRequest, "cache_ttl_min must be less or equal than cache_ttl_max") + aghhttp.Error( + r, + w, + http.StatusBadRequest, + "cache_ttl_min must be less or equal than cache_ttl_max", + ) + return } @@ -234,8 +248,7 @@ func (s *Server) handleSetConfig(w http.ResponseWriter, r *http.Request) { if restart { if err := s.Reconfigure(nil); err != nil { - httpError(r, w, http.StatusInternalServerError, "%s", err) - return + aghhttp.Error(r, w, http.StatusInternalServerError, "%s", err) } } } @@ -582,7 +595,7 @@ func (s *Server) handleTestUpstreamDNS(w http.ResponseWriter, r *http.Request) { req := &upstreamJSON{} err := json.NewDecoder(r.Body).Decode(req) if err != nil { - httpError(r, w, http.StatusBadRequest, "Failed to read request body: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "Failed to read request body: %s", err) return } @@ -620,7 +633,13 @@ func (s *Server) handleTestUpstreamDNS(w http.ResponseWriter, r *http.Request) { jsonVal, err := json.Marshal(result) if err != nil { - httpError(r, w, http.StatusInternalServerError, "Unable to marshal status json: %s", err) + aghhttp.Error( + r, + w, + http.StatusInternalServerError, + "Unable to marshal status json: %s", + err, + ) return } @@ -628,9 +647,7 @@ func (s *Server) handleTestUpstreamDNS(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") _, err = w.Write(jsonVal) if err != nil { - httpError(r, w, http.StatusInternalServerError, "Couldn't write body: %s", err) - - return + aghhttp.Error(r, w, http.StatusInternalServerError, "Couldn't write body: %s", err) } } @@ -641,12 +658,12 @@ func (s *Server) handleTestUpstreamDNS(w http.ResponseWriter, r *http.Request) { // -> dnsforward.handleDNSRequest func (s *Server) handleDoH(w http.ResponseWriter, r *http.Request) { if !s.conf.TLSAllowUnencryptedDoH && r.TLS == nil { - httpError(r, w, http.StatusNotFound, "Not Found") + aghhttp.Error(r, w, http.StatusNotFound, "Not Found") return } if !s.IsRunning() { - httpError(r, w, http.StatusInternalServerError, "dns server is not running") + aghhttp.Error(r, w, http.StatusInternalServerError, "dns server is not running") return } diff --git a/internal/filtering/blocked.go b/internal/filtering/blocked.go index a11b72c7..aa0ba979 100644 --- a/internal/filtering/blocked.go +++ b/internal/filtering/blocked.go @@ -4,6 +4,7 @@ import ( "encoding/json" "net/http" + "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/urlfilter/rules" ) @@ -287,7 +288,8 @@ func (d *DNSFilter) handleBlockedServicesList(w http.ResponseWriter, r *http.Req w.Header().Set("Content-Type", "application/json") err := json.NewEncoder(w).Encode(list) if err != nil { - httpError(r, w, http.StatusInternalServerError, "json.Encode: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "json.Encode: %s", err) + return } } @@ -296,7 +298,8 @@ func (d *DNSFilter) handleBlockedServicesSet(w http.ResponseWriter, r *http.Requ list := []string{} err := json.NewDecoder(r.Body).Decode(&list) if err != nil { - httpError(r, w, http.StatusBadRequest, "json.Decode: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "json.Decode: %s", err) + return } diff --git a/internal/filtering/filtering.go b/internal/filtering/filtering.go index 0e0bb0ab..2f5717f1 100644 --- a/internal/filtering/filtering.go +++ b/internal/filtering/filtering.go @@ -864,8 +864,7 @@ func makeResult(matchedRules []rules.Rule, reason Reason) (res Result) { } } -// InitModule manually initializes blocked services map using blockedSvcListID -// as list ID for the rules. +// InitModule manually initializes blocked services map. func InitModule() { initBlockedServices() } diff --git a/internal/filtering/rewrites.go b/internal/filtering/rewrites.go index 90eb262e..19885d55 100644 --- a/internal/filtering/rewrites.go +++ b/internal/filtering/rewrites.go @@ -9,6 +9,7 @@ import ( "sort" "strings" + "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/golibs/log" "github.com/miekg/dns" ) @@ -206,7 +207,8 @@ func (d *DNSFilter) handleRewriteList(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") err := json.NewEncoder(w).Encode(arr) if err != nil { - httpError(r, w, http.StatusInternalServerError, "json.Encode: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "json.Encode: %s", err) + return } } @@ -215,7 +217,8 @@ func (d *DNSFilter) handleRewriteAdd(w http.ResponseWriter, r *http.Request) { jsent := rewriteEntryJSON{} err := json.NewDecoder(r.Body).Decode(&jsent) if err != nil { - httpError(r, w, http.StatusBadRequest, "json.Decode: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "json.Decode: %s", err) + return } @@ -237,7 +240,8 @@ func (d *DNSFilter) handleRewriteDelete(w http.ResponseWriter, r *http.Request) jsent := rewriteEntryJSON{} err := json.NewDecoder(r.Body).Decode(&jsent) if err != nil { - httpError(r, w, http.StatusBadRequest, "json.Decode: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "json.Decode: %s", err) + return } diff --git a/internal/filtering/safebrowsing.go b/internal/filtering/safebrowsing.go index 495a9067..9de4bcd2 100644 --- a/internal/filtering/safebrowsing.go +++ b/internal/filtering/safebrowsing.go @@ -13,6 +13,7 @@ import ( "strings" "time" + "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/dnsproxy/upstream" "github.com/AdguardTeam/golibs/cache" "github.com/AdguardTeam/golibs/log" @@ -368,12 +369,6 @@ func (d *DNSFilter) checkParental( return check(sctx, res, d.parentalUpstream) } -func httpError(r *http.Request, w http.ResponseWriter, code int, format string, args ...interface{}) { - text := fmt.Sprintf(format, args...) - log.Info("DNSFilter: %s %s: %s", r.Method, r.URL, text) - http.Error(w, text, code) -} - func (d *DNSFilter) handleSafeBrowsingEnable(w http.ResponseWriter, r *http.Request) { d.Config.SafeBrowsingEnabled = true d.Config.ConfigModified() @@ -392,7 +387,8 @@ func (d *DNSFilter) handleSafeBrowsingStatus(w http.ResponseWriter, r *http.Requ Enabled: d.Config.SafeBrowsingEnabled, }) if err != nil { - httpError(r, w, http.StatusInternalServerError, "Unable to write response json: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "Unable to write response json: %s", err) + return } } @@ -415,8 +411,7 @@ func (d *DNSFilter) handleParentalStatus(w http.ResponseWriter, r *http.Request) Enabled: d.Config.ParentalEnabled, }) if err != nil { - httpError(r, w, http.StatusInternalServerError, "Unable to write response json: %s", err) - return + aghhttp.Error(r, w, http.StatusInternalServerError, "Unable to write response json: %s", err) } } diff --git a/internal/filtering/safesearch.go b/internal/filtering/safesearch.go index c67ac735..23751cb0 100644 --- a/internal/filtering/safesearch.go +++ b/internal/filtering/safesearch.go @@ -11,6 +11,7 @@ import ( "net/http" "time" + "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/golibs/cache" "github.com/AdguardTeam/golibs/log" ) @@ -152,8 +153,13 @@ func (d *DNSFilter) handleSafeSearchStatus(w http.ResponseWriter, r *http.Reques Enabled: d.Config.SafeSearchEnabled, }) if err != nil { - httpError(r, w, http.StatusInternalServerError, "Unable to write response json: %s", err) - return + aghhttp.Error( + r, + w, + http.StatusInternalServerError, + "Unable to write response json: %s", + err, + ) } } diff --git a/internal/home/auth.go b/internal/home/auth.go index bfcc7267..26a807a9 100644 --- a/internal/home/auth.go +++ b/internal/home/auth.go @@ -13,6 +13,7 @@ import ( "sync" "time" + "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/netutil" "github.com/AdguardTeam/golibs/timeutil" @@ -417,7 +418,7 @@ func handleLogin(w http.ResponseWriter, r *http.Request) { req := loginJSON{} err := json.NewDecoder(r.Body).Decode(&req) if err != nil { - httpError(w, http.StatusBadRequest, "json decode: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "json decode: %s", err) return } @@ -429,7 +430,7 @@ func handleLogin(w http.ResponseWriter, r *http.Request) { // // TODO(e.burkov): Use realIP when the issue will be fixed. if remoteAddr, err = netutil.SplitHost(r.RemoteAddr); err != nil { - httpError(w, http.StatusBadRequest, "auth: getting remote address: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "auth: getting remote address: %s", err) return } @@ -437,7 +438,8 @@ func handleLogin(w http.ResponseWriter, r *http.Request) { if blocker := Context.auth.blocker; blocker != nil { if left := blocker.check(remoteAddr); left > 0 { w.Header().Set("Retry-After", strconv.Itoa(int(left.Seconds()))) - httpError( + aghhttp.Error( + r, w, http.StatusTooManyRequests, "auth: blocked for %s", @@ -451,7 +453,7 @@ func handleLogin(w http.ResponseWriter, r *http.Request) { var cookie string cookie, err = Context.auth.httpCookie(req, remoteAddr) if err != nil { - httpError(w, http.StatusBadRequest, "crypto rand reader: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "crypto rand reader: %s", err) return } @@ -480,7 +482,7 @@ func handleLogin(w http.ResponseWriter, r *http.Request) { w.Header().Set("Pragma", "no-cache") w.Header().Set("Expires", "0") - returnOK(w) + aghhttp.OK(w) } func handleLogout(w http.ResponseWriter, r *http.Request) { diff --git a/internal/home/clientshttp.go b/internal/home/clientshttp.go index 412ff002..1f053343 100644 --- a/internal/home/clientshttp.go +++ b/internal/home/clientshttp.go @@ -6,6 +6,7 @@ import ( "net" "net/http" + "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/golibs/log" ) @@ -58,7 +59,7 @@ type clientListJSON struct { } // respond with information about configured clients -func (clients *clientsContainer) handleGetClients(w http.ResponseWriter, _ *http.Request) { +func (clients *clientsContainer) handleGetClients(w http.ResponseWriter, r *http.Request) { data := clientListJSON{} clients.lock.Lock() @@ -106,7 +107,14 @@ func (clients *clientsContainer) handleGetClients(w http.ResponseWriter, _ *http w.Header().Set("Content-Type", "application/json") e := json.NewEncoder(w).Encode(data) if e != nil { - httpError(w, http.StatusInternalServerError, "Failed to encode to json: %v", e) + aghhttp.Error( + r, + w, + http.StatusInternalServerError, + "Failed to encode to json: %v", + e, + ) + return } } @@ -154,7 +162,7 @@ func (clients *clientsContainer) handleAddClient(w http.ResponseWriter, r *http. cj := clientJSON{} err := json.NewDecoder(r.Body).Decode(&cj) if err != nil { - httpError(w, http.StatusBadRequest, "failed to process request body: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "failed to process request body: %s", err) return } @@ -162,11 +170,14 @@ func (clients *clientsContainer) handleAddClient(w http.ResponseWriter, r *http. c := jsonToClient(cj) ok, err := clients.Add(c) if err != nil { - httpError(w, http.StatusBadRequest, "%s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "%s", err) + return } + if !ok { - httpError(w, http.StatusBadRequest, "Client already exists") + aghhttp.Error(r, w, http.StatusBadRequest, "Client already exists") + return } @@ -178,19 +189,19 @@ func (clients *clientsContainer) handleDelClient(w http.ResponseWriter, r *http. cj := clientJSON{} err := json.NewDecoder(r.Body).Decode(&cj) if err != nil { - httpError(w, http.StatusBadRequest, "failed to process request body: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "failed to process request body: %s", err) return } if len(cj.Name) == 0 { - httpError(w, http.StatusBadRequest, "client's name must be non-empty") + aghhttp.Error(r, w, http.StatusBadRequest, "client's name must be non-empty") return } if !clients.Del(cj.Name) { - httpError(w, http.StatusBadRequest, "Client not found") + aghhttp.Error(r, w, http.StatusBadRequest, "Client not found") return } @@ -207,20 +218,22 @@ func (clients *clientsContainer) handleUpdateClient(w http.ResponseWriter, r *ht dj := updateJSON{} err := json.NewDecoder(r.Body).Decode(&dj) if err != nil { - httpError(w, http.StatusBadRequest, "failed to process request body: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "failed to process request body: %s", err) return } if len(dj.Name) == 0 { - httpError(w, http.StatusBadRequest, "Invalid request") + aghhttp.Error(r, w, http.StatusBadRequest, "Invalid request") + return } c := jsonToClient(dj.Data) err = clients.Update(dj.Name, c) if err != nil { - httpError(w, http.StatusBadRequest, "%s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "%s", err) + return } @@ -256,7 +269,7 @@ func (clients *clientsContainer) handleFindClient(w http.ResponseWriter, r *http w.Header().Set("Content-Type", "application/json") err := json.NewEncoder(w).Encode(data) if err != nil { - httpError(w, http.StatusInternalServerError, "Couldn't write response: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "Couldn't write response: %s", err) } } diff --git a/internal/home/config.go b/internal/home/config.go index 99463a6a..e5e1b14b 100644 --- a/internal/home/config.go +++ b/internal/home/config.go @@ -1,7 +1,6 @@ package home import ( - "fmt" "net" "os" "path/filepath" @@ -274,17 +273,34 @@ func getLogSettings() logSettings { } // parseConfig loads configuration from the YAML file -func parseConfig() error { - configFile := config.getConfigFilename() - log.Debug("Reading config file: %s", configFile) - yamlFile, err := readConfigFile() +func parseConfig() (err error) { + var fileData []byte + fileData, err = readConfigFile() if err != nil { return err } + config.fileData = nil - err = yaml.Unmarshal(yamlFile, &config) + err = yaml.Unmarshal(fileData, &config) if err != nil { - log.Error("Couldn't parse config file: %s", err) + return err + } + + pm := portsMap{} + pm.add( + config.BindPort, + config.BetaBindPort, + config.DNS.Port, + ) + if config.TLS.Enabled { + pm.add( + config.TLS.PortHTTPS, + config.TLS.PortDNSOverTLS, + config.TLS.PortDNSOverQUIC, + config.TLS.PortDNSCrypt, + ) + } + if err = pm.validate(); err != nil { return err } @@ -299,18 +315,17 @@ func parseConfig() error { return nil } -// readConfigFile reads config file contents if it exists -func readConfigFile() ([]byte, error) { - if len(config.fileData) != 0 { +// readConfigFile reads configuration file contents. +func readConfigFile() (fileData []byte, err error) { + if len(config.fileData) > 0 { return config.fileData, nil } - configFile := config.getConfigFilename() - d, err := os.ReadFile(configFile) - if err != nil { - return nil, fmt.Errorf("couldn't read config file %s: %w", configFile, err) - } - return d, nil + name := config.getConfigFilename() + log.Debug("reading config file: %s", name) + + // Do not wrap the error because it's informative enough as is. + return os.ReadFile(name) } // Saves configuration to the YAML file and also saves the user filter contents to a file diff --git a/internal/home/control.go b/internal/home/control.go index d9d809ba..df21e310 100644 --- a/internal/home/control.go +++ b/internal/home/control.go @@ -9,6 +9,7 @@ import ( "runtime" "strings" + "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/AdGuardHome/internal/aghnet" "github.com/AdguardTeam/AdGuardHome/internal/dnsforward" "github.com/AdguardTeam/AdGuardHome/internal/version" @@ -17,23 +18,6 @@ import ( "github.com/NYTimes/gziphandler" ) -// ---------------- -// helper functions -// ---------------- - -func returnOK(w http.ResponseWriter) { - _, err := fmt.Fprintf(w, "OK\n") - if err != nil { - httpError(w, http.StatusInternalServerError, "Couldn't write body: %s", err) - } -} - -func httpError(w http.ResponseWriter, code int, format string, args ...interface{}) { - text := fmt.Sprintf(format, args...) - log.Info(text) - http.Error(w, text, code) -} - // appendDNSAddrs is a convenient helper for appending a formatted form of DNS // addresses to a slice of strings. func appendDNSAddrs(dst []string, addrs ...net.IP) (res []string) { @@ -125,12 +109,12 @@ type statusResponse struct { Language string `json:"language"` } -func handleStatus(w http.ResponseWriter, _ *http.Request) { +func handleStatus(w http.ResponseWriter, r *http.Request) { dnsAddrs, err := collectDNSAddresses() if err != nil { // Don't add a lot of formatting, since the error is already // wrapped by collectDNSAddresses. - httpError(w, http.StatusInternalServerError, "%s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "%s", err) return } @@ -165,7 +149,7 @@ func handleStatus(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "application/json") err = json.NewEncoder(w).Encode(resp) if err != nil { - httpError(w, http.StatusInternalServerError, "Unable to write response json: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "Unable to write response json: %s", err) return } @@ -182,7 +166,7 @@ func handleGetProfile(w http.ResponseWriter, r *http.Request) { data, err := json.Marshal(pj) if err != nil { - httpError(w, http.StatusInternalServerError, "json.Marshal: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "json.Marshal: %s", err) return } _, _ = w.Write(data) @@ -295,7 +279,7 @@ func handleHTTPSRedirect(w http.ResponseWriter, r *http.Request) (ok bool) { host, err := netutil.SplitHost(r.Host) if err != nil { - httpError(w, http.StatusBadRequest, "bad host: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "bad host: %s", err) return false } diff --git a/internal/home/controlfiltering.go b/internal/home/controlfiltering.go index ee19fd16..639403d8 100644 --- a/internal/home/controlfiltering.go +++ b/internal/home/controlfiltering.go @@ -12,6 +12,7 @@ import ( "strings" "time" + "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/golibs/log" "github.com/miekg/dns" ) @@ -49,7 +50,8 @@ func (f *Filtering) handleFilteringAddURL(w http.ResponseWriter, r *http.Request fj := filterAddJSON{} err := json.NewDecoder(r.Body).Decode(&fj) if err != nil { - httpError(w, http.StatusBadRequest, "Failed to parse request body json: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "Failed to parse request body json: %s", err) + return } @@ -63,7 +65,8 @@ func (f *Filtering) handleFilteringAddURL(w http.ResponseWriter, r *http.Request // Check for duplicates if filterExists(fj.URL) { - httpError(w, http.StatusBadRequest, "Filter URL already added -- %s", fj.URL) + aghhttp.Error(r, w, http.StatusBadRequest, "Filter URL already added -- %s", fj.URL) + return } @@ -79,17 +82,35 @@ func (f *Filtering) handleFilteringAddURL(w http.ResponseWriter, r *http.Request // Download the filter contents ok, err := f.update(&filt) if err != nil { - httpError(w, http.StatusBadRequest, "Couldn't fetch filter from url %s: %s", filt.URL, err) - return - } - if !ok { - httpError(w, http.StatusBadRequest, "Filter at the url %s is invalid (maybe it points to blank page?)", filt.URL) + aghhttp.Error( + r, + w, + http.StatusBadRequest, + "Couldn't fetch filter from url %s: %s", + filt.URL, + err, + ) + return } - // URL is deemed valid, append it to filters, update config, write new filter file and tell dns to reload it + if !ok { + aghhttp.Error( + r, + w, + http.StatusBadRequest, + "Filter at the url %s is invalid (maybe it points to blank page?)", + filt.URL, + ) + + return + } + + // URL is assumed valid so append it to filters, update config, write new + // file and reload it to engines. if !filterAdd(filt) { - httpError(w, http.StatusBadRequest, "Filter URL already added -- %s", filt.URL) + aghhttp.Error(r, w, http.StatusBadRequest, "Filter URL already added -- %s", filt.URL) + return } @@ -98,7 +119,7 @@ func (f *Filtering) handleFilteringAddURL(w http.ResponseWriter, r *http.Request _, err = fmt.Fprintf(w, "OK %d rules\n", filt.RulesCount) if err != nil { - httpError(w, http.StatusInternalServerError, "Couldn't write body: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "Couldn't write body: %s", err) } } @@ -111,7 +132,8 @@ func (f *Filtering) handleFilteringRemoveURL(w http.ResponseWriter, r *http.Requ req := request{} err := json.NewDecoder(r.Body).Decode(&req) if err != nil { - httpError(w, http.StatusBadRequest, "failed to parse request body json: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "failed to parse request body json: %s", err) + return } @@ -152,7 +174,7 @@ func (f *Filtering) handleFilteringRemoveURL(w http.ResponseWriter, r *http.Requ _, err = fmt.Fprintf(w, "OK %d rules\n", deleted.RulesCount) if err != nil { - httpError(w, http.StatusInternalServerError, "couldn't write body: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "couldn't write body: %s", err) } } @@ -172,7 +194,8 @@ func (f *Filtering) handleFilteringSetURL(w http.ResponseWriter, r *http.Request fj := filterURLReq{} err := json.NewDecoder(r.Body).Decode(&fj) if err != nil { - httpError(w, http.StatusBadRequest, "json decode: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "json decode: %s", err) + return } @@ -228,7 +251,8 @@ func (f *Filtering) handleFilteringSetRules(w http.ResponseWriter, r *http.Reque // This use of ReadAll is safe, because request's body is now limited. body, err := io.ReadAll(r.Body) if err != nil { - httpError(w, http.StatusBadRequest, "Failed to read request body: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "Failed to read request body: %s", err) + return } @@ -250,7 +274,8 @@ func (f *Filtering) handleFilteringRefresh(w http.ResponseWriter, r *http.Reques req := Req{} err = json.NewDecoder(r.Body).Decode(&req) if err != nil { - httpError(w, http.StatusBadRequest, "json decode: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "json decode: %s", err) + return } @@ -270,13 +295,15 @@ func (f *Filtering) handleFilteringRefresh(w http.ResponseWriter, r *http.Reques resp.Updated, err = f.refreshFilters(flags|filterRefreshForce, false) }() if err != nil { - httpError(w, http.StatusInternalServerError, "%s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "%s", err) + return } js, err := json.Marshal(resp) if err != nil { - httpError(w, http.StatusInternalServerError, "json encode: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "json encode: %s", err) + return } w.Header().Set("Content-Type", "application/json") @@ -335,13 +362,14 @@ func (f *Filtering) handleFilteringStatus(w http.ResponseWriter, r *http.Request jsonVal, err := json.Marshal(resp) if err != nil { - httpError(w, http.StatusInternalServerError, "json encode: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "json encode: %s", err) + return } w.Header().Set("Content-Type", "application/json") _, err = w.Write(jsonVal) if err != nil { - httpError(w, http.StatusInternalServerError, "http write: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "http write: %s", err) } } @@ -350,12 +378,14 @@ func (f *Filtering) handleFilteringConfig(w http.ResponseWriter, r *http.Request req := filteringConfig{} err := json.NewDecoder(r.Body).Decode(&req) if err != nil { - httpError(w, http.StatusBadRequest, "json decode: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "json decode: %s", err) + return } if !checkFiltersUpdateIntervalHours(req.Interval) { - httpError(w, http.StatusBadRequest, "Unsupported interval") + aghhttp.Error(r, w, http.StatusBadRequest, "Unsupported interval") + return } @@ -408,7 +438,15 @@ func (f *Filtering) handleCheckHost(w http.ResponseWriter, r *http.Request) { Context.dnsFilter.ApplyBlockedServices(&setts, nil, true) result, err := Context.dnsFilter.CheckHost(host, dns.TypeA, &setts) if err != nil { - httpError(w, http.StatusInternalServerError, "couldn't apply filtering: %s: %s", host, err) + aghhttp.Error( + r, + w, + http.StatusInternalServerError, + "couldn't apply filtering: %s: %s", + host, + err, + ) + return } @@ -433,7 +471,8 @@ func (f *Filtering) handleCheckHost(w http.ResponseWriter, r *http.Request) { js, err := json.Marshal(resp) if err != nil { - httpError(w, http.StatusInternalServerError, "json encode: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "json encode: %s", err) + return } w.Header().Set("Content-Type", "application/json") diff --git a/internal/home/controlinstall.go b/internal/home/controlinstall.go index 84996017..baae5d00 100644 --- a/internal/home/controlinstall.go +++ b/internal/home/controlinstall.go @@ -14,6 +14,7 @@ import ( "strings" "time" + "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/AdGuardHome/internal/aghnet" "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/log" @@ -34,7 +35,8 @@ func (web *Web) handleInstallGetAddresses(w http.ResponseWriter, r *http.Request ifaces, err := aghnet.GetValidNetInterfacesForWeb() if err != nil { - httpError(w, http.StatusInternalServerError, "Couldn't get interfaces: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "Couldn't get interfaces: %s", err) + return } @@ -46,7 +48,14 @@ func (web *Web) handleInstallGetAddresses(w http.ResponseWriter, r *http.Request w.Header().Set("Content-Type", "application/json") err = json.NewEncoder(w).Encode(data) if err != nil { - httpError(w, http.StatusInternalServerError, "Unable to marshal default addresses to json: %s", err) + aghhttp.Error( + r, + w, + http.StatusInternalServerError, + "Unable to marshal default addresses to json: %s", + err, + ) + return } } @@ -84,23 +93,32 @@ type checkConfigResp struct { func (web *Web) handleInstallCheckConfig(w http.ResponseWriter, r *http.Request) { reqData := checkConfigReq{} respData := checkConfigResp{} + err := json.NewDecoder(r.Body).Decode(&reqData) if err != nil { - httpError(w, http.StatusBadRequest, "Failed to parse 'check_config' JSON data: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "Failed to parse 'check_config' JSON data: %s", err) + return } - if reqData.Web.Port != 0 && reqData.Web.Port != config.BindPort && reqData.Web.Port != config.BetaBindPort { - err = aghnet.CheckPortAvailable(reqData.Web.IP, reqData.Web.Port) + pm := portsMap{} + pm.add(config.BindPort, config.BetaBindPort, reqData.Web.Port) + if err = pm.validate(); err != nil { + respData.Web.Status = err.Error() + } else if reqData.Web.Port != 0 { + err = aghnet.CheckPort("tcp", reqData.Web.IP, reqData.Web.Port) if err != nil { respData.Web.Status = err.Error() } } - if reqData.DNS.Port != 0 { - err = aghnet.CheckPacketPortAvailable(reqData.DNS.IP, reqData.DNS.Port) + pm.add(reqData.DNS.Port) + if err = pm.validate(); err != nil { + respData.DNS.Status = err.Error() + } else if reqData.DNS.Port != 0 { + err = aghnet.CheckPort("udp", reqData.DNS.IP, reqData.DNS.Port) - if aghnet.ErrorIsAddrInUse(err) { + if aghnet.IsAddrInUse(err) { canAutofix := checkDNSStubListener() if canAutofix && reqData.DNS.Autofix { @@ -109,7 +127,7 @@ func (web *Web) handleInstallCheckConfig(w http.ResponseWriter, r *http.Request) log.Error("Couldn't disable DNSStubListener: %s", err) } - err = aghnet.CheckPacketPortAvailable(reqData.DNS.IP, reqData.DNS.Port) + err = aghnet.CheckPort("udp", reqData.DNS.IP, reqData.DNS.Port) canAutofix = false } @@ -117,7 +135,7 @@ func (web *Web) handleInstallCheckConfig(w http.ResponseWriter, r *http.Request) } if err == nil { - err = aghnet.CheckPortAvailable(reqData.DNS.IP, reqData.DNS.Port) + err = aghnet.CheckPort("tcp", reqData.DNS.IP, reqData.DNS.Port) } if err != nil { @@ -130,7 +148,8 @@ func (web *Web) handleInstallCheckConfig(w http.ResponseWriter, r *http.Request) w.Header().Set("Content-Type", "application/json") err = json.NewEncoder(w).Encode(respData) if err != nil { - httpError(w, http.StatusInternalServerError, "Unable to marshal JSON: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "Unable to marshal JSON: %s", err) + return } } @@ -287,21 +306,21 @@ func shutdownSrv(ctx context.Context, srv *http.Server) { func (web *Web) handleInstallConfigure(w http.ResponseWriter, r *http.Request) { req, restartHTTP, err := decodeApplyConfigReq(r.Body) if err != nil { - httpError(w, http.StatusBadRequest, "%s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "%s", err) return } - err = aghnet.CheckPacketPortAvailable(req.DNS.IP, req.DNS.Port) + err = aghnet.CheckPort("udp", req.DNS.IP, req.DNS.Port) if err != nil { - httpError(w, http.StatusBadRequest, "%s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "%s", err) return } - err = aghnet.CheckPortAvailable(req.DNS.IP, req.DNS.Port) + err = aghnet.CheckPort("tcp", req.DNS.IP, req.DNS.Port) if err != nil { - httpError(w, http.StatusBadRequest, "%s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "%s", err) return } @@ -315,28 +334,29 @@ func (web *Web) handleInstallConfigure(w http.ResponseWriter, r *http.Request) { config.DNS.BindHosts = []net.IP{req.DNS.IP} config.DNS.Port = req.DNS.Port - // TODO(e.burkov): StartMods() should be put in a separate goroutine at - // the moment we'll allow setting up TLS in the initial configuration or - // the configuration itself will use HTTPS protocol, because the - // underlying functions potentially restart the HTTPS server. + // TODO(e.burkov): StartMods() should be put in a separate goroutine at the + // moment we'll allow setting up TLS in the initial configuration or the + // configuration itself will use HTTPS protocol, because the underlying + // functions potentially restart the HTTPS server. err = StartMods() if err != nil { Context.firstRun = true copyInstallSettings(config, curConfig) - httpError(w, http.StatusInternalServerError, "%s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "%s", err) return } - u := User{} - u.Name = req.Username - Context.auth.UserAdd(&u, req.Password) + u := &User{ + Name: req.Username, + } + Context.auth.UserAdd(u, req.Password) err = config.write() if err != nil { Context.firstRun = true copyInstallSettings(config, curConfig) - httpError(w, http.StatusInternalServerError, "Couldn't write config: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "Couldn't write config: %s", err) return } @@ -347,7 +367,7 @@ func (web *Web) handleInstallConfigure(w http.ResponseWriter, r *http.Request) { registerControlHandlers() - returnOK(w) + aghhttp.OK(w) if f, ok := w.(http.Flusher); ok { f.Flush() } @@ -386,7 +406,7 @@ func decodeApplyConfigReq(r io.Reader) (req *applyConfigReq, restartHTTP bool, e restartHTTP = !config.BindHost.Equal(req.Web.IP) || config.BindPort != req.Web.Port if restartHTTP { - err = aghnet.CheckPortAvailable(req.Web.IP, req.Web.Port) + err = aghnet.CheckPort("tcp", req.Web.IP, req.Web.Port) if err != nil { return nil, false, fmt.Errorf( "checking address %s:%d: %w", @@ -437,12 +457,14 @@ func (web *Web) handleInstallCheckConfigBeta(w http.ResponseWriter, r *http.Requ reqData := checkConfigReqBeta{} err := json.NewDecoder(r.Body).Decode(&reqData) if err != nil { - httpError(w, http.StatusBadRequest, "Failed to parse 'check_config' JSON data: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "Failed to parse 'check_config' JSON data: %s", err) + return } if len(reqData.DNS.IP) == 0 || len(reqData.Web.IP) == 0 { - httpError(w, http.StatusBadRequest, http.StatusText(http.StatusBadRequest)) + aghhttp.Error(r, w, http.StatusBadRequest, http.StatusText(http.StatusBadRequest)) + return } @@ -464,7 +486,14 @@ func (web *Web) handleInstallCheckConfigBeta(w http.ResponseWriter, r *http.Requ err = json.NewEncoder(nonBetaReqBody).Encode(nonBetaReqData) if err != nil { - httpError(w, http.StatusBadRequest, "Failed to encode 'check_config' JSON data: %s", err) + aghhttp.Error( + r, + w, + http.StatusBadRequest, + "Failed to encode 'check_config' JSON data: %s", + err, + ) + return } body := nonBetaReqBody.String() @@ -505,12 +534,14 @@ func (web *Web) handleInstallConfigureBeta(w http.ResponseWriter, r *http.Reques reqData := applyConfigReqBeta{} err := json.NewDecoder(r.Body).Decode(&reqData) if err != nil { - httpError(w, http.StatusBadRequest, "Failed to parse 'check_config' JSON data: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "Failed to parse 'check_config' JSON data: %s", err) + return } if len(reqData.DNS.IP) == 0 || len(reqData.Web.IP) == 0 { - httpError(w, http.StatusBadRequest, http.StatusText(http.StatusBadRequest)) + aghhttp.Error(r, w, http.StatusBadRequest, http.StatusText(http.StatusBadRequest)) + return } @@ -531,7 +562,14 @@ func (web *Web) handleInstallConfigureBeta(w http.ResponseWriter, r *http.Reques err = json.NewEncoder(nonBetaReqBody).Encode(nonBetaReqData) if err != nil { - httpError(w, http.StatusBadRequest, "Failed to encode 'check_config' JSON data: %s", err) + aghhttp.Error( + r, + w, + http.StatusBadRequest, + "Failed to encode 'check_config' JSON data: %s", + err, + ) + return } body := nonBetaReqBody.String() @@ -564,7 +602,8 @@ func (web *Web) handleInstallGetAddressesBeta(w http.ResponseWriter, r *http.Req ifaces, err := aghnet.GetValidNetInterfacesForWeb() if err != nil { - httpError(w, http.StatusInternalServerError, "Couldn't get interfaces: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "Couldn't get interfaces: %s", err) + return } @@ -573,7 +612,14 @@ func (web *Web) handleInstallGetAddressesBeta(w http.ResponseWriter, r *http.Req w.Header().Set("Content-Type", "application/json") err = json.NewEncoder(w).Encode(data) if err != nil { - httpError(w, http.StatusInternalServerError, "Unable to marshal default addresses to json: %s", err) + aghhttp.Error( + r, + w, + http.StatusInternalServerError, + "Unable to marshal default addresses to json: %s", + err, + ) + return } } diff --git a/internal/home/controlupdate.go b/internal/home/controlupdate.go index 5217190e..79b9f37e 100644 --- a/internal/home/controlupdate.go +++ b/internal/home/controlupdate.go @@ -11,6 +11,7 @@ import ( "syscall" "time" + "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/AdGuardHome/internal/aghnet" "github.com/AdguardTeam/AdGuardHome/internal/updater" "github.com/AdguardTeam/golibs/errors" @@ -43,7 +44,8 @@ func handleGetVersionJSON(w http.ResponseWriter, r *http.Request) { if r.ContentLength != 0 { err = json.NewDecoder(r.Body).Decode(req) if err != nil { - httpError(w, http.StatusBadRequest, "JSON parse: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "JSON parse: %s", err) + return } } @@ -77,7 +79,15 @@ func handleGetVersionJSON(w http.ResponseWriter, r *http.Request) { if err != nil { vcu := Context.updater.VersionCheckURL() // TODO(a.garipov): Figure out the purpose of %T verb. - httpError(w, http.StatusBadGateway, "Couldn't get version check json from %s: %T %s\n", vcu, err, err) + aghhttp.Error( + r, + w, + http.StatusBadGateway, + "Couldn't get version check json from %s: %T %s\n", + vcu, + err, + err, + ) return } @@ -87,24 +97,26 @@ func handleGetVersionJSON(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") err = json.NewEncoder(w).Encode(resp) if err != nil { - httpError(w, http.StatusInternalServerError, "Couldn't write body: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "Couldn't write body: %s", err) } } // handleUpdate performs an update to the latest available version procedure. -func handleUpdate(w http.ResponseWriter, _ *http.Request) { +func handleUpdate(w http.ResponseWriter, r *http.Request) { if Context.updater.NewVersion() == "" { - httpError(w, http.StatusBadRequest, "/update request isn't allowed now") + aghhttp.Error(r, w, http.StatusBadRequest, "/update request isn't allowed now") + return } err := Context.updater.Update() if err != nil { - httpError(w, http.StatusInternalServerError, "%s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "%s", err) + return } - returnOK(w) + aghhttp.OK(w) if f, ok := w.(http.Flusher); ok { f.Flush() } diff --git a/internal/home/home.go b/internal/home/home.go index 1238aaec..fe11a8d3 100644 --- a/internal/home/home.go +++ b/internal/home/home.go @@ -159,14 +159,11 @@ func setupContext(args options) { } if !Context.firstRun { - // Do the upgrade if necessary + // Do the upgrade if necessary. err := upgradeConfig() - if err != nil { - log.Fatal(err) - } + fatalOnError(err) - err = parseConfig() - if err != nil { + if err = parseConfig(); err != nil { log.Error("parsing configuration file: %s", err) os.Exit(1) @@ -186,13 +183,13 @@ func setupContext(args options) { // unsupported errors and returns nil. If err is nil, logIfUnsupported returns // nil. Otherise, it returns err. func logIfUnsupported(msg string, err error) (outErr error) { - if unsupErr := (&aghos.UnsupportedError{}); errors.As(err, &unsupErr) { + if errors.As(err, new(*aghos.UnsupportedError)) { log.Debug(msg, err) - } else if err != nil { - return err + + return nil } - return nil + return err } // configureOS sets the OS-related configuration. @@ -297,13 +294,32 @@ func setupConfig(args options) (err error) { Context.clients.Init(config.Clients, Context.dhcpServer, Context.etcHosts) + if args.bindPort != 0 { + pm := portsMap{} + pm.add( + args.bindPort, + config.BetaBindPort, + config.DNS.Port, + ) + if config.TLS.Enabled { + pm.add( + config.TLS.PortHTTPS, + config.TLS.PortDNSOverTLS, + config.TLS.PortDNSOverQUIC, + config.TLS.PortDNSCrypt, + ) + } + if err = pm.validate(); err != nil { + return err + } + + config.BindPort = args.bindPort + } + // override bind host/port from the console if args.bindHost != nil { config.BindHost = args.bindHost } - if args.bindPort != 0 { - config.BindPort = args.bindPort - } if len(args.pidFile) != 0 && writePIDFile(args.pidFile) { Context.pidFileName = args.pidFile } @@ -766,8 +782,7 @@ func printHTTPAddresses(proto string) { port = tlsConf.PortHTTPS } - // TODO(e.burkov): Inspect and perhaps merge with the previous - // condition. + // TODO(e.burkov): Inspect and perhaps merge with the previous condition. if proto == schemeHTTPS && tlsConf.ServerName != "" { printWebAddrs(proto, tlsConf.ServerName, tlsConf.PortHTTPS, 0) diff --git a/internal/home/i18n.go b/internal/home/i18n.go index d46bd6c6..51f6a2ac 100644 --- a/internal/home/i18n.go +++ b/internal/home/i18n.go @@ -6,6 +6,7 @@ import ( "net/http" "strings" + "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/stringutil" ) @@ -96,5 +97,5 @@ func handleI18nChangeLanguage(w http.ResponseWriter, r *http.Request) { }() onConfigModified() - returnOK(w) + aghhttp.OK(w) } diff --git a/internal/home/portsmap.go b/internal/home/portsmap.go new file mode 100644 index 00000000..cfbfcde9 --- /dev/null +++ b/internal/home/portsmap.go @@ -0,0 +1,63 @@ +package home + +import ( + "fmt" + "strconv" + "strings" + + "github.com/AdguardTeam/golibs/errors" + "github.com/AdguardTeam/golibs/stringutil" +) + +// portsMap is a helper type for mapping a network port to the number of its +// users. +type portsMap map[int]int + +// add binds each of ps. Zeroes are skipped. +func (pm portsMap) add(ps ...int) { + for _, p := range ps { + if p == 0 { + continue + } + + pm[p]++ + } +} + +// validate returns an error about all the ports bound several times. +func (pm portsMap) validate() (err error) { + overbound := []int{} + for p, num := range pm { + if num > 1 { + overbound = append(overbound, p) + pm[p] = 1 + } + } + + switch len(overbound) { + case 0: + return nil + case 1: + return fmt.Errorf("port %d is already used", overbound[0]) + default: + b := &strings.Builder{} + + // TODO(e.burkov, a.garipov): Add JoinToBuilder helper to stringutil. + stringutil.WriteToBuilder(b, "ports ", strconv.Itoa(overbound[0])) + for _, p := range overbound[1:] { + stringutil.WriteToBuilder(b, ", ", strconv.Itoa(p)) + } + stringutil.WriteToBuilder(b, " are already used") + + return errors.Error(b.String()) + } +} + +// validatePorts is a helper function for a single-step ports binding +// validation. +func validatePorts(ps ...int) (err error) { + pm := portsMap{} + pm.add(ps...) + + return pm.validate() +} diff --git a/internal/home/tls.go b/internal/home/tls.go index c334e2e1..35138c34 100644 --- a/internal/home/tls.go +++ b/internal/home/tls.go @@ -20,6 +20,7 @@ import ( "sync" "time" + "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/AdGuardHome/internal/dnsforward" "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/log" @@ -224,7 +225,7 @@ type tlsConfigSettingsExt struct { PrivateKeySaved bool `yaml:"-" json:"private_key_saved,inline"` } -func (t *TLSMod) handleTLSStatus(w http.ResponseWriter, _ *http.Request) { +func (t *TLSMod) handleTLSStatus(w http.ResponseWriter, r *http.Request) { t.confLock.Lock() data := tlsConfig{ tlsConfigSettingsExt: tlsConfigSettingsExt{ @@ -233,13 +234,14 @@ func (t *TLSMod) handleTLSStatus(w http.ResponseWriter, _ *http.Request) { tlsConfigStatus: t.status, } t.confLock.Unlock() - marshalTLS(w, data) + marshalTLS(w, r, data) } func (t *TLSMod) handleTLSValidate(w http.ResponseWriter, r *http.Request) { setts, err := unmarshalTLS(r) if err != nil { - httpError(w, http.StatusBadRequest, "Failed to unmarshal TLS config: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "Failed to unmarshal TLS config: %s", err) + return } @@ -247,8 +249,31 @@ func (t *TLSMod) handleTLSValidate(w http.ResponseWriter, r *http.Request) { setts.PrivateKey = t.conf.PrivateKey } + if setts.Enabled { + if err = validatePorts( + config.BindPort, + config.BetaBindPort, + config.DNS.Port, + setts.PortHTTPS, + setts.PortDNSOverTLS, + setts.PortDNSOverQUIC, + setts.PortDNSCrypt, + ); err != nil { + aghhttp.Error(r, w, http.StatusBadRequest, "%s", err) + + return + } + } + if !WebCheckPortAvailable(setts.PortHTTPS) { - httpError(w, http.StatusBadRequest, "port %d is not available, cannot enable HTTPS on it", setts.PortHTTPS) + aghhttp.Error( + r, + w, + http.StatusBadRequest, + "port %d is not available, cannot enable HTTPS on it", + setts.PortHTTPS, + ) + return } @@ -261,7 +286,8 @@ func (t *TLSMod) handleTLSValidate(w http.ResponseWriter, r *http.Request) { tlsConfigSettingsExt: setts, tlsConfigStatus: status, } - marshalTLS(w, data) + + marshalTLS(w, r, data) } func (t *TLSMod) setConfig(newConf tlsConfigSettings, status tlsConfigStatus) (restartHTTPS bool) { @@ -302,7 +328,8 @@ func (t *TLSMod) setConfig(newConf tlsConfigSettings, status tlsConfigStatus) (r func (t *TLSMod) handleTLSConfigure(w http.ResponseWriter, r *http.Request) { data, err := unmarshalTLS(r) if err != nil { - httpError(w, http.StatusBadRequest, "Failed to unmarshal TLS config: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "Failed to unmarshal TLS config: %s", err) + return } @@ -310,8 +337,32 @@ func (t *TLSMod) handleTLSConfigure(w http.ResponseWriter, r *http.Request) { data.PrivateKey = t.conf.PrivateKey } + if data.Enabled { + if err = validatePorts( + config.BindPort, + config.BetaBindPort, + config.DNS.Port, + data.PortHTTPS, + data.PortDNSOverTLS, + data.PortDNSOverQUIC, + data.PortDNSCrypt, + ); err != nil { + aghhttp.Error(r, w, http.StatusBadRequest, "%s", err) + + return + } + } + + // TODO(e.burkov): Investigate and perhaps check other ports. if !WebCheckPortAvailable(data.PortHTTPS) { - httpError(w, http.StatusBadRequest, "port %d is not available, cannot enable HTTPS on it", data.PortHTTPS) + aghhttp.Error( + r, + w, + http.StatusBadRequest, + "port %d is not available, cannot enable HTTPS on it", + data.PortHTTPS, + ) + return } @@ -321,7 +372,7 @@ func (t *TLSMod) handleTLSConfigure(w http.ResponseWriter, r *http.Request) { tlsConfigSettingsExt: data, tlsConfigStatus: t.status, } - marshalTLS(w, data2) + marshalTLS(w, r, data2) return } @@ -334,7 +385,7 @@ func (t *TLSMod) handleTLSConfigure(w http.ResponseWriter, r *http.Request) { err = reconfigureDNSServer() if err != nil { - httpError(w, http.StatusInternalServerError, "%s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "%s", err) return } @@ -344,15 +395,15 @@ func (t *TLSMod) handleTLSConfigure(w http.ResponseWriter, r *http.Request) { tlsConfigStatus: t.status, } - marshalTLS(w, data2) + marshalTLS(w, r, data2) if f, ok := w.(http.Flusher); ok { f.Flush() } - // The background context is used because the TLSConfigChanged wraps - // context with timeout on its own and shuts down the server, which - // handles current request. It is also should be done in a separate - // goroutine due to the same reason. + // The background context is used because the TLSConfigChanged wraps context + // with timeout on its own and shuts down the server, which handles current + // request. It is also should be done in a separate goroutine due to the + // same reason. if restartHTTPS { go func() { Context.web.TLSConfigChanged(context.Background(), data.tlsConfigSettings) @@ -595,7 +646,7 @@ func unmarshalTLS(r *http.Request) (tlsConfigSettingsExt, error) { return data, nil } -func marshalTLS(w http.ResponseWriter, data tlsConfig) { +func marshalTLS(w http.ResponseWriter, r *http.Request, data tlsConfig) { w.Header().Set("Content-Type", "application/json") if data.CertificateChain != "" { @@ -610,8 +661,13 @@ func marshalTLS(w http.ResponseWriter, data tlsConfig) { err := json.NewEncoder(w).Encode(data) if err != nil { - httpError(w, http.StatusInternalServerError, "Failed to marshal json with TLS status: %s", err) - return + aghhttp.Error( + r, + w, + http.StatusInternalServerError, + "Failed to marshal json with TLS status: %s", + err, + ) } } diff --git a/internal/home/web.go b/internal/home/web.go index 23e629b9..07f9d73a 100644 --- a/internal/home/web.go +++ b/internal/home/web.go @@ -114,17 +114,8 @@ func CreateWeb(conf *webConfig) *Web { // WebCheckPortAvailable - check if port is available // BUT: if we are already using this port, no need func WebCheckPortAvailable(port int) bool { - alreadyRunning := false - if Context.web.httpsServer.server != nil { - alreadyRunning = true - } - if !alreadyRunning { - err := aghnet.CheckPortAvailable(config.BindHost, port) - if err != nil { - return false - } - } - return true + return Context.web.httpsServer.server != nil || + aghnet.CheckPort("tcp", config.BindHost, port) == nil } // TLSConfigChanged updates the TLS configuration and restarts the HTTPS server diff --git a/internal/querylog/http.go b/internal/querylog/http.go index f5ddf7c0..6a2bdcee 100644 --- a/internal/querylog/http.go +++ b/internal/querylog/http.go @@ -10,6 +10,7 @@ import ( "strings" "time" + "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/golibs/jsonutil" "github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/stringutil" @@ -33,18 +34,11 @@ func (l *queryLog) initWeb() { l.conf.HTTPRegister(http.MethodPost, "/control/querylog_config", l.handleQueryLogConfig) } -func httpError(r *http.Request, w http.ResponseWriter, code int, format string, args ...interface{}) { - text := fmt.Sprintf(format, args...) - - log.Info("QueryLog: %s %s: %s", r.Method, r.URL, text) - - http.Error(w, text, code) -} - func (l *queryLog) handleQueryLog(w http.ResponseWriter, r *http.Request) { params, err := l.parseSearchParams(r) if err != nil { - httpError(r, w, http.StatusBadRequest, "failed to parse params: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "failed to parse params: %s", err) + return } @@ -56,14 +50,21 @@ func (l *queryLog) handleQueryLog(w http.ResponseWriter, r *http.Request) { jsonVal, err := json.Marshal(data) if err != nil { - httpError(r, w, http.StatusInternalServerError, "Couldn't marshal data into json: %s", err) + aghhttp.Error( + r, + w, + http.StatusInternalServerError, + "Couldn't marshal data into json: %s", + err, + ) + return } w.Header().Set("Content-Type", "application/json") _, err = w.Write(jsonVal) if err != nil { - httpError(r, w, http.StatusInternalServerError, "Unable to write response json: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "Unable to write response json: %s", err) } } @@ -80,13 +81,15 @@ func (l *queryLog) handleQueryLogInfo(w http.ResponseWriter, r *http.Request) { jsonVal, err := json.Marshal(resp) if err != nil { - httpError(r, w, http.StatusInternalServerError, "json encode: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "json encode: %s", err) + return } + w.Header().Set("Content-Type", "application/json") _, err = w.Write(jsonVal) if err != nil { - httpError(r, w, http.StatusInternalServerError, "http write: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "http write: %s", err) } } @@ -109,13 +112,15 @@ func (l *queryLog) handleQueryLogConfig(w http.ResponseWriter, r *http.Request) d := &qlogConfig{} req, err := jsonutil.DecodeObject(d, r.Body) if err != nil { - httpError(r, w, http.StatusBadRequest, "%s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "%s", err) + return } ivl := time.Duration(float64(timeutil.Day) * d.Interval) if req.Exists("interval") && !checkInterval(ivl) { - httpError(r, w, http.StatusBadRequest, "Unsupported interval") + aghhttp.Error(r, w, http.StatusBadRequest, "Unsupported interval") + return } diff --git a/internal/stats/http.go b/internal/stats/http.go index e828a2b5..e2f00039 100644 --- a/internal/stats/http.go +++ b/internal/stats/http.go @@ -4,21 +4,13 @@ package stats import ( "encoding/json" - "fmt" "net/http" "time" + "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/golibs/log" ) -func httpError(r *http.Request, w http.ResponseWriter, code int, format string, args ...interface{}) { - text := fmt.Sprintf(format, args...) - - log.Info("Stats: %s %s: %s", r.Method, r.URL, text) - - http.Error(w, text, code) -} - // topAddrs is an alias for the types of the TopFoo fields of statsResponse. // The key is either a client's address or a requested address. type topAddrs = map[string]uint64 @@ -71,7 +63,7 @@ func (s *statsCtx) handleStats(w http.ResponseWriter, r *http.Request) { log.Debug("stats: prepared data in %v", time.Since(start)) if !ok { - httpError(r, w, http.StatusInternalServerError, "Couldn't get statistics data") + aghhttp.Error(r, w, http.StatusInternalServerError, "Couldn't get statistics data") return } @@ -81,7 +73,7 @@ func (s *statsCtx) handleStats(w http.ResponseWriter, r *http.Request) { err := json.NewEncoder(w).Encode(resp) if err != nil { - httpError(r, w, http.StatusInternalServerError, "json encode: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "json encode: %s", err) return } @@ -98,13 +90,14 @@ func (s *statsCtx) handleStatsInfo(w http.ResponseWriter, r *http.Request) { data, err := json.Marshal(resp) if err != nil { - httpError(r, w, http.StatusInternalServerError, "json encode: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "json encode: %s", err) + return } w.Header().Set("Content-Type", "application/json") _, err = w.Write(data) if err != nil { - httpError(r, w, http.StatusInternalServerError, "http write: %s", err) + aghhttp.Error(r, w, http.StatusInternalServerError, "http write: %s", err) } } @@ -113,12 +106,14 @@ func (s *statsCtx) handleStatsConfig(w http.ResponseWriter, r *http.Request) { reqData := config{} err := json.NewDecoder(r.Body).Decode(&reqData) if err != nil { - httpError(r, w, http.StatusBadRequest, "json decode: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "json decode: %s", err) + return } if !checkInterval(reqData.IntervalDays) { - httpError(r, w, http.StatusBadRequest, "Unsupported interval") + aghhttp.Error(r, w, http.StatusBadRequest, "Unsupported interval") + return } diff --git a/main.go b/main.go index 4d773d2f..505eb3e5 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,10 @@ import ( "github.com/AdguardTeam/AdGuardHome/internal/home" ) +// 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 build build2 var clientBuildFS embed.FS From 0aac9908c1d47d5a5d6d0bffd0be5fdcc2356d95 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Tue, 21 Dec 2021 15:22:11 +0300 Subject: [PATCH 058/135] Pull request: all: upd chlog Merge in DNS/adguard-home from chlog to master Squashed commit of the following: commit bd9925fa46d1ca67b52938ffa8cef3262367cc40 Author: Ainar Garipov Date: Tue Dec 21 15:01:04 2021 +0300 all: upd chlog --- CHANGELOG.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4b7ccad..956c732e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,9 +10,11 @@ and this project adheres to ## [Unreleased] +## [v0.107.0] - 2021-12-21 + ### Added - Upstream server information for responses from cache ([#3772]). Note that old @@ -238,6 +240,7 @@ In this release, the schema version has changed from 10 to 12. [#3638]: https://github.com/AdguardTeam/AdGuardHome/issues/3638 [#3655]: https://github.com/AdguardTeam/AdGuardHome/issues/3655 [#3707]: https://github.com/AdguardTeam/AdGuardHome/issues/3707 +[#3737]: https://github.com/AdguardTeam/AdGuardHome/issues/3737 [#3744]: https://github.com/AdguardTeam/AdGuardHome/issues/3744 [#3772]: https://github.com/AdguardTeam/AdGuardHome/issues/3772 [#3778]: https://github.com/AdguardTeam/AdGuardHome/issues/3778 @@ -610,11 +613,12 @@ In this release, the schema version has changed from 10 to 12. -[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.3...HEAD +[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.0...HEAD +[v0.107.0]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.3...v0.107.0 [v0.106.3]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.2...v0.106.3 [v0.106.2]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.1...v0.106.2 [v0.106.1]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.0...v0.106.1 From 779fbe79b8fb6a40e3f4054e406e74bd3aede7b7 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Wed, 22 Dec 2021 16:26:01 +0300 Subject: [PATCH 059/135] Pull request: scripts: add network-control plug Updates #3976. Squashed commit of the following: commit 49d8a3a2d333c7896530c8a44c5ef06c396b5ae0 Author: Ainar Garipov Date: Wed Dec 22 16:20:45 2021 +0300 scripts: add network-control plug --- scripts/snap/snap.tmpl.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/snap/snap.tmpl.yaml b/scripts/snap/snap.tmpl.yaml index a168908c..51b094de 100644 --- a/scripts/snap/snap.tmpl.yaml +++ b/scripts/snap/snap.tmpl.yaml @@ -29,6 +29,11 @@ # (cap_net_bind_service) and also to bind to a particular interface using # SO_BINDTODEVICE (cap_net_raw). - 'network-observe' + # Add the "network-control" plug to be able to use raw sockets in the DHCP + # server. + # + # TODO(a.garipov): If this works, request auto-connect of this plug. + - 'network-control' 'daemon': 'simple' 'restart-condition': 'always' 'adguard-home-web': From 2968a65f14551f7c2990df32d4c96782936be566 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Wed, 22 Dec 2021 16:34:51 +0300 Subject: [PATCH 060/135] Pull request: all: upd go, tools, deps Updates #2275. Updates #3057. Squashed commit of the following: commit da22ad203cec1ef2a5d0a218933ddc3ac03c2ad3 Merge: dbd7e202 779fbe79 Author: Ainar Garipov Date: Wed Dec 22 16:26:46 2021 +0300 Merge branch 'master' into 2275-upd-go commit dbd7e20209ddc04198e89698b7e3c2750c4d9902 Author: Ainar Garipov Date: Wed Dec 22 15:04:17 2021 +0300 all: upd docker img commit 269796e3a00f60120a6327d6501f2dde031435c4 Author: Ainar Garipov Date: Tue Dec 21 21:04:25 2021 +0300 all: upd go, tools, deps --- .github/workflows/build.yml | 2 +- .github/workflows/lint.yml | 2 +- CHANGELOG.md | 24 +++++- README.md | 2 +- bamboo-specs/release.yaml | 6 +- bamboo-specs/test.yaml | 2 +- go.mod | 61 ++++++++++----- go.sum | 136 +++++++++++++++++++++++++-------- internal/dhcpd/options_unix.go | 22 +++--- internal/dhcpd/server.go | 1 - internal/tools/go.mod | 35 ++++++--- internal/tools/go.sum | 111 ++++++++++++++++----------- scripts/make/build-release.sh | 3 +- scripts/make/go-lint.sh | 4 +- scripts/make/go-test.sh | 7 +- 15 files changed, 287 insertions(+), 131 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 31f0258b..af2dd565 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,7 +1,7 @@ 'name': 'build' 'env': - 'GO_VERSION': '1.16' + 'GO_VERSION': '1.17' 'NODE_VERSION': '14' 'on': diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 18285511..c1faeaa9 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,7 +1,7 @@ 'name': 'lint' 'env': - 'GO_VERSION': '1.16' + 'GO_VERSION': '1.17' 'on': 'push': diff --git a/CHANGELOG.md b/CHANGELOG.md index 956c732e..827f4bf2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,12 +7,34 @@ The format is based on and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + + ## [Unreleased] +### Added + +- `windows/arm64` support ([#3057]). + +### Deprecated + + +- Go 1.17 support. v0.109.0 will require at least Go 1.18 to build. + +### Removed + +- Go 1.16 support. + +[#3057]: https://github.com/AdguardTeam/AdGuardHome/issues/3057 + + + ## [v0.107.0] - 2021-12-21 ### Added diff --git a/README.md b/README.md index e50bac89..00664365 100644 --- a/README.md +++ b/README.md @@ -185,7 +185,7 @@ Run `make init` to prepare the development environment. You will need this to build AdGuard Home: - * [go](https://golang.org/dl/) v1.16 or later. + * [go](https://golang.org/dl/) v1.17 or later. * [node.js](https://nodejs.org/en/download/) v10.16.2 or later. * [npm](https://www.npmjs.com/) v6.14 or later (temporary requirement, TODO: remove when redesign is finished). * [yarn](https://yarnpkg.com/) v1.22.5 or later. diff --git a/bamboo-specs/release.yaml b/bamboo-specs/release.yaml index 325705ae..c180e5fb 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:3.8' + 'dockerGo': 'adguard/golang-ubuntu:4.0' 'stages': - 'Make release': @@ -266,7 +266,7 @@ # need to build a few of these. 'variables': 'channel': 'beta' - 'dockerGo': 'adguard/golang-ubuntu:3.8' + 'dockerGo': 'adguard/golang-ubuntu:4.0' # release-vX.Y.Z branches are the branches from which the actual final release # is built. - '^release-v[0-9]+\.[0-9]+\.[0-9]+': @@ -276,4 +276,4 @@ # are the ones that actually get released. 'variables': 'channel': 'release' - 'dockerGo': 'adguard/golang-ubuntu:3.8' + 'dockerGo': 'adguard/golang-ubuntu:4.0' diff --git a/bamboo-specs/test.yaml b/bamboo-specs/test.yaml index 9b427e5a..c6a2ffee 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:3.8' + 'dockerGo': 'adguard/golang-ubuntu:4.0' 'stages': - 'Tests': diff --git a/go.mod b/go.mod index d6e82e5c..b225b56c 100644 --- a/go.mod +++ b/go.mod @@ -1,42 +1,69 @@ module github.com/AdguardTeam/AdGuardHome -go 1.16 +go 1.17 require ( github.com/AdguardTeam/dnsproxy v0.39.13 github.com/AdguardTeam/golibs v0.10.3 github.com/AdguardTeam/urlfilter v0.15.1 github.com/NYTimes/gziphandler v1.1.1 - github.com/ameshkov/dnscrypt/v2 v2.2.2 + github.com/ameshkov/dnscrypt/v2 v2.2.3 github.com/digineo/go-ipset/v2 v2.2.1 - github.com/fsnotify/fsnotify v1.4.9 - github.com/go-ping/ping v0.0.0-20210506233800-ff8be3320020 - github.com/google/go-cmp v0.5.5 + 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/gopacket v1.1.19 github.com/google/renameio v1.0.1 - github.com/insomniacslk/dhcp v0.0.0-20210310193751-cfd4d47082c2 + github.com/insomniacslk/dhcp v0.0.0-20211214070828-5297eed8f489 github.com/kardianos/service v1.2.0 - github.com/lucas-clemente/quic-go v0.21.1 + github.com/lucas-clemente/quic-go v0.24.0 github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 - github.com/mdlayher/netlink v1.4.0 - github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf + github.com/mdlayher/netlink v1.5.0 + github.com/mdlayher/raw v0.0.0-20211126142749-4eae47f3d54b github.com/miekg/dns v1.1.43 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-20210817164053-32db794688a5 - golang.org/x/net v0.0.0-20210929193557-e81a3d93ecf6 - golang.org/x/sys v0.0.0-20210909193231-528a39cd75f3 + 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 gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/yaml.v2 v2.4.0 - howett.net/plist v0.0.0-20201203080718-1454fab16a06 + howett.net/plist v1.0.0 ) -require github.com/stretchr/objx v0.1.1 // indirect - -// TODO(e.burkov): Get rid of the fork in v0.108.0. -replace github.com/insomniacslk/dhcp => github.com/AdguardTeam/dhcp v0.0.0-20210519141215-51808c73c0bf +require ( + github.com/BurntSushi/toml v0.4.1 // 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/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/joomcode/errorx v1.0.3 // 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/mdlayher/socket v0.1.1 // 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 + golang.org/x/mod v0.5.1 // 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/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect + gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect + honnef.co/go/tools v0.2.2 // indirect +) // TODO(a.garipov): Return to the main repo once miekg/dns#1317 is merged. replace github.com/miekg/dns => github.com/ameshkov/dns v1.1.32-0.20211214123418-7a5e0dc5f1b0 diff --git a/go.sum b/go.sum index 03737110..45bb0165 100644 --- a/go.sum +++ b/go.sum @@ -7,8 +7,6 @@ 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/dhcp v0.0.0-20210519141215-51808c73c0bf h1:gc042VRSIRSUzZ+Px6xQCRWNJZTaPkomisDfUZmoFNk= -github.com/AdguardTeam/dhcp v0.0.0-20210519141215-51808c73c0bf/go.mod h1:TKl4jN3Voofo4UJIicyNhWGp/nlQqQkFxmwIFTvBkKI= github.com/AdguardTeam/dnsproxy v0.39.13 h1:7YM5Mr4EpFZ8UO4/4xd6zBG3lZ6AzZO6Xq29Cr4ydOY= github.com/AdguardTeam/dnsproxy v0.39.13/go.mod h1:g7zjF1TWpKNeDVh6h3YrjQN8565zsWRd7zo++C/935c= github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4= @@ -19,8 +17,9 @@ github.com/AdguardTeam/golibs v0.10.3/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8 github.com/AdguardTeam/gomitmproxy v0.2.0/go.mod h1:Qdv0Mktnzer5zpdpi5rAwixNJzW2FN91LjKJCkVbYGU= github.com/AdguardTeam/urlfilter v0.15.1 h1:dP6S7J6eFAk8MN4IDpUq2fZoBo8K8fmc6pXpxNIv84M= github.com/AdguardTeam/urlfilter v0.15.1/go.mod h1:EwXwrYhowP7bedqmOrmKKmQtpBYFyDNEBFQ+lxdUgQU= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= 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/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= @@ -31,8 +30,9 @@ github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 h1:52m0LGchQBBVqJRyY github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635/go.mod h1:lmLxL+FV291OopO93Bwf9fQLQeLyt33VJRUg5VJ30us= github.com/ameshkov/dns v1.1.32-0.20211214123418-7a5e0dc5f1b0 h1:a6ca3WlDG4zvUWqVFpVu48b9NZJ0fUFlRhiZKKkq+aw= github.com/ameshkov/dns v1.1.32-0.20211214123418-7a5e0dc5f1b0/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= -github.com/ameshkov/dnscrypt/v2 v2.2.2 h1:lxtS1iSA2EjTOMToSi+2+rwspNA+b/wG5/JpccvE9CU= github.com/ameshkov/dnscrypt/v2 v2.2.2/go.mod h1:+8SbPbVXpxxcUsgGi8eodkqWPo1MyNHxKYC8hDpqLSo= +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= github.com/ameshkov/dnsstamps v1.0.3 h1:Srzik+J9mivH1alRACTbys2xOxs0lRH9qnTA7Y1OYVo= github.com/ameshkov/dnsstamps v1.0.3/go.mod h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaEZZ4gKyIH5A= @@ -44,6 +44,8 @@ github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBT 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= @@ -56,16 +58,20 @@ 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 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= 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/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= github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY= github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-ping/ping v0.0.0-20210506233800-ff8be3320020 h1:mdi6AbCEoKCA1xKCmp7UtRB5fvGFlP92PvlhxgdvXEw= -github.com/go-ping/ping v0.0.0-20210506233800-ff8be3320020/go.mod h1:KmHOjTUmJh/l04ukqPoBWPEZr9jwN05h5NXQl5C+DyY= +github.com/go-ping/ping v0.0.0-20211130115550-779d1e919534 h1:dhy9OQKGBh4zVXbjwbxxHjRxMJtLXj3zfgpBYQaR4Q4= +github.com/go-ping/ping v0.0.0-20211130115550-779d1e919534/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.5/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -83,6 +89,9 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -90,8 +99,9 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw 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 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 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-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= @@ -100,6 +110,9 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/renameio v1.0.1 h1:Lh/jXZmvZxb0BBeSY5VKEfidcbcbenKjZFzM/q0fSeU= github.com/google/renameio v1.0.1/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWUAweKUpk= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -108,6 +121,8 @@ 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/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/joomcode/errorx v1.0.3 h1:3e1mi0u7/HTPNdg6d6DYyKGBhA5l9XpsfuVE29NxnWw= @@ -121,8 +136,10 @@ github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN 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 h1:c3NTyLNozICy8B4mlMXemD3z/gXgQzVXZS/HqT+i3do= 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= @@ -130,27 +147,31 @@ github.com/kardianos/service v1.2.0 h1:bGuZ/epo3vrt8IPC7mnKQolqFeYJb7Cs8Rk4PSOBB github.com/kardianos/service v1.2.0/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.21.1 h1:uuhCcu885TE9u/piPYMChI/yqA1lXfaLUEx8uCMxf8w= github.com/lucas-clemente/quic-go v0.21.1/go.mod h1:U9kFi5LKbNIlU30dkuM9vxmTxWq4Bvzee/MjBI+07UA= +github.com/lucas-clemente/quic-go v0.24.0 h1:ToR7SIIEdrgOhgVTHvPgdVRJfgVy+N0wQAagH7L4d5g= +github.com/lucas-clemente/quic-go v0.24.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0= 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 h1:RehYMOyRW8hPVEja1KBVsFVNSm35Jj9Mvs5yNoZZ28A= github.com/marten-seemann/qtls-go1-15 v0.1.4/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= -github.com/marten-seemann/qtls-go1-16 v0.1.3 h1:XEZ1xGorVy9u+lJq+WXNE+hiqRYLNvJGYmwfwKQN2gU= github.com/marten-seemann/qtls-go1-16 v0.1.3/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk= -github.com/marten-seemann/qtls-go1-17 v0.1.0-beta.1.2 h1:SficYjyOthSrliKI+EaFuXS6HqSsX3dkY9AqxAAjBjw= +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-beta.1.2/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8= +github.com/marten-seemann/qtls-go1-17 v0.1.0 h1:P9ggrs5xtwiqXv/FHNwntmuLMNq3KaSIG93AtAZ48xk= +github.com/marten-seemann/qtls-go1-17 v0.1.0/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8= 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 h1:WgyLFv10Ov49JAQI/ZLUkCZ7VJS3r74hwFIGXJsgZlY= 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/netlink v0.0.0-20190313131330-258ea9dff42c/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= @@ -163,12 +184,19 @@ github.com/mdlayher/netlink v1.2.0/go.mod h1:kwVW1io0AZy9A1E2YYgaD4Cj+C+GPkU6klX 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 h1:n3ARR+Fm0dDv37dj5wSWZXDKcy+U0zwcXS3zKMnSiT0= 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/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-20210412142147-51b895745faf h1:InctQoB89TIkmgIFQeIL4KXNvWc1iebQXdZggqPSwL8= -github.com/mdlayher/raw v0.0.0-20210412142147-51b895745faf/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/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= 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= @@ -176,15 +204,20 @@ github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJE github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= 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/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= +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/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak= +github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= @@ -246,11 +279,15 @@ github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs= 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/u-root v7.0.0+incompatible h1:u+KSS04pSxJGI5E7WE4Bs9+Zd75QjFv+REkjy/aoAc8= -github.com/u-root/u-root v7.0.0+incompatible/go.mod h1:RYkpo8pTHrNjW08opNd/U6p/RJE7K0D8fXO0d47+3YY= +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/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= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= @@ -264,16 +301,18 @@ 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-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/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= 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= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +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/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= @@ -293,19 +332,29 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 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-20210908191846-a5e095526f91/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210929193557-e81a3d93ecf6 h1:Z04ewVs7JhXaYkmDhBERPi41gnltfQpMWDnTnQbaCqk= +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 h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM= +golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 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= @@ -316,6 +365,7 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/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= @@ -347,22 +397,33 @@ 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-20201112073958-5cba982894dd/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-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-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-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-20210909193231-528a39cd75f3 h1:3Ad41xy2WCESpufXwgs7NpDSu+vjxqLt2UFqUV+20bI= +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 h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/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.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -383,9 +444,13 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3 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-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 h1:BonxutuHCTL0rBDnZlKjpGIQFTjyUVTexFOdWkB6Fg0= 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/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= @@ -413,6 +478,9 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= @@ -423,6 +491,7 @@ gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXL gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= 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/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -437,7 +506,10 @@ 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= -howett.net/plist v0.0.0-20201203080718-1454fab16a06 h1:QDxUo/w2COstK1wIBYpzQlHX/NqaQTcf9jyz347nI58= -howett.net/plist v0.0.0-20201203080718-1454fab16a06/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= +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= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/internal/dhcpd/options_unix.go b/internal/dhcpd/options_unix.go index 07375eaf..4e15ccce 100644 --- a/internal/dhcpd/options_unix.go +++ b/internal/dhcpd/options_unix.go @@ -130,21 +130,19 @@ func parseDHCPOption(s string) (opt dhcpv4.Option, err error) { // prepareOptions builds the set of DHCP options according to host requirements // document and values from conf. func prepareOptions(conf V4ServerConf) (opts dhcpv4.Options) { + // Set default values for host configuration parameters listed in Appendix + // A of RFC-2131. Those parameters, if requested by client, should be + // returned with values defined by Host Requirements Document. + // + // See https://datatracker.ietf.org/doc/html/rfc2131#appendix-A. + // + // See also https://datatracker.ietf.org/doc/html/rfc1122, + // https://datatracker.ietf.org/doc/html/rfc1123, and + // https://datatracker.ietf.org/doc/html/rfc2132. opts = dhcpv4.Options{ - // Set default values for host configuration parameters listed - // in Appendix A of RFC-2131. Those parameters, if requested by - // client, should be returned with values defined by Host - // Requirements Document. - // - // See https://datatracker.ietf.org/doc/html/rfc2131#appendix-A. - // - // See also https://datatracker.ietf.org/doc/html/rfc1122, - // https://datatracker.ietf.org/doc/html/rfc1123, and - // https://datatracker.ietf.org/doc/html/rfc2132. - // IP-Layer Per Host - dhcpv4.OptionNonLocalSourceRouting.Code(): []byte{0}, + // Set the current recommended default time to live for the // Internet Protocol which is 64, see // https://datatracker.ietf.org/doc/html/rfc1700. diff --git a/internal/dhcpd/server.go b/internal/dhcpd/server.go index 83127aa0..a359e740 100644 --- a/internal/dhcpd/server.go +++ b/internal/dhcpd/server.go @@ -27,7 +27,6 @@ type DHCPServer interface { Start() (err error) // Stop - stop server Stop() (err error) - getLeasesRef() []*Lease } diff --git a/internal/tools/go.mod b/internal/tools/go.mod index 6847bc93..98ef459a 100644 --- a/internal/tools/go.mod +++ b/internal/tools/go.mod @@ -1,21 +1,32 @@ module github.com/AdguardTeam/AdGuardHome/internal/tools -go 1.16 +go 1.17 require ( - github.com/fzipp/gocyclo v0.3.1 + github.com/fzipp/gocyclo v0.4.0 github.com/golangci/misspell v0.3.5 - github.com/google/go-cmp v0.5.5 // indirect - github.com/gookit/color v1.4.2 // indirect - github.com/gordonklaus/ineffassign v0.0.0-20210225214923-2e10b2664254 + 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/kyoh86/nolint v0.0.1 // indirect - github.com/securego/gosec/v2 v2.7.0 + github.com/securego/gosec/v2 v2.9.5 golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 - golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 // indirect - golang.org/x/tools v0.1.1 - honnef.co/go/tools v0.1.4 - mvdan.cc/gofumpt v0.1.1 - mvdan.cc/unparam v0.0.0-20210104141923-aac4ce9116a7 + 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 +) + +require ( + github.com/BurntSushi/toml v0.4.1 // indirect + github.com/client9/misspell v0.3.4 // indirect + github.com/google/go-cmp v0.5.6 // 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 + gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/internal/tools/go.sum b/internal/tools/go.sum index 02dbb0fb..e1b2e226 100644 --- a/internal/tools/go.sum +++ b/internal/tools/go.sum @@ -33,8 +33,9 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= 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 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= 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/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= @@ -76,6 +77,7 @@ github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwc github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -90,12 +92,14 @@ 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/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.3.1 h1:A9UeX3HJSXTBzvHzhqoYVuE0eAhe+aM8XBCCwsPMZOc= -github.com/fzipp/gocyclo v0.3.1/go.mod h1:DJHO6AUmbdqj2ET4Z9iArSuwWgYDRryYt2wASxc7x3E= +github.com/fzipp/gocyclo v0.4.0 h1:IykTnjwh2YLyYkGa0y92iTTEQcnyAz0r9zOo15EbJ7k= +github.com/fzipp/gocyclo v0.4.0/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= @@ -107,6 +111,7 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= @@ -137,6 +142,8 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golangci/misspell v0.3.5 h1:pLzmVdl3VxTOncgzHcvLOKirdvcx/TydsClUQXTehjo= github.com/golangci/misspell v0.3.5/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -149,9 +156,9 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 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.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 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/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= @@ -166,14 +173,15 @@ github.com/google/trillian v1.3.11/go.mod h1:0tPraVHrSDkA3BO6vKX67zgLXs6SsOAbHEi github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gookit/color v1.3.8/go.mod h1:R3ogXq2B9rTbXoSHJ1HyUVAZ3poOJHpd9nQmyGZsfvQ= -github.com/gookit/color v1.4.2 h1:tXy44JFSFkKnELV6WaMo/lLfu/meqITX3iAV52do7lk= -github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= +github.com/gookit/color v1.5.0 h1:1Opow3+BWDwqor78DcJkJCIwnkviFi+rrOANki9BUFw= +github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= -github.com/gordonklaus/ineffassign v0.0.0-20210225214923-2e10b2664254 h1:Nb2aRlC404yz7gQIfRZxX9/MLvQiqXyiBTJtgAy6yrI= -github.com/gordonklaus/ineffassign v0.0.0-20210225214923-2e10b2664254/go.mod h1:M9mZEtGIsR1oDaZagNPNG9iq9n2HrhZ17dsXk73V3Lw= +github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8 h1:PVRE9d4AQKmbelZ7emNig1+NT27DUmKZn5qXxfio54U= +github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75/go.mod h1:g2644b03hfBX9Ov0ZBDgXXens4rxSxmqFBbhvKv2yVA= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= @@ -217,11 +225,13 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 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/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/kyoh86/looppointer v0.1.7 h1:q5sZOhFvmvQ6ZoZxvPB/Mjj2croWX7L49BBuI4XQWCM= github.com/kyoh86/looppointer v0.1.7/go.mod h1:l0cRF49N6xDPx8IuBGC/imZo8Yn1BBLJY0vzI+4fepc= @@ -231,6 +241,7 @@ github.com/kyoh86/nolint v0.0.1/go.mod h1:1ZiZZ7qqrZ9dZegU96phwVcdQOMKIqRzFJL3ew github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJiIbETBPTl9ATXQag= github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -257,7 +268,7 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/mozilla/scribe v0.0.0-20180711195314-fb71baf557c1/go.mod h1:FIczTrinKo8VaLxe6PWTPEXRXDIHz2QAwiaBaP5/4a8= -github.com/mozilla/tls-observatory v0.0.0-20210209181001-cf43108d6880/go.mod h1:FUqVoUPHSEdDR0MnFM3Dh8AU0pZHLXUD127SAJGER/s= +github.com/mozilla/tls-observatory v0.0.0-20210609171429-7bc42856d2e5/go.mod h1:FUqVoUPHSEdDR0MnFM3Dh8AU0pZHLXUD127SAJGER/s= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007/go.mod h1:m2XC9Qq0AlmmVksL6FktJCdTYyLk7V3fKyp0sl1yWQo= github.com/mwitkow/go-proto-validators v0.2.0/go.mod h1:ZfA1hW+UH/2ZHOWvQ3HnQaU0DtnpXu850MZiy+YUgcc= @@ -273,15 +284,18 @@ 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.15.0 h1:1V1NfVQR87RtWAgp1lv9JZJ5Jap+XFGKPi00andXGi4= -github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg= +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/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.10.5 h1:7n6FEkpFmfCoo2t+YYqXH0evK+a9ICQz0xcAy9dYcaQ= -github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48= +github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= 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= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -305,13 +319,14 @@ github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.2 h1:aIihoIOHCiLZHxyoNQ+ABL4NKhFTgKLBdMLyEAh98m0= -github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= 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.7.0 h1:mOhJv5w6UyNLpSssQOQCc7eGkKLuicAxvf66Ey/X4xk= -github.com/securego/gosec/v2 v2.7.0/go.mod h1:xNbGArrGUspJLuz3LS5XCY1EBW/0vABAl/LWfSklmiM= +github.com/securego/gosec/v2 v2.9.5 h1:Wiyf78NNedu8RClwW0vPRgPKCY7LJX4WujjJcPV2Nwg= +github.com/securego/gosec/v2 v2.9.5/go.mod h1:lG831xFHrZofatyJb9Y5yMUE8Ws6z5U5CMHe9vYn1kM= 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= @@ -334,8 +349,10 @@ github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -356,6 +373,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 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.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/etcd v0.0.0-20200513171258-e048e166ab9c/go.mod h1:xCI7ZzBfRuGgBXyXO6yfWfDmlWd35khcWpUa4L0xI/k= @@ -383,7 +401,7 @@ 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-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/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= @@ -417,10 +435,9 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 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.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= 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/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= @@ -456,10 +473,11 @@ 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-20201202161906-c7110b5ffcbb/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 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= 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= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -522,11 +540,14 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w 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-20210228012217-479acdf4ea46/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-20210514084401-e8d321eab015 h1:hZR0X1kPW+nwyJ9xRxqZk1vx5RUObAPBdKVvXPDUH/E= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/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/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= @@ -534,8 +555,9 @@ 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= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -591,11 +613,10 @@ 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.0.0-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210104081019-d8d6ddbec6ee/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1 h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +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/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= @@ -679,6 +700,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -714,12 +737,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.1.4 h1:SadWOkti5uVN1FAMgxn165+Mw00fuQKyk4Gyn/inxNQ= -honnef.co/go/tools v0.1.4/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= -mvdan.cc/gofumpt v0.1.1 h1:bi/1aS/5W00E2ny5q65w9SnKpWEF/UIOqDYBILpo9rA= -mvdan.cc/gofumpt v0.1.1/go.mod h1:yXG1r1WqZVKWbVRtBWKWX9+CxGYfA51nSomhM0woR48= -mvdan.cc/unparam v0.0.0-20210104141923-aac4ce9116a7 h1:HT3e4Krq+IE44tiN36RvVEb6tvqeIdtsVSsxmNPqlFU= -mvdan.cc/unparam v0.0.0-20210104141923-aac4ce9116a7/go.mod h1:hBpJkZE8H/sb+VRFvw2+rBpHNsTBcvSpk61hr8mzXZE= +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= 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= diff --git a/scripts/make/build-release.sh b/scripts/make/build-release.sh index 2cdac0bc..f3326a04 100644 --- a/scripts/make/build-release.sh +++ b/scripts/make/build-release.sh @@ -159,7 +159,8 @@ linux ppc64le 0 0 0 openbsd amd64 0 0 0 openbsd arm64 0 0 0 windows 386 0 0 0 -windows amd64 0 0 0" +windows amd64 0 0 0 +windows arm64 0 0 0" readonly platforms # Function build builds the release for one platform. It builds a binary, an diff --git a/scripts/make/go-lint.sh b/scripts/make/go-lint.sh index 6ed9b503..2d4a7fdc 100644 --- a/scripts/make/go-lint.sh +++ b/scripts/make/go-lint.sh @@ -52,7 +52,7 @@ trap not_found EXIT go_version="$( "$GO" version )" readonly go_version -go_min_version='go1.16' +go_min_version='go1.17' go_version_msg=" warning: your go version (${go_version}) is different from the recommended minimal one (${go_min_version}). if you have the version installed, please set the GO environment variable. @@ -193,7 +193,7 @@ exit_on_output method_const exit_on_output underscores -exit_on_output gofumpt --extra -l -s . +exit_on_output gofumpt --extra -e -l . golint --set_exit_status ./... diff --git a/scripts/make/go-test.sh b/scripts/make/go-test.sh index 6ab9fadd..effefca8 100644 --- a/scripts/make/go-test.sh +++ b/scripts/make/go-test.sh @@ -35,10 +35,13 @@ fi readonly race_flags go="${GO:-go}" +readonly go count_flags='--count=1' cover_flags='--coverprofile=./coverage.txt' +shuffle_flags='--shuffle=on' timeout_flags="${TIMEOUT_FLAGS:---timeout=30s}" -readonly go timeout_flags cover_flags count_flags +readonly count_flags cover_flags shuffle_flags timeout_flags -"$go" test "$count_flags" "$cover_flags" "$race_flags" "$timeout_flags" "$x_flags" "$v_flags" ./... +"$go" test "$count_flags" "$cover_flags" "$race_flags" "$shuffle_flags" "$timeout_flags"\ + "$x_flags" "$v_flags" ./... From 7f55bd84613928ccc752ec1493f9e2a969e0cf06 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Wed, 22 Dec 2021 17:11:41 +0300 Subject: [PATCH 061/135] Pull request: all: temp disable gh notifications Merge in DNS/adguard-home from temp-disable-notify to master Squashed commit of the following: commit c7f1393668e4dfe8681c9ed1c6f2ef45aed9106b Author: Ainar Garipov Date: Wed Dec 22 17:07:37 2021 +0300 all: temp disable gh notifications --- .github/workflows/build.yml | 56 ++++++++++++++++++----------------- .github/workflows/lint.yml | 58 +++++++++++++++++++------------------ 2 files changed, 59 insertions(+), 55 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index af2dd565..f942f8c4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -103,30 +103,32 @@ - 'name': 'Run snapshot build' 'run': 'make SIGN=0 VERBOSE=1 build-release build-docker' - 'notify': - 'needs': - - 'build-release' - # Secrets are not passed to workflows that are triggered by a pull request - # from a fork. - # - # Use always() to signal to the runner that this job must run even if the - # previous ones failed. - 'if': - ${{ always() && - ( - github.event_name == 'push' || - github.event.pull_request.head.repo.full_name == github.repository - ) - }} - 'runs-on': 'ubuntu-latest' - 'steps': - - 'name': 'Conclusion' - 'uses': 'technote-space/workflow-conclusion-action@v1' - - 'name': 'Send Slack notif' - 'uses': '8398a7/action-slack@v3' - 'with': - 'status': '${{ env.WORKFLOW_CONCLUSION }}' - 'fields': 'repo, message, commit, author, workflow' - 'env': - 'GITHUB_TOKEN': '${{ secrets.GITHUB_TOKEN }}' - 'SLACK_WEBHOOK_URL': '${{ secrets.SLACK_WEBHOOK_URL }}' + # TODO(a.garipov): Remove once AWS/Slack are back online. + # + # 'notify': + # 'needs': + # - 'build-release' + # # Secrets are not passed to workflows that are triggered by a pull request + # # from a fork. + # # + # # Use always() to signal to the runner that this job must run even if the + # # previous ones failed. + # 'if': + # ${{ always() && + # ( + # github.event_name == 'push' || + # github.event.pull_request.head.repo.full_name == github.repository + # ) + # }} + # 'runs-on': 'ubuntu-latest' + # 'steps': + # - 'name': 'Conclusion' + # 'uses': 'technote-space/workflow-conclusion-action@v1' + # - 'name': 'Send Slack notif' + # 'uses': '8398a7/action-slack@v3' + # 'with': + # 'status': '${{ env.WORKFLOW_CONCLUSION }}' + # 'fields': 'repo, message, commit, author, workflow' + # 'env': + # 'GITHUB_TOKEN': '${{ secrets.GITHUB_TOKEN }}' + # 'SLACK_WEBHOOK_URL': '${{ secrets.SLACK_WEBHOOK_URL }}' diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index c1faeaa9..ce1e97a9 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -33,31 +33,33 @@ - 'name': 'Run ESLint' 'run': 'npm --prefix="./client" run lint' - 'notify': - 'needs': - - 'go-lint' - - 'eslint' - # Secrets are not passed to workflows that are triggered by a pull request - # from a fork. - # - # Use always() to signal to the runner that this job must run even if the - # previous ones failed. - 'if': - ${{ always() && - ( - github.event_name == 'push' || - github.event.pull_request.head.repo.full_name == github.repository - ) - }} - 'runs-on': 'ubuntu-latest' - 'steps': - - 'name': 'Conclusion' - 'uses': 'technote-space/workflow-conclusion-action@v1' - - 'name': 'Send Slack notif' - 'uses': '8398a7/action-slack@v3' - 'with': - 'status': '${{ env.WORKFLOW_CONCLUSION }}' - 'fields': 'repo, message, commit, author, workflow' - 'env': - 'GITHUB_TOKEN': '${{ secrets.GITHUB_TOKEN }}' - 'SLACK_WEBHOOK_URL': '${{ secrets.SLACK_WEBHOOK_URL }}' + # TODO(a.garipov): Remove once AWS/Slack are back online. + # + # 'notify': + # 'needs': + # - 'go-lint' + # - 'eslint' + # # Secrets are not passed to workflows that are triggered by a pull request + # # from a fork. + # # + # # Use always() to signal to the runner that this job must run even if the + # # previous ones failed. + # 'if': + # ${{ always() && + # ( + # github.event_name == 'push' || + # github.event.pull_request.head.repo.full_name == github.repository + # ) + # }} + # 'runs-on': 'ubuntu-latest' + # 'steps': + # - 'name': 'Conclusion' + # 'uses': 'technote-space/workflow-conclusion-action@v1' + # - 'name': 'Send Slack notif' + # 'uses': '8398a7/action-slack@v3' + # 'with': + # 'status': '${{ env.WORKFLOW_CONCLUSION }}' + # 'fields': 'repo, message, commit, author, workflow' + # 'env': + # 'GITHUB_TOKEN': '${{ secrets.GITHUB_TOKEN }}' + # 'SLACK_WEBHOOK_URL': '${{ secrets.SLACK_WEBHOOK_URL }}' From 39c4999d2d3d78eb6a1de4fc29d464767965043e Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Wed, 22 Dec 2021 18:14:28 +0300 Subject: [PATCH 062/135] Pull request: client: imp en i18n Merge in DNS/adguard-home from en-i18n-safe-browsing to master Squashed commit of the following: commit dd32a58c3761818a10386b4a1d9e6871da59c71e Author: Ainar Garipov Date: Wed Dec 22 17:31:35 2021 +0300 client: imp en i18n --- client/src/__locales/en.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index edf63255..86711e23 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -163,8 +163,8 @@ "apply_btn": "Apply", "disabled_filtering_toast": "Disabled filtering", "enabled_filtering_toast": "Enabled filtering", - "disabled_safe_browsing_toast": "Disabled safebrowsing", - "enabled_safe_browsing_toast": "Enabled safebrowsing", + "disabled_safe_browsing_toast": "Disabled Safe Browsing", + "enabled_safe_browsing_toast": "Enabled Safe Browsing", "disabled_parental_toast": "Disabled parental control", "enabled_parental_toast": "Enabled parental control", "disabled_safe_search_toast": "Disabled safe search", @@ -587,8 +587,8 @@ "show_blocked_responses": "Blocked", "show_whitelisted_responses": "Allowed", "show_processed_responses": "Processed", - "blocked_safebrowsing": "Blocked by Safebrowsing", - "blocked_adult_websites": "Blocked Adult Websites", + "blocked_safebrowsing": "Blocked by Safe Browsing", + "blocked_adult_websites": "Blocked by Parental Control", "blocked_threats": "Blocked Threats", "allowed": "Allowed", "filtered": "Filtered", @@ -625,7 +625,7 @@ "last_rule_in_allowlist": "Cannot disallow this client because excluding the rule \"{{disallowed_rule}}\" will DISABLE \"Allowed clients\" list.", "experimental": "Experimental", "use_saved_key": "Use the previously saved key", - "parental_control": "Parental control", - "safe_browsing": "Safe browsing", + "parental_control": "Parental Control", + "safe_browsing": "Safe Browsing", "served_from_cache": "{{value}} (served from cache)" } From d317e192910101b5e24a7b4f1a3d3a222f3572cf Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Wed, 22 Dec 2021 21:27:36 +0300 Subject: [PATCH 063/135] home: imp auth --- internal/dnsforward/config.go | 8 ++--- internal/home/auth.go | 55 ++++++++++++++--------------------- 2 files changed, 26 insertions(+), 37 deletions(-) diff --git a/internal/dnsforward/config.go b/internal/dnsforward/config.go index 3834f79d..0c1ca017 100644 --- a/internal/dnsforward/config.go +++ b/internal/dnsforward/config.go @@ -98,10 +98,10 @@ type FilteringConfig struct { AllowedClients []string `yaml:"allowed_clients"` // IP addresses of whitelist clients DisallowedClients []string `yaml:"disallowed_clients"` // IP addresses of clients that should be blocked BlockedHosts []string `yaml:"blocked_hosts"` // hosts that should be blocked - // TrustedProxies is the list of IP addresses and CIDR networks to - // detect proxy servers addresses the DoH requests from which should be - // handled. The value of nil or an empty slice for this field makes - // Proxy not trust any address. + // TrustedProxies is the list of IP addresses and CIDR networks to detect + // proxy servers addresses the DoH requests from which should be handled. + // The value of nil or an empty slice for this field makes Proxy not trust + // any address. TrustedProxies []string `yaml:"trusted_proxies"` // DNS cache settings diff --git a/internal/home/auth.go b/internal/home/auth.go index f3001153..0477630d 100644 --- a/internal/home/auth.go +++ b/internal/home/auth.go @@ -403,8 +403,8 @@ func realIP(r *http.Request) (ip net.IP, err error) { return ip, nil } - // When everything else fails, just return the remote address as - // understood by the stdlib. + // When everything else fails, just return the remote address as understood + // by the stdlib. ipStr, err := netutil.SplitHost(r.RemoteAddr) if err != nil { return nil, fmt.Errorf("getting ip from client addr: %w", err) @@ -423,7 +423,8 @@ func handleLogin(w http.ResponseWriter, r *http.Request) { } var remoteAddr string - // The realIP couldn't be used here due to security issues. + // realIP cannot be used here without taking TrustedProxies into accound due + // to security issues. // // See https://github.com/AdguardTeam/AdGuardHome/issues/2799. // @@ -437,12 +438,7 @@ func handleLogin(w http.ResponseWriter, r *http.Request) { if blocker := Context.auth.blocker; blocker != nil { if left := blocker.check(remoteAddr); left > 0 { w.Header().Set("Retry-After", strconv.Itoa(int(left.Seconds()))) - httpError( - w, - http.StatusTooManyRequests, - "auth: blocked for %s", - left, - ) + httpError(w, http.StatusTooManyRequests, "auth: blocked for %s", left) return } @@ -455,40 +451,33 @@ func handleLogin(w http.ResponseWriter, r *http.Request) { return } - - var ip net.IP - ip, err = realIP(r) + + // Use realIP here, since this IP address is only used for logging. + ip, err := realIP(r) + if err != nil { + log.Error("auth: getting real ip from request: %s", err) + } else if ip == nil { + // Technically shouldn't happen. + log.Error("auth: unknown ip") + } if len(cookie) == 0 { - if err != nil { - log.Info("auth: getting real ip from request: %s", err) - } else if ip == nil { - // Technically shouldn't happen. - log.Info("auth: failed to login user %q from unknown ip", req.Name) - } else { - log.Info("auth: failed to login user %q from ip %q", req.Name, ip) - } + log.Info("auth: failed to login user %q from ip %v", req.Name, ip) + time.Sleep(1 * time.Second) http.Error(w, "invalid username or password", http.StatusBadRequest) return } - - if err != nil { - log.Info("auth: getting real ip from request: %s", err) - } else if ip == nil { - // Technically shouldn't happen. - log.Info("auth: user %q successfully logged in from unknown ip", req.Name) - } else { - log.Info("auth: user %q successfully logged in from ip %q", req.Name, ip) - } - w.Header().Set("Set-Cookie", cookie) + log.Info("auth: user %q successfully logged in from ip %v", req.Name, ip) - w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate, proxy-revalidate") - w.Header().Set("Pragma", "no-cache") - w.Header().Set("Expires", "0") + h := w.Header() + h.Set("Set-Cookie", cookie) + h.Set("Cache-Control", "no-store, no-cache, must-revalidate, proxy-revalidate") + h.Set("Pragma", "no-cache") + h.Set("Expires", "0") returnOK(w) } From ff3df0ec334d62832d2d23fda358c361ac14b4ca Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Thu, 23 Dec 2021 13:38:38 +0300 Subject: [PATCH 064/135] Pull request: Update miekg/dns Merge in DNS/adguard-home from upd-dns-lib to master Updates #2275. Squashed commit of the following: commit 54d0485157ac4f08830ad7d8ca9be49eef87d678 Author: Eugene Burkov Date: Thu Dec 23 13:31:34 2021 +0300 all: upd dns lib --- go.mod | 5 +---- go.sum | 10 ++++++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index b225b56c..e72af0fd 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ 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.43 + github.com/miekg/dns v1.1.45 github.com/satori/go.uuid v1.2.0 github.com/stretchr/testify v1.7.0 github.com/ti-mo/netfilter v0.4.0 @@ -64,6 +64,3 @@ require ( gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect honnef.co/go/tools v0.2.2 // indirect ) - -// TODO(a.garipov): Return to the main repo once miekg/dns#1317 is merged. -replace github.com/miekg/dns => github.com/ameshkov/dns v1.1.32-0.20211214123418-7a5e0dc5f1b0 diff --git a/go.sum b/go.sum index 45bb0165..7cd820b0 100644 --- a/go.sum +++ b/go.sum @@ -28,8 +28,6 @@ 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/ameshkov/dns v1.1.32-0.20211214123418-7a5e0dc5f1b0 h1:a6ca3WlDG4zvUWqVFpVu48b9NZJ0fUFlRhiZKKkq+aw= -github.com/ameshkov/dns v1.1.32-0.20211214123418-7a5e0dc5f1b0/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/ameshkov/dnscrypt/v2 v2.2.2/go.mod h1:+8SbPbVXpxxcUsgGi8eodkqWPo1MyNHxKYC8hDpqLSo= 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= @@ -198,6 +196,10 @@ github.com/mdlayher/socket v0.1.0/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5A 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/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.45 h1:g5fRIhm9nx7g8osrAvgb16QJfmyMsyOCb+J7LSv+Qzk= +github.com/miekg/dns v1.1.45/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= @@ -327,6 +329,7 @@ golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn 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= @@ -382,6 +385,7 @@ 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-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -406,6 +410,7 @@ golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7w 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-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -443,6 +448,7 @@ 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= From 64e751e579fac33add077743dc1d9ff39da5722c Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Thu, 23 Dec 2021 16:25:44 +0300 Subject: [PATCH 065/135] Pull request: all: upd dnsproxy Updates #3977. Squashed commit of the following: commit 3aaaacac102cdea04ae46b36d2dd3a3be7d50147 Author: Ainar Garipov Date: Thu Dec 23 16:15:11 2021 +0300 all: upd dnsproxy --- go.mod | 5 ++--- go.sum | 21 +++++++-------------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/go.mod b/go.mod index e72af0fd..c63fbe4d 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.39.13 + github.com/AdguardTeam/dnsproxy v0.40.0 github.com/AdguardTeam/golibs v0.10.3 github.com/AdguardTeam/urlfilter v0.15.1 github.com/NYTimes/gziphandler v1.1.1 @@ -43,7 +43,6 @@ require ( 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/joomcode/errorx v1.0.3 // 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 @@ -61,6 +60,6 @@ require ( golang.org/x/tools v0.1.8 // 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-20200615113413-eeeca48fe776 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect honnef.co/go/tools v0.2.2 // indirect ) diff --git a/go.sum b/go.sum index 7cd820b0..8ae55223 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.39.13 h1:7YM5Mr4EpFZ8UO4/4xd6zBG3lZ6AzZO6Xq29Cr4ydOY= -github.com/AdguardTeam/dnsproxy v0.39.13/go.mod h1:g7zjF1TWpKNeDVh6h3YrjQN8565zsWRd7zo++C/935c= +github.com/AdguardTeam/dnsproxy v0.40.0 h1:4JeOCG7aOEQxXhvAZwI7VknuHjXYJlwehO5ufkkrJaQ= +github.com/AdguardTeam/dnsproxy v0.40.0/go.mod h1:PZ9l22h3Er+5mxFQB7oHZMTvx+aa9R6LbzA/ikXQlS0= 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.9.2/go.mod h1:fCAMwPBJ8S7YMYbTWvYS+eeTLblP5E04IDtNAo7y7IY= @@ -28,7 +28,6 @@ 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/ameshkov/dnscrypt/v2 v2.2.2/go.mod h1:+8SbPbVXpxxcUsgGi8eodkqWPo1MyNHxKYC8hDpqLSo= 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= @@ -70,7 +69,6 @@ github.com/go-ping/ping v0.0.0-20211130115550-779d1e919534 h1:dhy9OQKGBh4zVXbjwb github.com/go-ping/ping v0.0.0-20211130115550-779d1e919534/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/go-test/deep v1.0.5/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= @@ -123,8 +121,7 @@ github.com/insomniacslk/dhcp v0.0.0-20211214070828-5297eed8f489 h1:jhdHqd7DxBrzf github.com/insomniacslk/dhcp v0.0.0-20211214070828-5297eed8f489/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/joomcode/errorx v1.0.3 h1:3e1mi0u7/HTPNdg6d6DYyKGBhA5l9XpsfuVE29NxnWw= -github.com/joomcode/errorx v1.0.3/go.mod h1:eQzdtdlNyN7etw6YCS4W4+lu442waxZYw5yvz0ULrRo= +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/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= @@ -151,17 +148,14 @@ 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.21.1/go.mod h1:U9kFi5LKbNIlU30dkuM9vxmTxWq4Bvzee/MjBI+07UA= github.com/lucas-clemente/quic-go v0.24.0 h1:ToR7SIIEdrgOhgVTHvPgdVRJfgVy+N0wQAagH7L4d5g= github.com/lucas-clemente/quic-go v0.24.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0= 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.3/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk= 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-beta.1.2/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8= github.com/marten-seemann/qtls-go1-17 v0.1.0 h1:P9ggrs5xtwiqXv/FHNwntmuLMNq3KaSIG93AtAZ48xk= github.com/marten-seemann/qtls-go1-17 v0.1.0/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -198,6 +192,7 @@ github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5A 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.45 h1:g5fRIhm9nx7g8osrAvgb16QJfmyMsyOCb+J7LSv+Qzk= github.com/miekg/dns v1.1.45/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -302,7 +297,6 @@ 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-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= 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= @@ -388,7 +382,6 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w 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-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -413,6 +406,7 @@ golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7w 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= 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= @@ -429,7 +423,6 @@ golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBc 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/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.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -506,8 +499,8 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= 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= From d9df7c13becdccc250d43423e81d777aadcae346 Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Thu, 23 Dec 2021 16:35:10 +0300 Subject: [PATCH 066/135] Pull request: 3998 Make hosts rules match exactly Merge in DNS/adguard-home from 3998-fix-hosts-gen to master Closes #3998 Squashed commit of the following: commit b565d51afb6c292dd16accd45b7d37ed386714e8 Author: Eugene Burkov Date: Thu Dec 23 16:25:02 2021 +0300 aghnet: make hosts rules match exactly --- internal/aghnet/hostscontainer.go | 20 ++++++++------------ internal/aghnet/hostscontainer_test.go | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/internal/aghnet/hostscontainer.go b/internal/aghnet/hostscontainer.go index 85d6103d..612d2f9f 100644 --- a/internal/aghnet/hostscontainer.go +++ b/internal/aghnet/hostscontainer.go @@ -410,11 +410,11 @@ func (hp *hostsParser) writeAliasHostRule(alias, host string) { sc = ";" rwSuccess = rules.MaskSeparator + "$dnsrewrite=NOERROR" + sc + "CNAME" + sc - constLen = len(rules.MaskStartURL) + len(rwSuccess) + len(nl) + constLen = len(rules.MaskPipe) + len(rwSuccess) + len(nl) ) hp.rulesBuilder.Grow(constLen + len(host) + len(alias)) - stringutil.WriteToBuilder(hp.rulesBuilder, rules.MaskStartURL, alias, rwSuccess, host, nl) + stringutil.WriteToBuilder(hp.rulesBuilder, rules.MaskPipe, alias, rwSuccess, host, nl) } // writeMainHostRule writes the actual rule for the qtype and the PTR for the @@ -431,8 +431,8 @@ func (hp *hostsParser) writeMainHostRule(host string, ip net.IP) (added, addedPt rwSuccess = "^$dnsrewrite=NOERROR;" rwSuccessPTR = "^$dnsrewrite=NOERROR;PTR;" - modLen = len("||") + len(rwSuccess) + len(";") - modLenPTR = len("||") + len(rwSuccessPTR) + modLen = len(rules.MaskPipe) + len(rwSuccess) + len(";") + modLenPTR = len(rules.MaskPipe) + len(rwSuccessPTR) ) var qtype string @@ -451,7 +451,7 @@ func (hp *hostsParser) writeMainHostRule(host string, ip net.IP) (added, addedPt ruleBuilder.Grow(modLen + len(host) + len(qtype) + len(ipStr)) stringutil.WriteToBuilder( ruleBuilder, - "||", + rules.MaskPipe, host, rwSuccess, qtype, @@ -461,14 +461,10 @@ func (hp *hostsParser) writeMainHostRule(host string, ip net.IP) (added, addedPt added = ruleBuilder.String() ruleBuilder.Reset() + ruleBuilder.Grow(modLenPTR + len(arpa) + len(fqdn)) - stringutil.WriteToBuilder( - ruleBuilder, - "||", - arpa, - rwSuccessPTR, - fqdn, - ) + stringutil.WriteToBuilder(ruleBuilder, rules.MaskPipe, arpa, rwSuccessPTR, fqdn) + addedPtr = ruleBuilder.String() hp.rulesBuilder.Grow(len(added) + len(addedPtr) + 2*len(nl)) diff --git a/internal/aghnet/hostscontainer_test.go b/internal/aghnet/hostscontainer_test.go index 9d2b6a10..e2784908 100644 --- a/internal/aghnet/hostscontainer_test.go +++ b/internal/aghnet/hostscontainer_test.go @@ -346,6 +346,24 @@ func TestHostsContainer(t *testing.T) { testTail: func(t *testing.T, res *urlfilter.DNSResult) { assert.Equal(t, "hello", nRewrites(t, res, 1)[0].NewCNAME) }, + }, { + name: "hello_subdomain", + req: urlfilter.DNSRequest{ + Hostname: "say.hello", + DNSType: dns.TypeA, + }, + testTail: func(t *testing.T, res *urlfilter.DNSResult) { + assert.Empty(t, res.DNSRewrites()) + }, + }, { + name: "hello_alias_subdomain", + req: urlfilter.DNSRequest{ + Hostname: "say.hello.world", + DNSType: dns.TypeA, + }, + testTail: func(t *testing.T, res *urlfilter.DNSResult) { + assert.Empty(t, res.DNSRewrites()) + }, }, { name: "lots_of_aliases", req: urlfilter.DNSRequest{ From 201ef10de6d2241ee21b0bb2b2908af2c3c56a83 Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Thu, 23 Dec 2021 20:16:08 +0300 Subject: [PATCH 067/135] Pull request: 3987 Fix nil pointer dereference Merge in DNS/adguard-home from 3987-fix-nil-deref to master Updates #3987. Updates #2846. Squashed commit of the following: commit d653e09ce88a8b10b2a17fea1563c419895c714c Author: Eugene Burkov Date: Thu Dec 23 20:08:51 2021 +0300 all: log changes commit c47a4eeacf76fa7df2d01af166dee9d52528ac58 Author: Eugene Burkov Date: Thu Dec 23 19:22:39 2021 +0300 aghnet: fix windows tests commit 9c91f14ccfe967ada3c00ddb86d673238e52c12d Author: Eugene Burkov Date: Thu Dec 23 19:09:49 2021 +0300 aghnet: imp code readability, docs commit d3df15d1892e4ebfe7f8ea7144e39a0c712fce52 Author: Eugene Burkov Date: Thu Dec 23 18:47:28 2021 +0300 aghnet: fix nil pointer dereference --- CHANGELOG.md | 5 +++++ internal/aghnet/net.go | 9 +++++++-- internal/aghnet/net_test.go | 19 +++++++++++++++++++ internal/aghnet/net_unix.go | 1 + internal/aghnet/net_windows.go | 1 + 5 files changed, 33 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 827f4bf2..a8e5888a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,11 +27,16 @@ and this project adheres to --> - Go 1.17 support. v0.109.0 will require at least Go 1.18 to build. +### Fixed + +- Panic on port availability check during installation ([#3987]). + ### Removed - Go 1.16 support. [#3057]: https://github.com/AdguardTeam/AdGuardHome/issues/3057 +[#3987]: https://github.com/AdguardTeam/AdGuardHome/issues/3987 diff --git a/internal/aghnet/net.go b/internal/aghnet/net.go index f8e36406..77bdcc63 100644 --- a/internal/aghnet/net.go +++ b/internal/aghnet/net.go @@ -187,7 +187,8 @@ func GetSubnet(ifaceName string) *net.IPNet { return nil } -// CheckPort checks if the port is available for binding. +// CheckPort checks if the port is available for binding. network is expected +// to be one of "udp" and "tcp". func CheckPort(network string, ip net.IP, port int) (err error) { var c io.Closer addr := netutil.IPPort{IP: ip, Port: port}.String() @@ -200,7 +201,11 @@ func CheckPort(network string, ip net.IP, port int) (err error) { return nil } - return errors.WithDeferred(err, closePortChecker(c)) + if err != nil { + return err + } + + return closePortChecker(c) } // IsAddrInUse checks if err is about unsuccessful address binding. diff --git a/internal/aghnet/net_test.go b/internal/aghnet/net_test.go index 38fdf9cc..2e3f54be 100644 --- a/internal/aghnet/net_test.go +++ b/internal/aghnet/net_test.go @@ -5,6 +5,8 @@ import ( "testing" "github.com/AdguardTeam/AdGuardHome/internal/aghtest" + "github.com/AdguardTeam/golibs/netutil" + "github.com/AdguardTeam/golibs/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -69,3 +71,20 @@ func TestBroadcastFromIPNet(t *testing.T) { }) } } + +func TestCheckPort(t *testing.T) { + l, err := net.Listen("tcp", "127.0.0.1:") + require.NoError(t, err) + testutil.CleanupAndRequireSuccess(t, l.Close) + + ipp := netutil.IPPortFromAddr(l.Addr()) + require.NotNil(t, ipp) + require.NotNil(t, ipp.IP) + require.NotZero(t, ipp.Port) + + err = CheckPort("tcp", ipp.IP, ipp.Port) + target := &net.OpError{} + require.ErrorAs(t, err, &target) + + assert.Equal(t, "listen", target.Op) +} diff --git a/internal/aghnet/net_unix.go b/internal/aghnet/net_unix.go index 9f0f5011..27b79579 100644 --- a/internal/aghnet/net_unix.go +++ b/internal/aghnet/net_unix.go @@ -10,6 +10,7 @@ import ( "github.com/AdguardTeam/golibs/errors" ) +// closePortChecker closes c. c must be non-nil. func closePortChecker(c io.Closer) (err error) { return c.Close() } diff --git a/internal/aghnet/net_windows.go b/internal/aghnet/net_windows.go index bbbb81d7..128f5716 100644 --- a/internal/aghnet/net_windows.go +++ b/internal/aghnet/net_windows.go @@ -25,6 +25,7 @@ func ifaceSetStaticIP(string) (err error) { return aghos.Unsupported("setting static ip") } +// closePortChecker closes c. c must be non-nil. func closePortChecker(c io.Closer) (err error) { if err = c.Close(); err != nil { return err From 46cd974e2a5cda25032e44c525a164a0989ee061 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Fri, 24 Dec 2021 17:29:57 +0300 Subject: [PATCH 068/135] Pull request: all: opt log levels Updates #3929. Squashed commit of the following: commit bfb2361d81a0667c36193484ca125d08e5638b21 Author: Ainar Garipov Date: Fri Dec 24 17:23:39 2021 +0300 all: opt log levels --- go.mod | 2 +- go.sum | 4 ++-- internal/home/controlinstall.go | 6 +++++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index c63fbe4d..0988e3a4 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.40.0 + github.com/AdguardTeam/dnsproxy v0.40.1 github.com/AdguardTeam/golibs v0.10.3 github.com/AdguardTeam/urlfilter v0.15.1 github.com/NYTimes/gziphandler v1.1.1 diff --git a/go.sum b/go.sum index 8ae55223..0ee66fd4 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.40.0 h1:4JeOCG7aOEQxXhvAZwI7VknuHjXYJlwehO5ufkkrJaQ= -github.com/AdguardTeam/dnsproxy v0.40.0/go.mod h1:PZ9l22h3Er+5mxFQB7oHZMTvx+aa9R6LbzA/ikXQlS0= +github.com/AdguardTeam/dnsproxy v0.40.1 h1:lYNi7VeCBhmdyf5xEUxfj84ikgiz5cjzocL9moiIRhk= +github.com/AdguardTeam/dnsproxy v0.40.1/go.mod h1:PZ9l22h3Er+5mxFQB7oHZMTvx+aa9R6LbzA/ikXQlS0= 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.9.2/go.mod h1:fCAMwPBJ8S7YMYbTWvYS+eeTLblP5E04IDtNAo7y7IY= diff --git a/internal/home/controlinstall.go b/internal/home/controlinstall.go index baae5d00..8baa3f6a 100644 --- a/internal/home/controlinstall.go +++ b/internal/home/controlinstall.go @@ -298,7 +298,11 @@ func shutdownSrv(ctx context.Context, srv *http.Server) { err := srv.Shutdown(ctx) if err != nil { - log.Error("error while shutting down http server %q: %s", srv.Addr, err) + if errors.Is(err, context.Canceled) { + log.Debug("shutting down http server %q: %s", srv.Addr, err) + } else { + log.Error("shutting down http server %q: %s", srv.Addr, err) + } } } From 52f36f201eb559543a13ed571faaf3c5ca9745f7 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Fri, 24 Dec 2021 20:14:36 +0300 Subject: [PATCH 069/135] Pull request: filtering: restore rewrite behavior with other question types Updates #4008. Squashed commit of the following: commit babbc29331cfc2603c0c3b0987f5ba926690ec3e Author: Ainar Garipov Date: Fri Dec 24 18:46:20 2021 +0300 filtering: restore rewrite behavior with other question types --- .github/workflows/build.yml | 56 +++++------ .github/workflows/lint.yml | 58 ++++++----- CHANGELOG.md | 3 + internal/filtering/filtering.go | 73 ++++++++------ internal/filtering/rewrites.go | 47 +++++---- internal/filtering/rewrites_test.go | 147 +++++++++++++++------------- internal/home/controlinstall.go | 33 ++++--- 7 files changed, 227 insertions(+), 190 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f942f8c4..af2dd565 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -103,32 +103,30 @@ - 'name': 'Run snapshot build' 'run': 'make SIGN=0 VERBOSE=1 build-release build-docker' - # TODO(a.garipov): Remove once AWS/Slack are back online. - # - # 'notify': - # 'needs': - # - 'build-release' - # # Secrets are not passed to workflows that are triggered by a pull request - # # from a fork. - # # - # # Use always() to signal to the runner that this job must run even if the - # # previous ones failed. - # 'if': - # ${{ always() && - # ( - # github.event_name == 'push' || - # github.event.pull_request.head.repo.full_name == github.repository - # ) - # }} - # 'runs-on': 'ubuntu-latest' - # 'steps': - # - 'name': 'Conclusion' - # 'uses': 'technote-space/workflow-conclusion-action@v1' - # - 'name': 'Send Slack notif' - # 'uses': '8398a7/action-slack@v3' - # 'with': - # 'status': '${{ env.WORKFLOW_CONCLUSION }}' - # 'fields': 'repo, message, commit, author, workflow' - # 'env': - # 'GITHUB_TOKEN': '${{ secrets.GITHUB_TOKEN }}' - # 'SLACK_WEBHOOK_URL': '${{ secrets.SLACK_WEBHOOK_URL }}' + 'notify': + 'needs': + - 'build-release' + # Secrets are not passed to workflows that are triggered by a pull request + # from a fork. + # + # Use always() to signal to the runner that this job must run even if the + # previous ones failed. + 'if': + ${{ always() && + ( + github.event_name == 'push' || + github.event.pull_request.head.repo.full_name == github.repository + ) + }} + 'runs-on': 'ubuntu-latest' + 'steps': + - 'name': 'Conclusion' + 'uses': 'technote-space/workflow-conclusion-action@v1' + - 'name': 'Send Slack notif' + 'uses': '8398a7/action-slack@v3' + 'with': + 'status': '${{ env.WORKFLOW_CONCLUSION }}' + 'fields': 'repo, message, commit, author, workflow' + 'env': + 'GITHUB_TOKEN': '${{ secrets.GITHUB_TOKEN }}' + 'SLACK_WEBHOOK_URL': '${{ secrets.SLACK_WEBHOOK_URL }}' diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index ce1e97a9..c1faeaa9 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -33,33 +33,31 @@ - 'name': 'Run ESLint' 'run': 'npm --prefix="./client" run lint' - # TODO(a.garipov): Remove once AWS/Slack are back online. - # - # 'notify': - # 'needs': - # - 'go-lint' - # - 'eslint' - # # Secrets are not passed to workflows that are triggered by a pull request - # # from a fork. - # # - # # Use always() to signal to the runner that this job must run even if the - # # previous ones failed. - # 'if': - # ${{ always() && - # ( - # github.event_name == 'push' || - # github.event.pull_request.head.repo.full_name == github.repository - # ) - # }} - # 'runs-on': 'ubuntu-latest' - # 'steps': - # - 'name': 'Conclusion' - # 'uses': 'technote-space/workflow-conclusion-action@v1' - # - 'name': 'Send Slack notif' - # 'uses': '8398a7/action-slack@v3' - # 'with': - # 'status': '${{ env.WORKFLOW_CONCLUSION }}' - # 'fields': 'repo, message, commit, author, workflow' - # 'env': - # 'GITHUB_TOKEN': '${{ secrets.GITHUB_TOKEN }}' - # 'SLACK_WEBHOOK_URL': '${{ secrets.SLACK_WEBHOOK_URL }}' + 'notify': + 'needs': + - 'go-lint' + - 'eslint' + # Secrets are not passed to workflows that are triggered by a pull request + # from a fork. + # + # Use always() to signal to the runner that this job must run even if the + # previous ones failed. + 'if': + ${{ always() && + ( + github.event_name == 'push' || + github.event.pull_request.head.repo.full_name == github.repository + ) + }} + 'runs-on': 'ubuntu-latest' + 'steps': + - 'name': 'Conclusion' + 'uses': 'technote-space/workflow-conclusion-action@v1' + - 'name': 'Send Slack notif' + 'uses': '8398a7/action-slack@v3' + 'with': + 'status': '${{ env.WORKFLOW_CONCLUSION }}' + 'fields': 'repo, message, commit, author, workflow' + 'env': + 'GITHUB_TOKEN': '${{ secrets.GITHUB_TOKEN }}' + 'SLACK_WEBHOOK_URL': '${{ secrets.SLACK_WEBHOOK_URL }}' diff --git a/CHANGELOG.md b/CHANGELOG.md index a8e5888a..2cf589c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,8 @@ and this project adheres to ### Fixed +- Legacy DNS rewrites responding from upstream when a request other than `A` or + `AAAA` is received ([#4008]). - Panic on port availability check during installation ([#3987]). ### Removed @@ -37,6 +39,7 @@ and this project adheres to [#3057]: https://github.com/AdguardTeam/AdGuardHome/issues/3057 [#3987]: https://github.com/AdguardTeam/AdGuardHome/issues/3987 +[#4008]: https://github.com/AdguardTeam/AdGuardHome/issues/4008 diff --git a/internal/filtering/filtering.go b/internal/filtering/filtering.go index 2f5717f1..f4af7ad2 100644 --- a/internal/filtering/filtering.go +++ b/internal/filtering/filtering.go @@ -507,61 +507,76 @@ func (d *DNSFilter) matchSysHostsIntl( return res, nil } -// Process rewrites table -// . Find CNAME for a domain name (exact match or by wildcard) -// . if found and CNAME equals to domain name - this is an exception; exit -// . if found, set domain name to canonical name -// . repeat for the new domain name (Note: we return only the last CNAME) -// . Find A or AAAA record for a domain name (exact match or by wildcard) -// . if found, set IP addresses (IPv4 or IPv6 depending on qtype) in Result.IPList array +// processRewrites performs filtering based on the legacy rewrite records. +// +// Firstly, it finds CNAME rewrites for host. If the CNAME is the same as host, +// this query isn't filtered. If it's different, repeat the process for the new +// CNAME, breaking loops in the process. +// +// Secondly, it finds A or AAAA rewrites for host and, if found, sets res.IPList +// accordingly. If the found rewrite has a special value of "A" or "AAAA", the +// result is an exception. func (d *DNSFilter) processRewrites(host string, qtype uint16) (res Result) { d.confLock.RLock() defer d.confLock.RUnlock() - rr := findRewrites(d.Rewrites, host, qtype) - if len(rr) != 0 { - res.Reason = Rewritten + rewrites, matched := findRewrites(d.Rewrites, host, qtype) + if !matched { + return Result{} } + res.Reason = Rewritten + cnames := stringutil.NewSet() origHost := host - for len(rr) != 0 && rr[0].Type == dns.TypeCNAME { - log.Debug("rewrite: CNAME for %s is %s", host, rr[0].Answer) + for matched && len(rewrites) > 0 && rewrites[0].Type == dns.TypeCNAME { + rwAns := rewrites[0].Answer - if host == rr[0].Answer { // "host == CNAME" is an exception + log.Debug("rewrite: cname for %s is %s", host, rwAns) + + if host == rwAns { + // Rewrite of a domain onto itself is an exception rule. res.Reason = NotFilteredNotFound return res } - host = rr[0].Answer + host = rwAns if cnames.Has(host) { - log.Info("rewrite: breaking CNAME redirection loop: %s. Question: %s", host, origHost) + log.Info("rewrite: cname loop for %q on %q", origHost, host) return res } cnames.Add(host) - res.CanonName = rr[0].Answer - rr = findRewrites(d.Rewrites, host, qtype) + res.CanonName = host + rewrites, matched = findRewrites(d.Rewrites, host, qtype) } - for _, r := range rr { - if r.Type == qtype && (qtype == dns.TypeA || qtype == dns.TypeAAAA) { - if r.IP == nil { // IP exception - res.Reason = NotFilteredNotFound - - return res - } - - res.IPList = append(res.IPList, r.IP) - log.Debug("rewrite: A/AAAA for %s is %s", host, r.IP) - } - } + setRewriteResult(&res, host, rewrites, qtype) return res } +// setRewriteResult sets the Reason or IPList of res if necessary. res must not +// be nil. +func setRewriteResult(res *Result, host string, rewrites []RewriteEntry, qtype uint16) { + for _, rw := range rewrites { + if rw.Type == qtype && (qtype == dns.TypeA || qtype == dns.TypeAAAA) { + if rw.IP == nil { + // "A"/"AAAA" exception: allow getting from upstream. + res.Reason = NotFilteredNotFound + + return + } + + res.IPList = append(res.IPList, rw.IP) + + log.Debug("rewrite: a/aaaa for %s is %s", host, rw.IP) + } + } +} + // matchBlockedServicesRules checks the host against the blocked services rules // in settings, if any. The err is always nil, it is only there to make this // a valid hostChecker function. diff --git a/internal/filtering/rewrites.go b/internal/filtering/rewrites.go index 19885d55..28a56de6 100644 --- a/internal/filtering/rewrites.go +++ b/internal/filtering/rewrites.go @@ -18,12 +18,15 @@ import ( type RewriteEntry struct { // Domain is the domain for which this rewrite should work. Domain string `yaml:"domain"` + // Answer is the IP address, canonical name, or one of the special // values: "A" or "AAAA". Answer string `yaml:"answer"` + // IP is the IP address that should be used in the response if Type is // A or AAAA. IP net.IP `yaml:"-"` + // Type is the DNS record type: A, AAAA, or CNAME. Type uint16 `yaml:"-"` } @@ -143,39 +146,46 @@ func (d *DNSFilter) prepareRewrites() { } } -// findRewrites returns the list of matched rewrite entries. The priority is: -// CNAME, then A and AAAA; exact, then wildcard. If the host is matched -// exactly, wildcard entries aren't returned. If the host matched by wildcards, -// return the most specific for the question type. -func findRewrites(entries []RewriteEntry, host string, qtype uint16) (matched []RewriteEntry) { - rr := rewritesSorted{} +// findRewrites returns the list of matched rewrite entries. If rewrites are +// empty, but matched is true, the domain is found among the rewrite rules but +// not for this question type. +// +// The result priority is: CNAME, then A and AAAA; exact, then wildcard. If the +// host is matched exactly, wildcard entries aren't returned. If the host +// matched by wildcards, return the most specific for the question type. +func findRewrites( + entries []RewriteEntry, + host string, + qtype uint16, +) (rewrites []RewriteEntry, matched bool) { for _, e := range entries { if e.Domain != host && !matchDomainWildcard(host, e.Domain) { continue } + matched = true if e.matchesQType(qtype) { - rr = append(rr, e) + rewrites = append(rewrites, e) } } - if len(rr) == 0 { - return nil + if len(rewrites) == 0 { + return nil, matched } - sort.Sort(rr) + sort.Sort(rewritesSorted(rewrites)) - for i, r := range rr { + for i, r := range rewrites { if isWildcard(r.Domain) { - // Don't use rr[:0], because we need to return at least - // one item here. - rr = rr[:max(1, i)] + // Don't use rewrites[:0], because we need to return at least one + // item here. + rewrites = rewrites[:max(1, i)] break } } - return rr + return rewrites, matched } func max(a, b int) int { @@ -230,8 +240,7 @@ func (d *DNSFilter) handleRewriteAdd(w http.ResponseWriter, r *http.Request) { d.confLock.Lock() d.Config.Rewrites = append(d.Config.Rewrites, ent) d.confLock.Unlock() - log.Debug("Rewrites: added element: %s -> %s [%d]", - ent.Domain, ent.Answer, len(d.Config.Rewrites)) + log.Debug("rewrite: added element: %s -> %s [%d]", ent.Domain, ent.Answer, len(d.Config.Rewrites)) d.Config.ConfigModified() } @@ -253,9 +262,11 @@ func (d *DNSFilter) handleRewriteDelete(w http.ResponseWriter, r *http.Request) d.confLock.Lock() for _, ent := range d.Config.Rewrites { if ent.equal(entDel) { - log.Debug("Rewrites: removed element: %s -> %s", ent.Domain, ent.Answer) + log.Debug("rewrite: removed element: %s -> %s", ent.Domain, ent.Answer) + continue } + arr = append(arr, ent) } d.Config.Rewrites = arr diff --git a/internal/filtering/rewrites_test.go b/internal/filtering/rewrites_test.go index f02582c1..549530c6 100644 --- a/internal/filtering/rewrites_test.go +++ b/internal/filtering/rewrites_test.go @@ -70,94 +70,101 @@ func TestRewrites(t *testing.T) { d.prepareRewrites() testCases := []struct { - name string - host string - wantCName string - wantVals []net.IP - dtyp uint16 + name string + host string + wantCName string + wantIPs []net.IP + wantReason Reason + dtyp uint16 }{{ - name: "not_filtered_not_found", - host: "hoost.com", - wantCName: "", - wantVals: nil, - dtyp: dns.TypeA, + name: "not_filtered_not_found", + host: "hoost.com", + wantCName: "", + wantIPs: nil, + wantReason: NotFilteredNotFound, + dtyp: dns.TypeA, }, { - name: "rewritten_a", - host: "www.host.com", - wantCName: "host.com", - wantVals: []net.IP{{1, 2, 3, 4}, {1, 2, 3, 5}}, - dtyp: dns.TypeA, + name: "rewritten_a", + host: "www.host.com", + wantCName: "host.com", + wantIPs: []net.IP{{1, 2, 3, 4}, {1, 2, 3, 5}}, + wantReason: Rewritten, + dtyp: dns.TypeA, }, { - name: "rewritten_aaaa", - host: "www.host.com", - wantCName: "host.com", - wantVals: []net.IP{net.ParseIP("1:2:3::4")}, - dtyp: dns.TypeAAAA, + name: "rewritten_aaaa", + host: "www.host.com", + wantCName: "host.com", + wantIPs: []net.IP{net.ParseIP("1:2:3::4")}, + wantReason: Rewritten, + dtyp: dns.TypeAAAA, }, { - name: "wildcard_match", - host: "abc.host.com", - wantCName: "", - wantVals: []net.IP{{1, 2, 3, 5}}, - dtyp: dns.TypeA, + name: "wildcard_match", + host: "abc.host.com", + wantCName: "", + wantIPs: []net.IP{{1, 2, 3, 5}}, + wantReason: Rewritten, + dtyp: dns.TypeA, }, { - name: "wildcard_override", - host: "a.host.com", - wantCName: "", - wantVals: []net.IP{{1, 2, 3, 4}}, - dtyp: dns.TypeA, + name: "wildcard_override", + host: "a.host.com", + wantCName: "", + wantIPs: []net.IP{{1, 2, 3, 4}}, + wantReason: Rewritten, + dtyp: dns.TypeA, }, { - name: "wildcard_cname_interaction", - host: "www.host2.com", - wantCName: "host.com", - wantVals: []net.IP{{1, 2, 3, 4}, {1, 2, 3, 5}}, - dtyp: dns.TypeA, + name: "wildcard_cname_interaction", + host: "www.host2.com", + wantCName: "host.com", + wantIPs: []net.IP{{1, 2, 3, 4}, {1, 2, 3, 5}}, + wantReason: Rewritten, + dtyp: dns.TypeA, }, { - name: "two_cnames", - host: "b.host.com", - wantCName: "somehost.com", - wantVals: []net.IP{{0, 0, 0, 0}}, - dtyp: dns.TypeA, + name: "two_cnames", + host: "b.host.com", + wantCName: "somehost.com", + wantIPs: []net.IP{{0, 0, 0, 0}}, + wantReason: Rewritten, + dtyp: dns.TypeA, }, { - name: "two_cnames_and_wildcard", - host: "b.host3.com", - wantCName: "x.host.com", - wantVals: []net.IP{{1, 2, 3, 5}}, - dtyp: dns.TypeA, + name: "two_cnames_and_wildcard", + host: "b.host3.com", + wantCName: "x.host.com", + wantIPs: []net.IP{{1, 2, 3, 5}}, + wantReason: Rewritten, + dtyp: dns.TypeA, }, { - name: "issue3343", - host: "www.hostboth.com", - wantCName: "", - wantVals: []net.IP{net.ParseIP("1234::5678")}, - dtyp: dns.TypeAAAA, + name: "issue3343", + host: "www.hostboth.com", + wantCName: "", + wantIPs: []net.IP{net.ParseIP("1234::5678")}, + wantReason: Rewritten, + dtyp: dns.TypeAAAA, }, { - name: "issue3351", - host: "bighost.com", - wantCName: "", - wantVals: []net.IP{{1, 2, 3, 7}}, - dtyp: dns.TypeA, + name: "issue3351", + host: "bighost.com", + wantCName: "", + wantIPs: []net.IP{{1, 2, 3, 7}}, + wantReason: Rewritten, + dtyp: dns.TypeA, + }, { + name: "issue4008", + host: "somehost.com", + wantCName: "", + wantIPs: nil, + wantReason: Rewritten, + dtyp: dns.TypeHTTPS, }} for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - valsNum := len(tc.wantVals) - r := d.processRewrites(tc.host, tc.dtyp) - if valsNum == 0 { - assert.Equal(t, NotFilteredNotFound, r.Reason) - - return - } - - require.Equalf(t, Rewritten, r.Reason, "got %s", r.Reason) + require.Equalf(t, tc.wantReason, r.Reason, "got %s", r.Reason) if tc.wantCName != "" { assert.Equal(t, tc.wantCName, r.CanonName) } - require.Len(t, r.IPList, valsNum) - for i, ip := range tc.wantVals { - assert.Equal(t, ip, r.IPList[i]) - } + assert.Equal(t, tc.wantIPs, r.IPList) }) } } @@ -229,15 +236,17 @@ func TestRewritesExceptionCNAME(t *testing.T) { host string want net.IP }{{ - name: "match_sub-domain", + name: "match_subdomain", host: "my.host.com", want: net.IP{2, 2, 2, 2}, }, { name: "exception_cname", host: "sub.host.com", + want: nil, }, { name: "exception_wildcard", host: "my.sub.host.com", + want: nil, }} for _, tc := range testCases { diff --git a/internal/home/controlinstall.go b/internal/home/controlinstall.go index 8baa3f6a..cc01255f 100644 --- a/internal/home/controlinstall.go +++ b/internal/home/controlinstall.go @@ -22,16 +22,17 @@ import ( // getAddrsResponse is the response for /install/get_addresses endpoint. type getAddrsResponse struct { + Interfaces map[string]*aghnet.NetInterface `json:"interfaces"` WebPort int `json:"web_port"` DNSPort int `json:"dns_port"` - Interfaces map[string]*aghnet.NetInterface `json:"interfaces"` } // handleInstallGetAddresses is the handler for /install/get_addresses endpoint. func (web *Web) handleInstallGetAddresses(w http.ResponseWriter, r *http.Request) { - data := getAddrsResponse{} - data.WebPort = defaultPortHTTP - data.DNSPort = defaultPortDNS + data := getAddrsResponse{ + WebPort: defaultPortHTTP, + DNSPort: defaultPortDNS, + } ifaces, err := aghnet.GetValidNetInterfacesForWeb() if err != nil { @@ -61,8 +62,8 @@ func (web *Web) handleInstallGetAddresses(w http.ResponseWriter, r *http.Request } type checkConfigReqEnt struct { - Port int `json:"port"` IP net.IP `json:"ip"` + Port int `json:"port"` Autofix bool `json:"autofix"` } @@ -84,9 +85,9 @@ type staticIPJSON struct { } type checkConfigResp struct { + StaticIP staticIPJSON `json:"static_ip"` Web checkConfigRespEnt `json:"web"` DNS checkConfigRespEnt `json:"dns"` - StaticIP staticIPJSON `json:"static_ip"` } // Check if ports are available, respond with results @@ -298,10 +299,11 @@ func shutdownSrv(ctx context.Context, srv *http.Server) { err := srv.Shutdown(ctx) if err != nil { + const msgFmt = "shutting down http server %q: %s" if errors.Is(err, context.Canceled) { - log.Debug("shutting down http server %q: %s", srv.Addr, err) + log.Debug(msgFmt, srv.Addr, err) } else { - log.Error("shutting down http server %q: %s", srv.Addr, err) + log.Error(msgFmt, srv.Addr, err) } } } @@ -436,8 +438,8 @@ func (web *Web) registerInstallHandlers() { // TODO(e.burkov): This should removed with the API v1 when the appropriate // functionality will appear in default checkConfigReqEnt. type checkConfigReqEntBeta struct { - Port int `json:"port"` IP []net.IP `json:"ip"` + Port int `json:"port"` Autofix bool `json:"autofix"` } @@ -474,13 +476,13 @@ func (web *Web) handleInstallCheckConfigBeta(w http.ResponseWriter, r *http.Requ nonBetaReqData := checkConfigReq{ Web: checkConfigReqEnt{ - Port: reqData.Web.Port, IP: reqData.Web.IP[0], + Port: reqData.Web.Port, Autofix: reqData.Web.Autofix, }, DNS: checkConfigReqEnt{ - Port: reqData.DNS.Port, IP: reqData.DNS.IP[0], + Port: reqData.DNS.Port, Autofix: reqData.DNS.Autofix, }, SetStaticIP: reqData.SetStaticIP, @@ -589,9 +591,9 @@ func (web *Web) handleInstallConfigureBeta(w http.ResponseWriter, r *http.Reques // TODO(e.burkov): This should removed with the API v1 when the appropriate // functionality will appear in default firstRunData. type getAddrsResponseBeta struct { + Interfaces []*aghnet.NetInterface `json:"interfaces"` WebPort int `json:"web_port"` DNSPort int `json:"dns_port"` - Interfaces []*aghnet.NetInterface `json:"interfaces"` } // handleInstallConfigureBeta is a substitution of /install/get_addresses @@ -600,9 +602,10 @@ type getAddrsResponseBeta struct { // TODO(e.burkov): This should removed with the API v1 when the appropriate // functionality will appear in default handleInstallGetAddresses. func (web *Web) handleInstallGetAddressesBeta(w http.ResponseWriter, r *http.Request) { - data := getAddrsResponseBeta{} - data.WebPort = defaultPortHTTP - data.DNSPort = defaultPortDNS + data := getAddrsResponseBeta{ + WebPort: defaultPortHTTP, + DNSPort: defaultPortDNS, + } ifaces, err := aghnet.GetValidNetInterfacesForWeb() if err != nil { From 661f4ece48d9e8d4c17847961184f1d93bdfa16f Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Mon, 27 Dec 2021 19:12:40 +0300 Subject: [PATCH 070/135] Pull request: 3868 imp service uninstall Merge in DNS/adguard-home from 3868-imp-uninstall to master Closes #3868. Updates #3457. Squashed commit of the following: commit 6f50713407980c27e5b14bef4dc8839e134ec5c8 Author: Eugene Burkov Date: Mon Dec 27 19:06:13 2021 +0300 all: imp openwrt commit 59f058f8ec7f5ac8cb795bf837c396601652a6ff Author: Eugene Burkov Date: Mon Dec 27 17:26:32 2021 +0300 all: imp code && docs commit bab95366b0ffa40d96de5bb8116ec14606e310ed Merge: 92ebc210 52f36f20 Author: Eugene Burkov Date: Mon Dec 27 17:06:25 2021 +0300 Merge branch 'master' into 3868-imp-uninstall commit 92ebc210f04d5e02c3eef726017a0d5687f4bc4c Author: Eugene Burkov Date: Mon Dec 27 13:18:58 2021 +0300 home: imp freebsd script & log changes commit 583ffc256e9f87cf19da2eca8bbefc9e00ea86cc Author: Eugene Burkov Date: Thu Dec 16 14:08:46 2021 +0300 all: imp service uninstall --- CHANGELOG.md | 5 ++++- internal/home/service.go | 23 +++++++++++++++-------- internal/home/service_openbsd.go | 3 +-- scripts/install.sh | 1 + 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cf589c1..f7a8e9f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,12 +23,14 @@ and this project adheres to - Go 1.17 support. v0.109.0 will require at least Go 1.18 to build. ### Fixed +- Service not being stopped before running the `uninstall` service action + ([#3868]). - Legacy DNS rewrites responding from upstream when a request other than `A` or `AAAA` is received ([#4008]). - Panic on port availability check during installation ([#3987]). @@ -38,6 +40,7 @@ and this project adheres to - Go 1.16 support. [#3057]: https://github.com/AdguardTeam/AdGuardHome/issues/3057 +[#3868]: https://github.com/AdguardTeam/AdGuardHome/issues/3868 [#3987]: https://github.com/AdguardTeam/AdGuardHome/issues/3987 [#4008]: https://github.com/AdguardTeam/AdGuardHome/issues/4008 diff --git a/internal/home/service.go b/internal/home/service.go index 4d003584..c2073e6c 100644 --- a/internal/home/service.go +++ b/internal/home/service.go @@ -102,9 +102,9 @@ func sendSigReload() { return } - pidfile := fmt.Sprintf("/var/run/%s.pid", serviceName) + pidFile := fmt.Sprintf("/var/run/%s.pid", serviceName) var pid int - data, err := os.ReadFile(pidfile) + data, err := os.ReadFile(pidFile) if errors.Is(err, os.ErrNotExist) { if pid, err = aghos.PIDByCommand(serviceName, os.Getpid()); err != nil { log.Error("service: finding AdGuardHome process: %s", err) @@ -112,19 +112,19 @@ func sendSigReload() { return } } else if err != nil { - log.Error("service: reading pid file %s: %s", pidfile, err) + log.Error("service: reading pid file %s: %s", pidFile, err) return } else { parts := strings.SplitN(string(data), "\n", 2) if len(parts) == 0 { - log.Error("service: parsing pid file %s: bad value", pidfile) + log.Error("service: parsing pid file %s: bad value", pidFile) return } if pid, err = strconv.Atoi(strings.TrimSpace(parts[0])); err != nil { - log.Error("service: parsing pid from file %s: %s", pidfile, err) + log.Error("service: parsing pid from file %s: %s", pidFile, err) return } @@ -243,7 +243,7 @@ func handleServiceInstallCommand(s service.Service) { if aghos.IsOpenWrt() { // On OpenWrt it is important to run enable after the service - // installation Otherwise, the service won't start on the system + // installation. Otherwise, the service won't start on the system // startup. _, err = runInitdCommand("enable") if err != nil { @@ -279,6 +279,10 @@ func handleServiceUninstallCommand(s service.Service) { } } + if err := svcAction(s, "stop"); err != nil { + log.Debug("service: executing action %q: %s", "stop", err) + } + if err := svcAction(s, "uninstall"); err != nil { log.Fatalf("service: executing action %q: %s", "uninstall", err) } @@ -341,7 +345,9 @@ func configureService(c *service.Config) { // returns command code or error if any func runInitdCommand(action string) (int, error) { confPath := "/etc/init.d/" + serviceName + // Pass the script and action as a single string argument. code, _, err := aghos.RunCommand("sh", "-c", confPath+" "+action) + return code, err } @@ -579,9 +585,10 @@ const freeBSDScript = `#!/bin/sh name="{{.Name}}" {{.Name}}_env="IS_DAEMON=1" {{.Name}}_user="root" -pidfile="/var/run/${name}.pid" +pidfile_child="/var/run/${name}.pid" +pidfile="/var/run/${name}_daemon.pid" command="/usr/sbin/daemon" -command_args="-p ${pidfile} -f -r {{.WorkingDirectory}}/{{.Name}}" +command_args="-P ${pidfile} -p ${pidfile_child} -f -r {{.WorkingDirectory}}/{{.Name}}" run_rc_command "$1" ` diff --git a/internal/home/service_openbsd.go b/internal/home/service_openbsd.go index be715edf..521e6287 100644 --- a/internal/home/service_openbsd.go +++ b/internal/home/service_openbsd.go @@ -28,8 +28,7 @@ import ( // // TODO(e.burkov): Perhaps, file a PR to github.com/kardianos/service. -// sysVersion is the version of local service.System interface -// implementation. +// sysVersion is the version of local service.System interface implementation. const sysVersion = "openbsd-runcom" func chooseSystem() { diff --git a/scripts/install.sh b/scripts/install.sh index dd0bcdab..078dc34b 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -481,6 +481,7 @@ handle_existing() { "to reinstall/uninstall the AdGuard Home using this script specify one of the '-r' or '-u' flags" fi + # TODO(e.burkov): Remove the stop once v0.107.1 released. if ( cd "$agh_dir" && ! ./AdGuardHome -s stop || ! ./AdGuardHome -s uninstall ) then # It doesn't terminate the script since it is possible From 313555b10cabd58785a1702b8b8c3dbbf4ae7cc7 Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Mon, 27 Dec 2021 19:29:42 +0300 Subject: [PATCH 071/135] Pull request: 3868 log freebsd reload fix Merge in DNS/adguard-home from 3868-changelog to master Squashed commit of the following: commit 92ccf7422c4c1342c160e4806cbf9fb17c22749b Author: Eugene Burkov Date: Mon Dec 27 19:22:47 2021 +0300 all: log more changes --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7a8e9f7..b7e8a3db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ and this project adheres to - Service not being stopped before running the `uninstall` service action ([#3868]). +- Broken `reload` service action on FreeBSD. - Legacy DNS rewrites responding from upstream when a request other than `A` or `AAAA` is received ([#4008]). - Panic on port availability check during installation ([#3987]). From dea8a585f837c52476f98e192d7e8453720bc09d Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Mon, 27 Dec 2021 19:40:39 +0300 Subject: [PATCH 072/135] Pull request: filtering: fix rw to subdomain Updates #4016. Squashed commit of the following: commit 83bb15c5a5098103cd17e76b49f456fb4fa73408 Merge: 81905503 313555b1 Author: Ainar Garipov Date: Mon Dec 27 19:36:44 2021 +0300 Merge branch 'master' into 4016-rw-subdomain commit 81905503c977c004d7ddca1d4e7537bf76443a6e Author: Ainar Garipov Date: Mon Dec 27 19:35:51 2021 +0300 filtering: fix self reqs commit b706f481f00232d28dade0bd747a7496753c7deb Merge: 29cf83de 661f4ece Author: Ainar Garipov Date: Mon Dec 27 19:13:08 2021 +0300 Merge branch 'master' into 4016-rw-subdomain commit 29cf83de8e3ff60ea1c471c2a161055b1377392d Author: Ainar Garipov Date: Mon Dec 27 19:07:08 2021 +0300 all: fix docs commit 9213fd8ec2b81e65b1198ab241400065f14684b1 Author: Ainar Garipov Date: Mon Dec 27 18:44:06 2021 +0300 filtering: fix rw to subdomain --- CHANGELOG.md | 2 + internal/aghnet/hostscontainer.go | 6 +- internal/aghnet/interfaces.go | 6 +- internal/dhcpd/iprange.go | 4 +- internal/dnsforward/clientid_test.go | 4 +- internal/dnsforward/dns.go | 6 +- internal/dnsforward/dnsforward.go | 4 +- internal/dnsforward/dnsforward_test.go | 2 +- internal/dnsforward/recursiondetector.go | 4 +- internal/filtering/filtering.go | 61 +++++++--- internal/filtering/rewrites.go | 142 +++++++++++++++-------- internal/filtering/rewrites_test.go | 39 +++++-- internal/home/auth.go | 4 +- internal/home/clients.go | 4 +- internal/home/config.go | 2 +- internal/home/control.go | 2 +- internal/querylog/querylog.go | 2 +- internal/querylog/searchcriterion.go | 2 +- internal/querylog/searchparams.go | 2 +- 19 files changed, 193 insertions(+), 105 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7e8a3db..4893f839 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ and this project adheres to ### Fixed +- Legacy DNS rewrites from a wildcard pattern to a subdomain ([#4016]). - Service not being stopped before running the `uninstall` service action ([#3868]). - Broken `reload` service action on FreeBSD. @@ -44,6 +45,7 @@ and this project adheres to [#3868]: https://github.com/AdguardTeam/AdGuardHome/issues/3868 [#3987]: https://github.com/AdguardTeam/AdGuardHome/issues/3987 [#4008]: https://github.com/AdguardTeam/AdGuardHome/issues/4008 +[#4016]: https://github.com/AdguardTeam/AdGuardHome/issues/4016 diff --git a/internal/aghnet/hostscontainer.go b/internal/aghnet/hostscontainer.go index 612d2f9f..436464e2 100644 --- a/internal/aghnet/hostscontainer.go +++ b/internal/aghnet/hostscontainer.go @@ -373,7 +373,7 @@ func (hp *hostsParser) add(ip net.IP, host string) (hostType int) { // addPair puts the pair of ip and host to the rules builder if needed. For // each ip the first member of hosts will become the main one. func (hp *hostsParser) addPairs(ip net.IP, hosts []string) { - // Put the rule in a preproccesed format like: + // Put the rule in a processed format like: // // ip host1 host2 ... // @@ -488,14 +488,14 @@ func (hp *hostsParser) equalSet(target *netutil.IPMap) (ok bool) { v, hasIP := target.Get(ip) // ok is set to true if the target doesn't contain ip or if the // appropriate hosts set isn't equal to the checked one, i.e. the maps - // have at least one disperancy. + // have at least one discrepancy. ok = !hasIP || !v.(*stringutil.Set).Equal(val.(*stringutil.Set)) // Continue only if maps has no discrepancies. return !ok }) - // Return true if every value from the IP map has no disperancies with the + // Return true if every value from the IP map has no discrepancies with the // appropriate one from the target. return !ok } diff --git a/internal/aghnet/interfaces.go b/internal/aghnet/interfaces.go index b0511b0d..a5095919 100644 --- a/internal/aghnet/interfaces.go +++ b/internal/aghnet/interfaces.go @@ -8,8 +8,8 @@ import ( "github.com/AdguardTeam/golibs/log" ) -// IPVersion is a documentational alias for int. Use it when the integer means -// IP version. +// IPVersion is a alias for int for documentation purposes. Use it when the +// integer means IP version. type IPVersion = int // IP version constants. @@ -67,7 +67,7 @@ func IfaceIPAddrs(iface NetIface, ipv IPVersion) (ips []net.IP, err error) { // // It makes up to maxAttempts attempts to get the addresses if there are none, // each time using the provided backoff. Sometimes an interface needs a few -// seconds to really ititialize. +// seconds to really initialize. // // See https://github.com/AdguardTeam/AdGuardHome/issues/2304. func IfaceDNSIPAddrs( diff --git a/internal/dhcpd/iprange.go b/internal/dhcpd/iprange.go index 55670743..45422957 100644 --- a/internal/dhcpd/iprange.go +++ b/internal/dhcpd/iprange.go @@ -14,8 +14,8 @@ import ( // // It is safe for concurrent use. // -// TODO(a.garipov): Perhaps create an optimised version with uint32 for -// IPv4 ranges? Or use one of uint128 packages? +// TODO(a.garipov): Perhaps create an optimized version with uint32 for IPv4 +// ranges? Or use one of uint128 packages? type ipRange struct { start *big.Int end *big.Int diff --git a/internal/dnsforward/clientid_test.go b/internal/dnsforward/clientid_test.go index ad7ac43f..d43de02f 100644 --- a/internal/dnsforward/clientid_test.go +++ b/internal/dnsforward/clientid_test.go @@ -31,8 +31,8 @@ func (c testTLSConn) ConnectionState() (cs tls.ConnectionState) { // testQUICSession is a quicSession for tests. type testQUICSession struct { - // Session is embedded here simply to make testQUICSession - // a quic.Session without acctually implementing all methods. + // Session is embedded here simply to make testQUICSession a quic.Session + // without actually implementing all methods. quic.Session serverName string diff --git a/internal/dnsforward/dns.go b/internal/dnsforward/dns.go index 20c86c9f..5c3db14f 100644 --- a/internal/dnsforward/dns.go +++ b/internal/dnsforward/dns.go @@ -293,9 +293,9 @@ func (s *Server) processInternalHosts(dctx *dnsContext) (rc resultCode) { req := dctx.proxyCtx.Req q := req.Question[0] - // Go on processing the AAAA request despite the fact that we don't - // support it yet. The expected behavior here is to respond with an - // empty asnwer and not NXDOMAIN. + // Go on processing the AAAA request despite the fact that we don't support + // it yet. The expected behavior here is to respond with an empty answer + // and not NXDOMAIN. if q.Qtype != dns.TypeA && q.Qtype != dns.TypeAAAA { return resultCodeSuccess } diff --git a/internal/dnsforward/dnsforward.go b/internal/dnsforward/dnsforward.go index ab2d8a82..fcd438e3 100644 --- a/internal/dnsforward/dnsforward.go +++ b/internal/dnsforward/dnsforward.go @@ -443,7 +443,7 @@ func (s *Server) setupResolvers(localAddrs []string) (err error) { &upstream.Options{ Bootstrap: bootstraps, Timeout: defaultLocalTimeout, - // TODO(e.burkov): Should we verify server's ceritificates? + // TODO(e.burkov): Should we verify server's certificates? }, ) if err != nil { @@ -559,7 +559,7 @@ func (s *Server) IsRunning() bool { return s.isRunning } -// srvClosedErr is returned when the method can't complete without inacessible +// srvClosedErr is returned when the method can't complete without inaccessible // data from the closing server. const srvClosedErr errors.Error = "server is closed" diff --git a/internal/dnsforward/dnsforward_test.go b/internal/dnsforward/dnsforward_test.go index 512eb87a..d0191c85 100644 --- a/internal/dnsforward/dnsforward_test.go +++ b/internal/dnsforward/dnsforward_test.go @@ -892,7 +892,7 @@ func TestBlockedBySafeBrowsing(t *testing.T) { func TestRewrite(t *testing.T) { c := &filtering.Config{ - Rewrites: []filtering.RewriteEntry{{ + Rewrites: []*filtering.LegacyRewrite{{ Domain: "test.com", Answer: "1.2.3.4", Type: dns.TypeA, diff --git a/internal/dnsforward/recursiondetector.go b/internal/dnsforward/recursiondetector.go index 4555f4b0..870779f2 100644 --- a/internal/dnsforward/recursiondetector.go +++ b/internal/dnsforward/recursiondetector.go @@ -78,8 +78,8 @@ func newRecursionDetector(ttl time.Duration, suspectsNum uint) (rd *recursionDet // msgToSignature converts msg into it's signature represented in bytes. func msgToSignature(msg dns.Msg) (sig []byte) { sig = make([]byte, uint16sz*2+netutil.MaxDomainNameLen) - // The binary.BigEndian byte order is used everywhere except when the - // real machine's endianess is needed. + // The binary.BigEndian byte order is used everywhere except when the real + // machine's endianness is needed. byteOrder := binary.BigEndian byteOrder.PutUint16(sig[0:], msg.Id) q := msg.Question[0] diff --git a/internal/filtering/filtering.go b/internal/filtering/filtering.go index f4af7ad2..a2a8ff21 100644 --- a/internal/filtering/filtering.go +++ b/internal/filtering/filtering.go @@ -28,7 +28,7 @@ import ( // The IDs of built-in filter lists. // -// Keep in sync with client/src/helpers/contants.js. +// Keep in sync with client/src/helpers/constants.js. const ( CustomListID = -iota SysHostsListID @@ -80,7 +80,7 @@ type Config struct { ParentalCacheSize uint `yaml:"parental_cache_size"` // (in bytes) CacheTime uint `yaml:"cache_time"` // Element's TTL (in minutes) - Rewrites []RewriteEntry `yaml:"rewrites"` + Rewrites []*LegacyRewrite `yaml:"rewrites"` // Names of services to block (globally). // Per-client settings can override this configuration. @@ -161,9 +161,14 @@ type DNSFilter struct { // Filter represents a filter list type Filter struct { - ID int64 // auto-assigned when filter is added (see nextFilterID) - Data []byte `yaml:"-"` // List of rules divided by '\n' - FilePath string `yaml:"-"` // Path to a filtering rules file + // FilePath is the path to a filtering rules list file. + FilePath string `yaml:"-"` + + // Data is the content of the file. + Data []byte `yaml:"-"` + + // ID is automatically assigned when filter is added using nextFilterID. + ID int64 } // Reason holds an enum detailing why it was filtered or not filtered @@ -281,8 +286,14 @@ func (d *DNSFilter) WriteDiskConfig(c *Config) { c.Rewrites = cloneRewrites(c.Rewrites) } -func cloneRewrites(entries []RewriteEntry) (clone []RewriteEntry) { - return append([]RewriteEntry(nil), entries...) +// cloneRewrites returns a deep copy of entries. +func cloneRewrites(entries []*LegacyRewrite) (clone []*LegacyRewrite) { + clone = make([]*LegacyRewrite, len(entries)) + for i, rw := range entries { + clone[i] = rw.clone() + } + + return clone } // SetFilters - set new filters (synchronously or asynchronously) @@ -477,10 +488,8 @@ func (d *DNSFilter) matchSysHosts( } // matchSysHostsIntl actually matches the request. It's separated to avoid -// perfoming checks twice. -func (d *DNSFilter) matchSysHostsIntl( - req *urlfilter.DNSRequest, -) (res Result, err error) { +// performing checks twice. +func (d *DNSFilter) matchSysHostsIntl(req *urlfilter.DNSRequest) (res Result, err error) { dnsres, _ := d.EtcHosts.MatchRequest(*req) if dnsres == nil { return res, nil @@ -530,15 +539,25 @@ func (d *DNSFilter) processRewrites(host string, qtype uint16) (res Result) { cnames := stringutil.NewSet() origHost := host for matched && len(rewrites) > 0 && rewrites[0].Type == dns.TypeCNAME { - rwAns := rewrites[0].Answer + rw := rewrites[0] + rwPat := rw.Domain + rwAns := rw.Answer log.Debug("rewrite: cname for %s is %s", host, rwAns) - if host == rwAns { - // Rewrite of a domain onto itself is an exception rule. - res.Reason = NotFilteredNotFound + if origHost == rwAns || rwPat == rwAns { + // Either a request for the hostname itself or a rewrite of + // a pattern onto itself, both of which are an exception rules. + // Return a not filtered result. + return Result{} + } else if host == rwAns && isWildcard(rwPat) { + // An "*.example.com → sub.example.com" rewrite matching in a loop. + // + // See https://github.com/AdguardTeam/AdGuardHome/issues/4016. - return res + res.CanonName = host + + break } host = rwAns @@ -560,7 +579,7 @@ func (d *DNSFilter) processRewrites(host string, qtype uint16) (res Result) { // setRewriteResult sets the Reason or IPList of res if necessary. res must not // be nil. -func setRewriteResult(res *Result, host string, rewrites []RewriteEntry, qtype uint16) { +func setRewriteResult(res *Result, host string, rewrites []*LegacyRewrite, qtype uint16) { for _, rw := range rewrites { if rw.Type == qtype && (qtype == dns.TypeA || qtype == dns.TypeAAAA) { if rw.IP == nil { @@ -932,12 +951,18 @@ func New(c *Config, blockFilters []Filter) (d *DNSFilter) { err := d.initSecurityServices() if err != nil { log.Error("filtering: initialize services: %s", err) + return nil } if c != nil { d.Config = *c - d.prepareRewrites() + err = d.prepareRewrites() + if err != nil { + log.Error("rewrites: preparing: %s", err) + + return nil + } } bsvcs := []string{} diff --git a/internal/filtering/rewrites.go b/internal/filtering/rewrites.go index 28a56de6..dab4c034 100644 --- a/internal/filtering/rewrites.go +++ b/internal/filtering/rewrites.go @@ -4,19 +4,24 @@ package filtering import ( "encoding/json" + "fmt" "net" "net/http" "sort" "strings" "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" + "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/log" + "github.com/AdguardTeam/golibs/netutil" "github.com/miekg/dns" ) -// RewriteEntry is a rewrite array element -type RewriteEntry struct { - // Domain is the domain for which this rewrite should work. +// LegacyRewrite is a single legacy DNS rewrite record. +// +// Instances of *LegacyRewrite must never be nil. +type LegacyRewrite struct { + // Domain is the domain pattern for which this rewrite should work. Domain string `yaml:"domain"` // Answer is the IP address, canonical name, or one of the special @@ -24,77 +29,96 @@ type RewriteEntry struct { Answer string `yaml:"answer"` // IP is the IP address that should be used in the response if Type is - // A or AAAA. + // dns.TypeA or dns.TypeAAAA. IP net.IP `yaml:"-"` // Type is the DNS record type: A, AAAA, or CNAME. Type uint16 `yaml:"-"` } -// equal returns true if the entry is considered equal to the other. -func (e *RewriteEntry) equal(other RewriteEntry) (ok bool) { - return e.Domain == other.Domain && e.Answer == other.Answer +// clone returns a deep clone of rw. +func (rw *LegacyRewrite) clone() (cloneRW *LegacyRewrite) { + return &LegacyRewrite{ + Domain: rw.Domain, + Answer: rw.Answer, + IP: netutil.CloneIP(rw.IP), + Type: rw.Type, + } } -// matchesQType returns true if the entry matched qtype. -func (e *RewriteEntry) matchesQType(qtype uint16) (ok bool) { +// equal returns true if the rw is equal to the other. +func (rw *LegacyRewrite) equal(other *LegacyRewrite) (ok bool) { + return rw.Domain == other.Domain && rw.Answer == other.Answer +} + +// matchesQType returns true if the entry matches the question type qt. +func (rw *LegacyRewrite) matchesQType(qt uint16) (ok bool) { // Add CNAMEs, since they match for all types requests. - if e.Type == dns.TypeCNAME { + if rw.Type == dns.TypeCNAME { return true } // Reject types other than A and AAAA. - if qtype != dns.TypeA && qtype != dns.TypeAAAA { + if qt != dns.TypeA && qt != dns.TypeAAAA { return false } // If the types match or the entry is set to allow only the other type, // include them. - return e.Type == qtype || e.IP == nil + return rw.Type == qt || rw.IP == nil } // normalize makes sure that the a new or decoded entry is normalized with // regards to domain name case, IP length, and so on. -func (e *RewriteEntry) normalize() { - // TODO(a.garipov): Write a case-agnostic version of strings.HasSuffix - // and use it in matchDomainWildcard instead of using strings.ToLower +// +// If rw is nil, it returns an errors. +func (rw *LegacyRewrite) normalize() (err error) { + if rw == nil { + return errors.Error("nil rewrite entry") + } + + // TODO(a.garipov): Write a case-agnostic version of strings.HasSuffix and + // use it in matchDomainWildcard instead of using strings.ToLower // everywhere. - e.Domain = strings.ToLower(e.Domain) + rw.Domain = strings.ToLower(rw.Domain) - switch e.Answer { + switch rw.Answer { case "AAAA": - e.IP = nil - e.Type = dns.TypeAAAA + rw.IP = nil + rw.Type = dns.TypeAAAA - return + return nil case "A": - e.IP = nil - e.Type = dns.TypeA + rw.IP = nil + rw.Type = dns.TypeA - return + return nil default: // Go on. } - ip := net.ParseIP(e.Answer) + ip := net.ParseIP(rw.Answer) if ip == nil { - e.Type = dns.TypeCNAME + rw.Type = dns.TypeCNAME - return + return nil } ip4 := ip.To4() if ip4 != nil { - e.IP = ip4 - e.Type = dns.TypeA + rw.IP = ip4 + rw.Type = dns.TypeA } else { - e.IP = ip - e.Type = dns.TypeAAAA + rw.IP = ip + rw.Type = dns.TypeAAAA } + + return nil } -func isWildcard(host string) bool { - return len(host) > 1 && host[0] == '*' && host[1] == '.' +// isWildcard returns true if pat is a wildcard domain pattern. +func isWildcard(pat string) bool { + return len(pat) > 1 && pat[0] == '*' && pat[1] == '.' } // matchDomainWildcard returns true if host matches the wildcard pattern. @@ -110,16 +134,16 @@ func matchDomainWildcard(host, wildcard string) (ok bool) { // wildcard > exact // lower level wildcard > higher level wildcard // -type rewritesSorted []RewriteEntry +type rewritesSorted []*LegacyRewrite // Len implements the sort.Interface interface for legacyRewritesSorted. -func (a rewritesSorted) Len() int { return len(a) } +func (a rewritesSorted) Len() (l int) { return len(a) } // Swap implements the sort.Interface interface for legacyRewritesSorted. func (a rewritesSorted) Swap(i, j int) { a[i], a[j] = a[j], a[i] } // Less implements the sort.Interface interface for legacyRewritesSorted. -func (a rewritesSorted) Less(i, j int) bool { +func (a rewritesSorted) Less(i, j int) (less bool) { if a[i].Type == dns.TypeCNAME && a[j].Type != dns.TypeCNAME { return true } else if a[i].Type != dns.TypeCNAME && a[j].Type == dns.TypeCNAME { @@ -136,14 +160,20 @@ func (a rewritesSorted) Less(i, j int) bool { } } - // both are wildcards + // Both are wildcards. return len(a[i].Domain) > len(a[j].Domain) } -func (d *DNSFilter) prepareRewrites() { - for i := range d.Rewrites { - d.Rewrites[i].normalize() +// prepareRewrites normalizes and validates all legacy DNS rewrites. +func (d *DNSFilter) prepareRewrites() (err error) { + for i, r := range d.Rewrites { + err = r.normalize() + if err != nil { + return fmt.Errorf("at index %d: %w", i, err) + } } + + return nil } // findRewrites returns the list of matched rewrite entries. If rewrites are @@ -154,10 +184,10 @@ func (d *DNSFilter) prepareRewrites() { // host is matched exactly, wildcard entries aren't returned. If the host // matched by wildcards, return the most specific for the question type. func findRewrites( - entries []RewriteEntry, + entries []*LegacyRewrite, host string, qtype uint16, -) (rewrites []RewriteEntry, matched bool) { +) (rewrites []*LegacyRewrite, matched bool) { for _, e := range entries { if e.Domain != host && !matchDomainWildcard(host, e.Domain) { continue @@ -224,23 +254,32 @@ func (d *DNSFilter) handleRewriteList(w http.ResponseWriter, r *http.Request) { } func (d *DNSFilter) handleRewriteAdd(w http.ResponseWriter, r *http.Request) { - jsent := rewriteEntryJSON{} - err := json.NewDecoder(r.Body).Decode(&jsent) + rwJSON := rewriteEntryJSON{} + err := json.NewDecoder(r.Body).Decode(&rwJSON) if err != nil { aghhttp.Error(r, w, http.StatusBadRequest, "json.Decode: %s", err) return } - ent := RewriteEntry{ - Domain: jsent.Domain, - Answer: jsent.Answer, + rw := &LegacyRewrite{ + Domain: rwJSON.Domain, + Answer: rwJSON.Answer, } - ent.normalize() + + err = rw.normalize() + if err != nil { + // Shouldn't happen currently, since normalize only returns a non-nil + // error when a rewrite is nil, but be change-proof. + aghhttp.Error(r, w, http.StatusBadRequest, "normalizing: %s", err) + + return + } + d.confLock.Lock() - d.Config.Rewrites = append(d.Config.Rewrites, ent) + d.Config.Rewrites = append(d.Config.Rewrites, rw) d.confLock.Unlock() - log.Debug("rewrite: added element: %s -> %s [%d]", ent.Domain, ent.Answer, len(d.Config.Rewrites)) + log.Debug("rewrite: added element: %s -> %s [%d]", rw.Domain, rw.Answer, len(d.Config.Rewrites)) d.Config.ConfigModified() } @@ -254,11 +293,12 @@ func (d *DNSFilter) handleRewriteDelete(w http.ResponseWriter, r *http.Request) return } - entDel := RewriteEntry{ + entDel := &LegacyRewrite{ Domain: jsent.Domain, Answer: jsent.Answer, } - arr := []RewriteEntry{} + arr := []*LegacyRewrite{} + d.confLock.Lock() for _, ent := range d.Config.Rewrites { if ent.equal(entDel) { diff --git a/internal/filtering/rewrites_test.go b/internal/filtering/rewrites_test.go index 549530c6..5c3de110 100644 --- a/internal/filtering/rewrites_test.go +++ b/internal/filtering/rewrites_test.go @@ -15,7 +15,7 @@ func TestRewrites(t *testing.T) { d := newForTest(t, nil, nil) t.Cleanup(d.Close) - d.Rewrites = []RewriteEntry{{ + d.Rewrites = []*LegacyRewrite{{ // This one and below are about CNAME, A and AAAA. Domain: "somecname", Answer: "somehost.com", @@ -66,8 +66,12 @@ func TestRewrites(t *testing.T) { }, { Domain: "BIGHOST.COM", Answer: "1.2.3.7", + }, { + Domain: "*.issue4016.com", + Answer: "sub.issue4016.com", }} - d.prepareRewrites() + + require.NoError(t, d.prepareRewrites()) testCases := []struct { name string @@ -153,6 +157,20 @@ func TestRewrites(t *testing.T) { wantIPs: nil, wantReason: Rewritten, dtyp: dns.TypeHTTPS, + }, { + name: "issue4016", + host: "www.issue4016.com", + wantCName: "sub.issue4016.com", + wantIPs: nil, + wantReason: Rewritten, + dtyp: dns.TypeA, + }, { + name: "issue4016_self", + host: "sub.issue4016.com", + wantCName: "", + wantIPs: nil, + wantReason: NotFilteredNotFound, + dtyp: dns.TypeA, }} for _, tc := range testCases { @@ -173,7 +191,7 @@ func TestRewritesLevels(t *testing.T) { d := newForTest(t, nil, nil) t.Cleanup(d.Close) // Exact host, wildcard L2, wildcard L3. - d.Rewrites = []RewriteEntry{{ + d.Rewrites = []*LegacyRewrite{{ Domain: "host.com", Answer: "1.1.1.1", Type: dns.TypeA, @@ -186,7 +204,8 @@ func TestRewritesLevels(t *testing.T) { Answer: "3.3.3.3", Type: dns.TypeA, }} - d.prepareRewrites() + + require.NoError(t, d.prepareRewrites()) testCases := []struct { name string @@ -219,7 +238,7 @@ func TestRewritesExceptionCNAME(t *testing.T) { d := newForTest(t, nil, nil) t.Cleanup(d.Close) // Wildcard and exception for a sub-domain. - d.Rewrites = []RewriteEntry{{ + d.Rewrites = []*LegacyRewrite{{ Domain: "*.host.com", Answer: "2.2.2.2", }, { @@ -229,7 +248,8 @@ func TestRewritesExceptionCNAME(t *testing.T) { Domain: "*.sub.host.com", Answer: "*.sub.host.com", }} - d.prepareRewrites() + + require.NoError(t, d.prepareRewrites()) testCases := []struct { name string @@ -253,7 +273,7 @@ func TestRewritesExceptionCNAME(t *testing.T) { t.Run(tc.name, func(t *testing.T) { r := d.processRewrites(tc.host, dns.TypeA) if tc.want == nil { - assert.Equal(t, NotFilteredNotFound, r.Reason) + assert.Equal(t, NotFilteredNotFound, r.Reason, "got %s", r.Reason) return } @@ -269,7 +289,7 @@ func TestRewritesExceptionIP(t *testing.T) { d := newForTest(t, nil, nil) t.Cleanup(d.Close) // Exception for AAAA record. - d.Rewrites = []RewriteEntry{{ + d.Rewrites = []*LegacyRewrite{{ Domain: "host.com", Answer: "1.2.3.4", Type: dns.TypeA, @@ -290,7 +310,8 @@ func TestRewritesExceptionIP(t *testing.T) { Answer: "A", Type: dns.TypeA, }} - d.prepareRewrites() + + require.NoError(t, d.prepareRewrites()) testCases := []struct { name string diff --git a/internal/home/auth.go b/internal/home/auth.go index 58058519..ca708f4a 100644 --- a/internal/home/auth.go +++ b/internal/home/auth.go @@ -424,7 +424,7 @@ func handleLogin(w http.ResponseWriter, r *http.Request) { } var remoteAddr string - // realIP cannot be used here without taking TrustedProxies into accound due + // realIP cannot be used here without taking TrustedProxies into account due // to security issues. // // See https://github.com/AdguardTeam/AdGuardHome/issues/2799. @@ -528,7 +528,7 @@ func optionalAuthThird(w http.ResponseWriter, r *http.Request) (authFirst bool) cookie, err := r.Cookie(sessionCookieName) if glProcessCookie(r) { - log.Debug("auth: authentification was handled by GL-Inet submodule") + log.Debug("auth: authentication was handled by GL-Inet submodule") ok = true } else if err == nil { r := Context.auth.checkSession(cookie.Value) diff --git a/internal/home/clients.go b/internal/home/clients.go index 7a478679..5643f6b0 100644 --- a/internal/home/clients.go +++ b/internal/home/clients.go @@ -96,7 +96,7 @@ type clientsContainer struct { dnsServer *dnsforward.Server // etcHosts contains list of rewrite rules taken from the operating system's - // hosts databse. + // hosts database. etcHosts *aghnet.HostsContainer testing bool // if TRUE, this object is used for internal tests @@ -175,7 +175,7 @@ type clientObject struct { UseGlobalBlockedServices bool `yaml:"use_global_blocked_services"` } -// addFromConfig initializes the clients containter with objects from the +// addFromConfig initializes the clients container with objects from the // configuration file. func (clients *clientsContainer) addFromConfig(objects []*clientObject) { for _, o := range objects { diff --git a/internal/home/config.go b/internal/home/config.go index e5e1b14b..55d884c8 100644 --- a/internal/home/config.go +++ b/internal/home/config.go @@ -164,7 +164,7 @@ type tlsConfigSettings struct { // config is the global configuration structure. // -// TODO(a.garipov, e.burkov): This global is afwul and must be removed. +// TODO(a.garipov, e.burkov): This global is awful and must be removed. var config = &configuration{ BindPort: 3000, BetaBindPort: 0, diff --git a/internal/home/control.go b/internal/home/control.go index df21e310..8234e00e 100644 --- a/internal/home/control.go +++ b/internal/home/control.go @@ -37,7 +37,7 @@ func appendDNSAddrs(dst []string, addrs ...net.IP) (res []string) { // appendDNSAddrsWithIfaces formats and appends all DNS addresses from src to // dst. It also adds the IP addresses of all network interfaces if src contains -// an unspecified IP addresss. +// an unspecified IP address. func appendDNSAddrsWithIfaces(dst []string, src []net.IP) (res []string, err error) { ifacesAdded := false for _, h := range src { diff --git a/internal/querylog/querylog.go b/internal/querylog/querylog.go index f3de2aaf..18b52938 100644 --- a/internal/querylog/querylog.go +++ b/internal/querylog/querylog.go @@ -69,7 +69,7 @@ type Config struct { // addresses. AnonymizeClientIP bool - // Anonymizer proccesses the IP addresses to anonymize those if needed. + // Anonymizer processes the IP addresses to anonymize those if needed. Anonymizer *aghnet.IPMut } diff --git a/internal/querylog/searchcriterion.go b/internal/querylog/searchcriterion.go index 6517c936..0595fd6e 100644 --- a/internal/querylog/searchcriterion.go +++ b/internal/querylog/searchcriterion.go @@ -85,7 +85,7 @@ func ctDomainOrClientCaseNonStrict( // quickMatch quickly checks if the line matches the given search criterion. // It returns false if the like doesn't match. This method is only here for -// optimisation purposes. +// optimization purposes. func (c *searchCriterion) quickMatch(line string, findClient quickMatchClientFunc) (ok bool) { switch c.criterionType { case ctTerm: diff --git a/internal/querylog/searchparams.go b/internal/querylog/searchparams.go index eee9ec7a..f18ff561 100644 --- a/internal/querylog/searchparams.go +++ b/internal/querylog/searchparams.go @@ -32,7 +32,7 @@ type quickMatchClientFunc = func(clientID, ip string) (c *Client) // quickMatch quickly checks if the line matches the given search parameters. // It returns false if the line doesn't match. This method is only here for -// optimisation purposes. +// optimization purposes. func (s *searchParams) quickMatch(line string, findClient quickMatchClientFunc) (ok bool) { for _, c := range s.searchCriteria { if !c.quickMatch(line, findClient) { From 2ed1f939b59591335447d8b445c9d3832c772f09 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Mon, 27 Dec 2021 20:54:00 +0300 Subject: [PATCH 073/135] Pull request: aghnet: fix ipset init errors Updates #4027. Squashed commit of the following: commit 9ac0cc27ca94e630cc321c90b60b271499af4d9b Author: Ainar Garipov Date: Mon Dec 27 20:26:22 2021 +0300 aghnet: fix ipset init errors --- CHANGELOG.md | 2 ++ internal/aghnet/ipset.go | 7 ++++++- internal/aghnet/ipset_linux.go | 25 ++++++++++++++++++++----- internal/dnsforward/ipset.go | 15 +++++++-------- 4 files changed, 35 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4893f839..3c563ad2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ and this project adheres to ### Fixed +- `ipset` initialization bugs ([#4027]). - Legacy DNS rewrites from a wildcard pattern to a subdomain ([#4016]). - Service not being stopped before running the `uninstall` service action ([#3868]). @@ -46,6 +47,7 @@ and this project adheres to [#3987]: https://github.com/AdguardTeam/AdGuardHome/issues/3987 [#4008]: https://github.com/AdguardTeam/AdGuardHome/issues/4008 [#4016]: https://github.com/AdguardTeam/AdGuardHome/issues/4016 +[#4027]: https://github.com/AdguardTeam/AdGuardHome/issues/4027 diff --git a/internal/aghnet/ipset.go b/internal/aghnet/ipset.go index 422d4b4f..88a3f2b7 100644 --- a/internal/aghnet/ipset.go +++ b/internal/aghnet/ipset.go @@ -20,7 +20,12 @@ type IpsetManager interface { // // DOMAIN[,DOMAIN].../IPSET_NAME[,IPSET_NAME]... // -// The error is of type *aghos.UnsupportedError if the OS is not supported. +// If ipsetConf is empty, msg and err are nil. The error is of type +// *aghos.UnsupportedError if the OS is not supported. func NewIpsetManager(ipsetConf []string) (mgr IpsetManager, err error) { + if len(ipsetConf) == 0 { + return nil, nil + } + return newIpsetMgr(ipsetConf) } diff --git a/internal/aghnet/ipset_linux.go b/internal/aghnet/ipset_linux.go index fa33d2a8..57248b41 100644 --- a/internal/aghnet/ipset_linux.go +++ b/internal/aghnet/ipset_linux.go @@ -14,6 +14,7 @@ import ( "github.com/digineo/go-ipset/v2" "github.com/mdlayher/netlink" "github.com/ti-mo/netfilter" + "golang.org/x/sys/unix" ) // How to test on a real Linux machine: @@ -42,11 +43,17 @@ import ( // newIpsetMgr returns a new Linux ipset manager. func newIpsetMgr(ipsetConf []string) (set IpsetManager, err error) { - dial := func(pf netfilter.ProtoFamily, conf *netlink.Config) (conn ipsetConn, err error) { - return ipset.Dial(pf, conf) + return newIpsetMgrWithDialer(ipsetConf, defaultDial) +} + +// defaultDial is the default netfilter dialing function. +func defaultDial(pf netfilter.ProtoFamily, conf *netlink.Config) (conn ipsetConn, err error) { + conn, err = ipset.Dial(pf, conf) + if err != nil { + return nil, err } - return newIpsetMgrWithDialer(ipsetConf, dial) + return conn, nil } // ipsetConn is the ipset conn interface. @@ -103,8 +110,8 @@ func (m *ipsetMgr) dialNetfilter(conf *netlink.Config) (err error) { // The kernel API does not actually require two sockets but package // github.com/digineo/go-ipset does. // - // TODO(a.garipov): Perhaps we can ditch package ipset altogether and - // just use packages netfilter and netlink. + // TODO(a.garipov): Perhaps we can ditch package ipset altogether and just + // use packages netfilter and netlink. m.ipv4Conn, err = m.dial(netfilter.ProtoIPv4, conf) if err != nil { return fmt.Errorf("dialing v4: %w", err) @@ -214,6 +221,14 @@ func newIpsetMgrWithDialer(ipsetConf []string, dial ipsetDialer) (mgr IpsetManag err = m.dialNetfilter(&netlink.Config{}) if err != nil { + if errors.Is(err, unix.EPROTONOSUPPORT) { + // The implementation doesn't support this protocol version. Just + // issue a warning. + log.Info("ipset: dialing netfilter: warning: %s", err) + + return nil, nil + } + return nil, fmt.Errorf("dialing netfilter: %w", err) } diff --git a/internal/dnsforward/ipset.go b/internal/dnsforward/ipset.go index 78c2cd6e..1aca3077 100644 --- a/internal/dnsforward/ipset.go +++ b/internal/dnsforward/ipset.go @@ -24,20 +24,19 @@ type ipsetCtx struct { func (c *ipsetCtx) init(ipsetConf []string) (err error) { c.ipsetMgr, err = aghnet.NewIpsetManager(ipsetConf) if errors.Is(err, os.ErrInvalid) || errors.Is(err, os.ErrPermission) { - // ipset cannot currently be initialized if the server was - // installed from Snap or when the user or the binary doesn't - // have the required permissions, or when the kernel doesn't - // support netfilter. + // ipset cannot currently be initialized if the server was installed + // from Snap or when the user or the binary doesn't have the required + // permissions, or when the kernel doesn't support netfilter. // // Log and go on. // - // TODO(a.garipov): The Snap problem can probably be solved if - // we add the netlink-connector interface plug. - log.Info("warning: cannot initialize ipset: %s", err) + // TODO(a.garipov): The Snap problem can probably be solved if we add + // the netlink-connector interface plug. + log.Info("ipset: warning: cannot initialize: %s", err) return nil } else if unsupErr := (&aghos.UnsupportedError{}); errors.As(err, &unsupErr) { - log.Info("warning: %s", err) + log.Info("ipset: warning: %s", err) return nil } else if err != nil { From d2ce06e1ca73bfe43ad97bcf77a7f5b5ffdc50eb Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Tue, 28 Dec 2021 17:00:52 +0300 Subject: [PATCH 074/135] Pull request: all: imp uniq validation err msgs Updates #3975. Squashed commit of the following: commit f8578c2afb1bb5786e7b855a1715e0757bc08510 Author: Ainar Garipov Date: Tue Dec 28 16:39:13 2021 +0300 aghalgo: imp docs commit d9fc625f7c4ede2cf4b0683ad5efd0ddf9b966b1 Author: Ainar Garipov Date: Tue Dec 28 16:21:24 2021 +0300 all: imp uniq validation err msgs --- CHANGELOG.md | 6 +++ internal/aghalgo/aghalgo.go | 75 ++++++++++++++++++++++++++++++++ internal/dnsforward/access.go | 68 +++++++++++------------------ internal/home/config.go | 24 +++++++--- internal/home/controlinstall.go | 18 +++++--- internal/home/home.go | 15 ++++--- internal/home/portsmap.go | 63 --------------------------- internal/home/service.go | 2 +- internal/home/service_openbsd.go | 2 +- internal/home/tls.go | 21 ++++++--- 10 files changed, 166 insertions(+), 128 deletions(-) create mode 100644 internal/aghalgo/aghalgo.go delete mode 100644 internal/home/portsmap.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c563ad2..e51a8f40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,11 @@ and this project adheres to - `windows/arm64` support ([#3057]). +### Changed + +- The validation error message for duplicated allow- and blocklists in DNS + settings now shows the duplicated elements ([#3975]). + ### Deprecated +- Go 1.17 support. v0.109.0 will require at least Go 1.18 to build. + +### Removed + +- Go 1.16 support. + +[#3057]: https://github.com/AdguardTeam/AdGuardHome/issues/3057 + + + + + + + +## [v0.107.1] - 2021-12-29 + ### Changed - The validation error message for duplicated allow- and blocklists in DNS settings now shows the duplicated elements ([#3975]). -### Deprecated - - -- Go 1.17 support. v0.109.0 will require at least Go 1.18 to build. - ### Fixed - `ipset` initialization bugs ([#4027]). @@ -42,15 +58,12 @@ and this project adheres to - Legacy DNS rewrites responding from upstream when a request other than `A` or `AAAA` is received ([#4008]). - Panic on port availability check during installation ([#3987]). +- Incorrect application of rules from the OS's hosts files ([#3998]). -### Removed - -- Go 1.16 support. - -[#3057]: https://github.com/AdguardTeam/AdGuardHome/issues/3057 [#3868]: https://github.com/AdguardTeam/AdGuardHome/issues/3868 [#3975]: https://github.com/AdguardTeam/AdGuardHome/issues/3975 [#3987]: https://github.com/AdguardTeam/AdGuardHome/issues/3987 +[#3998]: https://github.com/AdguardTeam/AdGuardHome/issues/3998 [#4008]: https://github.com/AdguardTeam/AdGuardHome/issues/4008 [#4016]: https://github.com/AdguardTeam/AdGuardHome/issues/4016 [#4027]: https://github.com/AdguardTeam/AdGuardHome/issues/4027 @@ -657,11 +670,12 @@ In this release, the schema version has changed from 10 to 12. -[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.0...HEAD +[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.1...HEAD +[v0.107.1]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.0...v0.107.1 [v0.107.0]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.3...v0.107.0 [v0.106.3]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.2...v0.106.3 [v0.106.2]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.1...v0.106.2 diff --git a/bamboo-specs/release.yaml b/bamboo-specs/release.yaml index c180e5fb..754bfa9d 100644 --- a/bamboo-specs/release.yaml +++ b/bamboo-specs/release.yaml @@ -270,6 +270,11 @@ # release-vX.Y.Z branches are the branches from which the actual final release # is built. - '^release-v[0-9]+\.[0-9]+\.[0-9]+': + # Disable integration branches for release branches. + 'branch-config': + 'integration': + 'push-on-success': false + 'merge-from': 'beta-v0.107' # Build final releases on release branches manually. 'triggers': [] # Set the default release channel on the final branch to release, as these From a0bb5ce8a49b60055aefee2b8f2b849106ba8194 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Wed, 29 Dec 2021 22:09:46 +0300 Subject: [PATCH 078/135] Pull request: all: upd dnsproxy Updates #4042. Squashed commit of the following: commit 7531b974a6142fafee825ce9ca2ea202619b95af Author: Ainar Garipov Date: Wed Dec 29 22:01:54 2021 +0300 all: upd dnsproxy --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index c082bfff..8af0d2ca 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.40.2 + github.com/AdguardTeam/dnsproxy v0.40.3 github.com/AdguardTeam/golibs v0.10.3 github.com/AdguardTeam/urlfilter v0.15.1 github.com/NYTimes/gziphandler v1.1.1 diff --git a/go.sum b/go.sum index 53d958d7..19e7dcc5 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.40.2 h1:GG4StH+d4rB7YW3d20sdQjJG8URUeaIQicnEAsYJY7w= -github.com/AdguardTeam/dnsproxy v0.40.2/go.mod h1:PZ9l22h3Er+5mxFQB7oHZMTvx+aa9R6LbzA/ikXQlS0= +github.com/AdguardTeam/dnsproxy v0.40.3 h1:rdQBp3LMmOdD4EpRtnutfP4zwqNA/Q5TyYNNDyjSeQY= +github.com/AdguardTeam/dnsproxy v0.40.3/go.mod h1:PZ9l22h3Er+5mxFQB7oHZMTvx+aa9R6LbzA/ikXQlS0= 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.9.2/go.mod h1:fCAMwPBJ8S7YMYbTWvYS+eeTLblP5E04IDtNAo7y7IY= From e9c59b098e1c432b7612bedae55a26feb047e23a Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Thu, 30 Dec 2021 13:36:04 +0300 Subject: [PATCH 079/135] Pull request: all: upd chlog Merge in DNS/adguard-home from upd-chlog to master Squashed commit of the following: commit 737525aa065bff7b1ec99876447bbc2f961a4c4d Author: Ainar Garipov Date: Wed Dec 29 23:23:52 2021 +0300 all: upd chlog --- CHANGELOG.md | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 784efea0..b53e9f14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ and this project adheres to ## [Unreleased] ### Added @@ -36,11 +36,21 @@ TODO(a.garipov): Remove this deprecation, if v0.108.0 is released before the Go +## [v0.107.2] - 2021-12-29 + +### Fixed + +- Infinite loops when TCP connections time out ([#4042]). + +[#4042]: https://github.com/AdguardTeam/AdGuardHome/issues/4042 + + + ## [v0.107.1] - 2021-12-29 ### Changed @@ -670,11 +680,12 @@ In this release, the schema version has changed from 10 to 12. -[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.1...HEAD +[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.2...HEAD +[v0.107.2]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.1...v0.107.2 [v0.107.1]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.0...v0.107.1 [v0.107.0]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.3...v0.107.0 [v0.106.3]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.2...v0.106.3 From 34c95f99f86df9dd8c0dcead98424add0523383f Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Tue, 11 Jan 2022 21:33:14 +0300 Subject: [PATCH 080/135] Pull request: 4046 darwin service message Merge in DNS/adguard-home from 4046-log-dir to master Closes #4046. Squashed commit of the following: commit 05140550b14f477f52487c575f56428ce9e6fa10 Author: Eugene Burkov Date: Wed Jan 5 17:54:11 2022 +0500 all: add macOS service msg --- internal/home/home.go | 12 ++++++------ internal/home/service.go | 6 ++++++ scripts/install.sh | 26 +++----------------------- 3 files changed, 15 insertions(+), 29 deletions(-) diff --git a/internal/home/home.go b/internal/home/home.go index 853940e2..05d8c3fe 100644 --- a/internal/home/home.go +++ b/internal/home/home.go @@ -393,9 +393,9 @@ func run(args options, clientBuildFS fs.FS) { // Go memory hacks memoryUsage(args) - // print the first message after logger is configured + // Print the first message after logger is configured. log.Println(version.Full()) - log.Debug("Current working directory is %s", Context.workDir) + log.Debug("current working directory is %s", Context.workDir) if args.runningAsService { log.Info("AdGuard Home is running as a service") } @@ -631,13 +631,13 @@ func configureLogger(args options) { log.SetLevel(log.DEBUG) } - // Make sure that we see the microseconds in logs, as networking stuff - // can happen pretty quickly. + // Make sure that we see the microseconds in logs, as networking stuff can + // happen pretty quickly. log.SetFlags(log.LstdFlags | log.Lmicroseconds) if args.runningAsService && ls.LogFile == "" && runtime.GOOS == "windows" { - // When running as a Windows service, use eventlog by default if nothing else is configured - // Otherwise, we'll simply loose the log output + // When running as a Windows service, use eventlog by default if nothing + // else is configured. Otherwise, we'll simply lose the log output. ls.LogFile = configSyslog } diff --git a/internal/home/service.go b/internal/home/service.go index fc34fd67..e5d0ba39 100644 --- a/internal/home/service.go +++ b/internal/home/service.go @@ -82,6 +82,12 @@ func svcStatus(s service.Service) (status service.Status, err error) { // On OpenWrt, the service utility may not exist. We use our service script // directly in this case. func svcAction(s service.Service, action string) (err error) { + if runtime.GOOS == "darwin" && + action == "start" && + !strings.HasPrefix(Context.workDir, "/Applications/") { + log.Info("warning: service must be started from within the /Applications directory") + } + err = service.Control(s, action) if err != nil && service.Platform() == "unix-systemv" && (action == "start" || action == "stop" || action == "restart") { diff --git a/scripts/install.sh b/scripts/install.sh index 078dc34b..af80adfe 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -272,32 +272,12 @@ fix_darwin() { return 0 fi - if [ "$cpu" = 'arm64' ] - then - case "$channel" - in - ('beta'|'development'|'edge') - # Everything is fine, we have Apple Silicon support on - # these channels. - ;; - ('release') - cpu='amd64' - log "use $cpu build on Mac M1 until the native ARM support is added." - ;; - (*) - # Generally shouldn't happen, since the release channel - # has already been validated. - error_exit "invalid channel '$channel'" - ;; - esac - fi - # Set the package extension. pkg_ext='zip' - # It is important to install AdGuard Home into the /Applications - # directory on macOS. Otherwise, it may not grant enough privileges to - # the AdGuard Home. + # It is important to install AdGuard Home into the /Applications directory + # on macOS. Otherwise, it may grant not enough privileges to the AdGuard + # Home. out_dir='/Applications' } From 1458600c37dba16003518685729c7212598fe8ad Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Wed, 12 Jan 2022 12:14:59 +0300 Subject: [PATCH 081/135] Pull request: 4079 fix hosts container aliases Merge in DNS/adguard-home from 4079-hosts-again to master Updates #4079. Squashed commit of the following: commit 6aa8cbf32e8e47ba46bf5fba7681a10b68b4bc01 Merge: 19dba371 34c95f99 Author: Eugene Burkov Date: Wed Jan 12 14:05:30 2022 +0500 Merge branch 'master' into 4079-hosts-again commit 19dba371cc30ab8b75b0116833f4ecf0ef0f182f Author: Eugene Burkov Date: Wed Jan 12 14:05:20 2022 +0500 aghnet: imp docs commit 9f341eb8ee4ba8468240bc3eeeb4951a3f7f5e6d Author: Eugene Burkov Date: Mon Jan 10 18:44:17 2022 +0500 aghnet: fix races commit fd66191c7637c8584711e5bb8186494327ce0f87 Author: Eugene Burkov Date: Thu Jan 6 17:21:14 2022 +0500 aghnet: fix hosts container aliases --- CHANGELOG.md | 6 + internal/aghnet/hostscontainer.go | 195 ++++++++++++------ internal/aghnet/hostscontainer_test.go | 271 +++++++++++++++---------- internal/aghnet/testdata/etc_hosts | 10 + internal/home/clients.go | 9 +- 5 files changed, 314 insertions(+), 177 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b53e9f14..fdb58899 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,11 @@ TODO(a.garipov): Remove this deprecation, if v0.108.0 is released before the Go --> - Go 1.17 support. v0.109.0 will require at least Go 1.18 to build. +### Fixed + +- Omitted aliases of hosts specified by another line within the OS's hosts file + ([#4079]). + ### Removed - Go 1.16 support. @@ -77,6 +82,7 @@ TODO(a.garipov): Remove this deprecation, if v0.108.0 is released before the Go [#4008]: https://github.com/AdguardTeam/AdGuardHome/issues/4008 [#4016]: https://github.com/AdguardTeam/AdGuardHome/issues/4016 [#4027]: https://github.com/AdguardTeam/AdGuardHome/issues/4027 +[#4079]: https://github.com/AdguardTeam/AdGuardHome/issues/4079 diff --git a/internal/aghnet/hostscontainer.go b/internal/aghnet/hostscontainer.go index 436464e2..85379fed 100644 --- a/internal/aghnet/hostscontainer.go +++ b/internal/aghnet/hostscontainer.go @@ -72,7 +72,11 @@ func (rm *requestMatcher) MatchRequest( } // Translate returns the source hosts-syntax rule for the generated dnsrewrite -// rule or an empty string if the last doesn't exist. +// rule or an empty string if the last doesn't exist. The returned rules are in +// a processed format like: +// +// ip host1 host2 ... +// func (rm *requestMatcher) Translate(rule string) (hostRule string) { rm.stateLock.RLock() defer rm.stateLock.RUnlock() @@ -179,7 +183,7 @@ func NewHostsContainer( return nil, fmt.Errorf("adding path: %w", err) } - log.Debug("%s: file %q expected to exist but doesn't", hostsContainerPref, p) + log.Debug("%s: %s is expected to exist but doesn't", hostsContainerPref, p) } } @@ -199,7 +203,7 @@ func (hc *HostsContainer) Close() (err error) { } // Upd returns the channel into which the updates are sent. The receivable -// map's values are guaranteed to be of type of *stringutil.Set. +// map's values are guaranteed to be of type of *aghnet.Hosts. func (hc *HostsContainer) Upd() (updates <-chan *netutil.IPMap) { return hc.updates } @@ -228,8 +232,9 @@ func pathsToPatterns(fsys fs.FS, paths []string) (patterns []string, err error) return patterns, nil } -// handleEvents concurrently handles the events. It closes the update channel -// of HostsContainer when finishes. Used to be called within a goroutine. +// handleEvents concurrently handles the file system events. It closes the +// update channel of HostsContainer when finishes. It's used to be called +// within a separate goroutine. func (hc *HostsContainer) handleEvents() { defer log.OnPanic(fmt.Sprintf("%s: handling events", hostsContainerPref)) @@ -254,17 +259,27 @@ func (hc *HostsContainer) handleEvents() { } } +// ipRules is the pair of generated A/AAAA and PTR rules with related IP. +type ipRules struct { + // rule is the A/AAAA $dnsrewrite rule. + rule string + // rulePtr is the PTR $dnsrewrite rule. + rulePtr string + // ip is the IP address related to the rules. + ip net.IP +} + // hostsParser is a helper type to parse rules from the operating system's hosts // file. It exists for only a single refreshing session. type hostsParser struct { - // rulesBuilder builds the resulting rulesBuilder list content. + // rulesBuilder builds the resulting rules list content. rulesBuilder *strings.Builder - // translations maps generated $dnsrewrite rules to the hosts-translations - // rules. - translations map[string]string + // rules stores the rules for main hosts to generate translations. + rules []ipRules - // cnameSet prevents duplicating cname rules. + // cnameSet prevents duplicating cname rules, e.g. same hostname for + // different IP versions. cnameSet *stringutil.Set // table stores only the unique IP-hostname pairs. It's also sent to the @@ -272,13 +287,16 @@ type hostsParser struct { table *netutil.IPMap } +// newHostsParser creates a new *hostsParser with buffers of size taken from the +// previous parse. func (hc *HostsContainer) newHostsParser() (hp *hostsParser) { + lastLen := hc.last.Len() + return &hostsParser{ rulesBuilder: &strings.Builder{}, - // For A/AAAA and PTRs. - translations: make(map[string]string, hc.last.Len()*2), + rules: make([]ipRules, 0, lastLen), cnameSet: stringutil.NewSet(), - table: netutil.NewIPMap(hc.last.Len()), + table: netutil.NewIPMap(lastLen), } } @@ -286,9 +304,7 @@ func (hc *HostsContainer) newHostsParser() (hp *hostsParser) { // never signs to stop walking and never returns any additional patterns. // // See man hosts(5). -func (hp *hostsParser) parseFile( - r io.Reader, -) (patterns []string, cont bool, err error) { +func (hp *hostsParser) parseFile(r io.Reader) (patterns []string, cont bool, err error) { s := bufio.NewScanner(r) for s.Scan() { ip, hosts := hp.parseLine(s.Text()) @@ -339,62 +355,79 @@ func (hp *hostsParser) parseLine(line string) (ip net.IP, hosts []string) { return ip, hosts } -// Simple types of hosts in hosts database. Zero value isn't used to be able -// quizzaciously emulate nil with 0. -const ( - _ = iota - hostAlias - hostMain -) +// Hosts is used to contain the main host and all it's aliases. +type Hosts struct { + // Aliases contains all the aliases for Main. + Aliases *stringutil.Set + // Main is the host itself. + Main string +} + +// Equal returns true if h equals hh. +func (h *Hosts) Equal(hh *Hosts) (ok bool) { + if h == nil || hh == nil { + return h == hh + } + + return h.Main == hh.Main && h.Aliases.Equal(hh.Aliases) +} // add tries to add the ip-host pair. It returns: // -// hostAlias if the host is not the first one added for the ip. -// hostMain if the host is the first one added for the ip. -// 0 if the ip-host pair has already been added. +// main host if the host is not the first one added for the ip. +// host itself if the host is the first one added for the ip. +// "" if the ip-host pair has already been added. // -func (hp *hostsParser) add(ip net.IP, host string) (hostType int) { +func (hp *hostsParser) add(ip net.IP, host string) (mainHost string) { v, ok := hp.table.Get(ip) - switch hosts, _ := v.(*stringutil.Set); { - case ok && hosts.Has(host): - return 0 - case hosts == nil: - hosts = stringutil.NewSet(host) - hp.table.Set(ip, hosts) + switch h, _ := v.(*Hosts); { + case !ok: + // This is the first host for the ip. + hp.table.Set(ip, &Hosts{Main: host}) - return hostMain + return host + case h.Main == host: + // This is a duplicate. Go on. + case h.Aliases == nil: + // This is the first alias. + h.Aliases = stringutil.NewSet(host) + + return h.Main + case !h.Aliases.Has(host): + // This is a new alias. + h.Aliases.Add(host) + + return h.Main default: - hosts.Add(host) - - return hostAlias + // This is a duplicate. Go on. } + + return "" } // addPair puts the pair of ip and host to the rules builder if needed. For // each ip the first member of hosts will become the main one. func (hp *hostsParser) addPairs(ip net.IP, hosts []string) { - // Put the rule in a processed format like: - // - // ip host1 host2 ... - // - hostsLine := strings.Join(append([]string{ip.String()}, hosts...), " ") - var mainHost string for _, host := range hosts { - switch hp.add(ip, host) { - case 0: + switch mainHost := hp.add(ip, host); mainHost { + case "": + // This host is a duplicate. continue - case hostMain: - mainHost = host - added, addedPtr := hp.writeMainHostRule(host, ip) - hp.translations[added], hp.translations[addedPtr] = hostsLine, hostsLine - case hostAlias: + case host: + // This host is main. + added, addedPtr := hp.writeMainRule(host, ip) + hp.rules = append(hp.rules, ipRules{ + rule: added, + rulePtr: addedPtr, + ip: ip, + }) + default: + // This host is an alias. pair := fmt.Sprint(host, " ", mainHost) if hp.cnameSet.Has(pair) { continue } - // Since the hostAlias couldn't be returned from add before the - // hostMain the mainHost shouldn't appear empty. - hp.writeAliasHostRule(host, mainHost) + hp.writeAliasRule(host, mainHost) hp.cnameSet.Add(pair) } @@ -402,9 +435,9 @@ func (hp *hostsParser) addPairs(ip net.IP, hosts []string) { } } -// writeAliasHostRule writes the CNAME rule for the alias-host pair into -// internal builders. -func (hp *hostsParser) writeAliasHostRule(alias, host string) { +// writeAliasRule writes the CNAME rule for the alias-host pair into internal +// builders. +func (hp *hostsParser) writeAliasRule(alias, host string) { const ( nl = "\n" sc = ";" @@ -417,9 +450,9 @@ func (hp *hostsParser) writeAliasHostRule(alias, host string) { stringutil.WriteToBuilder(hp.rulesBuilder, rules.MaskPipe, alias, rwSuccess, host, nl) } -// writeMainHostRule writes the actual rule for the qtype and the PTR for the +// writeMainRule writes the actual rule for the qtype and the PTR for the // host-ip pair into internal builders. -func (hp *hostsParser) writeMainHostRule(host string, ip net.IP) (added, addedPtr string) { +func (hp *hostsParser) writeMainRule(host string, ip net.IP) (added, addedPtr string) { arpa, err := netutil.IPToReversedAddr(ip) if err != nil { return @@ -484,12 +517,15 @@ func (hp *hostsParser) equalSet(target *netutil.IPMap) (ok bool) { return false } - hp.table.Range(func(ip net.IP, val interface{}) (cont bool) { - v, hasIP := target.Get(ip) + hp.table.Range(func(ip net.IP, b interface{}) (cont bool) { // ok is set to true if the target doesn't contain ip or if the - // appropriate hosts set isn't equal to the checked one, i.e. the maps - // have at least one discrepancy. - ok = !hasIP || !v.(*stringutil.Set).Equal(val.(*stringutil.Set)) + // appropriate hosts set isn't equal to the checked one, i.e. the main + // hosts differ or the maps have at least one discrepancy. + if a, hasIP := target.Get(ip); !hasIP { + ok = true + } else if hosts, aok := a.(*Hosts); aok { + ok = !hosts.Equal(b.(*Hosts)) + } // Continue only if maps has no discrepancies. return !ok @@ -527,6 +563,35 @@ func (hp *hostsParser) newStrg(id int) (s *filterlist.RuleStorage, err error) { }}) } +// translations generates the map to translate $dnsrewrite rules to +// hosts-syntax ones. +func (hp *hostsParser) translations() (trans map[string]string) { + l := len(hp.rules) + if l == 0 { + return nil + } + + trans = make(map[string]string, l*2) + for _, r := range hp.rules { + v, ok := hp.table.Get(r.ip) + if !ok { + continue + } + + var hosts *Hosts + hosts, ok = v.(*Hosts) + if !ok { + continue + } + + strs := append([]string{r.ip.String(), hosts.Main}, hosts.Aliases.Values()...) + hostsLine := strings.Join(strs, " ") + trans[r.rule], trans[r.rulePtr] = hostsLine, hostsLine + } + + return trans +} + // refresh gets the data from specified files and propagates the updates if // needed. // @@ -540,7 +605,7 @@ func (hc *HostsContainer) refresh() (err error) { } if hp.equalSet(hc.last) { - log.Debug("%s: no updates detected", hostsContainerPref) + log.Debug("%s: no changes detected", hostsContainerPref) return nil } @@ -553,7 +618,7 @@ func (hc *HostsContainer) refresh() (err error) { return fmt.Errorf("initializing rules storage: %w", err) } - hc.resetEng(rulesStrg, hp.translations) + hc.resetEng(rulesStrg, hp.translations()) return nil } diff --git a/internal/aghnet/hostscontainer_test.go b/internal/aghnet/hostscontainer_test.go index e2784908..70f2d00f 100644 --- a/internal/aghnet/hostscontainer_test.go +++ b/internal/aghnet/hostscontainer_test.go @@ -9,6 +9,7 @@ import ( "sync/atomic" "testing" "testing/fstest" + "time" "github.com/AdguardTeam/AdGuardHome/internal/aghtest" "github.com/AdguardTeam/golibs/errors" @@ -129,24 +130,13 @@ func TestNewHostsContainer(t *testing.T) { }) } -func TestHostsContainer_Refresh(t *testing.T) { - knownIP := net.IP{127, 0, 0, 1} +func TestHostsContainer_refresh(t *testing.T) { + // TODO(e.burkov): Test the case with no actual updates. - const knownHost = "localhost" - const knownAlias = "hocallost" + ip := net.IP{127, 0, 0, 1} + ipStr := ip.String() - const dirname = "dir" - const filename1 = "file1" - const filename2 = "file2" - - p1 := path.Join(dirname, filename1) - p2 := path.Join(dirname, filename2) - - testFS := fstest.MapFS{ - p1: &fstest.MapFile{ - Data: []byte(strings.Join([]string{knownIP.String(), knownHost}, sp) + nl), - }, - } + testFS := fstest.MapFS{"dir/file1": &fstest.MapFile{Data: []byte(ipStr + ` hostname` + nl)}} // event is a convenient alias for an empty struct{} to emit test events. type event = struct{} @@ -157,119 +147,117 @@ func TestHostsContainer_Refresh(t *testing.T) { w := &aghtest.FSWatcher{ OnEvents: func() (e <-chan event) { return eventsCh }, OnAdd: func(name string) (err error) { - assert.Equal(t, dirname, name) + assert.Equal(t, "dir", name) return nil }, OnClose: func() (err error) { panic("not implemented") }, } - hc, err := NewHostsContainer(0, testFS, w, dirname) + hc, err := NewHostsContainer(0, testFS, w, "dir") require.NoError(t, err) - checkRefresh := func(t *testing.T, wantHosts *stringutil.Set) { + checkRefresh := func(t *testing.T, wantHosts Hosts) { upd, ok := <-hc.Upd() require.True(t, ok) require.NotNil(t, upd) assert.Equal(t, 1, upd.Len()) - v, ok := upd.Get(knownIP) + v, ok := upd.Get(ip) require.True(t, ok) - var hosts *stringutil.Set - hosts, ok = v.(*stringutil.Set) + var hosts *Hosts + hosts, ok = v.(*Hosts) require.True(t, ok) - assert.True(t, hosts.Equal(wantHosts)) + assert.Equal(t, wantHosts.Main, hosts.Main) + assert.True(t, hosts.Aliases.Equal(wantHosts.Aliases)) } t.Run("initial_refresh", func(t *testing.T) { - checkRefresh(t, stringutil.NewSet(knownHost)) + checkRefresh(t, Hosts{Main: "hostname"}) }) - testFS[p2] = &fstest.MapFile{ - Data: []byte(strings.Join([]string{knownIP.String(), knownAlias}, sp) + nl), - } - eventsCh <- event{} - t.Run("second_refresh", func(t *testing.T) { - checkRefresh(t, stringutil.NewSet(knownHost, knownAlias)) + testFS["dir/file2"] = &fstest.MapFile{Data: []byte(ipStr + ` alias` + nl)} + eventsCh <- event{} + checkRefresh(t, Hosts{Main: "hostname", Aliases: stringutil.NewSet("alias")}) }) - eventsCh <- event{} + t.Run("double_refresh", func(t *testing.T) { + // Make a change once. + testFS["dir/file1"] = &fstest.MapFile{Data: []byte(ipStr + ` alias` + nl)} + eventsCh <- event{} - t.Run("no_changes_refresh", func(t *testing.T) { - assert.Empty(t, hc.Upd()) + // Require the changes are written. + require.Eventually(t, func() bool { + res, ok := hc.MatchRequest(urlfilter.DNSRequest{ + Hostname: "hostname", + DNSType: dns.TypeA, + }) + + return !ok && res.DNSRewrites() == nil + }, 5*time.Second, time.Second/2) + + // Make a change again. + testFS["dir/file2"] = &fstest.MapFile{Data: []byte(ipStr + ` hostname` + nl)} + eventsCh <- event{} + + // Require the changes are written. + require.Eventually(t, func() bool { + res, ok := hc.MatchRequest(urlfilter.DNSRequest{ + Hostname: "hostname", + DNSType: dns.TypeA, + }) + + return !ok && res.DNSRewrites() != nil + }, 5*time.Second, time.Second/2) + + assert.Len(t, hc.Upd(), 1) }) } func TestHostsContainer_PathsToPatterns(t *testing.T) { - const ( - dir0 = "dir" - dir1 = "dir_1" - fn1 = "file_1" - fn2 = "file_2" - fn3 = "file_3" - fn4 = "file_4" - ) - - fp1 := path.Join(dir0, fn1) - fp2 := path.Join(dir0, fn2) - fp3 := path.Join(dir0, dir1, fn3) - gsfs := fstest.MapFS{ - fp1: &fstest.MapFile{Data: []byte{1}}, - fp2: &fstest.MapFile{Data: []byte{2}}, - fp3: &fstest.MapFile{Data: []byte{3}}, + "dir_0/file_1": &fstest.MapFile{Data: []byte{1}}, + "dir_0/file_2": &fstest.MapFile{Data: []byte{2}}, + "dir_0/dir_1/file_3": &fstest.MapFile{Data: []byte{3}}, } testCases := []struct { - name string - wantErr error - want []string - paths []string + name string + paths []string + want []string }{{ - name: "no_paths", - wantErr: nil, - want: nil, - paths: nil, + name: "no_paths", + paths: nil, + want: nil, }, { - name: "single_file", - wantErr: nil, - want: []string{fp1}, - paths: []string{fp1}, + name: "single_file", + paths: []string{"dir_0/file_1"}, + want: []string{"dir_0/file_1"}, }, { - name: "several_files", - wantErr: nil, - want: []string{fp1, fp2}, - paths: []string{fp1, fp2}, + name: "several_files", + paths: []string{"dir_0/file_1", "dir_0/file_2"}, + want: []string{"dir_0/file_1", "dir_0/file_2"}, }, { - name: "whole_dir", - wantErr: nil, - want: []string{path.Join(dir0, "*")}, - paths: []string{dir0}, + name: "whole_dir", + paths: []string{"dir_0"}, + want: []string{"dir_0/*"}, }, { - name: "file_and_dir", - wantErr: nil, - want: []string{fp1, path.Join(dir0, dir1, "*")}, - paths: []string{fp1, path.Join(dir0, dir1)}, + name: "file_and_dir", + paths: []string{"dir_0/file_1", "dir_0/dir_1"}, + want: []string{"dir_0/file_1", "dir_0/dir_1/*"}, }, { - name: "non-existing", - wantErr: nil, - want: nil, - paths: []string{path.Join(dir0, "file_3")}, + name: "non-existing", + paths: []string{path.Join("dir_0", "file_3")}, + want: nil, }} for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { patterns, err := pathsToPatterns(gsfs, tc.paths) - if tc.wantErr != nil { - assert.ErrorIs(t, err, tc.wantErr) - - return - } - require.NoError(t, err) assert.Equal(t, tc.want, patterns) @@ -290,16 +278,74 @@ 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 }, + OnClose: func() (err error) { panic("not implemented") }, + } + + hc, err := NewHostsContainer(0, testdata, &stubWatcher, "etc_hosts") + require.NoError(t, err) + + testCases := []struct { + name string + rule string + wantTrans []string + }{{ + name: "simplehost", + rule: "|simplehost^$dnsrewrite=NOERROR;A;1.0.0.1", + wantTrans: []string{"1.0.0.1", "simplehost"}, + }, { + name: "hello", + rule: "|hello^$dnsrewrite=NOERROR;A;1.0.0.0", + wantTrans: []string{"1.0.0.0", "hello", "hello.world", "hello.world.again"}, + }, { + name: "simplehost_v6", + rule: "|simplehost^$dnsrewrite=NOERROR;AAAA;::1", + wantTrans: []string{"::1", "simplehost"}, + }, { + name: "hello_v6", + rule: "|hello^$dnsrewrite=NOERROR;AAAA;::", + wantTrans: []string{"::", "hello", "hello.world", "hello.world.again"}, + }, { + name: "simplehost_ptr", + rule: "|1.0.0.1.in-addr.arpa^$dnsrewrite=NOERROR;PTR;simplehost.", + wantTrans: []string{"1.0.0.1", "simplehost"}, + }, { + name: "hello_ptr", + rule: "|0.0.0.1.in-addr.arpa^$dnsrewrite=NOERROR;PTR;hello.", + wantTrans: []string{"1.0.0.0", "hello", "hello.world", "hello.world.again"}, + }, { + name: "simplehost_ptr_v6", + rule: "|1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa" + + "^$dnsrewrite=NOERROR;PTR;simplehost.", + wantTrans: []string{"::1", "simplehost"}, + }, { + name: "hello_ptr_v6", + rule: "|0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa" + + "^$dnsrewrite=NOERROR;PTR;hello.", + wantTrans: []string{"::", "hello", "hello.world", "hello.world.again"}, + }} + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + want := stringutil.NewSet(tc.wantTrans...) + got := stringutil.NewSet(strings.Fields(hc.Translate(tc.rule))...) + assert.True(t, want.Equal(got)) + }) + } +} + func TestHostsContainer(t *testing.T) { const listID = 1234 testdata := os.DirFS("./testdata") nRewrites := func(t *testing.T, res *urlfilter.DNSResult, n int) (rws []*rules.DNSRewrite) { - t.Helper() - rewrites := res.DNSRewrites() - assert.Len(t, rewrites, n) + require.Len(t, rewrites, n) for _, rewrite := range rewrites { require.Equal(t, listID, rewrite.FilterListID) @@ -346,6 +392,15 @@ func TestHostsContainer(t *testing.T) { testTail: func(t *testing.T, res *urlfilter.DNSResult) { assert.Equal(t, "hello", nRewrites(t, res, 1)[0].NewCNAME) }, + }, { + name: "other_line_alias", + req: urlfilter.DNSRequest{ + Hostname: "hello.world.again", + DNSType: dns.TypeA, + }, + testTail: func(t *testing.T, res *urlfilter.DNSResult) { + assert.Equal(t, "hello", nRewrites(t, res, 1)[0].NewCNAME) + }, }, { name: "hello_subdomain", req: urlfilter.DNSRequest{ @@ -419,12 +474,8 @@ func TestHostsContainer(t *testing.T) { } func TestUniqueRules_ParseLine(t *testing.T) { - const ( - hostname = "localhost" - alias = "hocallost" - ) - - knownIP := net.IP{127, 0, 0, 1} + ip := net.IP{127, 0, 0, 1} + ipStr := ip.String() testCases := []struct { name string @@ -433,39 +484,39 @@ func TestUniqueRules_ParseLine(t *testing.T) { wantHosts []string }{{ name: "simple", - line: strings.Join([]string{knownIP.String(), hostname}, sp), - wantIP: knownIP, - wantHosts: []string{"localhost"}, + line: ipStr + ` hostname`, + wantIP: ip, + wantHosts: []string{"hostname"}, }, { name: "aliases", - line: strings.Join([]string{knownIP.String(), hostname, alias}, sp), - wantIP: knownIP, - wantHosts: []string{"localhost", "hocallost"}, + line: ipStr + ` hostname alias`, + wantIP: ip, + wantHosts: []string{"hostname", "alias"}, }, { name: "invalid_line", - line: knownIP.String(), + line: ipStr, wantIP: nil, wantHosts: nil, }, { name: "invalid_line_hostname", - line: strings.Join([]string{knownIP.String(), "#" + hostname}, sp), - wantIP: knownIP, + line: ipStr + ` # hostname`, + wantIP: ip, wantHosts: nil, }, { name: "commented_aliases", - line: strings.Join([]string{knownIP.String(), hostname, "#" + alias}, sp), - wantIP: knownIP, - wantHosts: []string{"localhost"}, + line: ipStr + ` hostname # alias`, + wantIP: ip, + wantHosts: []string{"hostname"}, }, { name: "whole_comment", - line: strings.Join([]string{"#", knownIP.String(), hostname}, sp), + line: `# ` + ipStr + ` hostname`, wantIP: nil, wantHosts: nil, }, { name: "partial_comment", - line: strings.Join([]string{knownIP.String(), hostname[:4] + "#" + hostname[4:]}, sp), - wantIP: knownIP, - wantHosts: []string{hostname[:4]}, + line: ipStr + ` host#name`, + wantIP: ip, + wantHosts: []string{"host"}, }, { name: "empty", line: ``, @@ -476,8 +527,8 @@ func TestUniqueRules_ParseLine(t *testing.T) { for _, tc := range testCases { hp := hostsParser{} t.Run(tc.name, func(t *testing.T) { - ip, hosts := hp.parseLine(tc.line) - assert.True(t, tc.wantIP.Equal(ip)) + got, hosts := hp.parseLine(tc.line) + assert.True(t, tc.wantIP.Equal(got)) assert.Equal(t, tc.wantHosts, hosts) }) } diff --git a/internal/aghnet/testdata/etc_hosts b/internal/aghnet/testdata/etc_hosts index 15e07566..afe7011c 100644 --- a/internal/aghnet/testdata/etc_hosts +++ b/internal/aghnet/testdata/etc_hosts @@ -12,9 +12,19 @@ 1.0.0.3 * 1.0.0.4 *.com +# See https://github.com/AdguardTeam/AdGuardHome/issues/4079. +1.0.0.0 hello.world.again + +# Duplicates of a main host and an alias. +1.0.0.1 simplehost +1.0.0.0 hello.world + # Same for IPv6. ::1 simplehost :: hello hello.world ::2 a.whole lot.of aliases for.testing ::3 * ::4 *.com +:: hello.world.again +::1 simplehost +:: hello.world \ No newline at end of file diff --git a/internal/home/clients.go b/internal/home/clients.go index 5643f6b0..94dd41f7 100644 --- a/internal/home/clients.go +++ b/internal/home/clients.go @@ -783,12 +783,17 @@ func (clients *clientsContainer) addFromHostsFile(hosts *netutil.IPMap) { n := 0 hosts.Range(func(ip net.IP, v interface{}) (cont bool) { - names, ok := v.(*stringutil.Set) + hosts, ok := v.(*aghnet.Hosts) if !ok { log.Error("dns: bad type %T in ipToRC for %s", v, ip) + + return true } - names.Range(func(name string) (cont bool) { + if clients.addHostLocked(ip, hosts.Main, ClientSourceHostsFile) { + n++ + } + hosts.Aliases.Range(func(name string) (cont bool) { if clients.addHostLocked(ip, name, ClientSourceHostsFile) { n++ } From 0e4ffd339f8c55fa671a2f5d6fb072b6815bf99a Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Thu, 13 Jan 2022 15:05:44 +0300 Subject: [PATCH 082/135] Pull request: 4074 fix upstream test Merge in DNS/adguard-home from 4074-upstream-test to master Updates #4074. Squashed commit of the following: commit 0de155b1e175a892b259791ff6d6e6f351bcfcf2 Author: Eugene Burkov Date: Wed Jan 12 19:20:01 2022 +0500 dnsforward: fix upstream test --- CHANGELOG.md | 4 +- internal/dnsforward/http.go | 133 ++++++++++++++----------------- internal/dnsforward/http_test.go | 121 ++++++++++++++-------------- openapi/openapi.yaml | 4 +- 4 files changed, 126 insertions(+), 136 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fdb58899..78ea8efd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ TODO(a.garipov): Remove this deprecation, if v0.108.0 is released before the Go ### Fixed +- Poor testing of domain-specific upstream servers ([#4074]). - Omitted aliases of hosts specified by another line within the OS's hosts file ([#4079]). @@ -37,6 +38,8 @@ TODO(a.garipov): Remove this deprecation, if v0.108.0 is released before the Go - Go 1.16 support. [#3057]: https://github.com/AdguardTeam/AdGuardHome/issues/3057 +[#4074]: https://github.com/AdguardTeam/AdGuardHome/issues/4074 +[#4079]: https://github.com/AdguardTeam/AdGuardHome/issues/4079 @@ -82,7 +85,6 @@ TODO(a.garipov): Remove this deprecation, if v0.108.0 is released before the Go [#4008]: https://github.com/AdguardTeam/AdGuardHome/issues/4008 [#4016]: https://github.com/AdguardTeam/AdGuardHome/issues/4016 [#4027]: https://github.com/AdguardTeam/AdGuardHome/issues/4027 -[#4079]: https://github.com/AdguardTeam/AdGuardHome/issues/4079 diff --git a/internal/dnsforward/http.go b/internal/dnsforward/http.go index 42a81946..b0de11b9 100644 --- a/internal/dnsforward/http.go +++ b/internal/dnsforward/http.go @@ -5,7 +5,6 @@ import ( "fmt" "net" "net/http" - "strconv" "strings" "time" @@ -192,22 +191,23 @@ func (req *dnsConfig) checkCacheTTL() bool { func (s *Server) handleSetConfig(w http.ResponseWriter, r *http.Request) { req := dnsConfig{} - dec := json.NewDecoder(r.Body) - if err := dec.Decode(&req); err != nil { + err := json.NewDecoder(r.Body).Decode(&req) + if err != nil { aghhttp.Error(r, w, http.StatusBadRequest, "json Encode: %s", err) return } if req.Upstreams != nil { - if err := ValidateUpstreams(*req.Upstreams); err != nil { + if err = ValidateUpstreams(*req.Upstreams); err != nil { aghhttp.Error(r, w, http.StatusBadRequest, "wrong upstreams specification: %s", err) return } } - if errBoot, err := req.checkBootstrap(); err != nil { + var errBoot string + if errBoot, err = req.checkBootstrap(); err != nil { aghhttp.Error( r, w, @@ -220,19 +220,16 @@ func (s *Server) handleSetConfig(w http.ResponseWriter, r *http.Request) { return } - if !req.checkBlockingMode() { + switch { + case !req.checkBlockingMode(): aghhttp.Error(r, w, http.StatusBadRequest, "blocking_mode: incorrect value") return - } - - if !req.checkUpstreamsMode() { + case !req.checkUpstreamsMode(): aghhttp.Error(r, w, http.StatusBadRequest, "upstream_mode: incorrect value") return - } - - if !req.checkCacheTTL() { + case !req.checkCacheTTL(): aghhttp.Error( r, w, @@ -241,13 +238,15 @@ func (s *Server) handleSetConfig(w http.ResponseWriter, r *http.Request) { ) return + default: + // Go on. } restart := s.setConfig(req) s.conf.ConfigModified() if restart { - if err := s.Reconfigure(nil); err != nil { + if err = s.Reconfigure(nil); err != nil { aghhttp.Error(r, w, http.StatusInternalServerError, "%s", err) } } @@ -387,14 +386,14 @@ func ValidateUpstreams(upstreams []string) (err error) { var defaultUpstreamFound bool for _, u := range upstreams { - var ok bool - ok, err = validateUpstream(u) + var useDefault bool + useDefault, err = validateUpstream(u) if err != nil { return err } if !defaultUpstreamFound { - defaultUpstreamFound = ok + defaultUpstreamFound = useDefault } } @@ -407,50 +406,62 @@ func ValidateUpstreams(upstreams []string) (err error) { var protocols = []string{"tls://", "https://", "tcp://", "sdns://", "quic://"} -func validateUpstream(u string) (bool, error) { +func validateUpstream(u string) (useDefault bool, err error) { // Check if the user tries to specify upstream for domain. - u, useDefault, err := separateUpstream(u) + var isDomainSpec bool + u, isDomainSpec, err = separateUpstream(u) if err != nil { - return useDefault, err + return !isDomainSpec, err } - // The special server address '#' means "use the default servers" - if u == "#" && !useDefault { + // The special server address '#' means that default server must be used. + if useDefault = !isDomainSpec; u == "#" && isDomainSpec { return useDefault, nil } - // Check if the upstream has a valid protocol prefix + // Check if the upstream has a valid protocol prefix. + // + // TODO(e.burkov): Validate the domain name. for _, proto := range protocols { if strings.HasPrefix(u, proto) { return useDefault, nil } } - // Return error if the upstream contains '://' without any valid protocol if strings.Contains(u, "://") { - return useDefault, fmt.Errorf("wrong protocol") + return useDefault, errors.Error("wrong protocol") } - // Check if upstream is valid plain DNS - return useDefault, checkPlainDNS(u) + // Check if upstream is either an IP or IP with port. + if net.ParseIP(u) != nil { + return useDefault, nil + } else if _, err = netutil.ParseIPPort(u); err != nil { + return useDefault, err + } + + return useDefault, nil } // separateUpstream returns the upstream without the specified domains. -// useDefault is true when a default upstream must be used. -func separateUpstream(upstreamStr string) (upstream string, useDefault bool, err error) { - defer func() { err = errors.Annotate(err, "bad upstream for domain spec %q: %w", upstreamStr) }() - +// isDomainSpec is true when the upstream is domains-specific. +func separateUpstream(upstreamStr string) (upstream string, isDomainSpec bool, err error) { if !strings.HasPrefix(upstreamStr, "[/") { - return upstreamStr, true, nil + return upstreamStr, false, nil } + defer func() { err = errors.Annotate(err, "bad upstream for domain %q: %w", upstreamStr) }() parts := strings.Split(upstreamStr[2:], "/]") - if len(parts) != 2 { - return "", false, errors.Error("duplicated separator") + switch len(parts) { + case 2: + // Go on. + case 1: + return "", false, errors.Error("missing separator") + default: + return "", true, errors.Error("duplicated separator") } - domains := parts[0] - upstream = parts[1] + var domains string + domains, upstream = parts[0], parts[1] for i, host := range strings.Split(domains, "/") { if host == "" { continue @@ -458,36 +469,11 @@ func separateUpstream(upstreamStr string) (upstream string, useDefault bool, err err = netutil.ValidateDomainName(host) if err != nil { - return "", false, fmt.Errorf("domain at index %d: %w", i, err) + return "", true, fmt.Errorf("domain at index %d: %w", i, err) } } - return upstream, false, nil -} - -// checkPlainDNS checks if host is plain DNS -func checkPlainDNS(upstream string) error { - // Check if host is ip without port - if net.ParseIP(upstream) != nil { - return nil - } - - // Check if host is ip with port - ip, port, err := net.SplitHostPort(upstream) - if err != nil { - return err - } - - if net.ParseIP(ip) == nil { - return fmt.Errorf("%s is not a valid IP", ip) - } - - _, err = strconv.ParseInt(port, 0, 64) - if err != nil { - return fmt.Errorf("%s is not a valid port: %w", port, err) - } - - return nil + return upstream, true, nil } // excFunc is a signature of function to check if upstream exchanges correctly. @@ -515,12 +501,8 @@ func checkDNSUpstreamExc(u upstream.Upstream) (err error) { if len(reply.Answer) != 1 { return fmt.Errorf("wrong response") - } - - if t, ok := reply.Answer[0].(*dns.A); ok { - if !net.IPv4(8, 8, 8, 8).Equal(t.A) { - return fmt.Errorf("wrong response") - } + } else if a, ok := reply.Answer[0].(*dns.A); !ok || !a.A.Equal(net.IP{8, 8, 8, 8}) { + return fmt.Errorf("wrong response") } return nil @@ -555,7 +537,7 @@ func checkDNS(input string, bootstrap []string, timeout time.Duration, ef excFun // Separate upstream from domains list. var useDefault bool - if input, useDefault, err = separateUpstream(input); err != nil { + if useDefault, err = validateUpstream(input); err != nil { return fmt.Errorf("wrong upstream format: %w", err) } @@ -564,7 +546,7 @@ func checkDNS(input string, bootstrap []string, timeout time.Duration, ef excFun return nil } - if _, err = validateUpstream(input); err != nil { + if input, _, err = separateUpstream(input); err != nil { return fmt.Errorf("wrong upstream format: %w", err) } @@ -572,7 +554,8 @@ func checkDNS(input string, bootstrap []string, timeout time.Duration, ef excFun bootstrap = defaultBootstrap } - log.Debug("checking if dns server %q works...", input) + log.Debug("checking if upstream %s works", input) + var u upstream.Upstream u, err = upstream.AddressToUpstream(input, &upstream.Options{ Bootstrap: bootstrap, @@ -586,7 +569,7 @@ func checkDNS(input string, bootstrap []string, timeout time.Duration, ef excFun return fmt.Errorf("upstream %q fails to exchange: %w", input, err) } - log.Debug("dns %s works OK", input) + log.Debug("upstream %s is ok", input) return nil } @@ -620,9 +603,9 @@ func (s *Server) handleTestUpstreamDNS(w http.ResponseWriter, r *http.Request) { err = checkDNS(host, bootstraps, timeout, checkPrivateUpstreamExc) if err != nil { log.Info("%v", err) - // TODO(e.burkov): If passed upstream have already - // written an error above, we rewriting the error for - // it. These cases should be handled properly instead. + // TODO(e.burkov): If passed upstream have already written an error + // above, we rewriting the error for it. These cases should be + // handled properly instead. result[host] = err.Error() continue diff --git a/internal/dnsforward/http_test.go b/internal/dnsforward/http_test.go index f411a1b0..876cfdcf 100644 --- a/internal/dnsforward/http_test.go +++ b/internal/dnsforward/http_test.go @@ -184,7 +184,7 @@ func TestDNSForwardHTTP_handleSetConfig(t *testing.T) { wantSet: "", }, { name: "upstream_dns_bad", - wantSet: `wrong upstreams specification: address !!!: ` + + wantSet: `wrong upstreams specification: bad ipport address "!!!": address !!!: ` + `missing port in address`, }, { name: "bootstraps_bad", @@ -235,107 +235,117 @@ func TestDNSForwardHTTP_handleSetConfig(t *testing.T) { } func TestIsCommentOrEmpty(t *testing.T) { - assert.True(t, IsCommentOrEmpty("")) - assert.True(t, IsCommentOrEmpty("# comment")) - assert.False(t, IsCommentOrEmpty("1.2.3.4")) + for _, tc := range []struct { + want assert.BoolAssertionFunc + str string + }{{ + want: assert.True, + str: "", + }, { + want: assert.True, + str: "# comment", + }, { + want: assert.False, + str: "1.2.3.4", + }} { + tc.want(t, IsCommentOrEmpty(tc.str)) + } } -// TODO(a.garipov): Rewrite to check the actual error messages. func TestValidateUpstream(t *testing.T) { testCases := []struct { + wantDef assert.BoolAssertionFunc name string upstream string - valid bool - wantDef bool + wantErr string }{{ + wantDef: assert.True, name: "invalid", upstream: "1.2.3.4.5", - valid: false, - wantDef: false, + wantErr: `bad ipport address "1.2.3.4.5": address 1.2.3.4.5: missing port in address`, }, { + wantDef: assert.True, name: "invalid", upstream: "123.3.7m", - valid: false, - wantDef: false, + wantErr: `bad ipport address "123.3.7m": address 123.3.7m: missing port in address`, }, { + wantDef: assert.True, name: "invalid", upstream: "htttps://google.com/dns-query", - valid: false, - wantDef: false, + wantErr: `wrong protocol`, }, { + wantDef: assert.True, name: "invalid", upstream: "[/host.com]tls://dns.adguard.com", - valid: false, - wantDef: false, + wantErr: `bad upstream for domain "[/host.com]tls://dns.adguard.com": missing separator`, }, { + wantDef: assert.True, name: "invalid", upstream: "[host.ru]#", - valid: false, - wantDef: false, + wantErr: `bad ipport address "[host.ru]#": address [host.ru]#: missing port in address`, }, { + wantDef: assert.True, name: "valid_default", upstream: "1.1.1.1", - valid: true, - wantDef: true, + wantErr: ``, }, { + wantDef: assert.True, name: "valid_default", upstream: "tls://1.1.1.1", - valid: true, - wantDef: true, + wantErr: ``, }, { + wantDef: assert.True, name: "valid_default", upstream: "https://dns.adguard.com/dns-query", - valid: true, - wantDef: true, + wantErr: ``, }, { + wantDef: assert.True, name: "valid_default", upstream: "sdns://AQMAAAAAAAAAFDE3Ni4xMDMuMTMwLjEzMDo1NDQzINErR_JS3PLCu_iZEIbq95zkSV2LFsigxDIuUso_OQhzIjIuZG5zY3J5cHQuZGVmYXVsdC5uczEuYWRndWFyZC5jb20", - valid: true, - wantDef: true, + wantErr: ``, }, { + wantDef: assert.False, name: "valid", upstream: "[/host.com/]1.1.1.1", - valid: true, - wantDef: false, + wantErr: ``, }, { + wantDef: assert.False, name: "valid", upstream: "[//]tls://1.1.1.1", - valid: true, - wantDef: false, + wantErr: ``, }, { + wantDef: assert.False, name: "valid", upstream: "[/www.host.com/]#", - valid: true, - wantDef: false, + wantErr: ``, }, { + wantDef: assert.False, name: "valid", upstream: "[/host.com/google.com/]8.8.8.8", - valid: true, - wantDef: false, + wantErr: ``, }, { + wantDef: assert.False, name: "valid", upstream: "[/host/]sdns://AQMAAAAAAAAAFDE3Ni4xMDMuMTMwLjEzMDo1NDQzINErR_JS3PLCu_iZEIbq95zkSV2LFsigxDIuUso_OQhzIjIuZG5zY3J5cHQuZGVmYXVsdC5uczEuYWRndWFyZC5jb20", - valid: true, - wantDef: false, + wantErr: ``, }, { + wantDef: assert.False, name: "idna", upstream: "[/пример.рф/]8.8.8.8", - valid: true, - wantDef: false, + wantErr: ``, }, { + wantDef: assert.False, name: "bad_domain", upstream: "[/!/]8.8.8.8", - valid: false, - wantDef: false, + wantErr: `bad upstream for domain "[/!/]8.8.8.8": domain at index 0: ` + + `bad domain name "!": bad domain name label "!": bad domain name label rune '!'`, }} for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { defaultUpstream, err := validateUpstream(tc.upstream) - require.Equal(t, tc.valid, err == nil) - if tc.valid { - assert.Equal(t, tc.wantDef, defaultUpstream) - } + testutil.AssertErrorMsg(t, tc.wantErr, err) + tc.wantDef(t, defaultUpstream) }) } } @@ -343,22 +353,19 @@ func TestValidateUpstream(t *testing.T) { func TestValidateUpstreamsSet(t *testing.T) { testCases := []struct { name string - msg string + wantErr string set []string - wantNil bool }{{ name: "empty", - msg: "empty upstreams array should be valid", + wantErr: ``, set: nil, - wantNil: true, }, { name: "comment", - msg: "comments should not be validated", + wantErr: ``, set: []string{"# comment"}, - wantNil: true, }, { - name: "valid_no_default", - msg: "there is no default upstream", + name: "valid_no_default", + wantErr: `no default upstreams specified`, set: []string{ "[/host.com/]1.1.1.1", "[//]tls://1.1.1.1", @@ -366,10 +373,9 @@ func TestValidateUpstreamsSet(t *testing.T) { "[/host.com/google.com/]8.8.8.8", "[/host/]sdns://AQMAAAAAAAAAFDE3Ni4xMDMuMTMwLjEzMDo1NDQzINErR_JS3PLCu_iZEIbq95zkSV2LFsigxDIuUso_OQhzIjIuZG5zY3J5cHQuZGVmYXVsdC5uczEuYWRndWFyZC5jb20", }, - wantNil: false, }, { - name: "valid_with_default", - msg: "upstreams set is valid, but doesn't pass through validation cause: %s", + name: "valid_with_default", + wantErr: ``, set: []string{ "[/host.com/]1.1.1.1", "[//]tls://1.1.1.1", @@ -378,19 +384,16 @@ func TestValidateUpstreamsSet(t *testing.T) { "[/host/]sdns://AQMAAAAAAAAAFDE3Ni4xMDMuMTMwLjEzMDo1NDQzINErR_JS3PLCu_iZEIbq95zkSV2LFsigxDIuUso_OQhzIjIuZG5zY3J5cHQuZGVmYXVsdC5uczEuYWRndWFyZC5jb20", "8.8.8.8", }, - wantNil: true, }, { name: "invalid", - msg: "there is an invalid upstream in set, but it pass through validation", + wantErr: `cannot prepare the upstream dhcp://fake.dns ([]): unsupported URL scheme: dhcp`, set: []string{"dhcp://fake.dns"}, - wantNil: false, }} for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { err := ValidateUpstreams(tc.set) - - assert.Equalf(t, tc.wantNil, err == nil, tc.msg, err) + testutil.AssertErrorMsg(t, tc.wantErr, err) }) } } diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index ef530663..720eecdf 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -123,7 +123,9 @@ '8.8.8.8': 'OK' '8.8.4.4': 'OK' '192.168.1.104:53535': > - Couldn't communicate with DNS server + upstream "192.168.1.104:1234" fails to exchange: couldn't + communicate with upstream: read udp + 192.168.1.100:60675->8.8.8.8:1234: i/o timeout '/version.json': 'post': 'tags': From 008f58c863f2aa6da908e3ce6ac696da42d1e5eb Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Mon, 17 Jan 2022 18:54:00 +0300 Subject: [PATCH 083/135] Pull request: all: upd dnsproxy Updates #4065. Squashed commit of the following: commit d65d2e3a783910b9cb95c5bcfbcf1af11da666d5 Author: Ainar Garipov Date: Mon Jan 17 18:47:17 2022 +0300 all: upd dnsproxy --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 8af0d2ca..7d838550 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.40.3 + github.com/AdguardTeam/dnsproxy v0.40.4 github.com/AdguardTeam/golibs v0.10.3 github.com/AdguardTeam/urlfilter v0.15.1 github.com/NYTimes/gziphandler v1.1.1 diff --git a/go.sum b/go.sum index 19e7dcc5..db1d9ced 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.40.3 h1:rdQBp3LMmOdD4EpRtnutfP4zwqNA/Q5TyYNNDyjSeQY= -github.com/AdguardTeam/dnsproxy v0.40.3/go.mod h1:PZ9l22h3Er+5mxFQB7oHZMTvx+aa9R6LbzA/ikXQlS0= +github.com/AdguardTeam/dnsproxy v0.40.4 h1:dnI60dO/lm7ILSZ5GLV5bt3Vp8jFUPKqpaWewWpb3gY= +github.com/AdguardTeam/dnsproxy v0.40.4/go.mod h1:PZ9l22h3Er+5mxFQB7oHZMTvx+aa9R6LbzA/ikXQlS0= 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.9.2/go.mod h1:fCAMwPBJ8S7YMYbTWvYS+eeTLblP5E04IDtNAo7y7IY= From 061136508ec3e5492c1ecaaee6e61c1f7d9b9fbf Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Tue, 18 Jan 2022 14:20:25 +0300 Subject: [PATCH 084/135] Pull request: 4120 service domain validation Merge in DNS/adguard-home from 4120-fix-services to master Closes #4120. Squashed commit of the following: commit ca2e5faf64f567cc6647a300181712236158e69d Author: Eugene Burkov Date: Tue Jan 18 14:14:54 2022 +0300 dnsforward: imp docs commit 9ed5f536e691dcdee5b7c94e161c738d31ff8588 Author: Eugene Burkov Date: Tue Jan 18 13:50:33 2022 +0300 dnsforward: fix reverse domain validation --- CHANGELOG.md | 2 ++ go.mod | 2 +- go.sum | 3 ++- internal/dnsforward/dns.go | 17 +++++++++++++++-- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78ea8efd..896efc0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ TODO(a.garipov): Remove this deprecation, if v0.108.0 is released before the Go ### Fixed +- Incorrectly invalidated service domains ([#4120]). - Poor testing of domain-specific upstream servers ([#4074]). - Omitted aliases of hosts specified by another line within the OS's hosts file ([#4079]). @@ -40,6 +41,7 @@ TODO(a.garipov): Remove this deprecation, if v0.108.0 is released before the Go [#3057]: https://github.com/AdguardTeam/AdGuardHome/issues/3057 [#4074]: https://github.com/AdguardTeam/AdGuardHome/issues/4074 [#4079]: https://github.com/AdguardTeam/AdGuardHome/issues/4079 +[#4120]: https://github.com/AdguardTeam/AdGuardHome/issues/4120 diff --git a/go.mod b/go.mod index 7d838550..9a9e743f 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.17 require ( github.com/AdguardTeam/dnsproxy v0.40.4 - github.com/AdguardTeam/golibs v0.10.3 + github.com/AdguardTeam/golibs v0.10.4 github.com/AdguardTeam/urlfilter v0.15.1 github.com/NYTimes/gziphandler v1.1.1 github.com/ameshkov/dnscrypt/v2 v2.2.3 diff --git a/go.sum b/go.sum index db1d9ced..3037daf0 100644 --- a/go.sum +++ b/go.sum @@ -12,8 +12,9 @@ github.com/AdguardTeam/dnsproxy v0.40.4/go.mod h1:PZ9l22h3Er+5mxFQB7oHZMTvx+aa9R 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.9.2/go.mod h1:fCAMwPBJ8S7YMYbTWvYS+eeTLblP5E04IDtNAo7y7IY= -github.com/AdguardTeam/golibs v0.10.3 h1:FBgk17zf35ESVWQKIqEUiqqB2bDaCBC8X5vMU760yB4= github.com/AdguardTeam/golibs v0.10.3/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw= +github.com/AdguardTeam/golibs v0.10.4 h1:TMBkablZC0IZOpRgg9fzAKlxxNhSN2YJq7qbgtuZ7PQ= +github.com/AdguardTeam/golibs v0.10.4/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw= github.com/AdguardTeam/gomitmproxy v0.2.0/go.mod h1:Qdv0Mktnzer5zpdpi5rAwixNJzW2FN91LjKJCkVbYGU= github.com/AdguardTeam/urlfilter v0.15.1 h1:dP6S7J6eFAk8MN4IDpUq2fZoBo8K8fmc6pXpxNIv84M= github.com/AdguardTeam/urlfilter v0.15.1/go.mod h1:EwXwrYhowP7bedqmOrmKKmQtpBYFyDNEBFQ+lxdUgQU= diff --git a/internal/dnsforward/dns.go b/internal/dnsforward/dns.go index 5c3db14f..d9e04b80 100644 --- a/internal/dnsforward/dns.go +++ b/internal/dnsforward/dns.go @@ -352,9 +352,22 @@ func (s *Server) processRestrictLocal(ctx *dnsContext) (rc resultCode) { ip, err := netutil.IPFromReversedAddr(q.Name) if err != nil { - log.Debug("dns: reversed addr: %s", err) + log.Debug("dns: parsing reversed addr: %s", err) - return resultCodeError + // DNS-Based Service Discovery uses PTR records having not an ARPA + // format of the domain name in question. Those shouldn't be + // invalidated. See http://www.dns-sd.org/ServerStaticSetup.html and + // RFC 2782. + name := strings.TrimSuffix(q.Name, ".") + if err = netutil.ValidateSRVDomainName(name); err != nil { + log.Debug("dns: validating service domain: %s", err) + + return resultCodeError + } + + log.Debug("dns: request is for a service domain") + + return resultCodeSuccess } // Restrict an access to local addresses for external clients. We also From 813a06d09a250bfbab2c2ea5c1fa14a4f0d2ac18 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Tue, 18 Jan 2022 15:05:34 +0300 Subject: [PATCH 085/135] Pull request: home: show version in install api Closes #4026. Squashed commit of the following: commit bcd1315a10e819daee3aee323427d90a27860b4a Author: Ainar Garipov Date: Tue Jan 18 14:57:49 2022 +0300 openapi: fix example commit b56e27c5ac1fc7c3f595057d77607479d72ec50a Author: Ildar Kamalov Date: Tue Jan 18 14:55:51 2022 +0300 client: show version on install page commit 95dfbfaa1235deef7b55e51457d11c677f6ef6b5 Author: Ainar Garipov Date: Tue Jan 18 14:29:08 2022 +0300 home: show version in install api --- client/src/components/ui/Version.js | 17 ++++++++++----- client/src/reducers/install.js | 11 ++++++++-- internal/home/controlinstall.go | 33 ++++++++++++++++++++--------- internal/version/version.go | 13 +++--------- openapi/CHANGELOG.md | 11 ++++++++-- openapi/openapi.yaml | 12 +++++++---- 6 files changed, 64 insertions(+), 33 deletions(-) diff --git a/client/src/components/ui/Version.js b/client/src/components/ui/Version.js index 30cec35d..918cd417 100644 --- a/client/src/components/ui/Version.js +++ b/client/src/components/ui/Version.js @@ -13,6 +13,12 @@ const Version = () => { checkUpdateFlag, } = useSelector((state) => state?.dashboard ?? {}, shallowEqual); + const { + dnsVersion: installDnsVersion, + } = useSelector((state) => state?.install ?? {}, shallowEqual); + + const version = dnsVersion || installDnsVersion; + const onClick = () => { dispatch(getVersion(true)); }; @@ -20,11 +26,12 @@ const Version = () => { return (
- {dnsVersion - && <> - version:  - {dnsVersion} - } + {version && ( + <> + version:  + {version} + + )} {checkUpdateFlag &&
); }, + sortMethod: sortIp, }, { Header: this.props.t('table_name'), diff --git a/client/src/helpers/helpers.js b/client/src/helpers/helpers.js index 6753062a..2546d5b9 100644 --- a/client/src/helpers/helpers.js +++ b/client/src/helpers/helpers.js @@ -754,8 +754,10 @@ const getAddressesComparisonBytes = (item) => { */ export const sortIp = (a, b) => { try { - const comparisonBytesA = getAddressesComparisonBytes(a); - const comparisonBytesB = getAddressesComparisonBytes(b); + const comparisonBytesA = Array.isArray(a) + ? getAddressesComparisonBytes(a[0]) : getAddressesComparisonBytes(a); + const comparisonBytesB = Array.isArray(b) + ? getAddressesComparisonBytes(b[0]) : getAddressesComparisonBytes(b); for (let i = 0; i < comparisonBytesA.length; i += 1) { const byteA = comparisonBytesA[i]; From 13871977f9f646f51056cace03cb2032402151ef Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Thu, 20 Jan 2022 17:05:59 +0300 Subject: [PATCH 093/135] Pull request: all: upd dnsproxy Updates #4128. Squashed commit of the following: commit c177750f3f4d3ae29133154eca4dfe4051de1310 Author: Ainar Garipov Date: Thu Jan 20 17:01:02 2022 +0300 all: upd dnsproxy --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 2c26ed36..e1fef011 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.40.4 + github.com/AdguardTeam/dnsproxy v0.40.5 github.com/AdguardTeam/golibs v0.10.4 github.com/AdguardTeam/urlfilter v0.15.2 github.com/NYTimes/gziphandler v1.1.1 diff --git a/go.sum b/go.sum index b4b08ec8..cd2a6179 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.40.4 h1:dnI60dO/lm7ILSZ5GLV5bt3Vp8jFUPKqpaWewWpb3gY= -github.com/AdguardTeam/dnsproxy v0.40.4/go.mod h1:PZ9l22h3Er+5mxFQB7oHZMTvx+aa9R6LbzA/ikXQlS0= +github.com/AdguardTeam/dnsproxy v0.40.5 h1:727KSGRmzq2DB5dMm093g0Guhc3dzzzMbfB0C9hK0s8= +github.com/AdguardTeam/dnsproxy v0.40.5/go.mod h1:PZ9l22h3Er+5mxFQB7oHZMTvx+aa9R6LbzA/ikXQlS0= 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.3/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw= From 5ec4a4dab8297fed0f8f7a477c7025d28a580db8 Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Thu, 20 Jan 2022 17:19:09 +0300 Subject: [PATCH 094/135] Pull request: 4142 stats panic Merge in DNS/adguard-home from 4142-stats-panic to master Updates #4142. Squashed commit of the following: commit bf168f50ac86bdfdab73bf7285705f09f87b6c72 Author: Eugene Burkov Date: Thu Jan 20 17:13:41 2022 +0300 stats: imp more commit bb638211da7d0c51959ded2dacb72faea00befb4 Author: Eugene Burkov Date: Thu Jan 20 17:09:31 2022 +0300 stats: imp code quality commit 27ac52f15e4e0f4112ce7a6b47b03f963463393e Author: Eugene Burkov Date: Thu Jan 20 17:00:09 2022 +0300 stats: recover panic on init commit 1ffcebbb9062438170b010e1c7bad3c6cef4cfc1 Author: Eugene Burkov Date: Thu Jan 20 14:19:01 2022 +0300 all: fix some typos --- CHANGELOG.md | 2 +- internal/aghalg/aghalg.go | 2 +- internal/home/controlinstall.go | 2 +- internal/home/dns.go | 2 +- internal/stats/unit.go | 22 ++++++++++++++++++++++ 5 files changed, 26 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7410cd93..8c9e5b4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,7 +51,7 @@ TODO(a.garipov): Remove this deprecation, if v0.108.0 is released before the Go diff --git a/internal/aghalg/aghalg.go b/internal/aghalg/aghalg.go index c3b6e906..3a9b07db 100644 --- a/internal/aghalg/aghalg.go +++ b/internal/aghalg/aghalg.go @@ -24,7 +24,7 @@ func (uc UniqChecker) Add(elems ...comparable) { } } -// Merge returns a validator containing data from both v and other. +// Merge returns a checker containing data from both uc and other. func (uc UniqChecker) Merge(other UniqChecker) (merged UniqChecker) { merged = make(UniqChecker, len(uc)+len(other)) for elem, num := range uc { diff --git a/internal/home/controlinstall.go b/internal/home/controlinstall.go index b9c302ee..82598078 100644 --- a/internal/home/controlinstall.go +++ b/internal/home/controlinstall.go @@ -128,7 +128,7 @@ func (req *checkConfReq) validateWeb(uc aghalg.UniqChecker) (err error) { } // validateDNS returns error if the DNS part of the initial configuration can't -// be set. autofix is true if the port can be unbound by AdGuard Home +// be set. canAutofix is true if the port can be unbound by AdGuard Home // automatically. func (req *checkConfReq) validateDNS(uc aghalg.UniqChecker) (canAutofix bool, err error) { defer func() { err = errors.Annotate(err, "validating ports: %w") }() diff --git a/internal/home/dns.go b/internal/home/dns.go index dfd133eb..8775e152 100644 --- a/internal/home/dns.go +++ b/internal/home/dns.go @@ -54,7 +54,7 @@ func initDNSServer() (err error) { } Context.stats, err = stats.New(statsConf) if err != nil { - return fmt.Errorf("couldn't initialize statistics module") + return fmt.Errorf("init stats: %w", err) } conf := querylog.Config{ diff --git a/internal/stats/unit.go b/internal/stats/unit.go index 43119907..35d47a51 100644 --- a/internal/stats/unit.go +++ b/internal/stats/unit.go @@ -67,7 +67,29 @@ type unitDB struct { TimeAvg uint32 // usec } +// withRecovered turns the value recovered from panic if any into an error and +// combines it with the one pointed by orig. orig must be non-nil. +func withRecovered(orig *error) { + p := recover() + if p == nil { + return + } + + var err error + switch p := p.(type) { + case error: + err = fmt.Errorf("panic: %w", p) + default: + err = fmt.Errorf("panic: recovered value of type %[1]T: %[1]v", p) + } + + *orig = errors.WithDeferred(*orig, err) +} + +// createObject creates s from conf and properly initializes it. func createObject(conf Config) (s *statsCtx, err error) { + defer withRecovered(&err) + s = &statsCtx{ mu: &sync.Mutex{}, } From f7ff02f3b128d2e7d6bb169e14112f7068b737df Mon Sep 17 00:00:00 2001 From: Ildar Kamalov Date: Thu, 20 Jan 2022 18:24:21 +0300 Subject: [PATCH 095/135] Pull request: 3971 fix client id error message Updates #3971 Squashed commit of the following: commit f6b855a16daaec7bfca1e1653b4b9c4180c2d80e Merge: 0cb31dbb 5ec4a4da Author: Ildar Kamalov Date: Thu Jan 20 18:19:20 2022 +0300 Merge branch 'master' into 3971-client-id commit 0cb31dbbea785fb5ba11a8efe2b6653aece7cd97 Author: Natalia Sokolova Date: Thu Jan 20 11:41:06 2022 +0300 client/src/__locales/en.json edited online with Bitbucket commit 7999f260d83adcb2fc8d5d5e40cb1934e0333873 Author: Ildar Kamalov Date: Wed Jan 19 15:58:18 2022 +0300 client: fix client id error message --- 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 86711e23..ccc4c0b8 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -43,7 +43,7 @@ "form_error_ip6_format": "Invalid IPv6 address", "form_error_ip_format": "Invalid IP address", "form_error_mac_format": "Invalid MAC address", - "form_error_client_id_format": "Invalid client ID", + "form_error_client_id_format": "Client ID must contain only numbers, lowercase letters, and hyphens", "form_error_server_name": "Invalid server name", "form_error_subnet": "Subnet \"{{cidr}}\" does not contain the IP address \"{{ip}}\"", "form_error_positive": "Must be greater than 0", From 3f5605c42e6287d52562439195fb47475ae61828 Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Fri, 21 Jan 2022 19:21:38 +0300 Subject: [PATCH 096/135] Pull request: 2846 cover aghnet vol.1 Merge in DNS/adguard-home from 2846-cover-aghnet-vol.1 to master Updates #2846. Squashed commit of the following: commit 368e75b0bacb290f9929b8a5a682b06f2d75df6a Author: Eugene Burkov Date: Fri Jan 21 19:11:59 2022 +0300 aghnet: imp tests commit 8bb3e2a1680fd30294f7c82693891ffb19474c6a Author: Eugene Burkov Date: Fri Jan 21 18:27:06 2022 +0300 aghnet: rm unused test commit 28d8e64880f845810d0af629e5d1f06b9bde5b28 Author: Eugene Burkov Date: Fri Jan 21 18:18:22 2022 +0300 aghnet: cover with tests --- internal/aghnet/dhcp_unix.go | 3 +- internal/aghnet/hostscontainer_test.go | 115 +++++++++++----------- internal/aghnet/interfaces.go | 37 +++---- internal/aghnet/interfaces_test.go | 128 ++++++++++++++++--------- internal/aghnet/ipmut_test.go | 44 +++++++++ internal/aghnet/net.go | 25 +---- internal/aghnet/net_test.go | 67 ++++++++++--- 7 files changed, 259 insertions(+), 160 deletions(-) create mode 100644 internal/aghnet/ipmut_test.go diff --git a/internal/aghnet/dhcp_unix.go b/internal/aghnet/dhcp_unix.go index 479d9926..554d68c6 100644 --- a/internal/aghnet/dhcp_unix.go +++ b/internal/aghnet/dhcp_unix.go @@ -19,7 +19,8 @@ import ( "github.com/insomniacslk/dhcp/iana" ) -// defaultDiscoverTime is the +// defaultDiscoverTime is the default timeout of checking another DHCP server +// response. const defaultDiscoverTime = 3 * time.Second func checkOtherDHCP(ifaceName string) (ok4, ok6 bool, err4, err6 error) { diff --git a/internal/aghnet/hostscontainer_test.go b/internal/aghnet/hostscontainer_test.go index 70f2d00f..150e8c19 100644 --- a/internal/aghnet/hostscontainer_test.go +++ b/internal/aghnet/hostscontainer_test.go @@ -343,113 +343,93 @@ func TestHostsContainer(t *testing.T) { testdata := os.DirFS("./testdata") - nRewrites := func(t *testing.T, res *urlfilter.DNSResult, n int) (rws []*rules.DNSRewrite) { - rewrites := res.DNSRewrites() - require.Len(t, rewrites, n) - - for _, rewrite := range rewrites { - require.Equal(t, listID, rewrite.FilterListID) - - rw := rewrite.DNSRewrite - require.NotNil(t, rw) - - rws = append(rws, rw) - } - - return rws - } - testCases := []struct { - testTail func(t *testing.T, res *urlfilter.DNSResult) - name string - req urlfilter.DNSRequest + want []*rules.DNSRewrite + name string + req urlfilter.DNSRequest }{{ + want: []*rules.DNSRewrite{{ + RCode: dns.RcodeSuccess, + Value: net.IPv4(1, 0, 0, 1), + RRType: dns.TypeA, + }, { + RCode: dns.RcodeSuccess, + Value: net.IP(append((&[15]byte{})[:], byte(1))), + RRType: dns.TypeAAAA, + }}, name: "simple", req: urlfilter.DNSRequest{ Hostname: "simplehost", DNSType: dns.TypeA, }, - testTail: func(t *testing.T, res *urlfilter.DNSResult) { - rws := nRewrites(t, res, 2) - - v, ok := rws[0].Value.(net.IP) - require.True(t, ok) - - assert.True(t, net.IP{1, 0, 0, 1}.Equal(v)) - - v, ok = rws[1].Value.(net.IP) - require.True(t, ok) - - // It's ::1. - assert.True(t, net.IP(append((&[15]byte{})[:], byte(1))).Equal(v)) - }, }, { + want: []*rules.DNSRewrite{{ + RCode: dns.RcodeSuccess, + NewCNAME: "hello", + }}, name: "hello_alias", req: urlfilter.DNSRequest{ Hostname: "hello.world", DNSType: dns.TypeA, }, - testTail: func(t *testing.T, res *urlfilter.DNSResult) { - assert.Equal(t, "hello", nRewrites(t, res, 1)[0].NewCNAME) - }, }, { + want: []*rules.DNSRewrite{{ + RCode: dns.RcodeSuccess, + NewCNAME: "hello", + }}, name: "other_line_alias", req: urlfilter.DNSRequest{ Hostname: "hello.world.again", DNSType: dns.TypeA, }, - testTail: func(t *testing.T, res *urlfilter.DNSResult) { - assert.Equal(t, "hello", nRewrites(t, res, 1)[0].NewCNAME) - }, }, { + want: []*rules.DNSRewrite{}, name: "hello_subdomain", req: urlfilter.DNSRequest{ Hostname: "say.hello", DNSType: dns.TypeA, }, - testTail: func(t *testing.T, res *urlfilter.DNSResult) { - assert.Empty(t, res.DNSRewrites()) - }, }, { + want: []*rules.DNSRewrite{}, name: "hello_alias_subdomain", req: urlfilter.DNSRequest{ Hostname: "say.hello.world", DNSType: dns.TypeA, }, - testTail: func(t *testing.T, res *urlfilter.DNSResult) { - assert.Empty(t, res.DNSRewrites()) - }, }, { + want: []*rules.DNSRewrite{{ + RCode: dns.RcodeSuccess, + NewCNAME: "a.whole", + }}, name: "lots_of_aliases", req: urlfilter.DNSRequest{ Hostname: "for.testing", DNSType: dns.TypeA, }, - testTail: func(t *testing.T, res *urlfilter.DNSResult) { - assert.Equal(t, "a.whole", nRewrites(t, res, 1)[0].NewCNAME) - }, }, { + want: []*rules.DNSRewrite{{ + RCode: dns.RcodeSuccess, + RRType: dns.TypePTR, + Value: "simplehost.", + }}, name: "reverse", req: urlfilter.DNSRequest{ Hostname: "1.0.0.1.in-addr.arpa", DNSType: dns.TypePTR, }, - testTail: func(t *testing.T, res *urlfilter.DNSResult) { - rws := nRewrites(t, res, 1) - - assert.Equal(t, dns.TypePTR, rws[0].RRType) - assert.Equal(t, "simplehost.", rws[0].Value) - }, }, { + want: []*rules.DNSRewrite{}, name: "non-existing", req: urlfilter.DNSRequest{ Hostname: "nonexisting", DNSType: dns.TypeA, }, - testTail: func(t *testing.T, res *urlfilter.DNSResult) { - require.NotNil(t, res) - - assert.Nil(t, res.DNSRewrites()) + }, { + want: nil, + name: "bad_type", + req: urlfilter.DNSRequest{ + Hostname: "1.0.0.1.in-addr.arpa", + DNSType: dns.TypeSRV, }, }} @@ -466,9 +446,26 @@ func TestHostsContainer(t *testing.T) { t.Run(tc.name, func(t *testing.T) { res, ok := hc.MatchRequest(tc.req) require.False(t, ok) + + if tc.want == nil { + assert.Nil(t, res) + + return + } + require.NotNil(t, res) - tc.testTail(t, res) + rewrites := res.DNSRewrites() + require.Len(t, rewrites, len(tc.want)) + + for i, rewrite := range rewrites { + require.Equal(t, listID, rewrite.FilterListID) + + rw := rewrite.DNSRewrite + require.NotNil(t, rw) + + assert.Equal(t, tc.want[i], rw) + } }) } } diff --git a/internal/aghnet/interfaces.go b/internal/aghnet/interfaces.go index a5095919..a667a1f3 100644 --- a/internal/aghnet/interfaces.go +++ b/internal/aghnet/interfaces.go @@ -25,6 +25,13 @@ type NetIface interface { // IfaceIPAddrs returns the interface's IP addresses. func IfaceIPAddrs(iface NetIface, ipv IPVersion) (ips []net.IP, err error) { + switch ipv { + case IPVersion4, IPVersion6: + // Go on. + default: + return nil, fmt.Errorf("invalid ip version %d", ipv) + } + addrs, err := iface.Addrs() if err != nil { return nil, err @@ -41,20 +48,16 @@ func IfaceIPAddrs(iface NetIface, ipv IPVersion) (ips []net.IP, err error) { continue } - // Assume that net.(*Interface).Addrs can only return valid IPv4 - // and IPv6 addresses. Thus, if it isn't an IPv4 address, it - // must be an IPv6 one. - switch ipv { - case IPVersion4: - if ip4 := ip.To4(); ip4 != nil { + // Assume that net.(*Interface).Addrs can only return valid IPv4 and + // IPv6 addresses. Thus, if it isn't an IPv4 address, it must be an + // IPv6 one. + ip4 := ip.To4() + if ipv == IPVersion4 { + if ip4 != nil { ips = append(ips, ip4) } - case IPVersion6: - if ip6 := ip.To4(); ip6 == nil { - ips = append(ips, ip) - } - default: - return nil, fmt.Errorf("invalid ip version %d", ipv) + } else if ip4 == nil { + ips = append(ips, ip) } } @@ -96,16 +99,16 @@ func IfaceDNSIPAddrs( switch len(addrs) { case 0: - // Don't return errors in case the users want to try and enable - // the DHCP server later. + // Don't return errors in case the users want to try and enable the DHCP + // server later. t := time.Duration(n) * backoff log.Error("dhcpv%d: no ip for iface after %d attempts and %s", ipv, n, t) return nil, nil case 1: - // Some Android devices use 8.8.8.8 if there is not a secondary - // DNS server. Fix that by setting the secondary DNS address to - // the same address. + // Some Android devices use 8.8.8.8 if there is not a secondary DNS + // server. Fix that by setting the secondary DNS address to the same + // address. // // See https://github.com/AdguardTeam/AdGuardHome/issues/1708. log.Debug("dhcpv%d: setting secondary dns ip to itself", ipv) diff --git a/internal/aghnet/interfaces_test.go b/internal/aghnet/interfaces_test.go index 2b70429c..ca829fb1 100644 --- a/internal/aghnet/interfaces_test.go +++ b/internal/aghnet/interfaces_test.go @@ -5,13 +5,15 @@ import ( "testing" "github.com/AdguardTeam/golibs/errors" + "github.com/AdguardTeam/golibs/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) +// fakeIface is a stub implementation of aghnet.NetIface to simplify testing. type fakeIface struct { - addrs []net.Addr err error + addrs []net.Addr } // Addrs implements the NetIface interface for *fakeIface. @@ -33,61 +35,86 @@ func TestIfaceIPAddrs(t *testing.T) { addr6 := &net.IPNet{IP: ip6} testCases := []struct { - name string - iface NetIface - ipv IPVersion - want []net.IP - wantErr error + iface NetIface + name string + wantErrMsg string + want []net.IP + ipv IPVersion }{{ - name: "ipv4_success", - iface: &fakeIface{addrs: []net.Addr{addr4}, err: nil}, - ipv: IPVersion4, - want: []net.IP{ip4}, - wantErr: nil, + iface: &fakeIface{addrs: []net.Addr{addr4}, err: nil}, + name: "ipv4_success", + wantErrMsg: "", + want: []net.IP{ip4}, + ipv: IPVersion4, }, { - name: "ipv4_success_with_ipv6", - iface: &fakeIface{addrs: []net.Addr{addr6, addr4}, err: nil}, - ipv: IPVersion4, - want: []net.IP{ip4}, - wantErr: nil, + iface: &fakeIface{addrs: []net.Addr{addr6, addr4}, err: nil}, + name: "ipv4_success_with_ipv6", + wantErrMsg: "", + want: []net.IP{ip4}, + ipv: IPVersion4, }, { - name: "ipv4_error", - iface: &fakeIface{addrs: []net.Addr{addr4}, err: errTest}, - ipv: IPVersion4, - want: nil, - wantErr: errTest, + iface: &fakeIface{addrs: []net.Addr{addr4}, err: errTest}, + name: "ipv4_error", + wantErrMsg: errTest.Error(), + want: nil, + ipv: IPVersion4, }, { - name: "ipv6_success", - iface: &fakeIface{addrs: []net.Addr{addr6}, err: nil}, - ipv: IPVersion6, - want: []net.IP{ip6}, - wantErr: nil, + iface: &fakeIface{addrs: []net.Addr{addr6}, err: nil}, + name: "ipv6_success", + wantErrMsg: "", + want: []net.IP{ip6}, + ipv: IPVersion6, }, { - name: "ipv6_success_with_ipv4", - iface: &fakeIface{addrs: []net.Addr{addr6, addr4}, err: nil}, - ipv: IPVersion6, - want: []net.IP{ip6}, - wantErr: nil, + iface: &fakeIface{addrs: []net.Addr{addr6, addr4}, err: nil}, + name: "ipv6_success_with_ipv4", + wantErrMsg: "", + want: []net.IP{ip6}, + ipv: IPVersion6, }, { - name: "ipv6_error", - iface: &fakeIface{addrs: []net.Addr{addr6}, err: errTest}, - ipv: IPVersion6, - want: nil, - wantErr: errTest, + iface: &fakeIface{addrs: []net.Addr{addr6}, err: errTest}, + name: "ipv6_error", + wantErrMsg: errTest.Error(), + want: nil, + ipv: IPVersion6, + }, { + iface: &fakeIface{addrs: nil, err: nil}, + name: "bad_proto", + wantErrMsg: "invalid ip version 10", + want: nil, + ipv: IPVersion6 + IPVersion4, + }, { + iface: &fakeIface{addrs: []net.Addr{&net.IPAddr{IP: ip4}}, err: nil}, + name: "ipaddr_v4", + wantErrMsg: "", + want: []net.IP{ip4}, + ipv: IPVersion4, + }, { + iface: &fakeIface{addrs: []net.Addr{&net.IPAddr{IP: ip6, Zone: ""}}, err: nil}, + name: "ipaddr_v6", + wantErrMsg: "", + want: []net.IP{ip6}, + ipv: IPVersion6, + }, { + iface: &fakeIface{addrs: []net.Addr{&net.UnixAddr{}}, err: nil}, + name: "non-ipv4", + wantErrMsg: "", + want: nil, + ipv: IPVersion4, }} for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - got, gotErr := IfaceIPAddrs(tc.iface, tc.ipv) - require.True(t, errors.Is(gotErr, tc.wantErr)) + got, err := IfaceIPAddrs(tc.iface, tc.ipv) + testutil.AssertErrorMsg(t, tc.wantErrMsg, err) + assert.Equal(t, tc.want, got) }) } } type waitingFakeIface struct { - addrs []net.Addr err error + addrs []net.Addr n int } @@ -116,11 +143,11 @@ func TestIfaceDNSIPAddrs(t *testing.T) { addr6 := &net.IPNet{IP: ip6} testCases := []struct { - name string iface NetIface - ipv IPVersion - want []net.IP wantErr error + name string + want []net.IP + ipv IPVersion }{{ name: "ipv4_success", iface: &fakeIface{addrs: []net.Addr{addr4}, err: nil}, @@ -169,12 +196,25 @@ func TestIfaceDNSIPAddrs(t *testing.T) { ipv: IPVersion6, want: []net.IP{ip6, ip6}, wantErr: nil, + }, { + name: "empty", + iface: &fakeIface{addrs: nil, err: nil}, + ipv: IPVersion4, + want: nil, + wantErr: nil, + }, { + name: "many", + iface: &fakeIface{addrs: []net.Addr{addr4, addr4}}, + ipv: IPVersion4, + want: []net.IP{ip4, ip4}, + wantErr: nil, }} for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - got, gotErr := IfaceDNSIPAddrs(tc.iface, tc.ipv, 2, 0) - require.True(t, errors.Is(gotErr, tc.wantErr)) + got, err := IfaceDNSIPAddrs(tc.iface, tc.ipv, 2, 0) + require.ErrorIs(t, err, tc.wantErr) + assert.Equal(t, tc.want, got) }) } diff --git a/internal/aghnet/ipmut_test.go b/internal/aghnet/ipmut_test.go new file mode 100644 index 00000000..51fc16ba --- /dev/null +++ b/internal/aghnet/ipmut_test.go @@ -0,0 +1,44 @@ +package aghnet + +import ( + "net" + "testing" + + "github.com/AdguardTeam/golibs/netutil" + "github.com/stretchr/testify/assert" +) + +func TestIPMut(t *testing.T) { + testIPs := []net.IP{{ + 127, 0, 0, 1, + }, { + 192, 168, 0, 1, + }, { + 8, 8, 8, 8, + }} + + t.Run("nil_no_mut", func(t *testing.T) { + ipmut := NewIPMut(nil) + + ips := netutil.CloneIPs(testIPs) + for i := range ips { + ipmut.Load()(ips[i]) + assert.True(t, ips[i].Equal(testIPs[i])) + } + }) + + t.Run("not_nil_mut", func(t *testing.T) { + ipmut := NewIPMut(func(ip net.IP) { + for i := range ip { + ip[i] = 0 + } + }) + want := netutil.IPv4Zero() + + ips := netutil.CloneIPs(testIPs) + for i := range ips { + ipmut.Load()(ips[i]) + assert.True(t, ips[i].Equal(want)) + } + }) +} diff --git a/internal/aghnet/net.go b/internal/aghnet/net.go index 77bdcc63..ecb70fa8 100644 --- a/internal/aghnet/net.go +++ b/internal/aghnet/net.go @@ -42,8 +42,7 @@ func GatewayIP(ifaceName string) net.IP { fields := strings.Fields(string(d)) // The meaningful "ip route" command output should contain the word - // "default" at first field and default gateway IP address at third - // field. + // "default" at first field and default gateway IP address at third field. if len(fields) < 3 || fields[0] != "default" { return nil } @@ -218,28 +217,6 @@ func IsAddrInUse(err error) (ok bool) { return isAddrInUse(sysErr) } -// SplitHost is a wrapper for net.SplitHostPort for the cases when the hostport -// does not necessarily contain a port. -func SplitHost(hostport string) (host string, err error) { - host, _, err = net.SplitHostPort(hostport) - if err != nil { - // Check for the missing port error. If it is that error, just - // use the host as is. - // - // See the source code for net.SplitHostPort. - const missingPort = "missing port in address" - - addrErr := &net.AddrError{} - if !errors.As(err, &addrErr) || addrErr.Err != missingPort { - return "", err - } - - host = hostport - } - - return host, nil -} - // CollectAllIfacesAddrs returns the slice of all network interfaces IP // addresses without port number. func CollectAllIfacesAddrs() (addrs []string, err error) { diff --git a/internal/aghnet/net_test.go b/internal/aghnet/net_test.go index 2e3f54be..b5bf2297 100644 --- a/internal/aghnet/net_test.go +++ b/internal/aghnet/net_test.go @@ -15,12 +15,20 @@ func TestMain(m *testing.M) { aghtest.DiscardLogOutput(m) } -func TestGetValidNetInterfacesForWeb(t *testing.T) { +func TestGetInterfaceByIP(t *testing.T) { ifaces, err := GetValidNetInterfacesForWeb() - require.NoErrorf(t, err, "cannot get net interfaces: %s", err) - require.NotEmpty(t, ifaces, "no net interfaces found") + require.NoError(t, err) + require.NotEmpty(t, ifaces) + for _, iface := range ifaces { - require.NotEmptyf(t, iface.Addresses, "no addresses found for %s", iface.Name) + t.Run(iface.Name, func(t *testing.T) { + require.NotEmpty(t, iface.Addresses) + + for _, ip := range iface.Addresses { + ifaceName := GetInterfaceByIP(ip) + require.Equal(t, iface.Name, ifaceName) + } + }) } } @@ -73,18 +81,47 @@ func TestBroadcastFromIPNet(t *testing.T) { } func TestCheckPort(t *testing.T) { - l, err := net.Listen("tcp", "127.0.0.1:") - require.NoError(t, err) - testutil.CleanupAndRequireSuccess(t, l.Close) + t.Run("tcp_bound", func(t *testing.T) { + l, err := net.Listen("tcp", "127.0.0.1:") + require.NoError(t, err) + testutil.CleanupAndRequireSuccess(t, l.Close) - ipp := netutil.IPPortFromAddr(l.Addr()) - require.NotNil(t, ipp) - require.NotNil(t, ipp.IP) - require.NotZero(t, ipp.Port) + ipp := netutil.IPPortFromAddr(l.Addr()) + require.NotNil(t, ipp) + require.NotNil(t, ipp.IP) + require.NotZero(t, ipp.Port) - err = CheckPort("tcp", ipp.IP, ipp.Port) - target := &net.OpError{} - require.ErrorAs(t, err, &target) + err = CheckPort("tcp", ipp.IP, ipp.Port) + target := &net.OpError{} + require.ErrorAs(t, err, &target) - assert.Equal(t, "listen", target.Op) + assert.Equal(t, "listen", target.Op) + }) + + t.Run("udp_bound", func(t *testing.T) { + conn, err := net.ListenPacket("udp", "127.0.0.1:") + require.NoError(t, err) + testutil.CleanupAndRequireSuccess(t, conn.Close) + + ipp := netutil.IPPortFromAddr(conn.LocalAddr()) + require.NotNil(t, ipp) + require.NotNil(t, ipp.IP) + require.NotZero(t, ipp.Port) + + err = CheckPort("udp", ipp.IP, ipp.Port) + target := &net.OpError{} + require.ErrorAs(t, err, &target) + + assert.Equal(t, "listen", target.Op) + }) + + t.Run("bad_network", func(t *testing.T) { + err := CheckPort("bad_network", nil, 0) + assert.NoError(t, err) + }) + + t.Run("can_bind", func(t *testing.T) { + err := CheckPort("udp", net.IP{0, 0, 0, 0}, 0) + assert.NoError(t, err) + }) } From 41e8db4221dbdce9940e927e4dc5db0a484f564f Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Mon, 24 Jan 2022 15:02:47 +0300 Subject: [PATCH 097/135] Pull request: client: upd i18n Merge in DNS/adguard-home from upd-i18n to master Squashed commit of the following: commit e3dfb6cd66813d45591f74c9cdddab8b61143db3 Author: Eugene Burkov Date: Mon Jan 24 14:52:19 2022 +0300 client: upd i18n --- client/src/__locales/be.json | 13 +++++++---- client/src/__locales/cs.json | 2 +- client/src/__locales/da.json | 2 +- client/src/__locales/es.json | 2 +- client/src/__locales/fa.json | 2 +- client/src/__locales/fi.json | 8 +++---- client/src/__locales/hr.json | 2 +- client/src/__locales/hu.json | 2 +- client/src/__locales/it.json | 16 ++++++------- client/src/__locales/nl.json | 2 +- client/src/__locales/pl.json | 2 +- client/src/__locales/pt-br.json | 2 +- client/src/__locales/pt-pt.json | 2 +- client/src/__locales/ro.json | 2 +- client/src/__locales/ru.json | 4 ++-- client/src/__locales/sk.json | 6 ++--- client/src/__locales/sv.json | 6 +++-- client/src/__locales/tr.json | 41 +++++++++++++++++---------------- client/src/__locales/uk.json | 2 +- client/src/__locales/zh-cn.json | 4 ++-- client/src/__locales/zh-tw.json | 4 ++-- 21 files changed, 66 insertions(+), 60 deletions(-) diff --git a/client/src/__locales/be.json b/client/src/__locales/be.json index 33ceba4f..10079eb1 100644 --- a/client/src/__locales/be.json +++ b/client/src/__locales/be.json @@ -163,8 +163,8 @@ "apply_btn": "Ужыць", "disabled_filtering_toast": "Фільтрацыя выкл.", "enabled_filtering_toast": "Фільтрацыя ўкл.", - "disabled_safe_browsing_toast": "Бяспечная навігацыя выкл.", - "enabled_safe_browsing_toast": "Бяспечная навігацыя ўкл.", + "disabled_safe_browsing_toast": "Бяспечная навігацыя выключана", + "enabled_safe_browsing_toast": "Бяспечная навігацыя ўключана", "disabled_parental_toast": "Бацькоўскі кантроль выкл.", "enabled_parental_toast": "Бацькоўскі кантроль укл.", "disabled_safe_search_toast": "Бяспечны пошук выкл.", @@ -200,6 +200,7 @@ "form_error_url_or_path_format": "Няслушны URL ці абсалютны шлях да спіса", "custom_filter_rules": "Карыстацкае рэдагавала фільтрацыі", "custom_filter_rules_hint": "Уводзьце па адным правіле на радок. Вы можаце выкарыстоўваць правілы блакавання ці сінтаксіс файлаў hosts.", + "system_host_files": "Сістэмныя hosts-файлы", "examples_title": "Прыклады", "example_meaning_filter_block": "заблакаваць доступ да дамена example.org і ўсім яго паддаменам", "example_meaning_filter_whitelist": "адблакаваць доступ да дамена example.org і ўсім яго паддаменам", @@ -586,8 +587,8 @@ "show_blocked_responses": "Заблакавана", "show_whitelisted_responses": "Белы спіс", "show_processed_responses": "Апрацавана", - "blocked_safebrowsing": "Заблакавана згодна базе дадзеных Safebrowsing", - "blocked_adult_websites": "Заблакаваныя \"дарослыя\" сайты", + "blocked_safebrowsing": "Заблакавана згодна базе дадзеных Safe Browsing", + "blocked_adult_websites": "Заблакавана Бацькоўскім кантролем", "blocked_threats": "Заблакавана пагроз", "allowed": "Дазволены", "filtered": "Адфільтраваныя", @@ -624,5 +625,7 @@ "last_rule_in_allowlist": "Няможна заблакаваць гэтага кліента, бо вынятак правіла «{{disallowed_rule}}» АДКЛЮЧЫЦЬ рэжым белага спіса.", "experimental": "Эксперыментальны", "use_saved_key": "Скарыстаць захаваны раней ключ", - "parental_control": "Бацькоўскі кантроль" + "parental_control": "Бацькоўскі кантроль", + "safe_browsing": "Бяспечны інтэрнэт", + "served_from_cache": "{{value}} (атрымана з кэша)" } diff --git a/client/src/__locales/cs.json b/client/src/__locales/cs.json index d03a4b89..67f9a7e5 100644 --- a/client/src/__locales/cs.json +++ b/client/src/__locales/cs.json @@ -43,7 +43,7 @@ "form_error_ip6_format": "Neplatná adresa IPv6", "form_error_ip_format": "Neplatná adresa IP", "form_error_mac_format": "Neplatná adresa MAC", - "form_error_client_id_format": "Neplatné ID klienta", + "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", diff --git a/client/src/__locales/da.json b/client/src/__locales/da.json index 5769b4c5..eb5b3c2f 100644 --- a/client/src/__locales/da.json +++ b/client/src/__locales/da.json @@ -43,7 +43,7 @@ "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": "Ugyldigt klient-ID", + "form_error_client_id_format": "Klient-ID må kun indeholde cifre, minuskler og bindestreger", "form_error_server_name": "Ugyldigt servernavn", "form_error_subnet": "Subnet \"{{cidr}}\" indeholder ikke IP-adressen \"{{ip}}\"", "form_error_positive": "Skal være større end 0", diff --git a/client/src/__locales/es.json b/client/src/__locales/es.json index ee040ff4..d6702989 100644 --- a/client/src/__locales/es.json +++ b/client/src/__locales/es.json @@ -43,7 +43,7 @@ "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": "ID de cliente no válido", + "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", diff --git a/client/src/__locales/fa.json b/client/src/__locales/fa.json index 77de4a78..90b07629 100644 --- a/client/src/__locales/fa.json +++ b/client/src/__locales/fa.json @@ -17,7 +17,7 @@ "form_error_required": "فیلد مورد نیاز", "form_error_ip4_format": "فرمت نامعتبر IPv4", "form_error_ip6_format": "فرمت نامعتبر IPv6", - "form_error_ip_format": "فرمت IPv4 نامعتبر است", + "form_error_ip_format": "آدرس آی پی نامعتبر است", "form_error_mac_format": "فرمت مَک نامعتبر است", "form_error_client_id_format": "فرمت شناسه کلاینت نامعتبر است", "form_error_positive": "باید بزرگتر از 0 باشد", diff --git a/client/src/__locales/fi.json b/client/src/__locales/fi.json index 52e89e9e..8228f1f6 100644 --- a/client/src/__locales/fi.json +++ b/client/src/__locales/fi.json @@ -43,7 +43,7 @@ "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": "Virheellinen päätelaitteen ID", + "form_error_client_id_format": "Päätelaitteen tunniste 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", @@ -603,9 +603,9 @@ "enter_cache_size": "Syötä välimuistin koko (tavuina)", "enter_cache_ttl_min_override": "Syötä vähimmäis-TTL (sekunteina)", "enter_cache_ttl_max_override": "Syötä enimmäis-TTL (sekunteina)", - "cache_ttl_min_override_desc": "Pidennä ylävirran palvelimelta vastaanotettuja, lyhyitä time-to-live -arvoja (sekunteina) tallennettaessa DNS-vastauksia välimuistiin.", - "cache_ttl_max_override_desc": "Määritä DNS-välimuistin kohteiden suurin time-to-live -arvo (sekunteina)", - "ttl_cache_validation": "Välimuistin TTL-vähimmäisarvon tulee olla pienempi tai sama kuin enimmäisarvon", + "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 suurin elinaika-arvo (sekunteina)", + "ttl_cache_validation": "Välimuistin elinajan vähimmäisarvon tulee olla pienempi tai sama kuin enimmäisarvon", "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", diff --git a/client/src/__locales/hr.json b/client/src/__locales/hr.json index 792500cf..23de5e17 100644 --- a/client/src/__locales/hr.json +++ b/client/src/__locales/hr.json @@ -163,7 +163,7 @@ "apply_btn": "Primijeni", "disabled_filtering_toast": "Onemogućeno filtriranje", "enabled_filtering_toast": "Omogućeno filtriranje", - "disabled_safe_browsing_toast": "Onemogućena sigurna pretraga", + "disabled_safe_browsing_toast": "Onemogućena Sigurna pretraga", "enabled_safe_browsing_toast": "Omogućena sigurna pretraga", "disabled_parental_toast": "Onemogućen roditeljski nadzor", "enabled_parental_toast": "Omogućen roditeljski nadzor", diff --git a/client/src/__locales/hu.json b/client/src/__locales/hu.json index 1b418c7e..21726a30 100644 --- a/client/src/__locales/hu.json +++ b/client/src/__locales/hu.json @@ -36,7 +36,7 @@ "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 formátum", + "form_error_ip4_format": "Érvénytelen IPv4 cím", "form_error_ip6_format": "Érvénytelen IPv6 formátum", "form_error_ip_format": "Érvénytelen IP-cím", "form_error_mac_format": "Érvénytelen MAC formátum", diff --git a/client/src/__locales/it.json b/client/src/__locales/it.json index e9573070..35e1e30f 100644 --- a/client/src/__locales/it.json +++ b/client/src/__locales/it.json @@ -43,7 +43,7 @@ "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": "ID cliente non valido", + "form_error_client_id_format": "Il client ID deve contenere solo numeri, lettere minuscole e trattini", "form_error_server_name": "Nome server non valido", "form_error_subnet": "La subnet \"{{cidr}}\" non contiene l'indirizzo IP \"{{ip}}\"", "form_error_positive": "Deve essere maggiore di 0", @@ -295,16 +295,16 @@ "blocking_mode_null_ip": "IP nullo: Rispondi con indirizzo IP zero (0.0.0.0 per A; :: per AAAA)", "blocking_mode_custom_ip": "IP personalizzato: Rispondi con un indirizzo IP impostato manualmente", "upstream_dns_client_desc": "Se lasci questo spazio vuoto, AdGuard Home utilizzerà i server configurati nelle <0>impostazioni DNS.", - "tracker_source": "Origine tracciante", + "tracker_source": "Origine del tracciatore", "source_label": "Fonte", - "found_in_known_domain_db": "Trovato nel database dei domini conosciuti.", + "found_in_known_domain_db": "Trovato nel database dei domini noti.", "category_label": "Categoria", "rule_label": "Regola(e)", "list_label": "Elenco", "unknown_filter": "Filtro sconosciuto {{filterId}}", - "known_tracker": "Tracciante noto", + "known_tracker": "Tracciatore noto", "install_welcome_title": "Benvenuto nella Home di AdGuard!", - "install_welcome_desc": "AdGuard Home è un server DNS che blocca annunci e traccianti in tutta la rete. Il suo scopo è quello di consentire di controllare l'intera rete e tutti i dispositivi, e non richiede l'utilizzo di un programma sul lato client.", + "install_welcome_desc": "AdGuard Home è un server DNS che blocca annunci e tracciatori a livello di rete. Il suo scopo è quello di permetterti il controllo dell'intera rete e di tutti i dispositivi, e non richiede l'utilizzo di un programma lato client.", "install_settings_title": "Interfaccia Web dell'Admin", "install_settings_listen": "Interfaccia d'ascolto", "install_settings_port": "Porta", @@ -400,7 +400,7 @@ "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 conosciuti da cui scegliere.", + "dns_providers": "Qui c'è un <0>elenco di fornitori DNS noti da cui scegliere.", "update_now": "Aggiorna ora", "update_failed": "Aggiornamento automatico non riuscito. Ti suggeriamo di seguire questi passaggi per aggiornare manualmente.", "processing_update": "Perfavore aspetta, AdGuard Home si sta aggiornando", @@ -612,9 +612,9 @@ "filter_category_security": "Sicurezza", "filter_category_regional": "Regionale", "filter_category_other": "Altro", - "filter_category_general_desc": "Elenchi per il blocco dei traccianti e degli annunci sulla maggioranza dei dispositivi", + "filter_category_general_desc": "Elenchi per il blocco dei tracciatori e degli annunci sulla maggioranza dei dispositivi", "filter_category_security_desc": "Elenchi progettati specificamente per bloccare domini malevoli, di phishing o truffa", - "filter_category_regional_desc": "Elenchi focalizzati su annunci regionali e server traccianti", + "filter_category_regional_desc": "Elenchi focalizzati su annunci regionali e server tracciatori", "filter_category_other_desc": "Altre liste nere", "setup_config_to_enable_dhcp_server": "Configurazione dell'installazione per l'attivazione del server DHCP", "original_response": "Responso originale", diff --git a/client/src/__locales/nl.json b/client/src/__locales/nl.json index a109d677..03c471f3 100644 --- a/client/src/__locales/nl.json +++ b/client/src/__locales/nl.json @@ -43,7 +43,7 @@ "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": "Ongeldige cliënt-ID", + "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", diff --git a/client/src/__locales/pl.json b/client/src/__locales/pl.json index 6aa16e94..76ce7da6 100644 --- a/client/src/__locales/pl.json +++ b/client/src/__locales/pl.json @@ -43,7 +43,7 @@ "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": "Nieprawidłowy ID klienta", + "form_error_client_id_format": "ID klienta 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", diff --git a/client/src/__locales/pt-br.json b/client/src/__locales/pt-br.json index 2d60d451..f628edb9 100644 --- a/client/src/__locales/pt-br.json +++ b/client/src/__locales/pt-br.json @@ -43,7 +43,7 @@ "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": "ID de cliente 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", diff --git a/client/src/__locales/pt-pt.json b/client/src/__locales/pt-pt.json index 38772d53..c3f82f45 100644 --- a/client/src/__locales/pt-pt.json +++ b/client/src/__locales/pt-pt.json @@ -43,7 +43,7 @@ "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": "ID de cliente 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", diff --git a/client/src/__locales/ro.json b/client/src/__locales/ro.json index c6a40421..5ada95cb 100644 --- a/client/src/__locales/ro.json +++ b/client/src/__locales/ro.json @@ -43,7 +43,7 @@ "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": "ID client nevalid", + "form_error_client_id_format": "ID-ul clientului trebuie să conțină numai numere, litere minuscule și liniuțe.", "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", diff --git a/client/src/__locales/ru.json b/client/src/__locales/ru.json index 51046eae..55321ebb 100644 --- a/client/src/__locales/ru.json +++ b/client/src/__locales/ru.json @@ -43,7 +43,7 @@ "form_error_ip6_format": "Некорректный IPv6-адрес", "form_error_ip_format": "Некорректный IP-адрес", "form_error_mac_format": "Некорректный MAC-адрес", - "form_error_client_id_format": "Некорректный ID клиента", + "form_error_client_id_format": "ID клиента может содержать только цифры, строчные латинские буквы и дефисы", "form_error_server_name": "Некорректное имя сервера", "form_error_subnet": "Подсеть «{{cidr}}» не содержит IP-адрес «{{ip}}»", "form_error_positive": "Должно быть больше 0", @@ -587,7 +587,7 @@ "show_blocked_responses": "Заблокировано", "show_whitelisted_responses": "В белом списке", "show_processed_responses": "Обработан", - "blocked_safebrowsing": "Заблокировано согласно базе данных Safebrowsing", + "blocked_safebrowsing": "Заблокировано согласно базе данных Safe Browsing", "blocked_adult_websites": "Заблокировано Родительским контролем", "blocked_threats": "Заблокировано угроз", "allowed": "Разрешённые", diff --git a/client/src/__locales/sk.json b/client/src/__locales/sk.json index f445e688..44efcb52 100644 --- a/client/src/__locales/sk.json +++ b/client/src/__locales/sk.json @@ -163,8 +163,8 @@ "apply_btn": "Použiť", "disabled_filtering_toast": "Vypnutá filtrácia", "enabled_filtering_toast": "Zapnutá filtrácia", - "disabled_safe_browsing_toast": "Vypnuté Bezpečné prehliadanie", - "enabled_safe_browsing_toast": "Zapnuté Bezpečné prehliadanie", + "disabled_safe_browsing_toast": "Bezpečné prehliadanie vypnuté", + "enabled_safe_browsing_toast": "Bezpečné prehliadanie zapnuté", "disabled_parental_toast": "Vypnutá Rodičovská kontrola", "enabled_parental_toast": "Zapnutá Rodičovská kontrola", "disabled_safe_search_toast": "Vypnuté bezpečné vyhľadávanie", @@ -588,7 +588,7 @@ "show_whitelisted_responses": "Obsiahnuté v bielej listine", "show_processed_responses": "Spracované", "blocked_safebrowsing": "Zablokované modulom Bezpečné prehliadanie", - "blocked_adult_websites": "Blokované Rodičovskou kontrolou", + "blocked_adult_websites": "Zablokovaná stránka pre dospelých", "blocked_threats": "Zablokované hrozby", "allowed": "Povolené", "filtered": "Filtrované", diff --git a/client/src/__locales/sv.json b/client/src/__locales/sv.json index dc25417f..72349474 100644 --- a/client/src/__locales/sv.json +++ b/client/src/__locales/sv.json @@ -16,6 +16,8 @@ "dhcp_static_leases": "Statiska DHCP-leases", "dhcp_leases_not_found": "Ingen DHCP-lease hittad", "form_error_required": "Obligatoriskt fält", + "form_error_ip4_format": "Ogiltig IPv4-adress", + "form_error_ip6_format": "Ogiltig IPv6-adress", "form_error_ip_format": "Ogiltig IP-adress", "form_error_mac_format": "Ogiltig MAC-adress", "form_error_positive": "Måste vara större än noll", @@ -351,7 +353,7 @@ "show_blocked_responses": "Blockerade", "show_whitelisted_responses": "Vitlistade", "show_processed_responses": "Utförda", - "blocked_adult_websites": "Blockerad av Föräldrakontrollen", + "blocked_adult_websites": "Blockerad av Föräldrakontroll", "blocked_threats": "Blockerade hot", "allowed": "Vitlistade", "safe_search": "Säker surf", @@ -359,5 +361,5 @@ "filter_category_security": "säkerhet", "filter_category_other": "Övrigt", "use_saved_key": "Använd den tidigare sparade nyckeln", - "parental_control": "Föräldrarkontroll" + "parental_control": "Föräldrakontroll" } diff --git a/client/src/__locales/tr.json b/client/src/__locales/tr.json index c4f4fbb9..a761e233 100644 --- a/client/src/__locales/tr.json +++ b/client/src/__locales/tr.json @@ -43,7 +43,7 @@ "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 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", @@ -53,7 +53,7 @@ "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'si", + "dhcp_form_gateway_input": "Ağ geçidi IP", "dhcp_form_subnet_input": "Alt ağ maskesi", "dhcp_form_range_title": "IP adresi aralığı", "dhcp_form_range_start": "Başlangıç aralığı", @@ -138,7 +138,7 @@ "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", - "filters_block_toggle_hint": "Filtreler sayfasından engelleme kurallarını ayarlayabilirsiniz.", + "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.", "use_adguard_parental": "AdGuard ebeveyn denetimi web hizmetini kullan", @@ -165,10 +165,10 @@ "enabled_filtering_toast": "Filtreleme etkin", "disabled_safe_browsing_toast": "Güvenli Gezinti devre dışı bırakıldı", "enabled_safe_browsing_toast": "Güvenli Gezinti etkinleştirildi", - "disabled_parental_toast": "Ebeveyn denetimi devre dışı", - "enabled_parental_toast": "Ebeveyn denetimi etkin", - "disabled_safe_search_toast": "Güvenli arama devre dışı", - "enabled_save_search_toast": "Güvenli arama etkin", + "disabled_parental_toast": "Ebeveyn denetimi devre dışı bırakıldı", + "enabled_parental_toast": "Ebeveyn denetimi etkinleştirildi", + "disabled_safe_search_toast": "Güvenli arama devre dışı bırakıldı", + "enabled_save_search_toast": "Güvenli arama etkinleştirildi", "enabled_table_header": "Etkin", "name_table_header": "İsim", "list_url_table_header": "Liste URL'si", @@ -178,7 +178,7 @@ "request_table_header": "İstek", "edit_table_action": "Düzenle", "delete_table_action": "Sil", - "elapsed": "Geçen zaman", + "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.", "no_blocklist_added": "Engel listesi eklenmedi", "no_whitelist_added": "İzin listesi eklenmedi", @@ -327,10 +327,10 @@ "install_submit_desc": "Yükleme işlemi tamamlandı ve artık AdGuard Home'u kullanmaya hazırsınız.", "install_devices_router": "Yönlendirici", "install_devices_router_desc": "Bu kurulum, ev yönlendiricinize bağlı tüm cihazları otomatik olarak kapsar ve her birini elle yapılandırmanıza gerek yoktur.", - "install_devices_address": "AdGuard Home DNS sunucusu şu adresi dinleyecektir", + "install_devices_address": "AdGuard Home DNS sunucusu aşağıdaki adresleri dinliyor", "install_devices_router_list_1": "Yönlendiricinizin ayarlarına gidin. Genellikle tarayıcınızdan http://192.168.0.1/ veya http://192.168.1.1/ gibi bir URL aracılığıyla erişebilirsiniz. Bir parola girmeniz istenebilir. Hatırlamıyorsanız, genellikle yönlendiricinin üzerindeki bir düğmeye basarak parolayı sıfırlayabilirsiniz, ancak bu işlemin seçilmesi durumunda yüksek ihtimalle tüm yönlendirici yapılandırmasını kaybedeceğinizi unutmayın. Yönlendiricinizin kurulumu için bir uygulama gerekiyorsa, lütfen uygulamayı telefonunuza veya PC'nize yükleyin ve yönlendiricinin ayarlarına erişmek için kullanın.", "install_devices_router_list_2": "DHCP/DNS ayarlarını bulun. DNS satırlarını arayın, genelde iki veya üç tanedir, üç rakam girilebilen dört ayrı grup içeren satırdır.", - "install_devices_router_list_3": "AdGuard Home sunucusunun adresini o kısma yazın.", + "install_devices_router_list_3": "AdGuard Home sunucu adreslerinizi oraya girin.", "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.", @@ -339,15 +339,15 @@ "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.", "install_devices_macos_list_1": "Apple simgesinde bulunan Sistem Tercihleri'ne tıklayın.", - "install_devices_macos_list_2": "Ağ seçeneğine tıklayın.", + "install_devices_macos_list_2": "Ağ'a 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 cihazınızda Ayarlar simgesine dokunun.", + "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_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.", - "install_devices_ios_list_1": "Ana ekrandaki Ayarlar simgesine dokunun.", + "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_4": "DNS alanına AdGuard Home sunucunuzun adreslerini girin.", @@ -386,8 +386,8 @@ "encryption_issuer": "Sağlayan", "encryption_hostnames": "Ana bilgisayar adları", "encryption_reset": "Şifreleme ayarlarını sıfırlamak istediğinizden emin misiniz?", - "topline_expiring_certificate": "SSL sertifikanızın süresi dolmak üzere. <0>Şifreleme ayarlarını güncelleyin.", - "topline_expired_certificate": "SSL sertifikanızın süresi doldu. <0>Şifreleme ayarlarını güncelleyin.", + "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ı", @@ -417,7 +417,7 @@ "client_identifier": "Tanımlayıcı", "ip_address": "IP adresi", "client_identifier_desc": "İstemciler IP adresi, CIDR, MAC adresi veya özel bir istemci kimliği ile tanımlanabilir (DoT/DoH/DoQ için kullanılabilir). İstemcileri nasıl tanımlayacağınız hakkında daha fazla bilgiyi <0>burada bulabilirsiniz.", - "form_enter_ip": "IP adresi girin", + "form_enter_ip": "IP girin", "form_enter_subnet_ip": "\"{{cidr}}\" alt ağına bir IP adresi girin", "form_enter_mac": "MAC adresi girin", "form_enter_id": "Tanımlayıcı girin", @@ -439,7 +439,7 @@ "access_allowed_desc": "CIDR'lerin, IP adreslerinin veya istemci kimliklerinin listesi. Yapılandırılırsa, AdGuard Home yalnızca bu istemcilerden gelen istekleri kabul eder.", "access_disallowed_title": "İzin verilmeyen istemciler", "access_disallowed_desc": "CIDR'lerin, IP adreslerinin veya istemci kimliklerinin listesi. Yapılandırılırsa, AdGuard Home bu istemcilerden gelen istekleri keser. İzin verilen istemciler yapılandırılırsa, bu alan yok sayılır.", - "access_blocked_title": "Engellenen alan adları", + "access_blocked_title": "İzin verilmeyen alan adları", "access_blocked_desc": "Bu işlem filtrelerle ilgili değildir. AdGuard Home, bu alan adlarından gelen DNS sorgularını yanıtsız bırakır ve bu sorgular sorgu günlüğünde görünmez. Tam alan adlarını, joker karakterleri veya URL filtre kurallarını belirtebilirsiniz, ör. \"example.org\", \"*.example.org\" veya \"||example.org^\".", "access_settings_saved": "Erişim ayarları başarıyla kaydedildi!", "updates_checked": "Güncelleme kontrolü başarılı", @@ -601,8 +601,8 @@ "cache_ttl_min_override": "Minimum TTL'i değiştir", "cache_ttl_max_override": "Maksimum TTL'i değiştir", "enter_cache_size": "Önbellek boyutunu girin (bayt)", - "enter_cache_ttl_min_override": "Minimum TTL değerini girin (saniye)", - "enter_cache_ttl_max_override": "Maksimum TTL değerini girin (saniye)", + "enter_cache_ttl_min_override": "Minimum TTL değerini girin (saniye olarak)", + "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 değeri, maksimum değerden küçük veya bu değere eşit olmalıdır", @@ -626,5 +626,6 @@ "experimental": "Deneysel", "use_saved_key": "Önceden kaydedilmiş anahtarı kullan", "parental_control": "Ebeveyn Denetimi", - "safe_browsing": "Güvenli Gezinti" + "safe_browsing": "Güvenli Gezinti", + "served_from_cache": "{{value}} (önbellekten kullanıldı)" } diff --git a/client/src/__locales/uk.json b/client/src/__locales/uk.json index ffcd1d7d..42db7636 100644 --- a/client/src/__locales/uk.json +++ b/client/src/__locales/uk.json @@ -43,7 +43,7 @@ "form_error_ip6_format": "Неправильна IPv6-адреса", "form_error_ip_format": "Неправильна IP-адреса", "form_error_mac_format": "Неправильна MAC-адреса", - "form_error_client_id_format": "Неправильний ID клієнта", + "form_error_client_id_format": "ID клієнта має містити лише цифри, малі букви та дефіси", "form_error_server_name": "Неправильна назва сервера", "form_error_subnet": "Підмережа «{{cidr}}» не містить IP-адресу «{{ip}}»", "form_error_positive": "Повинно бути більше 0", diff --git a/client/src/__locales/zh-cn.json b/client/src/__locales/zh-cn.json index f51a51bd..28fc7d63 100644 --- a/client/src/__locales/zh-cn.json +++ b/client/src/__locales/zh-cn.json @@ -43,7 +43,7 @@ "form_error_ip6_format": "无效的 IPv6 地址", "form_error_ip_format": "无效的 IP 地址", "form_error_mac_format": "无效的 MAC 地址", - "form_error_client_id_format": "无效的客户端 ID", + "form_error_client_id_format": "无效的客户端 ID 格式客户 ID 必须只包含数字、小写字母和连字符", "form_error_server_name": "无效的服务器名", "form_error_subnet": "子网 \"{{cidr}}\" 不包含 IP 地址 \"{{ip}}\"", "form_error_positive": "必须大于 0", @@ -588,7 +588,7 @@ "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-tw.json b/client/src/__locales/zh-tw.json index cc44a2cf..2358a49b 100644 --- a/client/src/__locales/zh-tw.json +++ b/client/src/__locales/zh-tw.json @@ -43,7 +43,7 @@ "form_error_ip6_format": "無效的 IPv6 位址", "form_error_ip_format": "無效的 IP 位址", "form_error_mac_format": "無效的媒體存取控制(MAC)位址", - "form_error_client_id_format": "無效的用戶端 ID", + "form_error_client_id_format": "用戶端 ID 必須只包含數值、小寫字母和連字號", "form_error_server_name": "無效的伺服器名稱", "form_error_subnet": "子網路 \"{{cidr}}\" 不包含該 IP 位址 \"{{ip}}\"", "form_error_positive": "必須大於 0", @@ -146,7 +146,7 @@ "enforce_safe_search": "使用安全搜尋", "enforce_save_search_hint": "AdGuard Home 將在下列的搜尋引擎:Google、YouTube、Bing、DuckDuckGo、Yandex 和 Pixabay 中強制執行安全搜尋。", "no_servers_specified": "無已明確指定的伺服器", - "general_settings": "一般的設定", + "general_settings": "一般設定", "dns_settings": "DNS 設定", "dns_blocklists": "DNS 封鎖清單", "dns_allowlists": "DNS 允許清單", From 3e2ab87293d9d75abe9c2f63d52da701d5599142 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Mon, 24 Jan 2022 17:39:39 +0300 Subject: [PATCH 098/135] Pull request: all: upd dnsproxy Merge in DNS/adguard-home from imp-logs to master Squashed commit of the following: commit bff4c3757b61db63320af72e1af56649f6f70a50 Author: Ainar Garipov Date: Mon Jan 24 17:25:34 2022 +0300 all: upd dnsproxy --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index e1fef011..64c4923d 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.40.5 + github.com/AdguardTeam/dnsproxy v0.40.6 github.com/AdguardTeam/golibs v0.10.4 github.com/AdguardTeam/urlfilter v0.15.2 github.com/NYTimes/gziphandler v1.1.1 diff --git a/go.sum b/go.sum index cd2a6179..b1a82f12 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.40.5 h1:727KSGRmzq2DB5dMm093g0Guhc3dzzzMbfB0C9hK0s8= -github.com/AdguardTeam/dnsproxy v0.40.5/go.mod h1:PZ9l22h3Er+5mxFQB7oHZMTvx+aa9R6LbzA/ikXQlS0= +github.com/AdguardTeam/dnsproxy v0.40.6 h1:cTyzjiDrTk4vOXixLsWZ4Xjpqy6pqjTY++Tndq3bEf4= +github.com/AdguardTeam/dnsproxy v0.40.6/go.mod h1:PZ9l22h3Er+5mxFQB7oHZMTvx+aa9R6LbzA/ikXQlS0= 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.3/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw= From f12eaf29a276003fd41861d4ffa59c969736ba25 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Tue, 25 Jan 2022 14:08:41 +0300 Subject: [PATCH 099/135] Pull request: client: upd i18n Updates #2643. Squashed commit of the following: commit bd6bc0aeaa1bd928ae39642691b913befbc0f396 Author: Ainar Garipov Date: Tue Jan 25 14:04:10 2022 +0300 client: upd i18n --- client/src/__locales/de.json | 20 +-- client/src/__locales/fr.json | 6 +- client/src/__locales/hr.json | 6 +- client/src/__locales/hu.json | 24 ++- client/src/__locales/id.json | 31 +++- client/src/__locales/ja.json | 6 +- client/src/__locales/ko.json | 8 +- client/src/__locales/sk.json | 2 +- client/src/__locales/sl.json | 2 +- client/src/__locales/sv.json | 294 ++++++++++++++++++++++++++++++-- client/src/__locales/zh-tw.json | 2 +- 11 files changed, 351 insertions(+), 50 deletions(-) diff --git a/client/src/__locales/de.json b/client/src/__locales/de.json index ff300daa..559deb15 100644 --- a/client/src/__locales/de.json +++ b/client/src/__locales/de.json @@ -43,7 +43,7 @@ "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": "Ungültiges Client-ID", + "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 (Null) sein", @@ -70,9 +70,9 @@ "dhcp_error": "AdGuard Home konnte nicht ermitteln, ob es einen anderen aktiven DHCP-Server im Netzwerk gibt.", "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": "Statischer Zuweisung „{{key}}“ erfolgreich hinzugefügt", + "dhcp_lease_added": "Statische Zuweisung „{{key}}“ erfolgreich hinzugefügt", "dhcp_lease_deleted": "Statische Zuweisung „{{key}}“ erfolgreich entfernt", - "dhcp_new_static_lease": "Neuer statischer Zuweisung", + "dhcp_new_static_lease": "Neue statische Zuweisung", "dhcp_static_leases_not_found": "Keine statischen DHCP-Zuweisungen gefunden", "dhcp_add_static_lease": "Statische Zuweisung hinzufügen", "dhcp_reset_leases": "Alle Zuweisungen zurücksetzen", @@ -133,8 +133,8 @@ "number_of_dns_query_blocked_24_hours": "Anzahl der durch Werbefilter und Host-Sperrlisten abgelehnte DNS-Anfragen", "number_of_dns_query_blocked_24_hours_by_sec": "Anzahl der durch das AdGuard-Modul „Internetsicherheit“ gesperrten DNS-Anfragen", "number_of_dns_query_blocked_24_hours_adult": "Anzahl der gesperrten Websites mit jugendgefährdenden Inhalten", - "enforced_save_search": "SafeSearch erzwungen", - "number_of_dns_query_to_safe_search": "Anzahl der DNS-Anfragen bei denen SafeSearch für Suchanfragen erzwungen wurde", + "enforced_save_search": "Sichere Suche erzwungen", + "number_of_dns_query_to_safe_search": "Anzahl der DNS-Anfragen bei denen Sichere Suche für Suchanfragen erzwungen wurde", "average_processing_time": "Durchschnittliche Bearbeitungsdauer", "average_processing_time_hint": "Durchschnittliche Zeit in Millisekunden zur Bearbeitung von DNS-Anfragen", "block_domain_use_filters_and_hosts": "Domains durch Filter und Host-Dateien sperren", @@ -143,8 +143,8 @@ "use_adguard_browsing_sec_hint": "AdGuard Home prüft, ob die Domain durch den Webdienst für Internetsicherheit auf eine Sperrliste gesetzt wurde. Es verwendet eine datenschutzfreundliche Lookup-API, um die Prüfung durchzuführen: Nur ein kurzes Präfix des Domänennamens SHA256-Hash wird an den Server gesendet.", "use_adguard_parental": "AdGuard Webservice für Kindersicherung verwenden", "use_adguard_parental_hint": "AdGuard Home wird prüfen, ob die Domain jugendgefährdende Inhalte enthält. Zum Schutz Ihrer Privatsphäre wird die selbe API wie für den Webservice für Internetsicherheit verwendet.", - "enforce_safe_search": "SafeSearch erzwingen", - "enforce_save_search_hint": "AdGuard kann SafeSearch für folgende Suchmaschinen erzwingen: Google, YouTube, Bing, DuckDuckGo, Yandex und Pixabay.", + "enforce_safe_search": "Sichere Suche verwenden", + "enforce_save_search_hint": "AdGuard kann Sichere Suche für folgende Suchmaschinen erzwingen: Google, YouTube, Bing, DuckDuckGo, Yandex und Pixabay.", "no_servers_specified": "Keine Server festgelegt", "general_settings": "Allgemeine Einstellungen", "dns_settings": "DNS-Einstellungen", @@ -167,8 +167,8 @@ "enabled_safe_browsing_toast": "Internetsicherheit aktiviert", "disabled_parental_toast": "Kindersicherung deaktiviert", "enabled_parental_toast": "Kindersicherung aktiviert", - "disabled_safe_search_toast": "SafeSearch deaktiviert", - "enabled_save_search_toast": "SafeSearch aktiviert", + "disabled_safe_search_toast": "Sichere Suche deaktiviert", + "enabled_save_search_toast": "Sichere Suche aktiviert", "enabled_table_header": "Aktiviert", "name_table_header": "Name", "list_url_table_header": "Adressliste", @@ -626,6 +626,6 @@ "experimental": "Experimentell", "use_saved_key": "Zuvor gespeicherten Schlüssel verwenden", "parental_control": "Kindersicherung", - "safe_browsing": "Sicheres Surfen", + "safe_browsing": "Internetsicherheit", "served_from_cache": "{{value}} (aus dem Zwischenspeicher abgerufen)" } diff --git a/client/src/__locales/fr.json b/client/src/__locales/fr.json index 4329bc37..e84ce1c4 100644 --- a/client/src/__locales/fr.json +++ b/client/src/__locales/fr.json @@ -43,7 +43,7 @@ "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": "Identifiant de client 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", @@ -163,8 +163,8 @@ "apply_btn": "Appliquer", "disabled_filtering_toast": "Filtrage désactivé", "enabled_filtering_toast": "Filtrage activé", - "disabled_safe_browsing_toast": "Surfing sécurisé désactivé", - "enabled_safe_browsing_toast": "Surfing sécurisé activé", + "disabled_safe_browsing_toast": "Navigation sécurisée désactivée", + "enabled_safe_browsing_toast": "Navigation sécurisée activée", "disabled_parental_toast": "Contrôle parental désactivé", "enabled_parental_toast": "Contrôle parental activé", "disabled_safe_search_toast": "Recherche sécurisée désactivée", diff --git a/client/src/__locales/hr.json b/client/src/__locales/hr.json index 23de5e17..e7642fd2 100644 --- a/client/src/__locales/hr.json +++ b/client/src/__locales/hr.json @@ -43,7 +43,7 @@ "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_client_id_format": "Nevažeći format ID-a klijenta", + "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}}\"", "form_error_positive": "Mora biti veće od 0", @@ -164,7 +164,7 @@ "disabled_filtering_toast": "Onemogućeno filtriranje", "enabled_filtering_toast": "Omogućeno filtriranje", "disabled_safe_browsing_toast": "Onemogućena Sigurna pretraga", - "enabled_safe_browsing_toast": "Omogućena sigurna pretraga", + "enabled_safe_browsing_toast": "Omogućena Sigurna pretraga", "disabled_parental_toast": "Onemogućen roditeljski nadzor", "enabled_parental_toast": "Omogućen roditeljski nadzor", "disabled_safe_search_toast": "Onemogućeno sigurno pretraživanje", @@ -588,7 +588,7 @@ "show_whitelisted_responses": "Na popisu dopuštenih", "show_processed_responses": "Obrađeno", "blocked_safebrowsing": "Blokirano s Sigurnom pretragom", - "blocked_adult_websites": "Blokirala roditeljska zaštita", + "blocked_adult_websites": "Blokirano Roditeljskom kontrolom", "blocked_threats": "Blokirane prijetnje", "allowed": "Dopušteno", "filtered": "Filtrirano", diff --git a/client/src/__locales/hu.json b/client/src/__locales/hu.json index 21726a30..6c876315 100644 --- a/client/src/__locales/hu.json +++ b/client/src/__locales/hu.json @@ -37,13 +37,22 @@ "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_ip6_format": "Érvénytelen IPv6 formátum", + "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": "Érvénytelen IPv4-cím az átjáró", + "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 formátum", - "form_error_client_id_format": "Érvénytelen kliens ID formátum", + "form_error_mac_format": "Érvénytelen MAC cím", + "form_error_client_id_format": "Az ügyfél-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 tartományon kívül legyen \"{{start}}\"-\"{{end}}\"", + "lower_range_start_error": "Kisebb legyen, mint a tartomány kezdete", + "greater_range_start_error": "Nagyobbbb legyen, 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", @@ -191,6 +200,7 @@ "form_error_url_or_path_format": "Helytelen URL vagy elérési út 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", "examples_title": "Példák", "example_meaning_filter_block": "letiltja a hozzáférést az example.org domainhez, valamint annak az összes aldomainjéhez is", "example_meaning_filter_whitelist": "feloldja a hozzáférést az example.org domainhez, valamint annak az összes aldomainjéhez is", @@ -577,7 +587,7 @@ "show_blocked_responses": "Blokkolva", "show_whitelisted_responses": "Kivételezett", "show_processed_responses": "Feldolgozva", - "blocked_safebrowsing": "Blokkolva a biztonságos böngészés által", + "blocked_safebrowsing": "Blokkolva a Biztonságos böngészés által", "blocked_adult_websites": "Szülői felügyelet által blokkolva", "blocked_threats": "Blokkolt fenyegetések", "allowed": "Engedve", @@ -611,7 +621,11 @@ "click_to_view_queries": "Kattintson a lekérésekért", "port_53_faq_link": "Az 53-as portot gyakran a \"DNSStubListener\" vagy a \"systemd-resolved\" (rendszer által feloldott) szolgáltatások használják. Kérjük, olvassa el <0>ezt az útmutatót a probléma megoldásához.", "adg_will_drop_dns_queries": "Az AdGuard Home eldobja az összes DNS kérést erről a kliensről.", + "filter_allowlist": "FIGYELMEZTETÉS: Ez a művelet a \"{{disallowed_rule}}\" szabályt is kizárja az engedélyezett ügyfelek listájából.", + "last_rule_in_allowlist": "Nem lehet letiltani ezt az ügyfelet, mert a \"{{disallowed_rule}}\" szabály kizárása letiltja az \"Allowed clients\" listát.", "experimental": "Kísérleti", "use_saved_key": "Előzőleg mentett kulcs használata", - "parental_control": "Szülői felügyelet" + "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)" } diff --git a/client/src/__locales/id.json b/client/src/__locales/id.json index 94c0b851..6449b62d 100644 --- a/client/src/__locales/id.json +++ b/client/src/__locales/id.json @@ -36,10 +36,23 @@ "dhcp_ipv4_settings": "Pengaturan DHCP IPv4", "dhcp_ipv6_settings": "Pengaturan DHCP IPv6", "form_error_required": "Kolom yang harus diisi", - "form_error_ip_format": "Alamat IP salah", + "form_error_ip4_format": "Alamat IPv4 tidak valid", + "form_error_ip4_range_start_format": "Alamat IPv4 tidak valid dari rentang awal", + "form_error_ip4_range_end_format": "Alamat IPv4 tidak valid dari rentang akhir", + "form_error_ip4_gateway_format": "Alamat IPv4 gateway tidak valid", + "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_server_name": "Nama server tidak valid", "form_error_subnet": "Subnet \"{{cidr}}\" tidak berisi alamat IP \"{{ip}}\"", "form_error_positive": "Harus lebih dari 0", + "out_of_range_error": "Harus di luar rentang \"{{start}}\"-\"{{end}}\"", + "lower_range_start_error": "Harus lebih rendah dari rentang awal", + "greater_range_start_error": "Harus lebih besar dari rentang awal", + "greater_range_end_error": "Harus lebih besar dari rentang akhir", + "subnet_error": "Alamat harus dalam satu subnet", + "gateway_or_subnet_invalid": "Subnet mask tidak valid", "dhcp_form_gateway_input": "IP gateway", "dhcp_form_subnet_input": "Subnet mask", "dhcp_form_range_title": "Rentang alamat IP", @@ -150,8 +163,8 @@ "apply_btn": "Terapkan", "disabled_filtering_toast": "Penyaringan nonaktif", "enabled_filtering_toast": "Penyaringan aktif", - "disabled_safe_browsing_toast": "Penelusuran aman dinonaktifkan", - "enabled_safe_browsing_toast": "Penelusuran aman diaktifkan", + "disabled_safe_browsing_toast": "Penjelajahan Aman dinonaktifkan", + "enabled_safe_browsing_toast": "Penjelajahan Aman Diaktifkan", "disabled_parental_toast": "Kontrol orang tua dinonaktifkan", "enabled_parental_toast": "Kontrol orang tua diaktifkan", "disabled_safe_search_toast": "Pencarian aman dinonaktifkan", @@ -187,6 +200,7 @@ "form_error_url_or_path_format": "URL atau jalur absolut dari daftar tidak valid", "custom_filter_rules": "Aturan penyaringan khusus", "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", @@ -202,6 +216,7 @@ "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)", "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", "dns_test_not_ok_toast": "Server \"{{key}}\": tidak dapat digunakan, mohon cek bahwa Anda telah menulisnya dengan benar", "unblock": "Buka Blokir", @@ -299,6 +314,7 @@ "install_settings_dns_desc": "Anda perlu mengkonfigurasi perangkat atau router anda untuk menggunakan server DNS berikut ini", "install_settings_all_interfaces": "Semua antarmuka", "install_auth_title": "Otentikasi", + "install_auth_desc": "Otentikasi kata sandi ke antarmuka web admin AdGuard Home Anda harus dikonfigurasi. Meskipun AdGuard Home hanya dapat diakses di jaringan lokal Anda, tetap penting untuk melindunginya dari akses tak terbatas.", "install_auth_username": "Nama Pengguna", "install_auth_password": "Kata Sandi", "install_auth_confirm": "Konfirmasi kata sandi", @@ -495,6 +511,7 @@ "statistics_clear_confirm": "Apakah Anda yakin ingin menghapus statistik?", "statistics_retention_confirm": "Apakah Anda yakin ingin mengubah retensi statistik? Jika Anda menurunkan nilai interval, beberapa data akan hilang", "statistics_cleared": "Statistik berhasil dihapus", + "statistics_enable": "Aktifkan statistik", "interval_hours": "{{count}} jam", "interval_hours_plural": "{{count}} jam", "filters_configuration": "Konfigurasi filter", @@ -570,7 +587,7 @@ "show_blocked_responses": "Diblokir", "show_whitelisted_responses": "Dalam Daftar Putih", "show_processed_responses": "Terproses", - "blocked_safebrowsing": "Terblokir oleh Safebrowsing", + "blocked_safebrowsing": "Diblokir oleh Penjelajahan Aman", "blocked_adult_websites": "Diblok oleh Kontrol Orang tua", "blocked_threats": "Blokir Ancaman", "allowed": "Dibolehkan", @@ -604,7 +621,11 @@ "click_to_view_queries": "Klik untuk lihat permintaan", "port_53_faq_link": "Port 53 sering ditempati oleh layanan \"DNSStubListener\" atau \"systemd-resolved\". Silakan baca <0>instruksi ini tentang cara menyelesaikan ini.", "adg_will_drop_dns_queries": "AdGuard Home akan menghapus semua permintaan DNS dari klien ini.", + "filter_allowlist": "PERINGATAN: Tindakan ini juga akan mengecualikan aturan \"{{disallowed_rule}}\" dari daftar klien yang diizinkan.", + "last_rule_in_allowlist": "Tidak dapat melarang klien ini karena mengecualikan aturan \"{{disallowed_rule}}\" akan MENONAKTIFKAN daftar \"Klien yang diizinkan\".", "experimental": "Eksperimental", "use_saved_key": "Gunakan kunci yang disimpan sebelumnya", - "parental_control": "Kontrol Orang Tua" + "parental_control": "Kontrol Orang Tua", + "safe_browsing": "Penjelajahan Aman", + "served_from_cache": "{{value}} (disajikan dari cache)" } diff --git a/client/src/__locales/ja.json b/client/src/__locales/ja.json index aa8f2c7a..3cb78c57 100644 --- a/client/src/__locales/ja.json +++ b/client/src/__locales/ja.json @@ -43,7 +43,7 @@ "form_error_ip6_format": "IPv6アドレスが無効です", "form_error_ip_format": "IPアドレスが無効です", "form_error_mac_format": "MACアドレスが無効です", - "form_error_client_id_format": "クライアントIDが無効です", + "form_error_client_id_format": "クライアントIDには、数字、小文字、ハイフンのみが使われている必要があります", "form_error_server_name": "サーバ名が無効です", "form_error_subnet": "IPアドレス「{{ip}}」はサブネット「{{cidr}}」に含まれていません", "form_error_positive": "0より大きい必要があります", @@ -587,8 +587,8 @@ "show_blocked_responses": "ブロック済", "show_whitelisted_responses": "ホワイトリストにあり", "show_processed_responses": "処理済", - "blocked_safebrowsing": "ブロックされたセーフブラウジング", - "blocked_adult_websites": "ペアレンタルコントロールによってブロックされました", + "blocked_safebrowsing": "セーフブラウジングによってブロック済み", + "blocked_adult_websites": "ペアレンタルコントロールによってブロック済み", "blocked_threats": "ブロックされた脅威", "allowed": "許可", "filtered": "フィルタで処理", diff --git a/client/src/__locales/ko.json b/client/src/__locales/ko.json index 3a76d411..2927797a 100644 --- a/client/src/__locales/ko.json +++ b/client/src/__locales/ko.json @@ -43,7 +43,7 @@ "form_error_ip6_format": "잘못된 IPv6 형식", "form_error_ip_format": "잘못된 IP 형식", "form_error_mac_format": "잘못된 MAC 형식", - "form_error_client_id_format": "잘못된 클라이언트 ID 형식", + "form_error_client_id_format": "클라이언트 ID는 숫자, 소문자 및 하이픈만 포함해야 합니다", "form_error_server_name": "유효하지 않은 서버 이름입니다", "form_error_subnet": "서브넷 \"{{cidr}}\"에 \"{{ip}}\" IP 주소가 없습니다", "form_error_positive": "0보다 커야 합니다", @@ -587,8 +587,8 @@ "show_blocked_responses": "차단됨", "show_whitelisted_responses": "예외 적용됨", "show_processed_responses": "처리됨", - "blocked_safebrowsing": "차단된 세이프 브라우징", - "blocked_adult_websites": "자녀 보호로 차단됨", + "blocked_safebrowsing": "세이프 브라우징에 의해 차단됨", + "blocked_adult_websites": "자녀 보호에 의해 차단됨", "blocked_threats": "차단된 위협", "allowed": "허용됨", "filtered": "필터링됨", @@ -626,6 +626,6 @@ "experimental": "실험", "use_saved_key": "이전에 저장했던 키 사용하기", "parental_control": "자녀 보호", - "safe_browsing": "안전한 브라우징", + "safe_browsing": "세이프 브라우징", "served_from_cache": "{{value}} (캐시에서 제공)" } diff --git a/client/src/__locales/sk.json b/client/src/__locales/sk.json index 44efcb52..9b3886c2 100644 --- a/client/src/__locales/sk.json +++ b/client/src/__locales/sk.json @@ -43,7 +43,7 @@ "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": "Neplatné ID klienta", + "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", diff --git a/client/src/__locales/sl.json b/client/src/__locales/sl.json index cd51b953..cb19b1c8 100644 --- a/client/src/__locales/sl.json +++ b/client/src/__locales/sl.json @@ -43,7 +43,7 @@ "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": "Neveljaven ID odjemalca", + "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", diff --git a/client/src/__locales/sv.json b/client/src/__locales/sv.json index 72349474..72ae983b 100644 --- a/client/src/__locales/sv.json +++ b/client/src/__locales/sv.json @@ -1,26 +1,58 @@ { "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", + "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", + "load_balancing_desc": "Fråga en uppströmsserver åt gången. AdGuard Home använder sin viktade slumpmässiga algoritm för att välja server så att den snabbaste servern används oftare.", "bootstrap_dns": "Bootstrap-DNS-servrar", "bootstrap_dns_desc": "Bootstrap-DNS-servrar används för att slå upp DoH/DoT-resolvrarnas IP-adresser som du specificerat som uppström.", + "local_ptr_title": "Privata omvända DNS-servrar", + "local_ptr_desc": "DNS servrarna som AdGuard Home använder för lokala PTR frågor. Dessa servrar används för att lösa värdnamnen på klienter med privata IP-adresser, till exempel \"192.168.12.34\", genom omvänd DNS. Om inga servrar angetts använder AdGuard Home adresserna till standard DNS servrar för ditt operativsystem förutom adresserna till AdGuard Home själv.", + "local_ptr_default_resolver": "Som standard använder AdGuard Home följande omvända DNS upplösare: {{ip}}.", + "local_ptr_no_default_resolver": "AdGuard Home kunde inte fastställa lämpliga privata omvända DNS upplösare för detta system.", "local_ptr_placeholder": "Ange en serveradress per rad", + "resolve_clients_title": "Aktivera omvänd upplösning av klienters IP-adresser", + "resolve_clients_desc": "Lös upp klienternas värdnamn med omvänt uppslag av klienternas IP-adresser genom att skicka PTR-frågor till motsvarande upplösare (privata DNS-servrar för lokala klienter, uppströmsservrar för klienter med offentliga IP-adresser).", + "use_private_ptr_resolvers_title": "Använd privata omvända DNS upplösare", + "use_private_ptr_resolvers_desc": "Utför omvända DNS-sökningar för lokalt betjänade adresser med dessa uppströmsservrar. Om det är inaktiverat svarar AdGuard Home med NXDOMAIN på alla sådana PTR-förfrågningar förutom klienter kända från DHCP, /etc/hosts, och så vidare.", "check_dhcp_servers": "Letar efter DHCP-servrar", "save_config": "Spara konfiguration", "enabled_dhcp": "DHCP-server aktiverad", "disabled_dhcp": "Dhcp-server avaktiverad", + "unavailable_dhcp": "DHCP är inte tillgängligt", + "unavailable_dhcp_desc": "AdGuard Home kan inte köra en DHCP-server på ditt operativsystem", "dhcp_title": "DHCP-server (experimentell)", "dhcp_description": "Om din router inte har inställningar för DHCP kan du använda AdGuards inbyggda server.", "dhcp_enable": "Aktivera DHCP.-server", "dhcp_disable": "Avaktivera DHCP-server", + "dhcp_not_found": "Det är säkert att aktivera den inbyggda DHCP-servern eftersom AdGuard Home inte hittade några aktiva DHCP-servrar i nätverket. Du bör dock kontrollera det igen manuellt eftersom den automatiska sökningenn efter DHCP-servrar inte ger 100 % garanti.", "dhcp_found": "Några aktiva DHCP-servar upptäcktes. Det är inte säkert att aktivera inbyggda DHCP-servrar.", "dhcp_leases": "DHCP-lease", "dhcp_static_leases": "Statiska DHCP-leases", "dhcp_leases_not_found": "Ingen DHCP-lease hittad", + "dhcp_config_saved": "DHCP-konfigurationen har sparats", + "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_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_client_id_format": "Ogiltigt klient-ID", + "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}}\"", + "lower_range_start_error": "Måste vara lägre än starten på intervallet", + "greater_range_start_error": "Måste vara högre än starten på intervallet", + "greater_range_end_error": "Måste vara större än intervallets slut", + "subnet_error": "Adresser måste finnas i ett subnät", + "gateway_or_subnet_invalid": "Subnätmask ogiltig", "dhcp_form_gateway_input": "Gateway-IP", "dhcp_form_subnet_input": "Subnetmask", "dhcp_form_range_title": "IP-adressgränser", @@ -31,17 +63,30 @@ "dhcp_interface_select": "Välj DHCP-gränssnitt", "dhcp_hardware_address": "Hårdvaruadress", "dhcp_ip_addresses": "IP-adresser", + "ip": "IP", "dhcp_table_hostname": "Värdnamn", "dhcp_table_expires": "Utgår", + "dhcp_warning": "Om du vill använda den inbyggda DHCP servern ändå, se till att det inte finns några andra aktiva DHCP servrar. Annars kan den störa internetanslutningen för anslutna enheter!", + "dhcp_error": "Vi kunde inte avgöra om det finns en till DHCP-server på nätverket.", + "dhcp_static_ip_error": "För att kunna använda en DHCP-server måste det finnas en statisk IP-adress. AdGuard Home kunde inte avgöra om nätverksgränssnittet är konfigurerat med en statisk IP-adress. Ställ in en statisk IP-adress manuellt.", + "dhcp_dynamic_ip_found": "Din enhet använder en dynamisk IP-adress för gränssnittet <0>{{interfaceName}}. För att kunna använda DHCP-servern behövs en statisk IP-adress. Din nuvarande IP-adress är <0>{{ipAddress}}. AdGuard Home kommer automatiskt att göra denna IP-adress statisk om du trycker på knappen \"Aktivera DHCP\".", "dhcp_lease_added": "Statisk lease \"{{key}}\" har lagts till", "dhcp_lease_deleted": "Statisk lease \"{{key}}\" har raderats", "dhcp_new_static_lease": "Ny statisk lease", "dhcp_static_leases_not_found": "Inga statiska DHCP-leases hittade", "dhcp_add_static_lease": "Lägg till statisk lease", + "dhcp_reset_leases": "Återställ alla leasingavtal", + "dhcp_reset_leases_confirm": "Är du säker på att du vill ta bort alla leasingavtal?", + "dhcp_reset_leases_success": "DHCP-leasing har återställts", + "dhcp_reset": "Är du säker på att du vill ta bort DHCP inställningarna?", + "country": "Land", + "city": "Stad", "delete_confirm": "Är du säker på att du vill ta bort \"{{key}}\"?", "form_enter_hostname": "Skriv in värdnamn", "error_details": "Felinformation", + "response_details": "Svarsdetaljer", "request_details": "Förfrågningsdetaljer", + "client_details": "Klient information", "details": "Detaljer", "back": "Tiilbaka", "dashboard": "Kontrollpanel", @@ -49,6 +94,8 @@ "filters": "Filter", "filter": "Filter", "query_log": "Förfrågningslogg", + "compact": "Komprimera", + "nothing_found": "Inget hittades", "faq": "FAQ", "version": "version", "address": "Adress", @@ -72,52 +119,88 @@ "for_last_24_hours": "under de senaste 24 timmarna", "for_last_days": "för den senaste {{count}} dagen", "for_last_days_plural": "för de senaste {{count}} dagarna", + "stats_disabled": "Statistiken har inaktiverats. Du kan aktivera det från <0>inställningssidan.", + "stats_disabled_short": "Statistiken har inaktiverats", "no_domains_found": "Inga domäner hittade", "requests_count": "Förfrågningsantal", "top_blocked_domains": "Flest blockerade domäner", "top_clients": "Toppklienter", "no_clients_found": "Inga klienter hittade", "general_statistics": "Allmän statistik", + "number_of_dns_query_days": "Antalet DNS-förfrågningar som utfördes under senaste {{count}} dagen", + "number_of_dns_query_days_plural": "Ett antal DNS förfrågningar utfördes under de senaste {{count}} dagarna", + "number_of_dns_query_24_hours": "Antalet DNS-förfrågningar som utfördes under de senaste 24 timmarna", + "number_of_dns_query_blocked_24_hours": "Antalet DNS-förfrågningar som blockerades av annonsfilter och värdens blockeringsklistor", + "number_of_dns_query_blocked_24_hours_by_sec": "Antalet DNS-förfrågningar som blockerades av AdGuards modul för surfsäkerhet", + "number_of_dns_query_blocked_24_hours_adult": "Antalet vuxensajter som blockerats", "enforced_save_search": "Aktivering av Säker surf", + "number_of_dns_query_to_safe_search": "Antalet DNS-förfrågningar mot sökmotorer där Säker surf tvingats", "average_processing_time": "Genomsnittlig processtid", "average_processing_time_hint": "Genomsnittlig processtid i millisekunder för DNS-förfrågning", "block_domain_use_filters_and_hosts": "Blockera domäner med filter- och värdfiler", "filters_block_toggle_hint": "Du kan ställa in egna blockerings regler i Filterinställningar.", "use_adguard_browsing_sec": "Använd AdGuards webbservice för surfsäkerhet", - "use_adguard_browsing_sec_hint": "AdGuard Home kommer att kontrollera om en domän är svartlistad i webbservicens surfsäkerhet. Med en integritetsvänlig metod görs en API-lookup för att kontrollera : endast en kort prefix i domännamnet SHA256 hash skickas till servern.", + "use_adguard_browsing_sec_hint": "AdGuard Home kommer att kontrollera om en domän är blockerad av webbservicen surfsäkerhet. Med en integritetsvänlig metod görs en API-lookup för att kontrollera: endast ett kort prefix i domännamnet SHA256 hash skickas till servern.", "use_adguard_parental": "Använda AdGuards webbservice för föräldrakontroll", "use_adguard_parental_hint": "AdGuard Home kommer att kontrollera domäner för innehåll av vuxenmaterial . Samma integritetsvänliga metod för API-lookup som tillämpas i webbservicens surfsäkerhet används.", - "enforce_safe_search": "Tillämpa Säker surf", + "enforce_safe_search": "Använd säker webbsökning", + "enforce_save_search_hint": "AdGuard Home kommer tvinga säker surf på följande sökmotorer: Google, Youtube, Bing, DuckDuckGo, Yandex, Pixabay.", "no_servers_specified": "Inga servrar angivna", "general_settings": "Allmänna inställningar", "dns_settings": "DNS-inställningar", + "dns_blocklists": "DNS blockeringslistor", + "dns_allowlists": "DNS frilistor", + "dns_blocklists_desc": "AdGuard Home kommer att blockera domäner som matchar blockeringslistorna.", + "dns_allowlists_desc": "Domäner från DNS frilistor kommer att tillåtas även om de finns i någon av blockeringslistorna.", "custom_filtering_rules": "Egna filterregler", "encryption_settings": "Krypteringsinställningar", "dhcp_settings": "DHCP-inställningar", "upstream_dns": "Upstream DNS-servrar", + "upstream_dns_help": "Ange en serveradress per rad. Läs mer om att konfigurera uppströms DNS-servrar.", + "upstream_dns_configured_in_file": "Konfigurerad i {{path}}", "test_upstream_btn": "Testa uppströmmar", + "upstreams": "Uppströms", "apply_btn": "Tillämpa", "disabled_filtering_toast": "Filtrering bortkopplad", "enabled_filtering_toast": "Filtrering inkopplad", - "disabled_safe_browsing_toast": "Säker surfning bortkopplat", - "enabled_safe_browsing_toast": "Säker surfning inkopplat", + "disabled_safe_browsing_toast": "Säker surfning inaktiverad", + "enabled_safe_browsing_toast": "Säker surfning aktiverat", "disabled_parental_toast": "Föräldrakontroll bortkopplat", "enabled_parental_toast": "Föräldrakontroll inkopplat", "disabled_safe_search_toast": "Säker webbsökning bortkopplat", "enabled_save_search_toast": "Säker webbsökning inkopplat", "enabled_table_header": "Inkopplat", "name_table_header": "Namn", + "list_url_table_header": "Lista URL", "rules_count_table_header": "Regelantal", "last_time_updated_table_header": "Uppdaterades senast", "actions_table_header": "Åtgärder", + "request_table_header": "Förfrågning", "edit_table_action": "Redigera", "delete_table_action": "Radera", + "elapsed": "Förfluten tid", "filters_and_hosts_hint": "AdGuard tillämpar grundläggande annonsblockeringsregler och värdfiltersyntaxer", + "no_blocklist_added": "Inga blocklistor har lagts till", + "no_whitelist_added": "Inga frilistor har lagts till", + "add_blocklist": "Lägg till blockeringslista", + "add_allowlist": "Lägg till frilista", "cancel_btn": "Avbryt", "enter_name_hint": "Skriv in namn", + "enter_url_or_path_hint": "Ange en URL eller en absolut sökväg till listan", "check_updates_btn": "Sök efter uppdateringar", + "new_blocklist": "Ny blockeringslista", + "new_allowlist": "Ny frilista", + "edit_blocklist": "Redigera blockeringslista", + "edit_allowlist": "Redigera frilista", + "choose_blocklist": "Välj blockeringslistor", + "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_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.", + "system_host_files": "Systemfiler", "examples_title": "Exempel", "example_meaning_filter_block": "blockera åtkomst till domän example.org domain och alla dess subdomäner", "example_meaning_filter_whitelist": "avblockera åtkomst till domän example.org domain och alla dess subdomäner", @@ -129,17 +212,26 @@ "example_upstream_regular": "vanlig DNS (över UDP)", "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_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)", + "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", "dns_test_not_ok_toast": "Server \"{{key}}\": kunde inte användas. Var snäll och kolla att du skrivit in rätt", "unblock": "Avblockera", "block": "Blockera", + "disallow_this_client": "Tillåt inte den här klienten", + "allow_this_client": "Tillåt den här klienten", + "block_for_this_client_only": "Blockera endast för denna klient", + "unblock_for_this_client_only": "Avblockera endast för denna klient", "time_table_header": "Tid", "date": "Datum", "domain_name_table_header": "Domännamn", + "domain_or_client": "Domän eller klient", "type_table_header": "Typ", "response_table_header": "Svar", + "response_code": "Svarskod", "client_table_header": "Klient", "empty_response_status": "Tomt", "show_all_filter_type": "Visa alla", @@ -151,13 +243,14 @@ "loading_table_status": "Läser in...", "page_table_footer_text": "Sida", "rows_table_footer_text": "rader", - "updated_custom_filtering_toast": "Uppdaterade de egna filterreglerna", + "updated_custom_filtering_toast": "Anpassade filterregler sparade", "rule_removed_from_custom_filtering_toast": "Regel borttagen från de egna filterreglerna: {{rule}}", "rule_added_to_custom_filtering_toast": "Regel tillagd till de egna filterreglerna: {{rule}}", "query_log_response_status": "Status: {{value}}", "query_log_filtered": "Filtrerat av {{filter}}", "query_log_confirm_clear": "Är du säker på att du vill rensa hela förfrågningsloggen?", "query_log_cleared": "Förfrågningsloggen har rensats", + "query_log_updated": "Förfrågningsloggen har uppdaterats", "query_log_clear": "Rensa förfrågningsloggar", "query_log_retention": "Förfrågningsloggars retentionstid", "query_log_enable": "Aktivera logg", @@ -165,27 +258,63 @@ "query_log_disabled": "Förfrågningsloggen är avaktiverad och kan konfigureras i <0>inställningar", "query_log_strict_search": "Använd dubbla citattecken för strikt sökning", "query_log_retention_confirm": "Är du säker på att du vill ändra förfrågningsloggars retentionstid? Om du minskar intervallet kommer viss data att gå förlorad", + "anonymize_client_ip": "Anonymisera klientens IP", + "anonymize_client_ip_desc": "Spara inte klientens fullständiga IP-adress i loggar och statistik", + "dns_config": "DNS server konfiguration", + "dns_cache_config": "DNS cache konfiguration", + "dns_cache_config_desc": "Här kan du konfigurera DNS cache", + "blocking_mode": "Blockeringsläge", "default": "Standard", + "nxdomain": "NXDOMÄN", + "refused": "REFUSED", + "null_ip": "Null IP", "custom_ip": "Eget IP", + "blocking_ipv4": "Blockera IPv4", + "blocking_ipv6": "Blockera IPv6", "dnscrypt": "DNSCrypt", "dns_over_https": "DNS-over-HTTPS", "dns_over_tls": "DNS-over-TLS", "dns_over_quic": "DNS-over-QUIC", + "client_id": "Klient ID", + "client_id_placeholder": "Ange klient ID", + "client_id_desc": "Olika klienter kan identifieras med ett speciellt klient ID. Här kan du lära dig mer om hur du identifierar klienter.", + "download_mobileconfig_doh": "Ladda ner .mobileconfig för DNS-over-HTTPS", + "download_mobileconfig_dot": "Ladda ner .mobileconfig för DNS-over-TLS", + "download_mobileconfig": "Ladda ner konfigurationsfil", + "plain_dns": "Vanlig DNS", + "form_enter_rate_limit": "Ange förfrågnings gräns", + "rate_limit": "Förfrågnings gräns", + "edns_enable": "Aktivera EDNS-klient subnät", + "edns_cs_desc": "Skicka klienternas subnät till DNS servrarna.", + "rate_limit_desc": "Antalet förfrågningar per sekund som tillåts per klient. Att sätta den till 0 innebär ingen gräns.", + "blocking_ipv4_desc": "IP adress som ska returneras för en blockerad A förfrågan", + "blocking_ipv6_desc": "IP adress som ska returneras för en blockerad AAAA förfrågan", + "blocking_mode_default": "Standard: Svara med noll IP-adress (0.0.0.0 för A; :: för AAAA) när det blockeras av regel i Adblock-stil; svara med IP-adressen som anges i regeln när den blockeras av regel i /etc/hosts-stil", + "blocking_mode_refused": "REFUSED: Svara med REFUSED kod", + "blocking_mode_nxdomain": "NXDOMAIN: Svara med NXDOMAIN kod", + "blocking_mode_null_ip": "Null IP: Svara med noll IP adress (0.0.0.0 för A; :: för AAAA)", + "blocking_mode_custom_ip": "Anpassad IP: Svara med en manuellt inställd IP adress", + "upstream_dns_client_desc": "Om detta fält är tomt kommer AdGuard Home att använda de servrar som konfigurerats i <0>DNS inställningarna.", + "tracker_source": "Spårningskälla", "source_label": "Källa", "found_in_known_domain_db": "Hittad i domändatabas.", "category_label": "Kategori", + "rule_label": "Regel(er)", + "list_label": "Lista", "unknown_filter": "Okänt filter {{filterId}}", + "known_tracker": "Känd spårare", "install_welcome_title": "Välkommen till AdGuard Home!", "install_welcome_desc": "AdGuard Home är en DNS-server för nätverkstäckande annons- och spårningsblockering. Dess syfte är att de dig kontroll över hela nätverket och alla dina enheter, utan behov av att använda klientbaserade program.", "install_settings_title": "Administratörens webbgränssnitt", "install_settings_listen": "Övervakningsgränssnitt", "install_settings_port": "Port", "install_settings_interface_link": "Din administratörssida för AdGuard Home finns på följande adresser:", + "form_error_port": "Skriv in ett giltigt portnummer", "install_settings_dns": "DNS-server", "install_settings_dns_desc": "Du behöver ställa in dina enheter eller din router för att använda DNS-server på följande adresser.", "install_settings_all_interfaces": "Alla gränssnitt", "install_auth_title": "Autentisering", - "install_auth_desc": "Det rekommenderas starkt att ställa in lösenordsskydd till webbgränssnittets administrativa del i ditt AdGuard Home. Även om den endast är åtkomlig på ditt lokala nätverk rekommenderas det ändå att skydda det mot oönskad åtkomst.", + "install_auth_desc": "Lösenordsautentisering till ditt AdGuard Home administratörsgränssnitt måste konfigureras. Även om AdGuard Home bara är tillgängligt i ditt lokala nätverk är det fortfarande viktigt att skydda det från obegränsad åtkomst.", "install_auth_username": "Användarnamn", "install_auth_password": "Lösenord", "install_auth_confirm": "Bekräfta lösenord", @@ -195,18 +324,20 @@ "install_devices_title": "Ställ in dina enheter", "install_devices_desc": "För att kunna använda AdGuard Home måste du ställa in dina enheter för att utnyttja den.", "install_submit_title": "Grattis!", - "install_submit_desc": "Inställningsproceduren är klar och du kan börja använda AdGuard Home.", + "install_submit_desc": "Installationen är klar och du kan börja använda AdGuard Home.", "install_devices_router": "Router", "install_devices_router_desc": "Den här anpassningen kommer att automatiskt täcka in alla de enheter som är anslutna till din hemmarouter och du behöver därför inte konfigurera var och en individuellt.", "install_devices_address": "AdGuard Home DNS-server täcker följande adresser", + "install_devices_router_list_1": "Öppna inställningarna för din router. Vanligtvis kan du komma åt den från din webbläsare via en URL, som http://192.168.0.1/ eller http://192.168.1.1/. Du kan bli ombedd att ange ett lösenord. Om du inte kommer ihåg det kan du ofta återställa lösenordet genom att trycka på en knapp på själva routern, men var medveten om att om denna procedur väljs kommer du förmodligen att förlora hela routerkonfigurationen. Om din router kräver en app för att konfigurera den, installera appen på din telefon eller dator och använd den för att komma åt routerns inställningar.", "install_devices_router_list_2": "Leta upp DHCP/DNS-inställningarna. Titta efter DNS-tecken intill ett fält med två eller tre uppsättningar siffror, var och en uppdelade i grupper om fyra med en eller tre siffror.", "install_devices_router_list_3": "Ange serveradressen till ditt AdGuard Home.", + "install_devices_router_list_4": "På vissa routertyper kan en anpassad DNS server inte konfigureras. I så fall kan det hjälpa att konfigurera AdGuard Home som en <0>DHCP server. Annars bör du kontrollera routermanualen om hur du anpassar DNS servrar på din specifika routermodell.", "install_devices_windows_list_1": "Öppna Kontrollpanelen via Start eller Windows Sök.", "install_devices_windows_list_2": "Välj Nätverks och delningscenter, Nätverk och Internet.", - "install_devices_windows_list_3": "Leta upp Ändra nätverkskortsalternativ", + "install_devices_windows_list_3": "På vänster sida av skärmen hittar du \"Ändra adapterinställningar\" och klicka på den.", "install_devices_windows_list_4": "Markera din aktiva anslutning. Högerklicka på den och välj Egenskaper.", - "install_devices_windows_list_5": "Markera Internet Protocol Version 4 (TCP/IP) och klicka på knappen Egenskaper.", - "install_devices_windows_list_6": "Markera Använd följande DNS-serveradresser och skriv in adresserna till ditt AdGuard Home.", + "install_devices_windows_list_5": "Hitta \"Internet Protocol Version 4 (TCP/IPv4)\" (eller, för IPv6, \"Internet Protocol Version 6 (TCP/IPv6)\") i listan, välj den och klicka sedan på Egenskaper igen.", + "install_devices_windows_list_6": "Välj \"Använd följande DNS-serveradresser\" och ange dina AdGuard Home-serveradresser.", "install_devices_macos_list_1": "Klicka på Apple-ikonen och välj Systemalternativ.", "install_devices_macos_list_2": "Klicka på Nätverk.", "install_devices_macos_list_3": "Välj den första anslutningen i listan och klicka på Avancerat.", @@ -215,7 +346,7 @@ "install_devices_android_list_2": "Tryck på Nätverk och Internet, Wi-Fi. Alla tillgängliga nätverk visas i en lista (det går inte all välja egen DNS på mobilnätverk.", "install_devices_android_list_3": "Håll ner på nätverksnamnet som du är ansluten till och välj Ändra nätverk.", "install_devices_android_list_4": "På en del enheter kan du behöva välja Avancerat för att komma åt ytterligare inställningar. För att ändra på DNS-inställningar måste du byta IP-inställning från DHCP till Statisk. På Android Pie väljs Privat DNS på Nätverk och internet.", - "install_devices_android_list_5": "Ändra DNS 1 och DNS 2 till serveradresserna för AdGuard Home.", + "install_devices_android_list_5": "Ändra DNS 1 och DNS 2 värdena till serveradresserna för din AdGuard Home.", "install_devices_ios_list_1": "Tryck Inställningar från hemskärmen.", "install_devices_ios_list_2": "Välj Wi_Fi på den vänstra menyn (det går inte att ställa in egen DNS för mobila nätverk).", "install_devices_ios_list_3": "Tryck på namnet på den aktiva anslutningen.", @@ -226,14 +357,18 @@ "install_saved": "Sparat utan fel", "encryption_title": "Kryptering", "encryption_desc": "Krypteringsstöd (HTTPS/TLS) för både DNS och adminwebbgränssnitt.", + "encryption_config_saved": "Krypteringsinställningar sparade", "encryption_server": "Servernamn", "encryption_server_enter": "Skriv in ditt domännamn", + "encryption_server_desc": "För att kunna använda HTTPS måste du ange servernamnet som matchar ditt SSL-certifikat eller jokerteckencertifikat. Om fältet inte är inställt kommer det att acceptera TLS-anslutningar för alla domäner.", "encryption_redirect": "Omdirigera till HTTPS automatiskt", "encryption_redirect_desc": "Om bockad kommer AdGuard Home automatiskt att omdirigera dig från HTTP till HTTPS-adresser.", "encryption_https": "HTTPS-port", "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_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.", "encryption_certificates_input": "Kopiera/klistra in dina PEM-kodade certifikat här.", @@ -253,11 +388,16 @@ "encryption_reset": "Är du säker på att du vill återställa krypteringsinställningarna?", "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_equal": "Får inte vara samma", "form_error_password": "Lösenorden överensstämmer inte", "reset_settings": "Återställ inställningar", "update_announcement": "AdGuard Home {{version}} är nu tillgänglig! <0>Klicka här för mer information.", + "setup_guide": "Installationsguide", "dns_addresses": "DNS-adresser", + "dns_start": "DNS servern startar", + "dns_status_error": "Fel vid kontroll av DNS serverns status", "down": "Ner", "fix": "Fixa", "dns_providers": "Här är en <0>lista över kända DNS-leverantörer att välja från.", @@ -276,8 +416,12 @@ "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.", "form_enter_ip": "Skriv in IP", + "form_enter_subnet_ip": "Ange en IP adress i subnätet \"{{cidr}}\"", "form_enter_mac": "Skriv in MAC", + "form_enter_id": "Ange identifierare", + "form_add_id": "Lägg till identifierare", "form_client_name": "Skriv in klientnamn", "name": "Namn", "client_global_settings": "Använda globala inställningar", @@ -286,15 +430,17 @@ "client_updated": "Klient \"{{key}}\" har uppdaterats", "clients_not_found": "Inga klienter hittade", "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", "access_title": "Åtkomstinställningar", "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 eller IP-adresser. Om konfigurerad kommer AdGuard Home endast acceptera förfrågningar från dessa IP-adresser.", + "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_disallowed_title": "Otillåtna klienter", - "access_disallowed_desc": "En lista över CIDR eller IP-adresser. Om konfigurerad kommer AdGuard Home inte acceptera förfrågningar från dessa IP-adresser.", + "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_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", "updates_checked": "Sökning efter uppdateringar genomförd", "updates_version_equal": "AdGuard Home är uppdaterat", @@ -302,6 +448,8 @@ "dns_privacy": "DNS-Integritet", "setup_dns_privacy_1": "<0>DNS-över-TLS: Använd: <1>{{address}}", "setup_dns_privacy_2": "<0>DNS-över-HTTPS: Använd: <1>{{address}}", + "setup_dns_privacy_3": "<0>Här är en lista över program du kan använda.", + "setup_dns_privacy_4": "På en iOS 14 eller macOS Big Sur enhet kan du ladda ner en speciell '.mobileconfig' fil som lägger till DNS-over-HTTPS eller DNS-over-TLS-servrar till DNS inställningarna.", "setup_dns_privacy_android_1": "Android 9 har inbyggt stöd för DNS-över-TLS. Konfigurera och uppge domännamn under Inställningar → Nätverk & Internet → Avancerat → Privat DNS.", "setup_dns_privacy_android_2": "<0>AdGuard för Android stödjer <1>DNS-över-HTTPS samt <1>DNS-över-TLS.", "setup_dns_privacy_android_3": "<0>Intra lägger till stöd för <1>DNS-ÖVER-HTTPS till Android.", @@ -313,15 +461,51 @@ "setup_dns_privacy_other_3": "<0>dnscrypt-proxy stödjer <1>DNS-over-HTTPS.", "setup_dns_privacy_other_4": "<0>Mozilla Firefox stödjer <1>DNS-over-HTTPS.", "setup_dns_privacy_other_5": "Du kan hitta fler implementeringar <0>här och <1>här.", + "setup_dns_privacy_ioc_mac": "iOS och macOS konfiguration", "setup_dns_notice": "För att kunna använda <1>DNS-över-HTTPS eller <1>DNS-över-TLS, behöver du <0>konfigurera Kryptering i AdGuard Home-inställningar.", "rewrite_added": "DNS-omskrivning för \"{{key}}\" lyckad", "rewrite_deleted": "DNS-omskrivning för \"{{key}}\" har tagits bort", + "rewrite_add": "Lägg till DNS omskrivning", + "rewrite_not_found": "Inga DNS omskrivningar hittades", + "rewrite_confirm_delete": "Är du säker på att du vill ta bort DNS-omskrivningen för \"{{key}}\"?", + "rewrite_desc": "Gör det enkelt att konfigurera anpassat DNS svar för ett specifikt domännamn.", + "rewrite_applied": "Omskrivningsregeln tillämpas", + "rewrite_hosts_applied": "Omskriven av värd fil regel", + "dns_rewrites": "DNS omskrivningar", + "form_domain": "Ange domännamn eller jokertecken", + "form_answer": "Ange IP adress eller domännamn", + "form_error_domain_format": "Ogiltigt domänformat", + "form_error_answer_format": "Ogiltigt svarsformat", + "configure": "Konfigurera", + "main_settings": "Huvudinställningar", + "block_services": "Blockera specifika tjänster", + "blocked_services": "Blockerade tjänster", + "blocked_services_desc": "Gör det möjligt att snabbt blockera populära webbplatser och tjänster.", + "blocked_services_saved": "Blockerade tjänster har sparats", + "blocked_services_global": "Använd globalt blockerade tjänster", + "blocked_service": "Blockerad tjänst", + "block_all": "Blockera alla", + "unblock_all": "Avblockera alla", + "encryption_certificate_path": "Certifikatsökväg", + "encryption_private_key_path": "Privat nyckel sökväg", + "encryption_certificates_source_path": "Ange sökväg för certifikatfilen", + "encryption_certificates_source_content": "Klistra in certifikatets innehåll", + "encryption_key_source_path": "Ställ in en privat nyckelfil", + "encryption_key_source_content": "Klistra in den privata nyckelns innehåll", + "stats_params": "Statistikkonfiguration", + "config_successfully_saved": "Konfigurationen har sparats", "interval_6_hour": "6 timmar", "interval_24_hour": "24 timmar", "interval_days": "{{count}} dag", "interval_days_plural": "{{count}} dagar", "domain": "Domän", + "punycode": "Punycode", "answer": "Svar", + "filter_added_successfully": "Listan har lagts till", + "filter_removed_successfully": "Listan har tagits bort", + "filter_updated": "Listan har uppdaterats", + "statistics_configuration": "Statistikkonfiguration", + "statistics_retention": "Bevarande av statistik", "statistics_retention_desc": "Om du minskar intervallet kommer viss data att gå förlorad", "statistics_clear": "Rensa statistik", "statistics_clear_confirm": "Är du säker på att du vill radera statistiken?", @@ -349,17 +533,99 @@ "descr": "Beskrivning", "whois": "Whois", "filtering_rules_learn_more": "<0>Mer info om att skapa dina egna blockeringslistor för värdar.", + "blocked_by_response": "Blockerad av CNAME eller IP i svaret", + "blocked_by_cname_or_ip": "Blockerad av CNAME eller IP", "try_again": "Försök igen", + "domain_desc": "Ange domännamnet eller jokertecken som du vill ska skrivas om.", + "example_rewrite_domain": "skriv bara om svar för detta domännamn.", + "example_rewrite_wildcard": "skriv om svar för alla <0>example.org subdomäner.", + "rewrite_ip_address": "IP adress: använd denna IP i ett A- eller AAAA-svar", + "rewrite_domain_name": "Domännamn: lägg till en CNAME post", + "rewrite_A": "<0>A: specialvärde, behåll <0>A poster från uppströms", + "rewrite_AAAA": "<0>AAAA: specialvärde, behåll <0>AAAA poster från uppströms", + "disable_ipv6": "Inaktivera upplösning av IPv6 adresser", + "disable_ipv6_desc": "Kasta alla DNS-frågor för IPv6-adresser (typ AAAA).", + "fastest_addr": "Snabbaste IP adressen", + "fastest_addr_desc": "Fråga alla DNS servrar och returnera den snabbaste IP adressen bland alla svar. Detta saktar ner DNS-frågor eftersom AdGuard Home måste vänta på svar från alla DNS servrar, men förbättrar den övergripande anslutningen.", + "autofix_warning_text": "Om du klickar på \"Fix\" kommer AdGuard Home att konfigurera ditt system för att använda AdGuard Home DNS server.", + "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", + "form_select_tags": "Välj klienttaggar", + "check_title": "Kontrollera filtreringen", + "check_desc": "Kontrollera om värdnamnet är filtrerat", + "check": "Kontrollera", + "form_enter_host": "Ange ett värdnamn", + "filtered_custom_rules": "Filtrerat efter anpassade filtreringsregler", + "choose_from_list": "Välj från listan", + "add_custom_list": "Lägg till en anpassad lista", + "host_whitelisted": "Värden är tillåten", + "check_ip": "IP adresser: {{ip}}", + "check_cname": "CNAME: {{cname}}", + "check_reason": "Anledning: {{reason}}", + "check_service": "Service namn: {{service}}", + "service_name": "Service namn", + "check_not_found": "Hittades inte i dina filterlistor", + "client_confirm_block": "Är du säker på att du vill blockera klienten \"{{ip}}\"?", + "client_confirm_unblock": "Är du säker på att du vill avblockera klienten \"{{ip}}\"?", + "client_blocked": "Klienten \"{{ip}}\" har blockerats", + "client_unblocked": "Klienten \"{{ip}}\" har avblockerats", + "static_ip": "Statisk IP adress", + "static_ip_desc": "AdGuard Home är en server så den behöver en statisk IP-adress för att fungera korrekt. Annars kan din router vid något tillfälle tilldela en annan IP-adress till den här enheten.", + "set_static_ip": "Ställ in en statisk IP adress", + "install_static_ok": "Goda nyheter! Den statiska IP adressen är redan konfigurerad", + "install_static_error": "AdGuard Home kan inte konfigurera det automatiskt för detta nätverksgränssnitt. Vänligen leta efter en instruktion om hur du gör detta manuellt.", + "install_static_configure": "AdGuard Home har upptäckt att den dynamiska IP adressen <0>{{ip}} används. Vill du att den ska ställas in som din statiska adress?", + "confirm_static_ip": "AdGuard Home kommer att konfigurera {{ip}} för att vara din statiska IP adress. Vill du fortsätta?", + "list_updated": "{{count}} listan uppdaterad", + "list_updated_plural": "{{count}} listor uppdaterade", + "dnssec_enable": "Aktivera DNSSEC", + "dnssec_enable_desc": "Ställ in DNSSEC flagga i de utgående DNS frågorna och kontrollera resultatet (DNSSEC-aktiverad upplösare krävs).", + "validated_with_dnssec": "Validerad med DNSSEC", + "all_queries": "Alla förfrågningar", "show_blocked_responses": "Blockerade", "show_whitelisted_responses": "Vitlistade", "show_processed_responses": "Utförda", + "blocked_safebrowsing": "Blockerad av Säker webbsökning", "blocked_adult_websites": "Blockerad av Föräldrakontroll", "blocked_threats": "Blockerade hot", "allowed": "Vitlistade", + "filtered": "Filtrerad", + "rewritten": "Omskriven", "safe_search": "Säker surf", + "blocklist": "Blocklista", + "milliseconds_abbreviation": "ms", + "cache_size": "Cachestorlek", + "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", + "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.", "filter_category_general": "General", "filter_category_security": "säkerhet", + "filter_category_regional": "Regional", "filter_category_other": "Övrigt", + "filter_category_general_desc": "Listor som blockerar spårning och reklam på de flesta enheterna", + "filter_category_security_desc": "Listor utformade specifikt för att blockera skadliga domäner, nätfiske och bluffdomäner", + "filter_category_regional_desc": "Listor som fokuserar på regionala annonser och spårningsservrar", + "filter_category_other_desc": "Andra blockeringslistor", + "setup_config_to_enable_dhcp_server": "Ställ in konfiguration för att aktivera DHCP-server", + "original_response": "Ursprungligt svar", + "click_to_view_queries": "Klicka för att se förfrågningar", + "port_53_faq_link": "Port 53 är ofta upptagen av \"DNSStubListener\" eller \"systemd-resolved\" tjänster. Läs <0>denna instruktion om hur du löser detta.", + "adg_will_drop_dns_queries": "AdGuard Home kommer att kasta alla DNS-frågor från den här klienten.", + "filter_allowlist": "VARNING: Denna åtgärd kommer också att utesluta regeln \"{{disallowed_rule}}\" från listan över tillåtna klienter.", + "last_rule_in_allowlist": "Det går inte att avvisa den här klienten eftersom att utesluta regeln \"{{disallowed_rule}}\" kommer att INAKTIVERA listan \"Tillåtna klienter\".", + "experimental": "Experimentell", "use_saved_key": "Använd den tidigare sparade nyckeln", - "parental_control": "Föräldrakontroll" + "parental_control": "Föräldrakontroll", + "safe_browsing": "Säker surfning", + "served_from_cache": "{{value}} (levereras från cache)" } diff --git a/client/src/__locales/zh-tw.json b/client/src/__locales/zh-tw.json index 2358a49b..da4ddca6 100644 --- a/client/src/__locales/zh-tw.json +++ b/client/src/__locales/zh-tw.json @@ -43,7 +43,7 @@ "form_error_ip6_format": "無效的 IPv6 位址", "form_error_ip_format": "無效的 IP 位址", "form_error_mac_format": "無效的媒體存取控制(MAC)位址", - "form_error_client_id_format": "用戶端 ID 必須只包含數值、小寫字母和連字號", + "form_error_client_id_format": "用戶端 ID 必須只包含數字、小寫字母和連字號", "form_error_server_name": "無效的伺服器名稱", "form_error_subnet": "子網路 \"{{cidr}}\" 不包含該 IP 位址 \"{{ip}}\"", "form_error_positive": "必須大於 0", From e29261516fa4d12e3cab76eeea19f7f5af4eada4 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Tue, 25 Jan 2022 18:20:26 +0300 Subject: [PATCH 100/135] Pull request: all: upd chlog Merge in DNS/adguard-home from upd-chlog to master Squashed commit of the following: commit ad258a27abfce7b1060d9937b446f6e794f8c172 Author: Ainar Garipov Date: Tue Jan 25 18:15:59 2022 +0300 all: upd chlog --- CHANGELOG.md | 45 +++++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c9e5b4b..4bb0e407 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,18 +17,37 @@ and this project adheres to ### Added -- Support for a `$dnsrewrite` modifier with an empty `NOERROR` response - ([#4133]). - `windows/arm64` support ([#3057]). ### Deprecated - Go 1.17 support. v0.109.0 will require at least Go 1.18 to build. +### Removed + +- Go 1.16 support. + +[#3057]: https://github.com/AdguardTeam/AdGuardHome/issues/3057 + + + + + + + +## [v0.107.3] - 2022-01-25 + +### Added + +- Support for a `$dnsrewrite` modifier with an empty `NOERROR` response + ([#4133]). + ### Fixed - Wrong set of ports checked for duplicates during the initial setup ([#4095]). @@ -37,11 +56,6 @@ TODO(a.garipov): Remove this deprecation, if v0.108.0 is released before the Go - Omitted aliases of hosts specified by another line within the OS's hosts file ([#4079]). -### Removed - -- Go 1.16 support. - -[#3057]: https://github.com/AdguardTeam/AdGuardHome/issues/3057 [#4074]: https://github.com/AdguardTeam/AdGuardHome/issues/4074 [#4079]: https://github.com/AdguardTeam/AdGuardHome/issues/4079 [#4095]: https://github.com/AdguardTeam/AdGuardHome/issues/4095 @@ -50,12 +64,6 @@ TODO(a.garipov): Remove this deprecation, if v0.108.0 is released before the Go - - - - ## [v0.107.2] - 2021-12-29 ### Fixed @@ -695,11 +703,12 @@ In this release, the schema version has changed from 10 to 12. -[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.2...HEAD +[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.3...HEAD +[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 [v0.107.1]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.0...v0.107.1 [v0.107.0]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.3...v0.107.0 From 0b72bcc5a1f4da47fe0dfc8154e71b94dcbc4896 Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Tue, 25 Jan 2022 18:54:37 +0300 Subject: [PATCH 101/135] Pull request: 1730 bogus cidr Merge in DNS/adguard-home from 1730-bogus-cidr to master Closes #1730. Squashed commit of the following: commit 0be54259ca4edb8752e9f7e5ea5104a2b51ed440 Author: Eugene Burkov Date: Tue Jan 25 18:50:01 2022 +0300 all: imp log of changes commit 59fb7a8c469216823ff54621ec40a4d084836132 Author: Eugene Burkov Date: Tue Jan 25 18:46:34 2022 +0300 all: log changes commit 9206b13dd715fdf1180d1d572d1b80024b9e6592 Author: Eugene Burkov Date: Tue Jan 25 18:41:26 2022 +0300 all: upd dnsproxy --- CHANGELOG.md | 6 ++++++ go.mod | 2 +- go.sum | 4 ++-- internal/dnsforward/config.go | 16 ++++++++-------- internal/querylog/qlog_test.go | 2 +- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bb0e407..709e8fe0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,11 @@ and this project adheres to - `windows/arm64` support ([#3057]). +### Changed + +- The `dns.bogus_nxdomain` configuration file parameter now supports CIDR + notation alongside IP addresses ([#1730]). + ### Deprecated - Go 1.17 support. v0.109.0 will require at least Go 1.18 to build. +## Fixed + +- Unnecessarily complex hosts-related logic leading to infinite recursion in + some cases ([#4216]). + ### Removed - Go 1.16 support. diff --git a/internal/aghnet/hostscontainer.go b/internal/aghnet/hostscontainer.go index 85379fed..198d4c78 100644 --- a/internal/aghnet/hostscontainer.go +++ b/internal/aghnet/hostscontainer.go @@ -46,13 +46,8 @@ type requestMatcher struct { } // MatchRequest processes the request rewriting hostnames and addresses read -// from the operating system's hosts files. -// -// res is nil for any request having not an A/AAAA or PTR type. Results -// containing CNAME information may be queried again with the same question type -// and the returned CNAME for Host field of request. Results are guaranteed to -// be direct, i.e. any returned CNAME resolves into actual address like an alias -// in hosts does, see man hosts (5). +// from the operating system's hosts files. res is nil for any request having +// not an A/AAAA or PTR type, see man 5 hosts. // // It's safe for concurrent use. func (rm *requestMatcher) MatchRequest( @@ -203,7 +198,7 @@ func (hc *HostsContainer) Close() (err error) { } // Upd returns the channel into which the updates are sent. The receivable -// map's values are guaranteed to be of type of *aghnet.Hosts. +// map's values are guaranteed to be of type of *stringutil.Set. func (hc *HostsContainer) Upd() (updates <-chan *netutil.IPMap) { return hc.updates } @@ -259,28 +254,14 @@ func (hc *HostsContainer) handleEvents() { } } -// ipRules is the pair of generated A/AAAA and PTR rules with related IP. -type ipRules struct { - // rule is the A/AAAA $dnsrewrite rule. - rule string - // rulePtr is the PTR $dnsrewrite rule. - rulePtr string - // ip is the IP address related to the rules. - ip net.IP -} - // hostsParser is a helper type to parse rules from the operating system's hosts // file. It exists for only a single refreshing session. type hostsParser struct { // rulesBuilder builds the resulting rules list content. rulesBuilder *strings.Builder - // rules stores the rules for main hosts to generate translations. - rules []ipRules - - // cnameSet prevents duplicating cname rules, e.g. same hostname for - // different IP versions. - cnameSet *stringutil.Set + // translations maps generated rules into actual hosts file lines. + translations map[string]string // table stores only the unique IP-hostname pairs. It's also sent to the // updates channel afterwards. @@ -290,13 +271,10 @@ type hostsParser struct { // newHostsParser creates a new *hostsParser with buffers of size taken from the // previous parse. func (hc *HostsContainer) newHostsParser() (hp *hostsParser) { - lastLen := hc.last.Len() - return &hostsParser{ rulesBuilder: &strings.Builder{}, - rules: make([]ipRules, 0, lastLen), - cnameSet: stringutil.NewSet(), - table: netutil.NewIPMap(lastLen), + translations: map[string]string{}, + table: netutil.NewIPMap(hc.last.Len()), } } @@ -342,6 +320,8 @@ func (hp *hostsParser) parseLine(line string) (ip net.IP, hosts []string) { // Make sure that invalid hosts aren't turned into rules. // // See https://github.com/AdguardTeam/AdGuardHome/issues/3946. + // + // TODO(e.burkov): Investigate if hosts may contain DNS-SD domains. err := netutil.ValidateDomainName(f) if err != nil { log.Error("%s: host %q is invalid, ignoring", hostsContainerPref, f) @@ -355,107 +335,45 @@ func (hp *hostsParser) parseLine(line string) (ip net.IP, hosts []string) { return ip, hosts } -// Hosts is used to contain the main host and all it's aliases. -type Hosts struct { - // Aliases contains all the aliases for Main. - Aliases *stringutil.Set - // Main is the host itself. - Main string -} - -// Equal returns true if h equals hh. -func (h *Hosts) Equal(hh *Hosts) (ok bool) { - if h == nil || hh == nil { - return h == hh - } - - return h.Main == hh.Main && h.Aliases.Equal(hh.Aliases) -} - -// add tries to add the ip-host pair. It returns: -// -// main host if the host is not the first one added for the ip. -// host itself if the host is the first one added for the ip. -// "" if the ip-host pair has already been added. -// -func (hp *hostsParser) add(ip net.IP, host string) (mainHost string) { - v, ok := hp.table.Get(ip) - switch h, _ := v.(*Hosts); { - case !ok: - // This is the first host for the ip. - hp.table.Set(ip, &Hosts{Main: host}) - - return host - case h.Main == host: - // This is a duplicate. Go on. - case h.Aliases == nil: - // This is the first alias. - h.Aliases = stringutil.NewSet(host) - - return h.Main - case !h.Aliases.Has(host): - // This is a new alias. - h.Aliases.Add(host) - - return h.Main - default: - // This is a duplicate. Go on. - } - - return "" -} - // addPair puts the pair of ip and host to the rules builder if needed. For // each ip the first member of hosts will become the main one. func (hp *hostsParser) addPairs(ip net.IP, hosts []string) { - for _, host := range hosts { - switch mainHost := hp.add(ip, host); mainHost { - case "": - // This host is a duplicate. + v, ok := hp.table.Get(ip) + if !ok { + // This ip is added at the first time. + v = stringutil.NewSet() + hp.table.Set(ip, v) + } + + var set *stringutil.Set + set, ok = v.(*stringutil.Set) + if !ok { + log.Debug("%s: adding pairs: unexpected value type %T", hostsContainerPref, v) + + return + } + + processed := strings.Join(append([]string{ip.String()}, hosts...), " ") + for _, h := range hosts { + if set.Has(h) { continue - case host: - // This host is main. - added, addedPtr := hp.writeMainRule(host, ip) - hp.rules = append(hp.rules, ipRules{ - rule: added, - rulePtr: addedPtr, - ip: ip, - }) - default: - // This host is an alias. - pair := fmt.Sprint(host, " ", mainHost) - if hp.cnameSet.Has(pair) { - continue - } - hp.writeAliasRule(host, mainHost) - hp.cnameSet.Add(pair) } - log.Debug("%s: added ip-host pair %q-%q", hostsContainerPref, ip, host) + set.Add(h) + + rule, rulePtr := hp.writeRules(h, ip) + hp.translations[rule], hp.translations[rulePtr] = processed, processed + + log.Debug("%s: added ip-host pair %q-%q", hostsContainerPref, ip, h) } } -// writeAliasRule writes the CNAME rule for the alias-host pair into internal -// builders. -func (hp *hostsParser) writeAliasRule(alias, host string) { - const ( - nl = "\n" - sc = ";" - - rwSuccess = rules.MaskSeparator + "$dnsrewrite=NOERROR" + sc + "CNAME" + sc - constLen = len(rules.MaskPipe) + len(rwSuccess) + len(nl) - ) - - hp.rulesBuilder.Grow(constLen + len(host) + len(alias)) - stringutil.WriteToBuilder(hp.rulesBuilder, rules.MaskPipe, alias, rwSuccess, host, nl) -} - -// writeMainRule writes the actual rule for the qtype and the PTR for the +// writeRules writes the actual rule for the qtype and the PTR for the // host-ip pair into internal builders. -func (hp *hostsParser) writeMainRule(host string, ip net.IP) (added, addedPtr string) { +func (hp *hostsParser) writeRules(host string, ip net.IP) (rule, rulePtr string) { arpa, err := netutil.IPToReversedAddr(ip) if err != nil { - return + return "", "" } const ( @@ -482,28 +400,20 @@ func (hp *hostsParser) writeMainRule(host string, ip net.IP) (added, addedPtr st ruleBuilder := &strings.Builder{} ruleBuilder.Grow(modLen + len(host) + len(qtype) + len(ipStr)) - stringutil.WriteToBuilder( - ruleBuilder, - rules.MaskPipe, - host, - rwSuccess, - qtype, - ";", - ipStr, - ) - added = ruleBuilder.String() + stringutil.WriteToBuilder(ruleBuilder, rules.MaskPipe, host, rwSuccess, qtype, ";", ipStr) + rule = ruleBuilder.String() ruleBuilder.Reset() ruleBuilder.Grow(modLenPTR + len(arpa) + len(fqdn)) stringutil.WriteToBuilder(ruleBuilder, rules.MaskPipe, arpa, rwSuccessPTR, fqdn) - addedPtr = ruleBuilder.String() + rulePtr = ruleBuilder.String() - hp.rulesBuilder.Grow(len(added) + len(addedPtr) + 2*len(nl)) - stringutil.WriteToBuilder(hp.rulesBuilder, added, nl, addedPtr, nl) + hp.rulesBuilder.Grow(len(rule) + len(rulePtr) + 2*len(nl)) + stringutil.WriteToBuilder(hp.rulesBuilder, rule, nl, rulePtr, nl) - return added, addedPtr + return rule, rulePtr } // equalSet returns true if the internal hosts table just parsed equals target. @@ -519,12 +429,11 @@ func (hp *hostsParser) equalSet(target *netutil.IPMap) (ok bool) { hp.table.Range(func(ip net.IP, b interface{}) (cont bool) { // ok is set to true if the target doesn't contain ip or if the - // appropriate hosts set isn't equal to the checked one, i.e. the main - // hosts differ or the maps have at least one discrepancy. + // appropriate hosts set isn't equal to the checked one. if a, hasIP := target.Get(ip); !hasIP { ok = true - } else if hosts, aok := a.(*Hosts); aok { - ok = !hosts.Equal(b.(*Hosts)) + } else if hosts, aok := a.(*stringutil.Set); aok { + ok = !hosts.Equal(b.(*stringutil.Set)) } // Continue only if maps has no discrepancies. @@ -563,35 +472,6 @@ func (hp *hostsParser) newStrg(id int) (s *filterlist.RuleStorage, err error) { }}) } -// translations generates the map to translate $dnsrewrite rules to -// hosts-syntax ones. -func (hp *hostsParser) translations() (trans map[string]string) { - l := len(hp.rules) - if l == 0 { - return nil - } - - trans = make(map[string]string, l*2) - for _, r := range hp.rules { - v, ok := hp.table.Get(r.ip) - if !ok { - continue - } - - var hosts *Hosts - hosts, ok = v.(*Hosts) - if !ok { - continue - } - - strs := append([]string{r.ip.String(), hosts.Main}, hosts.Aliases.Values()...) - hostsLine := strings.Join(strs, " ") - trans[r.rule], trans[r.rulePtr] = hostsLine, hostsLine - } - - return trans -} - // refresh gets the data from specified files and propagates the updates if // needed. // @@ -618,7 +498,7 @@ func (hc *HostsContainer) refresh() (err error) { return fmt.Errorf("initializing rules storage: %w", err) } - hc.resetEng(rulesStrg, hp.translations()) + hc.resetEng(rulesStrg, hp.translations) return nil } diff --git a/internal/aghnet/hostscontainer_test.go b/internal/aghnet/hostscontainer_test.go index 150e8c19..a141ce00 100644 --- a/internal/aghnet/hostscontainer_test.go +++ b/internal/aghnet/hostscontainer_test.go @@ -14,6 +14,7 @@ import ( "github.com/AdguardTeam/AdGuardHome/internal/aghtest" "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/stringutil" + "github.com/AdguardTeam/golibs/testutil" "github.com/AdguardTeam/urlfilter" "github.com/AdguardTeam/urlfilter/rules" "github.com/miekg/dns" @@ -86,6 +87,7 @@ func TestNewHostsContainer(t *testing.T) { return } + testutil.CleanupAndRequireSuccess(t, hc.Close) require.NoError(t, err) require.NotNil(t, hc) @@ -156,8 +158,9 @@ func TestHostsContainer_refresh(t *testing.T) { hc, err := NewHostsContainer(0, testFS, w, "dir") require.NoError(t, err) + testutil.CleanupAndRequireSuccess(t, hc.Close) - checkRefresh := func(t *testing.T, wantHosts Hosts) { + checkRefresh := func(t *testing.T, wantHosts *stringutil.Set) { upd, ok := <-hc.Upd() require.True(t, ok) require.NotNil(t, upd) @@ -167,22 +170,21 @@ func TestHostsContainer_refresh(t *testing.T) { v, ok := upd.Get(ip) require.True(t, ok) - var hosts *Hosts - hosts, ok = v.(*Hosts) + var set *stringutil.Set + set, ok = v.(*stringutil.Set) require.True(t, ok) - assert.Equal(t, wantHosts.Main, hosts.Main) - assert.True(t, hosts.Aliases.Equal(wantHosts.Aliases)) + assert.True(t, set.Equal(wantHosts)) } t.Run("initial_refresh", func(t *testing.T) { - checkRefresh(t, Hosts{Main: "hostname"}) + checkRefresh(t, stringutil.NewSet("hostname")) }) t.Run("second_refresh", func(t *testing.T) { testFS["dir/file2"] = &fstest.MapFile{Data: []byte(ipStr + ` alias` + nl)} eventsCh <- event{} - checkRefresh(t, Hosts{Main: "hostname", Aliases: stringutil.NewSet("alias")}) + checkRefresh(t, stringutil.NewSet("hostname", "alias")) }) t.Run("double_refresh", func(t *testing.T) { @@ -288,6 +290,7 @@ func TestHostsContainer_Translate(t *testing.T) { hc, err := NewHostsContainer(0, testdata, &stubWatcher, "etc_hosts") require.NoError(t, err) + testutil.CleanupAndRequireSuccess(t, hc.Close) testCases := []struct { name string @@ -300,7 +303,11 @@ func TestHostsContainer_Translate(t *testing.T) { }, { name: "hello", rule: "|hello^$dnsrewrite=NOERROR;A;1.0.0.0", - wantTrans: []string{"1.0.0.0", "hello", "hello.world", "hello.world.again"}, + wantTrans: []string{"1.0.0.0", "hello", "hello.world"}, + }, { + name: "hello-alias", + rule: "|hello.world.again^$dnsrewrite=NOERROR;A;1.0.0.0", + wantTrans: []string{"1.0.0.0", "hello.world.again"}, }, { name: "simplehost_v6", rule: "|simplehost^$dnsrewrite=NOERROR;AAAA;::1", @@ -308,7 +315,11 @@ func TestHostsContainer_Translate(t *testing.T) { }, { name: "hello_v6", rule: "|hello^$dnsrewrite=NOERROR;AAAA;::", - wantTrans: []string{"::", "hello", "hello.world", "hello.world.again"}, + wantTrans: []string{"::", "hello", "hello.world"}, + }, { + name: "hello_v6-alias", + rule: "|hello.world.again^$dnsrewrite=NOERROR;AAAA;::", + wantTrans: []string{"::", "hello.world.again"}, }, { name: "simplehost_ptr", rule: "|1.0.0.1.in-addr.arpa^$dnsrewrite=NOERROR;PTR;simplehost.", @@ -316,7 +327,11 @@ func TestHostsContainer_Translate(t *testing.T) { }, { name: "hello_ptr", rule: "|0.0.0.1.in-addr.arpa^$dnsrewrite=NOERROR;PTR;hello.", - wantTrans: []string{"1.0.0.0", "hello", "hello.world", "hello.world.again"}, + wantTrans: []string{"1.0.0.0", "hello", "hello.world"}, + }, { + name: "hello_ptr-alias", + rule: "|0.0.0.1.in-addr.arpa^$dnsrewrite=NOERROR;PTR;hello.world.again.", + wantTrans: []string{"1.0.0.0", "hello.world.again"}, }, { name: "simplehost_ptr_v6", rule: "|1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa" + @@ -326,14 +341,18 @@ func TestHostsContainer_Translate(t *testing.T) { name: "hello_ptr_v6", rule: "|0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa" + "^$dnsrewrite=NOERROR;PTR;hello.", - wantTrans: []string{"::", "hello", "hello.world", "hello.world.again"}, + wantTrans: []string{"::", "hello", "hello.world"}, + }, { + name: "hello_ptr_v6-alias", + rule: "|0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa" + + "^$dnsrewrite=NOERROR;PTR;hello.world.again.", + wantTrans: []string{"::", "hello.world.again"}, }} for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - want := stringutil.NewSet(tc.wantTrans...) got := stringutil.NewSet(strings.Fields(hc.Translate(tc.rule))...) - assert.True(t, want.Equal(got)) + assert.True(t, stringutil.NewSet(tc.wantTrans...).Equal(got)) }) } } @@ -354,7 +373,7 @@ func TestHostsContainer(t *testing.T) { RRType: dns.TypeA, }, { RCode: dns.RcodeSuccess, - Value: net.IP(append((&[15]byte{})[:], byte(1))), + Value: net.ParseIP("::1"), RRType: dns.TypeAAAA, }}, name: "simple", @@ -364,8 +383,13 @@ func TestHostsContainer(t *testing.T) { }, }, { want: []*rules.DNSRewrite{{ - RCode: dns.RcodeSuccess, - NewCNAME: "hello", + RCode: dns.RcodeSuccess, + Value: net.IPv4(1, 0, 0, 0), + RRType: dns.TypeA, + }, { + RCode: dns.RcodeSuccess, + Value: net.ParseIP("::"), + RRType: dns.TypeAAAA, }}, name: "hello_alias", req: urlfilter.DNSRequest{ @@ -374,8 +398,13 @@ func TestHostsContainer(t *testing.T) { }, }, { want: []*rules.DNSRewrite{{ - RCode: dns.RcodeSuccess, - NewCNAME: "hello", + RCode: dns.RcodeSuccess, + Value: net.IPv4(1, 0, 0, 0), + RRType: dns.TypeA, + }, { + RCode: dns.RcodeSuccess, + Value: net.ParseIP("::"), + RRType: dns.TypeAAAA, }}, name: "other_line_alias", req: urlfilter.DNSRequest{ @@ -398,8 +427,13 @@ func TestHostsContainer(t *testing.T) { }, }, { want: []*rules.DNSRewrite{{ - RCode: dns.RcodeSuccess, - NewCNAME: "a.whole", + RCode: dns.RcodeSuccess, + RRType: dns.TypeA, + Value: net.IPv4(1, 0, 0, 2), + }, { + RCode: dns.RcodeSuccess, + RRType: dns.TypeAAAA, + Value: net.ParseIP("::2"), }}, name: "lots_of_aliases", req: urlfilter.DNSRequest{ @@ -431,6 +465,51 @@ func TestHostsContainer(t *testing.T) { Hostname: "1.0.0.1.in-addr.arpa", DNSType: dns.TypeSRV, }, + }, { + want: []*rules.DNSRewrite{{ + RCode: dns.RcodeSuccess, + RRType: dns.TypeA, + Value: net.IPv4(4, 2, 1, 6), + }, { + RCode: dns.RcodeSuccess, + RRType: dns.TypeAAAA, + Value: net.ParseIP("::42"), + }}, + name: "issue_4216_4_6", + req: urlfilter.DNSRequest{ + Hostname: "domain", + DNSType: dns.TypeA, + }, + }, { + want: []*rules.DNSRewrite{{ + RCode: dns.RcodeSuccess, + RRType: dns.TypeA, + Value: net.IPv4(7, 5, 3, 1), + }, { + RCode: dns.RcodeSuccess, + RRType: dns.TypeA, + Value: net.IPv4(1, 3, 5, 7), + }}, + name: "issue_4216_4", + req: urlfilter.DNSRequest{ + Hostname: "domain4", + DNSType: dns.TypeA, + }, + }, { + want: []*rules.DNSRewrite{{ + RCode: dns.RcodeSuccess, + RRType: dns.TypeAAAA, + Value: net.ParseIP("::13"), + }, { + RCode: dns.RcodeSuccess, + RRType: dns.TypeAAAA, + Value: net.ParseIP("::31"), + }}, + name: "issue_4216_6", + req: urlfilter.DNSRequest{ + Hostname: "domain6", + DNSType: dns.TypeAAAA, + }, }} stubWatcher := aghtest.FSWatcher{ @@ -441,6 +520,7 @@ func TestHostsContainer(t *testing.T) { hc, err := NewHostsContainer(listID, testdata, &stubWatcher, "etc_hosts") require.NoError(t, err) + testutil.CleanupAndRequireSuccess(t, hc.Close) for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { diff --git a/internal/aghnet/testdata/etc_hosts b/internal/aghnet/testdata/etc_hosts index afe7011c..81041031 100644 --- a/internal/aghnet/testdata/etc_hosts +++ b/internal/aghnet/testdata/etc_hosts @@ -27,4 +27,12 @@ ::4 *.com :: hello.world.again ::1 simplehost -:: hello.world \ No newline at end of file +:: hello.world + +# See https://github.com/AdguardTeam/AdGuardHome/issues/4216. +4.2.1.6 domain domain.alias +::42 domain.alias domain +1.3.5.7 domain4 domain4.alias +7.5.3.1 domain4.alias domain4 +::13 domain6 domain6.alias +::31 domain6.alias domain6 \ No newline at end of file diff --git a/internal/filtering/filtering.go b/internal/filtering/filtering.go index a2a8ff21..0a8bcd6e 100644 --- a/internal/filtering/filtering.go +++ b/internal/filtering/filtering.go @@ -477,7 +477,7 @@ func (d *DNSFilter) matchSysHosts( return res, nil } - return d.matchSysHostsIntl(&urlfilter.DNSRequest{ + dnsres, _ := d.EtcHosts.MatchRequest(urlfilter.DNSRequest{ Hostname: host, SortedClientTags: setts.ClientTags, // TODO(e.burkov): Wait for urlfilter update to pass net.IP. @@ -485,12 +485,6 @@ func (d *DNSFilter) matchSysHosts( ClientName: setts.ClientName, DNSType: qtype, }) -} - -// matchSysHostsIntl actually matches the request. It's separated to avoid -// performing checks twice. -func (d *DNSFilter) matchSysHostsIntl(req *urlfilter.DNSRequest) (res Result, err error) { - dnsres, _ := d.EtcHosts.MatchRequest(*req) if dnsres == nil { return res, nil } @@ -501,13 +495,6 @@ func (d *DNSFilter) matchSysHostsIntl(req *urlfilter.DNSRequest) (res Result, er } res = d.processDNSRewrites(dnsr) - if cn := res.CanonName; cn != "" { - // Probably an alias. - req.Hostname = cn - - return d.matchSysHostsIntl(req) - } - res.Reason = RewrittenAutoHosts for _, r := range res.Rules { r.Text = stringutil.Coalesce(d.EtcHosts.Translate(r.Text), r.Text) diff --git a/internal/home/clients.go b/internal/home/clients.go index 94dd41f7..098fba91 100644 --- a/internal/home/clients.go +++ b/internal/home/clients.go @@ -783,17 +783,14 @@ func (clients *clientsContainer) addFromHostsFile(hosts *netutil.IPMap) { n := 0 hosts.Range(func(ip net.IP, v interface{}) (cont bool) { - hosts, ok := v.(*aghnet.Hosts) + hosts, ok := v.(*stringutil.Set) if !ok { log.Error("dns: bad type %T in ipToRC for %s", v, ip) return true } - if clients.addHostLocked(ip, hosts.Main, ClientSourceHostsFile) { - n++ - } - hosts.Aliases.Range(func(name string) (cont bool) { + hosts.Range(func(name string) (cont bool) { if clients.addHostLocked(ip, name, ClientSourceHostsFile) { n++ } From bf9b35b9c6a29b3c3f6535a8db993b879ab94d37 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Mon, 31 Jan 2022 18:40:21 +0300 Subject: [PATCH 107/135] Pull request: client: upd manual upd link Closes #4208. Squashed commit of the following: commit 4ae27b5f7cd6b0f4ec0c9041d92c4d1ac00dd622 Author: Ainar Garipov Date: Mon Jan 31 18:34:18 2022 +0300 client: upd manual upd link --- client/src/actions/index.js | 4 ++-- client/src/helpers/constants.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/actions/index.js b/client/src/actions/index.js index 5fd12b02..8e153224 100644 --- a/client/src/actions/index.js +++ b/client/src/actions/index.js @@ -13,7 +13,7 @@ import { STATUS_RESPONSE, SETTINGS_NAMES, FORM_NAME, - GETTING_STARTED_LINK, + MANUAL_UPDATE_LINK, } from '../helpers/constants'; import { areEqualVersions } from '../helpers/version'; import { getTlsStatus } from './encryption'; @@ -193,7 +193,7 @@ export const getUpdate = () => async (dispatch, getState) => { const handleRequestError = () => { const options = { components: { - a: , }, }; diff --git a/client/src/helpers/constants.js b/client/src/helpers/constants.js index ee0fd779..de65ad5e 100644 --- a/client/src/helpers/constants.js +++ b/client/src/helpers/constants.js @@ -58,7 +58,7 @@ export const REPOSITORY = { export const PRIVACY_POLICY_LINK = 'https://adguard.com/privacy/home.html'; export const PORT_53_FAQ_LINK = 'https://github.com/AdguardTeam/AdGuardHome/wiki/FAQ#bindinuse'; export const UPSTREAM_CONFIGURATION_WIKI_LINK = 'https://github.com/AdguardTeam/AdGuardHome/wiki/Configuration#upstreams'; -export const GETTING_STARTED_LINK = 'https://github.com/AdguardTeam/AdGuardHome/wiki/Getting-Started#update'; +export const MANUAL_UPDATE_LINK = 'https://github.com/AdguardTeam/AdGuardHome/wiki/FAQ#manual-update'; export const FILTERS_RELATIVE_LINK = '#filters'; From 2d46aa7121f49fb8e35abe62f02223b87c879eb3 Mon Sep 17 00:00:00 2001 From: Ildar Kamalov Date: Mon, 31 Jan 2022 20:14:09 +0300 Subject: [PATCH 108/135] Pull request: 4212 fix query log search results Closes #4212. Squashed commit of the following: commit cd854e5bf71953c753c690c28b5571f2c8b1ea0f Merge: 8532ca80 bf9b35b9 Author: Ainar Garipov Date: Mon Jan 31 20:10:17 2022 +0300 Merge branch 'master' into 4212-logs commit 8532ca80d135e4c306ac4d0c999475d77ba51a02 Author: Ildar Kamalov Date: Mon Jan 31 19:22:52 2022 +0300 fix lint commit 1a85074180d95d7a7aad854c75a7a811aee719e9 Author: Ildar Kamalov Date: Mon Jan 31 19:14:54 2022 +0300 client: fix query log search results --- client/src/reducers/queryLogs.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/client/src/reducers/queryLogs.js b/client/src/reducers/queryLogs.js index 19d92afb..1575c62d 100644 --- a/client/src/reducers/queryLogs.js +++ b/client/src/reducers/queryLogs.js @@ -28,11 +28,7 @@ const queryLogs = handleActions( }; }, - [actions.setLogsFilterRequest]: (state, { payload }) => { - const { filter } = payload; - - return { ...state, filter }; - }, + [actions.setLogsFilterRequest]: (state, { payload }) => ({ ...state, filter: payload }), [actions.getLogsRequest]: (state) => ({ ...state, processingGetLogs: true }), [actions.getLogsFailure]: (state) => ({ ...state, processingGetLogs: false }), From 8455940b5951579b0694f390af933fcd3665240e Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Tue, 1 Feb 2022 14:39:05 +0300 Subject: [PATCH 109/135] Pull request: all: upd quic-go Merge in DNS/adguard-home from upd-quic-go to master Squashed commit of the following: commit c7f0ab02a54ac435b6e0040dd221d819cf3ecdd4 Author: Ainar Garipov Date: Tue Feb 1 14:33:26 2022 +0300 all: upd quic-go --- go.mod | 3 ++- go.sum | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 00aee165..45adc3a8 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( 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.24.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/mdlayher/raw v0.0.0-20211126142749-4eae47f3d54b @@ -46,6 +46,7 @@ require ( 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/nxadm/tail v1.4.8 // indirect github.com/onsi/ginkgo v1.16.5 // indirect diff --git a/go.sum b/go.sum index d2abef6a..66427814 100644 --- a/go.sum +++ b/go.sum @@ -148,8 +148,9 @@ 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 h1:ToR7SIIEdrgOhgVTHvPgdVRJfgVy+N0wQAagH7L4d5g= 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/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= @@ -158,6 +159,8 @@ github.com/marten-seemann/qtls-go1-16 v0.1.4 h1:xbHbOGGhrenVtII6Co8akhLEdrawwB2i 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-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-18 v0.1.0-beta.1/go.mod h1:PUhIQk19LoFt2174H4+an8TYvWOGjb/hHwphBeaDHwI= 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= From 76fa60498e6c67dc4b9222e8fcaa4a8f85de27eb Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Tue, 1 Feb 2022 19:42:07 +0300 Subject: [PATCH 110/135] Pull request: all: imp ann url Updates #4209. Squashed commit of the following: commit 0c31a59c5bf6bcc27a4779adf226d9a1ac9eece1 Merge: 803f32db 8455940b Author: Ainar Garipov Date: Tue Feb 1 19:33:55 2022 +0300 Merge branch 'master' into 4209-ann-url commit 803f32dbc7276077a4374ed0f5e0a1fa36f91c9b Author: Ildar Kamalov Date: Tue Feb 1 14:46:47 2022 +0300 client: add manual update link to update topline commit ca375b52fa53503a3987b9723eb9a1d74878e890 Author: Ainar Garipov Date: Mon Jan 31 20:49:42 2022 +0300 all: imp ann url --- client/src/__locales/en.json | 1 + client/src/components/ui/UpdateTopline.js | 33 ++++++++++++++++------- scripts/make/build-release.sh | 12 ++++++--- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index ccc4c0b8..4b19ea7a 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -403,6 +403,7 @@ "dns_providers": "Here is a <0>list of known DNS providers to choose from.", "update_now": "Update now", "update_failed": "Auto-update failed. Please follow these steps to update manually.", + "manual_update": "Please follow these steps to update manually.", "processing_update": "Please wait, AdGuard Home is being updated", "clients_title": "Clients", "clients_desc": "Configure devices connected to AdGuard Home", diff --git a/client/src/components/ui/UpdateTopline.js b/client/src/components/ui/UpdateTopline.js index 2e78c884..85e75f4a 100644 --- a/client/src/components/ui/UpdateTopline.js +++ b/client/src/components/ui/UpdateTopline.js @@ -1,8 +1,10 @@ import React from 'react'; import { Trans } from 'react-i18next'; import { shallowEqual, useDispatch, useSelector } from 'react-redux'; + import Topline from './Topline'; import { getUpdate } from '../../actions'; +import { MANUAL_UPDATE_LINK } from '../../helpers/constants'; const UpdateTopline = () => { const { @@ -29,16 +31,27 @@ const UpdateTopline = () => { > update_announcement - {canAutoUpdate - && - } +   + {canAutoUpdate ? ( + + ) : ( + + Link + + ), + }}> + manual_update + + )} ; }; diff --git a/scripts/make/build-release.sh b/scripts/make/build-release.sh index f3326a04..16486e0b 100644 --- a/scripts/make/build-release.sh +++ b/scripts/make/build-release.sh @@ -379,17 +379,21 @@ readonly version_download_url version_json # Point users to the master branch if the channel is edge. if [ "$channel" = 'edge' ] then - version_history_url='https://github.com/AdguardTeam/AdGuardHome/commits/master' + # TODO(a.garipov): Put a link to the platforms page here. Something like: + # + # announcement_url='https://github.com/AdguardTeam/AdGuardHome/wiki/Platforms' + # + announcement_url='https://github.com/AdguardTeam/AdGuardHome/commits/master' else - version_history_url='https://github.com/AdguardTeam/AdGuardHome/releases' + announcement_url="https://github.com/AdguardTeam/AdGuardHome/releases/tag/${version}" fi -readonly version_history_url +readonly announcement_url rm -f "$version_json" echo "{ \"version\": \"${version}\", \"announcement\": \"AdGuard Home ${version} is now available!\", - \"announcement_url\": \"${version_history_url}\", + \"announcement_url\": \"${announcement_url}\", \"selfupdate_min_version\": \"0.0\", " >> "$version_json" From 9146df5493ddaf4022047dda116cdb285f7af48d Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Tue, 1 Feb 2022 20:00:32 +0300 Subject: [PATCH 111/135] Pull request: scripts: add link to platforms page Closes #4209. Squashed commit of the following: commit 12d99e7454ff01e00f29e51d002147a04a77a2b3 Author: Ainar Garipov Date: Tue Feb 1 19:55:31 2022 +0300 scripts: imp docs commit 12c4dabea2bac04601202a05d0c820ff2e32c93e Author: Ainar Garipov Date: Tue Feb 1 19:49:16 2022 +0300 scripts: add link to platforms page --- scripts/make/build-release.sh | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/scripts/make/build-release.sh b/scripts/make/build-release.sh index 16486e0b..f9b8e8da 100644 --- a/scripts/make/build-release.sh +++ b/scripts/make/build-release.sh @@ -7,7 +7,7 @@ # Experienced readers may find it overly verbose. # The default verbosity level is 0. Show log messages if the caller requested -# verbosity level greather than 0. Show every command that is run if the +# verbosity level greater than 0. Show every command that is run if the # verbosity level is greater than 1. Show the environment if the verbosity # level is greater than 2. Otherwise, print nothing. # @@ -370,20 +370,17 @@ log "writing versions" echo "version=$version" > "./${dist}/version.txt" -# Create the verison.json file. +# Create the version.json file. version_download_url="https://static.adguard.com/adguardhome/${channel}" version_json="./${dist}/version.json" readonly version_download_url version_json -# Point users to the master branch if the channel is edge. +# If the channel is edge, point users to the "Platforms" page on the Wiki, +# because the direct links to the edge packages are listed there. if [ "$channel" = 'edge' ] then - # TODO(a.garipov): Put a link to the platforms page here. Something like: - # - # announcement_url='https://github.com/AdguardTeam/AdGuardHome/wiki/Platforms' - # - announcement_url='https://github.com/AdguardTeam/AdGuardHome/commits/master' + announcement_url='https://github.com/AdguardTeam/AdGuardHome/wiki/Platforms' else announcement_url="https://github.com/AdguardTeam/AdGuardHome/releases/tag/${version}" fi From 0ee34534c664530211f6014c73c48f17d486086a Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Tue, 1 Feb 2022 21:44:01 +0300 Subject: [PATCH 112/135] Pull request: all: switch to SOURCE_DATE_EPOCH for source date Closes #4221. Squashed commit of the following: commit c84a5699280cf4c0b1c2ed034a44f05ffc74d30d Author: Ainar Garipov Date: Tue Feb 1 21:13:30 2022 +0300 all: switch to SOURCE_DATE_EPOCH for source date --- CHANGELOG.md | 8 ++++++++ internal/version/version.go | 25 +++++++++++++++++-------- scripts/README.md | 7 +++++-- scripts/make/Dockerfile | 30 +++++++++++++++++------------- scripts/make/go-build.sh | 8 ++++---- scripts/make/version.sh | 1 + 6 files changed, 52 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20aafe62..5ad22454 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,11 @@ and this project adheres to ### Changed +- Instead of adding the build time information, the build scripts now use the + standardized environment variable [`SOURCE_DATE_EPOCH`][repr] to add the date + 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 configuration file to avoid confusion ([#3367]). - The `dns.bogus_nxdomain` configuration file parameter now supports CIDR @@ -74,6 +79,9 @@ In this release, the schema version has changed from 12 to 13. [#2993]: https://github.com/AdguardTeam/AdGuardHome/issues/2993 [#3057]: https://github.com/AdguardTeam/AdGuardHome/issues/3057 [#3367]: https://github.com/AdguardTeam/AdGuardHome/issues/3367 +[#4221]: https://github.com/AdguardTeam/AdGuardHome/issues/4221 + +[repr]: https://reproducible-builds.org/docs/source-date-epoch/ diff --git a/internal/version/version.go b/internal/version/version.go index 4218d99e..eec8c4d0 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -7,6 +7,7 @@ import ( "runtime/debug" "strconv" "strings" + "time" "github.com/AdguardTeam/golibs/stringutil" ) @@ -26,11 +27,11 @@ const ( // TODO(a.garipov): Find out if we can get GOARM and GOMIPS values the same way // we can GOARCH and GOOS. var ( - channel string = ChannelDevelopment - goarm string - gomips string - version string - buildtime string + channel string = ChannelDevelopment + goarm string + gomips string + version string + committime string ) // Channel returns the current AdGuard Home release channel. @@ -106,7 +107,7 @@ const ( vFmtVerHdr = "Version: " vFmtChanHdr = "Channel: " vFmtGoHdr = "Go version: " - vFmtTimeHdr = "Build time: " + vFmtTimeHdr = "Commit time: " vFmtRaceHdr = "Race: " vFmtGOOSHdr = "GOOS: " + runtime.GOOS vFmtGOARCHHdr = "GOARCH: " + runtime.GOARCH @@ -148,15 +149,23 @@ func Verbose() (v string) { vFmtGoHdr, runtime.Version(), ) - if buildtime != "" { - stringutil.WriteToBuilder(b, nl, vFmtTimeHdr, buildtime) + + if committime != "" { + commitTimeUnix, err := strconv.ParseInt(committime, 10, 64) + if err != nil { + stringutil.WriteToBuilder(b, nl, vFmtTimeHdr, fmt.Sprintf("parse error: %s", err)) + } else { + stringutil.WriteToBuilder(b, nl, vFmtTimeHdr, time.Unix(commitTimeUnix, 0).String()) + } } + stringutil.WriteToBuilder(b, nl, vFmtGOOSHdr, nl, vFmtGOARCHHdr) if goarm != "" { stringutil.WriteToBuilder(b, nl, vFmtGOARMHdr, "v", goarm) } else if gomips != "" { stringutil.WriteToBuilder(b, nl, vFmtGOMIPSHdr, gomips) } + stringutil.WriteToBuilder(b, nl, vFmtRaceHdr, strconv.FormatBool(isRace)) info, ok := debug.ReadBuildInfo() diff --git a/scripts/README.md b/scripts/README.md index 1ca2e471..3178d7ee 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -90,14 +90,15 @@ Required environment: ### `go-build.sh`: Build The Backend Optional environment: - * `BUILD_TIME`: If set, overrides the build time information. Useful for - reproducible builds. * `GOARM`: ARM processor options for the Go compiler. * `GOMIPS`: ARM processor options for the Go compiler. * `GO`: set an alternative name for the Go compiler. * `OUT`: output binary name. * `PARALLELISM`: set the maximum number of concurrently run build commands (that is, compiler, linker, etc.). + * `SOURCE_DATE_EPOCH`: the [standardized][repr] environment variable for the + Unix epoch time of the latest commit in the repository. If set, overrides + the default obtained from Git. Useful for reproducible builds. * `VERBOSE`: verbosity level. `1` shows every command that is run and every Go package that is processed. `2` also shows subcommands and environment. The default value is `0`, don't be verbose. @@ -107,6 +108,8 @@ Optional environment: Required environment: * `CHANNEL`: release channel, see above. +[repr]: https://reproducible-builds.org/docs/source-date-epoch/ + ### `go-deps.sh`: Install Backend Dependencies diff --git a/scripts/make/Dockerfile b/scripts/make/Dockerfile index 44649721..f5a543a2 100644 --- a/scripts/make/Dockerfile +++ b/scripts/make/Dockerfile @@ -5,22 +5,26 @@ FROM alpine:3.13 ARG BUILD_DATE ARG VERSION ARG VCS_REF -LABEL maintainer="AdGuard Team " \ - org.opencontainers.image.created=$BUILD_DATE \ - org.opencontainers.image.url="https://adguard.com/adguard-home.html" \ - org.opencontainers.image.source="https://github.com/AdguardTeam/AdGuardHome" \ - org.opencontainers.image.version=$VERSION \ - org.opencontainers.image.revision=$VCS_REF \ - org.opencontainers.image.vendor="AdGuard" \ - org.opencontainers.image.title="AdGuard Home" \ - org.opencontainers.image.description="Network-wide ads & trackers blocking DNS server" \ - org.opencontainers.image.licenses="GPL-3.0" + +LABEL\ + maintainer="AdGuard Team " \ + org.opencontainers.image.authors="AdGuard Team " \ + org.opencontainers.image.created=$BUILD_DATE \ + org.opencontainers.image.description="Network-wide ads & trackers blocking DNS server" \ + org.opencontainers.image.documentation="https://github.com/AdguardTeam/AdGuardHome/wiki/" \ + org.opencontainers.image.licenses="GPL-3.0" \ + org.opencontainers.image.revision=$VCS_REF \ + org.opencontainers.image.source="https://github.com/AdguardTeam/AdGuardHome" \ + org.opencontainers.image.title="AdGuard Home" \ + org.opencontainers.image.url="https://adguard.com/en/adguard-home/overview.html" \ + org.opencontainers.image.vendor="AdGuard" \ + org.opencontainers.image.version=$VERSION # Update certificates. RUN apk --no-cache --update add ca-certificates libcap tzdata && \ - rm -rf /var/cache/apk/* && \ - mkdir -p /opt/adguardhome/conf /opt/adguardhome/work && \ - chown -R nobody: /opt/adguardhome + rm -rf /var/cache/apk/* && \ + mkdir -p /opt/adguardhome/conf /opt/adguardhome/work && \ + chown -R nobody: /opt/adguardhome ARG DIST_DIR ARG TARGETARCH diff --git a/scripts/make/go-build.sh b/scripts/make/go-build.sh index d6b86f51..7854166c 100644 --- a/scripts/make/go-build.sh +++ b/scripts/make/go-build.sh @@ -65,9 +65,9 @@ then fi readonly version -# Set date and time of the current build unless already set. -buildtime="${BUILD_TIME:-$( date -u +%FT%TZ%z )}" -readonly buildtime +# Set date and time of the latest commit unless already set. +committime="${SOURCE_DATE_EPOCH:-$( git log -1 --pretty=%ct )}" +readonly committime # Set the linker flags accordingly: set the release channel and the current # version as well as goarm and gomips variable values, if the variables are set @@ -78,7 +78,7 @@ readonly version_pkg ldflags="-s -w" ldflags="${ldflags} -X ${version_pkg}.version=${version}" ldflags="${ldflags} -X ${version_pkg}.channel=${channel}" -ldflags="${ldflags} -X ${version_pkg}.buildtime=${buildtime}" +ldflags="${ldflags} -X ${version_pkg}.committime=${committime}" if [ "${GOARM:-}" != '' ] then ldflags="${ldflags} -X ${version_pkg}.goarm=${GOARM}" diff --git a/scripts/make/version.sh b/scripts/make/version.sh index 45cfd353..903be7bf 100644 --- a/scripts/make/version.sh +++ b/scripts/make/version.sh @@ -86,6 +86,7 @@ in # minor release. If the current commit is the new minor release, # num_commits_since_minor is zero. num_commits_since_minor="$( git rev-list "${last_minor_zero}..HEAD" | wc -l )" + # The output of darwin's implementation of wc needs to be trimmed from # redundant spaces. num_commits_since_minor="$( echo "$num_commits_since_minor" | tr -d '[:space:]' )" From e783564084c8396fa0f216103e339d9c6991981a Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Thu, 3 Feb 2022 21:19:32 +0300 Subject: [PATCH 113/135] Pull request: 4238 response filtering Merge in DNS/adguard-home from 4238-response-filtering to master Closes #4238. Squashed commit of the following: commit 2113f83c617a396a39f910bb8df939364fedf391 Author: Eugene Burkov Date: Thu Feb 3 21:04:25 2022 +0300 dnsforward: restore a bit commit f78607ed97892557c6bd6f3c3332f0bae01c1987 Author: Eugene Burkov Date: Thu Feb 3 20:52:45 2022 +0300 all: imp code, docs commit 646074ce141e8ac12a972f46d071389a2ce124e4 Author: Eugene Burkov Date: Thu Feb 3 20:37:05 2022 +0300 all: log changes commit 94556d810549370fc455bcf14537fa1d2783eed1 Author: Eugene Burkov Date: Thu Feb 3 20:30:57 2022 +0300 all: imp test upstream, cover resp filtering commit 63e7721822a049734a390c7d7ea6d8416a43c8b5 Author: Eugene Burkov Date: Tue Feb 1 21:58:08 2022 +0300 all: filter response by rrtype --- CHANGELOG.md | 3 + internal/aghtest/aghtest.go | 20 ++-- internal/aghtest/upstream.go | 83 ++++--------- internal/dnsforward/dns.go | 6 +- internal/dnsforward/dns_test.go | 4 +- internal/dnsforward/dnsforward_test.go | 46 +++---- internal/dnsforward/filter.go | 41 ++++--- internal/dnsforward/filter_test.go | 159 +++++++++++++++++++++++++ internal/filtering/filtering.go | 21 ++-- internal/home/rdns_test.go | 2 +- 10 files changed, 257 insertions(+), 128 deletions(-) create mode 100644 internal/dnsforward/filter_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ad22454..1f00e1d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ and this project adheres to ### Changed +- Response filtering is now performed using the record types of the answer + section of messages as opposed to the type of the question ([#4238]). - Instead of adding the build time information, the build scripts now use the standardized environment variable [`SOURCE_DATE_EPOCH`][repr] to add the date of the commit from which the binary was built ([#4221]). This should simplify @@ -80,6 +82,7 @@ In this release, the schema version has changed from 12 to 13. [#3057]: https://github.com/AdguardTeam/AdGuardHome/issues/3057 [#3367]: https://github.com/AdguardTeam/AdGuardHome/issues/3367 [#4221]: https://github.com/AdguardTeam/AdGuardHome/issues/4221 +[#4238]: https://github.com/AdguardTeam/AdGuardHome/issues/4238 [repr]: https://reproducible-builds.org/docs/source-date-epoch/ diff --git a/internal/aghtest/aghtest.go b/internal/aghtest/aghtest.go index 0e7f600c..878ef178 100644 --- a/internal/aghtest/aghtest.go +++ b/internal/aghtest/aghtest.go @@ -20,17 +20,19 @@ func DiscardLogOutput(m *testing.M) { // ReplaceLogWriter moves logger output to w and uses Cleanup method of t to // revert changes. -func ReplaceLogWriter(t *testing.T, w io.Writer) { - stdWriter := log.Writer() - t.Cleanup(func() { - log.SetOutput(stdWriter) - }) +func ReplaceLogWriter(t testing.TB, w io.Writer) { + t.Helper() + + prev := log.Writer() + t.Cleanup(func() { log.SetOutput(prev) }) log.SetOutput(w) } // ReplaceLogLevel sets logging level to l and uses Cleanup method of t to // revert changes. -func ReplaceLogLevel(t *testing.T, l log.Level) { +func ReplaceLogLevel(t testing.TB, l log.Level) { + t.Helper() + switch l { case log.INFO, log.DEBUG, log.ERROR: // Go on. @@ -38,9 +40,7 @@ func ReplaceLogLevel(t *testing.T, l log.Level) { t.Fatalf("wrong l value (must be one of %v, %v, %v)", log.INFO, log.DEBUG, log.ERROR) } - stdLevel := log.GetLevel() - t.Cleanup(func() { - log.SetLevel(stdLevel) - }) + prev := log.GetLevel() + t.Cleanup(func() { log.SetLevel(prev) }) log.SetLevel(l) } diff --git a/internal/aghtest/upstream.go b/internal/aghtest/upstream.go index aa364310..95d8f5ad 100644 --- a/internal/aghtest/upstream.go +++ b/internal/aghtest/upstream.go @@ -11,10 +11,10 @@ import ( "github.com/miekg/dns" ) -// TestUpstream is a mock of real upstream. -type TestUpstream struct { +// Upstream is a mock implementation of upstream.Upstream. +type Upstream struct { // CName is a map of hostname to canonical name. - CName map[string]string + CName map[string][]string // IPv4 is a map of hostname to IPv4. IPv4 map[string][]net.IP // IPv6 is a map of hostname to IPv6. @@ -25,78 +25,45 @@ type TestUpstream struct { Addr string } -// Exchange implements upstream.Upstream interface for *TestUpstream. +// Exchange implements the upstream.Upstream interface for *Upstream. // // TODO(a.garipov): Split further into handlers. -func (u *TestUpstream) Exchange(m *dns.Msg) (resp *dns.Msg, err error) { - resp = &dns.Msg{} - resp.SetReply(m) +func (u *Upstream) Exchange(m *dns.Msg) (resp *dns.Msg, err error) { + resp = new(dns.Msg).SetReply(m) if len(m.Question) == 0 { return nil, fmt.Errorf("question should not be empty") } - name := m.Question[0].Name - - if cname, ok := u.CName[name]; ok { - ans := &dns.CNAME{ - Hdr: dns.RR_Header{ - Name: name, - Rrtype: dns.TypeCNAME, - }, + q := m.Question[0] + name := q.Name + for _, cname := range u.CName[name] { + resp.Answer = append(resp.Answer, &dns.CNAME{ + Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeCNAME}, Target: cname, - } - - resp.Answer = append(resp.Answer, ans) + }) } - rrType := m.Question[0].Qtype + qtype := q.Qtype hdr := dns.RR_Header{ Name: name, - Rrtype: rrType, + Rrtype: qtype, } - var names []string - var ips []net.IP - switch m.Question[0].Qtype { + switch qtype { case dns.TypeA: - ips = u.IPv4[name] + for _, ip := range u.IPv4[name] { + resp.Answer = append(resp.Answer, &dns.A{Hdr: hdr, A: ip}) + } case dns.TypeAAAA: - ips = u.IPv6[name] + for _, ip := range u.IPv6[name] { + resp.Answer = append(resp.Answer, &dns.AAAA{Hdr: hdr, AAAA: ip}) + } case dns.TypePTR: - names = u.Reverse[name] - } - - for _, ip := range ips { - var ans dns.RR - if rrType == dns.TypeA { - ans = &dns.A{ - Hdr: hdr, - A: ip, - } - - resp.Answer = append(resp.Answer, ans) - - continue + for _, name := range u.Reverse[name] { + resp.Answer = append(resp.Answer, &dns.PTR{Hdr: hdr, Ptr: name}) } - - ans = &dns.AAAA{ - Hdr: hdr, - AAAA: ip, - } - - resp.Answer = append(resp.Answer, ans) } - - for _, n := range names { - ans := &dns.PTR{ - Hdr: hdr, - Ptr: n, - } - - resp.Answer = append(resp.Answer, ans) - } - if len(resp.Answer) == 0 { resp.SetRcode(m, dns.RcodeNameError) } @@ -104,8 +71,8 @@ func (u *TestUpstream) Exchange(m *dns.Msg) (resp *dns.Msg, err error) { return resp, nil } -// Address implements upstream.Upstream interface for *TestUpstream. -func (u *TestUpstream) Address() string { +// Address implements upstream.Upstream interface for *Upstream. +func (u *Upstream) Address() string { return u.Addr } diff --git a/internal/dnsforward/dns.go b/internal/dnsforward/dns.go index c11171d9..87cb5194 100644 --- a/internal/dnsforward/dns.go +++ b/internal/dnsforward/dns.go @@ -613,9 +613,9 @@ func (s *Server) processFilteringAfterResponse(ctx *dnsContext) (rc resultCode) d.Res.Answer = answer } default: - // Check the response only if the it's from an upstream. Don't check - // the response if the protection is disabled since dnsrewrite rules - // aren't applied to it anyway. + // Check the response only if it's from an upstream. Don't check the + // response if the protection is disabled since dnsrewrite rules aren't + // applied to it anyway. if !ctx.protectionEnabled || !ctx.responseFromUpstream || s.dnsFilter == nil { break } diff --git a/internal/dnsforward/dns_test.go b/internal/dnsforward/dns_test.go index edf54f51..4fc87ccf 100644 --- a/internal/dnsforward/dns_test.go +++ b/internal/dnsforward/dns_test.go @@ -261,7 +261,7 @@ func TestServer_ProcessInternalHosts(t *testing.T) { } func TestServer_ProcessRestrictLocal(t *testing.T) { - ups := &aghtest.TestUpstream{ + ups := &aghtest.Upstream{ Reverse: map[string][]string{ "251.252.253.254.in-addr.arpa.": {"host1.example.net."}, "1.1.168.192.in-addr.arpa.": {"some.local-client."}, @@ -339,7 +339,7 @@ func TestServer_ProcessLocalPTR_usingResolvers(t *testing.T) { s := createTestServer(t, &filtering.Config{}, ServerConfig{ UDPListenAddrs: []*net.UDPAddr{{}}, TCPListenAddrs: []*net.TCPAddr{{}}, - }, &aghtest.TestUpstream{ + }, &aghtest.Upstream{ Reverse: map[string][]string{ reqAddr: {locDomain}, }, diff --git a/internal/dnsforward/dnsforward_test.go b/internal/dnsforward/dnsforward_test.go index d0191c85..bc90d760 100644 --- a/internal/dnsforward/dnsforward_test.go +++ b/internal/dnsforward/dnsforward_test.go @@ -89,7 +89,7 @@ func createTestServer( defer s.serverLock.Unlock() if localUps != nil { - s.localResolvers.Config.UpstreamConfig.Upstreams = []upstream.Upstream{localUps} + s.localResolvers.UpstreamConfig.Upstreams = []upstream.Upstream{localUps} s.conf.UsePrivateRDNS = true } @@ -247,7 +247,7 @@ func TestServer(t *testing.T) { TCPListenAddrs: []*net.TCPAddr{{}}, }, nil) s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{ - &aghtest.TestUpstream{ + &aghtest.Upstream{ IPv4: map[string][]net.IP{ "google-public-dns-a.google.com.": {{8, 8, 8, 8}}, }, @@ -316,7 +316,7 @@ func TestServerWithProtectionDisabled(t *testing.T) { TCPListenAddrs: []*net.TCPAddr{{}}, }, nil) s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{ - &aghtest.TestUpstream{ + &aghtest.Upstream{ IPv4: map[string][]net.IP{ "google-public-dns-a.google.com.": {{8, 8, 8, 8}}, }, @@ -339,7 +339,7 @@ func TestDoTServer(t *testing.T) { TLSListenAddrs: []*net.TCPAddr{{}}, }) s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{ - &aghtest.TestUpstream{ + &aghtest.Upstream{ IPv4: map[string][]net.IP{ "google-public-dns-a.google.com.": {{8, 8, 8, 8}}, }, @@ -369,7 +369,7 @@ func TestDoQServer(t *testing.T) { QUICListenAddrs: []*net.UDPAddr{{IP: net.IP{127, 0, 0, 1}}}, }) s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{ - &aghtest.TestUpstream{ + &aghtest.Upstream{ IPv4: map[string][]net.IP{ "google-public-dns-a.google.com.": {{8, 8, 8, 8}}, }, @@ -413,7 +413,7 @@ func TestServerRace(t *testing.T) { } s := createTestServer(t, filterConf, forwardConf, nil) s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{ - &aghtest.TestUpstream{ + &aghtest.Upstream{ IPv4: map[string][]net.IP{ "google-public-dns-a.google.com.": {{8, 8, 8, 8}}, }, @@ -552,7 +552,7 @@ func TestServerCustomClientUpstream(t *testing.T) { } s := createTestServer(t, &filtering.Config{}, forwardConf, nil) s.conf.GetCustomUpstreamByClient = func(_ string) (conf *proxy.UpstreamConfig, err error) { - ups := &aghtest.TestUpstream{ + ups := &aghtest.Upstream{ IPv4: map[string][]net.IP{ "host.": {{192, 168, 0, 1}}, }, @@ -580,9 +580,9 @@ func TestServerCustomClientUpstream(t *testing.T) { } // testCNAMEs is a map of names and CNAMEs necessary for the TestUpstream work. -var testCNAMEs = map[string]string{ - "badhost.": "NULL.example.org.", - "whitelist.example.org.": "NULL.example.org.", +var testCNAMEs = map[string][]string{ + "badhost.": {"NULL.example.org."}, + "whitelist.example.org.": {"NULL.example.org."}, } // testIPv4 is a map of names and IPv4s necessary for the TestUpstream work. @@ -596,7 +596,7 @@ func TestBlockCNAMEProtectionEnabled(t *testing.T) { UDPListenAddrs: []*net.UDPAddr{{}}, TCPListenAddrs: []*net.TCPAddr{{}}, }, nil) - testUpstm := &aghtest.TestUpstream{ + testUpstm := &aghtest.Upstream{ CName: testCNAMEs, IPv4: testIPv4, IPv6: nil, @@ -630,7 +630,7 @@ func TestBlockCNAME(t *testing.T) { } s := createTestServer(t, &filtering.Config{}, forwardConf, nil) s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{ - &aghtest.TestUpstream{ + &aghtest.Upstream{ CName: testCNAMEs, IPv4: testIPv4, }, @@ -640,14 +640,17 @@ func TestBlockCNAME(t *testing.T) { addr := s.dnsProxy.Addr(proxy.ProtoUDP).String() testCases := []struct { + name string host string want bool }{{ + name: "block_request", host: "badhost.", // 'badhost' has a canonical name 'NULL.example.org' which is // blocked by filters: response is blocked. want: true, }, { + name: "allowed", host: "whitelist.example.org.", // 'whitelist.example.org' has a canonical name // 'NULL.example.org' which is blocked by filters @@ -655,6 +658,7 @@ func TestBlockCNAME(t *testing.T) { // response isn't blocked. want: false, }, { + name: "block_response", host: "example.org.", // 'example.org' has a canonical name 'cname1' with IP // 127.0.0.255 which is blocked by filters: response is blocked. @@ -662,9 +666,9 @@ func TestBlockCNAME(t *testing.T) { }} for _, tc := range testCases { - t.Run("block_cname_"+tc.host, func(t *testing.T) { - req := createTestMessage(tc.host) + req := createTestMessage(tc.host) + t.Run(tc.name, func(t *testing.T) { reply, err := dns.Exchange(req, addr) require.NoError(t, err) @@ -674,7 +678,7 @@ func TestBlockCNAME(t *testing.T) { ans := reply.Answer[0] a, ok := ans.(*dns.A) - require.Truef(t, ok, "got %T", ans) + require.True(t, ok) assert.True(t, a.A.IsUnspecified()) } @@ -695,7 +699,7 @@ func TestClientRulesForCNAMEMatching(t *testing.T) { } s := createTestServer(t, &filtering.Config{}, forwardConf, nil) s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{ - &aghtest.TestUpstream{ + &aghtest.Upstream{ CName: testCNAMEs, IPv4: testIPv4, }, @@ -931,9 +935,9 @@ func TestRewrite(t *testing.T) { })) s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{ - &aghtest.TestUpstream{ - CName: map[string]string{ - "example.org": "somename", + &aghtest.Upstream{ + CName: map[string][]string{ + "example.org": {"somename"}, }, IPv4: map[string][]net.IP{ "example.org.": {{4, 3, 2, 1}}, @@ -1193,12 +1197,12 @@ func TestNewServer(t *testing.T) { } func TestServer_Exchange(t *testing.T) { - extUpstream := &aghtest.TestUpstream{ + extUpstream := &aghtest.Upstream{ Reverse: map[string][]string{ "1.1.1.1.in-addr.arpa.": {"one.one.one.one"}, }, } - locUpstream := &aghtest.TestUpstream{ + locUpstream := &aghtest.Upstream{ Reverse: map[string][]string{ "1.1.168.192.in-addr.arpa.": {"local.domain"}, "2.1.168.192.in-addr.arpa.": {}, diff --git a/internal/dnsforward/filter.go b/internal/dnsforward/filter.go index 471b463e..18f12797 100644 --- a/internal/dnsforward/filter.go +++ b/internal/dnsforward/filter.go @@ -116,7 +116,7 @@ func (s *Server) filterDNSRequest(ctx *dnsContext) (*filtering.Result, error) { // checkHostRules checks the host against filters. It is safe for concurrent // use. -func (s *Server) checkHostRules(host string, qtype uint16, setts *filtering.Settings) ( +func (s *Server) checkHostRules(host string, rrtype uint16, setts *filtering.Settings) ( r *filtering.Result, err error, ) { @@ -128,7 +128,7 @@ func (s *Server) checkHostRules(host string, qtype uint16, setts *filtering.Sett } var res filtering.Result - res, err = s.dnsFilter.CheckHostRules(host, qtype, setts) + res, err = s.dnsFilter.CheckHostRules(host, rrtype, setts) if err != nil { return nil, err } @@ -136,33 +136,36 @@ func (s *Server) checkHostRules(host string, qtype uint16, setts *filtering.Sett return &res, err } -// If response contains CNAME, A or AAAA records, we apply filtering to each -// canonical host name or IP address. If this is a match, we set a new response -// in d.Res and return. -func (s *Server) filterDNSResponse(ctx *dnsContext) (*filtering.Result, error) { +// filterDNSResponse checks each resource record of the response's answer +// section from ctx and returns a non-nil res if at least one of canonnical +// names or IP addresses in it matches the filtering rules. +func (s *Server) filterDNSResponse(ctx *dnsContext) (res *filtering.Result, err error) { d := ctx.proxyCtx + setts := ctx.setts + if !setts.FilteringEnabled { + return nil, nil + } + for _, a := range d.Res.Answer { host := "" - - switch v := a.(type) { + var rrtype uint16 + switch a := a.(type) { case *dns.CNAME: - log.Debug("DNSFwd: Checking CNAME %s for %s", v.Target, v.Hdr.Name) - host = strings.TrimSuffix(v.Target, ".") - + host = strings.TrimSuffix(a.Target, ".") + rrtype = dns.TypeCNAME case *dns.A: - host = v.A.String() - log.Debug("DNSFwd: Checking record A (%s) for %s", host, v.Hdr.Name) - + host = a.A.String() + rrtype = dns.TypeA case *dns.AAAA: - host = v.AAAA.String() - log.Debug("DNSFwd: Checking record AAAA (%s) for %s", host, v.Hdr.Name) - + host = a.AAAA.String() + rrtype = dns.TypeAAAA default: continue } - host = strings.TrimSuffix(host, ".") - res, err := s.checkHostRules(host, d.Req.Question[0].Qtype, ctx.setts) + log.Debug("dnsforward: checking %s %s for %s", dns.Type(rrtype), host, a.Header().Name) + + res, err = s.checkHostRules(host, rrtype, setts) if err != nil { return nil, err } else if res == nil { diff --git a/internal/dnsforward/filter_test.go b/internal/dnsforward/filter_test.go new file mode 100644 index 00000000..84570bce --- /dev/null +++ b/internal/dnsforward/filter_test.go @@ -0,0 +1,159 @@ +package dnsforward + +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 TestHandleDNSRequest_filterDNSResponse(t *testing.T) { + rules := ` +||blocked.domain^ +@@||allowed.domain^ +||cname.specific^$dnstype=~CNAME +||0.0.0.1^$dnstype=~A +||::1^$dnstype=~AAAA +` + + forwardConf := ServerConfig{ + UDPListenAddrs: []*net.UDPAddr{{}}, + TCPListenAddrs: []*net.TCPAddr{{}}, + FilteringConfig: FilteringConfig{ + ProtectionEnabled: true, + BlockingMode: BlockingModeDefault, + }, + } + filters := []filtering.Filter{{ + ID: 0, Data: []byte(rules), + }} + + 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, + }) + require.NoError(t, err) + + s.conf = forwardConf + err = s.Prepare(nil) + require.NoError(t, err) + + s.conf.UpstreamConfig.Upstreams = []upstream.Upstream{ + &aghtest.Upstream{ + CName: map[string][]string{ + "cname.exception.": {"cname.specific."}, + "should.block.": {"blocked.domain."}, + "allowed.first.": {"allowed.domain.", "blocked.domain."}, + "blocked.first.": {"blocked.domain.", "allowed.domain."}, + }, + IPv4: map[string][]net.IP{ + "a.exception.": {{0, 0, 0, 1}}, + }, + IPv6: map[string][]net.IP{ + "aaaa.exception.": {net.ParseIP("::1")}, + }, + }, + } + startDeferStop(t, s) + + testCases := []struct { + req *dns.Msg + name string + wantAns []dns.RR + }{{ + req: createTestMessage("cname.exception."), + name: "cname_exception", + wantAns: []dns.RR{&dns.CNAME{ + Hdr: dns.RR_Header{ + Name: "cname.exception.", + Rrtype: dns.TypeCNAME, + }, + Target: "cname.specific.", + }}, + }, { + req: createTestMessage("should.block."), + name: "blocked_by_cname", + wantAns: []dns.RR{&dns.A{ + Hdr: dns.RR_Header{ + Name: "should.block.", + Rrtype: dns.TypeA, + Class: dns.ClassINET, + }, + A: netutil.IPv4Zero(), + }}, + }, { + req: createTestMessage("a.exception."), + name: "a_exception", + wantAns: []dns.RR{&dns.A{ + Hdr: dns.RR_Header{ + Name: "a.exception.", + Rrtype: dns.TypeA, + }, + A: net.IP{0, 0, 0, 1}, + }}, + }, { + req: createTestMessageWithType("aaaa.exception.", dns.TypeAAAA), + name: "aaaa_exception", + wantAns: []dns.RR{&dns.AAAA{ + Hdr: dns.RR_Header{ + Name: "aaaa.exception.", + Rrtype: dns.TypeAAAA, + }, + AAAA: net.ParseIP("::1"), + }}, + }, { + req: createTestMessage("allowed.first."), + name: "allowed_first", + wantAns: []dns.RR{&dns.A{ + Hdr: dns.RR_Header{ + Name: "allowed.first.", + Rrtype: dns.TypeA, + Class: dns.ClassINET, + }, + A: netutil.IPv4Zero(), + }}, + }, { + req: createTestMessage("blocked.first."), + name: "blocked_first", + wantAns: []dns.RR{&dns.A{ + Hdr: dns.RR_Header{ + Name: "blocked.first.", + Rrtype: dns.TypeA, + Class: dns.ClassINET, + }, + A: netutil.IPv4Zero(), + }}, + }} + + for _, tc := range testCases { + dctx := &proxy.DNSContext{ + Proto: proxy.ProtoUDP, + Req: tc.req, + Addr: &net.UDPAddr{IP: net.IP{127, 0, 0, 1}, Port: 1}, + } + + t.Run(tc.name, func(t *testing.T) { + err = s.handleDNSRequest(nil, dctx) + require.NoError(t, err) + require.NotNil(t, dctx.Res) + + assert.Equal(t, tc.wantAns, dctx.Res.Answer) + }) + } +} diff --git a/internal/filtering/filtering.go b/internal/filtering/filtering.go index 0a8bcd6e..9bedeef7 100644 --- a/internal/filtering/filtering.go +++ b/internal/filtering/filtering.go @@ -420,14 +420,8 @@ func (r Reason) Matched() bool { } // CheckHostRules tries to match the host against filtering rules only. -func (d *DNSFilter) CheckHostRules(host string, qtype uint16, setts *Settings) (Result, error) { - if !setts.FilteringEnabled { - return Result{}, nil - } - - host = strings.ToLower(host) - - return d.matchHost(host, qtype, setts) +func (d *DNSFilter) CheckHostRules(host string, rrtype uint16, setts *Settings) (Result, error) { + return d.matchHost(strings.ToLower(host), rrtype, setts) } // CheckHost tries to match the host against filtering rules, then safebrowsing @@ -726,8 +720,7 @@ func hostRulesToRules(netRules []*rules.HostRule) (res []rules.Rule) { return res } -// matchHostProcessAllowList processes the allowlist logic of host -// matching. +// matchHostProcessAllowList processes the allowlist logic of host matching. func (d *DNSFilter) matchHostProcessAllowList( host string, dnsres *urlfilter.DNSResult, @@ -798,11 +791,11 @@ func (d *DNSFilter) matchHostProcessDNSResult( return Result{} } -// matchHost is a low-level way to check only if hostname is filtered by rules, +// matchHost is a low-level way to check only if host is filtered by rules, // skipping expensive safebrowsing and parental lookups. func (d *DNSFilter) matchHost( host string, - qtype uint16, + rrtype uint16, setts *Settings, ) (res Result, err error) { if !setts.FilteringEnabled { @@ -815,7 +808,7 @@ func (d *DNSFilter) matchHost( // TODO(e.burkov): Wait for urlfilter update to pass net.IP. ClientIP: setts.ClientIP.String(), ClientName: setts.ClientName, - DNSType: qtype, + DNSType: rrtype, } d.engineLock.RLock() @@ -855,7 +848,7 @@ func (d *DNSFilter) matchHost( return Result{}, nil } - res = d.matchHostProcessDNSResult(qtype, dnsres) + res = d.matchHostProcessDNSResult(rrtype, dnsres) for _, r := range res.Rules { log.Debug( "filtering: found rule %q for host %q, filter list id: %d", diff --git a/internal/home/rdns_test.go b/internal/home/rdns_test.go index 202f9f5f..08f4f013 100644 --- a/internal/home/rdns_test.go +++ b/internal/home/rdns_test.go @@ -167,7 +167,7 @@ func TestRDNS_WorkerLoop(t *testing.T) { w := &bytes.Buffer{} aghtest.ReplaceLogWriter(t, w) - locUpstream := &aghtest.TestUpstream{ + locUpstream := &aghtest.Upstream{ Reverse: map[string][]string{ "192.168.1.1": {"local.domain"}, "2a00:1450:400c:c06::93": {"ipv6.domain"}, From dc480ae70f978bca4d407283e316ccedd388c86a Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Fri, 4 Feb 2022 18:18:28 +0300 Subject: [PATCH 114/135] Pull request #1432: all: add gh milestone links to chlog Merge in DNS/adguard-home from chlog-ms-links to master Squashed commit of the following: commit 97156f1452a7713e5e8d66a9b5eeac25fb97ab04 Author: Ainar Garipov Date: Fri Feb 4 17:56:58 2022 +0300 all: add gh milestone links to chlog --- CHANGELOG.md | 69 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f00e1d2..132c6629 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,7 +63,7 @@ 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 +### Fixed - Unnecessarily complex hosts-related logic leading to infinite recursion in some cases ([#4216]). @@ -90,12 +90,18 @@ In this release, the schema version has changed from 12 to 13. ## [v0.107.3] - 2022-01-25 +See also the [v0.107.3 GitHub milestone][ms-v0.107.3]. + ### Added - Support for a `$dnsrewrite` modifier with an empty `NOERROR` response @@ -115,20 +121,28 @@ In this release, the schema version has changed from 12 to 13. [#4120]: https://github.com/AdguardTeam/AdGuardHome/issues/4120 [#4133]: https://github.com/AdguardTeam/AdGuardHome/issues/4133 +[ms-v0.107.3]: https://github.com/AdguardTeam/AdGuardHome/milestone/40?closed=1 + ## [v0.107.2] - 2021-12-29 +See also the [v0.107.2 GitHub milestone][ms-v0.107.2]. + ### Fixed - Infinite loops when TCP connections time out ([#4042]). [#4042]: https://github.com/AdguardTeam/AdGuardHome/issues/4042 +[ms-v0.107.2]: https://github.com/AdguardTeam/AdGuardHome/milestone/38?closed=1 + ## [v0.107.1] - 2021-12-29 +See also the [v0.107.1 GitHub milestone][ms-v0.107.1]. + ### Changed - The validation error message for duplicated allow- and blocklists in DNS @@ -154,10 +168,14 @@ In this release, the schema version has changed from 12 to 13. [#4016]: https://github.com/AdguardTeam/AdGuardHome/issues/4016 [#4027]: https://github.com/AdguardTeam/AdGuardHome/issues/4027 +[ms-v0.107.1]: https://github.com/AdguardTeam/AdGuardHome/milestone/37?closed=1 + ## [v0.107.0] - 2021-12-21 +See also the [v0.107.0 GitHub milestone][ms-v0.107.0]. + ### Added - Upstream server information for responses from cache ([#3772]). Note that old @@ -394,10 +412,14 @@ In this release, the schema version has changed from 10 to 12. [#3904]: https://github.com/AdguardTeam/AdGuardHome/issues/3904 [#3933]: https://github.com/AdguardTeam/AdGuardHome/pull/3933 +[ms-v0.107.0]: https://github.com/AdguardTeam/AdGuardHome/milestone/23?closed=1 + ## [v0.106.3] - 2021-05-19 +See also the [v0.106.3 GitHub milestone][ms-v0.106.3]. + ### Added - Support for reinstall (`-r`) and uninstall (`-u`) flags in the installation @@ -427,20 +449,28 @@ In this release, the schema version has changed from 10 to 12. [#3115]: https://github.com/AdguardTeam/AdGuardHome/issues/3115 [#3127]: https://github.com/AdguardTeam/AdGuardHome/issues/3127 +[ms-v0.106.3]: https://github.com/AdguardTeam/AdGuardHome/milestone/35?closed=1 + ## [v0.106.2] - 2021-05-06 +See also the [v0.106.2 GitHub milestone][ms-v0.106.2]. + ### Fixed - Uniqueness validation for dynamic DHCP leases ([#3056]). [#3056]: https://github.com/AdguardTeam/AdGuardHome/issues/3056 +[ms-v0.106.2]: https://github.com/AdguardTeam/AdGuardHome/milestone/34?closed=1 + ## [v0.106.1] - 2021-04-30 +See also the [v0.106.1 GitHub milestone][ms-v0.106.1]. + ### Fixed - Local domain name handling when the DHCP server is disabled ([#3028]). @@ -451,10 +481,14 @@ In this release, the schema version has changed from 10 to 12. [#3027]: https://github.com/AdguardTeam/AdGuardHome/issues/3027 [#3028]: https://github.com/AdguardTeam/AdGuardHome/issues/3028 +[ms-v0.106.1]: https://github.com/AdguardTeam/AdGuardHome/milestone/33?closed=1 + ## [v0.106.0] - 2021-04-28 +See also the [v0.106.0 GitHub milestone][ms-v0.106.0]. + ### Added - The ability to block user for login after configurable number of unsuccessful @@ -543,11 +577,14 @@ In this release, the schema version has changed from 10 to 12. [#2994]: https://github.com/AdguardTeam/AdGuardHome/issues/2994 [doq-draft-02]: https://tools.ietf.org/html/draft-ietf-dprive-dnsoquic-02 +[ms-v0.106.0]: https://github.com/AdguardTeam/AdGuardHome/milestone/26?closed=1 ## [v0.105.2] - 2021-03-10 +See also the [v0.105.2 GitHub milestone][ms-v0.105.2]. + ### Fixed - Incomplete hostnames with trailing zero-bytes handling ([#2582]). @@ -559,6 +596,11 @@ In this release, the schema version has changed from 10 to 12. - 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 [#2674]: https://github.com/AdguardTeam/AdGuardHome/issues/2674 @@ -567,16 +609,14 @@ In this release, the schema version has changed from 10 to 12. [#2692]: https://github.com/AdguardTeam/AdGuardHome/issues/2692 [#2757]: https://github.com/AdguardTeam/AdGuardHome/issues/2757 -### Security - -- Session token doesn't contain user's information anymore ([#2470]). - -[#2470]: https://github.com/AdguardTeam/AdGuardHome/issues/2470 +[ms-v0.105.2]: https://github.com/AdguardTeam/AdGuardHome/milestone/32?closed=1 ## [v0.105.1] - 2021-02-15 +See also the [v0.105.1 GitHub milestone][ms-v0.105.1]. + ### Changed - Increased HTTP API timeouts ([#2671], [#2682]). @@ -616,10 +656,14 @@ In this release, the schema version has changed from 10 to 12. [#2678]: https://github.com/AdguardTeam/AdGuardHome/issues/2678 [#2682]: https://github.com/AdguardTeam/AdGuardHome/issues/2682 +[ms-v0.105.1]: https://github.com/AdguardTeam/AdGuardHome/milestone/31?closed=1 + ## [v0.105.0] - 2021-02-10 +See also the [v0.105.0 GitHub milestone][ms-v0.105.0]. + ### Added - Added more services to the "Blocked services" list ([#2224], [#2401]). @@ -717,18 +761,28 @@ In this release, the schema version has changed from 10 to 12. [#2639]: https://github.com/AdguardTeam/AdGuardHome/issues/2639 [#2646]: https://github.com/AdguardTeam/AdGuardHome/issues/2646 +[ms-v0.105.0]: https://github.com/AdguardTeam/AdGuardHome/milestone/27?closed=1 + + + ## [v0.104.3] - 2020-11-19 +See also the [v0.104.3 GitHub milestone][ms-v0.104.3]. + ### Fixed - The accidentally exposed profiler HTTP API ([#2336]). [#2336]: https://github.com/AdguardTeam/AdGuardHome/issues/2336 +[ms-v0.104.3]: https://github.com/AdguardTeam/AdGuardHome/milestone/30?closed=1 + ## [v0.104.2] - 2020-11-19 +See also the [v0.104.2 GitHub milestone][ms-v0.104.2]. + ### Added - This changelog :-) ([#2294]). @@ -753,6 +807,9 @@ In this release, the schema version has changed from 10 to 12. [#2324]: https://github.com/AdguardTeam/AdGuardHome/issues/2324 [#2325]: https://github.com/AdguardTeam/AdGuardHome/issues/2325 +[ms-v0.104.2]: https://github.com/AdguardTeam/AdGuardHome/milestone/28?closed=1 + + - Go 1.17 support. v0.109.0 will require at least Go 1.18 to build. ### Fixed +- Optimistic cache now responds with expired items even if those can't be + resolved again ([#4254]). - Unnecessarily complex hosts-related logic leading to infinite recursion in some cases ([#4216]). @@ -81,8 +79,10 @@ In this release, the schema version has changed from 12 to 13. [#2993]: https://github.com/AdguardTeam/AdGuardHome/issues/2993 [#3057]: https://github.com/AdguardTeam/AdGuardHome/issues/3057 [#3367]: https://github.com/AdguardTeam/AdGuardHome/issues/3367 +[#4216]: https://github.com/AdguardTeam/AdGuardHome/issues/4216 [#4221]: https://github.com/AdguardTeam/AdGuardHome/issues/4221 [#4238]: https://github.com/AdguardTeam/AdGuardHome/issues/4238 +[#4254]: https://github.com/AdguardTeam/AdGuardHome/issues/4254 [repr]: https://reproducible-builds.org/docs/source-date-epoch/ From 6d0a43aad66239b462204f5386d495acd571c96a Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Tue, 8 Feb 2022 13:53:58 +0300 Subject: [PATCH 117/135] Pull request: client: upd i18n Merge in DNS/adguard-home from upd-i18n to master Squashed commit of the following: commit e2f9e9f52a424b7c13beebfc2f8fea3814d3b2f4 Author: Ainar Garipov Date: Tue Feb 8 13:48:17 2022 +0300 client: upd i18n --- client/src/__locales/cs.json | 1 + client/src/__locales/da.json | 1 + client/src/__locales/de.json | 3 ++- client/src/__locales/es.json | 1 + client/src/__locales/fa.json | 2 +- client/src/__locales/fi.json | 1 + client/src/__locales/fr.json | 3 ++- client/src/__locales/it.json | 1 + client/src/__locales/ja.json | 1 + client/src/__locales/ko.json | 1 + client/src/__locales/nl.json | 1 + client/src/__locales/no.json | 22 +++++++++++++++++++++- client/src/__locales/pl.json | 1 + client/src/__locales/pt-br.json | 1 + client/src/__locales/pt-pt.json | 1 + client/src/__locales/ro.json | 1 + client/src/__locales/ru.json | 1 + client/src/__locales/sk.json | 1 + client/src/__locales/sl.json | 1 + client/src/__locales/sv.json | 1 + client/src/__locales/tr.json | 1 + client/src/__locales/zh-cn.json | 1 + client/src/__locales/zh-tw.json | 1 + 23 files changed, 45 insertions(+), 4 deletions(-) diff --git a/client/src/__locales/cs.json b/client/src/__locales/cs.json index 67f9a7e5..95935953 100644 --- a/client/src/__locales/cs.json +++ b/client/src/__locales/cs.json @@ -403,6 +403,7 @@ "dns_providers": "Zde je <0>seznam známých poskytovatelů DNS, z nichž si můžete vybrat.", "update_now": "Aktualizovat nyní", "update_failed": "Automatická aktualizace selhala. Prosím následujte tyto kroky a aktualizujte ručně.", + "manual_update": "Prosím následujte tyto kroky a aktualizujte ručně.", "processing_update": "Čekejte prosím, AdGuard Home se aktualizuje", "clients_title": "Klienti", "clients_desc": "Konfigurace zařízení připojených k AdGuard Home", diff --git a/client/src/__locales/da.json b/client/src/__locales/da.json index eb5b3c2f..04d8a393 100644 --- a/client/src/__locales/da.json +++ b/client/src/__locales/da.json @@ -403,6 +403,7 @@ "dns_providers": "Her er en <0>liste over kendte DNS-udbydere at vælge imellem.", "update_now": "Opdatér nu", "update_failed": "Autoopdatering mislykkedes. Følg disse trin for at opdatere manuelt.", + "manual_update": "Følg disse trin for at opdatere manuelt.", "processing_update": "Vent venligst, AdGuard Home bliver opdateret", "clients_title": "Klienter", "clients_desc": "Opsæt enheder forbundet til AdGuard Home", diff --git a/client/src/__locales/de.json b/client/src/__locales/de.json index 559deb15..4fb4cd02 100644 --- a/client/src/__locales/de.json +++ b/client/src/__locales/de.json @@ -6,7 +6,7 @@ "parallel_requests": "Paralleles Abfragen", "load_balancing": "Lastverteilung", "load_balancing_desc": "Einen Server nach dem anderen abfragen. AdGuard Home verwendet den gewichteten Zufallsalgorithmus, um den Server so auszuwählen, dass der schnellste Server häufiger verwendet wird.", - "bootstrap_dns": "Bootstrap DNS-Server starten", + "bootstrap_dns": "Bootstrap DNS-Server", "bootstrap_dns_desc": "Bootstrap-DNS-Server werden verwendet, um IP-Adressen der DoH/DoT-Resolver aufzulösen, die Sie als Upstreams angeben.", "local_ptr_title": "Private inverse DNS-Server", "local_ptr_desc": "Die DNS-Server, die AdGuard Home für lokale PTR-Abfragen verwendet. Diese Server werden verwendet, um die Hostnamen von Clients mit privaten IP-Adressen, z. B. „192.168.12.34“, per inverse DNS-Anfragen aufzulösen. Wenn nicht festgelegt, verwendet AdGuard Home die Adressen der Standard-DNS-Auflöser Ihres Betriebssystems mit Ausnahme der Adressen von AdGuard Home selbst.", @@ -403,6 +403,7 @@ "dns_providers": "Hier finden Sie eine <0>Liste der bekannten DNS-Anbieter zur Auswahl.", "update_now": "Jetzt aktualisieren", "update_failed": "Das automatische Aktualisieren ist fehlgeschlagen. Bitte folgen Sie den Schritten, um manuell zu aktualisieren.", + "manual_update": "Bitte befolgen Sie diese Schritte, um manuell zu aktualisieren.", "processing_update": "Bitte warten Sie, AdGuard Home wird aktualisiert …", "clients_title": "Clients", "clients_desc": "Geräte einrichten, die mit AdGuard Home verbunden sind", diff --git a/client/src/__locales/es.json b/client/src/__locales/es.json index d6702989..753330ac 100644 --- a/client/src/__locales/es.json +++ b/client/src/__locales/es.json @@ -403,6 +403,7 @@ "dns_providers": "Aquí hay una <0>lista de proveedores DNS conocidos para elegir.", "update_now": "Actualizar ahora", "update_failed": "Error en la actualización automática. Por favor sigue estos pasos para actualizar manualmente.", + "manual_update": "Por favor sigue estos pasos para actualizar manualmente.", "processing_update": "Por favor espera, AdGuard Home se está actualizando", "clients_title": "Clientes", "clients_desc": "Configurar dispositivos conectados con AdGuard Home", diff --git a/client/src/__locales/fa.json b/client/src/__locales/fa.json index 90b07629..22e78275 100644 --- a/client/src/__locales/fa.json +++ b/client/src/__locales/fa.json @@ -313,7 +313,7 @@ "fix": "تعمیر", "dns_providers": "در اینجا یک <0>لیست از سرویس های ارائه دهنده DNS برای انتخاب هست.", "update_now": "حالا بروز رسانی", - "update_failed": "بروز رسانی خودکار موفق نشد. لطفا مراحل را دنبال کرده تا بطور دستی بروز رسانی کنید.", + "update_failed": "بروز رسانی خودکار موفق نشد. لطفا مراحل را دنبال کرده تا بطور دستی بروز رسانی کنید.", "processing_update": "منتظر بمانید،AdGuard Home در حال بروز رسانی است", "clients_title": "کلاینت ها", "clients_desc": "پیکربندی دستگاه های متصل شده به AdGuard Home", diff --git a/client/src/__locales/fi.json b/client/src/__locales/fi.json index 8228f1f6..d17d3646 100644 --- a/client/src/__locales/fi.json +++ b/client/src/__locales/fi.json @@ -403,6 +403,7 @@ "dns_providers": "Katso <0>luettelo tunnetuista DNS-palveluista, joista valita.", "update_now": "Päivitä nyt", "update_failed": "Automaattinen päivitys epäonnistui. Seuraa näitä ohjeita päivittääksesi manuaalisesti.", + "manual_update": "Seuraa näitä ohjeita päivittääksesi manuaalisesti.", "processing_update": "Odota kun AdGuard Home päivittyy", "clients_title": "Päätelaitteet", "clients_desc": "Määritä AdGuard Homeen yhdistetyt päätelaitteet", diff --git a/client/src/__locales/fr.json b/client/src/__locales/fr.json index e84ce1c4..e3260cdd 100644 --- a/client/src/__locales/fr.json +++ b/client/src/__locales/fr.json @@ -402,7 +402,8 @@ "fix": "Corriger", "dns_providers": "Voici une <0>liste de fournisseurs DNS connus.", "update_now": "Mettre à jour maintenant", - "update_failed": "Échec de la mise à jour automatique. Veuillez suivre ces étapes pour mettre à jour manuellement.", + "update_failed": "Échec de la mise à jour automatique. Veuillez suivre ces étapes pour mettre à jour manuellement.", + "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", "clients_desc": "Configurer les appareils connectés à AdGuard Home", diff --git a/client/src/__locales/it.json b/client/src/__locales/it.json index 35e1e30f..f0be3db7 100644 --- a/client/src/__locales/it.json +++ b/client/src/__locales/it.json @@ -403,6 +403,7 @@ "dns_providers": "Qui c'è un <0>elenco di fornitori DNS noti da cui scegliere.", "update_now": "Aggiorna ora", "update_failed": "Aggiornamento automatico non riuscito. Ti suggeriamo di seguire questi passaggi per aggiornare manualmente.", + "manual_update": "Ti invitiamo a seguire questi passaggi per aggiornare manualmente.", "processing_update": "Perfavore aspetta, AdGuard Home si sta aggiornando", "clients_title": "Client", "clients_desc": "Configura i dispositivi connessi ad AdGuard Home", diff --git a/client/src/__locales/ja.json b/client/src/__locales/ja.json index 3cb78c57..bc85b3e6 100644 --- a/client/src/__locales/ja.json +++ b/client/src/__locales/ja.json @@ -403,6 +403,7 @@ "dns_providers": "こちらは、選択可能な<0>既知のDNSプロバイダの一覧です。", "update_now": "今すぐ更新する", "update_failed": "自動更新に失敗しました。手動で更新するには、手順に従ってください。", + "manual_update": "手動でアップデートするには、こちらの手順を使ってください。", "processing_update": "AdGuard Homeを更新しています。しばらくお待ちください", "clients_title": "クライアント", "clients_desc": "AdGuard Homeに接続されているデバイスを設定します", diff --git a/client/src/__locales/ko.json b/client/src/__locales/ko.json index 2927797a..ba40f48c 100644 --- a/client/src/__locales/ko.json +++ b/client/src/__locales/ko.json @@ -403,6 +403,7 @@ "dns_providers": "다음은 선택할 수 있는 <0>알려진 DNS 공급자 목록입니다.", "update_now": "지금 업데이트", "update_failed": "자동 업데이트 실패 되었습니다. 단계를 따라 수동으로 업데이트하세요", + "manual_update": "절차를 따라 수동으로 업데이트하십시오.", "processing_update": "잠시만 기다려주세요, AdGuard Home가 업데이트 중입니다.", "clients_title": "클라이언트", "clients_desc": "AdGuard Home에 연결할 기기들을 설정", diff --git a/client/src/__locales/nl.json b/client/src/__locales/nl.json index 03c471f3..b6933045 100644 --- a/client/src/__locales/nl.json +++ b/client/src/__locales/nl.json @@ -403,6 +403,7 @@ "dns_providers": "hier is een <0>lijst of gekende DNS providers waarvan je kan kiezen.", "update_now": "Update nu", "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", "clients_title": "Gebruikers", "clients_desc": "Configureer apparaten die gebruik maken van AdGuard Home", diff --git a/client/src/__locales/no.json b/client/src/__locales/no.json index f7c3b846..4bac8cee 100644 --- a/client/src/__locales/no.json +++ b/client/src/__locales/no.json @@ -1,11 +1,18 @@ { "client_settings": "Klientinnstillinger", + "example_upstream_reserved": "Du kan bestemme en oppstrøms-DNS <0>for et spesifikt domene(r)", + "example_upstream_comment": "Du kan spesifisere en kommentar", + "upstream_parallel": "Bruk parallele forespørsler for å få oppfarten på behandlinger, ved å forespørre til alle oppstrømstjenerne samtidig", "parallel_requests": "Parallelle forespørsler", "load_balancing": "Pågangstrykk-utjevning", + "load_balancing_desc": "Forespør én tjener om gangen. AdGuard Home vil bruke en 'vektlagt tilfeldig valg'-algoritme for å velge tjener, slik at den raskeste tjeneren blir brukt oftere.", "bootstrap_dns": "Bootstrap-DNS-tjenere", "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.", + "use_private_ptr_resolvers_title": "Bruk private omvendte DNS-løsere", "check_dhcp_servers": "Se etter DHCP-tjenere", + "save_config": "Lagre oppsettet", "enabled_dhcp": "DHCP-tjeneren ble skrudd på", "disabled_dhcp": "DHCP-tjeneren ble skrudd av", "unavailable_dhcp": "DHCP er utilgjengelig", @@ -102,6 +109,7 @@ "use_adguard_parental": "Benytt AdGuard sin foreldrekontroll-nettjeneste", "use_adguard_parental_hint": "AdGuard Home vil sjekke om domenet inneholder erotisk materiale. Den benytter den samme privatlivsvennlige API-en som nettlesersikkerhetstjenesten.", "enforce_safe_search": "Påtving barnevennlige søk", + "enforce_save_search_hint": "AdGuard Home kan fremtvinge \"Safe Search\" i de følgende søkemotorene: Google, YouTube, Bing, DuckDuckGo, Yandex, og Pixabay.", "no_servers_specified": "Ingen tjenere er spesifisert", "general_settings": "Generelle innstillinger", "dns_settings": "DNS-innstillinger", @@ -113,6 +121,7 @@ "encryption_settings": "Krypteringsinnstillinger", "dhcp_settings": "DHCP-innstillinger", "upstream_dns": "Oppstrøms-DNS-tjenere", + "upstream_dns_help": "Skriv inn én tjeneradresse per linje. Lær mer om å konfigurere oppstrøms-DNS-tjenere.", "upstream_dns_configured_in_file": "Satt opp i {{path}}", "test_upstream_btn": "Test oppstrømstilkoblinger", "upstreams": "Oppstrømstjenere", @@ -156,6 +165,7 @@ "form_error_url_or_path_format": "Listens URL eller fulle filbane er ugyldig", "custom_filter_rules": "Selvvalgte filtreringsregler", "custom_filter_rules_hint": "Skriv inn én oppføring per linje. Du kan bruke adblock-oppføringer, «hosts»-filsyntaks, eller rå domener.", + "system_host_files": "System-'hosts'-filer", "examples_title": "Eksempler", "example_meaning_filter_block": "blokker tilgang til 'example.org'-domenet og alle dens underdomener", "example_meaning_filter_whitelist": "opphev blokkeringen av 'example.org'-domenet og alle dens underdomener", @@ -308,6 +318,7 @@ "encryption_desc": "Krypteringsstøtte (HTTPS/TLS) for både DNS og admin-nettgrensesnittet", "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.", "encryption_redirect": "Automatisk omdiriger til HTTPS", "encryption_redirect_desc": "Dersom dette er valgt, vil AdGuard Home automatisk omdirigere deg fra HTTP til HTTPS-adresser.", "encryption_https": "HTTPS-port", @@ -339,6 +350,7 @@ "form_error_password": "Passordet samsvarer ikke", "reset_settings": "Tilbakestill innstillinger", "update_announcement": "AdGuard Home {{version}} er nå tilgjengelig! <0>Klikk her for mere informasjon.", + "setup_guide": "Oppsettsveiledning", "dns_addresses": "DNS-adresser", "dns_start": "DNS-tjeneren starter opp", "dns_status_error": "Feil ved sjekk av DNS-tjenerstatusen", @@ -360,6 +372,7 @@ "client_edit": "Rediger klienten", "client_identifier": "Identifikator", "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_mac": "Skriv inn MAC", "form_enter_id": "Skriv inn identifikator", @@ -382,6 +395,7 @@ "access_disallowed_title": "Klienter som skal avvises", "access_disallowed_desc": "En liste over CIDR- eller IP-adresser. Dersom dette er satt opp, vil AdGuard Home avslå forespørsler fra disse IP-adressene.", "access_blocked_title": "Blokkerte domener", + "access_blocked_desc": "Ikke forveksle dette med filtre. AdGuard Home vil nekte å behandle DNS-forespørsler som har disse domenene, og disse forespørslene dukker ikke engang opp i forespørselsloggen. Du kan spesifisere nøyaktige domene navn, jokertegn, eller URL-filterregler, f.eks. «example.org», «*.example.log» eller «||example.org^» derav.", "access_settings_saved": "Tilgangsinnstillingene ble vellykket lagret", "updates_checked": "Oppdateringene ble vellykket sett etter", "updates_version_equal": "AdGuard Home er fullt oppdatert", @@ -390,6 +404,7 @@ "setup_dns_privacy_1": "<0>DNS-over-TLS: Benytt <1>{{address}}-strengen.", "setup_dns_privacy_2": "<0>DNS-over-HTTPS: Benytt <1>{{address}}-strengen.", "setup_dns_privacy_3": "<0>Her er en liste over programvarer du kan bruke.", + "setup_dns_privacy_4": "På en iOS 14 eller macOS Big Sur-enhet kan du laste ned en spesiell '.mobileconfig'-fil som legger tilDNS-over-HTTPS- ellerDNS-over-TLS-tjenere til DNS-innstillingene.", "setup_dns_privacy_android_1": "Android 9 har innebygd støtte for DNS-over-TLS. For å sette det opp, gå til Innstillinger → Nettverk og internett → Avansert → Privat DNS, og skriv inn domenenavnet ditt der.", "setup_dns_privacy_android_2": "<0>AdGuard for Android støtter <1>DNS-over-HTTPS og <1>DNS-over-TLS.", "setup_dns_privacy_android_3": "<0>Intra legger til <1>DNS-over-HTTPS-støtte i Android.", @@ -449,6 +464,7 @@ "statistics_clear_confirm": "Er du sikker på at du vil slette statistikkene?", "statistics_retention_confirm": "Er du sikker på at du vil endre hvor lenge statistikkene skal beholdes? Hvis du reduserer den interne verdien, vil noe av dataene gå tapt", "statistics_cleared": "Statistikkene ble vellykket tømt", + "statistics_enable": "Skru på statistikker", "interval_hours": "{{count}} time", "interval_hours_plural": "{{count}} timer", "filters_configuration": "Oppsett av filtre", @@ -541,6 +557,8 @@ "cache_ttl_min_override_desc": "Overstyr korte levetidsverdier (i sekunder) som mottas fra oppstrømstjeneren under mellomlagring av DNS-responser", "cache_ttl_max_override_desc": "Velg en maks-levetidsverdi (i sekunder) for oppføringer i DNS-mellomlageret", "ttl_cache_validation": "Minimums-mellomlagringslevetidsverdien må være mindre enn eller det samme som maksverdien", + "cache_optimistic": "Optimistisk mellomlagring", + "cache_optimistic_desc": "Få AdGuard Home til å svare fra hurtigbufferen selv når oppføringene er utløpt, og prøv også å oppfriske dem.", "filter_category_general": "Generelt", "filter_category_security": "Sikkerhet", "filter_category_regional": "Regional", @@ -554,5 +572,7 @@ "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.", "experimental": "Eksperimentell", - "parental_control": "Foreldrekontroll" + "use_saved_key": "Bruk den tidligere lagrede nøkkelen", + "parental_control": "Foreldrekontroll", + "served_from_cache": "{{value}} (formidlet fra mellomlageret)" } diff --git a/client/src/__locales/pl.json b/client/src/__locales/pl.json index 76ce7da6..19cf6aba 100644 --- a/client/src/__locales/pl.json +++ b/client/src/__locales/pl.json @@ -403,6 +403,7 @@ "dns_providers": "Oto lista <0>znanych dostawców DNS do wyboru.", "update_now": "Aktualizuj teraz", "update_failed": "Automatyczna aktualizacja nie powiodła się. Proszę wykonaj kroki aby zaktualizować ręcznie.", + "manual_update": "Proszę wykonać te czynności, aby zaktualizować ręcznie.", "processing_update": "Poczekaj, trwa aktualizacja AdGuard Home", "clients_title": "Klienci", "clients_desc": "Skonfiguruj urządzenia podłączone do AdGuard Home", diff --git a/client/src/__locales/pt-br.json b/client/src/__locales/pt-br.json index f628edb9..c71e619a 100644 --- a/client/src/__locales/pt-br.json +++ b/client/src/__locales/pt-br.json @@ -403,6 +403,7 @@ "dns_providers": "Aqui está uma <0>lista de provedores de DNS conhecidos para escolher.", "update_now": "Atualizar agora", "update_failed": "A atualização automática falhou. Por favor, siga estes passos para atualizar manualmente.", + "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", "clients_desc": "Configure dispositivos conectados ao AdGuard", diff --git a/client/src/__locales/pt-pt.json b/client/src/__locales/pt-pt.json index c3f82f45..0405f5c1 100644 --- a/client/src/__locales/pt-pt.json +++ b/client/src/__locales/pt-pt.json @@ -403,6 +403,7 @@ "dns_providers": "Aqui está uma <0>lista de provedores de DNS conhecidos para escolher.", "update_now": "Atualizar agora", "update_failed": "A atualização automática falhou. Por favor, siga estes passos para atualizar manualmente.", + "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", "clients_desc": "Configure os dispositivos ligados ao AdGuard", diff --git a/client/src/__locales/ro.json b/client/src/__locales/ro.json index 5ada95cb..0e959ee7 100644 --- a/client/src/__locales/ro.json +++ b/client/src/__locales/ro.json @@ -403,6 +403,7 @@ "dns_providers": "Iată o <0>listă de furnizori DNS cunoscuți ce pot fi aleși.", "update_now": "Actualizați acum", "update_failed": "Auto-actualizarea a eșuat. Vă rugăm să urmați aceste etape pentru a actualiza manual.", + "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", "clients_desc": "Configură aparatele conectate la AdGuard Home", diff --git a/client/src/__locales/ru.json b/client/src/__locales/ru.json index 55321ebb..cd1e8091 100644 --- a/client/src/__locales/ru.json +++ b/client/src/__locales/ru.json @@ -403,6 +403,7 @@ "dns_providers": "<0>Список известных DNS-провайдеров на выбор.", "update_now": "Обновить сейчас", "update_failed": "Ошибка авто-обновления. Пожалуйста, следуйте инструкции для обновления вручную.", + "manual_update": "Пожалуйста, следуйте инструкции для обновления вручную.", "processing_update": "Пожалуйста, подождите, AdGuard Home обновляется", "clients_title": "Клиенты", "clients_desc": "Настройте устройства, использующие AdGuard Home", diff --git a/client/src/__locales/sk.json b/client/src/__locales/sk.json index 9b3886c2..7b4596f3 100644 --- a/client/src/__locales/sk.json +++ b/client/src/__locales/sk.json @@ -403,6 +403,7 @@ "dns_providers": "Tu je <0>zoznam známych poskytovateľov DNS, z ktorého si vyberiete.", "update_now": "Aktualizovať teraz", "update_failed": "Automatická aktualizácia zlyhala. Prosím sledujte postup pre manuálnu aktualizáciu.", + "manual_update": "Pre manuálnu aktualizáciu prosím sledujte tento postup.", "processing_update": "Čakajte prosím, AdGuard Home sa aktualizuje", "clients_title": "Klienti", "clients_desc": "Konfigurácia zariadení pripojených k AdGuard Home", diff --git a/client/src/__locales/sl.json b/client/src/__locales/sl.json index cb19b1c8..a9c5fed6 100644 --- a/client/src/__locales/sl.json +++ b/client/src/__locales/sl.json @@ -403,6 +403,7 @@ "dns_providers": "Tukaj je <0>seznam znanih ponudnikov DNS, med katerimi lahko izbirate.", "update_now": "Posodobi zdaj", "update_failed": "Samodejna posodobitev ni uspela. Prosimo sledite korakom, da ročno posodobite.", + "manual_update": "Za ročno posodobitev sledite tem korakom.", "processing_update": "Prosimo, počakajte. AdGuard Home se posodablja!", "clients_title": "Odjemalci", "clients_desc": "Konfigurirajte naprave, ki so povezane z AdGuard Home", diff --git a/client/src/__locales/sv.json b/client/src/__locales/sv.json index 72ae983b..195a651f 100644 --- a/client/src/__locales/sv.json +++ b/client/src/__locales/sv.json @@ -403,6 +403,7 @@ "dns_providers": "Här är en <0>lista över kända DNS-leverantörer att välja från.", "update_now": "Uppdatera nu", "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", diff --git a/client/src/__locales/tr.json b/client/src/__locales/tr.json index a761e233..bf0431f7 100644 --- a/client/src/__locales/tr.json +++ b/client/src/__locales/tr.json @@ -403,6 +403,7 @@ "dns_providers": "Aralarından seçim yapabileceğiniz, bilinen <0>DNS sağlayıcıların listesi.", "update_now": "Şimdi güncelle", "update_failed": "Otomatik güncelleme başarısız oldu. Elle güncellemek için lütfen bu adımları uygulayın.", + "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": "İstemciler", "clients_desc": "AdGuard Home'a bağlı cihazları yapılandırın", diff --git a/client/src/__locales/zh-cn.json b/client/src/__locales/zh-cn.json index 28fc7d63..b24dc0c4 100644 --- a/client/src/__locales/zh-cn.json +++ b/client/src/__locales/zh-cn.json @@ -403,6 +403,7 @@ "dns_providers": "此为可从中选择的<0>已知 DNS 提供商列表。", "update_now": "立即更新", "update_failed": "自动更新失败。请跟随这些步骤以手动更新。", + "manual_update": "请跟随此步骤以进行手动更新。", "processing_update": "正在更新 AdGuard Home,请稍侯", "clients_title": "客户端", "clients_desc": "配置已连接到 AdGuard Home 的设备", diff --git a/client/src/__locales/zh-tw.json b/client/src/__locales/zh-tw.json index da4ddca6..0757f08d 100644 --- a/client/src/__locales/zh-tw.json +++ b/client/src/__locales/zh-tw.json @@ -403,6 +403,7 @@ "dns_providers": "這裡是一個從中選擇之<0>已知的 DNS 供應商之清單。", "update_now": "立即更新", "update_failed": "自動更新已失敗。請遵循這些步驟以手動地更新。", + "manual_update": "請遵循這些步驟以手動地更新。", "processing_update": "請稍候,AdGuard Home 正被更新", "clients_title": "用戶端", "clients_desc": "配置被連線到 AdGuard Home 的裝置", From b290eddc70e426a3f28a711d517f943e28297aef Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Wed, 9 Feb 2022 19:51:26 +0300 Subject: [PATCH 118/135] Pull request: scripts: imp install, sup wget Closes #3637. Squashed commit of the following: commit 453094d9a016b0d5a7b7f584b2b492244703064d Author: Ainar Garipov Date: Wed Feb 9 19:44:51 2022 +0300 scripts: fix wget commit d16f8d9ad4ac62ce0bc88bab7ceb24a4089e93c3 Author: Ainar Garipov Date: Wed Feb 9 19:17:22 2022 +0300 scripts: imp install, sup wget --- scripts/install.sh | 71 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 15 deletions(-) diff --git a/scripts/install.sh b/scripts/install.sh index 3b1777ed..7cf35adc 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -46,33 +46,31 @@ is_little_endian() { # Function check_required checks if the required software is available on the # machine. The required software: # -# curl # unzip (macOS) / tar (other unixes) # +# curl/wget are checked in function configure. check_required() { required_darwin="unzip" required_unix="tar" readonly required_darwin required_unix - # Split with space. - required="curl" case "$os" in ('freebsd'|'linux'|'openbsd') - required="$required $required_unix" + required="$required_unix" ;; ('darwin') - required="$required $required_darwin" + required="$required_darwin" ;; (*) - # Generally shouldn't happen, since the OS has already been - # validated. + # Generally shouldn't happen, since the OS has already been validated. error_exit "unsupported operating system: '$os'" ;; esac + readonly required # Don't use quotes to get word splitting. - for cmd in ${required} + for cmd in $required do log "checking $cmd" if ! is_command "$cmd" @@ -189,6 +187,9 @@ set_os() { ('OpenBSD') os='openbsd' ;; + (*) + error_exit "unsupported operating system: '$os'" + ;; esac fi @@ -240,6 +241,9 @@ set_cpu() { fi cpu="${cpu}_softfloat" ;; + (*) + error_exit "unsupported cpu type: $cpu" + ;; esac fi @@ -297,6 +301,41 @@ fix_freebsd() { fi } +# download_curl uses curl(1) to download a file. The first argument is the URL. +# The second argument is optional and is the output file. +download_curl() { + curl_output="${2:-}" + if [ "$curl_output" = '' ] + then + curl -L -S -s "$1" + else + curl -L -S -o "$curl_output" -s "$1" + fi +} + +# download_wget uses wget(1) to download a file. The first argument is the URL. +# The second argument is optional and is the output file. +download_wget() { + wget_output="${2:--}" + + wget --no-verbose -O "$wget_output" "$1" +} + +# Function set_download_func sets the appropriate function for downloading +# files. +set_download_func() { + if is_command 'curl' + then + # Go on and use the default, download_curl. + return 0 + elif is_command 'wget' + then + download_func='download_wget' + else + error_exit "either curl or wget is required to install AdGuard Home via this script" + fi +} + # Function set_sudo_cmd sets the appropriate command to run a command under # superuser privileges. set_sudo_cmd() { @@ -320,6 +359,7 @@ configure() { set_os set_cpu fix_darwin + set_download_func set_sudo_cmd check_out_dir @@ -384,11 +424,11 @@ rerun_with_root() { log 'restarting with root privileges' - # Group curl together with an echo, so that if curl fails before producing - # any output, the echo prints an exit command for the following shell to - # execute to prevent it from getting an empty input and exiting with a zero - # code in that case. - { curl -L -S -s "$script_url" || echo 'exit 1'; }\ + # Group curl/wget together with an echo, so that if the former fails before + # producing any output, the latter prints an exit command for the following + # shell to execute to prevent it from getting an empty input and exiting + # with a zero code in that case. + { "$download_func" "$script_url" || echo 'exit 1'; }\ | $sudo_cmd sh -s -- -c "$channel" -C "$cpu" -O "$os" -o "$out_dir" "$r" "$u" "$v" # Exit the script. Since if the code of the previous pipeline is non-zero, @@ -401,7 +441,7 @@ rerun_with_root() { download() { log "downloading package from $url -> $pkg_name" - if ! curl -s "$url" --output "$pkg_name" + if ! "$download_func" "$url" "$pkg_name" then error_exit "cannot download the package from $url into $pkg_name" fi @@ -450,7 +490,7 @@ handle_existing() { return 0 fi - if [ "$( ls -1 -A $agh_dir )" != '' ] + if [ "$( ls -1 -A "$agh_dir" )" != '' ] then log 'the existing AdGuard Home installation is detected' @@ -522,6 +562,7 @@ cpu='' os='' out_dir='/opt' pkg_ext='tar.gz' +download_func='download_curl' sudo_cmd='sudo' parse_opts "$@" From 2a5b5f1927262a6e4b8fa8379dc95a933704f282 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Wed, 9 Feb 2022 21:21:34 +0300 Subject: [PATCH 119/135] Pull request: scripts: imp snap building Closes #4239. Squashed commit of the following: commit 942c03bd88b81d813a12136a135ca6dc003fedf3 Author: Ainar Garipov Date: Wed Feb 9 20:38:36 2022 +0300 scripts: imp snap building --- scripts/make/build-release.sh | 105 +++++++++++++--------------------- 1 file changed, 41 insertions(+), 64 deletions(-) diff --git a/scripts/make/build-release.sh b/scripts/make/build-release.sh index f9b8e8da..36fc98f7 100644 --- a/scripts/make/build-release.sh +++ b/scripts/make/build-release.sh @@ -130,37 +130,34 @@ done readonly sha256sum_cmd # Data section. Arrange data into space-separated tables for read -r to read. -# Use 0 for missing values. -# -# TODO(a.garipov): Remove armv6, because it was always overwritten by armv7. -# Rename armv7 to armhf. Rename the 386 snap to i386. +# Use a hyphen for missing values. # os arch arm mips snap platforms="\ -darwin amd64 0 0 0 -darwin arm64 0 0 0 -freebsd 386 0 0 0 -freebsd amd64 0 0 0 -freebsd arm 5 0 0 -freebsd arm 6 0 0 -freebsd arm 7 0 0 -freebsd arm64 0 0 0 -linux 386 0 0 386 -linux amd64 0 0 amd64 -linux arm 5 0 0 -linux arm 6 0 armv6 -linux arm 7 0 armv7 -linux arm64 0 0 arm64 -linux mips 0 softfloat 0 -linux mips64 0 softfloat 0 -linux mips64le 0 softfloat 0 -linux mipsle 0 softfloat 0 -linux ppc64le 0 0 0 -openbsd amd64 0 0 0 -openbsd arm64 0 0 0 -windows 386 0 0 0 -windows amd64 0 0 0 -windows arm64 0 0 0" +darwin amd64 - - - +darwin arm64 - - - +freebsd 386 - - - +freebsd amd64 - - - +freebsd arm 5 - - +freebsd arm 6 - - +freebsd arm 7 - - +freebsd arm64 - - - +linux 386 - - i386 +linux amd64 - - amd64 +linux arm 5 - - +linux arm 6 - - +linux arm 7 - armhf +linux arm64 - - arm64 +linux mips - softfloat - +linux mips64 - softfloat - +linux mips64le - softfloat - +linux mipsle - softfloat - +linux ppc64le - - - +openbsd amd64 - - - +openbsd arm64 - - - +windows 386 - - - +windows amd64 - - - +windows arm64 - - -" readonly platforms # Function build builds the release for one platform. It builds a binary, an @@ -189,15 +186,15 @@ build() { # Build the binary. # - # Set GOARM and GOMIPS to an empty string if $build_arm and $build_mips - # are zero by removing the zero as if it's a prefix. + # Set GOARM and GOMIPS to an empty string if $build_arm and $build_mips are + # the zero value by removing the hyphen as if it's a prefix. # # Don't use quotes with $build_par because we want an empty space if # parallelism wasn't set. env\ GOARCH="$build_arch"\ - GOARM="${build_arm#0}"\ - GOMIPS="${build_mips#0}"\ + GOARM="${build_arm#-}"\ + GOMIPS="${build_mips#-}"\ GOOS="$os"\ VERBOSE="$(( verbose - 1 ))"\ VERSION="$version"\ @@ -228,8 +225,8 @@ build() { in ('darwin'|'windows') build_archive="./${dist}/${build_ar}.zip" - # TODO(a.garipov): Find an option similar to the -C option of - # tar for zip. + # TODO(a.garipov): Find an option similar to the -C option of tar for + # zip. ( cd "${dist}/${1}" && zip -9 -q -r "../../${build_archive}" "./AdGuardHome" ) ;; (*) @@ -240,58 +237,38 @@ build() { log "$build_archive" - # build_snap is a string, so use string comparison for it. - # - # TODO(a.garipov): Consider using a different empty value in the - # platforms table. - if [ "$build_snap" = '0' ] || [ "$snap_enabled" -eq '0' ] + # Exit if we don't need to build the Snap package. + if [ "$build_snap" = '-' ] || [ "$snap_enabled" -eq '0' ] then return fi - # Prepare snap build. + # Prepare the Snap build. build_snap_output="./${dist}/AdGuardHome_${build_snap}.snap" build_snap_dir="${build_snap_output}.dir" # Create the meta subdirectory and copy files there. mkdir -p "${build_snap_dir}/meta" - cp "$build_output"\ - './scripts/snap/local/adguard-home-web.sh'\ - "$build_snap_dir" - cp -r './scripts/snap/gui'\ - "${build_snap_dir}/meta/" - - # TODO(a.garipov): Remove this crutch later. - case "$build_snap" - in - ('386') - build_snap_arch="i386" - ;; - ('armv6'|'armv7') - build_snap_arch="armhf" - ;; - (*) - build_snap_arch="$build_snap" - ;; - esac + cp "$build_output" './scripts/snap/local/adguard-home-web.sh' "$build_snap_dir" + cp -r './scripts/snap/gui' "${build_snap_dir}/meta/" # Create a snap.yaml file, setting the values. sed -e 's/%VERSION%/'"$version"'/'\ - -e 's/%ARCH%/'"$build_snap_arch"'/'\ + -e 's/%ARCH%/'"$build_snap"'/'\ ./scripts/snap/snap.tmpl.yaml\ >"${build_snap_dir}/meta/snap.yaml" # TODO(a.garipov): The snapcraft tool will *always* write everything, - # including errors, to stdout. And there doesn't seem to be a way to - # change that. So, save the combined output, but only show it when - # snapcraft actually fails. + # including errors, to stdout. And there doesn't seem to be a way to change + # that. So, save the combined output, but only show it when snapcraft + # actually fails. set +e build_snapcraft_output="$( snapcraft pack "$build_snap_dir" --output "$build_snap_output" 2>&1 )" build_snapcraft_exit_code="$?" set -e - if [ "$build_snapcraft_exit_code" != '0' ] + if [ "$build_snapcraft_exit_code" -ne '0' ] then log "$build_snapcraft_output" exit "$build_snapcraft_exit_code" From f53f48cc332574750232c428ee347ec7c2507fff Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Thu, 10 Feb 2022 15:42:59 +0300 Subject: [PATCH 120/135] Pull request: all: use "ClientID" consistently Closes #4242. Updates #4244. Squashed commit of the following: commit 3a2296a7a70006cf6777e54ce1e2fc3559aec5be Author: Ainar Garipov Date: Wed Feb 9 21:23:43 2022 +0300 client: imp more commit 3aacc8696ac694ff459fd33ba7beeeabd2569a55 Merge: b28a120f 2a5b5f19 Author: Ainar Garipov Date: Wed Feb 9 21:21:59 2022 +0300 Merge branch 'master' into 4244-imp-i18n commit b28a120fe9aa68507b173717059b7b259097d6a4 Author: Ainar Garipov Date: Wed Feb 9 14:49:49 2022 +0300 client: imp texts more commit c1fa6ca336f2d5bdcc67836f348be4843a0a8f79 Author: Ainar Garipov Date: Tue Feb 8 21:12:15 2022 +0300 all: use "ClientID" consistently --- CHANGELOG.md | 8 +- client/src/__locales/en.json | 97 +++++++++---------- client/src/components/Filters/Examples.js | 12 +-- .../src/components/Settings/Clients/Form.js | 10 +- .../components/Settings/Dns/Access/Form.js | 4 +- .../Settings/Dns/Upstream/Examples.js | 18 ++-- .../components/Settings/Encryption/Form.js | 2 - .../components/ui/Guide/MobileConfigForm.js | 9 +- client/src/helpers/constants.js | 7 +- internal/dnsforward/access.go | 4 +- internal/dnsforward/clientid.go | 20 ++-- internal/dnsforward/clientid_test.go | 41 ++++---- internal/dnsforward/config.go | 4 +- internal/dnsforward/dns.go | 4 +- internal/dnsforward/dnsforward.go | 6 +- internal/dnsforward/stats_test.go | 2 +- internal/home/clients.go | 2 +- internal/home/dns.go | 2 +- internal/querylog/search.go | 11 +-- openapi/CHANGELOG.md | 4 +- openapi/openapi.yaml | 18 ++-- 21 files changed, 142 insertions(+), 143 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1464d3ff..8b14fa13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -186,7 +186,7 @@ See also the [v0.107.0 GitHub milestone][ms-v0.107.0]. - Static IP address detection on FreeBSD ([#3289]). - Optimistic cache ([#2145]). - New possible value of `6h` for `querylog_interval` setting ([#2504]). -- Blocking access using client IDs ([#2624], [#3162]). +- Blocking access using ClientIDs ([#2624], [#3162]). - `source` directives support in `/etc/network/interfaces` on Linux ([#3257]). - RFC 9000 support in DNS-over-QUIC. - Completely disabling statistics by setting the statistics interval to zero @@ -317,7 +317,7 @@ In this release, the schema version has changed from 10 to 12. - Occasional panics when reading old statistics databases ([#3506]). - `reload` service action on macOS and FreeBSD ([#3457]). - Inaccurate using of service actions in the installation script ([#3450]). -- Client ID checking ([#3437]). +- ClientID checking ([#3437]). - Discovering other DHCP servers on `darwin` and `freebsd` ([#3417]). - Switching listening address to unspecified one when bound to a single specified IPv4 address on Darwin (macOS) ([#2807]). @@ -334,7 +334,7 @@ In this release, the schema version has changed from 10 to 12. - Redundant hostname generating while loading static leases with empty hostname ([#3166]). - Domain name case in responses ([#3194]). -- Custom upstreams selection for clients with client IDs in DNS-over-TLS and +- Custom upstreams selection for clients with ClientIDs in DNS-over-TLS and DNS-over-HTTP ([#3186]). - Incorrect client-based filtering applying logic ([#2875]). @@ -668,7 +668,7 @@ See also the [v0.105.0 GitHub milestone][ms-v0.105.0]. - Added more services to the "Blocked services" list ([#2224], [#2401]). - `ipset` subdomain matching, just like `dnsmasq` does ([#2179]). -- Client ID support for DNS-over-HTTPS, DNS-over-QUIC, and DNS-over-TLS +- ClientID support for DNS-over-HTTPS, DNS-over-QUIC, and DNS-over-TLS ([#1383]). - `$dnsrewrite` modifier for filters ([#2102]). - The host checking API and the query logs API can now return multiple matched diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index 4b19ea7a..07021b59 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -1,7 +1,7 @@ { "client_settings": "Client settings", - "example_upstream_reserved": "You can specify a DNS upstream <0>for the specific domain(s)", - "example_upstream_comment": "You can specify a comment", + "example_upstream_reserved": "an upstream <0>for specific domains;", + "example_upstream_comment": "a comment.", "upstream_parallel": "Use parallel queries to speed up resolving by querying all upstream servers simultaneously.", "parallel_requests": "Parallel requests", "load_balancing": "Load-balancing", @@ -43,7 +43,7 @@ "form_error_ip6_format": "Invalid IPv6 address", "form_error_ip_format": "Invalid IP address", "form_error_mac_format": "Invalid MAC address", - "form_error_client_id_format": "Client ID must contain only numbers, lowercase letters, and hyphens", + "form_error_client_id_format": "ClientID must contain only numbers, lowercase letters, and hyphens", "form_error_server_name": "Invalid server name", "form_error_subnet": "Subnet \"{{cidr}}\" does not contain the IP address \"{{ip}}\"", "form_error_positive": "Must be greater than 0", @@ -143,7 +143,7 @@ "use_adguard_browsing_sec_hint": "AdGuard Home will check if the domain is blocked by the browsing security web service. It will use privacy-friendly lookup API to perform the check: only a short prefix of the domain name SHA256 hash is sent to the server.", "use_adguard_parental": "Use AdGuard parental control web service", "use_adguard_parental_hint": "AdGuard Home will check if domain contains adult materials. It uses the same privacy-friendly API as the browsing security web service.", - "enforce_safe_search": "Use safe search", + "enforce_safe_search": "Use Safe Search", "enforce_save_search_hint": "AdGuard Home will enforce safe search in the following search engines: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.", "no_servers_specified": "No servers specified", "general_settings": "General settings", @@ -165,10 +165,10 @@ "enabled_filtering_toast": "Enabled filtering", "disabled_safe_browsing_toast": "Disabled Safe Browsing", "enabled_safe_browsing_toast": "Enabled Safe Browsing", - "disabled_parental_toast": "Disabled parental control", - "enabled_parental_toast": "Enabled parental control", - "disabled_safe_search_toast": "Disabled safe search", - "enabled_save_search_toast": "Enabled safe search", + "disabled_parental_toast": "Disabled Parental Control", + "enabled_parental_toast": "Enabled Parental Control", + "disabled_safe_search_toast": "Disabled Safe Search", + "enabled_save_search_toast": "Enabled Safe Search", "enabled_table_header": "Enabled", "name_table_header": "Name", "list_url_table_header": "List URL", @@ -202,19 +202,19 @@ "custom_filter_rules_hint": "Enter one rule on a line. You can use either adblock rules or hosts files syntax.", "system_host_files": "System hosts files", "examples_title": "Examples", - "example_meaning_filter_block": "block access to the example.org domain and all its subdomains", - "example_meaning_filter_whitelist": "unblock access to the example.org domain and all its subdomains", - "example_meaning_host_block": "AdGuard Home will now return 127.0.0.1 address for the example.org domain (but not its subdomains).", - "example_comment": "! Here goes a comment", - "example_comment_meaning": "just a comment", - "example_comment_hash": "# Also a comment", - "example_regex_meaning": "block access to the domains matching the specified regular expression", - "example_upstream_regular": "regular DNS (over UDP)", - "example_upstream_dot": "encrypted <0>DNS-over-TLS", - "example_upstream_doh": "encrypted <0>DNS-over-HTTPS", - "example_upstream_doq": "encrypted <0>DNS-over-QUIC", - "example_upstream_sdns": "you can use <0>DNS Stamps for <1>DNSCrypt or <2>DNS-over-HTTPS resolvers", - "example_upstream_tcp": "regular DNS (over TCP)", + "example_meaning_filter_block": "block access to example.org and all its subdomains;", + "example_meaning_filter_whitelist": "unblock access to example.org and all its subdomains;", + "example_meaning_host_block": "respond with 127.0.0.1 for example.org (but not for its subdomains);", + "example_comment": "! Here goes a comment.", + "example_comment_meaning": "just a comment;", + "example_comment_hash": "# Also a comment.", + "example_regex_meaning": "block access to domains matching the specified regular expression.", + "example_upstream_regular": "regular DNS (over UDP);", + "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_sdns": "<0>DNS Stamps for <1>DNSCrypt or <2>DNS-over-HTTPS resolvers;", + "example_upstream_tcp": "regular DNS (over TCP);", "all_lists_up_to_date_toast": "All lists are already up-to-date", "updated_upstream_dns_toast": "Upstream servers successfully saved", "dns_test_ok_toast": "Specified DNS servers are working correctly", @@ -259,10 +259,10 @@ "query_log_strict_search": "Use double quotes for strict search", "query_log_retention_confirm": "Are you sure you want to change query log retention? If you decrease the interval value, some data will be lost", "anonymize_client_ip": "Anonymize client IP", - "anonymize_client_ip_desc": "Don't save the full IP address of the client in logs and statistics", + "anonymize_client_ip_desc": "Don't save the client's full IP address to logs or statistics.", "dns_config": "DNS server configuration", "dns_cache_config": "DNS cache configuration", - "dns_cache_config_desc": "Here you can configure DNS cache", + "dns_cache_config_desc": "Here you can configure DNS cache.", "blocking_mode": "Blocking mode", "default": "Default", "nxdomain": "NXDOMAIN", @@ -275,9 +275,9 @@ "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": "Enter client ID", - "client_id_desc": "Different clients can be identified by a special client ID. Here you can learn more about how to identify clients.", + "client_id": "ClientID", + "client_id_placeholder": "Enter a ClientID", + "client_id_desc": "Clients can be identified by ClientID. Learn more about how to identify clients here.", "download_mobileconfig_doh": "Download .mobileconfig for DNS-over-HTTPS", "download_mobileconfig_dot": "Download .mobileconfig for DNS-over-TLS", "download_mobileconfig": "Download configuration file", @@ -334,12 +334,12 @@ "install_devices_router_list_4": "On some router types, a custom DNS server cannot be set up. In that case, setting up AdGuard Home as a <0>DHCP server may help. Otherwise, you should check the router manual on how to customize DNS servers on your specific router model.", "install_devices_windows_list_1": "Open Control Panel through Start menu or Windows search.", "install_devices_windows_list_2": "Go to Network and Internet category and then to Network and Sharing Center.", - "install_devices_windows_list_3": "On the left side of the screen find \"Change adapter settings\" and click on it.", - "install_devices_windows_list_4": "Select your active connection, right-click on it and choose Properties.", + "install_devices_windows_list_3": "In the left panel, click \"Change adapter settings\".", + "install_devices_windows_list_4": "Right-click your active connection and select Properties.", "install_devices_windows_list_5": "Find \"Internet Protocol Version 4 (TCP/IPv4)\" (or, for IPv6, \"Internet Protocol Version 6 (TCP/IPv6)\") in the list, select it and then click on Properties again.", "install_devices_windows_list_6": "Choose \"Use the following DNS server addresses\" and enter your AdGuard Home server addresses.", - "install_devices_macos_list_1": "Click on Apple icon and go to System Preferences.", - "install_devices_macos_list_2": "Click on Network.", + "install_devices_macos_list_1": "Click the Apple icon and go to System Preferences.", + "install_devices_macos_list_2": "Click Network.", "install_devices_macos_list_3": "Select the first connection in your list and click Advanced.", "install_devices_macos_list_4": "Select the DNS tab and enter your AdGuard Home server addresses.", "install_devices_android_list_1": "From the Android Menu home screen, tap Settings.", @@ -356,7 +356,7 @@ "open_dashboard": "Open Dashboard", "install_saved": "Saved successfully", "encryption_title": "Encryption", - "encryption_desc": "Encryption (HTTPS/TLS) support for both DNS and admin web interface", + "encryption_desc": "Encryption (HTTPS/TLS) support for both DNS and admin web interface.", "encryption_config_saved": "Encryption configuration saved", "encryption_server": "Server name", "encryption_server_enter": "Enter your domain name", @@ -367,7 +367,7 @@ "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", + "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_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.", @@ -405,8 +405,8 @@ "update_failed": "Auto-update failed. Please follow these steps to update manually.", "manual_update": "Please follow these steps to update manually.", "processing_update": "Please wait, AdGuard Home is being updated", - "clients_title": "Clients", - "clients_desc": "Configure devices connected to AdGuard Home", + "clients_title": "Persistent clients", + "clients_desc": "Configure persistent client records for devices connected to AdGuard Home.", "settings_global": "Global", "settings_custom": "Custom", "table_client": "Client", @@ -417,7 +417,7 @@ "client_edit": "Edit Client", "client_identifier": "Identifier", "ip_address": "IP address", - "client_identifier_desc": "Clients can be identified by the IP address, CIDR, MAC address, or a special client ID (can be used for DoT/DoH/DoQ). <0>Here you can learn more about how to identify clients.", + "client_identifier_desc": "Clients can be identified by their IP address, CIDR, MAC address, or ClientID (can be used for DoT/DoH/DoQ). Learn more about how to identify clients <0>here.", "form_enter_ip": "Enter IP", "form_enter_subnet_ip": "Enter an IP address in the subnet \"{{cidr}}\"", "form_enter_mac": "Enter MAC", @@ -432,14 +432,14 @@ "clients_not_found": "No clients found", "client_confirm_delete": "Are you sure you want to delete client \"{{key}}\"?", "list_confirm_delete": "Are you sure you want to delete this list?", - "auto_clients_title": "Clients (runtime)", - "auto_clients_desc": "Data on the clients that use AdGuard Home, but not stored in the configuration", + "auto_clients_title": "Runtime clients", + "auto_clients_desc": "Devices not on the list of Persistent clients that may still use AdGuard Home.", "access_title": "Access settings", "access_desc": "Here you can configure access rules for the AdGuard Home DNS server.", "access_allowed_title": "Allowed clients", - "access_allowed_desc": "A list of CIDRs, IP addresses, or client IDs. If configured, AdGuard Home will accept requests only from these clients.", + "access_allowed_desc": "A list of CIDRs, IP addresses, or ClientIDs. If this list has entries, AdGuard Home will accept requests only from these clients.", "access_disallowed_title": "Disallowed clients", - "access_disallowed_desc": "A list of CIDRs, IP addresses, or client IDs. If configured, AdGuard Home will drop requests from these clients. If allowed clients are configured, this field is ignored.", + "access_disallowed_desc": "A list of CIDRs, IP addresses, or ClientIDs. If this list has entries, AdGuard Home will drop requests from these clients. This field is ignored if there are entries in Allowed clients.", "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", @@ -507,7 +507,7 @@ "filter_updated": "The list has been successfully updated", "statistics_configuration": "Statistics configuration", "statistics_retention": "Statistics retention", - "statistics_retention_desc": "If you decrease the interval value, some data will be lost", + "statistics_retention_desc": "If you decrease the interval value, some data will be lost.", "statistics_clear": "Clear statistics", "statistics_clear_confirm": "Are you sure you want to clear statistics?", "statistics_retention_confirm": "Are you sure you want to change statistics retention? If you decrease the interval value, some data will be lost", @@ -532,7 +532,7 @@ "netname": "Network name", "network": "Network", "descr": "Description", - "whois": "Whois", + "whois": "WHOIS", "filtering_rules_learn_more": "<0>Learn more about creating your own hosts lists.", "blocked_by_response": "Blocked by CNAME or IP in response", "blocked_by_cname_or_ip": "Blocked by CNAME or IP", @@ -552,10 +552,10 @@ "autofix_warning_list": "It will perform these tasks: <0>Deactivate system DNSStubListener <0>Set DNS server address to 127.0.0.1 <0>Replace symbolic link target of /etc/resolv.conf with /run/systemd/resolve/resolv.conf <0>Stop DNSStubListener (reload systemd-resolved service)", "autofix_warning_result": "As a result all DNS requests from your system will be processed by AdGuard Home by default.", "tags_title": "Tags", - "tags_desc": "You can select the tags that correspond to the client. Tags can be included in the filtering rules and allow you to apply them more accurately. <0>Learn more", + "tags_desc": "You can select tags that correspond to the client. Include tags in filtering rules to apply them more precisely. <0>Learn more.", "form_select_tags": "Select client tags", "check_title": "Check the filtering", - "check_desc": "Check if the host name is filtered", + "check_desc": "Check if a host name is filtered.", "check": "Check", "form_enter_host": "Enter a host name", "filtered_custom_rules": "Filtered by Custom filtering rules", @@ -594,19 +594,19 @@ "allowed": "Allowed", "filtered": "Filtered", "rewritten": "Rewritten", - "safe_search": "Safe search", + "safe_search": "Safe Search", "blocklist": "Blocklist", "milliseconds_abbreviation": "ms", "cache_size": "Cache size", - "cache_size_desc": "DNS cache size (in bytes)", + "cache_size_desc": "DNS cache size (in bytes).", "cache_ttl_min_override": "Override minimum TTL", "cache_ttl_max_override": "Override maximum TTL", "enter_cache_size": "Enter cache size (bytes)", "enter_cache_ttl_min_override": "Enter minimum TTL (seconds)", "enter_cache_ttl_max_override": "Enter maximum TTL (seconds)", - "cache_ttl_min_override_desc": "Extend short time-to-live values (seconds) received from the upstream server when caching DNS responses", - "cache_ttl_max_override_desc": "Set a maximum time-to-live value (seconds) for entries in the DNS cache", - "ttl_cache_validation": "Minimum cache TTL value must be less than or equal to the maximum value", + "cache_ttl_min_override_desc": "Extend short time-to-live values (seconds) received from the upstream server when caching DNS responses.", + "cache_ttl_max_override_desc": "Set a maximum time-to-live value (seconds) for entries in the DNS cache.", + "ttl_cache_validation": "Minimum cache TTL override must be less than or equal to the maximum.", "cache_optimistic": "Optimistic caching", "cache_optimistic_desc": "Make AdGuard Home respond from the cache even when the entries are expired and also try to refresh them.", "filter_category_general": "General", @@ -624,7 +624,6 @@ "adg_will_drop_dns_queries": "AdGuard Home will be dropping all DNS queries from this client.", "filter_allowlist": "WARNING: This action also will exclude the rule \"{{disallowed_rule}}\" from the list of allowed clients.", "last_rule_in_allowlist": "Cannot disallow this client because excluding the rule \"{{disallowed_rule}}\" will DISABLE \"Allowed clients\" list.", - "experimental": "Experimental", "use_saved_key": "Use the previously saved key", "parental_control": "Parental Control", "safe_browsing": "Safe Browsing", diff --git a/client/src/components/Filters/Examples.js b/client/src/components/Filters/Examples.js index 9164b646..6dcc01c7 100644 --- a/client/src/components/Filters/Examples.js +++ b/client/src/components/Filters/Examples.js @@ -7,27 +7,27 @@ const Examples = () => ( examples_title:
  1. - ||example.org^ –  + ||example.org^: example_meaning_filter_block
  2. - @@||example.org^ –  + @@||example.org^: example_meaning_filter_whitelist
  3. - 127.0.0.1 example.org –  + 127.0.0.1 example.org: example_meaning_host_block
  4. - example_comment –  + example_comment: example_comment_meaning
  5. - example_comment_hash –  + example_comment_hash: example_comment_meaning
  6. - /REGEX/ –  + /REGEX/: example_regex_meaning
diff --git a/client/src/components/Settings/Clients/Form.js b/client/src/components/Settings/Clients/Form.js index 631272d8..d5f80c62 100644 --- a/client/src/components/Settings/Clients/Form.js +++ b/client/src/components/Settings/Clients/Form.js @@ -19,7 +19,7 @@ import { renderServiceField, } from '../../../helpers/form'; import { validateClientId, validateRequiredValue } from '../../../helpers/validators'; -import { FORM_NAME, SERVICES } from '../../../helpers/constants'; +import { CLIENT_ID_LINK, FORM_NAME, SERVICES } from '../../../helpers/constants'; import './Service.css'; const settingsCheckboxes = [ @@ -281,11 +281,11 @@ let Form = (props) => {
- link + components={{ + a: + text , - ]} + }} > client_identifier_desc diff --git a/client/src/components/Settings/Dns/Access/Form.js b/client/src/components/Settings/Dns/Access/Form.js index aaf60412..868e3fde 100644 --- a/client/src/components/Settings/Dns/Access/Form.js +++ b/client/src/components/Settings/Dns/Access/Form.js @@ -9,7 +9,7 @@ import { trimMultilineString, removeEmptyLines, } from '../../../../helpers/helpers'; -import { FORM_NAME } from '../../../../helpers/constants'; +import { CLIENT_ID_LINK, FORM_NAME } from '../../../../helpers/constants'; const fields = [ { @@ -48,7 +48,7 @@ let Form = (props) => { }
- {subtitle} + text }}>{subtitle}
( examples_title:
  1. - 94.140.14.140 - {props.t('example_upstream_regular')} + 94.140.14.140: {props.t('example_upstream_regular')}
  2. - tls://dns-unfiltered.adguard.com –  + tls://dns-unfiltered.adguard.com: (
  3. - https://dns-unfiltered.adguard.com/dns-query –  + https://dns-unfiltered.adguard.com/dns-query: (
  4. - quic://dns-unfiltered.adguard.com:784 –  + quic://dns-unfiltered.adguard.com:784: ( > example_upstream_doq -   - (experimental)
  5. - tcp://94.140.14.140example_upstream_tcp + tcp://94.140.14.140: example_upstream_tcp
  6. - sdns://... –  + sdns://...: (
  7. - [/example.local/]94.140.14.140 –  + [/example.local/]94.140.14.140: (
  8. - {COMMENT_LINE_DEFAULT_TOKEN} comment –  + {COMMENT_LINE_DEFAULT_TOKEN} comment: example_upstream_comment diff --git a/client/src/components/Settings/Encryption/Form.js b/client/src/components/Settings/Encryption/Form.js index 82b3acdd..b94dd94b 100644 --- a/client/src/components/Settings/Encryption/Form.js +++ b/client/src/components/Settings/Encryption/Form.js @@ -201,8 +201,6 @@ let Form = (props) => {
    { const githubLink = ( diff --git a/client/src/helpers/constants.js b/client/src/helpers/constants.js index de65ad5e..d4477b72 100644 --- a/client/src/helpers/constants.js +++ b/client/src/helpers/constants.js @@ -55,10 +55,11 @@ export const REPOSITORY = { ISSUES: 'https://github.com/AdguardTeam/AdGuardHome/issues/new/choose', }; -export const PRIVACY_POLICY_LINK = 'https://adguard.com/privacy/home.html'; -export const PORT_53_FAQ_LINK = 'https://github.com/AdguardTeam/AdGuardHome/wiki/FAQ#bindinuse'; -export const UPSTREAM_CONFIGURATION_WIKI_LINK = 'https://github.com/AdguardTeam/AdGuardHome/wiki/Configuration#upstreams'; +export const CLIENT_ID_LINK = 'https://github.com/AdguardTeam/AdGuardHome/wiki/Clients#clientid'; export const MANUAL_UPDATE_LINK = 'https://github.com/AdguardTeam/AdGuardHome/wiki/FAQ#manual-update'; +export const PORT_53_FAQ_LINK = 'https://github.com/AdguardTeam/AdGuardHome/wiki/FAQ#bindinuse'; +export const PRIVACY_POLICY_LINK = 'https://adguard.com/privacy/home.html'; +export const UPSTREAM_CONFIGURATION_WIKI_LINK = 'https://github.com/AdguardTeam/AdGuardHome/wiki/Configuration#upstreams'; export const FILTERS_RELATIVE_LINK = '#filters'; diff --git a/internal/dnsforward/access.go b/internal/dnsforward/access.go index 76145fdf..7a771946 100644 --- a/internal/dnsforward/access.go +++ b/internal/dnsforward/access.go @@ -119,8 +119,8 @@ func (a *accessCtx) allowlistMode() (ok bool) { func (a *accessCtx) isBlockedClientID(id string) (ok bool) { allowlistMode := a.allowlistMode() if id == "" { - // In allowlist mode, consider requests without client IDs - // blocked by default. + // In allowlist mode, consider requests without ClientIDs blocked by + // default. return allowlistMode } diff --git a/internal/dnsforward/clientid.go b/internal/dnsforward/clientid.go index 1580e416..481fb84d 100644 --- a/internal/dnsforward/clientid.go +++ b/internal/dnsforward/clientid.go @@ -12,12 +12,12 @@ import ( "github.com/lucas-clemente/quic-go" ) -// ValidateClientID returns an error if clientID is not a valid client ID. -func ValidateClientID(clientID string) (err error) { - err = netutil.ValidateDomainNameLabel(clientID) +// ValidateClientID returns an error if id is not a valid ClientID. +func ValidateClientID(id string) (err error) { + err = netutil.ValidateDomainNameLabel(id) if err != nil { // Replace the domain name label wrapper with our own. - return fmt.Errorf("invalid client id %q: %w", clientID, errors.Unwrap(err)) + return fmt.Errorf("invalid clientid %q: %w", id, errors.Unwrap(err)) } return nil @@ -33,7 +33,7 @@ func hasLabelSuffix(s, suffix string) (ok bool) { return strings.HasSuffix(s, suffix) && s[len(s)-len(suffix)-1] == '.' } -// clientIDFromClientServerName extracts and validates a client ID. hostSrvName +// clientIDFromClientServerName extracts and validates a ClientID. hostSrvName // is the server name of the host. cliSrvName is the server name as sent by the // client. When strict is true, and client and host server name don't match, // clientIDFromClientServerName will return an error. @@ -86,22 +86,22 @@ func clientIDFromDNSContextHTTPS(pctx *proxy.DNSContext) (clientID string, err e } if len(parts) == 0 || parts[0] != "dns-query" { - return "", fmt.Errorf("client id check: invalid path %q", origPath) + return "", fmt.Errorf("clientid check: invalid path %q", origPath) } switch len(parts) { case 1: - // Just /dns-query, no client ID. + // Just /dns-query, no ClientID. return "", nil case 2: clientID = parts[1] default: - return "", fmt.Errorf("client id check: invalid path %q: extra parts", origPath) + return "", fmt.Errorf("clientid check: invalid path %q: extra parts", origPath) } err = ValidateClientID(clientID) if err != nil { - return "", fmt.Errorf("client id check: %w", err) + return "", fmt.Errorf("clientid check: %w", err) } return clientID, nil @@ -166,7 +166,7 @@ func (s *Server) clientIDFromDNSContext(pctx *proxy.DNSContext) (clientID string s.conf.StrictSNICheck, ) if err != nil { - return "", fmt.Errorf("client id check: %w", err) + return "", fmt.Errorf("clientid check: %w", err) } return clientID, nil diff --git a/internal/dnsforward/clientid_test.go b/internal/dnsforward/clientid_test.go index d43de02f..e62dbe58 100644 --- a/internal/dnsforward/clientid_test.go +++ b/internal/dnsforward/clientid_test.go @@ -65,7 +65,7 @@ func TestServer_clientIDFromDNSContext(t *testing.T) { wantErrMsg: "", strictSNI: false, }, { - name: "tls_no_client_id", + name: "tls_no_clientid", proto: proxy.ProtoTLS, hostSrvName: "example.com", cliSrvName: "example.com", @@ -78,7 +78,7 @@ func TestServer_clientIDFromDNSContext(t *testing.T) { hostSrvName: "example.com", cliSrvName: "", wantClientID: "", - wantErrMsg: `client id check: client server name "" ` + + wantErrMsg: `clientid check: client server name "" ` + `doesn't match host server name "example.com"`, strictSNI: true, }, { @@ -90,7 +90,7 @@ func TestServer_clientIDFromDNSContext(t *testing.T) { wantErrMsg: "", strictSNI: false, }, { - name: "tls_client_id", + name: "tls_clientid", proto: proxy.ProtoTLS, hostSrvName: "example.com", cliSrvName: "cli.example.com", @@ -98,36 +98,36 @@ func TestServer_clientIDFromDNSContext(t *testing.T) { wantErrMsg: "", strictSNI: true, }, { - name: "tls_client_id_hostname_error", + name: "tls_clientid_hostname_error", proto: proxy.ProtoTLS, hostSrvName: "example.com", cliSrvName: "cli.example.net", wantClientID: "", - wantErrMsg: `client id check: client server name "cli.example.net" ` + + wantErrMsg: `clientid check: client server name "cli.example.net" ` + `doesn't match host server name "example.com"`, strictSNI: true, }, { - name: "tls_invalid_client_id", + name: "tls_invalid_clientid", proto: proxy.ProtoTLS, hostSrvName: "example.com", cliSrvName: "!!!.example.com", wantClientID: "", - wantErrMsg: `client id check: invalid client id "!!!": ` + + wantErrMsg: `clientid check: invalid clientid "!!!": ` + `bad domain name label rune '!'`, strictSNI: true, }, { - name: "tls_client_id_too_long", + name: "tls_clientid_too_long", proto: proxy.ProtoTLS, hostSrvName: "example.com", cliSrvName: `abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmno` + `pqrstuvwxyz0123456789.example.com`, wantClientID: "", - wantErrMsg: `client id check: invalid client id "abcdefghijklmno` + + wantErrMsg: `clientid check: invalid clientid "abcdefghijklmno` + `pqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789": ` + `domain name label is too long: got 72, max 63`, strictSNI: true, }, { - name: "quic_client_id", + name: "quic_clientid", proto: proxy.ProtoQUIC, hostSrvName: "example.com", cliSrvName: "cli.example.com", @@ -135,12 +135,12 @@ func TestServer_clientIDFromDNSContext(t *testing.T) { wantErrMsg: "", strictSNI: true, }, { - name: "tls_client_id_issue3437", + name: "tls_clientid_issue3437", proto: proxy.ProtoTLS, hostSrvName: "example.com", cliSrvName: "cli.myexample.com", wantClientID: "", - wantErrMsg: `client id check: client server name "cli.myexample.com" ` + + wantErrMsg: `clientid check: client server name "cli.myexample.com" ` + `doesn't match host server name "example.com"`, strictSNI: true, }} @@ -191,22 +191,22 @@ func TestClientIDFromDNSContextHTTPS(t *testing.T) { wantClientID string wantErrMsg string }{{ - name: "no_client_id", + name: "no_clientid", path: "/dns-query", wantClientID: "", wantErrMsg: "", }, { - name: "no_client_id_slash", + name: "no_clientid_slash", path: "/dns-query/", wantClientID: "", wantErrMsg: "", }, { - name: "client_id", + name: "clientid", path: "/dns-query/cli", wantClientID: "cli", wantErrMsg: "", }, { - name: "client_id_slash", + name: "clientid_slash", path: "/dns-query/cli/", wantClientID: "cli", wantErrMsg: "", @@ -214,18 +214,17 @@ func TestClientIDFromDNSContextHTTPS(t *testing.T) { name: "bad_url", path: "/foo", wantClientID: "", - wantErrMsg: `client id check: invalid path "/foo"`, + wantErrMsg: `clientid check: invalid path "/foo"`, }, { name: "extra", path: "/dns-query/cli/foo", wantClientID: "", - wantErrMsg: `client id check: invalid path "/dns-query/cli/foo": extra parts`, + wantErrMsg: `clientid check: invalid path "/dns-query/cli/foo": extra parts`, }, { - name: "invalid_client_id", + name: "invalid_clientid", path: "/dns-query/!!!", wantClientID: "", - wantErrMsg: `client id check: invalid client id "!!!": ` + - `bad domain name label rune '!'`, + wantErrMsg: `clientid check: invalid clientid "!!!": bad domain name label rune '!'`, }} for _, tc := range testCases { diff --git a/internal/dnsforward/config.go b/internal/dnsforward/config.go index cb93e278..9a050f52 100644 --- a/internal/dnsforward/config.go +++ b/internal/dnsforward/config.go @@ -150,8 +150,8 @@ type TLSConfig struct { CertificateChainData []byte `yaml:"-" json:"-"` PrivateKeyData []byte `yaml:"-" json:"-"` - // ServerName is the hostname of the server. Currently, it is only - // being used for client ID checking. + // ServerName is the hostname of the server. Currently, it is only being + // used for ClientID checking. ServerName string `yaml:"-" json:"-"` cert tls.Certificate diff --git a/internal/dnsforward/dns.go b/internal/dnsforward/dns.go index 87cb5194..dd5a4dd5 100644 --- a/internal/dnsforward/dns.go +++ b/internal/dnsforward/dns.go @@ -35,7 +35,7 @@ type dnsContext struct { // err is the error returned from a processing function. err error - // clientID is the clientID from DoH, DoQ, or DoT, if provided. + // clientID is the ClientID from DoH, DoQ, or DoT, if provided. clientID string // origQuestion is the question received from the client. It is set @@ -546,7 +546,7 @@ func (s *Server) processUpstream(dctx *dnsContext) (rc resultCode) { } if pctx.Addr != nil && s.conf.GetCustomUpstreamByClient != nil { - // Use the clientID first, since it has a higher priority. + // Use the ClientID first, since it has a higher priority. id := stringutil.Coalesce(dctx.clientID, ipStringFromAddr(pctx.Addr)) upsConf, err := s.conf.GetCustomUpstreamByClient(id) if err != nil { diff --git a/internal/dnsforward/dnsforward.go b/internal/dnsforward/dnsforward.go index fcd438e3..2d32cfd2 100644 --- a/internal/dnsforward/dnsforward.go +++ b/internal/dnsforward/dnsforward.go @@ -28,7 +28,7 @@ import ( // DefaultTimeout is the default upstream timeout const DefaultTimeout = 10 * time.Second -// defaultClientIDCacheCount is the default count of items in the LRU client ID +// defaultClientIDCacheCount is the default count of items in the LRU ClientID // cache. The assumption here is that there won't be more than this many // requests between the BeforeRequestHandler stage and the actual processing. const defaultClientIDCacheCount = 1024 @@ -88,8 +88,8 @@ type Server struct { tableIPToHost *netutil.IPMap tableIPToHostLock sync.Mutex - // clientIDCache is a temporary storage for clientIDs that were - // extracted during the BeforeRequestHandler stage. + // clientIDCache is a temporary storage for ClientIDs that were extracted + // during the BeforeRequestHandler stage. clientIDCache cache.Cache // DNS proxy instance for internal usage diff --git a/internal/dnsforward/stats_test.go b/internal/dnsforward/stats_test.go index bdd4f4f5..fdaa3678 100644 --- a/internal/dnsforward/stats_test.go +++ b/internal/dnsforward/stats_test.go @@ -66,7 +66,7 @@ func TestProcessQueryLogsAndStats(t *testing.T) { reason: filtering.NotFilteredNotFound, wantStatResult: stats.RNotFiltered, }, { - name: "success_tls_client_id", + name: "success_tls_clientid", proto: proxy.ProtoTLS, addr: &net.TCPAddr{IP: net.IP{1, 2, 3, 4}, Port: 1234}, clientID: "cli42", diff --git a/internal/home/clients.go b/internal/home/clients.go index 098fba91..f539adbe 100644 --- a/internal/home/clients.go +++ b/internal/home/clients.go @@ -532,7 +532,7 @@ func (clients *clientsContainer) check(c *Client) (err error) { } else if err = dnsforward.ValidateClientID(id); err == nil { c.IDs[i] = id } else { - return fmt.Errorf("invalid client id at index %d: %q", i, id) + return fmt.Errorf("invalid clientid at index %d: %q", i, id) } } diff --git a/internal/home/dns.go b/internal/home/dns.go index 4278a321..4c27abd9 100644 --- a/internal/home/dns.go +++ b/internal/home/dns.go @@ -318,7 +318,7 @@ func applyAdditionalFiltering(clientAddr net.IP, clientID string, setts *filteri } } - log.Debug("using settings for client %s with ip %s and id %q", c.Name, clientAddr, clientID) + log.Debug("using settings for client %s with ip %s and clientid %q", c.Name, clientAddr, clientID) if c.UseOwnBlockedServices { Context.dnsFilter.ApplyBlockedServices(setts, c.BlockedServices, false) diff --git a/internal/querylog/search.go b/internal/querylog/search.go index d387c938..4a3de979 100644 --- a/internal/querylog/search.go +++ b/internal/querylog/search.go @@ -8,7 +8,7 @@ import ( "github.com/AdguardTeam/golibs/log" ) -// client finds the client info, if any, by its client ID and IP address, +// client finds the client info, if any, by its ClientID and IP address, // optionally checking the provided cache. It will use the IP address // regardless of if the IP anonymization is enabled now, because the // anonymization could have been disabled in the past, and client will try to @@ -57,7 +57,7 @@ func (l *queryLog) searchMemory(params *searchParams, cache clientCache) (entrie e.client, err = l.client(e.ClientID, e.IP.String(), cache) if err != nil { msg := "querylog: enriching memory record at time %s" + - " for client %q (client id %q): %s" + " for client %q (clientid %q): %s" log.Error(msg, e.Time, e.IP, e.ClientID, err) // Go on and try to match anyway. @@ -216,8 +216,8 @@ func (f quickMatchClientFinder) findClient(clientID, ip string) (c *Client) { var err error c, err = f.client(clientID, ip, f.cache) if err != nil { - log.Error("querylog: enriching file record for quick search:"+ - " for client %q (client id %q): %s", + log.Error( + "querylog: enriching file record for quick search: for client %q (clientid %q): %s", ip, clientID, err, @@ -259,8 +259,7 @@ func (l *queryLog) readNextEntry( e.client, err = l.client(e.ClientID, e.IP.String(), cache) if err != nil { log.Error( - "querylog: enriching file record at time %s"+ - " for client %q (client id %q): %s", + "querylog: enriching file record at time %s for client %q (clientid %q): %s", e.Time, e.IP, e.ClientID, diff --git a/openapi/CHANGELOG.md b/openapi/CHANGELOG.md index 9545d2ec..ef32f6ea 100644 --- a/openapi/CHANGELOG.md +++ b/openapi/CHANGELOG.md @@ -69,9 +69,9 @@ * The type of `"interval"` field is now `number` instead of `integer`. -### Client IDs in Access Settings +### ClientIDs in Access Settings -* The `POST /control/access/set` HTTP API now accepts client IDs in +* The `POST /control/access/set` HTTP API now accepts ClientIDs in `"allowed_clients"` and `"disallowed_clients"` fields. ### The new field `"unicode_name"` in `DNSQuestion` diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index 31dade36..30d25b44 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -822,12 +822,12 @@ - 'clients' 'operationId': 'clientsFind' 'summary': > - Get information about clients by their IP addresses or client IDs. + Get information about clients by their IP addresses or ClientIDs. 'parameters': - 'name': 'ip0' 'in': 'query' 'description': > - Filter by IP address or client IDs. Parameters with names `ip1`, + Filter by IP address or ClientIDs. Parameters with names `ip1`, `ip2`, and so on are also accepted and interpreted as "ip0 OR ip1 OR ip2". @@ -1150,7 +1150,7 @@ 'schema': 'type': 'string' - 'description': > - Client ID. + ClientID. 'example': 'client-1' 'in': 'query' 'name': 'client_id' @@ -1185,7 +1185,7 @@ 'schema': 'type': 'string' - 'description': > - Client ID. + ClientID. 'example': 'client-1' 'in': 'query' 'name': 'client_id' @@ -1890,7 +1890,7 @@ 'type': 'string' 'client_id': 'description': > - The client ID, if provided in DoH, DoQ, or DoT. + The ClientID, if provided in DoH, DoQ, or DoT. 'example': 'cli123' 'type': 'string' 'client_info': @@ -2276,7 +2276,7 @@ 'example': 'localhost' 'ids': 'type': 'array' - 'description': 'IP, CIDR, MAC, or client ID.' + 'description': 'IP, CIDR, MAC, or ClientID.' 'items': 'type': 'string' 'use_global_settings': @@ -2381,13 +2381,13 @@ 'properties': 'allowed_clients': 'description': > - The allowlist of clients: IP addresses, CIDRs, or client IDs. + The allowlist of clients: IP addresses, CIDRs, or ClientIDs. 'items': 'type': 'string' 'type': 'array' 'disallowed_clients': 'description': > - The blocklist of clients: IP addresses, CIDRs, or client IDs. + The blocklist of clients: IP addresses, CIDRs, or ClientIDs. 'items': 'type': 'string' 'type': 'array' @@ -2411,7 +2411,7 @@ 'example': 'localhost' 'ids': 'type': 'array' - 'description': 'IP, CIDR, MAC, or client ID.' + 'description': 'IP, CIDR, MAC, or ClientID.' 'items': 'type': 'string' 'use_global_settings': From 0ef83441788ae041097343a384d571d3a6e19a43 Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Thu, 10 Feb 2022 18:30:41 +0300 Subject: [PATCH 121/135] Pull request: 3503 password policy Merge in DNS/adguard-home from 3503-password-policy to master Closes #3503. Squashed commit of the following: commit 1f03cd9ef6e76a691ae383d6ba4b7f851eabddb8 Author: Eugene Burkov Date: Thu Feb 10 18:24:59 2022 +0300 client: imp msg commit e164ae2544284cf9a1d3333c50b68e361f78ce2a Merge: b7efd764 f53f48cc Author: Eugene Burkov Date: Thu Feb 10 16:52:01 2022 +0300 Merge branch 'master' into 3503-password-policy commit b7efd7640ec0fa3deac5290f8306ce5142428718 Author: Ildar Kamalov Date: Thu Feb 10 16:17:59 2022 +0300 client: remove empty line commit f19aba6cb579d2c4681675c881000c8f16257ab9 Author: Ildar Kamalov Date: Thu Feb 10 16:09:14 2022 +0300 client: validate password length commit a6943c94483306ecfc0d1431d576d42053823b61 Author: Eugene Burkov Date: Fri Feb 4 18:57:02 2022 +0300 all: fix docs again commit 9346bb6c393af0799a79b228285acdd8f8799b83 Author: Eugene Burkov Date: Fri Feb 4 18:54:15 2022 +0300 openapi: fix docs commit a8016443237c130f69108970ddfc77ef71126be6 Author: Eugene Burkov Date: Fri Feb 4 18:25:55 2022 +0300 all: validate passwd runes count --- CHANGELOG.md | 2 + client/package-lock.json | 114 +++++++++++++++++++++++-------- client/package.json | 1 + client/src/__locales/en.json | 3 +- client/src/helpers/constants.js | 2 + client/src/helpers/validators.js | 14 +++- client/src/install/Setup/Auth.js | 3 +- internal/home/controlinstall.go | 16 +++++ openapi/CHANGELOG.md | 6 ++ openapi/openapi.yaml | 3 + 10 files changed, 133 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b14fa13..54c916d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -72,6 +72,7 @@ In this release, the schema version has changed from 12 to 13. ### Security +- Enforced password strength policy ([3503]). - Weaker cipher suites that use the CBC (cipher block chaining) mode of operation have been disabled ([#2993]). @@ -79,6 +80,7 @@ In this release, the schema version has changed from 12 to 13. [#2993]: https://github.com/AdguardTeam/AdGuardHome/issues/2993 [#3057]: https://github.com/AdguardTeam/AdGuardHome/issues/3057 [#3367]: https://github.com/AdguardTeam/AdGuardHome/issues/3367 +[#3503]: https://github.com/AdguardTeam/AdGuardHome/issues/3503 [#4216]: https://github.com/AdguardTeam/AdGuardHome/issues/4216 [#4221]: https://github.com/AdguardTeam/AdGuardHome/issues/4221 [#4238]: https://github.com/AdguardTeam/AdGuardHome/issues/4238 diff --git a/client/package-lock.json b/client/package-lock.json index 09746154..ba1d3772 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1700,6 +1700,12 @@ "v8-to-istanbul": "^4.1.3" }, "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, "ansi-styles": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", @@ -1720,6 +1726,12 @@ "supports-color": "^7.1.0" } }, + "char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1747,6 +1759,25 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, + "string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "requires": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, "supports-color": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", @@ -3959,10 +3990,9 @@ "integrity": "sha1-6LL+PX8at9aaMhma/5HqaTFAlRU=" }, "char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-2.0.0.tgz", + "integrity": "sha512-oGu2QekBMXgyQNWPDRQ001bjvDnZe4/zBTz37TMbiKz1NbNiyiH5hRkobe7npRN6GfbGbxMYFck/vQ1r9c1VMA==" }, "character-entities": { "version": "1.2.4", @@ -10037,6 +10067,12 @@ "string-length": "^4.0.1" }, "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, "ansi-styles": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", @@ -10057,6 +10093,12 @@ "supports-color": "^7.1.0" } }, + "char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -10078,6 +10120,25 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "requires": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, "supports-color": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", @@ -14193,38 +14254,26 @@ "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=" }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, "string-length": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.1.tgz", - "integrity": "sha512-PKyXUd0LK0ePjSOnWn34V2uD6acUWev9uy0Ft05k0E8xRW+SKcA0F7eMr7h5xlzfn+4O3N+55rduYyet3Jk+jw==", - "dev": true, + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-5.0.1.tgz", + "integrity": "sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow==", "requires": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" + "char-regex": "^2.0.0", + "strip-ansi": "^7.0.1" }, "dependencies": { "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==" }, "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", "requires": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^6.0.1" } } } @@ -14297,6 +14346,15 @@ "define-properties": "^1.1.3" } }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, "stringify-entities": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-3.0.1.tgz", diff --git a/client/package.json b/client/package.json index aa96f271..22b83010 100644 --- a/client/package.json +++ b/client/package.json @@ -42,6 +42,7 @@ "redux-actions": "^2.6.5", "redux-form": "^8.3.5", "redux-thunk": "^2.3.0", + "string-length": "^5.0.1", "url-polyfill": "^1.1.9" }, "devDependencies": { diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index 07021b59..9917ef2e 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -627,5 +627,6 @@ "use_saved_key": "Use the previously saved key", "parental_control": "Parental Control", "safe_browsing": "Safe Browsing", - "served_from_cache": "{{value}} (served from cache)" + "served_from_cache": "{{value}} (served from cache)", + "form_error_password_length": "Password must be at least {{value}} characters long" } diff --git a/client/src/helpers/constants.js b/client/src/helpers/constants.js index d4477b72..197cabba 100644 --- a/client/src/helpers/constants.js +++ b/client/src/helpers/constants.js @@ -26,6 +26,8 @@ export const R_WIN_ABSOLUTE_PATH = /^([a-zA-Z]:)?(\\|\/)(?:[^\\/:*?"<>|\x00]+\\) export const R_CLIENT_ID = /^[a-z0-9-]{1,63}$/; +export const MIN_PASSWORD_LENGTH = 8; + export const HTML_PAGES = { INSTALL: '/install.html', LOGIN: '/login.html', diff --git a/client/src/helpers/validators.js b/client/src/helpers/validators.js index 2ebf6a30..862a2ca4 100644 --- a/client/src/helpers/validators.js +++ b/client/src/helpers/validators.js @@ -1,4 +1,5 @@ import i18next from 'i18next'; +import stringLength from 'string-length'; import { MAX_PORT, @@ -13,6 +14,7 @@ import { UNSAFE_PORTS, R_CLIENT_ID, R_DOMAIN, + MIN_PASSWORD_LENGTH, } from './constants'; import { ip4ToInt, isValidAbsolutePath } from './form'; import { isIpInCidr, parseSubnetMask } from './helpers'; @@ -320,10 +322,20 @@ export const validatePath = (value) => { * @param cidr {string} * @returns {Function} */ - export const validateIpv4InCidr = (valueIp, allValues) => { if (!isIpInCidr(valueIp, allValues.cidr)) { return i18next.t('form_error_subnet', { ip: valueIp, cidr: allValues.cidr }); } return undefined; }; + +/** + * @param value {string} + * @returns {Function} + */ +export const validatePasswordLength = (value) => { + if (value && stringLength(value) < MIN_PASSWORD_LENGTH) { + return i18next.t('form_error_password_length', { value: MIN_PASSWORD_LENGTH }); + } + return undefined; +}; diff --git a/client/src/install/Setup/Auth.js b/client/src/install/Setup/Auth.js index b4184191..c2314aa5 100644 --- a/client/src/install/Setup/Auth.js +++ b/client/src/install/Setup/Auth.js @@ -8,6 +8,7 @@ import i18n from '../../i18n'; import Controls from './Controls'; import { renderInputField } from '../../helpers/form'; import { FORM_NAME } from '../../helpers/constants'; +import { validatePasswordLength } from '../../helpers/validators'; const required = (value) => { if (value || value === 0) { @@ -67,7 +68,7 @@ const Auth = (props) => { type="password" className="form-control" placeholder={ t('install_auth_password_enter') } - validate={[required]} + validate={[required, validatePasswordLength]} autoComplete="new-password" />
    diff --git a/internal/home/controlinstall.go b/internal/home/controlinstall.go index 82598078..98cbf31a 100644 --- a/internal/home/controlinstall.go +++ b/internal/home/controlinstall.go @@ -13,6 +13,7 @@ import ( "runtime" "strings" "time" + "unicode/utf8" "github.com/AdguardTeam/AdGuardHome/internal/aghalg" "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" @@ -359,6 +360,9 @@ func shutdownSrv(ctx context.Context, srv *http.Server) { } } +// PasswordMinRunes is the minimum length of user's password in runes. +const PasswordMinRunes = 8 + // Apply new configuration, start DNS server, restart Web server func (web *Web) handleInstallConfigure(w http.ResponseWriter, r *http.Request) { req, restartHTTP, err := decodeApplyConfigReq(r.Body) @@ -368,6 +372,18 @@ func (web *Web) handleInstallConfigure(w http.ResponseWriter, r *http.Request) { return } + if utf8.RuneCountInString(req.Password) < PasswordMinRunes { + aghhttp.Error( + r, + w, + http.StatusUnprocessableEntity, + "password must be at least %d symbols long", + PasswordMinRunes, + ) + + return + } + err = aghnet.CheckPort("udp", req.DNS.IP, req.DNS.Port) if err != nil { aghhttp.Error(r, w, http.StatusBadRequest, "%s", err) diff --git a/openapi/CHANGELOG.md b/openapi/CHANGELOG.md index ef32f6ea..0762fdf2 100644 --- a/openapi/CHANGELOG.md +++ b/openapi/CHANGELOG.md @@ -4,6 +4,12 @@ ## v0.107.3: API changes +### The new possible status code in `/install/configure` response. + +* The new status code `422 Unprocessable Entity` in the response for + `POST /install/configure` which means that the specified password does not + meet the strength requirements. + ### The new field `"version"` in `AddressesInfo` * The new field `"version"` in `GET /install/get_addresses` is the version of diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index 30d25b44..85c372a3 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -1088,6 +1088,9 @@ 'description': > Failed to parse initial configuration or cannot listen to the specified addresses. + '422': + 'description': > + The specified password does not meet the strength requirements. '500': 'description': 'Cannot start the DNS server' '/login': From a1f29c31b99928a5ca4356cddbfcd0048e9007a0 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Thu, 10 Feb 2022 20:42:39 +0300 Subject: [PATCH 122/135] Pull request: client: imp validation texts Merge in DNS/adguard-home from imp-i18n to master Squashed commit of the following: commit c58c00383824a88ea8e22a845e422ba2ff7d225e Author: Ainar Garipov Date: Thu Feb 10 20:21:00 2022 +0300 client: imp validation texts --- client/src/__locales/en.json | 66 ++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index 9917ef2e..1559a24e 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -35,24 +35,24 @@ "dhcp_config_saved": "DHCP configuration successfully saved", "dhcp_ipv4_settings": "DHCP IPv4 Settings", "dhcp_ipv6_settings": "DHCP IPv6 Settings", - "form_error_required": "Required field", - "form_error_ip4_format": "Invalid IPv4 address", - "form_error_ip4_range_start_format": "Invalid IPv4 address of the range start", - "form_error_ip4_range_end_format": "Invalid IPv4 address of the range end", - "form_error_ip4_gateway_format": "Invalid IPv4 address of the gateway", - "form_error_ip6_format": "Invalid IPv6 address", - "form_error_ip_format": "Invalid IP address", - "form_error_mac_format": "Invalid MAC address", - "form_error_client_id_format": "ClientID must contain only numbers, lowercase letters, and hyphens", - "form_error_server_name": "Invalid server name", - "form_error_subnet": "Subnet \"{{cidr}}\" does not contain the IP address \"{{ip}}\"", - "form_error_positive": "Must be greater than 0", - "out_of_range_error": "Must be out of range \"{{start}}\"-\"{{end}}\"", - "lower_range_start_error": "Must be lower than range start", - "greater_range_start_error": "Must be greater than range start", - "greater_range_end_error": "Must be greater than range end", - "subnet_error": "Addresses must be in one subnet", - "gateway_or_subnet_invalid": "Subnet mask invalid", + "form_error_required": "Required field.", + "form_error_ip4_format": "Invalid IPv4 address.", + "form_error_ip4_range_start_format": "Invalid IPv4 address of the range start.", + "form_error_ip4_range_end_format": "Invalid IPv4 address of the range end.", + "form_error_ip4_gateway_format": "Invalid IPv4 address of the gateway.", + "form_error_ip6_format": "Invalid IPv6 address.", + "form_error_ip_format": "Invalid IP address.", + "form_error_mac_format": "Invalid MAC address.", + "form_error_client_id_format": "ClientID must contain only numbers, lowercase letters, and hyphens.", + "form_error_server_name": "Invalid server name.", + "form_error_subnet": "Subnet \"{{cidr}}\" does not contain the IP address \"{{ip}}\".", + "form_error_positive": "Must be greater than 0.", + "out_of_range_error": "Must be out of range \"{{start}}\"-\"{{end}}\".", + "lower_range_start_error": "Must be lower than range start.", + "greater_range_start_error": "Must be greater than range start.", + "greater_range_end_error": "Must be greater than range end.", + "subnet_error": "Addresses must be in one subnet.", + "gateway_or_subnet_invalid": "Subnet mask invalid.", "dhcp_form_gateway_input": "Gateway IP", "dhcp_form_subnet_input": "Subnet mask", "dhcp_form_range_title": "Range of IP addresses", @@ -196,8 +196,8 @@ "choose_allowlist": "Choose allowlists", "enter_valid_blocklist": "Enter a valid URL to the blocklist.", "enter_valid_allowlist": "Enter a valid URL to the allowlist.", - "form_error_url_format": "Invalid URL format", - "form_error_url_or_path_format": "Invalid URL or absolute path of the list", + "form_error_url_format": "Invalid URL format.", + "form_error_url_or_path_format": "Invalid URL or absolute path of the list.", "custom_filter_rules": "Custom filtering rules", "custom_filter_rules_hint": "Enter one rule on a line. You can use either adblock rules or hosts files syntax.", "system_host_files": "System hosts files", @@ -309,7 +309,7 @@ "install_settings_listen": "Listen interface", "install_settings_port": "Port", "install_settings_interface_link": "Your AdGuard Home admin web interface will be available on the following addresses:", - "form_error_port": "Enter valid port number", + "form_error_port": "Enter valid port number.", "install_settings_dns": "DNS server", "install_settings_dns_desc": "You will need to configure your devices or router to use the DNS server on the following addresses:", "install_settings_all_interfaces": "All interfaces", @@ -378,26 +378,26 @@ "encryption_key_input": "Copy/paste your PEM-encoded private key for your certificate here.", "encryption_enable": "Enable Encryption (HTTPS, DNS-over-HTTPS, and DNS-over-TLS)", "encryption_enable_desc": "If encryption is enabled, AdGuard Home admin interface will work over HTTPS, and the DNS server will listen for requests over DNS-over-HTTPS and DNS-over-TLS.", - "encryption_chain_valid": "Certificate chain is valid", - "encryption_chain_invalid": "Certificate chain is invalid", - "encryption_key_valid": "This is a valid {{type}} private key", - "encryption_key_invalid": "This is an invalid {{type}} private key", + "encryption_chain_valid": "Certificate chain is valid.", + "encryption_chain_invalid": "Certificate chain is invalid.", + "encryption_key_valid": "This is a valid {{type}} private key.", + "encryption_key_invalid": "This is an invalid {{type}} private key.", "encryption_subject": "Subject", "encryption_issuer": "Issuer", "encryption_hostnames": "Hostnames", "encryption_reset": "Are you sure you want to reset encryption settings?", "topline_expiring_certificate": "Your SSL certificate is about to expire. Update <0>Encryption settings.", "topline_expired_certificate": "Your SSL certificate is expired. Update <0>Encryption settings.", - "form_error_port_range": "Enter port number in the range of 80-65535", - "form_error_port_unsafe": "This is an unsafe port", - "form_error_equal": "Must not be equal", - "form_error_password": "Password mismatched", + "form_error_port_range": "Enter port number in the range of 80-65535.", + "form_error_port_unsafe": "This is an unsafe port.", + "form_error_equal": "Must not be equal.", + "form_error_password": "Password mismatched.", "reset_settings": "Reset settings", "update_announcement": "AdGuard Home {{version}} is now available! <0>Click here for more info.", "setup_guide": "Setup Guide", "dns_addresses": "DNS addresses", "dns_start": "DNS server is starting up", - "dns_status_error": "Error checking the DNS server status", + "dns_status_error": "Error checking the DNS server status.", "down": "Down", "fix": "Fix", "dns_providers": "Here is a <0>list of known DNS providers to choose from.", @@ -475,8 +475,8 @@ "dns_rewrites": "DNS rewrites", "form_domain": "Enter domain name or wildcard", "form_answer": "Enter IP address or domain name", - "form_error_domain_format": "Invalid domain format", - "form_error_answer_format": "Invalid answer format", + "form_error_domain_format": "Invalid domain format.", + "form_error_answer_format": "Invalid answer format.", "configure": "Configure", "main_settings": "Main settings", "block_services": "Block specific services", @@ -628,5 +628,5 @@ "parental_control": "Parental Control", "safe_browsing": "Safe Browsing", "served_from_cache": "{{value}} (served from cache)", - "form_error_password_length": "Password must be at least {{value}} characters long" + "form_error_password_length": "Password must be at least {{value}} characters long." } From 18079ca1bbf0e92f0cae3b2a179321bf3f232a54 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Fri, 11 Feb 2022 16:30:09 +0300 Subject: [PATCH 123/135] Pull request: all: upd go Merge in DNS/adguard-home from upd-go to master Squashed commit of the following: commit 5540d0afd7579a2f2d543afaa96008d12ce1bf3e Author: Ainar Garipov Date: Fri Feb 11 16:15:35 2022 +0300 all: upd go --- .gitattributes | 4 ++++ bamboo-specs/release.yaml | 6 +++--- bamboo-specs/test.yaml | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.gitattributes b/.gitattributes index b2b017bd..825a99ca 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,5 @@ client/* linguist-vendored +# This file contains a lot of inline SVG data, which often interferes with +# grepping. Technically, this file must be reviewed when new icons appear, but +# that happens fairly rarely. +client/src/components/ui/Icons.js -diff diff --git a/bamboo-specs/release.yaml b/bamboo-specs/release.yaml index 754bfa9d..796d874d 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.0' + 'dockerGo': 'adguard/golang-ubuntu:4.1' 'stages': - 'Make release': @@ -266,7 +266,7 @@ # need to build a few of these. 'variables': 'channel': 'beta' - 'dockerGo': 'adguard/golang-ubuntu:4.0' + 'dockerGo': 'adguard/golang-ubuntu:4.1' # release-vX.Y.Z branches are the branches from which the actual final release # is built. - '^release-v[0-9]+\.[0-9]+\.[0-9]+': @@ -281,4 +281,4 @@ # are the ones that actually get released. 'variables': 'channel': 'release' - 'dockerGo': 'adguard/golang-ubuntu:4.0' + 'dockerGo': 'adguard/golang-ubuntu:4.1' diff --git a/bamboo-specs/test.yaml b/bamboo-specs/test.yaml index c6a2ffee..e41f172f 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.0' + 'dockerGo': 'adguard/golang-ubuntu:4.1' 'stages': - 'Tests': From 6824eec3084a1a77e0d702c292f6453400df669a Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Fri, 11 Feb 2022 17:41:36 +0300 Subject: [PATCH 124/135] Pull request: scripts: imp mips compat Updates #4269. Squashed commit of the following: commit f633e875f4f0ab767a0537d9bfe95734823f8a51 Author: Ainar Garipov Date: Fri Feb 11 17:33:53 2022 +0300 scripts: imp mips compat --- scripts/install.sh | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/scripts/install.sh b/scripts/install.sh index 7cf35adc..8cad4609 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -39,8 +39,25 @@ is_command() { } # Function is_little_endian checks if the CPU is little-endian. +# +# See https://serverfault.com/a/163493/267530. is_little_endian() { - [ "$( head -c 6 /bin/sh | tail -c 1 )" = "$( printf '\001' )" ] + # The ASCII character "I" has the octal code of 111. In the two-byte octal + # display mode (-o), hexdump will print it either as "000111" on a little + # endian system or as a "111000" on a big endian one. Return the sixth + # character to compare it against the number '1'. + # + # Do not use echo -n, because its behavior in the presence of the -n flag is + # explicitly implementation-defined in POSIX. Use hexdump instead of od, + # because OpenWrt and its derivatives have the former but not the latter. + is_little_endian_result="$( + printf 'I'\ + | hexdump -o\ + | awk '{ print substr($2, 6, 1); exit; }' + )" + readonly is_little_endian_result + + [ "$is_little_endian_result" -eq '1' ] } # Function check_required checks if the required software is available on the From b43aa86caec77ae1f917d0543420cf622a732f1a Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Fri, 11 Feb 2022 18:56:08 +0300 Subject: [PATCH 125/135] Pull request: client: use strict search by client Updates #4271. Squashed commit of the following: commit 10a113126306fce51b4dd10a696b8c7d3213a445 Author: Ainar Garipov Date: Fri Feb 11 18:37:18 2022 +0300 client: more strict search commit 7aa24129195c0eba442bfe43564469fdb2a5b138 Author: Ainar Garipov Date: Fri Feb 11 18:22:18 2022 +0300 client: use strict search by client --- client/src/components/Logs/Cells/ClientCell.js | 2 +- client/src/helpers/renderFormattedClientCell.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/components/Logs/Cells/ClientCell.js b/client/src/components/Logs/Cells/ClientCell.js index cfcf19ec..79d4cd4f 100644 --- a/client/src/components/Logs/Cells/ClientCell.js +++ b/client/src/components/Logs/Cells/ClientCell.js @@ -199,7 +199,7 @@ const ClientCell = ({ {isDetailed && clientName && !whoisAvailable && ( {clientName} diff --git a/client/src/helpers/renderFormattedClientCell.js b/client/src/helpers/renderFormattedClientCell.js index 6cbb735f..3e610430 100644 --- a/client/src/helpers/renderFormattedClientCell.js +++ b/client/src/helpers/renderFormattedClientCell.js @@ -64,7 +64,7 @@ export const renderFormattedClientCell = (value, info, isDetailed = false, isLog } return
    - {nameContainer} + {nameContainer} {whoisContainer}
    ; }; From f13106727890c2bd265ab9e3bbb29b5d5430101b Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Mon, 14 Feb 2022 16:56:14 +0300 Subject: [PATCH 126/135] Pull request: 3381 check private domains Merge in DNS/adguard-home from 3381-validate-privateness to master Closes #3381. Squashed commit of the following: commit 21cb12d10b07bb0bf0578db74ca9ac7b3ac5ae14 Author: Eugene Burkov Date: Mon Feb 14 16:29:59 2022 +0300 all: imp code, docs commit 39793551438cbea71e6ec78d0e05bee2d8dba3e5 Author: Eugene Burkov Date: Mon Feb 14 15:08:36 2022 +0300 all: imp code, docs commit 6b71848fd0980582b1bfe24a34f48608795e9b7d Author: Eugene Burkov Date: Mon Feb 14 14:22:00 2022 +0300 all: check private domains --- CHANGELOG.md | 6 + go.mod | 2 +- go.sum | 3 +- internal/aghnet/subnetdetector.go | 10 +- internal/dnsforward/http.go | 251 +++++++++++------- internal/dnsforward/http_test.go | 62 ++++- .../TestDNSForwardHTTP_handleSetConfig.json | 37 +++ 7 files changed, 262 insertions(+), 109 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54c916d8..2976e276 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,11 @@ and this project adheres to ### Changed +- Domain-specific private reverse DNS upstream servers are now validated to + allow only `*.in-addr.arpa` and `*.ip6.arpa` domains pointing to + locally-served networks ([#3381]). **Note:** If you already have invalid + entires in your configuration, consider removing them manually, since they + essentially had no effect. - Response filtering is now performed using the record types of the answer section of messages as opposed to the type of the question ([#4238]). - Instead of adding the build time information, the build scripts now use the @@ -80,6 +85,7 @@ In this release, the schema version has changed from 12 to 13. [#2993]: https://github.com/AdguardTeam/AdGuardHome/issues/2993 [#3057]: https://github.com/AdguardTeam/AdGuardHome/issues/3057 [#3367]: https://github.com/AdguardTeam/AdGuardHome/issues/3367 +[#3381]: https://github.com/AdguardTeam/AdGuardHome/issues/3381 [#3503]: https://github.com/AdguardTeam/AdGuardHome/issues/3503 [#4216]: https://github.com/AdguardTeam/AdGuardHome/issues/4216 [#4221]: https://github.com/AdguardTeam/AdGuardHome/issues/4221 diff --git a/go.mod b/go.mod index d75e299e..00182235 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.17 require ( github.com/AdguardTeam/dnsproxy v0.41.1 - github.com/AdguardTeam/golibs v0.10.4 + github.com/AdguardTeam/golibs v0.10.5 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 65128977..99f20fd1 100644 --- a/go.sum +++ b/go.sum @@ -12,8 +12,9 @@ github.com/AdguardTeam/dnsproxy v0.41.1/go.mod h1:PZ9l22h3Er+5mxFQB7oHZMTvx+aa9R 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.3/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw= -github.com/AdguardTeam/golibs v0.10.4 h1:TMBkablZC0IZOpRgg9fzAKlxxNhSN2YJq7qbgtuZ7PQ= github.com/AdguardTeam/golibs v0.10.4/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw= +github.com/AdguardTeam/golibs v0.10.5 h1:4/nl1yIBJOv5luVu9SURW8LfgOjI3zQ2moIUy/1k0y4= +github.com/AdguardTeam/golibs v0.10.5/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 index e353903b..fd338aaa 100644 --- a/internal/aghnet/subnetdetector.go +++ b/internal/aghnet/subnetdetector.go @@ -6,16 +6,18 @@ import ( // SubnetDetector describes IP address properties. type SubnetDetector struct { - // spNets is the slice of special-purpose address registries as defined - // by RFC-6890 (https://tools.ietf.org/html/rfc6890). + // spNets is the collection of special-purpose address registries as defined + // by RFC 6890. spNets []*net.IPNet - // locServedNets is the slice of locally-served networks as defined by - // RFC-6303 (https://tools.ietf.org/html/rfc6303). + // 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. diff --git a/internal/dnsforward/http.go b/internal/dnsforward/http.go index b0de11b9..d653fa1e 100644 --- a/internal/dnsforward/http.go +++ b/internal/dnsforward/http.go @@ -5,10 +5,12 @@ import ( "fmt" "net" "net/http" + "sort" "strings" "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" @@ -41,7 +43,7 @@ type dnsConfig struct { LocalPTRUpstreams *[]string `json:"local_ptr_upstreams"` } -func (s *Server) getDNSConfig() dnsConfig { +func (s *Server) getDNSConfig() (c *dnsConfig) { s.serverLock.RLock() defer s.serverLock.RUnlock() @@ -70,7 +72,7 @@ func (s *Server) getDNSConfig() dnsConfig { upstreamMode = "parallel" } - return dnsConfig{ + return &dnsConfig{ Upstreams: &upstreams, UpstreamsFile: &upstreamFile, Bootstraps: &bootstraps, @@ -106,7 +108,7 @@ func (s *Server) handleGetConfig(w http.ResponseWriter, r *http.Request) { // since there is no need to omit it while decoding from JSON. DefautLocalPTRUpstreams []string `json:"default_local_ptr_upstreams,omitempty"` }{ - dnsConfig: s.getDNSConfig(), + dnsConfig: *s.getDNSConfig(), DefautLocalPTRUpstreams: defLocalPTRUps, } @@ -138,39 +140,63 @@ func (req *dnsConfig) checkBlockingMode() bool { } func (req *dnsConfig) checkUpstreamsMode() bool { - if req.UpstreamMode == nil { - return true - } + valid := []string{"", "fastest_addr", "parallel"} - for _, valid := range []string{ - "", - "fastest_addr", - "parallel", - } { - if *req.UpstreamMode == valid { - return true - } - } - - return false + return req.UpstreamMode == nil || stringutil.InSlice(valid, *req.UpstreamMode) } -func (req *dnsConfig) checkBootstrap() (string, error) { +func (req *dnsConfig) checkBootstrap() (err error) { if req.Bootstraps == nil { - return "", nil + return nil } - for _, boot := range *req.Bootstraps { - if boot == "" { - return boot, fmt.Errorf("invalid bootstrap server address: empty") + var b string + defer func() { err = errors.Annotate(err, "checking bootstrap %s: invalid address: %w", b) }() + + for _, b = range *req.Bootstraps { + if b == "" { + return errors.Error("empty") } - if _, err := upstream.NewResolver(boot, nil); err != nil { - return boot, fmt.Errorf("invalid bootstrap server address: %w", err) + if _, err = upstream.NewResolver(b, nil); err != nil { + return err } } - return "", nil + return nil +} + +// validate returns an error if any field of req is invalid. +func (req *dnsConfig) validate(snd *aghnet.SubnetDetector) (err error) { + if req.Upstreams != nil { + err = ValidateUpstreams(*req.Upstreams) + if err != nil { + return fmt.Errorf("validating upstream servers: %w", err) + } + } + + if req.LocalPTRUpstreams != nil { + err = ValidateUpstreamsPrivate(*req.LocalPTRUpstreams, snd) + if err != nil { + return fmt.Errorf("validating private upstream servers: %w", err) + } + } + + err = req.checkBootstrap() + if err != nil { + return err + } + + switch { + case !req.checkBlockingMode(): + return errors.Error("blocking_mode: incorrect value") + case !req.checkUpstreamsMode(): + return errors.Error("upstream_mode: incorrect value") + case !req.checkCacheTTL(): + return errors.Error("cache_ttl_min must be less or equal than cache_ttl_max") + default: + return nil + } } func (req *dnsConfig) checkCacheTTL() bool { @@ -190,69 +216,33 @@ func (req *dnsConfig) checkCacheTTL() bool { } func (s *Server) handleSetConfig(w http.ResponseWriter, r *http.Request) { - req := dnsConfig{} - err := json.NewDecoder(r.Body).Decode(&req) + req := &dnsConfig{} + err := json.NewDecoder(r.Body).Decode(req) if err != nil { - aghhttp.Error(r, w, http.StatusBadRequest, "json Encode: %s", err) + aghhttp.Error(r, w, http.StatusBadRequest, "decoding request: %s", err) return } - if req.Upstreams != nil { - if err = ValidateUpstreams(*req.Upstreams); err != nil { - aghhttp.Error(r, w, http.StatusBadRequest, "wrong upstreams specification: %s", err) - - return - } - } - - var errBoot string - if errBoot, err = req.checkBootstrap(); err != nil { - aghhttp.Error( - r, - w, - http.StatusBadRequest, - "%s can not be used as bootstrap dns cause: %s", - errBoot, - err, - ) + err = req.validate(s.subnetDetector) + if err != nil { + aghhttp.Error(r, w, http.StatusBadRequest, "%s", err) return } - switch { - case !req.checkBlockingMode(): - aghhttp.Error(r, w, http.StatusBadRequest, "blocking_mode: incorrect value") - - return - case !req.checkUpstreamsMode(): - aghhttp.Error(r, w, http.StatusBadRequest, "upstream_mode: incorrect value") - - return - case !req.checkCacheTTL(): - aghhttp.Error( - r, - w, - http.StatusBadRequest, - "cache_ttl_min must be less or equal than cache_ttl_max", - ) - - return - default: - // Go on. - } - restart := s.setConfig(req) s.conf.ConfigModified() if restart { - if err = s.Reconfigure(nil); err != nil { + err = s.Reconfigure(nil) + if err != nil { aghhttp.Error(r, w, http.StatusInternalServerError, "%s", err) } } } -func (s *Server) setConfigRestartable(dc dnsConfig) (restart bool) { +func (s *Server) setConfigRestartable(dc *dnsConfig) (restart bool) { if dc.Upstreams != nil { s.conf.UpstreamDNS = *dc.Upstreams restart = true @@ -273,9 +263,9 @@ func (s *Server) setConfigRestartable(dc dnsConfig) (restart bool) { restart = true } - if dc.RateLimit != nil { - restart = restart || s.conf.Ratelimit != *dc.RateLimit + if dc.RateLimit != nil && s.conf.Ratelimit != *dc.RateLimit { s.conf.Ratelimit = *dc.RateLimit + restart = true } if dc.EDNSCSEnabled != nil { @@ -306,7 +296,7 @@ func (s *Server) setConfigRestartable(dc dnsConfig) (restart bool) { return restart } -func (s *Server) setConfig(dc dnsConfig) (restart bool) { +func (s *Server) setConfig(dc *dnsConfig) (restart bool) { s.serverLock.Lock() defer s.serverLock.Unlock() @@ -353,52 +343,117 @@ type upstreamJSON struct { PrivateUpstreams []string `json:"private_upstream"` } -// IsCommentOrEmpty returns true of the string starts with a "#" character or is -// an empty string. This function is useful for filtering out non-upstream -// lines from upstream configs. +// IsCommentOrEmpty returns true if s starts with a "#" character or is empty. +// This function is useful for filtering out non-upstream lines from upstream +// configs. 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. +// +// TODO(e.burkov): Perhaps proxy.ParseUpstreamsConfig should validate upstreams +// slice already so that this function may be considered useless. +func newUpstreamConfig(upstreams []string) (conf *proxy.UpstreamConfig, err error) { + // No need to validate comments and empty lines. + upstreams = stringutil.FilterOut(upstreams, IsCommentOrEmpty) + if len(upstreams) == 0 { + // Consider this case valid since it means the default server should be + // used. + return nil, nil + } + + conf, err = proxy.ParseUpstreamsConfig( + upstreams, + &upstream.Options{Bootstrap: []string{}, Timeout: DefaultTimeout}, + ) + if err != nil { + return nil, err + } else if len(conf.Upstreams) == 0 { + return nil, errors.Error("no default upstreams specified") + } + + for _, u := range upstreams { + _, err = validateUpstream(u) + if err != nil { + return nil, err + } + } + + return conf, nil +} + // ValidateUpstreams validates each upstream and returns an error if any // upstream is invalid or if there are no default upstreams specified. // -// TODO(e.burkov): Move into aghnet or even into dnsproxy. +// TODO(e.burkov): Move into aghnet or even into dnsproxy. func ValidateUpstreams(upstreams []string) (err error) { - // No need to validate comments - upstreams = stringutil.FilterOut(upstreams, IsCommentOrEmpty) + _, err = newUpstreamConfig(upstreams) - // Consider this case valid because defaultDNS will be used - if len(upstreams) == 0 { - return nil + return err +} + +// stringKeysSorted returns the sorted slice of string keys of m. +// +// TODO(e.burkov): Use generics in Go 1.18. Move into golibs. +func stringKeysSorted(m map[string][]upstream.Upstream) (sorted []string) { + sorted = make([]string, 0, len(m)) + for s := range m { + sorted = append(sorted, s) } - _, err = proxy.ParseUpstreamsConfig( - upstreams, - &upstream.Options{ - Bootstrap: []string{}, - Timeout: DefaultTimeout, - }, - ) + sort.Strings(sorted) + + return sorted +} + +// 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) { + conf, err := newUpstreamConfig(upstreams) if err != nil { return err } - var defaultUpstreamFound bool - for _, u := range upstreams { - var useDefault bool - useDefault, err = validateUpstream(u) + if conf == nil { + return nil + } + + var errs []error + + for _, domain := range stringKeysSorted(conf.DomainReservedUpstreams) { + var subnet *net.IPNet + subnet, err = netutil.SubnetFromReversedAddr(domain) if err != nil { - return err + errs = append(errs, err) + + continue } - if !defaultUpstreamFound { - defaultUpstreamFound = useDefault + if !lnc.IsLocallyServedNetwork(subnet.IP) { + errs = append( + errs, + fmt.Errorf("arpa domain %q should point to a locally-served network", domain), + ) } } - if !defaultUpstreamFound { - return fmt.Errorf("no default upstreams specified") + if len(errs) > 0 { + return errors.List("checking domain-specific upstreams", errs...) } return nil diff --git a/internal/dnsforward/http_test.go b/internal/dnsforward/http_test.go index 876cfdcf..66931f4d 100644 --- a/internal/dnsforward/http_test.go +++ b/internal/dnsforward/http_test.go @@ -184,12 +184,11 @@ func TestDNSForwardHTTP_handleSetConfig(t *testing.T) { wantSet: "", }, { name: "upstream_dns_bad", - wantSet: `wrong upstreams specification: bad ipport address "!!!": address !!!: ` + - `missing port in address`, + wantSet: `validating upstream servers: bad ipport address "!!!": ` + + `address !!!: missing port in address`, }, { name: "bootstraps_bad", - wantSet: `a can not be used as bootstrap dns cause: ` + - `invalid bootstrap server address: ` + + wantSet: `checking bootstrap a: invalid address: ` + `Resolver a is not eligible to be a bootstrap DNS server`, }, { name: "cache_bad_ttl", @@ -200,6 +199,10 @@ func TestDNSForwardHTTP_handleSetConfig(t *testing.T) { }, { name: "local_ptr_upstreams_good", wantSet: "", + }, { + name: "local_ptr_upstreams_bad", + wantSet: `validating private upstream servers: checking domain-specific upstreams: ` + + `bad arpa domain name "non.arpa": not a reversed ip network`, }, { name: "local_ptr_upstreams_null", wantSet: "", @@ -350,7 +353,7 @@ func TestValidateUpstream(t *testing.T) { } } -func TestValidateUpstreamsSet(t *testing.T) { +func TestValidateUpstreams(t *testing.T) { testCases := []struct { name string wantErr string @@ -397,3 +400,52 @@ func TestValidateUpstreamsSet(t *testing.T) { }) } } + +func TestValidateUpstreamsPrivate(t *testing.T) { + snd, err := aghnet.NewSubnetDetector() + require.NoError(t, err) + + testCases := []struct { + name string + wantErr string + u string + }{{ + name: "success_address", + wantErr: ``, + u: "[/1.0.0.127.in-addr.arpa/]#", + }, { + name: "success_subnet", + wantErr: ``, + u: "[/127.in-addr.arpa/]#", + }, { + name: "not_arpa_subnet", + wantErr: `checking domain-specific upstreams: ` + + `bad arpa domain name "hello.world": not a reversed ip network`, + u: "[/hello.world/]#", + }, { + name: "non-private_arpa_address", + wantErr: `checking domain-specific upstreams: ` + + `arpa domain "1.2.3.4.in-addr.arpa." should point to a locally-served network`, + u: "[/1.2.3.4.in-addr.arpa/]#", + }, { + name: "non-private_arpa_subnet", + wantErr: `checking domain-specific upstreams: ` + + `arpa domain "128.in-addr.arpa." should point to a locally-served network`, + u: "[/128.in-addr.arpa/]#", + }, { + name: "several_bad", + wantErr: `checking domain-specific upstreams: 2 errors: ` + + `"arpa domain \"1.2.3.4.in-addr.arpa.\" should point to a locally-served network", ` + + `"bad arpa domain name \"non.arpa\": not a reversed ip network"`, + u: "[/non.arpa/1.2.3.4.in-addr.arpa/127.in-addr.arpa/]#", + }} + + for _, tc := range testCases { + set := []string{"192.168.0.1", tc.u} + + t.Run(tc.name, func(t *testing.T) { + err = ValidateUpstreamsPrivate(set, snd) + testutil.AssertErrorMsg(t, tc.wantErr, err) + }) + } +} diff --git a/internal/dnsforward/testdata/TestDNSForwardHTTP_handleSetConfig.json b/internal/dnsforward/testdata/TestDNSForwardHTTP_handleSetConfig.json index b594029c..830bf491 100644 --- a/internal/dnsforward/testdata/TestDNSForwardHTTP_handleSetConfig.json +++ b/internal/dnsforward/testdata/TestDNSForwardHTTP_handleSetConfig.json @@ -520,6 +520,43 @@ ] } }, + "local_ptr_upstreams_bad": { + "req": { + "local_ptr_upstreams": [ + "123.123.123.123", + "[/non.arpa/]#" + ] + }, + "want": { + "upstream_dns": [ + "8.8.8.8:53", + "8.8.4.4:53" + ], + "upstream_dns_file": "", + "bootstrap_dns": [ + "9.9.9.10", + "149.112.112.10", + "2620:fe::10", + "2620:fe::fe:10" + ], + "protection_enabled": true, + "ratelimit": 0, + "blocking_mode": "", + "blocking_ipv4": "", + "blocking_ipv6": "", + "edns_cs_enabled": false, + "dnssec_enabled": false, + "disable_ipv6": false, + "upstream_mode": "", + "cache_size": 0, + "cache_ttl_min": 0, + "cache_ttl_max": 0, + "cache_optimistic": false, + "resolve_clients": false, + "use_private_ptr_resolvers": false, + "local_ptr_upstreams": [] + } + }, "local_ptr_upstreams_null": { "req": { "local_ptr_upstreams": null From 773b80a96978b41cef5556bb881150ff26f25d84 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Mon, 21 Feb 2022 17:06:12 +0300 Subject: [PATCH 127/135] Pull request: client: upd i18n Updates #2643. Squashed commit of the following: commit 048c245ab682f0799c2f7a7f0435a1898a482392 Author: Ainar Garipov Date: Mon Feb 21 16:58:10 2022 +0300 client: upd i18n --- client/src/__locales/be.json | 3 +- client/src/__locales/bg.json | 1 + client/src/__locales/cs.json | 136 +++++++++++++------------- client/src/__locales/da.json | 102 ++++++++++---------- client/src/__locales/de.json | 150 ++++++++++++++--------------- client/src/__locales/es.json | 142 +++++++++++++-------------- client/src/__locales/fa.json | 2 +- client/src/__locales/fi.json | 146 ++++++++++++++-------------- client/src/__locales/fr.json | 156 +++++++++++++++--------------- client/src/__locales/hr.json | 1 - client/src/__locales/hu.json | 1 - client/src/__locales/id.json | 3 +- client/src/__locales/it.json | 166 ++++++++++++++++---------------- client/src/__locales/ja.json | 116 +++++++++++----------- client/src/__locales/ko.json | 138 +++++++++++++------------- client/src/__locales/nl.json | 152 ++++++++++++++--------------- client/src/__locales/no.json | 4 +- client/src/__locales/pl.json | 148 ++++++++++++++-------------- client/src/__locales/pt-br.json | 140 +++++++++++++-------------- client/src/__locales/pt-pt.json | 136 +++++++++++++------------- client/src/__locales/ro.json | 152 ++++++++++++++--------------- client/src/__locales/ru.json | 148 ++++++++++++++-------------- client/src/__locales/si-lk.json | 1 - client/src/__locales/sk.json | 4 +- client/src/__locales/sl.json | 150 ++++++++++++++--------------- client/src/__locales/sr-cs.json | 3 +- client/src/__locales/sv.json | 19 ++-- client/src/__locales/tr.json | 156 +++++++++++++++--------------- client/src/__locales/uk.json | 74 +++++++------- client/src/__locales/vi.json | 3 +- client/src/__locales/zh-cn.json | 144 +++++++++++++-------------- client/src/__locales/zh-hk.json | 3 +- client/src/__locales/zh-tw.json | 146 ++++++++++++++-------------- 33 files changed, 1418 insertions(+), 1428 deletions(-) diff --git a/client/src/__locales/be.json b/client/src/__locales/be.json index 10079eb1..db3d9e85 100644 --- a/client/src/__locales/be.json +++ b/client/src/__locales/be.json @@ -593,7 +593,7 @@ "allowed": "Дазволены", "filtered": "Адфільтраваныя", "rewritten": "Перапісаныя", - "safe_search": "Бяспечны пошук", + "safe_search": "Уключыць Бяспечны пошук", "blocklist": "Чорны спіс", "milliseconds_abbreviation": "мс", "cache_size": "Памер кэша", @@ -623,7 +623,6 @@ "adg_will_drop_dns_queries": "AdGuard Home скіне ўсе DNS-запыты ад гэтага кліента.", "filter_allowlist": "УВАГА: Гэта дзеянне таксама выключыць правіла «{{disallowed_rule}}» са спіса дазволеных кліентаў.", "last_rule_in_allowlist": "Няможна заблакаваць гэтага кліента, бо вынятак правіла «{{disallowed_rule}}» АДКЛЮЧЫЦЬ рэжым белага спіса.", - "experimental": "Эксперыментальны", "use_saved_key": "Скарыстаць захаваны раней ключ", "parental_control": "Бацькоўскі кантроль", "safe_browsing": "Бяспечны інтэрнэт", diff --git a/client/src/__locales/bg.json b/client/src/__locales/bg.json index 8f8991f5..1b6a1db5 100644 --- a/client/src/__locales/bg.json +++ b/client/src/__locales/bg.json @@ -242,6 +242,7 @@ "show_whitelisted_responses": "В белия списък", "show_processed_responses": "Обработен", "allowed": "В белия списък", + "safe_search": "Безопасно търсене", "filter_category_general": "General", "filter_category_security": "Сигурност", "port_53_faq_link": "Порт 53 често е зает от \"DNSStubListener\" или \"systemd-resolved\" услуги. Моля, прочетете <0>тази инструкция как да решите това.", diff --git a/client/src/__locales/cs.json b/client/src/__locales/cs.json index 95935953..8d89f204 100644 --- a/client/src/__locales/cs.json +++ b/client/src/__locales/cs.json @@ -1,7 +1,7 @@ { "client_settings": "Nastavení klienta", - "example_upstream_reserved": "Můžete zadat odchozí DNS připojení <0>pro konkrétní doménu(y)", - "example_upstream_comment": "Můžete zadat komentář", + "example_upstream_reserved": "odchozí DNS připojení <0>pro konkrétní doménu(y);", + "example_upstream_comment": "komentář.", "upstream_parallel": "Použijte paralelní požadavky na urychlení řešení simultánním dotazováním na všechny navazující servery.", "parallel_requests": "Paralelní požadavky", "load_balancing": "Optimalizace vytížení", @@ -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á adresa IP", - "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", @@ -196,25 +196,25 @@ "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ů", "examples_title": "Příklady", "example_meaning_filter_block": "zablokovat přístup k doméně example.org a všem jejím subdoménám", "example_meaning_filter_whitelist": "odblokovat přístup k doméně example.org a všem jejím subdoménám", - "example_meaning_host_block": "AdGuard Home nyní vrátí adresu 127.0.0.1 pro doménu example.org (ale ne pro její subdomény).", - "example_comment": "! Sem se přidává komentář", - "example_comment_meaning": "jen komentář", - "example_comment_hash": "# Také komentář", - "example_regex_meaning": "blokuje přístup doménám, které vyhovují regulárnímu výrazu", - "example_upstream_regular": "obyčejný DNS (přes UDP)", - "example_upstream_dot": "šifrovaný <0>DNS skrze TLS", - "example_upstream_doh": "šifrovaný <0>DNS skrze HTTPS", - "example_upstream_doq": "šifrovaný <0>DNS skrze QUIC", - "example_upstream_sdns": "můžete použít <0>DNS razítka pro <1>DNSCrypt nebo <2>DNS skrze HTTPS řešitele", - "example_upstream_tcp": "obyčejný DNS (přes TCP)", + "example_meaning_host_block": "odezva s adresou 127.0.0.1 pro doménu example.org (ale ne pro její subdomény);", + "example_comment": "! Sem se přidává komentář.", + "example_comment_meaning": "jen komentář;", + "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_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);", "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 +259,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", @@ -277,7 +277,7 @@ "dns_over_quic": "DNS skrze QUIC", "client_id": "ID klienta", "client_id_placeholder": "Zadejte ID klienta", - "client_id_desc": "Různé klienty lze identifikovat pomocí speciálního ID klienta.
    Zde se můžete dozvědět více o tom, jak klienty identifikovat.", + "client_id_desc": "Klienty lze identifikovat pomocí ID klienta. Zde se můžete dozvědět více o tom, jak klienty identifikovat.", "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", @@ -309,7 +309,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í", @@ -334,7 +334,7 @@ "install_devices_router_list_4": "Na některých typech routerů nemůžete nastavit vlastní DNS server. V tomto případě může AdGuard Home pomoci, pokud jej nastavíte jako <0>DHCP server. V ostatních případech byste si v manuálu k Vašemu routeru měli zjistit, jak přizpůsobit vlastní DNS servery.", "install_devices_windows_list_1": "Otevřete ovládací panel prostřednictvím nabídky Start nebo vyhledání v systému Windows.", "install_devices_windows_list_2": "Přejděte na kategorii Síť a Internet a poté na Centrum sítí a sdílení.", - "install_devices_windows_list_3": "Na levé straně obrazovky najděte možnost \"Změnit nastavení adaptéru\" a klepněte na něj.", + "install_devices_windows_list_3": "Na levé straně panelu klikněte na \"Změnit nastavení adaptéru\".", "install_devices_windows_list_4": "Vyberte své aktivní spojení, klikněte na něj pravým tlačítkem myši a zvolte Vlastnosti.", "install_devices_windows_list_5": "V seznamu najděte \"Internet Protocol Version 4 (TCP/IP)\", (nebo IPv6, \"Internet Protocol Version 6 (TCP/IPv6)\"), vyberte jej a znovu klikněte na Vlastnosti.", "install_devices_windows_list_6": "Zvolte \"Použít následující adresy serveru DNS\" a zadejte adresy serveru AdGuard Home.", @@ -356,7 +356,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", @@ -367,7 +367,7 @@ "encryption_https_desc": "Pokud je nakonfigurován port HTTPS, AdGuard Home administrátorské rozhraní bude přístupné přes HTTPS a bude také poskytovat DNS skrze HTTPS na '/dns-query'.", "encryption_dot": "DNS skrze TLS port", "encryption_dot_desc": "Pokud je tento port nakonfigurován, AdGuard Home bude na tomto portu spouštět DNS skrze TLS server.", - "encryption_doq": "DNS skrze QUIC port", + "encryption_doq": "Port DNS skrze QUIC (experimentální)", "encryption_doq_desc": "Pokud je tento port nakonfigurován, AdGuard Home spustí na tomto portu server DNS skrze QUIC. Je to experimentální a nemusí být spolehlivé. V současnosti také není příliš mnoho klientů, kteří to podporují.", "encryption_certificates": "Certifikáty", "encryption_certificates_desc": "Chcete-li používat šifrování, musíte pro svou doménu poskytnout platný řetězec certifikátů SSL. Certifikát můžete získat bezplatně na adrese <0>{{link}}, nebo jej můžete zakoupit od jednoho z důvěryhodných certifikačních úřadů.", @@ -378,26 +378,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": "Toto není bezpečný 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.", @@ -405,8 +405,8 @@ "update_failed": "Automatická aktualizace selhala. Prosím následujte tyto kroky a aktualizujte ručně.", "manual_update": "Prosím následujte tyto kroky a aktualizujte ručně.", "processing_update": "Čekejte prosím, AdGuard Home se aktualizuje", - "clients_title": "Klienti", - "clients_desc": "Konfigurace zařízení připojených k AdGuard Home", + "clients_title": "Stálí klienti", + "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", @@ -417,7 +417,7 @@ "client_edit": "Upravit klienta", "client_identifier": "Identifikátor", "ip_address": "IP adresa", - "client_identifier_desc": "Klienti můžou být identifikováni podle IP adresy, CIDR, MAC adresy nebo speciálního ID klienta (může být použito pro DoT/DoH/DoQ). <0>Zde se můžete dozvědět více o tom, jak klienty identifikovat.", + "client_identifier_desc": "Klienti můžou být identifikováni podle jejich IP adresy, CIDR, MAC adresy nebo ID klienta (může být použito pro DoT/DoH/DoQ). <0>Zde se můžete dozvědět více o tom, jak klienty identifikovat.", "form_enter_ip": "Zadejte IP", "form_enter_subnet_ip": "Zadejte adresu IP adresu do podsítě \"{{cidr}}\"", "form_enter_mac": "Zadejte MAC", @@ -432,14 +432,14 @@ "clients_not_found": "Nenalezeni žádní klienti", "client_confirm_delete": "Opravdu chcete odstranit klienta \"{{key}}\"?", "list_confirm_delete": "Opravdu chcete smazat tento seznam?", - "auto_clients_title": "Klienti (doba spuštění)", - "auto_clients_desc": "Data o klientech, kteří používají AdGuard Home, ale nejsou uloženi v konfiguraci", + "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.", "access_title": "Nastavení přístupu", "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 je nakonfigurován, AdGuard Home bude přijímat požadavky pouze od těchto klientů.", + "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", - "access_disallowed_desc": "Seznam CIDR, IP adres nebo ID klientů. Pokud je nakonfigurován, AdGuard Home bude odmítat požadavky od těchto klientů. Pokud jsou povolení klienti nakonfigurováni, je toto pole ignorováno.", + "access_disallowed_desc": "Seznam CIDR, IP adres nebo ID klientů. Pokud tento seznam obsahuje položky, AdGuard Home bude odmítat požadavky od těchto klientů. Pokud jsou povolení klienti nakonfigurováni, je toto pole ignorováno.", "access_blocked_title": "Blokované domény", "access_blocked_desc": "Nezaměňujte to s filtry. AdGuard Home zruší dotazy DNS odpovídající těmto doménám a tyto dotazy se neobjeví ani v protokolu dotazů. Zde můžete určit přesné názvy domén, zástupné znaky a pravidla filtrování URL adres, např. \"example.org\", \"*.example.org\" nebo \"||example.org^\".", "access_settings_saved": "Nastavení přístupu bylo úspěšně uloženo", @@ -475,8 +475,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", @@ -507,7 +507,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", @@ -532,7 +532,7 @@ "netname": "Název sítě", "network": "Síť", "descr": "Popis", - "whois": "Whois", + "whois": "WHOIS", "filtering_rules_learn_more": "<0>Další informace o vytváření vlastních seznamů hostitelů.", "blocked_by_response": "Zakázáno dle CNAME nebo IP v odpovědi", "blocked_by_cname_or_ip": "Zakázáno dle CNAME nebo IP", @@ -552,10 +552,10 @@ "autofix_warning_list": "Jsou prováděny následující úlohy: <0>Deaktivace systému DNSStubListener <0>Nastavení adresy serveru DNS na 127.0.0.1 <0>Nahrazení cíle symbolického odkazu z /etc/resolv.conf do /run/systemd/resolve/resolv.conf <0>Zastavení služby DNSStubListener (znovu načtení služby systemd-resolved)", "autofix_warning_result": "Výsledkem je, že všechny požadavky DNS z vašeho systému jsou ve výchozím nastavení zpracovány službou AdGuard Home.", "tags_title": "Značky", - "tags_desc": "Můžete vybrat značky, které jsou přiřazeny klientovi. Značky mohou být zahrnuty do pravidel filtrování a umožňují Vám je přesněji použít. <0>Dozvědět se více", + "tags_desc": "Můžete vybrat značky, které jsou přiřazeny klientovi. Značky mohou být zahrnuty do pravidel filtrování a umožňují Vám je přesněji použít. <0>Dozvědět se více.", "form_select_tags": "Vyberte značky klienta", "check_title": "Zkontrolovat filtrování", - "check_desc": "Zkontrolujte, zda je název hostitele filtrován", + "check_desc": "Zkontrolujte, zda je název hostitele filtrován.", "check": "Zkontrolovat", "form_enter_host": "Zadejte název hostitele", "filtered_custom_rules": "Filtrováno pomocí vlastních pravidel filtrování", @@ -598,15 +598,15 @@ "blocklist": "Zakázaný", "milliseconds_abbreviation": "ms", "cache_size": "Velikost mezipaměti", - "cache_size_desc": "Velikost mezipaměti DNS (v bajtech)", + "cache_size_desc": "Velikost mezipaměti DNS (v bajtech).", "cache_ttl_min_override": "Přepsat minimální hodnotu TTL", "cache_ttl_max_override": "Přepsat maximální hodnotu TTL", "enter_cache_size": "Zadejte velikost mezipaměti (v bajtech)", "enter_cache_ttl_min_override": "Zadejte minimální hodnotu TTL (v sekundách)", "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í hodnota TTL mezipaměti musí být menší nebo rovna maximální hodnotě", + "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ě.", "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é", @@ -624,9 +624,9 @@ "adg_will_drop_dns_queries": "AdGuard Home zruší všechny DNS dotazy tohoto klienta.", "filter_allowlist": "VAROVÁNÍ: Tato akce také vyloučí pravidlo \"{{disallowed_rule}}\" ze seznamu povolených klientů.", "last_rule_in_allowlist": "Nelze zakázat tohoto klienta, protože vyloučení pravidla \"{{disallowed_rule}}\" ZRUŠÍ seznam \"Povolených klientů\".", - "experimental": "Experimentální", "use_saved_key": "Použít dříve uložený klíče", "parental_control": "Rodičovská ochrana", "safe_browsing": "Bezpečné prohlížení", - "served_from_cache": "{{value}} (převzato z mezipaměti)" + "served_from_cache": "{{value}} (převzato z mezipaměti)", + "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 04d8a393..fb67607d 100644 --- a/client/src/__locales/da.json +++ b/client/src/__locales/da.json @@ -1,7 +1,7 @@ { "client_settings": "Klientindstillinger", - "example_upstream_reserved": "DNS-upstream kan agives <0>for et eller flere specifikke domæner", - "example_upstream_comment": "Du kan angive en kommentaren", + "example_upstream_reserved": "en upstream <0>for bestemte domæner;", + "example_upstream_comment": "en kommentaren.", "upstream_parallel": "Brug parallelforespørgsler til at accelerere fortolkningen ved at forespørge alle upstream-servere samtidigt.", "parallel_requests": "Parallelle forespørgsler", "load_balancing": "Belastningsfordeling", @@ -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-adresse for områdestart", - "form_error_ip4_range_end_format": "Ugyldig IPv4-adresse for områdeafslutning", - "form_error_ip4_gateway_format": "Ugyldig IPv4-adresse for gateway", - "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": "Klient-ID må kun indeholde cifre, minuskler og bindestreger", - "form_error_server_name": "Ugyldigt servernavn", - "form_error_subnet": "Subnet \"{{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 slutningen på ​​området", - "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", @@ -197,23 +197,23 @@ "enter_valid_blocklist": "Angiv en gyldig URL til sortlisten.", "enter_valid_allowlist": "Angiv en gyldig URL til hvidlisten.", "form_error_url_format": "Ugyldigt URL-format", - "form_error_url_or_path_format": "Ugyldig URL eller absolut listesti", + "form_error_url_or_path_format": "Ugyldig URL eller absolut sti til liste.", "custom_filter_rules": "Tilpassede filtreringsregler", "custom_filter_rules_hint": "Angiv én regel pr. linje. Du kan bruge enten adblockingregler eller værtsfilsyntaks.", "system_host_files": "System hosts-filer", "examples_title": "Eksempler", - "example_meaning_filter_block": "blokér adgang til example.org-domænet samt alle underdomæner", - "example_meaning_filter_whitelist": "afblokér adgang til example.ord-domænet samt alle underdomæner", - "example_meaning_host_block": "AdGuard Home returnerer nu adressen 127.0.0.1 for example.org-domænet (men ikke underdomænerne).", - "example_comment": "! Hér angives en evt. kommentar", - "example_comment_meaning": "bare en kommentar", - "example_comment_hash": "# Også en kommentar", + "example_meaning_filter_block": "blokér adgang til eksmpel.dk-domænet og alle underdomæner;", + "example_meaning_filter_whitelist": "afblokér adgang til eksempel.dk-domænet og alle underdomæner;", + "example_meaning_host_block": "besvar med 127.0.0.1 for eksempel.dk-domænet (men ikke underdomænerne);", + "example_comment": "! Hér angives en kommentar.", + "example_comment_meaning": "kun en kommentar;", + "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_dot": "krypteret <0>DNS-over-TLS", "example_upstream_doh": "krypteret <0>DNS-over-HTTPS", - "example_upstream_doq": "krypteret <0>DNS-over-QUIC", - "example_upstream_sdns": "du kan bruge <0>DNS Stamps til <1>DNSCrypt eller <2>DNS-over-HTTPS-resolvers", + "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)", "all_lists_up_to_date_toast": "Alle lister er allerede opdaterede", "updated_upstream_dns_toast": "Upstream-servere er gemt", @@ -262,7 +262,7 @@ "anonymize_client_ip_desc": "Gem ikke klientens fulde IP-adresse i logfiler og statistikker", "dns_config": "DNS-serveropsætning", "dns_cache_config": "DNS-cacheopsætning", - "dns_cache_config_desc": "Hér kan du opsætte DNS-cache", + "dns_cache_config_desc": "Hér kan DNS-cache opsættes.", "blocking_mode": "Blokeringstilstand", "default": "Standard", "nxdomain": "NXDOMAIN", @@ -275,9 +275,9 @@ "dns_over_https": "DNS-over-HTTPS", "dns_over_tls": "DNS-over-TLS", "dns_over_quic": "DNS-over-Quic", - "client_id": "Klient-ID", - "client_id_placeholder": "Angiv klient-ID", - "client_id_desc": "Forskellige klienter kan identificeres via et specielt klient-ID. Hér finder du ud af mere om, hvordan klienter identificeres.", + "client_id": "KlientID", + "client_id_placeholder": "Angiv en KlientID", + "client_id_desc": "Klienter kan identificeres via KlientID. Læs mere om, hvordan klienter identificeres hér.", "download_mobileconfig_doh": "Download .mobileconfig til DNS-over-HTTPS", "download_mobileconfig_dot": "Download .mobileconfig til DNS-over-TLS", "download_mobileconfig": "Download opsætningsfil", @@ -334,11 +334,11 @@ "install_devices_router_list_4": "På visse routertyper kan en tilpasset DNS-server ikke opsættes. I så tilfælde kan det hjælpe, hvis du opsætter AdGuard Home som en <0>DHCP-server. Ellers bør du tjekke i routermanualen, hvordan du tilpasser DNS-servere i din givne routermodel.", "install_devices_windows_list_1": "Åbn Kontrolpanel via menuen Start eller Windows-søgning.", "install_devices_windows_list_2": "Gå til kategorien Netværk og Internet og derefter til Netværks- og delingscenter.", - "install_devices_windows_list_3": "Find punktet \"Skift adapterindstillinger\" til venstre på skærmen, klik på det.", - "install_devices_windows_list_4": "Vælg din aktive forbindelse, højreklik på den og vælg Egenskaber.", + "install_devices_windows_list_3": "Find og klik på \"Skift adapterindstillinger\" i venstre panel.", + "install_devices_windows_list_4": "Højreklik på den aktive forbindelse, og vælg Egenskaber.", "install_devices_windows_list_5": "Find \"Internet Protocol Version 4 (TCP/IPv4)\" (eller for IPv6, \"Internet Protocol Version 6 (TCP/IPv6)\") på listen, vælg den og klik derefter på Egenskaber igen.", "install_devices_windows_list_6": "Vælg \"Brug følgende DNS-serveradresser og angiv dine AdGuard Home-serveradresser.", - "install_devices_macos_list_1": "Klik på Apple-ikonet og gå til Systemindstillinger.", + "install_devices_macos_list_1": "Klik på Apple-ikonet og gå til Systempræferencer.", "install_devices_macos_list_2": "Klik på Netværk.", "install_devices_macos_list_3": "Vælg den første forbindelse på din liste, og klik på Avanceret.", "install_devices_macos_list_4": "Vælg fanen DNS og angiv dine AdGuard Home-serveradresser.", @@ -356,7 +356,7 @@ "open_dashboard": "Åbn Dashboard", "install_saved": "Gemt", "encryption_title": "Kryptering", - "encryption_desc": "Kryptering (HTTPS/TLS) understøtter 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", @@ -367,7 +367,7 @@ "encryption_https_desc": "Er HTTPS-porten opsat, vil AdGuard Home admin grænsefladen være tilgængelig via HTTPS, og den vil muliggøre DNS-over-HTTPS på '/dns-query' placeringen.", "encryption_dot": "DNS-over-TLS port", "encryption_dot_desc": "Er denne port opsat, vil AdGuard Home køre en DNS-over-TLS server på denne port.", - "encryption_doq": "DNS-over-QUIC port", + "encryption_doq": "DNS-over-QUIC port (eksperimentel)", "encryption_doq_desc": "Er denne port opsat, vil AdGuard Home køre en DNS-over-QUIC server på denne port. Den er eksperimentel og er måske ikke pålidelig. Derudover understøttes den pt. heller ikke af ret mange klienter.", "encryption_certificates": "Certifikater", "encryption_certificates_desc": "For at kunne bruge kryptering skal du angive en gyldig SSL-certifikatkæde til dit domæne. Du kan få et gratis certifikat via <0>{{link}}, eller du kan købe det via en af de betroede Certifikatmyndigheder.", @@ -390,14 +390,14 @@ "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_equal": "Må ikke være ens", - "form_error_password": "Adgangskoden matcher ikke", + "form_error_equal": "Må ikke svare til.", + "form_error_password": "Adgangskoder matcher ikke.", "reset_settings": "Nulstil indstillinger", "update_announcement": "AdGuard Home {{version}} er nu tilgængelig! <0>Kik hér for mere info.", "setup_guide": "Installationsvejledning", "dns_addresses": "DNS-adresser", "dns_start": "DNS-server starter", - "dns_status_error": "Fejl ved tjek af DNS-serverstatus", + "dns_status_error": "Fejl under tjek af DNS-serverstatus.", "down": "Ned", "fix": "Korrigér", "dns_providers": "Her er en <0>liste over kendte DNS-udbydere at vælge imellem.", @@ -405,8 +405,8 @@ "update_failed": "Autoopdatering mislykkedes. Følg disse trin for at opdatere manuelt.", "manual_update": "Følg disse trin for at opdatere manuelt.", "processing_update": "Vent venligst, AdGuard Home bliver opdateret", - "clients_title": "Klienter", - "clients_desc": "Opsæt enheder forbundet til AdGuard Home", + "clients_title": "Blivende klienter", + "clients_desc": "Opsæt blivende klientposter for enheder tilsluttet AdGuard Home.", "settings_global": "Global", "settings_custom": "Tilpasset", "table_client": "Klient", @@ -417,7 +417,7 @@ "client_edit": "Redigér Klient", "client_identifier": "Identifikator", "ip_address": "IP-adresse", - "client_identifier_desc": "Klienter kan identificeres ud fra IP-/MAC-adresser, CIDR eller et særligt klient-ID (kan bruges til DoT/DoH/DoQ). <0>Hér kan du læse mere om, hvordan klienter identificeres.", + "client_identifier_desc": "Klienter kan identificeres ud fra IP-/MAC-adresser, CIDR eller et særligt KlientID (kan bruges til DoT/DoH/DoQ). Læs mere om, hvordan klienter identificeres <0>hér.", "form_enter_ip": "Angiv IP", "form_enter_subnet_ip": "Indtast en IP-adresse i subnettet \"{{cidr}}\"", "form_enter_mac": "Angiv MAC", @@ -433,13 +433,13 @@ "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": "Data om de klienter, som bruger AdGuard Home, men ikke gemt i opsætningen", + "auto_clients_desc": "Enheder, som ikke er på listen over Blivende klienter, som stadig kan bruge AdGuard Home.", "access_title": "Adgangsindstillinger", "access_desc": "Her kan du opsætte adgangsregler for AdGuard Home DNS-serveren.", "access_allowed_title": "Tilladte klienter", - "access_allowed_desc": "En liste over CIDR-, IP-adresser eller klient-ID'er. Hvis opsat, accepterer AdGuard Home kun forespørgsler fra disse 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", - "access_disallowed_desc": "En liste over CIDR-, IP-adresser eller klient-ID'er. Hvis opsat, dropper AdGuard Home forespørgsler fra disse klienter. Opsættes tilladte klienter, ignoreres dette felt.", + "access_disallowed_desc": "En liste over CIDR'er, IP-adresser eller KlientID'er. Har listen poster, dropper AdGuard Home forespørgsler fra disse klienter. Har Tilladte klienter poster, ignoreres dette felt.", "access_blocked_title": "Ikke tilladte domæner", "access_blocked_desc": "Ikke at forveksle med filtre. AdGuard Home dropper DNS-forespørgsler matchende disse domæner, ej heller vil forespørgslerne optræde i forespørgselsloggen. Der kan angives præcise domænenavne, jokertegn eller URL-filterregler, f.eks. \"eksempel.org\", \"*.eksempel.org\", \"||eksempel.org^\" eller tilsvarende.", "access_settings_saved": "Adgangsindstillinger gemt", @@ -532,7 +532,7 @@ "netname": "Netværksnavn", "network": "Netværk", "descr": "Beskrivelse", - "whois": "Whois", + "whois": "WHOIS", "filtering_rules_learn_more": "<0>Læs mere om at oprette dine egne værtslister.", "blocked_by_response": "Blokeret af CNAME eller IP i svar", "blocked_by_cname_or_ip": "Blokeret af CNAME eller IP", @@ -552,10 +552,10 @@ "autofix_warning_list": "Den vil udføre disse opgaver: <0>Deaktivere system DNSStubListener <0>Opsætte DNS-serveradressen til 127.0.0.1 <0>Erstatte symbolsk linkmål for /etc/resolv.conf med /run/systemd/resolve/resolv.conf <0>Stoppe DNSStubListener (genindlæs systemd-opløst tjeneste)", "autofix_warning_result": "Det betyder, at alle DNS-forespørgsler fra dit system som standard behandles af AdGuard Home.", "tags_title": "Tags", - "tags_desc": "Du kan vælge de tags, som svarer til klienten. Tags kan inkluderes i filtreringsreglerne, hvilket lader anvende dem mere præcist. <0>Læs mere", + "tags_desc": "Der kan vælges tags, som svarer til klienten. Medtag tags i filtreringsregler for at anvende dem mere præcist. <0>Læs mere.", "form_select_tags": "Vælg klient tags", "check_title": "Tjek filtreringen", - "check_desc": "Tjek, om værtsnavnet er filtreret", + "check_desc": "Tjek, om værtsnavnet filtreres.", "check": "Tjek", "form_enter_host": "Angiv et værtsnavn", "filtered_custom_rules": "Filtreret af tilpassede filtreringsregler", @@ -598,14 +598,14 @@ "blocklist": "Sortliste", "milliseconds_abbreviation": "ms", "cache_size": "Cache-størrelse", - "cache_size_desc": "DNS-cache størrelse (i bytes)", + "cache_size_desc": "DNS cache-størrelse (i bytes).", "cache_ttl_min_override": "Tilsidesæt minimum TTL", "cache_ttl_max_override": "Tilsidesæt maksimal TTL", "enter_cache_size": "Angiv cache-størrelse (bytes)", "enter_cache_ttl_min_override": "Angiv minimum TTL (sekunder)", "enter_cache_ttl_max_override": "Angiv maksimum TTL (sekunder)", "cache_ttl_min_override_desc": "Forlæng korte time-to-live værdier (sekunder) modtaget fra upstream-serveren, når DNS-svar cachelagres", - "cache_ttl_max_override_desc": "Indstil en maksimal time-to-live (sekunder) for registreringer i DNS-cachen", + "cache_ttl_max_override_desc": "Angiv en maksimal time-to-live (sekunder) for poster i DNS-cachen.", "ttl_cache_validation": "Minimum cache TTL-værdi skal være mindre end eller lig med den maksimale værdi", "cache_optimistic": "Optimistisk caching", "cache_optimistic_desc": "Får AdGuard Home til at svare fra cachen, selv når posterne er udløbet, og prøver også at opdatere dem.", @@ -624,9 +624,9 @@ "adg_will_drop_dns_queries": "AdGuard Home vil afbryde alle DNS-forespørgsler fra denne klient.", "filter_allowlist": "ADVARSEL: Denne handling udelukker også reglen \"{{disallowed_rule}}\" fra listen over tilladte klienter.", "last_rule_in_allowlist": "Kan ikke afvise denne klient, da udelukkelse af reglen \"{{disallowed_rule}}\" DEAKTIVERER listen \"Tilladte klienter\".", - "experimental": "Eksperimentel", "use_saved_key": "Brug den tidligere gemte nøgle", "parental_control": "Forældrekontrol", "safe_browsing": "Sikker Browsing", - "served_from_cache": "{{value}} (leveret fra cache)" + "served_from_cache": "{{value}} (leveret fra cache)", + "form_error_password_length": "Adgangskoden skal udgøre mindst {{value}} tegn." } diff --git a/client/src/__locales/de.json b/client/src/__locales/de.json index 4fb4cd02..fc9f5878 100644 --- a/client/src/__locales/de.json +++ b/client/src/__locales/de.json @@ -1,7 +1,7 @@ { "client_settings": "Client-Einstellungen", - "example_upstream_reserved": "Sie können DNS-Upstream <0>für bestimmte Domain(s) angeben", - "example_upstream_comment": "Sie können den Kommentar angeben", + "example_upstream_reserved": "ein Upstream <0>für bestimmte Domains;", + "example_upstream_comment": "ein Kommentar.", "upstream_parallel": "Parallele Abfragen verwenden, um das Auflösen zu beschleunigen, indem alle Upstream-Server gleichzeitig abgefragt werden.", "parallel_requests": "Paralleles Abfragen", "load_balancing": "Lastverteilung", @@ -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ültiger Bereichsbeginn der IPv4-Adresse", - "form_error_ip4_range_end_format": "Ungültiges Bereichsende der IPv4-Adresse", - "form_error_ip4_gateway_format": "Ungültiges Gateway-IPv4-Adresse", - "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 (Null) 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ü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.", "dhcp_form_gateway_input": "Gateway-IP", "dhcp_form_subnet_input": "Subnetz-Maske", "dhcp_form_range_title": "Bereich von IP-Adressen", @@ -187,7 +187,7 @@ "cancel_btn": "Abbrechen", "enter_name_hint": "Name eingeben", "enter_url_or_path_hint": "URL oder absoluten Pfad der Liste eingeben", - "check_updates_btn": "Nach Updates suchen", + "check_updates_btn": "Nach Aktualisierungen suchen", "new_blocklist": "Neue Sperrliste", "new_allowlist": "Neue Freigabeliste", "edit_blocklist": "Sperrliste bearbeiten", @@ -196,25 +196,25 @@ "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.", "system_host_files": "Hosts-Datei des Systems", "examples_title": "Beispiele", - "example_meaning_filter_block": "blockiert den Zugang zur Domain example.org und all ihren Subdomains", - "example_meaning_filter_whitelist": "entblockt den Zugang zur Domain example.org und all ihren Subdomains", - "example_meaning_host_block": "AdGuard Home wird jetzt die Adresse 127.0.0.1 für die Domain example.org zurückgeben (aber nicht für die Subdomains).", - "example_comment": "! Hier steht ein Kommentar", - "example_comment_meaning": "Nur ein Kommentar", - "example_comment_hash": "# Auch ein Kommentar", - "example_regex_meaning": "Zugriff auf die Domains sperren, die dem <0>angegebenen regulären Ausdruck entsprechen", - "example_upstream_regular": "regulärer DNS (über UDP)", - "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", - "example_upstream_sdns": "Sie können <0>DNS-Stempel für <1>DNSCrypt oder <2>DNS-over-HTTPS Resolver benutzen", - "example_upstream_tcp": "regulärer DNS (über TCP)", + "example_meaning_filter_block": "Zugriff auf die Domain example.org und alle ihre Subdomains sperren;", + "example_meaning_filter_whitelist": "Zugriff auf die Domain example.org und alle ihre Subdomains entsperren;", + "example_meaning_host_block": "Adresse 127.0.0.1 für die Domain example.org zurückgeben (aber nicht für ihre Subdomains);", + "example_comment": "! Hier steht ein Kommentar.", + "example_comment_meaning": "nur ein Kommentar;", + "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_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);", "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 +259,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-Zwischenspeicher", - "dns_cache_config_desc": "Hier können Sie den DNS-Zwischenspeicher konfigurieren", + "dns_cache_config": "Konfiguration des DNS-Cache", + "dns_cache_config_desc": "Hier können Sie den DNS-Cache konfigurieren.", "blocking_mode": "Sperrmodus", "default": "Standard", "nxdomain": "NXDomain", @@ -309,7 +309,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": "Gültige Portnummer eingeben", + "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", @@ -334,12 +334,12 @@ "install_devices_router_list_4": "Bei einigen Routertypen kann kein eigener DNS-Server eingerichtet werden. In diesem Fall kann es helfen, AdGuard Home als <0>DHCP-Server einzurichten. Andernfalls sollten Sie im Handbuch des Routers nachsehen, wie Sie DNS-Server auf Ihrem konkreten Router-Modell anpassen können.", "install_devices_windows_list_1": "Öffnen Sie die Systemsteuerung über das Startmenü oder die Windows-Suche.", "install_devices_windows_list_2": "Öffnen Sie die Kategorie „Netzwerk und Internet“ und dann „Netzwerk- und Freigabecenter“.", - "install_devices_windows_list_3": "Suchen Sie auf der linken Seite des Bildschirms nach „Adaptereinstellungen ändern“ und klicken Sie darauf.", - "install_devices_windows_list_4": "Wählen Sie Ihre aktive Verbindung aus, klicken Sie mit der rechten Maustaste darauf und wählen Sie „Eigenschaften“.", + "install_devices_windows_list_3": "Klicken Sie in der linken Leiste auf „Adaptereinstellungen ändern“.", + "install_devices_windows_list_4": "Klicken Sie mit der rechten Maustaste auf Ihre aktive Verbindung und wählen Sie „Eigenschaften“.", "install_devices_windows_list_5": "Suchen Sie in der Liste nach „Internet Protokoll Version 4 (TCP/IP)“ (oder, für IPv6, „Internet Protocol Version 6 (TCP/IPv6)“), markieren Sie diese und klicken Sie dann erneut auf „Eigenschaften“.", "install_devices_windows_list_6": "Wählen Sie „Folgende DNS-Serveradressen verwenden“ und geben Sie Ihre AdGuard Home-Serveradressen ein.", - "install_devices_macos_list_1": "Klicken Sie auf das Apple-Symbol (oben links in der Menüzeile) und wählen den Eintrag „Systemeinstellungen“.", - "install_devices_macos_list_2": "Klicken Sie dort auf „Netzwerk“", + "install_devices_macos_list_1": "Klicken Sie auf das Apple-Symbol und gehen Sie zu Systemeinstellungen.", + "install_devices_macos_list_2": "Klicken Sie auf „Netzwerk“.", "install_devices_macos_list_3": "Wählen Sie die erste Verbindung in Ihrer Liste aus und klicken Sie auf „Weitere Optionen“.", "install_devices_macos_list_4": "Wählen Sie den Tab „DNS“ und geben Sie dort Ihre AdGuard Home-Serveradressen ein.", "install_devices_android_list_1": "Tippen Sie auf dem Startbildschirm des Android-Menüs auf „Einstellungen“.", @@ -356,7 +356,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": "Verschlüsselungsunterstützung (HTTPS/TLS) für DNS- und Admin-Weboberfläche.", "encryption_config_saved": "Verschlüsselungskonfiguration gespeichert", "encryption_server": "Servername", "encryption_server_enter": "Domain-Namen eingeben", @@ -367,7 +367,7 @@ "encryption_https_desc": "Wenn der HTTPS-Port konfiguriert ist, ist die AdGuard Home-Administrationsschnittstelle über HTTPS zugänglich und bietet auch DNS-over-HTTPS am Server „/dns-query“.", "encryption_dot": "DNS-over-TLS", "encryption_dot_desc": "Wenn dieser Port konfiguriert ist, führt AdGuard Home auf diesem Port einen DNS-over-TLS-Server aus.", - "encryption_doq": "Port für DNS-over-QUIC", + "encryption_doq": "Port für DNS-over-QUIC (experimentell)", "encryption_doq_desc": "Wenn dieser Port eingerichtet ist, wird AdGuard Home einen DNS-over-QUIC-Server auf diesem Port ausführen. Es ist experimentell und möglicherweise nicht zuverlässig. Außerdem gibt es im Moment nicht allzu viele Clients, die ihn unterstützen.", "encryption_certificates": "Zertifikate", "encryption_certificates_desc": "Um die Verschlüsselung verwenden zu können, müssen Sie eine gültige SSL-Zertifikatskette für Ihre Domain angeben. Sie können ein kostenloses Zertifikat für <0>{{link}} erhalten oder es bei einer der vertrauenswürdigen Zertifizierungsstellen kaufen.", @@ -378,26 +378,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": "Das ist ein gültiger {{type}} privater Schlüssel", - "encryption_key_invalid": "Das 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": "Dies ist ein gültiger {{type}} privater Schlüssel.", + "encryption_key_invalid": "Dies 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": "Port zwischen 80 und 65535 eingeben", - "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": "Dies ist ein 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.", @@ -405,8 +405,8 @@ "update_failed": "Das automatische Aktualisieren ist fehlgeschlagen. Bitte folgen Sie den Schritten, um manuell zu aktualisieren.", "manual_update": "Bitte befolgen Sie diese Schritte, um manuell zu aktualisieren.", "processing_update": "Bitte warten Sie, AdGuard Home wird aktualisiert …", - "clients_title": "Clients", - "clients_desc": "Geräte einrichten, die mit AdGuard Home verbunden sind", + "clients_title": "Persistente Clients", + "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", @@ -432,14 +432,14 @@ "clients_not_found": "Keine Clients gefunden", "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": "Clients (Laufzeit)", - "auto_clients_desc": "Daten zu den Clients, die AdGuard Home verwenden, aber nicht in der Konfiguration gespeichert sind", + "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.", "access_title": "Zugriffsrechte", "access_desc": "Hier können Sie die Zugriffsregeln für den AdGuard Home DNS-Server konfigurieren.", "access_allowed_title": "Zugelassene Clients", - "access_allowed_desc": "Eine Liste von CIDRs, IP-Adressen oder Client-IDs. Wenn konfiguriert, akzeptiert AdGuard Home Anfragen von diesen 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", - "access_disallowed_desc": "Eine Liste von CIDRs, IP-Adressen oder Client-IDs. Wenn konfiguriert, löscht AdGuard Home Anfragen von diesen Clients. Wenn erlaubte Clients konfiguriert sind, wird dieses Feld ignoriert.", + "access_disallowed_desc": "Eine Liste von CIDRs, IP-Adressen oder ClientIDs. Wenn diese Liste gefüllt ist, weist AdGuard Home Anfragen von diesen Clients zurück. Dieses Feld wird ignoriert, wenn es Einträge in der Liste „Zugelassene Clients“ gibt.", "access_blocked_title": "Nicht zugelassene Domains", "access_blocked_desc": "Verwechseln Sie dies nicht mit Filtern. AdGuard Home verwirft DNS-Abfragen, die mit diesen Domänen übereinstimmen, und diese Abfragen erscheinen nicht einmal im Abfrageprotokoll. Hier können Sie die genauen Domain-Namen, Wildcards und URL-Filter-Regeln angeben, z.B. 'beispiel.org', '*.beispiel.org' oder '||beispiel.org^'.", "access_settings_saved": "Zugriffseinstellungen erfolgreich gespeichert", @@ -475,8 +475,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", @@ -507,7 +507,7 @@ "filter_updated": "Der Filter wurde erfolgreich aktualisiert", "statistics_configuration": "Statistikkonfiguration", "statistics_retention": "Statistiken speichern", - "statistics_retention_desc": "Wenn Sie den Zeitraum verringern, werden einige Daten verloren gehen", + "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.", @@ -552,10 +552,10 @@ "autofix_warning_list": "Es werden folgende Aufgaben ausgeführt: <0>Deaktivieren des DNSStubListener-Systems <0>Festlegen der DNS-Server-Adresse auf 127.0.0.1 <0>Ersetzen des symbolischen Linkziels von /etc/resolv.conf auf /run/systemd/resolve/resolv.conf <0>Anhalten des DNSStubListener (systemseitig aufgelöster Dienst wird nachladen)", "autofix_warning_result": "Als Folge daraus werden alle DNS-Anforderungen von Ihrem System standardmäßig von AdGuardHome verarbeitet.", "tags_title": "Schlagwörter", - "tags_desc": "Sie können die Schlagwörter auswählen, die dem Client entsprechen. Die Schlagwörter können in die Filterregeln aufgenommen werden und erlauben Ihnen, sie genauer anzuwenden. <0>Mehr erfahren", + "tags_desc": "Sie können die Schlagwörter auswählen, die dem Client entsprechen. Die Schlagwörter können in die Filterregeln aufgenommen werden und erlauben Ihnen, sie genauer anzuwenden. <0>Mehr erfahren.", "form_select_tags": "Schlagwörter des Clients auswählen", "check_title": "Filterung überprüfen", - "check_desc": "Prüfen, ob der Hostname gefiltert wird", + "check_desc": "Prüfen, ob der Hostname gefiltert wird.", "check": "Prüfen", "form_enter_host": "Gerätenamen eingeben", "filtered_custom_rules": "Nach benutzerdefinierten Filterregeln gefiltert", @@ -597,18 +597,18 @@ "safe_search": "Sichere Suche", "blocklist": "Sperrliste", "milliseconds_abbreviation": "ms", - "cache_size": "Größe des Zwischenspeichers", - "cache_size_desc": "Größe des DNS-Zwischenspeichers (in Bytes)", + "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)", - "enter_cache_size": "Größe des Zwischenspeichers eingeben", + "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", - "cache_ttl_min_override_desc": "Überschreibt den TTL-Minimalwert, der vom vorgeschalteten Server empfangen wurde. Dieser Wert darf nicht mehr als 3600 (Sek.) (≙ 1 Stunde) betragen.", - "cache_ttl_max_override_desc": "Überschreibt den TLL-Maximalwert, der vom vorgeschalteten Server empfangen wurde.", - "ttl_cache_validation": "Der minimale Cache des TTL-Wertes muss kleiner oder gleich dem maximalen Wert sein", - "cache_optimistic": "Optimistisches Zwischenspeichern", - "cache_optimistic_desc": "Sorgt dafür, dass AdGuard Home auch dann aus dem Zwischenspeicher antwortet, wenn die Einträge abgelaufen sind, und versucht zudem, diese zu aktualisieren.", + "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.", + "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", "filter_category_security": "Sicherheit", "filter_category_regional": "Regional", @@ -624,9 +624,9 @@ "adg_will_drop_dns_queries": "AdGuard Home wird alle DNS-Abfragen von diesem Client verwerfen.", "filter_allowlist": "Warnhinweis: Durch diese Aktion wird außerdem die Regel „{{disallowed_rule}}“ aus der Liste der zugelassenen Clients ausgeschlossen.", "last_rule_in_allowlist": "Dieser Client kann nicht gesperrt werden, da das Ausschließen der Regel „{{disallowed_rule}}“ die Liste „Zugelassene Clients“ deaktivieren würde.", - "experimental": "Experimentell", "use_saved_key": "Zuvor gespeicherten Schlüssel verwenden", "parental_control": "Kindersicherung", "safe_browsing": "Internetsicherheit", - "served_from_cache": "{{value}} (aus dem Zwischenspeicher abgerufen)" + "served_from_cache": "{{value}} (aus dem Cache abgerufen)", + "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 753330ac..76eedb0f 100644 --- a/client/src/__locales/es.json +++ b/client/src/__locales/es.json @@ -1,7 +1,7 @@ { "client_settings": "Configuración de clientes", - "example_upstream_reserved": "puedes especificar el DNS de subida <0>para un dominio específico", - "example_upstream_comment": "puedes especificar el comentario", + "example_upstream_reserved": "un DNS de subida <0>para un dominio específico.", + "example_upstream_comment": "un comentario.", "upstream_parallel": "Usar consultas paralelas para acelerar la resolución al consultar simultáneamente a todos los servidores DNS de subida.", "parallel_requests": "Consultas paralelas", "load_balancing": "Balanceo de carga", @@ -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", @@ -196,25 +196,25 @@ "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", "examples_title": "Ejemplos", - "example_meaning_filter_block": "bloquea el acceso al dominio ejemplo.org y a todos sus subdominios", - "example_meaning_filter_whitelist": "desbloquea el acceso al dominio ejemplo.org y a todos sus subdominios", - "example_meaning_host_block": "AdGuard Home devolverá la dirección 127.0.0.1 para el dominio ejemplo.org (pero no para sus subdominios).", - "example_comment": "! Aquí va un comentario", - "example_comment_meaning": "solo un comentario", - "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_dot": "cifrado <0>DNS mediante TLS", - "example_upstream_doh": "cifrado <0>DNS mediante HTTPS", - "example_upstream_doq": "cifrado <0>DNS mediante QUIC", - "example_upstream_sdns": "puedes usar <0>DNS Stamps para <1>DNSCrypt o resolutores <2>DNS mediante HTTPS", - "example_upstream_tcp": "DNS regular (mediante TCP)", + "example_meaning_filter_block": "bloquea el acceso al dominio ejemplo.org y a todos sus subdominios.", + "example_meaning_filter_whitelist": "desbloquea el acceso al dominio ejemplo.org y a todos sus subdominios.", + "example_meaning_host_block": "responde con 127.0.0.1 para ejemplo.org (pero no para sus subdominios).", + "example_comment": "! Aquí va un comentario.", + "example_comment_meaning": "solo un comentario.", + "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_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).", "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 +259,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 y 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", @@ -277,7 +277,7 @@ "dns_over_quic": "DNS mediante QUIC", "client_id": "ID de cliente", "client_id_placeholder": "Ingresa el ID del cliente", - "client_id_desc": "Diferentes clientes pueden ser identificados por un ID de cliente especial. Aquí puedes obtener más información sobre cómo identificar clientes.", + "client_id_desc": "Los clientes pueden ser identificados por un ID de cliente. Obtén más información sobre cómo identificar clientes aquí.", "download_mobileconfig_doh": "Descargar .mobileconfig para DNS mediante HTTPS", "download_mobileconfig_dot": "Descargar .mobileconfig para DNS mediante TLS", "download_mobileconfig": "Descargar archivo de configuración", @@ -309,7 +309,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", @@ -334,8 +334,8 @@ "install_devices_router_list_4": "En algunos tipos de router, no se puede configurar un servidor DNS personalizado. En ese caso, configurar AdGuard Home como <0>servidor DHCP puede ayudar. De lo contrario, debes consultar el manual del router para saber cómo personalizar los servidores DNS en tu modelo de router específico.", "install_devices_windows_list_1": "Abre el Panel de control a través del menú Inicio o en el buscador de Windows.", "install_devices_windows_list_2": "Ve a la categoría Redes e Internet, luego a Centro de redes y recursos compartidos.", - "install_devices_windows_list_3": "En el lado izquierdo de la pantalla, busca \"Cambiar configuración del adaptador\" y luego haz clic en él.", - "install_devices_windows_list_4": "Selecciona tu conexión activa, haz clic derecho sobre ella y elige Propiedades.", + "install_devices_windows_list_3": "En el panel izquierdo, haz clic en \"Cambiar configuración del adaptador\".", + "install_devices_windows_list_4": "Haz clic derecho en tu conexión activa y selecciona Propiedades.", "install_devices_windows_list_5": "Busca en la lista el \"Protocolo de Internet versión 4 (TCP/IPv4)\" (o \"Protocolo de Internet versión 6 (TCP/IPv6)\"), selecciónalo y vuelve a hacer clic en Propiedades.", "install_devices_windows_list_6": "Elige \"Usar las siguientes direcciones de servidor DNS\" e ingresa las direcciones de tu servidor AdGuard Home.", "install_devices_macos_list_1": "Haz clic en el icono de Apple y ve a Preferencias del sistema.", @@ -356,7 +356,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/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", @@ -367,7 +367,7 @@ "encryption_https_desc": "Si el puerto HTTPS está configurado, la interfaz de administración de AdGuard Home será accesible a través de HTTPS, y también proporcionará DNS mediante HTTPS en la ubicación '/dns-query'.", "encryption_dot": "Puerto DNS mediante TLS", "encryption_dot_desc": "Si este puerto está configurado, AdGuard Home ejecutará un servidor DNS mediante TLS en este puerto.", - "encryption_doq": "Puerto DNS mediante QUIC", + "encryption_doq": "Puerto DNS mediante QUIC (experimental)", "encryption_doq_desc": "Si este puerto está configurado, AdGuard Home ejecutará un servidor DNS mediante QUIC en este puerto. Es experimental y puede no ser confiable. Además, no hay muchos clientes que lo soporten por el momento.", "encryption_certificates": "Certificados", "encryption_certificates_desc": "Para utilizar el cifrado, debes proporcionar una cadena de certificado SSL válida para tu dominio. Puedes obtener un certificado gratuito en <0>{{link}} o puedes comprarlo en una de las autoridades de certificación de confianza.", @@ -378,26 +378,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": "Este es un 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.", @@ -405,8 +405,8 @@ "update_failed": "Error en la actualización automática. Por favor sigue estos pasos para actualizar manualmente.", "manual_update": "Por favor sigue estos pasos para actualizar manualmente.", "processing_update": "Por favor espera, AdGuard Home se está actualizando", - "clients_title": "Clientes", - "clients_desc": "Configurar dispositivos conectados con AdGuard Home", + "clients_title": "Clientes persistentes", + "clients_desc": "Configurar registros de clientes persistentes para dispositivos conectados a AdGuard Home.", "settings_global": "Global", "settings_custom": "Personalizado", "table_client": "Cliente", @@ -417,7 +417,7 @@ "client_edit": "Editar cliente", "client_identifier": "Identificador", "ip_address": "Dirección IP", - "client_identifier_desc": "Los clientes pueden ser identificados por la dirección IP, MAC, CIDR o un ID de cliente especial (puede ser utilizado para DoT/DoH/DoQ). <0>Aquí puedes obtener más información sobre cómo identificar clientes.", + "client_identifier_desc": "Los clientes pueden ser identificados por su dirección IP, MAC, CIDR o un ID de cliente (puede ser utilizado para DoT/DoH/DoQ). Obtén más información sobre cómo identificar clientes <0>aquí.", "form_enter_ip": "Ingresa la IP", "form_enter_subnet_ip": "Ingresa una dirección IP en la subred \"{{cidr}}\"", "form_enter_mac": "Ingresa la MAC", @@ -432,14 +432,14 @@ "clients_not_found": "No se han encontrado clientes", "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": "Datos de los clientes que utilizan AdGuard Home, pero no se almacenan en la configuración", + "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.", "access_title": "Configuración de acceso", "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 está configurado, AdGuard Home aceptará peticiones solo de estos clientes.", + "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", - "access_disallowed_desc": "Lista de CIDR, direcciones IP o ID de clientes. Si está configurado, AdGuard Home descartará las peticiones de estos clientes. Si se configuran clientes permitidos, este campo será ignorado.", + "access_disallowed_desc": "Lista de CIDR, direcciones IP o ID de clientes. Si esta lista tiene entradas, AdGuard Home descartará las peticiones de estos clientes. Este campo será ignorado si hay entradas en clientes permitidos.", "access_blocked_title": "Dominios no permitidos", "access_blocked_desc": "No debe confundirse con filtros. AdGuard Home descartará las consultas DNS que coincidan con estos dominios, y estas consultas ni siquiera aparecerán en el registro de consultas. Puedes especificar nombres de dominio exactos, comodines o reglas de filtrado de URL, por ejemplo: \"ejemplo.org\", \"*.ejemplo.org\" o \"||ejemplo.org^\" correspondientemente.", "access_settings_saved": "Configuración de acceso guardado correctamente", @@ -475,8 +475,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", @@ -507,7 +507,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", @@ -532,7 +532,7 @@ "netname": "Nombre de la red", "network": "Red", "descr": "Descripción", - "whois": "Whois", + "whois": "WHOIS", "filtering_rules_learn_more": "<0>Más información sobre cómo crear tus propias listas de hosts.", "blocked_by_response": "Bloqueado por CNAME o IP en respuesta", "blocked_by_cname_or_ip": "Bloqueado por CNAME o IP", @@ -552,10 +552,10 @@ "autofix_warning_list": "Realizará estas tareas: <0>Deshabilitar el sistema DNSStubListener <0>Establecer la dirección del servidor DNS en 127.0.0.1 <0>Reemplazar el destino del enlace simbólico de /etc/resolv.conf por /run/systemd/resolve/resolv.conf <0>Detener DNSStubListener (recargar el servicio systemd-resolved)", "autofix_warning_result": "Como resultado, todas las peticiones DNS de tu sistema serán procesadas por AdGuard Home de manera predeterminada.", "tags_title": "Etiquetas", - "tags_desc": "Puedes seleccionar las etiquetas que correspondan al cliente. Las etiquetas pueden ser incluidas en las reglas de filtrado y te permiten aplicarlas con mayor precisión. <0>Más información", + "tags_desc": "Puedes seleccionar las etiquetas que correspondan al cliente. Incluye etiquetas en las reglas de filtrado para aplicarlas con mayor precisión. <0>Más información.", "form_select_tags": "Seleccione las etiquetas del cliente", "check_title": "Comprobar filtrado", - "check_desc": "Comprueba si el nombre del host está siendo filtrado", + "check_desc": "Comprueba si un nombre del host está siendo filtrado.", "check": "Comprobar", "form_enter_host": "Ingresa un nombre de host", "filtered_custom_rules": "Filtrado por reglas de filtrado personalizado", @@ -598,15 +598,15 @@ "blocklist": "Lista de bloqueo", "milliseconds_abbreviation": "ms", "cache_size": "Tamaño de la caché", - "cache_size_desc": "Tamaño de la caché DNS (en bytes)", + "cache_size_desc": "Tamaño de la caché DNS (en bytes).", "cache_ttl_min_override": "Anular TTL mínimo", "cache_ttl_max_override": "Anular TTL máximo", "enter_cache_size": "Ingresa el tamaño de la caché (bytes)", "enter_cache_ttl_min_override": "Ingresa el TTL mínimo (en segundos)", "enter_cache_ttl_max_override": "Ingresa el TTL máximo (en segundos)", - "cache_ttl_min_override_desc": "Amplia el corto tiempo de vida 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 máximo para las entradas en la caché DNS", - "ttl_cache_validation": "El valor TTL mínimo de la caché debe ser menor o igual al valor máximo", + "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.", "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", @@ -624,9 +624,9 @@ "adg_will_drop_dns_queries": "AdGuard Home descartará todas las consultas DNS de este cliente.", "filter_allowlist": "ADVERTENCIA: Esta acción también excluirá la regla \"{{disallowed_rule}}\" de la lista de clientes permitidos.", "last_rule_in_allowlist": "No se puede desautorizar a este cliente porque al excluir la regla \"{{disallowed_rule}}\" DESHABILITARÁ la lista de \"Clientes permitidos\".", - "experimental": "experimental", "use_saved_key": "Usar la clave guardada previamente", "parental_control": "Control parental", "safe_browsing": "Navegación segura", - "served_from_cache": "{{value}} (servido desde la caché)" + "served_from_cache": "{{value}} (servido desde la caché)", + "form_error_password_length": "La contraseña debe tener al menos {{value}} caracteres." } diff --git a/client/src/__locales/fa.json b/client/src/__locales/fa.json index 22e78275..d465b2bf 100644 --- a/client/src/__locales/fa.json +++ b/client/src/__locales/fa.json @@ -482,7 +482,7 @@ "allowed": "اجازه داده شده", "filtered": "فیلتر شده", "rewritten": "بازنویسی شده", - "safe_search": "جستجوی اَمن", + "safe_search": "فعالسازی جستجوی اَمن", "blocklist": "لیست سیاه", "milliseconds_abbreviation": "هـ ثـ", "filter_category_general": "General", diff --git a/client/src/__locales/fi.json b/client/src/__locales/fi.json index d17d3646..899748a7 100644 --- a/client/src/__locales/fi.json +++ b/client/src/__locales/fi.json @@ -1,7 +1,7 @@ { "client_settings": "Päätelaiteasetukset", - "example_upstream_reserved": "voit määrittää DNS-ylävirran <0>tietyille verkkotunnuksille", - "example_upstream_comment": "voit määrittää kommentin", + "example_upstream_reserved": "ylävirta <0>tietyille verkkotunnuksille;", + "example_upstream_comment": "kommentti.", "upstream_parallel": "Käytä rinnakkaisia pyyntöjä ja nopeuta selvitystä käyttämällä kaikkia ylävirran palvelimia samanaikaisesti.", "parallel_requests": "Rinnakkaiset pyynnöt", "load_balancing": "Kuormantasaus", @@ -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": "Vaaditaan", - "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 tunniste 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", @@ -143,7 +143,7 @@ "use_adguard_browsing_sec_hint": "AdGuard Home tarkistaa onko verkkotunnus turvallisen selauksen verkkopalvelun estämä. Se käyttää tarkastukseen tietosuojapainotteista rajapintaa: palvelimelle lähetetään vain pieni osa verkkotunnuksen SHA256-hajautusarvosta.", "use_adguard_parental": "Käytä AdGuardin lapsilukko-palvelua", "use_adguard_parental_hint": "AdGuard Home tarkistaa, sisältääkö verkkotunnus aikuisille tarkoitettua sisältöä. Se käyttää samaa tietosuojapainotteista rajapintaa, kuin turvallisen selauksen palvelu.", - "enforce_safe_search": "Pakota turvallinen haku", + "enforce_safe_search": "Käytä turvallista hakua", "enforce_save_search_hint": "AdGuard Home voi pakottaa turvallisen haun käyttöön seuraavissa hakukoneissa: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.", "no_servers_specified": "Palvelimia ei ole määritetty", "general_settings": "Yleiset asetukset", @@ -196,25 +196,25 @@ "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", "examples_title": "Esimerkkejä", - "example_meaning_filter_block": "estä pääsy verkkotunnukseen example.org ja sen aliverkkotunnuksiin", - "example_meaning_filter_whitelist": "salli pääsy verkkotunnukseen example.org ja sen aliverkkotunnuksiin", - "example_meaning_host_block": "AdGuard Home palauttaa verkkotunnukselle example.org osoitteen 127.0.0.1 (muttei sen aliverkkotunnuksille)", - "example_comment": "! Tähän tulee kommentti", - "example_comment_meaning": "voit määrittää kommentin", - "example_comment_hash": "# Myös tämä on kommentti", - "example_regex_meaning": "estä pääsy säännöllistä lauseketta vastaaviin verkkotunnuksiin", - "example_upstream_regular": "tavallinen DNS (UDP)", - "example_upstream_dot": "salattu <0>DNS-over-TLS", - "example_upstream_doh": "salattu <0>DNS-over-HTTPS", - "example_upstream_doq": "salattu <0>DNS-over-QUIC", - "example_upstream_sdns": "voit käyttää <0>DNS Stamp -merkintöjä <1>DNSCrypt tai <2>DNS-over-HTTPS -resolvereille", - "example_upstream_tcp": "tavallinen DNS (TCP)", + "example_meaning_filter_block": "estä pääsy verkkotunnukseen example.org sekä kaikkiin sen aliverkkotunnuksiin;", + "example_meaning_filter_whitelist": "salli pääsy verkkotunnukseen example.org sekä kaikkiin sen aliverkkotunnuksiin;", + "example_meaning_host_block": "vastaa verkkotunnukselle example.org IP-osoitteella 127.0.0.1 (muttei sen aliverkkotunnuksille);", + "example_comment": "! Tähän tulee kommentti.", + "example_comment_meaning": "vain kommentti;", + "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_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ä);", "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", @@ -259,10 +259,10 @@ "query_log_strict_search": "Käytä tarkalle haulle lainausmerkkejä", "query_log_retention_confirm": "Haluatko varmasti muuttaa pyyntöhistoriasi säilytysaikaa? Jos lyhennät aikaa, joitakin tietoja menetetään", "anonymize_client_ip": "Piilota päätelaitteen IP-osoite", - "anonymize_client_ip_desc": "Älä tallenna päätelaitteen täydellistä IP-osoitetta historiaan ja tilastoihin", + "anonymize_client_ip_desc": "Älä tallenna päätelaitteen täydellistä IP-osoitetta historiaan ja tilastoihin.", "dns_config": "DNS-palvelimen määritys", "dns_cache_config": "DNS-välimuistin määritys", - "dns_cache_config_desc": "Täällä voit määrittää DNS-välimuistin asetukset", + "dns_cache_config_desc": "Tässä voit määrittää DNS-välimuistin.", "blocking_mode": "Estotila", "default": "Oletus", "nxdomain": "NXDOMAIN", @@ -277,7 +277,7 @@ "dns_over_quic": "DNS-over-QUIC", "client_id": "Päätelaitteen ID", "client_id_placeholder": "Syötä päätelaitteen ID", - "client_id_desc": "Eri päätelaitteet voidaan tunnistaa erityisillä tunnisteilla. Täältä löydät lisätietoja päätelaitteiden tunnistuksesta.", + "client_id_desc": "Päätelaitteet voidaan tunnistaa erityisillä ID-tunnisteilla. Lue lisää päätelaitteiden tunnistuksesta täältä.", "download_mobileconfig_doh": "Lataa .mobileconfig-tiedosto DNS-over-HTTPS -käytölle", "download_mobileconfig_dot": "Lataa .mobileconfig-tiedosto DNS-over-TLS -käytölle", "download_mobileconfig": "Lataa asetustiedosto", @@ -309,7 +309,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ä oikea portin numero.", "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", @@ -334,11 +334,11 @@ "install_devices_router_list_4": "Joissakin reitittimissä ei ole mahdollista määrittää omaa DNS-palvelinta. Tällöin AdGuard Homen määritys <0>DHCP-palvelimeksi voi auttaa. Muutoin on selvitettävä reitittimen käyttöohjeesta, miten sen DNS-palvelinasetukset muutetaan.", "install_devices_windows_list_1": "Avaa \"Ohjauspaneeli\" Käynnistä-valikon tai Windowsin haun kautta.", "install_devices_windows_list_2": "Avaa \"Verkko ja Internet\" -ryhmä ja sitten \"Verkko ja jakamiskeskus\".", - "install_devices_windows_list_3": "Etsi ikkunan vasemmasta laidasta \"Muuta sovittimen asetuksia\" ja paina sitä.", - "install_devices_windows_list_4": "Valitse aktiivinen yhteytesi, paina sitä hiiren kakkospainikkeella ja valitse valikosta \"Ominaisuudet\".", + "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_6": "Valitse \"Käytä seuraavia DNS-palvelinten osoitteita\" ja syötä AdGuard Home -palvelimesi osoitteet.", - "install_devices_macos_list_1": "Avaa Omenavalikko ja valitse \"Järjestelmäasetukset \".", + "install_devices_macos_list_1": "Paina Omena-kuvaketta ja valitse \"Järjestelmäasetukset\".", "install_devices_macos_list_2": "Paina \"Verkko\".", "install_devices_macos_list_3": "Valitse listan ensimmäinen yhteys ja paina \"Lisävalinnat\".", "install_devices_macos_list_4": "Valitse DNS-välilehti ja syötä AdGuard Home -palvelimesi osoitteet.", @@ -356,7 +356,7 @@ "open_dashboard": "Avaa hallintapaneeli", "install_saved": "Tallenus onnistui", "encryption_title": "Salaus", - "encryption_desc": "Salaus (HTTPS/TLS) DNS-palvelimelle ja selaimen hallintasivulle", + "encryption_desc": "Salaustuki (HTTPS/TLS) DNS:lle ja verkkokäyttölliittymälle.", "encryption_config_saved": "Salausasetukset tallennettiin", "encryption_server": "Palvelimen nimi", "encryption_server_enter": "Syötä verkkotunnuksesi", @@ -367,7 +367,7 @@ "encryption_https_desc": "Jos HTTPS-portti on määritetty, on AdGuard Homen hallintapaneeli käytettävissä HTTPS-yhteydellä ja lisäksi tämä mahdollistaa myös DNS-over-HTTPS -yhteyden '/dns-query' -kohteessa.", "encryption_dot": "DNS-over-TLS -portti", "encryption_dot_desc": "Jos portti on määritetty, AdGuard Home suorittaa DNS-over-TLS -palvelimen tässä portissa.", - "encryption_doq": "DNS-over-QUIC -portti", + "encryption_doq": "DNS-over-QUIC -portti (kokeellinen)", "encryption_doq_desc": "Jos portti on määritetty, AdGuard Home suorittaa DNS-over-QUIC -palvelimen tässä portissa. Ominaisuus on kokeellinen, eikä välttämättä luotettava. Lisäksi tätä tukevia päätelaitteita ei vielä ole kovin paljon.", "encryption_certificates": "Varmenteet", "encryption_certificates_desc": "Salauksen käyttämiseksi, on syötettävä verkkotunnuksellesi myönnetty, aito SSL-varmenneketju. Voit hankkia ilmaisen varmenteen osoitteesta <0>{{link}} tai ostaa sellaisen joltakin luotetulta varmentajalta.", @@ -378,26 +378,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 pätevä", - "encryption_chain_invalid": "Varmenneketju ei kelpaa", - "encryption_key_valid": "Yksityinen {{type}}-avain on pätevä", - "encryption_key_invalid": "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": "Tämä 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.", @@ -405,8 +405,8 @@ "update_failed": "Automaattinen päivitys epäonnistui. Seuraa näitä ohjeita päivittääksesi manuaalisesti.", "manual_update": "Seuraa näitä ohjeita päivittääksesi manuaalisesti.", "processing_update": "Odota kun AdGuard Home päivittyy", - "clients_title": "Päätelaitteet", - "clients_desc": "Määritä AdGuard Homeen yhdistetyt päätelaitteet", + "clients_title": "Pysyvät päätelaitteet", + "clients_desc": "Määritä pysyvät AdGuard Homeen yhdistetyt päätelaittetiedot.", "settings_global": "Yleinen", "settings_custom": "Oma", "table_client": "Päätelaite", @@ -417,9 +417,9 @@ "client_edit": "Muokkaa päätelaitetta", "client_identifier": "Tunniste", "ip_address": "IP-osoite", - "client_identifier_desc": "Päätelaitteet voidaan tunnistaa IP-osoitteista, CIDR-merkinnöistä, MAC-osoitteista tai erityisistä päätelaitteen ID-tunnisteista (voidaan käyttää DoT/DoH/DoQ kanssa). <0>Täältä voit lukea lisää päätelaitteiden tunnistuksesta.", + "client_identifier_desc": "Päätelaitteet voidaan tunnistaa IP- tai MAC-osoitteista, CIDR-merkinnöistä tai erityisistä päätelaite ID -tunnisteista (voidaan käyttää DoT/DoH/DoQ yhteydessä). Lue lisää päätelaitteiden tunnistuksesta <0>täältä.", "form_enter_ip": "Syötä IP-osoite", - "form_enter_subnet_ip": "Syötä IP-osoite aliverkkoon \"{{cidr}}\"", + "form_enter_subnet_ip": "Syötä aliverkossa \"{{cidr}}\" oleva IP-osoite", "form_enter_mac": "Syötä MAC-osoite", "form_enter_id": "Muokkaa tunnistetta", "form_add_id": "Lisää tunniste", @@ -432,14 +432,14 @@ "clients_not_found": "Päätelaitteita ei löytynyt", "client_confirm_delete": "Haluatko varmasti poistaa päätelaitteen \"{{key}}\"?", "list_confirm_delete": "Haluatko varmasti poistaa tämän listan?", - "auto_clients_title": "Päätelaitteet (määrittämättömät)", - "auto_clients_desc": "Tiedot niistä AdGuard Homea käyttävistä päätelaitteista, joita ei ole määritetty asetuksissa", + "auto_clients_title": "Määrittämättömät päätelaitteet", + "auto_clients_desc": "Päätelaitteet, joita ei ole määritetty pysyviksi ja jotka voivat silti käyttää AdGuard Homea.", "access_title": "Käytön asetukset", "access_desc": "Tässä voidaan määrittää AdGuard Homen DNS-palvelimen käyttöoikeussääntöjä.", "access_allowed_title": "Sallitut päätelaitteet", - "access_allowed_desc": "Lista CIDR-merkinnöistä, IP-osoitteista tai päätelaitteiden ID-tunnisteista. Jos määritetty, hyväksyy AdGuard Home pyyntöjä vain näiltä päätelaitteilta.", + "access_allowed_desc": "Lista CIDR-merkinnöistä, IP-osoitteista tai päätelaite ID -tunnisteista. Jos listalla on kohteita, hyväksyy AdGuard Home pyyntöjä vain näiltä päätelaitteilta.", "access_disallowed_title": "Kielletyt päätelaitteet", - "access_disallowed_desc": "Lista CIDR-merkinnöistä, IP-osoitteista tai päätelaitteiden ID-tunnisteista. Jos määritetty, hylkää AdGuard Home näiden päätelaitteiden pyynnöt. Tätä kenttää ei huomioida, jos sallittuja päätelaitteita on määritetty.", + "access_disallowed_desc": "Lista CIDR-merkinnöistä, IP-osoitteista tai päätelaite ID -tunnisteista. Jos listalla on kohteita, hylkää AdGuard Home näiden päätelaitteiden pyynnöt. Tätä kenttää ei huomioida, jos sallittuja päätelaitteita on määritetty.", "access_blocked_title": "Kielletyt verkkotunnukset", "access_blocked_desc": "Ei pidä sekoittaa suodattimiin. AdGuard Home hylkää näiden verkkotunnusten DNS-pyynnöt, eivätkä nämä pyynnöt näy edes pyyntöhistoriassa. Tähän voidaan syöttää tarkkoja verkkotunnuksia, jokerimerkkejä tai URL-suodatussääntöjä, kuten \"example.org\", \"*.example.org\" tai \"||example.org^\".", "access_settings_saved": "Käytön asetukset tallennettiin", @@ -475,8 +475,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", @@ -507,7 +507,7 @@ "filter_updated": "Listan päivitettiin", "statistics_configuration": "Tilastoinnin määritys", "statistics_retention": "Tilastojen säilytys", - "statistics_retention_desc": "Jos aikaa lyhennetään, joitakin tietoja menetetään.", + "statistics_retention_desc": "Jos aikajaksoa lyhennetään, joitakin tietoja menetetään.", "statistics_clear": "Tyhjennä tilastot", "statistics_clear_confirm": "Haluatko varmasti tyhjentää tilastot?", "statistics_retention_confirm": "Haluatko varmasti muuttaa tilastojen säilytysaikaa? Jos aikaa lyhennetään, joitakin tietoja menetetään.", @@ -532,7 +532,7 @@ "netname": "Verkon nimi", "network": "Verkko", "descr": "Kuvaus", - "whois": "Whois", + "whois": "WHOIS", "filtering_rules_learn_more": "<0>Lue lisää omien hosts-listojesi luonnista.", "blocked_by_response": "Vastauksen sisältämän CNAME:n tai IP:n estämä", "blocked_by_cname_or_ip": "CNAME:n tai IP:n estämä", @@ -552,10 +552,10 @@ "autofix_warning_list": "Suorittaa toiminnot: <0>Poistaa käytöstä järjestelmän DNSStubListener-palvelun <0>Määrittää DNS-palvelimen osoitteeksi 127.0.0.1 <0>Muuttaa sijainnnin /etc/resolv.conf symbolisen linkin kohteeksi /run/systemd/resolve/resolv.conf <0>Pysäyttää DNSStubListener-palvelun (uudelleenlataa systemd-resolved -palvelu)", "autofix_warning_result": "Tämän jälkeen järjestelmäsi kaikki DNS-pyynnöt käsittelee oletusarvoisesti AdGuard Home.", "tags_title": "Tunnisteet", - "tags_desc": "Voit valita päätelaitteeseen viittaavia tunnisteita. Tunnisteet voidaan sisällyttää suodatussääntöihin ja näin voit kohdistaa niitä tarkemmin. <0>Lue lisää", + "tags_desc": "Voit valita päätelaitetta vastaavia tunnisteita. Tunnisteet voidaan sisällyttää suodatussääntöihin ja näin voit kohdistaa niitä tarkemmin. <0>Lue lisää.", "form_select_tags": "Valitse päätelaitteen tunnisteet", "check_title": "Tarkasta suodatus", - "check_desc": "Tarkasta suodatetaanko isäntänimeä", + "check_desc": "Tarkasta onko isäntänimi suodatettu.", "check": "Tarkasta", "form_enter_host": "Syötä osoite", "filtered_custom_rules": "Suodatettu omilla suodatussäännöillä", @@ -598,15 +598,15 @@ "blocklist": "Estolista", "milliseconds_abbreviation": "ms", "cache_size": "Välimuistin koko", - "cache_size_desc": "DNS-välimuistin koko (tavuina)", + "cache_size_desc": "DNS-välimuistin koko (tavuina).", "cache_ttl_min_override": "Korvaa vähimmäis-TTL", "cache_ttl_max_override": "Korvaa enimmäis-TTL", "enter_cache_size": "Syötä välimuistin koko (tavuina)", "enter_cache_ttl_min_override": "Syötä vähimmäis-TTL (sekunteina)", "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 suurin elinaika-arvo (sekunteina)", - "ttl_cache_validation": "Välimuistin elinajan vähimmäisarvon tulee olla pienempi tai sama kuin enimmäisarvon", + "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.", "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", @@ -624,9 +624,9 @@ "adg_will_drop_dns_queries": "AdGuard Home hylkää tämän päätelaitteen DNS-pyynnöt.", "filter_allowlist": "VAROITUS: Toiminto ohittaa \"{{disallowed_rule}}\" -säännön sallittujen päätelaitteiden listalta.", "last_rule_in_allowlist": "Et voi estää tätä päätelaitetta, koska säännön \"{{disallowed_rule}}\" ohitus POISTAA KÄYTÖSTÄ \"Sallitut päätelaitteet\" -listan.", - "experimental": "Kokeellinen", "use_saved_key": "Käytä aiemmin tallennettua avainta", "parental_control": "Lapsilukko", "safe_browsing": "Turvallinen selaus", - "served_from_cache": "{{value}} (jaettu välimuistista)" + "served_from_cache": "{{value}} (jaettu välimuistista)", + "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 e3260cdd..b10433ae 100644 --- a/client/src/__locales/fr.json +++ b/client/src/__locales/fr.json @@ -1,7 +1,7 @@ { "client_settings": "Paramètres du client", - "example_upstream_reserved": "Vous pouvez spécifier un DNS en amont <0>pour un/des domaine(s) spécifique(s)", - "example_upstream_comment": "Vous pouvez spécifier un commentaire", + "example_upstream_reserved": "un amont <0>pour des domaines spécifiques ;", + "example_upstream_comment": " un commentaire.", "upstream_parallel": "Utilisez des requêtes parallèles pour accélérer la résolution en requêtant simultanément tous les serveurs en amont.", "parallel_requests": "Demandes en parallèle", "load_balancing": "Équilibrage de charge", @@ -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": "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", + "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.", "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", @@ -143,7 +143,7 @@ "use_adguard_browsing_sec_hint": "AdGuard Home vérifiera si le domaine est bloqué par le service web de sécurité de la navigation. Il utilisera une API de recherche respectueuse de la vie privée pour effectuer la vérification : seul un préfixe court du hachage SHA256 du nom de domaine est envoyé au serveur.", "use_adguard_parental": "Utiliser le contrôle parental d'AdGuard", "use_adguard_parental_hint": "AdGuard Home va vérifier s'il y a du contenu pour adultes sur le domaine. Ce sera fait par aide du même API discret que celui utilisé par le service de Sécurité de navigation.", - "enforce_safe_search": "Utiliser la recherche sécurisée", + "enforce_safe_search": "Utiliser la Recherche Sécurisée", "enforce_save_search_hint": "AdGuard Home appliquera la recherche sécurisée dans les moteurs de recherche suivants : Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.", "no_servers_specified": "Pas de serveurs spécifiés", "general_settings": "Paramètres généraux", @@ -165,10 +165,10 @@ "enabled_filtering_toast": "Filtrage activé", "disabled_safe_browsing_toast": "Navigation sécurisée désactivée", "enabled_safe_browsing_toast": "Navigation sécurisée activée", - "disabled_parental_toast": "Contrôle parental désactivé", - "enabled_parental_toast": "Contrôle parental activé", - "disabled_safe_search_toast": "Recherche sécurisée désactivée", - "enabled_save_search_toast": "Recherche sécurisée activée", + "disabled_parental_toast": "Contrôle Parental désactivé", + "enabled_parental_toast": "Contrôle Parental activé", + "disabled_safe_search_toast": "Recherche Sécurisée désactivée", + "enabled_save_search_toast": "Recherche Sécurisée activée", "enabled_table_header": "Activé", "name_table_header": "Nom", "list_url_table_header": "URL de la liste", @@ -196,25 +196,25 @@ "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": "Entrez une URL ou le chemin absolu de la liste.", "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", "examples_title": "Exemples", - "example_meaning_filter_block": "bloque l’accès au domaine example.org et à tous ses sous-domaines", - "example_meaning_filter_whitelist": "débloque l’accès au domaine example.org et à tous ses sous-domaines", - "example_meaning_host_block": "AdGuard Home va retourner l'adresse 127.0.0.1 au domaine example.org (mais pas aux sous-domaines).", - "example_comment": "! Voici comment ajouter une déscription", - "example_comment_meaning": "commentaire", - "example_comment_hash": "# Et comme ça aussi on peut laisser des commentaires", - "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_dot": "<0>DNS-over-TLS chiffré", - "example_upstream_doh": "<0>DNS-over-HTTPS chiffré", - "example_upstream_doq": "<0>DNS-over-QUIC chiffré", - "example_upstream_sdns": "vous pouvez utiliser <0>DNS Stamps pour <1>DNSCrypt ou les resolveurs <2>DNS_over_HTTPS", - "example_upstream_tcp": "DNS classique (au-dessus de TCP)", + "example_meaning_filter_block": "bloque l’accès au domaine example.org et à tous ses sous-domaines ;", + "example_meaning_filter_whitelist": "débloque l’accès au domaine example.org et à tous ses sous-domaines ;", + "example_meaning_host_block": "AdGuard Home va retourner l'adresse 127.0.0.1 au domaine example.org (mais pas aux sous-domaines) ;", + "example_comment": "! Voici comment ajouter une déscription.", + "example_comment_meaning": "juste un commentaire ;", + "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_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) ;", "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 +259,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", @@ -275,9 +275,9 @@ "dns_over_https": "DNS-over-HTTPS", "dns_over_tls": "DNS-over-TLS", "dns_over_quic": "DNS-over-QUIC", - "client_id": "ID du client", - "client_id_placeholder": "Saisissez le ID du client", - "client_id_desc": "Les clients différents peuvent être identifiés par aide d'un ID client spécial. Vous trouverez plus d'information sur l'identification des clients ici .", + "client_id": "ClientID", + "client_id_placeholder": "Saisissez le ClientID", + "client_id_desc": "Les clients différents peuvent être identifiés par aide d'un ClientID spécial. Vous trouverez plus d'information sur l'identification des clients ici .", "download_mobileconfig_doh": "Télécharger .mobileconfig pour DNS-sur-HTTPS", "download_mobileconfig_dot": "Télécharger .mobileconfig pour DNS-sur-TLS", "download_mobileconfig": "Télécharger le fichier de configuration", @@ -309,7 +309,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 numéro de port valide", + "form_error_port": "Entrez un 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", @@ -334,8 +334,8 @@ "install_devices_router_list_4": "Vous ne pouvez pas définir un serveur DNS personnalisé sur certains types de routeurs. Dans ce cas, la configuration de AdGuard Home en tant que <0>serveur DHCP peut aider. Sinon, vous devez rechercher le manuel sur la façon de personnaliser les serveurs DNS pour votre modèle de routeur particulier.", "install_devices_windows_list_1": "Ouvrez votre Panneau de configuration depuis le menu Démarrer ou la recherche Windows.", "install_devices_windows_list_2": "Allez dans la catégorie Réseau et Internet et ensuite dans le Centre Réseau et Partage.", - "install_devices_windows_list_3": "Sur la partie gauche de l'écran, recherchez « Modifier les paramètres de l'adaptateur » et cliquez dessus.", - "install_devices_windows_list_4": "Sélectionnez votre connexion active, clic droit dessus et sélectionnez Propriétés.", + "install_devices_windows_list_3": "Dans le panneau de gauche, cliquez sur \"Modifier les paramètres de l'adaptateur\".", + "install_devices_windows_list_4": "Cliquez avec le bouton droit de la souris sur votre connexion active et sélectionnez Propriétés.", "install_devices_windows_list_5": "Recherchez « Protocole Internet Version 4 (TCP/IPv4) » (soit, pour IPv6, « Protocole Internet Version 6 (TCP/IPv6) ») dans la liste, sélectionnez-la puis cliquez à nouveau sur Propriétés.", "install_devices_windows_list_6": "Sélectionnez « Utiliser l’adresse de serveur DNS suivante » et saisissez votre adresse de serveur AdGuard Home.", "install_devices_macos_list_1": "Cliquez sur l'icône Apple et allez dans les Préférences Système.", @@ -367,7 +367,7 @@ "encryption_https_desc": "Si le port HTTPS est configuré, l'interface administrateur de AdGuard Home sera accessible via HTTPS et fournira aussi un service DNS-over-HTTPS sur l'emplacement '/dns-query'.", "encryption_dot": "Port DNS-over-TLS", "encryption_dot_desc": "Si ce port est configuré, AdGuard Home exécutera un serveur DNS-over-TLS sur ce port.", - "encryption_doq": "Port DNS sur QUIC", + "encryption_doq": "Port DNS sur QUIC (expérimental)", "encryption_doq_desc": "Si ce port est configuré, AdGuard Home exécutera un serveur DNS sur QUIC sur ce port. Ceci est expérimental et possiblement pas entièrement fiable. Peu de clients le prennent en charge actuellement.", "encryption_certificates": "Certificats", "encryption_certificates_desc": "Pour utiliser le chiffrement, vous devez fournir une chaîne de certificats SSL valide pour votre domaine. Vous pouvez en obtenir une gratuitement sur <0>{{link}} ou vous pouvez en acheter une via les Autorités de Certification de confiance.", @@ -378,26 +378,26 @@ "encryption_key_input": "Copiez/coller votre clé privée PEM encodée pour votre certificat ici.", "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_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_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": "C'est un 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 récupération du statut du serveur DNS .", "down": "Descendant", "fix": "Corriger", "dns_providers": "Voici une <0>liste de fournisseurs DNS connus.", @@ -405,8 +405,8 @@ "update_failed": "Échec de la mise à jour automatique. Veuillez suivre ces étapes pour mettre à jour manuellement.", "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", - "clients_desc": "Configurer les appareils connectés à AdGuard Home", + "clients_title": "Clients persistants", + "clients_desc": "Configurez des enregistrements clients persistants pour les appareils connectés à AdGuard Home.", "settings_global": "Général", "settings_custom": "Personnalisé", "table_client": "Client", @@ -417,7 +417,7 @@ "client_edit": "Modifier le client", "client_identifier": "Identifiant", "ip_address": "Adresse IP", - "client_identifier_desc": "Les clients peuvent être identifiés par les adresses IP, CIDR, MAC ou un ID client spécial (qui peut être utilisé pour DoT/DoH/DoQ). Vous trouverez plus d'information sur l'identification des clients <0>ici .", + "client_identifier_desc": "Les clients peuvent être identifiés par leur adresse IP, CIDR, adresse MAC ou ClientID (peut être utilisé pour DoT/DoH/DoQ). En savoir plus sur la façon d'identifier les clients <0>ici.", "form_enter_ip": "Saisissez l'IP", "form_enter_subnet_ip": "Saisissez une adresse IP dans le sous-réseau « {{cidr}} »", "form_enter_mac": "Saisissez MAC", @@ -432,14 +432,14 @@ "clients_not_found": "Aucun client trouvé", "client_confirm_delete": "Voulez-vous vraiment supprimer le client « {{key}} »?", "list_confirm_delete": "Voulez-vous vraiment supprimer cette liste ?", - "auto_clients_title": "Clients (exécution)", - "auto_clients_desc": "Les données des clients qu'utilisent AdGuard Home, mais non stockées dans la configuration", + "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_allowed_title": "Clients autorisés", - "access_allowed_desc": "Une liste de CIDR, d'adresses IP ou d'ID client. S'il est configuré, AdGuard Home acceptera uniquement les demandes de ces clients.", + "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", - "access_disallowed_desc": "Une liste d'adresses IP ou CIDR. Si configuré, AdGuard Home bloquera les requêtes provenant de ces adresses IP. Si des clients sont configurés, ce champ sera ignoré.", + "access_disallowed_desc": "Une liste de CIDRs, d'adresses IP, ou de ClientIDs. Si cette liste comporte des entrées, AdGuard Home abandonnera les demandes provenant de ces clients. Ce champ est ignoré s'il y a des entrées dans Clients autorisés.", "access_blocked_title": "Domaines interdits", "access_blocked_desc": "A ne pas confondre avec les filtres. AdGuard Home rejette les requêtes DNS correspondant à ces domaines, et ces requêtes n'apparaissent même pas dans le journal des requêtes. Vous pouvez spécifier des noms de domaine exacts, des caractères génériques ou des règles de filtrage d'URL, par exemple « exemple.org », « *.exemple.org » ou « ||example.org^ » de manière correspondante.", "access_settings_saved": "Paramètres d'accès enregistrés avec succès", @@ -475,8 +475,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": "Format de domaine invalide", - "form_error_answer_format": "Format de réponse invalide", + "form_error_domain_format": "Nom 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", @@ -507,7 +507,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", @@ -532,7 +532,7 @@ "netname": "Nom du réseau", "network": "Réseau", "descr": "Description", - "whois": "Whois", + "whois": "WHOIS", "filtering_rules_learn_more": "<0>Apprenez-en plus à propos de la création de vos propres listes de blocage d’hôtes.", "blocked_by_response": "Bloqué par un CNAME ou une réponse IP", "blocked_by_cname_or_ip": "Bloqué par CNAME ou adresse IP", @@ -552,10 +552,10 @@ "autofix_warning_list": "Ceci effectuera les tâches suivantes : <0>Désactiver le système DNSStubListener <0>Définir l’adresse du serveur DNS à 127.0.0.1 <0>Remplacer la cible du lien symbolique de /etc/resolv.conf par /run/systemd/resolve/resolv.conf <0>Arrêter DNSStubListener (recharger le service résolu par systemd)", "autofix_warning_result": "Par conséquent, toutes les demandes DNS de votre système seront traitées par AdGuardHome par défaut.", "tags_title": "Mots clés", - "tags_desc": "Vous pouvez sélectionner les mots clés qui correspondent au client. Les mots clés peuvent être inclus dans les règles de filtrage et vous permettent de les appliquer plus précisément. <0>En savoir plus", + "tags_desc": "Vous pouvez sélectionner les mots clés qui correspondent au client. Les mots clés peuvent être inclus dans les règles de filtrage et vous permettent de les appliquer plus précisément. <0>En savoir plus .", "form_select_tags": "Sélectionner les mots clés du client", "check_title": "Vérification du filtrage", - "check_desc": "Vérifier si le nom d’hôte est filtré", + "check_desc": "Vérifier si le nom d’hôte est filtré .", "check": "Vérifier", "form_enter_host": "Saisissez un nom d’hôte", "filtered_custom_rules": "Filtré par des règles de filtrage personnalisées", @@ -594,19 +594,19 @@ "allowed": "Autorisé", "filtered": "Filtré", "rewritten": "Réécrit", - "safe_search": "Recherche sécurisée", + "safe_search": "Recherche Sécurisée", "blocklist": "Liste de blocage", "milliseconds_abbreviation": "ms", "cache_size": "Taille du cache", - "cache_size_desc": "Taille du cache DNS (en bytes)", + "cache_size_desc": "Taille du cache DNS (en bytes) .", "cache_ttl_min_override": "Remplacer le TTL minimum", "cache_ttl_max_override": "Remplacer le TTL maximum", "enter_cache_size": "Entrer la taille du cache (octets)", "enter_cache_ttl_min_override": "Entrez le TTL minimum (secondes)", "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", + "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 .", "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", @@ -624,9 +624,9 @@ "adg_will_drop_dns_queries": "AdGuard Home ignorera toutes les requêtes DNS de ce client.", "filter_allowlist": "ATTENTION : Cette action exclura également la règle « {{disallowed_rule}} » de la liste des clients autorisés.", "last_rule_in_allowlist": "Impossible d’interdire ce client, car l’exclusion de la règle « {{disallowed_rule}} » DÉSACTIVERA la liste des « clients autorisés ».", - "experimental": "Expérimental", "use_saved_key": "Utiliser la clef précédemment enregistrée", "parental_control": "Contrôle parental", "safe_browsing": "Navigation sécurisée", - "served_from_cache": "{{value}} (depuis le cache)" + "served_from_cache": "{{value}} (depuis le cache)", + "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 e7642fd2..5b0dc1dc 100644 --- a/client/src/__locales/hr.json +++ b/client/src/__locales/hr.json @@ -623,7 +623,6 @@ "adg_will_drop_dns_queries": "AdGuard Home odbaciti će sve DNS upite od ovog klijenta.", "filter_allowlist": "UPOZORENJE: Ova akcija će također isključiti pravilo \"{{disallowed_rule}}\" s popisa dopuštenih klijenata.", "last_rule_in_allowlist": "Ovaj klijent nije moguće onemogućiti jer će isključivanje pravila \"{{disallowed_rule}}\" ONEMOGUĆITI popis \"Dopušteni klijenti\".", - "experimental": "Eksperimentalno", "use_saved_key": "Korištenje prethodno spremljenog ključa", "parental_control": "Roditeljska zaštita", "safe_browsing": "Sigurno surfanje", diff --git a/client/src/__locales/hu.json b/client/src/__locales/hu.json index 6c876315..b49b6506 100644 --- a/client/src/__locales/hu.json +++ b/client/src/__locales/hu.json @@ -623,7 +623,6 @@ "adg_will_drop_dns_queries": "Az AdGuard Home eldobja az összes DNS kérést erről a kliensről.", "filter_allowlist": "FIGYELMEZTETÉS: Ez a művelet a \"{{disallowed_rule}}\" szabályt is kizárja az engedélyezett ügyfelek listájából.", "last_rule_in_allowlist": "Nem lehet letiltani ezt az ügyfelet, mert a \"{{disallowed_rule}}\" szabály kizárása letiltja az \"Allowed clients\" listát.", - "experimental": "Kísérleti", "use_saved_key": "Előzőleg mentett kulcs használata", "parental_control": "Szülői felügyelet", "safe_browsing": "Biztonságos böngészés", diff --git a/client/src/__locales/id.json b/client/src/__locales/id.json index 6449b62d..58148123 100644 --- a/client/src/__locales/id.json +++ b/client/src/__locales/id.json @@ -593,7 +593,7 @@ "allowed": "Dibolehkan", "filtered": "Tersaring", "rewritten": "Tulis ulang", - "safe_search": "Pencarian aman", + "safe_search": "Aktifkan Pencarian Aman", "blocklist": "Daftar blokir", "milliseconds_abbreviation": "ms", "cache_size": "Ukuran cache", @@ -623,7 +623,6 @@ "adg_will_drop_dns_queries": "AdGuard Home akan menghapus semua permintaan DNS dari klien ini.", "filter_allowlist": "PERINGATAN: Tindakan ini juga akan mengecualikan aturan \"{{disallowed_rule}}\" dari daftar klien yang diizinkan.", "last_rule_in_allowlist": "Tidak dapat melarang klien ini karena mengecualikan aturan \"{{disallowed_rule}}\" akan MENONAKTIFKAN daftar \"Klien yang diizinkan\".", - "experimental": "Eksperimental", "use_saved_key": "Gunakan kunci yang disimpan sebelumnya", "parental_control": "Kontrol Orang Tua", "safe_browsing": "Penjelajahan Aman", diff --git a/client/src/__locales/it.json b/client/src/__locales/it.json index f0be3db7..fd560562 100644 --- a/client/src/__locales/it.json +++ b/client/src/__locales/it.json @@ -1,7 +1,7 @@ { "client_settings": "Impostazioni client", - "example_upstream_reserved": "Puoi specificare un upstream DNS<0>per lo specifico dominio(i)", - "example_upstream_comment": "Puoi specificare un commento", + "example_upstream_reserved": "un upstream <0>per specifici domini;", + "example_upstream_comment": "un commento.", "upstream_parallel": "Utilizza richieste parallele per accelerare la risoluzione interrogando simultaneamente tutti i server upstream.", "parallel_requests": "Richieste parallele", "load_balancing": "Bilanciamento del carico", @@ -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 client ID deve contenere solo numeri, lettere minuscole e trattini", - "form_error_server_name": "Nome server non valido", - "form_error_subnet": "La 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", @@ -143,7 +143,7 @@ "use_adguard_browsing_sec_hint": "AdGuard Home verificherà se il dominio è bloccato dal servizio web di sicurezza della navigazione. Utilizzerà l'API di ricerca rispettosa della privacy per eseguire il controllo: solo un breve prefisso hash SHA256 del nome di dominio viene inviato al server.", "use_adguard_parental": "Utilizza il Controllo Parentale di AdGuard", "use_adguard_parental_hint": "AdGuard Home verificherà se il dominio contiene materiale per adulti. Utilizza le stesse API privacy-friendly del servizio web 'sicurezza di navigazione'.", - "enforce_safe_search": "Utilizza ricerca sicura", + "enforce_safe_search": "Utilizza Ricerca Sicura", "enforce_save_search_hint": "AdGuard Home forzerà la ricerca sicura sui seguenti motori di ricerca: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.", "no_servers_specified": "Nessun server specificato", "general_settings": "Impostazioni generali", @@ -165,10 +165,10 @@ "enabled_filtering_toast": "Attiva filtri", "disabled_safe_browsing_toast": "Disattiva Navigazione Sicura", "enabled_safe_browsing_toast": "Attiva Navigazione Sicura", - "disabled_parental_toast": "Disattiva il Controllo Parentale", - "enabled_parental_toast": "Attiva Controllo Parentale", - "disabled_safe_search_toast": "Ricerca sicura disattivata", - "enabled_save_search_toast": "Attiva ricerca sicura", + "disabled_parental_toast": "Il Controllo Parentale è disattivato", + "enabled_parental_toast": "Il Controllo Parentale è attivo", + "disabled_safe_search_toast": "La Ricerca Sicura è disattivata", + "enabled_save_search_toast": "La Ricerca Sicura è attiva", "enabled_table_header": "Attivo", "name_table_header": "Nome", "list_url_table_header": "Elenco URL", @@ -196,25 +196,25 @@ "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", "examples_title": "Esempi", - "example_meaning_filter_block": "blocca accesso al dominio example.org e a tutti i suoi sottodomini", - "example_meaning_filter_whitelist": "consente l'accesso al dominio esempio.org e a tutti i relativi sottodomini", - "example_meaning_host_block": "AdGuard Home restituirà 127.0.0.1 come indirizzo per il dominio example.org (ma non per i suoi sottodomini)", - "example_comment": "! Qui va un commento", - "example_comment_meaning": "un commento", - "example_comment_hash": "# Un altro commento", - "example_regex_meaning": "blocca l'accesso ai domini che corrispondono alla specifica espressione regolare", - "example_upstream_regular": "DNS regolari (via UDP)", - "example_upstream_dot": "<0>DNS su TLS crittografato", - "example_upstream_doh": "<0>DNS su HTTPS crittografato", - "example_upstream_doq": "<0>DNS su QUIC crittografato", - "example_upstream_sdns": "puoi utilizzare <0>DNS Stamps per <1>DNSCrypt oppure dei risolutori <2>DNS-over-HTTPS", - "example_upstream_tcp": "DNS regolari (via TCP)", + "example_meaning_filter_block": "blocca accesso al dominio example.org e a tutti i suoi sottodomini;", + "example_meaning_filter_whitelist": "consente l'accesso al dominio esempio.org e a tutti i relativi sottodomini;", + "example_meaning_host_block": "restituisce 127.0.0.1 per example.org (ma non per i suoi sottodomini);", + "example_comment": "! Qui va un commento.", + "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_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);", "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 +259,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 e 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", @@ -274,10 +274,10 @@ "dnscrypt": "DNSCrypt", "dns_over_https": "DNS su HTTPS", "dns_over_tls": "DNS su TLS", - "dns_over_quic": "DNS su Quic", - "client_id": "ID client", - "client_id_placeholder": "Inserisci ID client", - "client_id_desc": "Client differenti possono essere identificati da uno speciale ID. Qui potrai saperne di più sui metodi per identificarli.", + "dns_over_quic": "DNS su QUIC", + "client_id": "ClientID", + "client_id_placeholder": "Inserisci un ClientID", + "client_id_desc": "I client possono essere identificati attraverso un ClientID. Qui potrai saperne di più sui metodi per identificarli.", "download_mobileconfig_doh": "Scarica .mobileconfig per DNS su HTTPS", "download_mobileconfig_dot": "Scarica .mobileconfig per DNS su TLS", "download_mobileconfig": "Scarica file di configurazione", @@ -309,7 +309,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", @@ -334,12 +334,12 @@ "install_devices_router_list_4": "Su alcuni tipi di router, non è possibile configurare un server DNS personalizzato. In tal caso, configurare AdGuard Home come un <0>server DHCP potrebbe aiutare. In alternativa, dovresti leggere il manuale di istruzioni per capire come personalizzare i server DNS sul tuo specifico modello di router.", "install_devices_windows_list_1": "Apri il Pannello di controllo tramite il menu Start o la ricerca di Windows.", "install_devices_windows_list_2": "Vai a Rete e categoria Internet e poi a Centro connessioni di rete e condivisione.", - "install_devices_windows_list_3": "Sul lato sinistro dello schermo, trova \"Cambia impostazioni adattatore\" e clicca su di esso.", - "install_devices_windows_list_4": "Seleziona la tua connessione attiva, fai clic destro su di essa e scegli Proprietà.", + "install_devices_windows_list_3": "Sul lato sinistro dello schermo, clicca su \"Cambia impostazioni adattatore\".", + "install_devices_windows_list_4": "Fai clic destro sulla tua connessione attiva e seleziona Proprietà.", "install_devices_windows_list_5": "Trova \"Protocollo Internet versione 4 (TCP/IPv4)\" (o, per IPv6, \"Protocollo Internet versione 6 (TCP/IPv6)\" nell'elenco, selezionalo e quindi clicca nuovamente su Proprietà.", "install_devices_windows_list_6": "Scegli \"Utilizza i seguenti indirizzi server DNS\" ed inserisci i tuoi indirizzi server AdGuard Home.", - "install_devices_macos_list_1": "Fai clic sull'icona Apple e vai su Preferenze di Sistema.", - "install_devices_macos_list_2": "Clicca sulla rete.", + "install_devices_macos_list_1": "Fai clic sull'icona Apple e dirigiti sulle Preferenze di Sistema.", + "install_devices_macos_list_2": "Clicca su Rete.", "install_devices_macos_list_3": "Seleziona la prima connessione nel tuo elenco e clicca su Avanzate.", "install_devices_macos_list_4": "Seleziona la scheda DNS e inserisci gli indirizzi del tuo server AdGuard Home", "install_devices_android_list_1": "Dalla schermata Home Menu di Android, clicca Impostazioni.", @@ -356,7 +356,7 @@ "open_dashboard": "Apri pannello di controllo", "install_saved": "Salvataggio riuscito", "encryption_title": "crittografia", - "encryption_desc": "Supporto di crittografia (HTTPS / TLS) per interfaccia web sia di DNS che di amministrazione", + "encryption_desc": "Supporto alla crittografia (HTTPS / TLS) per DNS ed interfaccia web amministrazione.", "encryption_config_saved": "Configurazione crittografia salvata", "encryption_server": "Nome server", "encryption_server_enter": "Inserisci il tuo nome di dominio", @@ -367,7 +367,7 @@ "encryption_https_desc": "Se la porta HTTPS è configurata, l'interfaccia di amministrazione di AdGuard Home sarà accessibile tramite HTTPS e fornirà anche DNS su HTTPS nella posizione \"/ dns-query\".", "encryption_dot": "DNS su porta TLS", "encryption_dot_desc": "Se questa porta è configurata, AdGuard Home eseguirà un server DNS su TLS su questa porta.", - "encryption_doq": "DNS su porta QUIC", + "encryption_doq": "Porta DNS su QUIC (sperimentale)", "encryption_doq_desc": "Se questa porta è configurata, AdGuard Home eseguirà un server DNS su porta QUIC. Questa opzione è sperimentale e potrebbe non risultare affidabile. Inoltre, al momento non sono molti i client a supportarla.", "encryption_certificates": "Certificati", "encryption_certificates_desc": "Per utilizzare la crittografia, è necessario fornire una catena di certificati SSL valida per il proprio dominio. Puoi ottenere un certificato gratuito su <0> {{link}} o puoi acquistarlo da una delle Autorità di certificazione attendibili.", @@ -378,26 +378,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 dovrebbe 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 è una 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.", @@ -405,8 +405,8 @@ "update_failed": "Aggiornamento automatico non riuscito. Ti suggeriamo di seguire questi passaggi per aggiornare manualmente.", "manual_update": "Ti invitiamo a seguire questi passaggi per aggiornare manualmente.", "processing_update": "Perfavore aspetta, AdGuard Home si sta aggiornando", - "clients_title": "Client", - "clients_desc": "Configura i dispositivi connessi ad AdGuard Home", + "clients_title": "Client persistenti", + "clients_desc": "Configura le registrazioni dei client persistenti per i dispositivi connessi ad AdGuard Home.", "settings_global": "Globale", "settings_custom": "Personalizzato", "table_client": "Client", @@ -417,7 +417,7 @@ "client_edit": "Modifica Client", "client_identifier": "Identificatore", "ip_address": "Indirizzo IP", - "client_identifier_desc": "I client possono essere identificati dall'indirizzo IP, CIDR, indirizzo MAC o un ID speciale (che può essere utilizzato per DoT/DoH/DoQ). <0>Qui potrai saperne di più sui metodi per identificarli.", + "client_identifier_desc": "I client possono essere identificati attraverso il loro indirizzo IP, CIDR, indirizzo MAC o ClientID (che può essere utilizzato per DoT/DoH/DoQ). <0>Qui potrai saperne di più sui metodi per identificarli.", "form_enter_ip": "Inserisci IP", "form_enter_subnet_ip": "Inserisci un indirizzo IP nella subnet \"{{cidr}}\"", "form_enter_mac": "Inserisci MAC", @@ -432,14 +432,14 @@ "clients_not_found": "Nessun client trovato", "client_confirm_delete": "Sei sicuro di voler eliminare il client \"{{key}}\"?", "list_confirm_delete": "Sei sicuro di voler eliminare questo elenco?", - "auto_clients_title": "Clienti (tempo di esecuzione)", - "auto_clients_desc": "Dati dei clienti che utilizzano AdGuard Home, ma che non sono salvati nella configurazione", + "auto_clients_title": "Client in tempo reale", + "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_allowed_title": "Client permessi", - "access_allowed_desc": "Un elenco di CIDR, indirizzi IP o ID client. Se configurata AdGuard Home accetterà richieste solo da questi client.", + "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", - "access_disallowed_desc": "Un elenco di CIDR, indirizzi IP o ID client. Se configurata, AdGuard Home rifiuterà richieste da questi client. Se i client consentiti risulteranno configurati, questo campo verrà ignorato.", + "access_disallowed_desc": "Un elenco di CIDR, indirizzi IP o ClientID. Se l'elenco conterrà degli elementi, AdGuard Home rifiuterà richieste da questi client. Questo campo verrà ignorato se ci saranno elementi nei client Consentiti.", "access_blocked_title": "Domini bloccati", "access_blocked_desc": "Da non confondere con i filtri. AdGuard Home eliminerà le richieste DNS corrispondenti a questi domini e queste richieste non verranno visualizzate nel relativo registro. Puoi specificare nomi di dominio esatti, caratteri jolly o regole di filtraggio URL, ad esempio \"esempio.org\", \"*.esempio.org\" o \"||esempio.org^\".", "access_settings_saved": "Impostazioni di accesso salvate correttamente", @@ -450,7 +450,7 @@ "setup_dns_privacy_1": "<0>DNS su TLS: Utilizza la stringa <1>{{address}}.", "setup_dns_privacy_2": "<0>DNS su HTTPS: Utilizza la stringa <1>{{address}}.", "setup_dns_privacy_3": "<0>Ecco un elenco di software che è possibile utilizzare.", - "setup_dns_privacy_4": "Si usa un dispositivo iOS 14 o macOS Big Sur puoi scaricare uno file speciale.mobileconfig' che aggiunge i server DNS su HTTPS or DNS su TLS alle configurazioni DNS.", + "setup_dns_privacy_4": "Su un dispositivo iOS 14 o macOS Big Sur puoi scaricare uno speciale file '.mobileconfig' che aggiunge server DNS su HTTPS o DNS su TLS alle configurazioni DNS.", "setup_dns_privacy_android_1": "Android 9 supporta DNS su TLS in modo nativo. Per configurarlo, vai su Impostazioni → Rete e Internet → Avanzate → DNS privato e inserisci qui il tuo nome di dominio.", "setup_dns_privacy_android_2": "<0>AdGuard per Android supporta <1>DNS su HTTPS e <1>DNS su TLS.", "setup_dns_privacy_android_3": "<0>Intra aggiunge <1>DNS su HTTPS il supporto ad Android.", @@ -475,8 +475,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", @@ -507,7 +507,7 @@ "filter_updated": "L'elenco è stato aggiornato correttamente", "statistics_configuration": "Configurazione delle statistiche", "statistics_retention": "Conservazione delle statistiche", - "statistics_retention_desc": "Se il valore di intervallo dovesse diminuire, 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", @@ -532,7 +532,7 @@ "netname": "Nome Network", "network": "Rete", "descr": "Descrizione", - "whois": "Chi è", + "whois": "WHOIS", "filtering_rules_learn_more": "<0>Leggi altro su come creare i tuoi elenchi host.", "blocked_by_response": "Bloccato per CNAME o IP in risposta", "blocked_by_cname_or_ip": "Bloccato da CNAME o IP", @@ -552,10 +552,10 @@ "autofix_warning_list": "Eseguirà queste attività: <0> Disattiva DNSStubListener di sistema <0> Imposta l'indirizzo del server DNS su 127.0.0.1 <0> Sostituisci la destinazione del collegamento simbolico di /etc/resolv.conf su / run / systemd /resolve/resolv.conf <0> Arresta DNSStubListener (ricarica il servizio systemd-resolved) ", "autofix_warning_result": "Di conseguenza, tutte le richieste DNS dal sistema verranno elaborate da AdGuardHome per impostazione predefinita.", "tags_title": "Tag", - "tags_desc": "È possibile selezionare i tag che corrispondono al client. I tag possono essere inclusi nelle regole dei filtri e consentono di applicarli in modo più accurato. <0> Ulteriori informazioni ", + "tags_desc": "Puoi selezionare i tag che corrispondono al client. È possibile includere tag nelle regole di filtraggio per applicarli in modo più accurato. <0>Per saperne di più.", "form_select_tags": "Seleziona i tag client", "check_title": "Controlla il filtro", - "check_desc": "Controlla se il nome host è filtrato", + "check_desc": "Verifica che il nome host sia filtrato.", "check": "Controlla", "form_enter_host": "Inserisci un nome per l'host", "filtered_custom_rules": "Filtrato dalle regole filtro personalizzate", @@ -594,19 +594,19 @@ "allowed": "Consentito", "filtered": "Filtrato", "rewritten": "Riscritto", - "safe_search": "Ricerca sicura", + "safe_search": "Ricerca Sicura", "blocklist": "Lista nera", "milliseconds_abbreviation": "ms", "cache_size": "Dimensioni cache", - "cache_size_desc": "Dimensioni cache DNS (in byte)", + "cache_size_desc": "Dimensioni cache DNS (in byte).", "cache_ttl_min_override": "Sovrascrivi TTL minimo", "cache_ttl_max_override": "Sovrascrivi TTL massimo", "enter_cache_size": "Immetti dimensioni cache (in byte)", "enter_cache_ttl_min_override": "Immetti TTL minimo (in secondi)", "enter_cache_ttl_max_override": "Immetti TTL massimo (in secondi)", - "cache_ttl_min_override_desc": "Estende i valori brevi (in secondi) ricevuti dal server upstream durante la memorizzazione nella cache delle risposte DNS", - "cache_ttl_max_override_desc": "Imposta un periodo massimo di attivazione (in secondi) per le voci nella cache DNS", - "ttl_cache_validation": "Il valore minimo della cache TTL deve essere inferiore o uguale al valore massimo", + "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.", "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", @@ -624,9 +624,9 @@ "adg_will_drop_dns_queries": "AdGuard Home eliminerà tutte le richieste DNS da questo client.", "filter_allowlist": "ATTENZIONE: Quest'azione escluderà anche la regola \"{{disallowed_rule}}\" dall'elenco di clienti consentiti.", "last_rule_in_allowlist": "Impossibile bloccare questo client perché escludere la regola \"{{disallowed_rule}}\" DISATIVERÁ l'elenco \"Clienti consentiti\".", - "experimental": "Sperimentale", "use_saved_key": "Utilizza la chiave salvata in precedenza", "parental_control": "Controllo Parentale", "safe_browsing": "Navigazione Sicura", - "served_from_cache": "{{value}} (fornito dalla cache)" + "served_from_cache": "{{value}} (fornito dalla cache)", + "form_error_password_length": "La password deve essere lunga almeno {{value}} caratteri." } diff --git a/client/src/__locales/ja.json b/client/src/__locales/ja.json index bc85b3e6..7c2f8ba1 100644 --- a/client/src/__locales/ja.json +++ b/client/src/__locales/ja.json @@ -1,7 +1,7 @@ { "client_settings": "クライアント設定", "example_upstream_reserved": "<0>特定のドメインに対してDNSアップストリームを指定できます。", - "example_upstream_comment": "コメントを指定できます。", + "example_upstream_comment": "コメントを追加できます。", "upstream_parallel": "並列リクエストを使用する(同時にすべてのアップストリームサーバーに処理要求することで解決スピードが向上)", "parallel_requests": "並列リクエスト", "load_balancing": "ロードバランシング", @@ -35,7 +35,7 @@ "dhcp_config_saved": "DHCP構成が無事に保存されました。", "dhcp_ipv4_settings": "DHCP IPv4 設定", "dhcp_ipv6_settings": "DHCP IPv6 設定", - "form_error_required": "必須項目", + "form_error_required": "必須項目です", "form_error_ip4_format": "IPv4アドレスが無効です", "form_error_ip4_range_start_format": "範囲開始のIPv4アドレスが無効です", "form_error_ip4_range_end_format": "範囲終了のIPv4アドレスが無効です", @@ -43,14 +43,14 @@ "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_client_id_format": "ClientIDには、数字、小文字、ハイフン以外は使用できません", + "form_error_server_name": "サーバー名が無効です", "form_error_subnet": "IPアドレス「{{ip}}」はサブネット「{{cidr}}」に含まれていません", - "form_error_positive": "0より大きい必要があります", + "form_error_positive": "0より大きい値でなければなりません", "out_of_range_error": "\"{{start}}\"-\"{{end}}\" の範囲外である必要があります", "lower_range_start_error": "範囲開始よりも低い値である必要があります", - "greater_range_start_error": "範囲開始より大きい必要があります", - "greater_range_end_error": "範囲終了より大きい必要があります", + "greater_range_start_error": "範囲開始値より大きい値でなければなりません", + "greater_range_end_error": "範囲終了値より大きい値でなければなりません", "subnet_error": "アドレスは1つのサブネット内にある必要があります", "gateway_or_subnet_invalid": "サブネットマスクが無効です", "dhcp_form_gateway_input": "ゲートウェイIP", @@ -143,7 +143,7 @@ "use_adguard_browsing_sec_hint": "AdGuard Homeは、ブラウジング・セキュリティ・ウェブサービスによってドメインがブロックされているかを確認します。 確認は、プライバシーに配慮したルックアップAPIを使用して行います(ドメイン名のSHA256ハッシュの短いプレフィックスのみがサーバーに送信されます)。", "use_adguard_parental": "AdGuardペアレンタルコントロール・ウェブサービスを使用する", "use_adguard_parental_hint": "AdGuard Homeは、ドメインにアダルトコンテンツが含まれているかどうかを確認します。 ブラウジングセキュリティ・ウェブサービスと同じプライバシーに優しいAPIを使用します。", - "enforce_safe_search": "セーフサーチを強制する", + "enforce_safe_search": "セーフサーチを使用する", "enforce_save_search_hint": "AdGuard Homeは、次の検索エンジンでセーフサーチを強制適用します: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay", "no_servers_specified": "サーバが指定されていません", "general_settings": "一般設定", @@ -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リスト", @@ -196,25 +196,25 @@ "choose_allowlist": "許可リストの選択", "enter_valid_blocklist": "ブロックリストへ有効なURLを入力してください。", "enter_valid_allowlist": "許可リストへ有効なURLを入力してください。", - "form_error_url_format": "URLフォーマットが間違っています", + "form_error_url_format": "URLフォーマットが無効です", "form_error_url_or_path_format": "リストのURLまたは絶対パスが無効です", "custom_filter_rules": "カスタム・フィルタリングルール", "custom_filter_rules_hint": "1つの行に1つのルールを入力してください。 広告ブロックルールやhostsファイル構文を使用できます。", "system_host_files": "システムのhostsファイル", "examples_title": "例", - "example_meaning_filter_block": "example.orgドメインとそのすべてのサブドメインへのアクセスをブロックする", - "example_meaning_filter_whitelist": "example.orgドメインとそのすべてのサブドメインへのアクセスのブロックを解除する", + "example_meaning_filter_block": "example.orgドメインとそのすべてのサブドメインへのアクセスをブロックします。", + "example_meaning_filter_whitelist": "example.orgドメインとそのすべてのサブドメインへのアクセスのブロックを解除します。", "example_meaning_host_block": "AdGuard Homeは、example.orgドメイン(サブドメインを除く)に対して127.0.0.1のアドレスを返すようになります。", - "example_comment": "! ここにはコメントが入ります", - "example_comment_meaning": "ただのコメントです", - "example_comment_hash": "# ここもコメントです", - "example_regex_meaning": "指定の正規表現に一致するドメインへのアクセスをブロックします", - "example_upstream_regular": "通常の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 Stamps を使えます", - "example_upstream_tcp": "通常のDNS(TCPでの問い合わせ)", + "example_comment": "! コメント本文", + "example_comment_meaning": "コメントが入ります。", + "example_comment_hash": "# これもコメントです", + "example_regex_meaning": "指定の正規表現に一致するドメインへのアクセスをブロックします。", + "example_upstream_regular": "通常の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)。", "all_lists_up_to_date_toast": "すべてのリストは既に最新です", "updated_upstream_dns_toast": "上流DNSサーバを保存しました。", "dns_test_ok_toast": "指定されたDNSサーバは正しく動作しています", @@ -259,7 +259,7 @@ "query_log_strict_search": "完全一致検索には二重引用符を使用します", "query_log_retention_confirm": "クエリ・ログの保持を変更してもよろしいですか? 期間を短くすると、一部のデータが失われます", "anonymize_client_ip": "クライアントIPを匿名化する", - "anonymize_client_ip_desc": "ログと統計にクライアントの完全なIPアドレスを保存しない", + "anonymize_client_ip_desc": "ログと統計にクライアントのフルPアドレスを保存しません。", "dns_config": "DNSサーバ設定", "dns_cache_config": "DNSキャッシュ設定", "dns_cache_config_desc": "ここでDNSキャッシュを設定できます。", @@ -275,9 +275,9 @@ "dns_over_https": "DNS-over-HTTPS", "dns_over_tls": "DNS-over-TLS", "dns_over_quic": "DNS-over-QUIC", - "client_id": "Client ID(クライアントID)", - "client_id_placeholder": "クライアントIDを入力してください", - "client_id_desc": "それぞれのクライアントは、特別なクライアントIDで識別できます。 ここでは、クライアントを特定する方法について詳しく知ることができます。", + "client_id": "ClientID(クライアントID)", + "client_id_placeholder": "ClientIDを入力してください", + "client_id_desc": "それぞれのクライアントは、ClinetIDで識別できます。 こちらでは、クライアントを識別する方法について詳しく知ることができます。", "download_mobileconfig_doh": "DNS-over-HTTPS用の .mobileconfig をダウンロード", "download_mobileconfig_dot": "DNS-over-TLS用の .mobileconfig をダウンロード", "download_mobileconfig": "設定ファイルをダウンロードする", @@ -334,11 +334,11 @@ "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_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": "「次のDNSサーバーアドレスを使う」を選択して、お使いのAdGuard Homeサーバーアドレスを入力します。", - "install_devices_macos_list_1": "Apple アイコンをクリックして「システム環境設定」へ行きます。", + "install_devices_macos_list_1": "Apple アイコンをクリックして「システム環境設定」へ移動します。", "install_devices_macos_list_2": "「ネットワーク」をクリックします。", "install_devices_macos_list_3": "一覧の最初の接続を選択して「詳細...」をクリックします。", "install_devices_macos_list_4": "「DNS」タブを選択して、AdGuard Homeサーバのアドレスを入力します。", @@ -356,7 +356,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": "ドメイン名を入力してください", @@ -367,7 +367,7 @@ "encryption_https_desc": "HTTPSポートが設定されていると、AdGuard Home 管理インターフェースはHTTPS経由でアクセス可能になり、そして「/dns-query」の場所にDNS-over-HTTPSも提供されます。", "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}} で入手できます。または、信頼できる認証局のいずれかから購入することもできます。", @@ -378,10 +378,10 @@ "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_valid": "証明書チェーンは有効です。", "encryption_chain_invalid": "証明書チェーンは無効です", - "encryption_key_valid": "これは有効な{{type}}秘密鍵です", - "encryption_key_invalid": "これは無効な{{type}}秘密鍵です", + "encryption_key_valid": "これは有効な{{type}}プライベートキーです。", + "encryption_key_invalid": "これは無効な{{type}}プライベートキーです", "encryption_subject": "件名", "encryption_issuer": "発行者", "encryption_hostnames": "ホスト名", @@ -389,15 +389,15 @@ "topline_expiring_certificate": "SSL証明書は期限切れになります。<0>暗号化設定を更新します。", "topline_expired_certificate": "SSL証明書は期限切れです。<0>暗号化設定を更新します。", "form_error_port_range": "80〜65535 の範囲でポート番号を入力してください", - "form_error_port_unsafe": "これは危険なポートです", + "form_error_port_unsafe": "これは不安全なポートです", "form_error_equal": "同じ値であってはなりません", - "form_error_password": "パスワードが不一致です", + "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プロバイダの一覧です。", @@ -405,8 +405,8 @@ "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": "クライアント", @@ -417,7 +417,7 @@ "client_edit": "クライアントの編集", "client_identifier": "識別子", "ip_address": "IPアドレス", - "client_identifier_desc": "クライアントは、IPアドレス、CIDR、MACアドレス、または特別なクライアントID(DoT/DoH/DoQで使用可能)によって識別することができます。<0>ここでは、クライアントの識別方法についてより詳しくご確認いただけます。", + "client_identifier_desc": "クライアントは、IPアドレス、CIDR、MACアドレス、またはClientID(DoT/DoH/DoQに使用可能)によって識別することができます。<0>こちらにて、クライアントの識別方法についてより詳しくご確認いただけます。", "form_enter_ip": "IPアドレスを入力してください", "form_enter_subnet_ip": "サブネット「{{cidr}}」内のIPアドレスを入力してください", "form_enter_mac": "MACアドレスを入力してください", @@ -432,14 +432,14 @@ "clients_not_found": "クライアント情報はありません", "client_confirm_delete": "クライアント \"{{key}}\" を削除してもよろしいですか?", "list_confirm_delete": "このリストを削除してもよろしいですか?", - "auto_clients_title": "クライアント(実行時)", - "auto_clients_desc": "AdGuard Homeで使用しているが設定に保存されていないクライアント上のデータ", + "auto_clients_title": "ランタイムクライアント", + "auto_clients_desc": "永続的クライアントのリストに未登録で、AdGuard Homeを使用する場合があるデバイスのリスト。", "access_title": "アクセス設定", "access_desc": "ここで、AdGuard Home DNSサーバのアクセスルールを設定できます。", "access_allowed_title": "許可されたクライアント", - "access_allowed_desc": "CIDR、IPアドレス、またはクライアントIDのリスト。設定されている場合、AdGuard HomeはこれらのIPアドレスからのリクエストのみを受け入れます。", + "access_allowed_desc": "CIDR、IPアドレス、またはClientIDのリスト。このリストに入力がある場合、AdGuard Homeはリストに入っているクライアントからのみリクエストを受け入れます。", "access_disallowed_title": "拒否するクライアント", - "access_disallowed_desc": "CIDR、IPアドレス、またはクライアントIDのリスト。設定されている場合、AdGuard HomeはこれらのIPアドレスからのリクエストを破棄します。「許可されたクライアント」欄が設定されている場合、この欄は無視されます。", + "access_disallowed_desc": "CIDR、IPアドレス、またはClientIDのリスト。リストに入力がある場合、AdGuard Homeはリストに入力されているクライアントからのリクエストを破棄します。※「許可されたクライアント」リストに入力項目がある場合、この「拒否するクライアント」設定は無視されます。", "access_blocked_title": "拒否するドメイン", "access_blocked_desc": "こちらをフィルタと混同しないでください。AdGuard Homeは、ここで入力されたドメインに一致するDNSクエリをドロップし、そういったクエリはクエリログにも表示されません。ここでは、「example.org」、「*.example.org」、「 ||example.org^ 」など、特定のドメイン名、ワイルドカード、URLフィルタルールを入力できます。", "access_settings_saved": "アクセス設定の保存に成功しました", @@ -475,8 +475,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": "特定のサービスをブロックする", @@ -507,7 +507,7 @@ "filter_updated": "フィルタの更新に成功しました", "statistics_configuration": "統計設定", "statistics_retention": "統計保持", - "statistics_retention_desc": "期間を短くすると、一部のデータが失われます", + "statistics_retention_desc": "※保持期間を短くすると、一部のデータが失われます。", "statistics_clear": "統計を消去する", "statistics_clear_confirm": "統計を消去してもよろしいですか?", "statistics_retention_confirm": "統計の保持を変更してもよろしいですか? 期間を短くすると、一部のデータが失われます", @@ -532,7 +532,7 @@ "netname": "ネットワーク名", "network": "ネットワーク", "descr": "説明", - "whois": "Whois", + "whois": "WHOIS", "filtering_rules_learn_more": "独自ホストリストの作成についての<0>詳細はこちら。", "blocked_by_response": "応答されたCNAMEかIPアドレスによるブロック", "blocked_by_cname_or_ip": "CNAMEもしくはIPアドレスによってブロック済み", @@ -552,10 +552,10 @@ "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>詳細", + "tags_desc": "クライアントに対応するタグを選択できます。フィルタリングルールにタグを含めることで、ルールをより正確に適用できます。 <0>詳細はこちら", "form_select_tags": "クライアントのタグを選択する", "check_title": "フィルタのチェック", - "check_desc": "ホスト名がフィルタで処理されるかをチェックします", + "check_desc": "ホスト名がフィルタリングされているかを確認できます。", "check": "チェックする", "form_enter_host": "ホスト名を入力してください", "filtered_custom_rules": "カスタム・フィルタリングルールによる処理されました", @@ -604,9 +604,9 @@ "enter_cache_size": "キャッシュサイズ(バイト単位)を入力してください", "enter_cache_ttl_min_override": "最小TTL(秒単位)を入力してください", "enter_cache_ttl_max_override": "最大TTL(秒単位)を入力してください", - "cache_ttl_min_override_desc": "DNS応答をキャッシュするとき、上流サーバから受信した短いTTL(秒単位)を延長します", - "cache_ttl_max_override_desc": "DNSキャッシュ内のエントリの最大TTL(秒単位)を設定します", - "ttl_cache_validation": "最小キャッシュTTL値は最大値以下にする必要があります", + "cache_ttl_min_override_desc": "DNS応答をキャッシュするとき、上流サーバから受信した短いTTL(秒単位)を延長します。", + "cache_ttl_max_override_desc": "DNSキャッシュ内のエントリの最大TTL(秒単位)を設定します。", + "ttl_cache_validation": "最小キャッシュTTL上書きは最大値以下にする必要があります", "cache_optimistic": "Optimistic cashing (オプティミスティック・キャッシュ)", "cache_optimistic_desc": "エントリの有効期限が切れた場合でも、AdGuard Homeがキャッシュから応答するようにし、エントリの更新も試みます。", "filter_category_general": "一般", @@ -624,9 +624,9 @@ "adg_will_drop_dns_queries": "AdGuard Homeは、このクライアントからすべてのDNSクエリを落とします。", "filter_allowlist": "【注意】このアクションは、許可されたクライアントのリストから「{{disallowed_rule}}」というルールも除外します。", "last_rule_in_allowlist": "ルール「{{disallowed_rule}}」を除外すると「許可されたクライアント」リストが無効になるため、このクライアントを拒否することはできません。", - "experimental": "実験用", "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/ko.json b/client/src/__locales/ko.json index ba40f48c..ff52d178 100644 --- a/client/src/__locales/ko.json +++ b/client/src/__locales/ko.json @@ -1,7 +1,7 @@ { "client_settings": "클라이언트 설정", - "example_upstream_reserved": "<0>특정 도메인에 대한 DNS 업스트림을 지정할 수 있습니다.", - "example_upstream_comment": "설명을 맞춤 지정할 수 있습니다.", + "example_upstream_reserved": "<0>특정 도메인에 대한 업스트림;", + "example_upstream_comment": "댓글.", "upstream_parallel": "쿼리 처리 속도를 높이려면 모든 업스트림 서버에서 동시에 병렬 쿼리를 사용해주세요.", "parallel_requests": "병렬 처리 요청", "load_balancing": "로드 밸런싱", @@ -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": "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 주소 범위", @@ -133,7 +133,7 @@ "number_of_dns_query_blocked_24_hours": "광고 차단 필터 및 호스트 차단 목록에 의해 차단된 DNS 요청 수", "number_of_dns_query_blocked_24_hours_by_sec": "AdGuard 브라우징 보안 모듈에 의해 차단된 DNS 요청 수", "number_of_dns_query_blocked_24_hours_adult": "차단된 성인 웹 사이트의 수", - "enforced_save_search": "세이프 서치 강제", + "enforced_save_search": "세이프서치 강제", "number_of_dns_query_to_safe_search": "세이프서치가 적용된 검색 엔진에 대해 DNS 요청 수", "average_processing_time": "평균처리 시간", "average_processing_time_hint": "DNS 요청 처리시 평균 시간(밀리초)", @@ -196,25 +196,25 @@ "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": "시스템 호스트 파일", "examples_title": "예시", - "example_meaning_filter_block": "example.org 을 포함한 모든 서브 도메인 접근을 차단합니다", + "example_meaning_filter_block": "example.org 및 모든 하위 도메인에 대한 접근 차단;", "example_meaning_filter_whitelist": "example.org 을 포함한 모든 서브 도메인 접근을 차단 해제합니다.", - "example_meaning_host_block": "AdGuard Home은 example.org 접속 시 127.0.0.1으로 이동합니다. (서브 도메인은 포함되지 않습니다)", - "example_comment": "! 여기는 주석이 올 수 있습니다", - "example_comment_meaning": "말 그대로의 의미입니다", - "example_comment_hash": "# 이것 또한 주석입니다", - "example_regex_meaning": "<0>특정 정규 표현식에 맞는 도메인 접근을 차단합니다", - "example_upstream_regular": "사용자 지정 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_meaning_host_block": "example.org에 대해 127.0.0.1로 응답합니다 (하위 도메인은 아님);", + "example_comment": "! 댓글을 추가하는 방법", + "example_comment_meaning": "이것은 단지 댓글입니다;", + "example_comment_hash": "# 이것 또한 댓글입니다.", + "example_regex_meaning": "특정 정규 표현식에 맞는 도메인 접근을 차단합니다.", + "example_upstream_regular": "일반 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를 통한 접속);", "all_lists_up_to_date_toast": "모든 리스트가 이미 최신입니다", "updated_upstream_dns_toast": "업스트림 서버가 성공적으로 저장되었습니다", "dns_test_ok_toast": "특정 DNS 서버들은 정상적으로 동작 중입니다", @@ -262,7 +262,7 @@ "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", @@ -275,9 +275,9 @@ "dns_over_https": "DNS-over-HTTPS", "dns_over_tls": "DNS-over-TLS", "dns_over_quic": "DNS-over-QUIC", - "client_id": "클라이언트 ID", - "client_id_placeholder": "클라이언트 ID 입력", - "client_id_desc": "클라이언트는 특별한 클라이언트 ID를 기반으로 구분됩니다. 여기에서 클라이언트를 구분하는 방법을 자세히 알아보세요.", + "client_id": "ClientID", + "client_id_placeholder": "ClientID 입력", + "client_id_desc": "클라이언트는 ClientID로 식별할 수 있습니다. 여기에서 클라이언트를 식별하는 방법을 자세히 알아보세요.", "download_mobileconfig_doh": "DNS-over-HTTPS용 .mobileconfig 다운로드", "download_mobileconfig_dot": "DNS-over-TLS용 .mobileconfig 다운로드", "download_mobileconfig": "설정 파일 내려받기", @@ -309,7 +309,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,7 +334,7 @@ "install_devices_router_list_4": "일부 라우터 유형에서는 사용자 정의 DNS 서버를 설정할 수 없습니다. 이 경우에는 AdGuard Home을 <0>DHCP 서버로 설정할 수 있습니다. 그렇지 않으면 특정 라우터 모델에 맞게 DNS 서버를 설정하는 방법을 찾아야 합니다.", "install_devices_windows_list_1": "시작 메뉴 또는 윈도우 검색을 통해 제어판을 엽니다.", "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": "목록에서 '인터넷 프로토콜 버전 4(TCP/IP)' (또는 IPv6의 경우 '인터넷 프로토콜 버전 6(TCP/IPv6)')를 찾아 선택하고 속성을 클릭합니다.", "install_devices_windows_list_6": "'DNS 서버 주소 사용'을 선택하고 AdGuard Home 서버 주소 입력합니다.", @@ -356,7 +356,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": "도메인 이름을 입력하세요.", @@ -367,7 +367,7 @@ "encryption_https_desc": "HTTPS 포트가 구성되면 HTTPS를 통해 AdGuard Home 관리자 인터페이스에 액세스할 수 있으며, '/dns-query' 위치에 DNS-over-HTTPS도 제공합니다.", "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}}에서 무료 증명서를 받을 수도 있고, 신뢰할 수있는 인증 기관에서 구입할 수 있습니다.", @@ -378,26 +378,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 공급자 목록입니다.", @@ -405,8 +405,8 @@ "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": "클라이언트", @@ -417,7 +417,7 @@ "client_edit": "클라이언트 수정", "client_identifier": "식별자", "ip_address": "IP 주소", - "client_identifier_desc": "클라이언트는 IP 주소, CIDR, MAC 주소 또는 특수 클라이언트 ID로 식별할 수 있습니다 (DoT/DoH/DoQ에 사용 가능). <0>여기에서 클라이언트를 식별하는 방법에 대한 자세한 내용은 확인하실 수 있습니다.", + "client_identifier_desc": "클라이언트는 IP 주소, CIDR, MAC 주소 또는 ClientID(DoT/DoH/DoQ에 사용 가능)로 식별할 수 있습니다. <0>여기에서 클라이언트를 식별하는 방법에 대한 자세한 내용은 확인하실 수 있습니다.", "form_enter_ip": "IP 입력", "form_enter_subnet_ip": "서브넷 \"{{cidr}}\" 내의 IP 주소 입력", "form_enter_mac": "MAC 입력", @@ -432,14 +432,14 @@ "clients_not_found": "클라이언트 없음", "client_confirm_delete": "정말 클라이언트 \"{{key}}\" 삭제하시겠습니까?", "list_confirm_delete": "정말로 이 목록을 제거하시겠습니까?", - "auto_clients_title": "클라이언트 (런타임)", - "auto_clients_desc": "AdGuard Home을 사용하지만 구성에 저장되지 않은 클라이언트의 데이터입니다.", + "auto_clients_title": "런타임 클라이언트", + "auto_clients_desc": "AdGuard Home을 계속 사용할 수 있는 영구 클라이언트 목록에 없는 디바이스입니다.", "access_title": "접근 설정", "access_desc": "여기에서 AdGuard Home DNS 서버에 대한 액세스 규칙을 구성할 수 있습니다.", "access_allowed_title": "허용된 클라이언트", - "access_allowed_desc": "CIDR, IP 주소 또는 클라이언트 ID 목록입니다. 허용된 클라이언트가 구성된 경우, AdGuard Home은 이 클라이언트의 요청만 수락합니다.", + "access_allowed_desc": "CIDR, IP 주소 또는 ClientID 목록입니다. 이 목록에 항목이 있는 경우, AdGuard Home은 이러한 클라이언트의 요청만 수락합니다.", "access_disallowed_title": "차단된 클라이언트", - "access_disallowed_desc": "CIDR, IP 주소 또는 클라이언트 ID 목록입니다. 차단된 클라이언트가 구성된 경우, AdGuard Home은 이 클라이언트의 요청을 무시합니다. 허용된 클라이언트가 구성된 경우, 이 필드는 무시됩니다.", + "access_disallowed_desc": "CIDR, IP 주소 또는 ClientID 목록입니다. 이 목록에 항목이 있는 경우, AdGuard Home은 이러한 클라이언트의 요청을 무시합니다. 허용된 클라이언트에 항목이 있는 경우, 이 필드는 무시됩니다.", "access_blocked_title": "차단된 도메인", "access_blocked_desc": "이 기능을 필터와 혼동하지 마세요. AdGuard Home은 이 도메인에 대한 DNS 요청을 무시합니다. 여기에서는 'example.org' '*. example.org', '|| example.org ^'와 같은 특정 도메인 이름, 와일드 카드, URL 필터 규칙을 지정할 수 있습니다.", "access_settings_saved": "액세스 설정이 성공적으로 저장되었습니다.", @@ -475,7 +475,7 @@ "dns_rewrites": "DNS 변경", "form_domain": "도메인 이름 또는 와일드카드를 입력합니다", "form_answer": "IP 주소 또는 도메인 이름을 입력하세요", - "form_error_domain_format": "도메인 형식이 잘못되었습니다", + "form_error_domain_format": "도메인 형식이 잘못되었습니다.", "form_error_answer_format": "답변 형식이 잘못되었습니다. ", "configure": "설정하기", "main_settings": "기본 설정", @@ -507,7 +507,7 @@ "filter_updated": "필터가 성공적으로 업데이트됨", "statistics_configuration": "통계 구성", "statistics_retention": "통계 저장 기간", - "statistics_retention_desc": "값을 줄이면 설정한 값보다 오래된 데이터가 소멸됩니다.", + "statistics_retention_desc": "간격 값을 줄이면 일부 데이터가 손실됩니다.", "statistics_clear": "통계 초기화", "statistics_clear_confirm": "통계를 정말로 초기화하시겠습니까?", "statistics_retention_confirm": "정말로 통계 저장 기간을 변경하시겠습니까? 저장 주기를 낮출 경우, 일부 데이터가 손실됩니다", @@ -532,7 +532,7 @@ "netname": "네트워크 이름", "network": "네트워크", "descr": "설명", - "whois": "후이즈", + "whois": "WHOIS", "filtering_rules_learn_more": "차단 리스트를 직접 호스트하는 법을 <0>알아보세요.", "blocked_by_response": "응답 중 차단된 CNAME 또는 IP", "blocked_by_cname_or_ip": "CNAME 또는 IP에 의해 차단됨", @@ -552,10 +552,10 @@ "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>자세히 알아보기", + "tags_desc": "클라이언트에 해당하는 태그를 선택할 수 있습니다. 필터링 규칙에 태그를 포함시키면 더 정확하게 적용시킬 수 있습니다. <0>자세히 알아보기.", "form_select_tags": "클라이언트 태그 선택", "check_title": "필터링 확인", - "check_desc": "호스트 이름이 필터링되는지 확인", + "check_desc": "호스트 이름이 필터링되는지 확인합니다.", "check": "확인", "form_enter_host": "호스트 이름을 입력해주세요", "filtered_custom_rules": "사용자 정의 필터링 규칙으로 필터링됨", @@ -598,14 +598,14 @@ "blocklist": "차단 목록", "milliseconds_abbreviation": "ms", "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 값(최소)을 무시합니다", - "cache_ttl_max_override_desc": "업스트림 서버에서 수신한 TTL 값(최대)을 무시합니다", + "cache_ttl_min_override_desc": "DNS 응답을 캐싱할 때 업스트림 서버에서 수신한 짧은 TTL 값(초)을 확장합니다.", + "cache_ttl_max_override_desc": "DNS 캐시의 항목에 대한 최대 TTL 값(초)을 설정합니다.", "ttl_cache_validation": "최소 캐시 TTL 값은 최대 값보다 이하여야 합니다", "cache_optimistic": "옵티미스틱 캐시", "cache_optimistic_desc": "세션이 만료되었거나 새로고침을 시도하는 경우에도 AdGuard Home이 캐시를 기반으로 응답하도록 합니다.", @@ -624,9 +624,9 @@ "adg_will_drop_dns_queries": "AdGuard Home은 이 클라이언트에서 모든 DNS 쿼리를 삭제합니다.", "filter_allowlist": "경고: 이 경우 허용된 클라이언트 목록에서 '{{disallowed_rule}}' 규칙 또한 제외됩니다.", "last_rule_in_allowlist": "'{{disallowed_rule}}' 규칙을 제외하면 '허용된 클라이언트' 목록이 꺼지므로 해당 클라이언트를 제외할 수 없습니다.", - "experimental": "실험", "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/nl.json b/client/src/__locales/nl.json index b6933045..36478928 100644 --- a/client/src/__locales/nl.json +++ b/client/src/__locales/nl.json @@ -1,7 +1,7 @@ { "client_settings": "Cliëntinstellingen", - "example_upstream_reserved": "Je kan een DNS-upstream opgeven <0>voor specifieke domein(en)", - "example_upstream_comment": "Je kan je commentaar specifiëren", + "example_upstream_reserved": "een upstream <0>voor specifieke domeinen;", + "example_upstream_comment": "een commentaar.", "upstream_parallel": "Parallelle verzoeken gebruiken om te versnellen door gelijktijdig verzoeken te sturen naar alle upstream servers.", "parallel_requests": "Parallelle verzoeken", "load_balancing": "Volume balanceren", @@ -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", @@ -165,10 +165,10 @@ "enabled_filtering_toast": "Filters ingeschakeld", "disabled_safe_browsing_toast": "Veilig browsen uitgeschakeld", "enabled_safe_browsing_toast": "Veilig browsen ingeschakeld", - "disabled_parental_toast": "Ouderlijk toezicht uitgeschakeld", - "enabled_parental_toast": "Ouderlijk toezicht ingeschakeld", - "disabled_safe_search_toast": "Veilig zoeken uitgeschakeld", - "enabled_save_search_toast": "Veilig zoeken ingeschakeld", + "disabled_parental_toast": "Uitgeschakeld ouderlijk toezicht", + "enabled_parental_toast": "Ingeschakeld Ouderlijk toezicht", + "disabled_safe_search_toast": "Uitgeschakeld Veilig zoeken", + "enabled_save_search_toast": "Ingeschakeld Veilig zoeken", "enabled_table_header": "Ingeschakeld", "name_table_header": "Naam", "list_url_table_header": "URL lijst", @@ -196,25 +196,25 @@ "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 formaat", - "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", "examples_title": "Voorbeelden", - "example_meaning_filter_block": "blokkeer toegang tot het example.org domein en alle subdomeinen", - "example_meaning_filter_whitelist": "deblokkering van toegang tot het example.org-domein en alle bijbehorende subdomeinen", - "example_meaning_host_block": "AdGuard Home zal nu het adres 127.0.0.1 voor het domein example.org retourneren (maar niet de subdomeinen).", - "example_comment": "! Hier komt een opmerking", - "example_comment_meaning": "zomaar een opmerking", - "example_comment_hash": "# Nog een opmerking", - "example_regex_meaning": "blokkeer de toegang tot de domeinen die overeenkomen met de opgegeven reguliere expressie", - "example_upstream_regular": "standaard DNS (over UDP)", - "example_upstream_dot": "versleutelde <0>DNS-via-TLS", - "example_upstream_doh": "versleutelde <0>DNS-via-HTTPS", - "example_upstream_doq": "versleutelde <0>DNS-via-QUIC", - "example_upstream_sdns": "je kunt <0>DNS Stamps voor <1>DNSCrypt of <2>DNS-via-HTTPS oplossingen gebruiken", - "example_upstream_tcp": "standaard DNS (over TCP)", + "example_meaning_filter_block": "blokkeer toegang tot example.org en alle subdomeinen ervan;", + "example_meaning_filter_whitelist": "deblokkeer toegang tot example.org en alle subdomeinen ervan;", + "example_meaning_host_block": "127.0.0.1 voor het domein example.org retourneren (maar niet diens subdomeinen);", + "example_comment": "! Hier komt een opmerking.", + "example_comment_meaning": "zomaar een opmerking;", + "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_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);", "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 +259,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", @@ -275,9 +275,9 @@ "dns_over_https": "DNS-via-HTTPS", "dns_over_tls": "DNS-via-TLS", "dns_over_quic": "DNS-via-QUIC", - "client_id": "Apparaat-ID", - "client_id_placeholder": "Apparaat-ID invoeren", - "client_id_desc": "Verschillende apparaten kunnen worden geïdentificeerd door hun specifiek apparaat-ID. Hier vind je meer informatie over het identificeren van apparaten.", + "client_id": "Client-ID", + "client_id_placeholder": "Client-ID invoeren", + "client_id_desc": "Clients kunnen worden geïdentificeerd door hun Client-ID. Hier vind je meer informatie over het identificeren van clienten.", "download_mobileconfig_doh": ".mobileconfig voor DNS-via-HTTPS downloaden", "download_mobileconfig_dot": ".mobileconfig voor DNS-via-TLS downloaden", "download_mobileconfig": "Configuratiebestand downloaden", @@ -309,7 +309,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": "Geldige poortwaarde 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", @@ -334,8 +334,8 @@ "install_devices_router_list_4": "Je kan een DNS-server niet instellen op sommige routers. In dat geval kan het een oplossing zijn om AdGuard Home te definiëren als een <0>DHCP-server. Je kan ook in de handleiding van je router kijken hoe je een DNS-server aanpast.", "install_devices_windows_list_1": "Open het Configuratiescherm via het menu Start of Windows zoeken.", "install_devices_windows_list_2": "Ga naar de categorie Netwerk en Internet en vervolgens naar Netwerkcentrum.", - "install_devices_windows_list_3": "Zoek aan de linkerkant van het scherm \"Adapter-instellingen wijzigen\" en klik erop.", - "install_devices_windows_list_4": "Selecteer jouw actieve verbinding, klik er met de rechtermuisknop op en kies Eigenschappen.", + "install_devices_windows_list_3": "Aan de linkerkant van het scherm, klik op \"Adapter-instellingen wijzigen\".", + "install_devices_windows_list_4": "Klik met de rechtermuisknop op jouw actieve verbinding en kies Eigenschappen.", "install_devices_windows_list_5": "Zoek \"Internet Protocol versie 4 (TCP/IPv4)\" (of, voor IPv6, \"Internet Protocol versie 6 (TCP/IPv6)\") in de lijst, selecteer het en klik vervolgens opnieuw op Eigenschappen.", "install_devices_windows_list_6": "Kies \"Gebruik de volgende DNS-serveradressen\" en voer jouw AdGuard Home serveradressen in.", "install_devices_macos_list_1": "Klik op het Apple-pictogram en ga naar Systeemvoorkeuren.", @@ -356,7 +356,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", @@ -367,7 +367,7 @@ "encryption_https_desc": "Als de HTTPS-poort is geconfigureerd, is de AdGuard Home beheerders interface toegankelijk via HTTPS en biedt deze ook DNS-via-HTTPS op de locatie '/ dns-query'.", "encryption_dot": "DNS-via-TLS poort", "encryption_dot_desc": "Indien deze poort is geconfigureerd, zal AdGuard Home gebruik maken van een DNS-via-TLS server via deze poort.", - "encryption_doq": "DNS-via-QUIC poort", + "encryption_doq": "DNS-via-QUIC poort (experimenteel)", "encryption_doq_desc": "Als deze poort is geconfigureerd, zal AdGuard Home een DNS-via-QUIC server gebruiken via deze poort. Dit is experimenteel en kan onbetrouwbaar zijn. Er zijn overigens nog niet veel systemen die dit nu al ondersteunen.", "encryption_certificates": "Certificaten", "encryption_certificates_desc": "Om encryptie te gebruiken, moet u een geldige SSL certificaat voor uw domein opgeven. U kunt een gratis certificaat krijgen op <0> {{link}} of u kunt het kopen bij een van de vertrouwde certificaatautoriteiten.", @@ -378,26 +378,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 geldig {{type}} privé sleutel", - "encryption_key_invalid": "Dit is een ongeldig {{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": "Poort nummer 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": "Dit is een 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 oproepen 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.", @@ -405,8 +405,8 @@ "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", - "clients_title": "Gebruikers", - "clients_desc": "Configureer apparaten die gebruik maken van AdGuard Home", + "clients_title": "Permanente clients", + "clients_desc": "Permanente client-records configureren voor apparaten verboden met AdGuard Home.", "settings_global": "Globaal", "settings_custom": "Aangepast", "table_client": "Gebruiker", @@ -417,7 +417,7 @@ "client_edit": "Wijzig gebruiker", "client_identifier": "Identificeer via", "ip_address": "IP adres", - "client_identifier_desc": "Apparaten kunnen worden geïdentificeerd door hun IP-adres, CIDR, MAC-adres of een speciaal apparaat-ID (kan gebruikt worden voor DoT/DoH/DoQ). <0>Hier kan je meer lezen over het identificeren van apparaten.", + "client_identifier_desc": "Cliënten kunnen worden geïdentificeerd door hun IP-adres, CIDR, MAC-adres of Client-ID (kan gebruikt worden voor DoT/DoH/DoQ). <0>Hier kan je meer lezen over het identificeren van cliënten.", "form_enter_ip": "Vul IP in", "form_enter_subnet_ip": "Voer een IP-adres in voor het subnet “{{cidr}}”", "form_enter_mac": "Vul MAC in", @@ -432,14 +432,14 @@ "clients_not_found": "Geen gebruikers gevonden", "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": "Gebruikers (runtime)", - "auto_clients_desc": "Data over gebruikers die AdGuard Home gebruiken, maar niet geconfigureerd zijn", + "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.", "access_title": "Toegangs instellingen", "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_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", - "access_disallowed_desc": "Een lijst met CIDR's, IP-adressen of client-ID's. Indien geconfigureerd, zal AdGuard Home verzoeken van deze klanten verwerpen. Als toegestane cliënts zijn geconfigureerd, wordt dit veld genegeerd.", + "access_disallowed_desc": "Een lijst met CIDR's, IP-adressen of Client-ID's. Indien geconfigureerd, zal AdGuard Home verzoeken van deze klanten verwerpen. Als toegestane cliënts zijn geconfigureerd, wordt dit veld genegeerd.", "access_blocked_title": "Niet toegelaten domeinen", "access_blocked_desc": "Verwar dit niet met filters. AdGuard Home zal deze DNS-zoekopdrachten niet uitvoeren die deze domeinen in de zoekopdracht bevatten. Hier kan je de exacte domeinnamen, wildcards en URL-filter-regels specifiëren, bijv. \"example.org\", \"*.example.org\" of \"||example.org^\".", "access_settings_saved": "Toegangsinstellingen succesvol opgeslagen", @@ -475,8 +475,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 domeinnaam", - "form_error_answer_format": "Ongeldig antwoord", + "form_error_domain_format": "Ongeldige opmaak domein.", + "form_error_answer_format": "Ongeldig opmaak antwoord.", "configure": "Bewerk", "main_settings": "Algemene instellingen", "block_services": "Specifieke services blokkeren", @@ -507,7 +507,7 @@ "filter_updated": "De lijst is succesvol geüpdatet", "statistics_configuration": "Statistieken configuratie", "statistics_retention": "Statistieken retentie", - "statistics_retention_desc": "Als je de interval waarde 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", @@ -552,10 +552,10 @@ "autofix_warning_list": "De volgende taken worden uitgevoerd: <0> Deactiveren van Systeem DNSStubListener <0> DNS-serveradres instellen op 127.0.0.1 <0> Symbolisch koppelingsdoel van /etc/resolv.conf vervangen door /run/systemd/resolve/resolv.conf <0> Stop DNSStubListener (herlaad systemd-resolved service) ", "autofix_warning_result": "Als gevolg hiervan worden alle DNS-verzoeken van je systeem standaard door AdGuard Home verwerkt.", "tags_title": "Labels", - "tags_desc": "Je kunt tags selecteren die overeenkomen met de client. Tags kunnen worden opgenomen in de filterregels en je kunt ze dan nauwkeuriger toepassen. <0> Meer informatie ", + "tags_desc": "Je kunt labels selecteren die overeenkomen met de client. Labels kunnen worden opgenomen in de filterregels om ze \n nauwkeuriger toe te passen. <0>Meer informatie.", "form_select_tags": "Client tags selecteren", "check_title": "Controleer de filtering", - "check_desc": "Controleer of de hostnaam wordt gefilterd", + "check_desc": "Controleren of een hostnaam wordt gefilterd.", "check": "Controleren", "form_enter_host": "Voer een hostnaam in", "filtered_custom_rules": "Gefilterd door aangepaste filterregels", @@ -598,15 +598,15 @@ "blocklist": "Blokkeerlijst", "milliseconds_abbreviation": "ms", "cache_size": "Cache grootte", - "cache_size_desc": "DNS cache grootte (in bytes)", + "cache_size_desc": "DNS-cache grootte (in bytes).", "cache_ttl_min_override": "Minimale TTL overschrijven", "cache_ttl_max_override": "Maximale TTL overschrijven", "enter_cache_size": "Cache grootte invoeren (bytes)", "enter_cache_ttl_min_override": "Minimum TTL invoeren (seconden)", "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", + "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.", "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", @@ -624,9 +624,9 @@ "adg_will_drop_dns_queries": "AdGuard Home zal alle DNS verzoeken van deze toepassing/dit systeem negeren.", "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.", - "experimental": "Experimenteel", "use_saved_key": "De eerder opgeslagen sleutel gebruiken", "parental_control": "Ouderlijk toezicht", "safe_browsing": "Veilig browsen", - "served_from_cache": "{{value}} (geleverd vanuit cache)" + "served_from_cache": "{{value}} (geleverd vanuit cache)", + "form_error_password_length": "Wachtwoord moet minimaal {{value}} tekens lang zijn." } diff --git a/client/src/__locales/no.json b/client/src/__locales/no.json index 4bac8cee..b8f8bc63 100644 --- a/client/src/__locales/no.json +++ b/client/src/__locales/no.json @@ -544,7 +544,7 @@ "allowed": "Unntak", "filtered": "Filtrert", "rewritten": "Omskrevet", - "safe_search": "Trygge søk", + "safe_search": "Aktivert sikkert søk", "blocklist": "Blokkeringsliste", "milliseconds_abbreviation": "ms", "cache_size": "Mellomlagerstørrelse", @@ -564,14 +564,12 @@ "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", "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.", - "experimental": "Eksperimentell", "use_saved_key": "Bruk den tidligere lagrede nøkkelen", "parental_control": "Foreldrekontroll", "served_from_cache": "{{value}} (formidlet fra mellomlageret)" diff --git a/client/src/__locales/pl.json b/client/src/__locales/pl.json index 19cf6aba..253a8cac 100644 --- a/client/src/__locales/pl.json +++ b/client/src/__locales/pl.json @@ -1,7 +1,7 @@ { "client_settings": "Ustawienia klienta", - "example_upstream_reserved": "Możesz określić nadrzędny serwer DNS <0>dla określonych domen", - "example_upstream_comment": "Możesz podać komentarz", + "example_upstream_reserved": "upstream <0>dla określonych domen;", + "example_upstream_comment": "komentarz.", "upstream_parallel": "Użyj zapytań równoległych, aby przyspieszyć rozwiązywanie przez jednoczesne wysyłanie zapytań do wszystkich serwerów nadrzędnych.", "parallel_requests": "Równoległe żądania", "load_balancing": "Równoważenie obciążenia", @@ -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 jest 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": "ID klienta 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", @@ -167,8 +167,8 @@ "enabled_safe_browsing_toast": "Włączone Bezpieczne przeglądanie", "disabled_parental_toast": "Wyłączona Kontrola Rodzicielska", "enabled_parental_toast": "Włączona Kontrola Rodzicielska", - "disabled_safe_search_toast": "Bezpieczne wyszukiwanie zostało włączone", - "enabled_save_search_toast": "Bezpieczne wyszukiwanie zostało włączone", + "disabled_safe_search_toast": "Wyłączone bezpieczne wyszukiwanie", + "enabled_save_search_toast": "Włączone bezpieczne wyszukiwanie", "enabled_table_header": "Włączone", "name_table_header": "Nazwa", "list_url_table_header": "Adres URL listy", @@ -196,25 +196,25 @@ "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": "Format adresu URL jest nieprawidłowy", - "form_error_url_or_path_format": "Adres URL lub bezwzględna ścieżka listy jest nieprawidłowa", + "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", "examples_title": "Przykłady", - "example_meaning_filter_block": "zablokuj dostęp do domeny example.org i wszystkich jej subdomen", - "example_meaning_filter_whitelist": "odblokuj dostęp do domeny example.org i wszystkich jej subdomen", - "example_meaning_host_block": "AdGuard Home zwróci adres 127.0.0.1 dla domeny example.org (ale nie jej subdomen).", - "example_comment": "! Tutaj jest komentarz", - "example_comment_meaning": "komentarz", - "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_dot": "zaszyfrowany <0>DNS-over-TLS", - "example_upstream_doh": "zaszyfrowany <0>DNS-over-HTTPS", - "example_upstream_doq": "zaszyfrowany <0>DNS-over-QUIC", - "example_upstream_sdns": "możesz użyć adresu <0>DNS Stamps dla protokołu <1>DNSCrypt lub <2>DNS-over-HTTPS", - "example_upstream_tcp": "zwykły DNS (przez TCP)", + "example_meaning_filter_block": "zablokuj dostęp do domeny example.org i wszystkich jej subdomen;", + "example_meaning_filter_whitelist": "odblokuj dostęp do domeny example.org i wszystkich jej subdomen;", + "example_meaning_host_block": "odpowiedz 127.0.0.1 na example.org (ale nie dla jego subdomen);", + "example_comment": "! Tutaj jest komentarz.", + "example_comment_meaning": "komentarz;", + "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_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);", "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 +259,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", @@ -275,9 +275,9 @@ "dns_over_https": "DNS-over-HTTPS", "dns_over_tls": "DNS-over-TLS", "dns_over_quic": "DNS-over-QUIC", - "client_id": "ID klienta", - "client_id_placeholder": "Wpisz ID klienta", - "client_id_desc": "Różnych klientów można zidentyfikować za pomocą specjalnego ID klienta. Tutaj możesz dowiedzieć się więcej o tym, jak identyfikować klientów.", + "client_id": "ClientID", + "client_id_placeholder": "Wpisz ClientID", + "client_id_desc": "Klienci mogą być identyfikowani przez ClientID. Dowiedz się więcej o tym, jak identyfikować klientów tutaj.", "download_mobileconfig_doh": "Pobierz plik .mobileconfig dla DNS-over-HTTPS", "download_mobileconfig_dot": "Pobierz plik .mobileconfig dla DNS-over-TLS", "download_mobileconfig": "Pobierz plik konfiguracyjny", @@ -309,7 +309,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", @@ -334,8 +334,8 @@ "install_devices_router_list_4": "Na niektórych typach routerów nie można skonfigurować własnego serwera DNS. W takim przypadku pomocne może być skonfigurowanie AdGuard Home jako <0>serwera DHCP. W przeciwnym razie należy sprawdzić w instrukcji obsługi routera, jak dostosować serwery DNS do konkretnego modelu routera.", "install_devices_windows_list_1": "Otwórz panel Ustawienia w menu Start lub w Windows.", "install_devices_windows_list_2": "Przejdź do kategorii Sieć i Internet, a następnie do Centrum sieci i udostępniania.", - "install_devices_windows_list_3": "Po lewej stronie ekranu znajdź \"Zmień ustawienia adaptera\" i kliknij na niego.", - "install_devices_windows_list_4": "Wybierz aktywne połączenie, kliknij je prawym przyciskiem myszy i wybierz Właściwości.", + "install_devices_windows_list_3": "W lewym panelu kliknij \"Zmień ustawienia adaptera\".", + "install_devices_windows_list_4": "Kliknij prawym przyciskiem myszy aktywne połączenie i wybierz Właściwości.", "install_devices_windows_list_5": "Znajdź na liście \"Protokół internetowy w wersji 4 (TCP/IPv4)\" (lub w przypadku IPv6 \"Protokół internetowy w wersji 6 (TCP/IPv6)\"), zaznacz go i ponownie kliknij na Właściwości.", "install_devices_windows_list_6": "Wybierz opcję \"Użyj następujących adresów serwerów DNS\" i wprowadź adresy serwerów AdGuard Home.", "install_devices_macos_list_1": "Kliknij ikonę Apple i przejdź do Preferencje systemowe.", @@ -356,7 +356,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", @@ -367,7 +367,7 @@ "encryption_https_desc": "Jeśli port HTTPS jest skonfigurowany, interfejs administratora AdGuard Home będzie dostępny za pośrednictwem protokołu HTTPS i zapewni DNS przez HTTPS w lokalizacji zapytania '/dns-query'.", "encryption_dot": "Port DNS-over-TLS", "encryption_dot_desc": "Jeśli ten port jest skonfigurowany, AdGuard Home uruchomi serwer DNS-over-TLS na tym porcie.", - "encryption_doq": "Port DNS-over-QUIC", + "encryption_doq": "Port DNS-over-QUIC (eksperymentalny)", "encryption_doq_desc": "Jeśli ten port jest skonfigurowany, AdGuard Home uruchomi serwer DNS-over-QUIC na tym porcie. Jest to funkcja eksperymentalna i może nie być stabilna. Ponadto, w tej chwili nie ma zbyt wielu klientów, którzy go obsługują.", "encryption_certificates": "Certyfikaty", "encryption_certificates_desc": "Aby korzystać z szyfrowania, musisz podać prawidłowy łańcuch certyfikatów SSL dla swojej domeny. Możesz uzyskać bezpłatny certyfikat na <0>{{link}} lub możesz go kupić od jednego z zaufanych urzędów certyfikacji.", @@ -378,26 +378,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_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": "Klucz prywatny {{type}} jest nieprawidłowy", + "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": "Hasło nie pasuje", + "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.", "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 uzyskania statusu 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.", @@ -405,8 +405,8 @@ "update_failed": "Automatyczna aktualizacja nie powiodła się. Proszę wykonaj kroki aby zaktualizować ręcznie.", "manual_update": "Proszę wykonać te czynności, aby zaktualizować ręcznie.", "processing_update": "Poczekaj, trwa aktualizacja AdGuard Home", - "clients_title": "Klienci", - "clients_desc": "Skonfiguruj urządzenia podłączone do AdGuard Home", + "clients_title": "Trwali klienci", + "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", @@ -417,7 +417,7 @@ "client_edit": "Edytuj klienta", "client_identifier": "Identyfikator", "ip_address": "Adres IP", - "client_identifier_desc": "Klientów można zidentyfikować po adresie IP, CIDR, adresie MAC lub specjalnym identyfikatorze klienta (może służyć do DoT/DoH/DoQ). <0>Tutaj możesz dowiedzieć się więcej o tym, jak identyfikować klientów.", + "client_identifier_desc": "Klienci mogą być identyfikowani na podstawie ich adresu IP, CIDR, adresu MAC lub ClientID (może być używany do DoT/DoH/DoQ). Dowiedz się więcej o tym, jak identyfikować klientów <0>tutaj.", "form_enter_ip": "Wpisz adres IP", "form_enter_subnet_ip": "Wprowadź adres IP w podsieci \"{{cidr}}\"", "form_enter_mac": "Wpisz adres MAC", @@ -432,14 +432,14 @@ "clients_not_found": "Nie znaleziono klientów", "client_confirm_delete": "Czy na pewno chcesz usunąć klienta \"{{key}}\"?", "list_confirm_delete": "Czy na pewno chcesz usunąć tę listę?", - "auto_clients_title": "Klienci (czas uruchamiania)", - "auto_clients_desc": "Dane klientów, które używają AdGuard Home, ale nie są przechowywane w konfiguracji", + "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.", "access_title": "Ustawienia dostępu", "access_desc": "Tutaj możesz skonfigurować reguły dostępu dla serwera DNS AdGuard Home.", "access_allowed_title": "Dozwoleni klienci", - "access_allowed_desc": "Lista CIDR-ów, adresów IP lub identyfikatorów klientów. Jeśli zostanie skonfigurowana, AdGuard Home będzie przyjmował żądania tylko od tych klientów.", + "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", - "access_disallowed_desc": "Lista CIDR-ów, adresów IP lub identyfikatorów klientów. Jeśli jest skonfigurowana, AdGuard Home będzie odrzucał żądania od tych klientów. Jeśli skonfigurowano dozwolonych klientów, pole to jest ignorowane.", + "access_disallowed_desc": "Lista identyfikatorów CIDR, adresów IP lub identyfikatorów klienta. Jeśli ta lista zawiera wpisy, AdGuard Home odrzuci żądania od tych klientów. To pole jest ignorowane, jeśli istnieją wpisy w Dozwolonych klientach.", "access_blocked_title": "Niedozwolone domeny", "access_blocked_desc": "Nie należy ich mylić z filtrami. AdGuard Home usuwa zapytania DNS pasujące do tych domen, a zapytania te nie pojawiają się nawet w dzienniku zapytań. Możesz określić dokładne nazwy domen, symbole wieloznaczne lub reguły filtrowania adresów URL, np. \"example.org\", \"*.example.org\" lub \"||example.org^\".", "access_settings_saved": "Ustawienia dostępu zostały pomyślnie zapisane", @@ -475,8 +475,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", @@ -507,7 +507,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", @@ -532,7 +532,7 @@ "netname": "Nazwa sieci", "network": "Sieć", "descr": "Opis", - "whois": "Whois", + "whois": "WHOIS", "filtering_rules_learn_more": "<0>Dowiedz się więcej o tworzeniu własnych list blokowania hostów.", "blocked_by_response": "W odpowiedzi zablokowany przez CNAME lub IP", "blocked_by_cname_or_ip": "Zablokowany przez rekord CNAME lub adres IP", @@ -552,10 +552,10 @@ "autofix_warning_list": "Wykona następujące zadania: <0>Dezaktywuj system DNSStubListener <0>Ustaw adres serwera DNS na 127.0.0.1 <0>Zamień symboliczny cel łącza z /etc/resolv.conf na /run/systemd/resolve/resolv.conf <0>Zatrzymaj DNSStubListener (przeładuj usługę systemową)", "autofix_warning_result": "W rezultacie wszystkie żądania DNS z Twojego systemu będą domyślnie przetwarzane przez AdGuardHome.", "tags_title": "Tagi", - "tags_desc": "Możesz wybrać tagi odpowiadające klientowi. Tagi mogą być uwzględnione w regułach filtrowania i umożliwiają ich dokładniejsze stosowanie. <0>Dowiedz się więcej ", + "tags_desc": "Możesz wybrać tagi, które odpowiadają klientowi. Uwzględnij tagi w regułach filtrowania, aby zastosować je dokładniej. <0>Dowiedz się więcej.", "form_select_tags": "Wybierz tagi klienta", "check_title": "Sprawdź filtrowanie", - "check_desc": "Sprawdź, czy nazwa hosta jest filtrowana", + "check_desc": "Sprawdź, czy nazwa hosta jest filtrowana.", "check": "Sprawdź", "form_enter_host": "Wpisz nazwę hosta", "filtered_custom_rules": "Filtrowane według niestandardowych reguł filtrowania", @@ -598,15 +598,15 @@ "blocklist": "Lista zablokowanych", "milliseconds_abbreviation": "ms", "cache_size": "Rozmiar pamięci podręcznej", - "cache_size_desc": "Rozmiar pamięci podręcznej DNS (w bajtach)", + "cache_size_desc": "Rozmiar pamięci podręcznej DNS (w bajtach).", "cache_ttl_min_override": "Nadpisz minimalną wartość TTL", "cache_ttl_max_override": "Nadpisz maksymalną wartość TTL", "enter_cache_size": "Wpisz rozmiar pamięci podręcznej (w bajtach)", "enter_cache_ttl_min_override": "Wpisz minimalną wartość TTL (w sekundach)", "enter_cache_ttl_max_override": "Wpisz maksymalną wartość TTL (w sekundach)", - "cache_ttl_min_override_desc": "Zastąp wartość TTL (w sekundach) otrzymaną z serwera nadrzędnego podczas buforowania odpowiedzi DNS", - "cache_ttl_max_override_desc": "Ustaw maksymalną wartość TTL (w sekundach) dla wpisów w pamięci podręcznej DNS", - "ttl_cache_validation": "Minimalna pamięć podręczna wartości TTL musi być mniejsza lub równa maksymalnej wartości", + "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.", "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", @@ -624,9 +624,9 @@ "adg_will_drop_dns_queries": "AdGuard Home odrzuci zapytanie DNS od tego klienta.", "filter_allowlist": "OSTRZEŻENIE: To działanie spowoduje również wykluczenie reguły \"{{disallowed_rule}}\" z listy dozwolonych klientów.", "last_rule_in_allowlist": "Nie można odrzucić tego klienta, ponieważ wykluczenie reguły \"{{disallowed_rule}}\" spowoduje WYŁĄCZENIE listy „Dozwolonych klientów”.", - "experimental": "Funkcja eksperymentalna", "use_saved_key": "Użyj wcześniej zapisanego klucza", "parental_control": "Kontrola rodzicielska", "safe_browsing": "Bezpieczne przeglądanie", - "served_from_cache": "{{value}} (podawane z pamięci podręcznej)" + "served_from_cache": "{{value}} (podawane z pamięci podręcznej)", + "form_error_password_length": "Hasło musi mieć przynajmniej {{value}} znaków." } diff --git a/client/src/__locales/pt-br.json b/client/src/__locales/pt-br.json index c71e619a..56c91880 100644 --- a/client/src/__locales/pt-br.json +++ b/client/src/__locales/pt-br.json @@ -1,7 +1,7 @@ { "client_settings": "Configurações do cliente", - "example_upstream_reserved": "Você pode especificar o DNS primário <0>para o domínio(s) especifico", - "example_upstream_comment": "Você pode especificar o comentário", + "example_upstream_reserved": "um DNS primário <0>para o domínios especificos;", + "example_upstream_comment": "um comentário.", "upstream_parallel": "Usar consultas paralelas para acelerar a resolução consultando simultaneamente todos oss servidores DNS primário", "parallel_requests": "Solicitações paralelas", "load_balancing": "Balanceamento de carga", @@ -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_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 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", @@ -196,25 +196,25 @@ "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", "examples_title": "Exemplos", - "example_meaning_filter_block": "bloqueia o acesso ao domínio exemplo.org e a todos os seus subdomínios", - "example_meaning_filter_whitelist": "desbloqueia o acesso ao domínio exemplo.org e a todos os seus subdomínios", - "example_meaning_host_block": "O AdGuard Home irá retornar o endereço 127.0.0.1 para o domínio exemplo.org (exceto seus subdomínios).", - "example_comment": "! Aqui vai um comentário", - "example_comment_meaning": "apenas um comentário", - "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_dot": "<0>DNS-sobre-TLS criptografado", - "example_upstream_doh": "<0>DNS-sobre-HTTPS criptografado", - "example_upstream_doq": "<0>DNS-sobre-QUIC criptografado", - "example_upstream_sdns": "você pode usar <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_meaning_filter_block": "bloqueia o acesso ao exemplo.org e a todos os seus subdomínios;", + "example_meaning_filter_whitelist": "desbloqueia o acesso ao exemplo.org e a todos os seus subdomínios;", + "example_meaning_host_block": "responde o endereço 127.0.0.1 para o exemplo.org (exceto seus subdomínios);", + "example_comment": "! Aqui vai um comentário.", + "example_comment_meaning": "apenas um comentário;", + "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_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);", "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 +259,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 e 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", @@ -277,7 +277,7 @@ "dns_over_quic": "DNS-sobre-QUIC", "client_id": "ID do cliente", "client_id_placeholder": "Digite o ID do cliente", - "client_id_desc": "Diferentes clientes podem ser identificados por um ID de cliente especial. Aqui você pode aprender mais sobre como identificar clientes.", + "client_id_desc": "Os clientes podem ser identificados por um ID de cliente especial. Saiba mais como identificar clientes aqui.", "download_mobileconfig_doh": "BAixar .mobileconfig para DNS-sobre-HTTPS", "download_mobileconfig_dot": "BAixar .mobileconfig para DNS-sobre-TLS", "download_mobileconfig": "Baixar arquivo de configuração", @@ -309,7 +309,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", @@ -334,11 +334,11 @@ "install_devices_router_list_4": "Em alguns tipos de roteador, um servidor DNS personalizado não pode ser configurado. Nesse caso, configurar o AdGuard Home como um <0>Servidor DHCP pode ajudar. Caso contrário, você deve verificar o manual do roteador sobre como personalizar os servidores DNS em seu modelo de roteador específico.", "install_devices_windows_list_1": "Abra o Painel de Controle pelo Menu Iniciar ou pela Pesquisa do Windows.", "install_devices_windows_list_2": "Entre na categoria Rede e Internet e depois clique em Central de Rede e Compartilhamento.", - "install_devices_windows_list_3": "No lado esquerdo da janela clique em \"Alterar as configurações do adaptador\".", - "install_devices_windows_list_4": "Selecione sua atual conexão, clique nela com o botão direito do mouse e depois clique em Propriedades.", + "install_devices_windows_list_3": "No painel esquerdo, clique em \"Alterar configurações do adaptador\".", + "install_devices_windows_list_4": "Clique com o botão direito do mouse em sua conexão ativa e selecione Propriedades.", "install_devices_windows_list_5": "Procure na lista por \"Internet Protocol Version 4 (TCP/IP)\" (ou por IPv6, \"Internet Protocol Version 6 (TCP/IPv6)\"), selecione e clique em Propriedades novamente.", "install_devices_windows_list_6": "Marque \"usar os seguintes endereços de servidor DNS\" e digite os endereços do servidores do AdGuard Home.", - "install_devices_macos_list_1": "Clique na ícone da Apple e depois em Preferências do Sistema.", + "install_devices_macos_list_1": "Clique no ícone da Apple e depois em Preferências do Sistema.", "install_devices_macos_list_2": "Clique em Rede.", "install_devices_macos_list_3": "Selecione a primeira conexão da lista e clique em Avançado.", "install_devices_macos_list_4": "Selecione a guia DNS e digite os endereços dos servidores do AdGuard Home.", @@ -356,7 +356,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/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", @@ -367,7 +367,7 @@ "encryption_https_desc": "Se a porta HTTPS estiver configurada, a interface administrativa do AdGuard Home será acessível via HTTPS e também fornecerá o DNS-sobre-HTTPS no local '/dns-query'.", "encryption_dot": "Porta DNS-sobre-TLS", "encryption_dot_desc": "Se essa porta estiver configurada, o AdGuard Home irá executar o servidor DNS-sobre- TSL nesta porta.", - "encryption_doq": "Porta DNS-sobre-QUIC", + "encryption_doq": "Porta DNS-sobre-QUIC (experimental)", "encryption_doq_desc": "Se esta porta estiver configurada, o AdGuard Home executará um servidor DNS-sobre-QUIC nesta porta. É experimental e pode não ser confiável. Além disso, não há muitos clientes que ofereçam suporte no momento.", "encryption_certificates": "Certificados", "encryption_certificates_desc": "Para usar criptografia, você precisa fornecer uma cadeia de certificados SSL válida para seu domínio. Você pode obter um certificado gratuito em <0> {{link}} ou pode comprá-lo de uma das autoridades de certificação confiáveis.", @@ -379,25 +379,25 @@ "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_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": "Esta 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 obter 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.", @@ -405,8 +405,8 @@ "update_failed": "A atualização automática falhou. Por favor, siga estes passos para atualizar manualmente.", "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", - "clients_desc": "Configure dispositivos conectados ao AdGuard", + "clients_title": "Clientes persistentes", + "clients_desc": "Configure registros de cliente persistentes para dispositivos conectados ao AdGuard Home.", "settings_global": "Global", "settings_custom": "Personalizado", "table_client": "Cliente", @@ -417,7 +417,7 @@ "client_edit": "Editar cliente", "client_identifier": "Identificador", "ip_address": "Endereço de IP", - "client_identifier_desc": "Os clientes podem ser identificados pelo endereço IP, CIDR, Endereço MAC ou um ID de cliente especial (pode ser usado para DoT/DoH/DoQ). <0>Aqui você pode aprender mais sobre como identificar clientes.", + "client_identifier_desc": "Os clientes podem ser identificados pelo endereço IP, CIDR, Endereço MAC ou um ID de cliente especial (pode ser usado para DoT/DoH/DoQ). Saiba mais sobre como identificar clientes <0>aqui.", "form_enter_ip": "Digite o endereço de IP", "form_enter_subnet_ip": "Digite um endereço IP na sub-rede \"{{cidr}}\"", "form_enter_mac": "Digite o endereço MAC", @@ -432,14 +432,14 @@ "clients_not_found": "Nenhum cliente foi encontrado", "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 (tempo de execução)", - "auto_clients_desc": "Dados dos clientes que usam o AdGuard Home, que não são armazenados na configuração", + "auto_clients_title": "Clientes ativos", + "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_allowed_title": "Clientes permitidos", - "access_allowed_desc": "Uma lista de CIDRs, endereços IP ou IDs de cliente. Se configurado, o AdGuard Home do aceitará solicitações apenas desses clientes.", + "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", - "access_disallowed_desc": "Uma lista de CIDRs, endereços IP ou IDs de cliente. Se configurado, o AdGuard Home descartará as solicitações desses clientes. Se clientes permitidos estiverem configurados, este campo será ignorado.", + "access_disallowed_desc": "Uma lista de CIDRs, endereços IP ou IDs de cliente. Se essa lista tiver entradas, o AdGuard Home descartará as solicitações desses clientes. Este campo é ignorado se houver entradas em clientes permitidos.", "access_blocked_title": "Domínios bloqueados", "access_blocked_desc": "Não deve ser confundido com filtros. O AdGuard Home elimina as consultas DNS que correspondem a esses domínios, e essas consultas nem aparecem no registro de consultas. Você pode especificar nomes de domínio exatos, caracteres curinga ou regras de filtro de URL, por exemplo \"exemplo.org\", \"*.exemplo.org\", ou \"||exemplo.org^\" correspondentemente.", "access_settings_saved": "Configurações de acesso foram salvas com sucesso", @@ -475,8 +475,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", @@ -507,7 +507,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", @@ -532,7 +532,7 @@ "netname": "Nome da rede", "network": "Rede", "descr": "Descrição", - "whois": "Whois", + "whois": "WHOIS", "filtering_rules_learn_more": "<0>Saiba mais sobre como criar as suas próprias listas negras de servidores.", "blocked_by_response": "Bloqueado por CNAME ou IP na resposta", "blocked_by_cname_or_ip": "Bloqueado por CNAME ou IP", @@ -552,10 +552,10 @@ "autofix_warning_list": "Ele irá realizar estas tarefas: <0>Desativar sistema DNSStubListener <0>Definir endereço do servidor DNS para 127.0.0.1 <0>Substituir o alvo simbólico do link /etc/resolv.conf para /run/systemd/resolv.conf <0>Parar DNSStubListener (recarregar serviço resolvido pelo sistema)", "autofix_warning_result": "Como resultado, todos as solicitações DNS do seu sistema serão processadas pelo AdGuard Home por padrão.", "tags_title": "Marcadores", - "tags_desc": "Você pode selecionar as tags que correspondem ao cliente. As tags podem ser incluídas nas regras de filtragem e permitir que você as aplique com mais precisão. <0>Saiba mais", + "tags_desc": "Você pode selecionar tags que correspondam ao cliente. Inclua tags nas regras de filtragem para aplicá-las com mais precisão. <0>Saber mais.", "form_select_tags": "Selecione as tags do cliente", "check_title": "Verifique a filtragem", - "check_desc": "Verificar se o nome do host está sendo filtrado", + "check_desc": "Verificar se um nome do host está sendo filtrado.", "check": "Verificar", "form_enter_host": "Digite o nome do host", "filtered_custom_rules": "Filtrado pelas regras de filtragem personalizadas", @@ -598,15 +598,15 @@ "blocklist": "Lista de bloqueio", "milliseconds_abbreviation": "ms", "cache_size": "Tamanho do cache", - "cache_size_desc": "Tamanho do cache do DNS (em bytes)", + "cache_size_desc": "Tamanho do cache do DNS (em bytes).", "cache_ttl_min_override": "Sobrepor o TTL mínimo", "cache_ttl_max_override": "Sobrepor o TTL máximo", "enter_cache_size": "Digite o tamanho do cache (bytes)", "enter_cache_ttl_min_override": "Digite o TTL máximo (segundos)", "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 valor TTL mínimo do cache deve ser menor ou igual ao valor máximo", + "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.", "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", @@ -624,9 +624,9 @@ "adg_will_drop_dns_queries": "O AdGuard Home descartará todas as consultas DNS deste cliente.", "filter_allowlist": "AVISO: Esta ação também excluirá a regra \"{{disallowed_rule}}\" da lista de clientes permitidos.", "last_rule_in_allowlist": "Não é possível desautorizar este cliente porque excluir a regra \"{{disallowed_rule}}\" DESATIVARÁ a lista de \"Clientes permitidos\".", - "experimental": "Experimental", "use_saved_key": "Use a chave salva anteriormente", "parental_control": "Controle parental", "safe_browsing": "Navegação segura", - "served_from_cache": "{{value}} (servido do cache)" + "served_from_cache": "{{value}} (servido do cache)", + "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 0405f5c1..068ebc03 100644 --- a/client/src/__locales/pt-pt.json +++ b/client/src/__locales/pt-pt.json @@ -1,7 +1,7 @@ { "client_settings": "Definições do cliente", "example_upstream_reserved": "Podes especificar o DNS primário <0>para domínio(s) especifico(s)", - "example_upstream_comment": "Tu podes especificar o comentário", + "example_upstream_comment": "um comentário.", "upstream_parallel": "Usar consultas paralelas para acelerar a resolução consultando simultaneamente todos os servidores DNS", "parallel_requests": "Solicitações paralelas", "load_balancing": "Balanceamento de carga", @@ -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 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": "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", @@ -196,25 +196,25 @@ "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", "examples_title": "Exemplos", - "example_meaning_filter_block": "bloqueia o acesso ao domínio exemplo.org e a todos os seus subdomínios", - "example_meaning_filter_whitelist": "desbloqueia o acesso ao domínio exemplo.org e a todos os seus subdomínios", - "example_meaning_host_block": "O AdGuard Home irá retornar o endereço 127.0.0.1 para o domínio exemplo.org (excepto os seus subdomínios).", - "example_comment": "! Aqui vai um comentário", - "example_comment_meaning": "apenas um comentário", - "example_comment_hash": "# Também um comentário", - "example_regex_meaning": "bloquear o acesso aos domínios que correspondam à expressão regular especificada", + "example_meaning_filter_block": "bloqueia o acesso ao exemplo.org e a todos os seus subdomínios;", + "example_meaning_filter_whitelist": "desbloqueia o acesso ao exemplo.org e a todos os seus subdomínios;", + "example_meaning_host_block": "retorna o endereço 127.0.0.1 para o exemplo.org (exceto seus subdomínios);", + "example_comment": "! Aqui vai um comentário.", + "example_comment_meaning": "apenas um comentário;", + "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_dot": "<0>DNS-sobre-TLS criptografado", - "example_upstream_doh": "<0>DNS-sobre-HTTPS criptografado", - "example_upstream_doq": "<0>DNS-sobre-QUIC criptografado", - "example_upstream_sdns": "pode usar <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_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);", "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 +259,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 salva o endereço de IP completo do cliente em registros e 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", @@ -277,7 +277,7 @@ "dns_over_quic": "DNS-sobre-QUIC", "client_id": "ID do cliente", "client_id_placeholder": "Insira o ID do cliente", - "client_id_desc": "Diferentes clientes podem ser identificados por um ID de cliente especial. Aqui você pode aprender mais sobre como identificar clientes.", + "client_id_desc": "Os clientes podem ser identificados por um ID de cliente especial. Saiba mais como identificar clientes aqui.", "download_mobileconfig_doh": "Transferir .mobileconfig para DNS-sobre-HTTPS", "download_mobileconfig_dot": "Transferir .mobileconfig para DNS-sobre-TLS", "download_mobileconfig": "Transferir ficheiro de configuração", @@ -334,11 +334,11 @@ "install_devices_router_list_4": "Em alguns tipos de roteador, um servidor DNS personalizado não pode ser configurado. Nesse caso, configurar o AdGuard Home como um <0>Servidor DHCP pode ajudar. Caso contrário, tu deve verificar o manual do router sobre como personalizar os servidores DNS em seu modelo de router específico.", "install_devices_windows_list_1": "Abra o Painel de Controlo através do Menu Iniciar ou pela Pesquisa do Windows.", "install_devices_windows_list_2": "Entre na categoria Rede e Internet e depois clique em Central de Rede e Partilha.", - "install_devices_windows_list_3": "No lado esquerdo da janela clique em \"Alterar as definições do adaptador\".", - "install_devices_windows_list_4": "Selecione sua atual ligação, clique nela com o botão direito do rato e depois clique em Propriedades.", + "install_devices_windows_list_3": "No painel esquerdo, clique em \"Alterar configurações do adaptador\".", + "install_devices_windows_list_4": "Clique com o botão direito do mouse em sua conexão ativa e selecione Propriedades.", "install_devices_windows_list_5": "Procure na lista por \"Internet Protocol Version 4 (TCP/IP)\" (ou por IPv6, \"Internet Protocol Version 6 (TCP/IPv6)\"), selecione e clique em Propriedades novamente.", "install_devices_windows_list_6": "Marque \"Usar os seguintes endereços de servidor DNS\" e insira os endereços do servidores do AdGuard Home.", - "install_devices_macos_list_1": "Clique na ícone da Apple e depois em Preferências do Sistema.", + "install_devices_macos_list_1": "Clique no ícone da Apple e depois em Preferências do Sistema.", "install_devices_macos_list_2": "Clique em Rede.", "install_devices_macos_list_3": "Selecione a primeira ligação da lista e clique em Avançado.", "install_devices_macos_list_4": "Selecione a guia DNS e insira os endereços dos servidores do AdGuard Home.", @@ -356,7 +356,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/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", @@ -367,7 +367,7 @@ "encryption_https_desc": "Se a porta HTTPS estiver configurada, a interface administrativa do AdGuard Home será acessível via HTTPS e também fornecerá o DNS-sobre-HTTPS no local '/dns-query'.", "encryption_dot": "Porta DNS-sobre-TLS", "encryption_dot_desc": "Se essa porta estiver configurada, o AdGuard Home irá executar o servidor DNS-sobre- TSL nesta porta.", - "encryption_doq": "Porta DNS-sobre-QUIC", + "encryption_doq": "Porta DNS-sobre-QUIC (experimental)", "encryption_doq_desc": "Se esta porta estiver configurada, o AdGuard Home executará um servidor DNS-sobre-QUIC nesta porta. É experimental e pode não ser confiável. Além disso, não há demasiados clientes que ofereçam suporte no momento.", "encryption_certificates": "Certificados", "encryption_certificates_desc": "Para usar criptografia, precisa de fornecer uma cadeia de certificados SSL válida para o seu domínio. Pode obter um certificado gratuito em <0> {{link}} ou pode comprá-lo numa das autoridades de certificação confiáveis.", @@ -378,26 +378,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": "Esta 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": "Erro ao obter 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.", @@ -405,8 +405,8 @@ "update_failed": "A atualização automática falhou. Por favor, siga estes passos para atualizar manualmente.", "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", - "clients_desc": "Configure os dispositivos ligados ao AdGuard", + "clients_title": "Clientes persistentes", + "clients_desc": "Configure registros de cliente persistentes para dispositivos conectados ao AdGuard Home.", "settings_global": "Global", "settings_custom": "Personalizar", "table_client": "Cliente", @@ -417,7 +417,7 @@ "client_edit": "Editar cliente", "client_identifier": "Identificador", "ip_address": "Endereço de IP", - "client_identifier_desc": "Os clientes podem ser identificados pelo endereço IP, CIDR, Endereço MAC ou um ID de cliente especial (pode ser usado para DoT/DoH/DoQ). <0>Aqui você pode aprender mais sobre como identificar clientes.", + "client_identifier_desc": "Os clientes podem ser identificados pelo endereço IP, CIDR, Endereço MAC ou um ID de cliente especial (pode ser usado para DoT/DoH/DoQ). Saiba mais sobre como identificar clientes <0>aqui.", "form_enter_ip": "Insira IP", "form_enter_subnet_ip": "Digite um endereço IP na sub-rede \"{{cidr}}\"", "form_enter_mac": "Insira o endereço MAC", @@ -432,14 +432,14 @@ "clients_not_found": "Nenhum cliente foi encontrado", "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 (tempo de execução)", - "auto_clients_desc": "Dados dos clientes que usam o AdGuard Home, que não são armazenados na definição", + "auto_clients_title": "Clientes ativos", + "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_allowed_title": "Clientes permitidos", - "access_allowed_desc": "Uma lista de CIDRs, endereços IP ou IDs de cliente. Se configurado, o AdGuard Home do aceitará solicitações apenas desses clientes.", + "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", - "access_disallowed_desc": "Uma lista de CIDRs, endereços IP ou IDs de cliente. Se configurado, o AdGuard Home descartará as solicitações desses clientes. Se clientes permitidos estiverem configurados, este campo será ignorado.", + "access_disallowed_desc": "Uma lista de CIDRs, endereços IP ou IDs de cliente. Se essa lista tiver entradas, o AdGuard Home descartará as solicitações desses clientes. Este campo é ignorado se houver entradas em clientes permitidos.", "access_blocked_title": "Domínios bloqueados", "access_blocked_desc": "Não deve ser confundido com filtros. O AdGuard Home elimina as consultas DNS que correspondem a esses domínios, e essas consultas nem aparecem no registro de consultas. Você pode especificar nomes de domínio exatos, caracteres curinga ou regras de filtro de URL, por exemplo \"exemplo.org\", \"*.exemplo.org\", ou \"||exemplo.org^\" correspondentemente.", "access_settings_saved": "Definições de acesso foram guardadas com sucesso", @@ -475,8 +475,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", @@ -507,7 +507,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", @@ -532,7 +532,7 @@ "netname": "Nome da rede", "network": "Rede", "descr": "Descrição", - "whois": "Whois", + "whois": "WHOIS", "filtering_rules_learn_more": "<0>Saiba maissobre como criar as suas próprias listas negras de servidores.", "blocked_by_response": "Bloqueado por CNAME ou IP em resposta", "blocked_by_cname_or_ip": "Bloqueado por CNAME ou IP", @@ -552,10 +552,10 @@ "autofix_warning_list": "Irá realizar estas tarefas: <0>Desativar sistema DNSStubListener <0>Definir endereço do servidor DNS para 127.0.0.1 <0>Substituir o alvo simbólico do link /etc/resolv.conf para /run/systemd/resolv.conf <0>Parar DNSStubListener (recarregar serviço resolvido pelo sistema)", "autofix_warning_result": "Como resultado, todos as solicitações DNS do seu sistema serão processadas pelo AdGuard Home por predefinição.", "tags_title": "Etiquetas", - "tags_desc": "Tu podes selecionar as etiquetas que correspondem ao cliente. As etiquetas podem ser incluídas nas regras de filtragem e permitir que tu as aplique com mais precisão. <0>Saiba mais", + "tags_desc": "Você pode selecionar tags que correspondam ao cliente. Inclua tags nas regras de filtragem para aplicá-las com mais precisão. <0>Saber mais.", "form_select_tags": "Selecione as tags do cliente", "check_title": "Verifique a filtragem", - "check_desc": "Verificar se o nome do host está sendo filtrado", + "check_desc": "Verificar se um nome do host está sendo filtrado.", "check": "Verificar", "form_enter_host": "Insira o hostname", "filtered_custom_rules": "Filtrado pelas regras de filtragem personalizadas", @@ -598,15 +598,15 @@ "blocklist": "Lista de bloqueio", "milliseconds_abbreviation": "ms", "cache_size": "Tamanho do cache", - "cache_size_desc": "Tamanho do cache do DNS (em bytes)", + "cache_size_desc": "Tamanho do cache do DNS (em bytes).", "cache_ttl_min_override": "Sobrepor o TTL mínimo", "cache_ttl_max_override": "Sobrepor o TTL máximo", "enter_cache_size": "Digite o tamanho do cache (bytes)", "enter_cache_ttl_min_override": "Digite o TTL máximo (segundos)", "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 valor TTL mínimo do cache deve ser menor ou igual ao valor máximo", + "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.", "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", @@ -624,9 +624,9 @@ "adg_will_drop_dns_queries": "O AdGuard Home descartará todas as consultas DNS deste cliente.", "filter_allowlist": "AVISO: Esta ação também excluirá a regra \"{{disallowed_rule}}\" da lista de clientes permitidos.", "last_rule_in_allowlist": "Não é possível desautorizar este cliente porque excluir a regra \"{{disallowed_rule}}\" DESATIVARÁ a lista de \"Clientes permitidos\".", - "experimental": "Experimental", "use_saved_key": "Use a chave guardada anteriormente", "parental_control": "Controlo parental", "safe_browsing": "Navegação segura", - "served_from_cache": "{{value}} (servido do cache)" + "served_from_cache": "{{value}} (servido do cache)", + "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 0e959ee7..c4b304b2 100644 --- a/client/src/__locales/ro.json +++ b/client/src/__locales/ro.json @@ -1,7 +1,7 @@ { "client_settings": "Setări client", - "example_upstream_reserved": "Puteți specifica un DNS în amonte <0>pentru domeniul (domeniile) specific(e)", - "example_upstream_comment": "Puteți specifica un comentariu", + "example_upstream_reserved": "un flux în amonte <0>pentru domenii specifice;", + "example_upstream_comment": "un comentariu.", "upstream_parallel": "Folosiți interogări paralele pentru a accelera rezolvarea, interogând simultan toate serverele în amonte.", "parallel_requests": "Solicitări paralele", "load_balancing": "Echilibrare-sarcini", @@ -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 necesar", - "form_error_ip4_format": "Adresă IPv4 nevalidă", - "form_error_ip4_range_start_format": "Adresă IPv4 de început al intervalului nevalidă", - "form_error_ip4_range_end_format": "Adresa IPv4 de sfârșit al intervalului nevalidă", - "form_error_ip4_gateway_format": "Adresă IPv4 a gateway-ului nevalidă", - "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": "ID-ul clientului trebuie să conțină numai numere, litere minuscule și liniuțe.", - "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", @@ -196,25 +196,25 @@ "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 invalid", - "form_error_url_or_path_format": "Invalid URL sau o cale 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", "examples_title": "Exemple", - "example_meaning_filter_block": "blochează accesul la domeniul exemplu.org și la toate subdomeniile sale", - "example_meaning_filter_whitelist": "deblochează accesul la domeniul exemplu.org și la toate subdomeniile sale", - "example_meaning_host_block": "AdGuard Home va returna acum adresa 127.0.0.1 pentru domeniul exemplu.org (dar nu și subdomeniile sale).", - "example_comment": "! Iată cum se adăugă o descriere", - "example_comment_meaning": "comentariu", - "example_comment_hash": "# Astfel putem lăsa comentarii", - "example_regex_meaning": "blocare acces la domenii care corespund expresiei obișnuite specificate", - "example_upstream_regular": "DNS clasic (over UDP)", - "example_upstream_dot": "<0>DNS-over-TLS criptat", - "example_upstream_doh": "<0>DNS-over-HTTPS criptat", - "example_upstream_doq": "<0>DNS-over-QUIC criptat", - "example_upstream_sdns": "puteți utiliza <0>DNS Stamps pentru rezolvere <1>DNSCrypt sau <2>DNS-over-HTTPS", - "example_upstream_tcp": "DNS clasic (over TCP)", + "example_meaning_filter_block": "blochează accesul la domeniul exemplu.org și la toate subdomeniile sale;", + "example_meaning_filter_whitelist": "deblochează accesul la domeniul exemplu.org și la toate subdomeniile sale;", + "example_meaning_host_block": "răspunde cu 127.0.0.1 pentru domeniul exemplu.org (dar nu și pentru subdomeniile sale);", + "example_comment": "! Aici urmează un comentariu.", + "example_comment_meaning": "doar un comentariu;", + "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_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);", "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 +259,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", @@ -275,9 +275,9 @@ "dns_over_https": "DNS-over-HTTPS", "dns_over_tls": "DNS-over-TLS", "dns_over_quic": "DNS-over-QUIC", - "client_id": "ID Client", - "client_id_placeholder": "Introduceți ID client", - "client_id_desc": "Diferiți clienți pot fi identificați printr-un ID special al clientului. Aici puteți afla mai multe despre cum să identificați clienții.", + "client_id": "ClientID", + "client_id_placeholder": "Introduceți un ClientID", + "client_id_desc": "Clienții pot fi identificați prin ClientID. Aflați mai multe despre cum să identificați clienții aici.", "download_mobileconfig_doh": "Descărcați .mobileconfig pentru DNS-over-HTTPS", "download_mobileconfig_dot": "Descărcați .mobileconfig pentru DNS-over-TLS", "download_mobileconfig": "Descărcați fișierul de configurare", @@ -309,7 +309,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", @@ -334,12 +334,12 @@ "install_devices_router_list_4": "Unele tipuri de routere, nu permit configurarea unui server DNS personalizat. În acest caz, configurarea AdGuard Home ca un <0>server DHCPvă poate ajuta. Dacă nu, ar trebui verificat manualul routerului dvs. specific, ca să aflați cum se pot personaliza serverele DNS.", "install_devices_windows_list_1": "Deschideți panoul de control prin meniul Start sau căutare Windows.", "install_devices_windows_list_2": "Accesați categoria \"Rețea și Internet\", apoi la \"Centrul de Rețea și Partajare\".", - "install_devices_windows_list_3": "În partea stângă a ecranului găsiți \"Schimbare setări adaptor\" și clicați pe el.", - "install_devices_windows_list_4": "Selectați conexiunea activă, faceți clic dreapta pe ea și alegeți \"Proprietăți\".", + "install_devices_windows_list_3": "În panoul din stânga, faceți clic pe „Modificare setări adaptor”.", + "install_devices_windows_list_4": "Faceți clic dreapta pe conexiunea activă și selectați „Proprietăți”.", "install_devices_windows_list_5": "Găsiți Internet Protocol Versiunea 4 (TCP/IPv4) din listă, selectați-l și apoi clicați din nou pe Proprietăți.", "install_devices_windows_list_6": "Alegeți „Utilizați următoarele adrese de server DNS” și introduceți adresele serverului dvs. AdGuard Home.", - "install_devices_macos_list_1": "Clicați pe icoana Apple și accesați Preferințele Sistemului.", - "install_devices_macos_list_2": "Clicați pe Network.", + "install_devices_macos_list_1": "Faceți clic pe pictograma „Apple” și accesați „Preferințe de sistem”.", + "install_devices_macos_list_2": "Faceți clic pe „Rețea”.", "install_devices_macos_list_3": "Selectați prima conexiune din listă și clicați pe Avansat.", "install_devices_macos_list_4": "Selectați fila DNS și introduceți adresele serverului dvs. AdGuard Home.", "install_devices_android_list_1": "Din ecranul principal al Meniului Android, tapați Setări.", @@ -356,7 +356,7 @@ "open_dashboard": "Deschideți Tabloul de bord", "install_saved": "Salvat cu succes", "encryption_title": "Criptare", - "encryption_desc": "Suport de Criptare (HTTPS/TLS) pentru DNS și interfața web administrator", + "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", @@ -367,7 +367,7 @@ "encryption_https_desc": "Dacă portul HTTPS este configurat, interfața administrator AdGuard Home va fi accesibilă prin HTTPS și va oferi de asemenea DNS-over-HTTPS în locația '/DNS-query'.", "encryption_dot": "Port DNS-over-TLS", "encryption_dot_desc": "Dacă acest port este configurat, AdGuard Home va rula un server DNS-over-TLS pe acest port.", - "encryption_doq": "Port DNS-over-QUIC", + "encryption_doq": "Port DNS-over-QUIC (experimental)", "encryption_doq_desc": "Dacă acest port este configurat, AdGuard Home va rula un server DNS-over-QUIC pe acest port. Este experimental și este posibil să nu fie fiabil. De asemenea, nu există prea mulți clienți care să-l susțină în acest moment.", "encryption_certificates": "Certificate", "encryption_certificates_desc": "Pentru a utiliza criptarea, trebuie furnizate o serie de certificate SSL valabile pentru domeniul dvs.. Puteți obține un certificat gratuit pe <0>{{link}} sau îl puteți cumpăra de la una din Autoritățile Certificate de încredere.", @@ -378,26 +378,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": "Acesta este un 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 verificare statut server DNS.", "down": "Down", "fix": "Fix", "dns_providers": "Iată o <0>listă de furnizori DNS cunoscuți ce pot fi aleși.", @@ -405,8 +405,8 @@ "update_failed": "Auto-actualizarea a eșuat. Vă rugăm să urmați aceste etape pentru a actualiza manual.", "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", - "clients_desc": "Configură aparatele conectate la AdGuard Home", + "clients_title": "Clienți persistenți", + "clients_desc": "Configură înregistrările clientului permanent pentru dispozitivele conectate la AdGuard Home.", "settings_global": "General", "settings_custom": "Personalizat", "table_client": "Client", @@ -417,7 +417,7 @@ "client_edit": "Editare client", "client_identifier": "Identificator", "ip_address": "Adresa IP", - "client_identifier_desc": "Clienții pot fi identificați prin adresa IP, CIDR, adresa MAC sau un ID client special (poate fi folosit pentru DoT/DoH/DoQ). <0>Aici puteți afla mai multe despre cum să identificați clienții.", + "client_identifier_desc": "Clienții pot fi identificați prin adresa lor IP, CIDR, adresa MAC sau ClientID (poate fi utilizat pentru DoT/DoH/DoQ). Aflați mai multe despre cum să identificați clienții <0>aici.", "form_enter_ip": "Introduceți IP", "form_enter_subnet_ip": "Introduceți o adresă IP în subrețeaua „{{cidr}}”", "form_enter_mac": "Introduceți MAC", @@ -432,14 +432,14 @@ "clients_not_found": "Nu au fost găsiți clienți", "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": "Date despre clienții care folosesc AdGuard Home, dar care nu sunt stocate în configurație", + "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.", "access_title": "Setări de acces", "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 adrese CIDR sau IP client. Dacă este configurat, AdGuard Home va accepta cereri numai de la acești clienț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", - "access_disallowed_desc": "O listă de adrese CIDR sau IP. Dacă este configurat, AdGuard Home va elimina cereri de la acești clienți. Dacă sunt configurați clienți permiși, acest câmp este ignorat.", + "access_disallowed_desc": "O listă de CIDR-uri, adrese IP sau ClientID-uri. Dacă această listă are intrări, AdGuard Home va renunța la cererile de la acești clienți. Acest câmp este ignorat dacă există intrări în „Clienți permiși”.", "access_blocked_title": "Domenii blocate", "access_blocked_desc": "A nu se confunda cu filtrele. AdGuard Home respinge cererile DNS pentru aceste domenii, iar aceste cereri nici măcar nu apar în jurnalul de solicitări. Puteți specifica nume exacte de domenii, metacaractere sau reguli de filtrare URL, cum ar fi \"example.org\", \"*.exemple.org\" sau \"||example.org^\" în mod corespunzător.", "access_settings_saved": "Setările de acces au fost salvate cu succes", @@ -475,8 +475,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 răspuns 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", @@ -507,7 +507,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", @@ -532,7 +532,7 @@ "netname": "Numele rețelei", "network": "Rețea", "descr": "Descriere", - "whois": "Whois", + "whois": "WHOIS", "filtering_rules_learn_more": "<0>Aflați mai multe despre crearea propriilor liste hosts.", "blocked_by_response": "Blocat de CNAME sau IP ca răspuns", "blocked_by_cname_or_ip": "Blocat de CNAME sau IP", @@ -552,10 +552,10 @@ "autofix_warning_list": "Va efectua aceste sarcini: <0>Dezactivare sistem DNSStubListener <0>Setare adresă server DNS la 127.0.0.1 <0>Înlocuire link simbolic țintă /etc/resolv.conf cu /run/systemd/resolve/resolv.conf <0>Oprire DNSStubListener (reîncărcare servici rezolvat prin sistem)", "autofix_warning_result": "Ca urmare, toate cererile DNS ale sistemul dvs. vor fi procesate în mod implicit de AdGuardHome.", "tags_title": "Etichete", - "tags_desc": "Puteți selecta etichetele care corespund clientului. Etichetele pot fi incluse în regulile de filtrare și vă permit să le aplicați mai exact. <0>Aflați mai multe", + "tags_desc": "Puteți selecta etichetele care corespund clientului. Includeți etichete în regulile de filtrare pentru a le aplica mai precis. <0>Aflați mai multe.", "form_select_tags": "Selectați etichete client", "check_title": "Verificați filtrarea", - "check_desc": "Verificați dacă numele de host este filtrat", + "check_desc": "Verifică dacă numele de host este filtrat.", "check": "Verificați", "form_enter_host": "Introduceți un nume de host", "filtered_custom_rules": "Filtrat prin reguli de filtrare personalizate", @@ -594,19 +594,19 @@ "allowed": "Permise", "filtered": "Filtrate", "rewritten": "Rescrise", - "safe_search": "Căutare sigură", + "safe_search": "Căutarea sigură", "blocklist": "Lista de blocări", "milliseconds_abbreviation": "ms", "cache_size": "Mărime cache", - "cache_size_desc": "Mărime cache DNS (în octeți)", + "cache_size_desc": "Mărime cache DNS (în octeți).", "cache_ttl_min_override": "Suprascrieți minimum TTL", "cache_ttl_max_override": "Suprascrieți maximum TTL", "enter_cache_size": "Introduceți mărimea cache-ului (bytes)", "enter_cache_ttl_min_override": "Introduceți minimum TTL (secunde)", "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ă", + "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ă.", "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", @@ -624,9 +624,9 @@ "adg_will_drop_dns_queries": "AdGuard Home va renunța la toate interogările DNS de la acest client.", "filter_allowlist": "AVERTISMENT: Această acțiune va exclude și regula „{{disallowed_rule}}” din lista de clienți permiși.", "last_rule_in_allowlist": "Acest client nu poate fi exclus deoarece excluderea regulii „{{disallowed_rule}}” va DEZACTIVA lista „Clienți acceptați”.", - "experimental": "Experimental", "use_saved_key": "Folosiți cheia salvată anterior", "parental_control": "Control Parental", "safe_browsing": "Navigare în siguranță", - "served_from_cache": "{{value}} (furnizat din cache)" + "served_from_cache": "{{value}} (furnizat din cache)", + "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 cd1e8091..dc73fded 100644 --- a/client/src/__locales/ru.json +++ b/client/src/__locales/ru.json @@ -1,7 +1,7 @@ { "client_settings": "Настройки клиентов", - "example_upstream_reserved": "Вы можете указать DNS-сервер <0>для конкретного домена(-ов)", - "example_upstream_comment": "Вы можете указать комментарий", + "example_upstream_reserved": "DNS-сервер <0>для конкретных доменов;", + "example_upstream_comment": "комментарий.", "upstream_parallel": "Использовать параллельные запросы ко всем серверам одновременно для ускорения обработки запроса.", "parallel_requests": "Параллельные запросы", "load_balancing": "Распределение нагрузки\n", @@ -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": "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-адресов", @@ -196,25 +196,25 @@ "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-файлы", "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": "зашифрованный <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_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_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);", "all_lists_up_to_date_toast": "Все списки уже обновлены", "updated_upstream_dns_toast": "DNS-серверы успешно обновлены", "dns_test_ok_toast": "Указанные серверы DNS работают корректно", @@ -259,10 +259,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", @@ -275,9 +275,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": "Загрузить файл конфигурации", @@ -309,7 +309,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 +334,12 @@ "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_4": "Выделите ваше активное подключение, затем кликните по нему правой клавишей мыши и выберите «Свойства».", + "install_devices_windows_list_3": "В левой панели кликните на «Изменение параметров адаптера».", + "install_devices_windows_list_4": "Кликните на ваше активное подключение правой кнопкой мыши и выберите «Свойства».", "install_devices_windows_list_5": "Найдите в списке пункт «IP версии 4 (TCP/IPv4)» (или «IP версии 6 (TCP/IPv6)» для IPv6), выделите его и затем снова нажмите «Свойства».", "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 +356,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": "Введите ваше доменное имя", @@ -367,7 +367,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}} или вы можете купить его у одного из доверенных Центров Сертификации.", @@ -378,26 +378,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-провайдеров на выбор.", @@ -405,8 +405,8 @@ "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": "Клиент", @@ -417,7 +417,7 @@ "client_edit": "Редактировать клиента", "client_identifier": "Идентификатор", "ip_address": "IP-адрес", - "client_identifier_desc": "Клиенты могут быть идентифицированы по IP-адресу, CIDR или MAC-адресу или специальному ID (можно использовать для DoT/DoH/DoQ). <0>Здесь вы можете узнать больше об идентификации клиентов.", + "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", @@ -433,13 +433,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_allowed_title": "Разрешённые клиенты", - "access_allowed_desc": "Список CIDR, IP-адресов или ID клиентов. Если он настроен, AdGuard Home будет принимать запросы только от этих клиентов.", + "access_allowed_desc": "Список CIDR, IP-адресов или ClientID. Если в списке есть записи, AdGuard Home будет принимать запросы только от этих клиентов.", "access_disallowed_title": "Запрещённые клиенты", - "access_disallowed_desc": "Список CIDR, IP-адресов или ID клиентов. Если он настроен, AdGuard Home будет игнорировать запросы от этих клиентов. Если настроены разрешённые клиенты, это поле игнорируется.", + "access_disallowed_desc": "Список CIDR, IP-адресов или ClientID. Если в списке есть записи, AdGuard Home будет игнорировать запросы от этих клиентов. Это поле игнорируется, если список разрешённых клиентов содержит записи.", "access_blocked_title": "Неразрешённые домены", "access_blocked_desc": "Не путать с фильтрами. AdGuard Home будет игнорировать DNS-запросы с этими доменами. Здесь вы можете уточнить точные имена доменов, шаблоны, правила URL-фильтрации, например, «example.org», «*.example.org» или «||example.org».", "access_settings_saved": "Настройки доступа успешно сохранены", @@ -475,8 +475,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": "Выбрать заблокированные сервисы", @@ -507,7 +507,7 @@ "filter_updated": "Список успешно обновлён", "statistics_configuration": "Конфигурация статистики", "statistics_retention": "Сохранение статистики", - "statistics_retention_desc": "Если вы уменьшите значение интервала, некоторые данные могут быть утеряны", + "statistics_retention_desc": "Если вы уменьшите значение интервала, некоторые данные могут быть потеряны.", "statistics_clear": "Очистить статистику", "statistics_clear_confirm": "Вы уверены, что хотите очистить статистику?", "statistics_retention_confirm": "Вы уверены, что хотите изменить срок хранения статистики? При сокращении интервала данные могут быть утеряны", @@ -532,7 +532,7 @@ "netname": "Название сети", "network": "Сеть", "descr": "Описание", - "whois": "Whois", + "whois": "WHOIS", "filtering_rules_learn_more": "<0>Узнайте больше о создании собственных списков блокировки хостов.", "blocked_by_response": "Заблокировано по CNAME или IP в ответе", "blocked_by_cname_or_ip": "Заблокировано с помощью CNAME или IP", @@ -552,10 +552,10 @@ "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": "Проверить фильтрацию имени хоста", + "check_desc": "Проверить фильтрацию имени хоста.", "check": "Проверить", "form_enter_host": "Введите имя хоста", "filtered_custom_rules": "Отфильтрованы с помощью пользовательских правил фильтрации", @@ -598,15 +598,15 @@ "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-сервера при кешировании DNS-ответов", - "cache_ttl_max_override_desc": "Установить максимальное TTL-значение (в секундах) для записей в DNS-кэше", - "ttl_cache_validation": "Минимальное значение TTL-кеша должно быть меньше или равно максимальному значению", + "cache_ttl_min_override_desc": "Расширить короткие TTL-значения (в секундах), полученные с upstream-сервера при кешировании DNS-ответов.", + "cache_ttl_max_override_desc": "Установить максимальное TTL-значение (в секундах) для записей в DNS-кеше.", + "ttl_cache_validation": "Минимальное значение TTL-кеша должно быть меньше или равно максимальному значению.", "cache_optimistic": "Оптимистическое кеширование", "cache_optimistic_desc": "AdGuard Home будет отвечать из кеша, даже если ответы в нём неактуальны, и попытается обновить их.", "filter_category_general": "Общие", @@ -624,9 +624,9 @@ "adg_will_drop_dns_queries": "AdGuard Home AdGuard Home сбросит все DNS-запросы от этого клиента.", "filter_allowlist": "ВНИМАНИЕ: Это действие также исключит правило «{{disallowed_rule}}» из списка разрешённых клиентов.", "last_rule_in_allowlist": "Нельзя заблокировать этого клиента, так как исключение правила «{{disallowed_rule}}» ОТКЛЮЧИТ режим белого списка.", - "experimental": "Экспериментальный", "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/si-lk.json b/client/src/__locales/si-lk.json index e9f02cb2..d2a4f5b9 100644 --- a/client/src/__locales/si-lk.json +++ b/client/src/__locales/si-lk.json @@ -541,7 +541,6 @@ "click_to_view_queries": "විමසුම් බැලීමට ඔබන්න", "port_53_faq_link": "53 වන කෙවෙනිය බොහෝ විට \"DNSStubListener\" හෝ \"systemd-resolved\" සේවා භාවිතයට ගනු ලැබේ. කරුණාකර මෙය විසඳන්නේ කෙසේද යන්න පිළිබඳ <0>මෙම උපදෙස් කියවන්න.", "adg_will_drop_dns_queries": "ඇඩ්ගාර්ඩ් හෝම් මෙම අනුග්‍රාහකයේ සියළුම ව.නා.ප. විමසුම් අතහැර දමනු ඇත.", - "experimental": "පරීක්‍ෂාත්මක", "use_saved_key": "පෙර සුරැකි යතුර භාවිතා කරන්න", "parental_control": "දෙමාපිය පාලනය", "safe_browsing": "ආරක්‍ෂිත පිරික්සුම", diff --git a/client/src/__locales/sk.json b/client/src/__locales/sk.json index 7b4596f3..da174fda 100644 --- a/client/src/__locales/sk.json +++ b/client/src/__locales/sk.json @@ -624,9 +624,9 @@ "adg_will_drop_dns_queries": "AdGuard Home zruší všetky DNS dopyty od tohto klienta.", "filter_allowlist": "UPOZORNENIE: Táto akcia tiež vylúči pravidlo \"\"{{disallowed_rule}}\"\" zo zoznamu povolených klientov.", "last_rule_in_allowlist": "Nemôžete zakázať tohto klienta, pretože vylúčenie pravidla \"{{disallowed_rule}}\" zakáže zoznam \"povolených klientov\".", - "experimental": "Experimentálne", "use_saved_key": "Použiť predtým uložený kľúč", "parental_control": "Rodičovská kontrola", "safe_browsing": "Bezpečné prehliadanie", - "served_from_cache": "{{value}} (prevzatá z cache pamäte)" + "served_from_cache": "{{value}} (prevzatá z cache pamäte)", + "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 a9c5fed6..8df19766 100644 --- a/client/src/__locales/sl.json +++ b/client/src/__locales/sl.json @@ -1,7 +1,7 @@ { "client_settings": "Nastavitve odjemalca", - "example_upstream_reserved": "Lahko določite gorvodni DNS <0>za določene domene", - "example_upstream_comment": "Lahko določite komentar", + "example_upstream_reserved": "gorvodni <0>za določene domene;", + "example_upstream_comment": "komentar.", "upstream_parallel": "Uporabite vzporedne zahteve za pospešitev reševanja s hkratnim poizvedovanjem vseh gorvodnih strežnikov.", "parallel_requests": "Vzporedne zahteve", "load_balancing": "Uravnavanje obremenitve", @@ -35,24 +35,24 @@ "dhcp_config_saved": "Nastavitve DHCP so bile uspešno shranjena", "dhcp_ipv4_settings": "Nastavitve DHCP IPv4", "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 začetek oblike razpona IPv4", - "form_error_ip4_range_end_format": "Neveljaven konec oblike razpona 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", + "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.", "dhcp_form_gateway_input": "IP prehoda", "dhcp_form_subnet_input": "Maska podomrežja", "dhcp_form_range_title": "Razpon naslovov IP", @@ -143,7 +143,7 @@ "use_adguard_browsing_sec_hint": "AdGuard Home bo preveril ali je domena onemogočena s spletno storitivijo 'Varnost brskanja'ovoljenih. Za izvedbo preverjanja bo uporabil API za iskanje, ki je prijazen do zasebnosti: strežniku se pošlje le kratka predpona zgoščenke domenskega imena SHA256.", "use_adguard_parental": "Uporabi AdGuardovo spletno storitev 'Starševski nadzor'", "use_adguard_parental_hint": "AdGuard Home bo preveril, če domena vsebuje vsebine za odrasle. Uporablja enako, za zasebnost prijazen API, kot spletno storitev za varnost brskanja.", - "enforce_safe_search": "Uporabi varno iskanje", + "enforce_safe_search": "Uporabi Varno iskanje", "enforce_save_search_hint": "AdGuard Home bo vsilil varno iskanje v naslednjih iskalnikih: Google, YouTube, Bing, DuckDuckGo, Yandex, Pixabay.", "no_servers_specified": "Ni določenih strežnikov", "general_settings": "Splošne nastavitve", @@ -167,8 +167,8 @@ "enabled_safe_browsing_toast": "Omogočeno varno brskanje", "disabled_parental_toast": "Onemogočen starševski nadzor", "enabled_parental_toast": "Omogočen starševski nadzor", - "disabled_safe_search_toast": "Onemogočeno varno iskanje", - "enabled_save_search_toast": "Omogočeno varno iskanje", + "disabled_safe_search_toast": "Onemogočeno Varno iskanje", + "enabled_save_search_toast": "Omogočeno Varno iskanje", "enabled_table_header": "Omogočeno", "name_table_header": "Ime", "list_url_table_header": "Seznam URL naslovov", @@ -196,25 +196,25 @@ "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": "Neveljaven format 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.", "system_host_files": "Sistemske gostiteljske datooteke", "examples_title": "Primeri", - "example_meaning_filter_block": "onemogoči dostop do domene example.org in vseh njenih poddomen", - "example_meaning_filter_whitelist": "omogoči dostop do domene example.org in vseh njenih poddomen", - "example_meaning_host_block": "AdGuard Home bo zdaj vrnil naslov 127.0.0.1 za domeno example.org (ne pa tudi njunih poddomen).", - "example_comment": "! Tukaj je komentar", - "example_comment_meaning": "samo komentar", - "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_dot": "šifriran <0>DNS-prek-TLS", - "example_upstream_doh": "šifriran <0>DNS-prek-HTTPS", - "example_upstream_doq": "šifriran <0>DNS-prek-QUIC", - "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_meaning_filter_block": "onemogoči dostop do domene example.org in vseh njenih poddomen;", + "example_meaning_filter_whitelist": "omogoči dostop do domene example.org in vseh njenih poddomen;", + "example_meaning_host_block": "odgovori z 127.0.0.1 na primer.org (vendar ne za njegove poddomene);", + "example_comment": "! Tukaj je komentar.", + "example_comment_meaning": "samo komentar;", + "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_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);", "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 +259,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 in 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 konfigurirate predpomnilnik DNS", + "dns_cache_config_desc": "Tu lahko nastavite predpomnilnik DNS.", "blocking_mode": "Način zaviranja", "default": "Privzeto", "nxdomain": "NXDOMAIN", @@ -277,7 +277,7 @@ "dns_over_quic": "DNS-prek-QIUC", "client_id": "ID odjemalca", "client_id_placeholder": "Vnesite ID odjemalca", - "client_id_desc": "Različne odjemalce je mogoče prepoznati s posebnim ID-jem odjemalca. Tukaj lahko izveste več o prepoznavanju odjemalcev.", + "client_id_desc": "Odjemalce je mogoče identificirati s ClientID. Več o tem, kako prepoznati odjemalce, preberite tukaj.", "download_mobileconfig_doh": "Prenos .mobileconfig za DNS-preko-HTTPS", "download_mobileconfig_dot": "Prenos .mobileconfig za DNS-preko-TLS", "download_mobileconfig": "Prenesi nastavitveno datoteko", @@ -309,7 +309,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", @@ -334,12 +334,12 @@ "install_devices_router_list_4": "Pri nekaterih vrstah usmerjevalnikov strežnika DNS po meri ni mogoče nastaviti. V tem primeru vam lahko pomaga nastavitev AdGuard Home kot <0>strežnika DHCP. V nasprotnem primeru bi morali v priročniku usmerjevalnika preveriti, kako prilagodite strežnike DNS na vašem določenem modelu usmerjevalnika.", "install_devices_windows_list_1": "Odprite 'Nadzorno ploščo' prek menija 'Začetek' ali 'Iskanja v sistemu Windows'.", "install_devices_windows_list_2": "Pojdite v 'Omrežje' in 'Kategorija interneta' in nato v 'Omrežje' in 'Središče za skupno rabo'.", - "install_devices_windows_list_3": "Na levi strani zaslona poiščite 'Spremeni nastavitve kartice' in kliknite nanjo.", - "install_devices_windows_list_4": "Izberite aktivno povezavo, kliknite na njo z desno miškino tipko in izberite 'Lastnosti'.", + "install_devices_windows_list_3": "V levem podoknu kliknite 'Spremeni nastavitve kartice'\".", + "install_devices_windows_list_4": "Z desno tipko miške kliknite svojo aktivno povezavo in izberite Lastnosti.", "install_devices_windows_list_5": "Na seznamu poiščite 'Internet protokol različica 4 (TCP/IPv4)' (ali, za IPv6, 'Internet protokol različica 6 (TCP/IPv6)'), jo izberite in nato še enkrat kliknite 'Lastnosti'.", "install_devices_windows_list_6": "Izberite 'Uporabi naslednje naslove DNS strežnikov' in vnesite vaše naslove strežnika AdGuard Home.", - "install_devices_macos_list_1": "Kliknite ikono Apple in pojdite na 'Nastavitve sistema'.", - "install_devices_macos_list_2": "Kliknite na 'Omrežje'", + "install_devices_macos_list_1": "Kkliknite ikono Apple in pojdite na Sistemske nastavitve.", + "install_devices_macos_list_2": "Kliknite na 'Omrežje'.", "install_devices_macos_list_3": "Izberite prvo povezavo na seznamu in kliknite na 'Napredno'.", "install_devices_macos_list_4": "Izberite zavihek DNS in vnesite vaše naslove AdGuard Home strežnika.", "install_devices_android_list_1": "Na začetnem zaslonu menija Android tapnite 'Nastavitve'.", @@ -356,7 +356,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", @@ -367,7 +367,7 @@ "encryption_https_desc": "Če so vrata HTTPS konfigurirana, bo skrbniški vmesnik AdGuard Home dostopen prek protokola HTTPS, prav tako pa bo zagotovil DNS-prek-HTTPS na mestu '/dns-query'.", "encryption_dot": "Vrata DNS-prek-TLS", "encryption_dot_desc": "Če so ta vrata konfigurirana, bo AdGuard Home na teh vratih zagnal DNS-prek-TLS strežnika.", - "encryption_doq": "DNS-prek-vrat QUIC", + "encryption_doq": "DNS-prek-vrat QUIC (eksperimentalno)", "encryption_doq_desc": "Če so nastavljena ta vrata bo AdGuard Home na teh vratih zagnal strežnik DNS-prek-QUIC. To je eksperimentalno in morda ni zanesljivo. Prav tako trenutno ni preveč odjemalcev, ki to podpirajo.", "encryption_certificates": "Digitalna potrdila", "encryption_certificates_desc": "Za uporabo šifriranja morate za svojo domeno zagotoviti veljavno verigo potrdil SSL. Brezplačno digitalno potrdilo lahko dobite na <0>{{link}} ali pa ga kupite pri enem od zaupanja vrednih overiteljev.\n\n", @@ -378,26 +378,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 vrednost 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": "To so 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 pridobivanju 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.", @@ -405,8 +405,8 @@ "update_failed": "Samodejna posodobitev ni uspela. Prosimo sledite korakom, da ročno posodobite.", "manual_update": "Za ročno posodobitev sledite tem korakom.", "processing_update": "Prosimo, počakajte. AdGuard Home se posodablja!", - "clients_title": "Odjemalci", - "clients_desc": "Konfigurirajte naprave, ki so povezane z AdGuard Home", + "clients_title": "Trajni odjemalci", + "clients_desc": "Nastavite trajne zapise odjemalca za povezane naprave z AdGuard Home.", "settings_global": "Splošno", "settings_custom": "Po meri", "table_client": "Odjemalec", @@ -417,7 +417,7 @@ "client_edit": "Uredi odjemalca", "client_identifier": "Identifikator", "ip_address": "IP naslov", - "client_identifier_desc": "Odjemalce je mogoče prepoznati po naslovu IP, CIDR, naslovu MAC ali posebnem ID-ju odjemalca (lahko se uporablja za DoT/DoH/DoQ). <0>Tukaj lahko izveste več o prepoznavanju odjemalcev.", + "client_identifier_desc": "Odjemalce je mogoče prepoznati po naslovu IP, CIDR, naslovu MAC ali ID-ju (lahko se uporablja za DoT/DoH/DoQ). <0>Tukaj lahko izveste več o prepoznavanju odjemalcev.", "form_enter_ip": "Vnesite IP", "form_enter_subnet_ip": "V podomrežje \"{{cidr}}\" vnesite naslov IP", "form_enter_mac": "Vnesite MAC", @@ -432,14 +432,14 @@ "clients_not_found": "Odjemalcev ni bilo mogoče najti", "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 (čas izvajanja)", - "auto_clients_desc": "Podatki o odjemalcih, ki uporabljajo AdGuard Home, vendar niso shranjeni v konfiguraciji", + "auto_clients_title": "Odjemalci izvajanja", + "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_allowed_title": "Dovoljeni odjemalci", - "access_allowed_desc": "Seznam naslovov CIDR ali IP. Če je nastavljen, bo AdGuard Home sprejel zahteve samo od teh teh naslovov IP.", + "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", - "access_disallowed_desc": "Seznam naslovov CIDR ali IP. Če je nastavljen, bo AdGuard Home spustil zahteve iz teh naslovov IP.", + "access_disallowed_desc": "Seznam CIDR-jev, naslovov IP ali ID-jev odjemalcev. Če ta seznam vsebuje vnose, bo AdGuard Home zavrnil zahteve teh odjemalcev. To polje je prezrto, če so vnosi v dovoljenih odjemalcih.", "access_blocked_title": "Prepovedane domene", "access_blocked_desc": "Ne gre zamenjati s filtri. AdGuard Home spusti poizvedbe DNS, ki se ujemajo s temi domenami, in te poizvedbe se niti ne pojavijo v dnevniku poizvedb. Določite lahko natančna imena domen, nadomestne znake ali pravila filtriranja URL-jev, npr. ustrezno \"example.org\", \"*.example.org\" ali \"|| example.org ^\".", "access_settings_saved": "Nastavitve dostopa so uspešno shranjene", @@ -475,8 +475,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", @@ -507,7 +507,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", @@ -532,7 +532,7 @@ "netname": "Ime omrežja", "network": "Omrežje", "descr": "Opis", - "whois": "Whois", + "whois": "WHOIS", "filtering_rules_learn_more": "<0>Več o ustvarjanju lastnih seznamov gostiteljev.", "blocked_by_response": "Onemogočeno s CNAME ali IP v odgovoru", "blocked_by_cname_or_ip": "Onemogočeno s CNAME ali IP naslovom", @@ -552,10 +552,10 @@ "autofix_warning_list": "To bo izvedlo naslednja opravila: <0>Deaktiviraj sistemski DNSStubListener <0>Nastavi naslov strežnika DNS na 127.0.0.1 <0>Zamenjaj cilj simbolične povezave /etc/resolv.conf with /run/systemd/resolve/resolv.conf <0>Zaustavi DNSStubListener (znova naloži storitev systemd-resolved)", "autofix_warning_result": "Kot rezultat, bo vse zahteve DNS iz vašega sistema privzeto obdelal AdGuard Home.", "tags_title": "Oznake", - "tags_desc": "Izberete lahko oznake, ki ustrezajo odjemalcu. Oznake lahko vključite v pravila filtriranja in vam omogočajo, da jih natančneje uporabite. <0>Več o tem", + "tags_desc": "Izberete lahko oznake, ki ustrezajo odjemalcu. Oznake lahko vključite v pravila filtriranja in vam omogočajo, da jih natančneje uporabite. <0>Več o tem.", "form_select_tags": "Izberite odjemalske oznake", "check_title": "Preveri filtriranje", - "check_desc": "Preverite, ali je ime gostitelja filtrirano", + "check_desc": "Preverite, ali je ime gostitelja filtrirano.", "check": "Preveri", "form_enter_host": "Vnesite ime gostitelja", "filtered_custom_rules": "Filtrirano s pravili filtriranja po meri", @@ -598,15 +598,15 @@ "blocklist": "Seznam nedovoljenih", "milliseconds_abbreviation": "ms", "cache_size": "Velikost predpomnilnika", - "cache_size_desc": "Velikost predpomnilnika DNS (v bajtih)", + "cache_size_desc": "Velikost predpomnilnika DNS (v bajtih).", "cache_ttl_min_override": "Preglasi najmanjši TTL", "cache_ttl_max_override": "Preglasi največji TTL", "enter_cache_size": "Vnesite velikost predpomnilnika (v bajtih)", "enter_cache_ttl_min_override": "Vnesite najmanjši TTL (v sekundah)", "enter_cache_ttl_max_override": "Vnesite največji TTL (v sekundah)", - "cache_ttl_min_override_desc": "Razširite kratke vrednosti časa v živo (v sekundah), ki jih prejme strežnik za predpomnjenje, ko predpomni odzive DNS", - "cache_ttl_max_override_desc": "Nastavi največjo vrednost časa v živo (v sekundah) za vnose v predpomnilnik DNS", - "ttl_cache_validation": "Najmanjša vrednost predpomnilnika TTL mora biti manjša ali enaka največji vrednosti", + "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.", "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", @@ -624,9 +624,9 @@ "adg_will_drop_dns_queries": "AdGuard Home bo izpustil vse poizvedbe DNS iz tega odjemalca.", "filter_allowlist": "OPOZORILO: S to akcijo bo pravilo \"{{disallowed_rule}}\" izključeno s seznama dovoljenih odjemalcev.", "last_rule_in_allowlist": "Tega odjemalca ni mogoče onemogočiti, ker izključitev pravila \"{{disallowed_rule}}\" bo ONEMOGOČILO seznam 'Dovoljeni odjemalci'.", - "experimental": "Eksperimentalno", "use_saved_key": "Uporabi prej shranjeni ključ", "parental_control": "Starševski nadzor", "safe_browsing": "Varno brskanje", - "served_from_cache": "{{value}} (postreženo iz predpomnilnika)" + "served_from_cache": "{{value}} (postreženo iz predpomnilnika)", + "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 59aad3a0..3c6a19f2 100644 --- a/client/src/__locales/sr-cs.json +++ b/client/src/__locales/sr-cs.json @@ -524,7 +524,7 @@ "allowed": "Dozvoljeno", "filtered": "Filtrirano", "rewritten": "Prepisano", - "safe_search": "Sigurna pretraga", + "safe_search": "uključi sigurno pretraživanje", "blocklist": "Lista blokiranih", "milliseconds_abbreviation": "ms", "cache_size": "Veličina predmemorije", @@ -549,6 +549,5 @@ "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.", - "experimental": "Eksperimentalno", "parental_control": "Roditeljska kontrola" } diff --git a/client/src/__locales/sv.json b/client/src/__locales/sv.json index 195a651f..8ab55d81 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}}\"", @@ -94,7 +94,7 @@ "filters": "Filter", "filter": "Filter", "query_log": "Förfrågningslogg", - "compact": "Komprimera", + "compact": "Kompakt", "nothing_found": "Inget hittades", "faq": "FAQ", "version": "version", @@ -532,7 +532,7 @@ "netname": "Nätverksnamn", "network": "Nätverk", "descr": "Beskrivning", - "whois": "Whois", + "whois": "WHOIS", "filtering_rules_learn_more": "<0>Mer info om att skapa dina egna blockeringslistor för värdar.", "blocked_by_response": "Blockerad av CNAME eller IP i svaret", "blocked_by_cname_or_ip": "Blockerad av CNAME eller IP", @@ -562,7 +562,7 @@ "choose_from_list": "Välj från listan", "add_custom_list": "Lägg till en anpassad lista", "host_whitelisted": "Värden är tillåten", - "check_ip": "IP adresser: {{ip}}", + "check_ip": "IP-adresser: {{ip}}", "check_cname": "CNAME: {{cname}}", "check_reason": "Anledning: {{reason}}", "check_service": "Service namn: {{service}}", @@ -594,7 +594,7 @@ "allowed": "Vitlistade", "filtered": "Filtrerad", "rewritten": "Omskriven", - "safe_search": "Säker surf", + "safe_search": "Säker sökning", "blocklist": "Blocklista", "milliseconds_abbreviation": "ms", "cache_size": "Cachestorlek", @@ -624,7 +624,6 @@ "adg_will_drop_dns_queries": "AdGuard Home kommer att kasta alla DNS-frågor från den här klienten.", "filter_allowlist": "VARNING: Denna åtgärd kommer också att utesluta regeln \"{{disallowed_rule}}\" från listan över tillåtna klienter.", "last_rule_in_allowlist": "Det går inte att avvisa den här klienten eftersom att utesluta regeln \"{{disallowed_rule}}\" kommer att INAKTIVERA listan \"Tillåtna klienter\".", - "experimental": "Experimentell", "use_saved_key": "Använd den tidigare sparade nyckeln", "parental_control": "Föräldrakontroll", "safe_browsing": "Säker surfning", diff --git a/client/src/__locales/tr.json b/client/src/__locales/tr.json index bf0431f7..86683857 100644 --- a/client/src/__locales/tr.json +++ b/client/src/__locales/tr.json @@ -1,7 +1,7 @@ { "client_settings": "İstemci ayarları", - "example_upstream_reserved": "<0>Belirli alan adları için DNS üst sunucusu tanımlayabilirsiniz.", - "example_upstream_comment": "Bir yorum belirtebilirsiniz", + "example_upstream_reserved": "<0>belirli alan adları için bir üst sunucusu;", + "example_upstream_comment": "bir yorum.", "upstream_parallel": "Tüm üst sunucuları eş zamanlı sorgulayarak çözümlemeyi hızlandırmak için paralel sorgular kullanın.", "parallel_requests": "Paralel istekler", "load_balancing": "Yük dengeleme", @@ -35,24 +35,24 @@ "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", - "gateway_or_subnet_invalid": "Alt ağ maskesi geçersiz", + "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.", + "gateway_or_subnet_invalid": "Alt ağ maskesi geçersiz.", "dhcp_form_gateway_input": "Ağ geçidi IP", "dhcp_form_subnet_input": "Alt ağ maskesi", "dhcp_form_range_title": "IP adresi aralığı", @@ -143,7 +143,7 @@ "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.", "use_adguard_parental": "AdGuard ebeveyn denetimi web hizmetini kullan", "use_adguard_parental_hint": "AdGuard Home, alan adının yetişkin içerik bulundurup bulundurmadığını kontrol eder. Gezinti koruması web hizmeti ile kullandığımız aynı gizlilik dostu API'yi kullanır.", - "enforce_safe_search": "Güvenli aramayı kullan", + "enforce_safe_search": "Güvenli Aramayı kullan", "enforce_save_search_hint": "AdGuard Home, şu arama motorlarında güvenli aramayı uygular: Google, YouTube, Bing, DuckDuckGo, Yandex ve Pixabay.", "no_servers_specified": "Sunucu belirtilmedi", "general_settings": "Genel ayarlar", @@ -165,10 +165,10 @@ "enabled_filtering_toast": "Filtreleme etkin", "disabled_safe_browsing_toast": "Güvenli Gezinti devre dışı bırakıldı", "enabled_safe_browsing_toast": "Güvenli Gezinti etkinleştirildi", - "disabled_parental_toast": "Ebeveyn denetimi devre dışı bırakıldı", - "enabled_parental_toast": "Ebeveyn denetimi etkinleştirildi", - "disabled_safe_search_toast": "Güvenli arama devre dışı bırakıldı", - "enabled_save_search_toast": "Güvenli arama etkinleştirildi", + "disabled_parental_toast": "Ebeveyn Denetimi devre dışı bırakıldı", + "enabled_parental_toast": "Ebeveyn Denetimi etkinleştirildi", + "disabled_safe_search_toast": "Güvenli Arama devre dışı bırakıldı", + "enabled_save_search_toast": "Güvenli Arama etkinleştirildi", "enabled_table_header": "Etkin", "name_table_header": "İsim", "list_url_table_header": "Liste URL'si", @@ -196,25 +196,25 @@ "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": "URL biçimi geçersiz.", + "form_error_url_or_path_format": "Listenin URL adresi veya dosya konumu geçersiz.", "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ı", "examples_title": "Örnekler", - "example_meaning_filter_block": "example.org alan adına ve tüm alt alan adlarına olan erişimi engeller", - "example_meaning_filter_whitelist": "example.org alan adına ve tüm alt alan adlarına olan erişim engelini kaldırır", - "example_meaning_host_block": "AdGuard Home, example.org adresi için 127.0.0.1 adresine yönlendirme yapacaktır (alt alan adları için geçerli değildir)", - "example_comment": "! Buraya bir yorum ekledim", - "example_comment_meaning": "sadece bir yorum", - "example_comment_hash": "# Bir yorum daha ekledim", - "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_dot": "şifrelenmiş <0>DNS-over-TLS", - "example_upstream_doh": "şifrelenmiş <0>DNS-over-HTTPS", - "example_upstream_doq": "şifrelenmiş <0>DNS-over-QUIC", - "example_upstream_sdns": "<1>DNSCrypt veya <2>DNS-over-HTTPS çözümleyicileri için <0>DNS Damgaları kullanabilirsiniz", - "example_upstream_tcp": "normal DNS (TCP üzerinden)", + "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;", + "example_meaning_host_block": "example.org için 127.0.0.1 ile yanıt verin (ancak alt alanları için değil);", + "example_comment": "! Buraya bir yorum gelir.", + "example_comment_meaning": "sadece bir yorum;", + "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_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);", "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 +259,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 IP adresini günlüklere ve 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", @@ -276,8 +276,8 @@ "dns_over_tls": "DNS-over-TLS", "dns_over_quic": "DNS-over-QUIC", "client_id": "İstemci Kimliği", - "client_id_placeholder": "İstemci kimliği girin", - "client_id_desc": "Farklı istemciler, özel bir istemci kimliği ile tanımlanabilir. Burada istemcileri nasıl tanımlayacağınız hakkında daha fazla bilgi edinebilirsiniz.", + "client_id_placeholder": "İstemci Kimliği girin", + "client_id_desc": "İstemciler, İstemci Kimliği ile tanımlanabilir. İstemcileri nasıl tanımlayacağınız hakkında daha fazla bilgiyi buradan öğrenin.", "download_mobileconfig_doh": "DNS-over-HTTPS için .mobileconfig dosyasını indir", "download_mobileconfig_dot": "DNS-over-TLS için .mobileconfig dosyasını indir", "download_mobileconfig": "Yapılandırma dosyasını indir", @@ -309,7 +309,7 @@ "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", + "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", @@ -338,7 +338,7 @@ "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.", - "install_devices_macos_list_1": "Apple simgesinde bulunan Sistem Tercihleri'ne tıklayın.", + "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_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.", @@ -356,7 +356,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", @@ -367,7 +367,7 @@ "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_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ı", + "encryption_doq": "DNS-over-QUIC bağlantı noktası (deneysel)", "encryption_doq_desc": "Bu bağlantı noktası yapılandırılırsa, AdGuard Home, DNS-over-QUIC sunucusunu bu bağlantı noktası üzerinden çalıştıracaktır. Bu özellik deneme aşamasındadır ve güvenilir olmayabilir. Ayrıca, şu anda bu özelliği destekleyen çok fazla istemci yok.", "encryption_certificates": "Sertifikalar", "encryption_certificates_desc": "Şifrelemeyi kullanmak için alan adınıza geçerli bir SSL sertifika zinciri sağlamanız gerekir. <0>{{link}} adresinden ücretsiz bir sertifika alabilir veya güvenilir Sertifika Yetkililerinden satın alabilirsiniz.", @@ -378,26 +378,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_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_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_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": "Şifreler uyuşmuyor", + "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.", "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.", @@ -405,8 +405,8 @@ "update_failed": "Otomatik güncelleme başarısız oldu. Elle güncellemek için lütfen bu adımları uygulayın.", "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": "İstemciler", - "clients_desc": "AdGuard Home'a bağlı cihazları yapılandırın", + "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.", "settings_global": "Genel", "settings_custom": "Özel", "table_client": "İstemci", @@ -417,7 +417,7 @@ "client_edit": "İstemciyi Düzenle", "client_identifier": "Tanımlayıcı", "ip_address": "IP adresi", - "client_identifier_desc": "İstemciler IP adresi, CIDR, MAC adresi veya özel bir istemci kimliği ile tanımlanabilir (DoT/DoH/DoQ için kullanılabilir). İstemcileri nasıl tanımlayacağınız hakkında daha fazla bilgiyi <0>burada bulabilirsiniz.", + "client_identifier_desc": "İstemciler IP adresleri, CIDR, MAC adresleri veya ClientID (DoT/DoH/DoQ için kullanılabilir) ile tanımlanabilir. İstemcileri nasıl tanımlayacağınız hakkında daha fazla bilgiyi <0>buradan edinebilirsiniz.", "form_enter_ip": "IP girin", "form_enter_subnet_ip": "\"{{cidr}}\" alt ağına bir IP adresi girin", "form_enter_mac": "MAC adresi girin", @@ -432,14 +432,14 @@ "clients_not_found": "İstemci bulunamadı", "client_confirm_delete": "\"{{key}}\" istemcisini silmek istediğinizden emin misiniz?", "list_confirm_delete": "Bu listeyi silmek istediğinizden emin misiniz?", - "auto_clients_title": "İstemciler (çalışma zamanı)", - "auto_clients_desc": "AdGuard Home'u kullanan ancak yapılandırmada depolanmayan istemcilerle ilgili veriler", + "auto_clients_title": "Çalışma zamanı istemcileri", + "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_allowed_title": "İzin verilen istemciler", - "access_allowed_desc": "CIDR'lerin, IP adreslerinin veya istemci kimliklerinin listesi. Yapılandırılırsa, AdGuard Home yalnızca bu istemcilerden gelen istekleri kabul eder.", + "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", - "access_disallowed_desc": "CIDR'lerin, IP adreslerinin veya istemci kimliklerinin listesi. Yapılandırılırsa, AdGuard Home bu istemcilerden gelen istekleri keser. İzin verilen istemciler yapılandırılırsa, bu alan yok sayılır.", + "access_disallowed_desc": "CIDR'lerin, IP adreslerinin veya İstemci Kimliklerin listesi. Bu listede girişler varsa, AdGuard Home bu istemcilerden gelen istekleri keser. İzin verilen istemcilerde girişler varsa, bu alan yok sayılır.", "access_blocked_title": "İzin verilmeyen alan adları", "access_blocked_desc": "Bu işlem filtrelerle ilgili değildir. AdGuard Home, bu alan adlarından gelen DNS sorgularını yanıtsız bırakır ve bu sorgular sorgu günlüğünde görünmez. Tam alan adlarını, joker karakterleri veya URL filtre kurallarını belirtebilirsiniz, ör. \"example.org\", \"*.example.org\" veya \"||example.org^\".", "access_settings_saved": "Erişim ayarları başarıyla kaydedildi!", @@ -453,7 +453,7 @@ "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_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 desteğini ekler.", + "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.", "setup_dns_privacy_ios_2": "<0>iOS için AdGuard, <1>DNS-over-HTTPS ve <1>DNS-over-TLS protokolünü destekler.", "setup_dns_privacy_other_title": "Diğer kullanım alanları", @@ -475,8 +475,8 @@ "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": "Alan adı biçimi geçersiz.", + "form_error_answer_format": "Yanıt biçimi geçersiz.", "configure": "Yapılandır", "main_settings": "Ana ayarlar", "block_services": "Belirli hizmetleri engelle", @@ -507,7 +507,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", @@ -532,7 +532,7 @@ "netname": "Ağ adı", "network": "Ağ", "descr": "Açıklama", - "whois": "Whois", + "whois": "WHOIS", "filtering_rules_learn_more": "Kendi ana bilgisayar 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", @@ -552,10 +552,10 @@ "autofix_warning_list": "Bu görevleri gerçekleştirecek: <0>Sistem DNSStubListener'ı devre dışı bırakın <0>DNS sunucusu adresini 127.0.0.1 olarak ayarlayın <0>/etc/resolv.conf'un sembolik bağlantı hedefini /run/systemd/resolve/resolv.conf ile değiştirin<0> <0>DNSStubListener'ı durdurun (systemd çözümlenmiş hizmeti yeniden yükleyin)", "autofix_warning_result": "Sonuç olarak, sisteminizden gelen tüm DNS istekleri varsayılan olarak AdGuard Home tarafından işlenecektir.", "tags_title": "Etiketler", - "tags_desc": "İstemciyi tanımlayan etiketleri seçebilirsiniz. Etiketler, filtreleme kurallarına dahil edilebilir ve bunları daha doğru bir şekilde uygulamanıza olanak tanır. <0>Daha fazla bilgi edinin", + "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 bilgisayar adının filtreleme durumunu kontrol edin.", "check": "Denetle", "form_enter_host": "Ana bilgisayar adı girin", "filtered_custom_rules": "Özel filtreleme kurallarına göre filtrelendi", @@ -594,19 +594,19 @@ "allowed": "İzin verilen", "filtered": "Filtrelenen", "rewritten": "Yeniden yazılan", - "safe_search": "Güvenli arama", + "safe_search": "Güvenli Arama", "blocklist": "Engel listesi", "milliseconds_abbreviation": "ms", "cache_size": "Önbellek boyutu", - "cache_size_desc": "DNS önbellek boyutu (bayt cinsinden)", + "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", "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)", - "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 değeri, maksimum değerden küçük veya bu değere eşit olmalıdır", + "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.", "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", @@ -624,9 +624,9 @@ "adg_will_drop_dns_queries": "AdGuard Home, bu istemciden gelen tüm DNS sorgularını yok sayar.", "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.", - "experimental": "Deneysel", "use_saved_key": "Önceden kaydedilmiş anahtarı kullan", "parental_control": "Ebeveyn Denetimi", "safe_browsing": "Güvenli Gezinti", - "served_from_cache": "{{value}} (önbellekten kullanıldı)" + "served_from_cache": "{{value}} (önbellekten kullanıldı)", + "form_error_password_length": "Parola en az {{value}} karakter uzunluğunda olmalı." } diff --git a/client/src/__locales/uk.json b/client/src/__locales/uk.json index 42db7636..eb721af4 100644 --- a/client/src/__locales/uk.json +++ b/client/src/__locales/uk.json @@ -1,7 +1,7 @@ { "client_settings": "Налаштування клієнта", - "example_upstream_reserved": "Ви можете вказати DNS-сервер <0>для певних доменів", - "example_upstream_comment": "Ви можете вказати коментар", + "example_upstream_reserved": "DNS-сервер <0>для певних доменів;", + "example_upstream_comment": "коментар.", "upstream_parallel": "Використовувати паралельні запити, щоб пришвидшити вирішення одночасною чергою всіх оригінальних серверів.", "parallel_requests": "Паралельні запити", "load_balancing": "Балансування навантаження", @@ -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": "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-адрес", @@ -196,20 +196,20 @@ "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-файли", "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": "блокує доступ до доменів, що відповідають вказаному звичайному виразу", - "example_upstream_regular": "звичайний DNS (через UDP)", + "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_dot": "зашифрований <0>DNS-over-TLS", "example_upstream_doh": "зашифрований <0>DNS-over-HTTPS", "example_upstream_doq": "зашифрований <0>DNS-over-QUIC", @@ -431,7 +431,7 @@ "clients_not_found": "Клієнтів не знайдено", "client_confirm_delete": "Ви впевнені, що хочете видалити клієнта «{{key}}»?", "list_confirm_delete": "Ви впевнені, що хочете видалити цей список?", - "auto_clients_title": "Клієнти (поза налаштуванням)", + "auto_clients_title": "Runtime-клієнти", "auto_clients_desc": "Дані про клієнтів, які використовують AdGuard Home, але не зберігаються в конфігурації", "access_title": "Налаштування доступу", "access_desc": "Тут ви можете налаштувати правила доступу для DNS-сервера AdGuard Home.", @@ -531,7 +531,7 @@ "netname": "Назва мережі", "network": "Мережа", "descr": "Опис", - "whois": "Whois", + "whois": "WHOIS", "filtering_rules_learn_more": "<0>Як створити власні списки блокування.", "blocked_by_response": "У відповідь заблоковано по CNAME або IP", "blocked_by_cname_or_ip": "Заблоковано по CNAME або IP", @@ -551,10 +551,10 @@ "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>Докладніше", + "tags_desc": "Ви можете вибрати теги, які відповідають клієнту. Теги можна використати в правилах фільтрування, щоб точніше застосовувати їх. <0>Докладніше.", "form_select_tags": "Виберіть теги клієнта", "check_title": "Перевірте фільтрування", - "check_desc": "Перевірте чи фільтрується назва вузла", + "check_desc": "Перевірити чи фільтрується назва вузла.", "check": "Перевірити", "form_enter_host": "Введіть назву вузла", "filtered_custom_rules": "Відфільтровано за власними правилами фільтрування", @@ -597,7 +597,7 @@ "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": "Введіть розмір кешу (байт)", @@ -623,9 +623,9 @@ "adg_will_drop_dns_queries": "AdGuard Home буде видаляти всі запити DNS із цього клієнта.", "filter_allowlist": "ПОПЕРЕДЖЕННЯ: Таким чином ви також виключите правило «{{disallowed_rule}}» зі списку дозволених клієнтів.", "last_rule_in_allowlist": "Неможливо заблокувати цього клієнта, тому що правило «{{disallowed_rule}}» ВИМКНЕ режим списку дозволів.", - "experimental": "Експериментальний", "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/vi.json b/client/src/__locales/vi.json index 394801f1..28ec3b1b 100644 --- a/client/src/__locales/vi.json +++ b/client/src/__locales/vi.json @@ -583,7 +583,7 @@ "allowed": "Được phép", "filtered": "Đã lọc", "rewritten": "Đã viết lại", - "safe_search": "Tìm kiếm an toàn", + "safe_search": "Kích hoạt Tìm kiếm An toàn", "blocklist": "Danh sách chặn", "milliseconds_abbreviation": "ms", "cache_size": "Kích thước cache", @@ -611,6 +611,5 @@ "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\".", - "experimental": "Thử nghiệm", "parental_control": "Quản lý của phụ huynh" } diff --git a/client/src/__locales/zh-cn.json b/client/src/__locales/zh-cn.json index b24dc0c4..dce4be31 100644 --- a/client/src/__locales/zh-cn.json +++ b/client/src/__locales/zh-cn.json @@ -1,7 +1,7 @@ { "client_settings": "客户端设置", - "example_upstream_reserved": "您可以<0>为特定域名指定上游 DNS 服务器", - "example_upstream_comment": "您可以指定注解", + "example_upstream_reserved": "指定为<0>特定域名的上游服务器;", + "example_upstream_comment": "注释。", "upstream_parallel": "使用并行请求以同时查询所有上游服务器来加快解析速度。", "parallel_requests": "并行请求", "load_balancing": "负载均衡", @@ -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 格式客户 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 地址范围", @@ -196,25 +196,25 @@ "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": "系统主机文件", "examples_title": "范例", - "example_meaning_filter_block": "拦截 example.org 域名及其所有子域名", - "example_meaning_filter_whitelist": "放行 example.org 及其所有子域名", - "example_meaning_host_block": "AdGuard Home 现在将会把 example.org(但不包括它的子域名)解析到 127.0.0.1。", - "example_comment": "! 这是一行注释", - "example_comment_meaning": "只是一条注释", - "example_comment_hash": "# 这也是一行注释", - "example_regex_meaning": "阻止访问与<0>指定的正则表达式匹配的域", - "example_upstream_regular": "常规 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_meaning_filter_block": "阻止 example.org 域名及其所有子域名;", + "example_meaning_filter_whitelist": "解除 example.org 及其所有子域名的封锁;", + "example_meaning_host_block": "对 example.org(不包括它的子域名)以 127.0.0.1 作为响应;", + "example_comment": "! 这是一行注释。", + "example_comment_meaning": "只是一条注释;", + "example_comment_hash": "# 这也是一行注释。", + "example_regex_meaning": "阻止访问与指定的正则表达式匹配的域名。", + "example_upstream_regular": "常规 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 );", "all_lists_up_to_date_toast": "所有列表都是最新的", "updated_upstream_dns_toast": "上游服务器保存成功", "dns_test_ok_toast": "指定的 DNS 服务器现已正常运行", @@ -259,10 +259,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": "无效域名", @@ -277,7 +277,7 @@ "dns_over_quic": "DNS-over-QUIC", "client_id": "客户端 ID", "client_id_placeholder": "输入客户端 ID", - "client_id_desc": "可根据一个特殊的客户端 ID 识别不同客户端。在 这里你可以了解到更多关于如何识别客户端的信息。", + "client_id_desc": "可根据一个特殊的客户端 ID 识别不同客户端。在这里您可以了解到更多关于如何识别客户端的信息。", "download_mobileconfig_doh": "下载适用于 DNS-over-HTTPS 的 .mobileconfig", "download_mobileconfig_dot": "下载适用于 DNS-over-TLS 的 .mobileconfig", "download_mobileconfig": "下载配置文件", @@ -309,7 +309,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 +334,12 @@ "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_3": "在窗口的左侧找到 ”更改适配器设置“ 并点击进入。", - "install_devices_windows_list_4": "选择您正在连接的网络设备,右击它并选择 ”属性“ 。", + "install_devices_windows_list_3": "在窗口的左侧点击「更改适配器设置」。", + "install_devices_windows_list_4": "选择您正在连接的网络设备,右击它并选择「属性”」。", "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_1": "点击苹果图标,进入「系统首选项」。", + "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 +356,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": "输入您的域名", @@ -367,7 +367,7 @@ "encryption_https_desc": "如果配置了 HTTPS 端口,AdGuard Home 管理界面将可以通过 HTTPS 访问,它还将在在 '/dns-query' 位置提供 DNS-over-HTTPS 。", "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}} 上获得免费证书,也可以从受信任的证书颁发机构购买证书。", @@ -378,26 +378,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 提供商列表。", @@ -405,8 +405,8 @@ "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": "客户端", @@ -417,7 +417,7 @@ "client_edit": "编辑客户端", "client_identifier": "标识符", "ip_address": "IP 地址", - "client_identifier_desc": "客户端可通过 IP 、MAC 地址、CIDR 或特殊 ID(可用于 DoT/DoH/DoQ)被识别。<0>这里您可多了解如何识别客户端。", + "client_identifier_desc": "客户端可通过 IP 、MAC 地址、CIDR 或客户端 ID(可用于 DoT/DoH/DoQ)被识别。<0>这里您可多了解如何识别客户端。", "form_enter_ip": "输入 IP", "form_enter_subnet_ip": "输入一个 IP 地址,其须位于子网\"{{cidr}}\"", "form_enter_mac": "输入 MAC", @@ -433,13 +433,13 @@ "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_allowed_title": "允许的客户端", - "access_allowed_desc": "CIDR、IP 地址或客户端 ID 的列表。如已配置,则 AdGuard Home 将仅接受来自这些客户端的请求。", + "access_allowed_desc": "CIDR、IP 地址或客户端 ID 的列表。如已配置,则 AdGuard Home 将仅接受来自这些客户端的请求。", "access_disallowed_title": "不允许的客户端", - "access_disallowed_desc": "CIDR、IP 地址或客户端 ID 的列表。如果已配置,则 AdGuard Home 将丢弃来自这些 IP 地址的请求。如果允许的客户端已配置,此字段将会被忽略。", + "access_disallowed_desc": "CIDR、IP 地址或客户端 ID 的列表。如果已配置,则 AdGuard Home 将丢弃来自这些客户端的请求。如果允许的客户端已配置,此字段将会被忽略。", "access_blocked_title": "不允许的域名", "access_blocked_desc": "不要将此功能与过滤器混淆。AdGuard Home 将排除匹配这些网域的 DNS 查询,并且这些查询将不会在查询日志中显示。在此可以明确指定域名、通配符(wildcard)和网址过滤的规则,例如 \"example.org\"、\"*.example.org\" 或 \"||example.org^\"。", "access_settings_saved": "访问设置保存成功", @@ -475,8 +475,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": "阻止特定服务", @@ -507,7 +507,7 @@ "filter_updated": "成功更新过滤器", "statistics_configuration": "统计配置", "statistics_retention": "统计保留", - "statistics_retention_desc": "如果您减少该间隔的数值, 某些数据可能会丢失", + "statistics_retention_desc": "如果您减少该间隔的数值, 某些数据可能会丢失。", "statistics_clear": " 清除统计数据", "statistics_clear_confirm": "您确定要清除统计数据?", "statistics_retention_confirm": "您确定要更改统计记录保留时间吗? 如果您减少间隔时间的值, 某些数据可能会丢失。", @@ -532,7 +532,7 @@ "netname": "网络名称", "network": "网络", "descr": "描述", - "whois": "Whois", + "whois": "WHOIS", "filtering_rules_learn_more": "<0>了解更多关于创建自己的hosts清单。", "blocked_by_response": "因响应的CNAME或IP被屏蔽", "blocked_by_cname_or_ip": "按CNAME或IP拦截", @@ -552,10 +552,10 @@ "autofix_warning_list": "其将会进行如下工作:<0>停用系统DNSStubListener<0>设置DNS服务器地址为127.0.0.1<0>将/etc/resolv.conf的符号链接目标替换为/run/systemd/resolv/resolv.conf<0>停止DNSStubListener(重新加载系统解析服务)", "autofix_warning_result": "因此,默认情况下所有来自系统的DNS请求都将由AdGuardHome处理。", "tags_title": "标签", - "tags_desc": "您可以选择与客户端对应的标记。标签可以包含在过滤规则中,并允许您更准确地应用它们。<0>了解更多", + "tags_desc": "您可以选择与客户端对应的标记。标签可以包含在过滤规则中,并允许您更准确地应用它们。<0>了解更多。", "form_select_tags": "选择客户端标签", "check_title": "检查过滤", - "check_desc": "检查主机名是否被过滤", + "check_desc": "检查主机名是否被过滤。", "check": "检查", "form_enter_host": "输入主机名称", "filtered_custom_rules": "被自定义过滤规则过滤", @@ -598,15 +598,15 @@ "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": "缓存 DNS 响应时,延长从上游服务器接收到的 TTL 值 (秒)", - "cache_ttl_max_override_desc": "设定 DNS 缓存条目的最大 TTL 值(秒)", - "ttl_cache_validation": "最小缓存TTL值必须小于或等于最大值", + "cache_ttl_min_override_desc": "缓存 DNS 响应时,延长从上游服务器接收到的 TTL 值 (秒)。", + "cache_ttl_max_override_desc": "设定 DNS 缓存条目的最大 TTL 值(秒)。", + "ttl_cache_validation": "最小缓存 TTL 值必须小于或等于最大值。", "cache_optimistic": "乐观缓存", "cache_optimistic_desc": "即使条目已过期,也让 AdGuard Home 从缓存中响应,并尝试刷新它们。", "filter_category_general": "常规", @@ -624,9 +624,9 @@ "adg_will_drop_dns_queries": "AdGuard Home 会终止所有来自此客户端的DNS查询。", "filter_allowlist": "警告:此操作将把规则 \"{{disallowed_rule}}\" 排除在允许客户端的列表之外。", "last_rule_in_allowlist": "无法禁止此客户端,因为排除 “{{disallowed_rule}}” 规则将禁用“允许客户端”的列表。", - "experimental": "实验性的", "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/zh-hk.json b/client/src/__locales/zh-hk.json index e0ffb3e3..cae94b69 100644 --- a/client/src/__locales/zh-hk.json +++ b/client/src/__locales/zh-hk.json @@ -608,6 +608,5 @@ "original_response": "原始回應", "click_to_view_queries": "按一下以檢視查詢結果", "port_53_faq_link": "連接埠 53 經常被「DNSStubListener」或「systemd-resolved」服務佔用。請閱讀下列有關解決<0>這個問題的說明", - "adg_will_drop_dns_queries": "AdGuard Home 將停止回應此用戶端的所有 DNS 查詢。", - "experimental": "實驗性" + "adg_will_drop_dns_queries": "AdGuard Home 將停止回應此用戶端的所有 DNS 查詢。" } diff --git a/client/src/__locales/zh-tw.json b/client/src/__locales/zh-tw.json index 0757f08d..52bbc4e0 100644 --- a/client/src/__locales/zh-tw.json +++ b/client/src/__locales/zh-tw.json @@ -1,7 +1,7 @@ { "client_settings": "用戶端設定", - "example_upstream_reserved": "您可<0>對於特定的網域明確指定 DNS 上游", - "example_upstream_comment": "您可明確指定註解", + "example_upstream_reserved": "<0>供特定的網域之上游;", + "example_upstream_comment": "註解。", "upstream_parallel": "透過同時地查詢所有上游的伺服器,使用並行的查詢以加速解析。", "parallel_requests": "並行的請求", "load_balancing": "負載平衡", @@ -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 位址範圍", @@ -196,25 +196,25 @@ "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": "系統主機檔案", "examples_title": "範例", - "example_meaning_filter_block": "封鎖至 example.org 網域及其所有的子網域之存取", - "example_meaning_filter_whitelist": "解除封鎖至 example.org 網域及其所有的子網域之存取", - "example_meaning_host_block": "AdGuard Home 現在將對 example.org 網域(但非其子網域)返回 127.0.0.1 位址。", - "example_comment": "! 看,一個註解", - "example_comment_meaning": "只是一個註解", - "example_comment_hash": "# 也是一個註解", - "example_regex_meaning": "封鎖至與該已明確指定的規則運算式(Regular Expression)相符的網域之存取", - "example_upstream_regular": "一般的 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_meaning_filter_block": "封鎖至 example.org 網域及其所有的子網域之存取;", + "example_meaning_filter_whitelist": "解除封鎖至 example.org 網域及其所有的子網域之存取;", + "example_meaning_host_block": "對 example.org(但非對其子網域)以 127.0.0.1 回覆;", + "example_comment": "! 看,一個註解。", + "example_comment_meaning": "只是一個註解;", + "example_comment_hash": "# 也是一個註解。", + "example_regex_meaning": "封鎖至與該已明確指定的規則運算式(Regular Expression)相符的網域之存取。", + "example_upstream_regular": "常規 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);", "all_lists_up_to_date_toast": "所有的清單已是最新的", "updated_upstream_dns_toast": "上游的伺服器被成功地儲存", "dns_test_ok_toast": "已明確指定的 DNS 伺服器正在正確地運作", @@ -259,10 +259,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)", @@ -277,7 +277,7 @@ "dns_over_quic": "DNS-over-QUIC", "client_id": "用戶端 ID", "client_id_placeholder": "輸入用戶端 ID", - "client_id_desc": "不同的用戶端可根據特殊的用戶端 ID 被識別。<0>於此,您可了解更多關於如何識別用戶端。", + "client_id_desc": "用戶端可根據用戶端 ID 被識別。於此,了解更多關於如何識別用戶端。", "download_mobileconfig_doh": "下載用於 DNS-over-HTTPS 的 .mobileconfig", "download_mobileconfig_dot": "下載用於 DNS-over-TLS 的 .mobileconfig", "download_mobileconfig": "下載配置檔案", @@ -309,7 +309,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 +334,12 @@ "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_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": "選擇\"使用下列的 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": "從 Android 選單主畫面中,輕觸設定。", @@ -356,7 +356,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": "輸入您的域名", @@ -367,7 +367,7 @@ "encryption_https_desc": "如果 HTTPS 連接埠被配置,AdGuard Home 管理員介面透過 HTTPS 將為可存取的,且它也將於 '/dns-query' 位置上提供 DNS-over-HTTPS。", "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}} 上您可取得免費的憑證或您可從受信任的憑證授權單位之一購買它。", @@ -378,26 +378,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 供應商之清單。", @@ -405,8 +405,8 @@ "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": "用戶端", @@ -417,7 +417,7 @@ "client_edit": "編輯用戶端", "client_identifier": "識別碼", "ip_address": "IP 位址", - "client_identifier_desc": "用戶端可根據 IP 位址、無類別網域間路由(CIDR)、媒體存取控制(MAC)位址或特殊的用戶端 ID(可被用於 DoT/DoH/DoQ)被識別。<0>於此,您可了解更多關於如何識別用戶端。", + "client_identifier_desc": "用戶端可根據它們的 IP 位址、無類別網域間路由(CIDR)、媒體存取控制(MAC)位址或用戶端 ID(可被用於 DoT/DoH/DoQ)被識別。<0>於此,了解更多關於如何識別用戶端。", "form_enter_ip": "輸入 IP", "form_enter_subnet_ip": "在子網路 \"{{cidr}}\" 中輸入一組 IP 位址", "form_enter_mac": "輸入媒體存取控制(MAC)", @@ -432,14 +432,14 @@ "clients_not_found": "無已發現之用戶端", "client_confirm_delete": "您確定您想要刪除用戶端 \"{{key}}\" 嗎?", "list_confirm_delete": "您確定您想要刪除該清單嗎?", - "auto_clients_title": "用戶端(執行時期)", - "auto_clients_desc": "使用 AdGuard Home 但未被儲存在配置中之關於用戶端的資料", + "auto_clients_title": "執行時期用戶端", + "auto_clients_desc": "未於可能仍然使用 AdGuard Home 的持續性用戶端之清單上的裝置。", "access_title": "存取設定", "access_desc": "於此您可配置用於 AdGuard Home DNS 伺服器之存取規則。", "access_allowed_title": "已允許的用戶端", - "access_allowed_desc": "無類別網域間路由(CIDRs)、IP 位址或用戶端 ID 之清單。如果被配置,AdGuard Home 將接受僅來自這些用戶端的請求。", + "access_allowed_desc": "無類別網域間路由(CIDRs)、IP 位址或用戶端 IDs 之清單。如果此清單有項目,AdGuard Home 將接受僅來自這些用戶端的請求。", "access_disallowed_title": "未被允許的用戶端", - "access_disallowed_desc": "無類別網域間路由(CIDRs)、IP 位址或用戶端 IDs 之清單。如果被配置,AdGuard Home 將排除來自這些用戶端的請求。如果已允許的用戶端被配置,此欄位被忽略。", + "access_disallowed_desc": "無類別網域間路由(CIDRs)、IP 位址或用戶端 IDs 之清單。如果此清單有項目,AdGuard Home 將排除來自這些用戶端的請求。如果在已允許的用戶端中有項目,此欄位被忽略。", "access_blocked_title": "未被允許的網域", "access_blocked_desc": "不要把這個和過濾器混淆。AdGuard Home 排除與這些網域相符的 DNS 查詢,且這些查詢甚至不會出現在查詢記錄中。您可相應地明確指定確切的域名、萬用字元(wildcard)或網址過濾器的規則,例如,\"example.org\"、\"*.example.org\" 或 \"||example.org^\"。", "access_settings_saved": "存取設定被成功地儲存", @@ -475,8 +475,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": "封鎖特定的服務", @@ -507,7 +507,7 @@ "filter_updated": "該清單已被成功地更新", "statistics_configuration": "統計資料配置", "statistics_retention": "統計資料保留", - "statistics_retention_desc": "如果您減少該間隔值,某些資料將被丟失", + "statistics_retention_desc": "如果您減少該間隔值,某些資料將被丟失。", "statistics_clear": " 清除統計資料", "statistics_clear_confirm": "您確定您想要清除統計資料嗎?", "statistics_retention_confirm": "您確定您想要更改統計資料保留嗎?如果您減少該間隔值,某些資料將被丟失", @@ -532,7 +532,7 @@ "netname": "網路名稱", "network": "網路", "descr": "說明", - "whois": "Whois", + "whois": "WHOIS", "filtering_rules_learn_more": "<0>了解更多有關創建您自己的主機(hosts)清單。", "blocked_by_response": "在回應過程中被正規名稱(CNAME)或 IP 封鎖", "blocked_by_cname_or_ip": "被正規名稱(CNAME)或 IP 封鎖", @@ -552,10 +552,10 @@ "autofix_warning_list": "它將執行這些任務:<0>撤銷系統 DNSStubListener <0>設定 DNS 伺服器位址為 127.0.0.1 <0>用 /run/systemd/resolve/resolv.conf 取代 /etc/resolv.conf 的符號連結目標 <0>停止 DNSStubListener(重新載入 systemd-resolved 服務)", "autofix_warning_result": "因此,預設下,來自您的系統之所有的 DNS 請求將被 AdGuard Home 處理。", "tags_title": "標記", - "tags_desc": "您可選擇對應該用戶端的標記。標記可被包括在過濾規則中並允許您更準確地套用它們。<0>了解更多", + "tags_desc": "您可選擇對應該用戶端的標記。包括在過濾規則中的標記以更準確地套用它們。<0>了解更多。", "form_select_tags": "選擇用戶端標記", "check_title": "檢查該過濾", - "check_desc": "檢查該主機名稱是否被過濾", + "check_desc": "檢查主機名稱是否被過濾。", "check": "檢查", "form_enter_host": "輸入主機名稱", "filtered_custom_rules": "被自訂的過濾規則過濾", @@ -598,15 +598,15 @@ "blocklist": "封鎖清單", "milliseconds_abbreviation": "ms", "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": "輸入最小的存活時間(秒)", "enter_cache_ttl_max_override": "輸入最大的存活時間(秒)", - "cache_ttl_min_override_desc": "當快取 DNS 回應時,延長從上游的伺服器收到的短存活時間數值(秒)", - "cache_ttl_max_override_desc": "設定最大的存活時間數值(秒)供在 DNS 快取中的項目", - "ttl_cache_validation": "最小的快取存活時間(TTL)數值必須小於或等於最大的數值", + "cache_ttl_min_override_desc": "當快取 DNS 回應時,延長從上游的伺服器收到的短存活時間數值(秒)。", + "cache_ttl_max_override_desc": "設定最大的存活時間數值(秒)供在 DNS 快取中的項目。", + "ttl_cache_validation": "最小的快取存活時間(TTL)覆寫必須小於或等於最大的。", "cache_optimistic": "樂觀快取", "cache_optimistic_desc": "即使當項目為已到期的,從快取使 AdGuard Home 回覆,並還嘗試重新整理它們。", "filter_category_general": "一般的", @@ -624,9 +624,9 @@ "adg_will_drop_dns_queries": "AdGuard Home 將持續排除來自此用戶端之所有的 DNS 查詢。", "filter_allowlist": "警告:此操作將把 \"{{disallowed_rule}}\" 規則排除在已允許用戶端的清單之外。", "last_rule_in_allowlist": "無法禁止此用戶端,因為排除 “{{disallowed_rule}}” 規則將禁用“已允許用戶端”的清單。", - "experimental": "實驗性的", "use_saved_key": "使用該先前已儲存的金鑰", "parental_control": "家長控制", "safe_browsing": "安全瀏覽", - "served_from_cache": "{{value}} (由快取提供)" + "served_from_cache": "{{value}} (由快取提供)", + "form_error_password_length": "密碼必須為至少長 {{value}} 個字元。" } From ff1e108bfe820c533bd757feb25c10a88f9127b1 Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Mon, 28 Feb 2022 16:26:45 +0300 Subject: [PATCH 128/135] Pull request: 4213 add bsd syslog Merge in DNS/adguard-home from 4213-bsd-syslog to master Updates #4046. Closes #4213. Squashed commit of the following: commit 1e57c75c4184e83b09cfd27456340ca9447791be Author: Eugene Burkov Date: Mon Feb 28 16:20:32 2022 +0300 home: imp error msg commit 63059d031153ff9b6dc9aecd9522d2ad4f8448da Author: Eugene Burkov Date: Mon Feb 28 15:36:37 2022 +0300 all: imp log of changes commit 682c3c9e8986b6bdf2d0c665c9cad4a71fd2cc83 Author: Eugene Burkov Date: Mon Feb 28 15:29:29 2022 +0300 home: imp code commit 86c311a71d07823c18521890bea7c898c117466b Author: Eugene Burkov Date: Mon Feb 28 15:03:02 2022 +0300 home: add bsd syslog --- CHANGELOG.md | 3 +++ internal/home/service.go | 22 +++++++++++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2976e276..a54f8c57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ and this project adheres to ### Added +- Logs are now collected by default on FreeBSD and OpenBSD when AdGuard Home is + installed as a service ([#4213]). - `windows/arm64` support ([#3057]). ### Changed @@ -87,6 +89,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 +[#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 diff --git a/internal/home/service.go b/internal/home/service.go index e5d0ba39..081974e2 100644 --- a/internal/home/service.go +++ b/internal/home/service.go @@ -4,6 +4,7 @@ import ( "fmt" "io/fs" "os" + "path/filepath" "runtime" "strconv" "strings" @@ -82,10 +83,15 @@ func svcStatus(s service.Service) (status service.Status, err error) { // On OpenWrt, the service utility may not exist. We use our service script // directly in this case. func svcAction(s service.Service, action string) (err error) { - if runtime.GOOS == "darwin" && - action == "start" && - !strings.HasPrefix(Context.workDir, "/Applications/") { - log.Info("warning: service must be started from within the /Applications directory") + if runtime.GOOS == "darwin" && action == "start" { + var exe string + if exe, err = os.Executable(); err != nil { + log.Error("starting service: getting executable path: %s", err) + } else if exe, err = filepath.EvalSymlinks(exe); err != nil { + log.Error("starting service: evaluating executable symlinks: %s", err) + } else if !strings.HasPrefix(exe, "/Applications/") { + log.Info("warning: service must be started from within the /Applications directory") + } } err = service.Control(s, action) @@ -579,6 +585,9 @@ status() { } ` +// freeBSDScript is the source of the daemon script for FreeBSD. Keep as close +// as possible to the https://github.com/kardianos/service/blob/18c957a3dc1120a2efe77beb401d476bade9e577/service_freebsd.go#L204. +// // TODO(a.garipov): Don't use .WorkingDirectory here. There are currently no // guarantees that it will actually be the required directory. // @@ -587,14 +596,16 @@ const freeBSDScript = `#!/bin/sh # PROVIDE: {{.Name}} # REQUIRE: networking # KEYWORD: shutdown + . /etc/rc.subr + name="{{.Name}}" {{.Name}}_env="IS_DAEMON=1" {{.Name}}_user="root" pidfile_child="/var/run/${name}.pid" pidfile="/var/run/${name}_daemon.pid" command="/usr/sbin/daemon" -command_args="-P ${pidfile} -p ${pidfile_child} -f -r {{.WorkingDirectory}}/{{.Name}}" +command_args="-P ${pidfile} -p ${pidfile_child} -T ${name} -r {{.WorkingDirectory}}/{{.Name}}" run_rc_command "$1" ` @@ -604,6 +615,7 @@ const openBSDScript = `#!/bin/sh daemon="{{.Path}}" daemon_flags={{ .Arguments | args }} +daemon_logger="daemon.info" . /etc/rc.d/rc.subr From afbc7a72e3844f348c22d59e957c525334576a10 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Mon, 28 Feb 2022 19:13:15 +0300 Subject: [PATCH 129/135] Pull request: client: fix link in client form Updates #4244. Squashed commit of the following: commit 20d558e9e6935555a13e1aebc7d364e6f1910e9e Author: Ainar Garipov Date: Mon Feb 28 19:01:32 2022 +0300 client: fix link in client form --- client/src/components/Settings/Clients/Form.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/client/src/components/Settings/Clients/Form.js b/client/src/components/Settings/Clients/Form.js index d5f80c62..353b0bea 100644 --- a/client/src/components/Settings/Clients/Form.js +++ b/client/src/components/Settings/Clients/Form.js @@ -280,13 +280,10 @@ let Form = (props) => {
- - text - , - }} - > + text, + ]}> client_identifier_desc
From 3afe7c3daf39d53fdcf5260b7b3f035f0891c83f Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Tue, 1 Mar 2022 15:10:48 +0300 Subject: [PATCH 130/135] Pull request: client: upd i18n Merge in DNS/adguard-home from 2643-upd-i18n to master Squashed commit of the following: commit 1f36b960877ee2c30319e26132db892fb8a2ef71 Author: Ainar Garipov Date: Tue Mar 1 15:05:24 2022 +0300 client: upd i18n --- client/src/__locales/hu.json | 148 ++++++++++++++++++----------------- client/src/__locales/sk.json | 138 ++++++++++++++++---------------- client/src/__locales/uk.json | 48 ++++++------ 3 files changed, 168 insertions(+), 166 deletions(-) diff --git a/client/src/__locales/hu.json b/client/src/__locales/hu.json index b49b6506..5ffa9d15 100644 --- a/client/src/__locales/hu.json +++ b/client/src/__locales/hu.json @@ -1,7 +1,7 @@ { "client_settings": "Kliens beállítások", "example_upstream_reserved": "Megadhat egy DNS kiszolgálót <0>egy adott domainhez vagy domainekhez", - "example_upstream_comment": "Megadhat egy megjegyzést", + "example_upstream_comment": "egy megjegyzés.", "upstream_parallel": "Használjon párhuzamos lekéréseket a domainek feloldásának felgyorsításához az összes upstream kiszolgálóra való egyidejű lekérdezéssel.", "parallel_requests": "Párhuzamos lekérések", "load_balancing": "Terheléselosztás", @@ -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": "Érvénytelen IPv4-cím az átjáró", - "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": "Az ügyfél-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 tartományon kívül legyen \"{{start}}\"-\"{{end}}\"", - "lower_range_start_error": "Kisebb legyen, mint a tartomány kezdete", - "greater_range_start_error": "Nagyobbbb legyen, 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", @@ -143,7 +143,7 @@ "use_adguard_browsing_sec_hint": "Az AdGuard Home ellenőrzi, hogy a böngészési biztonsági modul a domaint tiltólistára tette-e. Az ellenőrzés elvégzéséhez egy adatvédelmet tiszteletben tartó API-t fog használni: a domain név egy rövid előtagját elküldi SHA256 kódolással a szerver felé.", "use_adguard_parental": "Használja az AdGuard szülői felügyelet webszolgáltatását", "use_adguard_parental_hint": "Az AdGuard Home ellenőrzi, hogy a domain tartalmaz-e felnőtteknek szóló anyagokat. Ugyanazokat az adatvédelmi API-kat használja, mint a böngésző biztonsági webszolgáltatás.", - "enforce_safe_search": "Biztonságos keresés kényszerítése", + "enforce_safe_search": "Biztonságos keresés használata", "enforce_save_search_hint": "Az AdGuard Home a következő keresőmotorokban biztosíthatja a biztonságos keresést: Google, Youtube, Bing, DuckDuckGo, Yandex és Pixabay.", "no_servers_specified": "Nincsenek megadott kiszolgálók", "general_settings": "Általános beállítások", @@ -196,25 +196,25 @@ "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 elérési út 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", "examples_title": "Példák", - "example_meaning_filter_block": "letiltja a hozzáférést az example.org domainhez, valamint annak az összes aldomainjéhez is", - "example_meaning_filter_whitelist": "feloldja a hozzáférést az example.org domainhez, valamint annak az összes aldomainjéhez is", - "example_meaning_host_block": "Az AdGuard Home mostantol a 127.0.0.1 címre irányítja az example.org domaint (de az aldomaineket nem).", - "example_comment": "! Ide írhat egy megjegyzést", - "example_comment_meaning": "csak egy megjegyzés", - "example_comment_hash": "# Ez is egy megjegyzés", - "example_regex_meaning": "megakadályozza a hozzáférést a reguláris kifejezéssel egyező domaineknél", - "example_upstream_regular": "hagyományos DNS (UDP felett)", - "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", - "example_upstream_sdns": "használhatja a <0> DNS Stamps-ot a <1>DNSCrypt vagy a <2>DNS-over-HTTPS feloldások érdekében", - "example_upstream_tcp": "hagyományos DNS (TCP felett)", + "example_meaning_filter_block": "letiltja a hozzáférést az example.org domainhez, valamint annak az összes aldomainjéhez is;", + "example_meaning_filter_whitelist": "feloldja a hozzáférést az example.org domainhez, valamint annak az összes aldomainjéhez is;", + "example_meaning_host_block": "az example.org-ot a 127.0.0.1-es címre oldja fel (de az aldomainjeit nem);", + "example_comment": "! Ide írhat egy megjegyzést.", + "example_comment_meaning": "csak egy megjegyzés;", + "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_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);", "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 +259,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", @@ -275,9 +275,9 @@ "dns_over_https": "DNS-over-HTTPS", "dns_over_tls": "DNS-over-TLS", "dns_over_quic": "DNS-over-QUIC", - "client_id": "Kliens azonosító", - "client_id_placeholder": "Kliens azonosító megadása", - "client_id_desc": "A különböző klienseket egy speciális kliens azonosító segítségével lehet azonosítani. Itt többet is megtudhat arról, hogyan lehet a klienseket azonosítani.", + "client_id": "Kliens azonosító (ClientID)", + "client_id_placeholder": "Kliens azonosító (ClientID) megadása", + "client_id_desc": "A kliensek a ClientID által kerülnek azonosításra. Tudjon meg többet arról ide kattintva, hogy miként történik a kliensek azonosítása.", "download_mobileconfig_doh": ".mobileconfig letöltése DNS-over-HTTPS-hez", "download_mobileconfig_dot": ".mobileconfig letöltése DNS-over-TLS-hez", "download_mobileconfig": "Konfigurációs fájl letöltése", @@ -309,7 +309,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": "Írja be az érvényes portszámot", + "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", @@ -334,8 +334,8 @@ "install_devices_router_list_4": "Bizonyos típusú routereknél nem állíthat be egyéni DNS-kiszolgálót. Ebben az esetben segíthet, ha az AdGuard Home-t DHCP-szerverként állítja be. Ellenkező esetben keresse meg az adott router kézikönyvében a DNS-kiszolgálók testreszabását.", "install_devices_windows_list_1": "Nyissa meg a Vezérlőpultot a Start menün vagy a Windows keresőn keresztül.", "install_devices_windows_list_2": "Válassza a Hálózat és internet kategóriát, majd pedig a Hálózati és megosztási központot.", - "install_devices_windows_list_3": "A képernyő bal oldalán keresse meg az Adapterbeállítások módosítása lehetőséget és kattintson rá.", - "install_devices_windows_list_4": "Válassza ki a jelenleg is használt kapcsolatot, majd jobb egérgombbal kattintson rá és a megjelenő menüből válassza a Tulajdonságok elemet.", + "install_devices_windows_list_3": "A bal oldali panelben kattintson az \"Adapterbeállítások módosítása\" lehetőségre.", + "install_devices_windows_list_4": "Kattintson jobb egérgombbal az aktív kapcsolatra és válassza ki a Tulajdonságokat.", "install_devices_windows_list_5": "Keresse meg az Internet Protocol Version 4 (TCP/IPv4) elemet a listában, válassza ki, majd ismét kattintson a Tulajdonságokra.", "install_devices_windows_list_6": "Válassza a \"Következő DNS címek használata\" lehetőséget és adja meg az AdGuard Home szerver címeit.", "install_devices_macos_list_1": "Kattintson az Apple ikonra és válassza a Rendszerbeállításokat.", @@ -356,7 +356,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/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", @@ -367,7 +367,7 @@ "encryption_https_desc": "Ha a HTTPS port konfigurálva van, akkor az AdGuard Home admin felülete elérhető lesz a HTTPS-en keresztül, és ezenkívül DNS-over-HTTPS-t is biztosít a '/dns-query' helyen.", "encryption_dot": "DNS-over-TLS port", "encryption_dot_desc": "Ha ez a port be van állítva, az AdGuard Home DNS-over-TLS szerverként tud futni ezen a porton.", - "encryption_doq": "DNS-over-TLS port", + "encryption_doq": "DNS-over-QUIC port (kísérleti)", "encryption_doq_desc": "Ha ez a port be van állítva, akkor az AdGuard Home egy DNS-over-QUIC szerverként fog futni ezen a porton. Ez egy kísérleti funkció és nem biztos, hogy megbízható. Emellett nincs sok olyan kliens, ami támogatná ezt jelenleg.", "encryption_certificates": "Tanúsítványok", "encryption_certificates_desc": "A titkosítás használatához érvényes SSL tanúsítványláncot kell megadnia a domainjéhez. Ingyenes tanúsítványt kaphat a <0>{{link}} webhelyen, vagy megvásárolhatja az egyik megbízható tanúsítványkibocsátó hatóságtól.", @@ -378,34 +378,35 @@ "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": "A port értékét a 80-65535 tartományban adja meg", - "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.", "update_now": "Frissítés most", "update_failed": "Az automatikus frissítés nem sikerült. Kérjük, hogy kövesse ezeket a lépéseket a manuális frissítéshez.", + "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": "Kliensek", - "clients_desc": "Az AdGuard Home-hoz csatlakozó eszközök kezelése", + "clients_title": "Fenntartott kliensek", + "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", @@ -416,7 +417,7 @@ "client_edit": "Kliens módosítása", "client_identifier": "Azonosító", "ip_address": "IP cím", - "client_identifier_desc": "A klienseket az IP-cím, a CIDR, a MAC-cím vagy egy speciális kliens azonosító alapján lehet azonosítani (ez használható DoT/DoH /DoQ esetén). <0>Itt többet is megtudhat a kliensek azonosításáról.", + "client_identifier_desc": "A kliensek azonosíthatók az IP cím, CIDR, MAC cím, vagy a ClientID (ami használható DoT/DoH/DoQ esetén) alapján. Tudjon meg többet arról <0>ide kattintva, hogy miként lehet azonosítani a klienseket.", "form_enter_ip": "IP-cím megadása", "form_enter_subnet_ip": "Adjon meg egy IP címet az alhálózatban \"{{cidr}}\"", "form_enter_mac": "MAC-cím megadása", @@ -431,14 +432,14 @@ "clients_not_found": "Nem található kliens", "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": "Kliensek (futási idő)", - "auto_clients_desc": "Az AdGuard Home-ot használó, de a konfigurációban nem tárolt kliensek adatai", + "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.", "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_allowed_title": "Engedélyezett kliensek", - "access_allowed_desc": "CIDR-ek, IP-címek vagy kliensazonosító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_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", - "access_disallowed_desc": "CIDR-ek, IP-címek vagy kliensazonosítók listája. Ha be van állítva, akkor az AdGuard Home eldobja azokat a lekérdezéseket, amelyek ezektől a kliensektől érkeznek. Ha engedélyezett kliensek vannak ide bekonfigurálva, akkor pedig az a mező ki lesz hagyva.", + "access_disallowed_desc": "CIDR-ek, IP-címek vagy ClientID-k listája. Ha be van állítva, akkor az AdGuard Home eldobja azokat a lekérdezéseket, amelyek ezektől a kliensektől érkeznek. Ha engedélyezett kliensek vannak ide bekonfigurálva, akkor pedig az a mező ki lesz hagyva.", "access_blocked_title": "Nem engedélyezett domainek", "access_blocked_desc": "Ne keverje össze ezt a szűrőkkel. Az AdGuard Home az összes DNS kérést el fogja dobni, ami ezekkel a domainekkel megegyezik, és ezek a lekérések nem is fognak megjelenni a lekérdezési naplóban sem. Megadhatja a pontos domain neveket, a helyettesítő karaktereket vagy az URL szűrési szabályokat, pl. ennek megfelelően \"example.org\", \"*.example.org\", vagy \"||example.org^\".", "access_settings_saved": "A hozzáférési beállítások sikeresen mentésre kerültek", @@ -474,8 +475,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", @@ -506,7 +507,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", @@ -516,7 +517,7 @@ "interval_hours_plural": "{{count}} óra", "filters_configuration": "Szűrők beállításai", "filters_enable": "Szűrők engedélyezése", - "filters_interval": "Szűrőfrissítési gyakoriság", + "filters_interval": "Szűrők frissítési gyakorisága:", "disabled": "Kikapcsolva", "username_label": "Felhasználónév", "username_placeholder": "Felhasználónév megadása", @@ -531,7 +532,7 @@ "netname": "Hálózat neve", "network": "Hálózat", "descr": "Leírás", - "whois": "Whois", + "whois": "WHOIS", "filtering_rules_learn_more": "<0>Tudjon meg többet a saját hosztlisták létrehozásáról.", "blocked_by_response": "Blokkolva a CNAME vagy a válasz IP-címe alapján", "blocked_by_cname_or_ip": "CNAME vagy IP által blokkolva", @@ -551,10 +552,10 @@ "autofix_warning_list": "A következő feladatokat hajtja végre: <0>A DNSStubListener rendszer kikapcsolása<0>Beállítja a DNS-kiszolgáló címét 127.0.0.1-re.<0>Lecseréli az /etc/resolv.conf szimbolikus útvonalat erre: /run/systemd/resolve/resolv.conf<0>A DNSStubListener leállítása (a rendszer által feloldott szolgáltatás újratöltése)", "autofix_warning_result": "Mindennek eredményeként az Ön rendszeréből származó összes DNS-kérést alapértelmezés szerint az AdGuard Home dolgozza fel.", "tags_title": "Címkék", - "tags_desc": "Kiválaszthatja a klienseknek megfelelő címkéket. A címkék beilleszthetők a szűrési szabályokba, és lehetővé teszik azok pontosabb alkalmazását. <0>További információ", + "tags_desc": "Kiválaszthatja a klienseknek megfelelő címkéket. A címkék beilleszthetők a szűrési szabályokba, és lehetővé teszik azok pontosabb alkalmazását. <0>További információ.", "form_select_tags": "Válasszon kliens címkéket", "check_title": "Szűrés ellenőrzése", - "check_desc": "Ellenőrzi, hogy a hosztnév szűrve van-e", + "check_desc": "Ellenőrzi, hogy a hosztnév szűrve van-e.", "check": "Ellenőrzés", "form_enter_host": "Adja meg a hosztnevet", "filtered_custom_rules": "Szűrve van az egyéni szűrési szabályok alapján", @@ -597,15 +598,15 @@ "blocklist": "Tiltólista", "milliseconds_abbreviation": "ms", "cache_size": "Gyorsítótár mérete", - "cache_size_desc": "DNS gyorsítótár mérete (bájtokban)", + "cache_size_desc": "DNS gyorsítótár mérete (bájtokban).", "cache_ttl_min_override": "A minimális TTL felülírása", "cache_ttl_max_override": "A maximális TTL felülírása", "enter_cache_size": "Adja meg a gyorsítótár méretét", "enter_cache_ttl_min_override": "Adja meg a minimális TTL-t (másodpercben)", "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", + "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.", "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", @@ -626,5 +627,6 @@ "use_saved_key": "Előzőleg mentett kulcs használata", "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)" + "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." } diff --git a/client/src/__locales/sk.json b/client/src/__locales/sk.json index da174fda..118a0578 100644 --- a/client/src/__locales/sk.json +++ b/client/src/__locales/sk.json @@ -1,7 +1,7 @@ { "client_settings": "Nastavenie klienta", - "example_upstream_reserved": "Môžete zadať DNS upstream <0>pre konkrétnu doménu (domény)", - "example_upstream_comment": "Môžete napísať komentár", + "example_upstream_reserved": "upstream <0>pre konkrétne domény;", + "example_upstream_comment": "komentár.", "upstream_parallel": "Používať paralelné dopyty na zrýchlenie súčasným dopytovaním všetkých upstream serverov súčasne.", "parallel_requests": "Paralelné dopyty", "load_balancing": "Vyrovnávanie záťaže", @@ -35,24 +35,24 @@ "dhcp_config_saved": "Konfigurácia DHCP servera bola úspešne uložená", "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ý 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_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_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", @@ -167,8 +167,8 @@ "enabled_safe_browsing_toast": "Bezpečné prehliadanie zapnuté", "disabled_parental_toast": "Vypnutá Rodičovská kontrola", "enabled_parental_toast": "Zapnutá Rodičovská kontrola", - "disabled_safe_search_toast": "Vypnuté bezpečné vyhľadávanie", - "enabled_save_search_toast": "Zapnuté bezpečné vyhľadávanie", + "disabled_safe_search_toast": "Vypnuté Bezpečné vyhľadávanie", + "enabled_save_search_toast": "Zapnuté Bezpečné vyhľadávanie", "enabled_table_header": "Zapnuté", "name_table_header": "Meno", "list_url_table_header": "Zoznam URL adries", @@ -196,25 +196,25 @@ "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", "examples_title": "Príklady", - "example_meaning_filter_block": "zablokovať prístup k doméne example.org a všetkým jej subdoménam", - "example_meaning_filter_whitelist": "odblokovať prístup k doméne example.org a všetkým jej subdoménam", - "example_meaning_host_block": "AdGuard Home teraz vráti adresu 127.0.0.1 pre doménu example.org (ale nie pre jej subdomény).", - "example_comment": "! Sem sa pridáva komentár", - "example_comment_meaning": "len komentár", - "example_comment_hash": "# Tiež komentár", - "example_regex_meaning": "zablokovať prístup k doménam, ktoré zodpovedajú zadanému regulárnemu výrazu", - "example_upstream_regular": "radová DNS (cez UDP)", - "example_upstream_dot": "šifrované <0>DNS-over-TLS", - "example_upstream_doh": "šifrované <0>DNS-over-HTTPS", - "example_upstream_doq": "šifrované <0>DNS-over-QUIC", - "example_upstream_sdns": "môžete použiť <0>DNS pečiatky pre <1>DNSCrypt alebo <2>DNS-over-HTTPS", - "example_upstream_tcp": "radová DNS (cez TCP)", + "example_meaning_filter_block": "zablokovať prístup k doméne example.org a všetkým jej subdoménam;", + "example_meaning_filter_whitelist": "odblokovať prístup k doméne example.org a všetkým jej subdoménam;", + "example_meaning_host_block": "vrátiť IP adresu 127.0.0.1 pre doménu example.org (ale nie pre jej subdomény);", + "example_comment": "! Sem sa pridáva komentár.", + "example_comment_meaning": "len komentár;", + "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_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);", "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 +259,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", @@ -277,7 +277,7 @@ "dns_over_quic": "DNS-over-QUIC", "client_id": "ID klienta", "client_id_placeholder": "Zadať ID klienta", - "client_id_desc": "Rôznych klientov možno identifikovať podľa špeciálneho ID klienta. Tu sa dozviete viac o tom, ako identifikovať klientov.", + "client_id_desc": "Klientov možno identifikovať podľa ClientID. Viac informácií o tom, ako identifikovať klientov, nájdete tu.", "download_mobileconfig_doh": "Prevziať .mobileconfig pre DNS-over-HTTPS", "download_mobileconfig_dot": "Prevziať .mobileconfig pre DNS-over-TLS", "download_mobileconfig": "Stiahnuť konfiguračný súbor", @@ -334,11 +334,11 @@ "install_devices_router_list_4": "Na niektorých typoch smerovačov nemôžete nastaviť vlastný DNS server. V takom prípade môže pomôcť, ak nastavíte AdGuard Home ako <0>DHCP server. V opačnom prípade by ste mali vyhľadať príručku, ako prispôsobiť DNS servery konkrétnemu modelu smerovača.", "install_devices_windows_list_1": "Otvorte panel Nastavenia cez menu Štart alebo vyhľadávanie Windows.", "install_devices_windows_list_2": "Prejdite do kategórie Sieť a internet a potom do Centra sietí a zdieľania.", - "install_devices_windows_list_3": "Na ľavej strane obrazovky nájdite položku \"Zmeniť nastavenia adaptéra\" a kliknite na ňu.", - "install_devices_windows_list_4": "Zvoľte aktívne pripojený adaptér a pravým klikom otvorte Vlastnosti", + "install_devices_windows_list_3": "Na ľavom paneli kliknite na „Zmeniť nastavenia adaptéra“.", + "install_devices_windows_list_4": "Kliknite pravým tlačidlom myši na aktívne pripojenie a vyberte Vlastnosti.", "install_devices_windows_list_5": "Nájdite v zozname položku \"Internet Protocol verzia 4 (TCP/IPv4)\" (alebo pre IPv6, \"Internet Protocol verzia 6 (TCP/IPv6)\"), vyberte ju a potom znova kliknite na Vlastnosti.", "install_devices_windows_list_6": "Zvoľte \"Použiť nasledujúce adresy DNS servera\" a zadajte adresy domáceho AdGuard servera.", - "install_devices_macos_list_1": "Kliknite na ikonu Apple a prejdite na položku Systémové predvoľby.", + "install_devices_macos_list_1": "Kliknite na ikonu Apple a prejdite na Predvoľby systému.", "install_devices_macos_list_2": "Kliknite na Sieť.", "install_devices_macos_list_3": "Zvoľte prvé pripojenie vo Vašom zozname a kliknite na Pokročilé.", "install_devices_macos_list_4": "Vyberte kartu DNS a zadajte adresy Vašich AdGuard Home serverov.", @@ -356,7 +356,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", @@ -367,7 +367,7 @@ "encryption_https_desc": "Ak je nakonfigurovaný HTTPS port, AdGuard Home administrátorské rozhranie bude prístupné cez HTTPS a bude tiež poskytovať DNS-cez-HTTPS na '/dns-query'.", "encryption_dot": "Port DNS-cez-TLS", "encryption_dot_desc": "Ak je tento port nakonfigurovaný, AdGuard Home bude na tomto porte spúšťať DNS-cez-TLS server.", - "encryption_doq": "Port DNS-cez-QUIC", + "encryption_doq": "DNS-over-QUIC (experimentálne)", "encryption_doq_desc": "Ak je tento port nakonfigurovaný, AdGuard Home na tomto porte spustí server DNS-over-QUIC. Je to experimentálne a nemusí to byť spoľahlivé. Momentálne tiež nie je príliš veľa klientov, ktorí by ju podporovali.", "encryption_certificates": "Certifikáty", "encryption_certificates_desc": "Ak chcete používať šifrovanie, musíte pre svoju doménu poskytnúť platný reťazec certifikátov SSL. Certifikát môžete získať bezplatne na adrese <0>{{link}} alebo si ho môžete kúpiť od jedného z dôveryhodných certifikačných orgánov.", @@ -378,26 +378,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": "Toto nie je bezpečný 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.", @@ -405,8 +405,8 @@ "update_failed": "Automatická aktualizácia zlyhala. Prosím sledujte postup pre manuálnu aktualizáciu.", "manual_update": "Pre manuálnu aktualizáciu prosím sledujte tento postup.", "processing_update": "Čakajte prosím, AdGuard Home sa aktualizuje", - "clients_title": "Klienti", - "clients_desc": "Konfigurácia zariadení pripojených k AdGuard Home", + "clients_title": "Permanentní klienti", + "clients_desc": "Nakonfigurujte trvalé záznamy klientov pre zariadenia pripojené k domovskej stránke AdGuard.", "settings_global": "Globálne", "settings_custom": "Vlastné", "table_client": "Klient", @@ -417,7 +417,7 @@ "client_edit": "Upraviť klienta", "client_identifier": "Identifikátor", "ip_address": "IP adresa", - "client_identifier_desc": "Klientov je možné identifikovať podľa IP adresy, CIDR a MAC adresy alebo špeciálneho ID klienta (možno použiť pre DoT/DoH/DoQ). <0>Tu sa dozviete viac o tom, ako identifikovať klientov.", + "client_identifier_desc": "Klientov možno identifikovať podľa ich IP adresy, CIDR, MAC adresy alebo ClientID (možno použiť pre DoT/DoH/DoQ). Viac informácií o tom, ako identifikovať klientov, nájdete <0>tu.", "form_enter_ip": "Zadajte IP adresu", "form_enter_subnet_ip": "Zadajte IP adresu do podsiete \"{{cidr}}\"", "form_enter_mac": "Zadajte MAC adresu", @@ -432,14 +432,14 @@ "clients_not_found": "Nebol nájdený žiaden klient", "client_confirm_delete": "Naozaj chcete vymazať \"{{key}}\" klienta?", "list_confirm_delete": "Naozaj chcete vymazať tento zoznam?", - "auto_clients_title": "Klienti (runtime)", - "auto_clients_desc": "Údaje o klientoch, ktorí používajú AdGuard Home, ale nie sú uložení v konfigurácii", + "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.", "access_title": "Nastavenia prístupu", "access_desc": "Tu môžete konfigurovať pravidlá prístupu pre server DNS AdGuard Home.", "access_allowed_title": "Povolení klienti", - "access_allowed_desc": "Zoznam CIDR, IP adries alebo ID klientov. Ak je nakonfigurovaný, AdGuard Home akceptuje len dopyty od týchto klientov.", + "access_allowed_desc": "Zoznam CIDR, IP adries alebo ClientID. Ak tento zoznam obsahuje položky, AdGuard Home bude akceptovať požiadavky iba od týchto klientov.", "access_disallowed_title": "Nepovolení klienti", - "access_disallowed_desc": "Zoznam CIDR, IP adries alebo ID klientov. Ak je nakonfigurovaný, AdGuard Home bude ignorovať dopyty od týchto klientov.", + "access_disallowed_desc": "Zoznam CIDR, IP adries alebo ClientID. Ak tento zoznam obsahuje položky, AdGuard Home zruší požiadavky od týchto klientov. Toto pole sa ignoruje, ak sú v poli Povolení klienti položky.", "access_blocked_title": "Nepovolené domény", "access_blocked_desc": "Nesmie byť zamieňaná s filtrami. AdGuard Home zruší DNS dopyty, ktoré sa zhodujú s týmito doménami, a tieto dopyty sa nezobrazia ani v denníku dopytov. Môžete určiť presné názvy domén, zástupné znaky alebo pravidlá filtrovania URL adries, napr. \"example.org\", \"*.example.org\" alebo ||example.org^\" zodpovedajúcim spôsobom.", "access_settings_saved": "Nastavenia prístupu úspešne uložené", @@ -475,8 +475,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", @@ -507,7 +507,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", @@ -532,7 +532,7 @@ "netname": "Meno siete", "network": "Sieť", "descr": "Popis", - "whois": "Whois", + "whois": "WHOIS", "filtering_rules_learn_more": "<0>Dozvedieť sa viac o tvorbe vlastných zoznamov hostiteľov.", "blocked_by_response": "Blokované pomocou CNAME alebo IP v odpovedi", "blocked_by_cname_or_ip": "Zablokované na základe CNAME alebo IP", @@ -552,10 +552,10 @@ "autofix_warning_list": "Bude vykonávať tieto úlohy: <0>Deaktivovať systém DNSStubListener <0>Nastaviť adresu servera DNS na 127.0.0.1 <0>Nahradiť cieľový symbolický odkaz /etc/resolv.conf na /run/systemd/resolve/resolv.conf <0>Zastaviť službu DNSStubListener (znova načítať službu systemd-resolved)", "autofix_warning_result": "Výsledkom bude, že všetky DNS dopyty z Vášho systému budú štandardne spracované službou AdGuard Home.", "tags_title": "Tagy", - "tags_desc": "Môžete vybrať tagy ktoré zodpovedajú klientovi. Tagy môžu byť súčasťou filtračných pravidiel a umožňujú Vám použiť ich presnejšie. <0>Viac informácií", + "tags_desc": "Môžete vybrať značky, ktoré zodpovedajú klientovi. Zahrňte značky do pravidiel filtrovania, aby ste ich použili presnejšie. <0>Viac informácií.", "form_select_tags": "Zvoľte tagy klienta", "check_title": "Skontrolujte filtráciu", - "check_desc": "Skontrolujte, či je názov hostiteľa filtrovaný", + "check_desc": "Skontrolujte, či je názov hostiteľa filtrovaný.", "check": "Kontrola", "form_enter_host": "Zadajte meno hostiteľa", "filtered_custom_rules": "Filtrované podľa vlastných filtračných pravidiel", @@ -604,9 +604,9 @@ "enter_cache_size": "Zadať veľkosť cache (v bajtoch)", "enter_cache_ttl_min_override": "Zadať minimálne TTL (v sekundách)", "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", + "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.", "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é", diff --git a/client/src/__locales/uk.json b/client/src/__locales/uk.json index eb721af4..716d784c 100644 --- a/client/src/__locales/uk.json +++ b/client/src/__locales/uk.json @@ -210,11 +210,11 @@ "example_comment_hash": "# Також коментар.", "example_regex_meaning": "блокувати доступ до доменів, що відповідають вказаному регулярному виразу.", "example_upstream_regular": "звичайний 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_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);", "all_lists_up_to_date_toast": "Всі списки вже оновлені", "updated_upstream_dns_toast": "DNS-сервери оновлено", "dns_test_ok_toast": "Вказані DNS сервери працюють правильно", @@ -259,10 +259,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", @@ -275,9 +275,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": "Завантажити файл конфігурації", @@ -309,7 +309,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 +334,12 @@ "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_4": "Виберіть своє активне з'єднання, клацніть на ньому правою кнопкою миші та виберіть Властивості.", + "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.", "install_devices_macos_list_1": "Клацніть на піктограму Apple і перейдіть до Системних налаштувань.", - "install_devices_macos_list_2": "Клацніть на Мережа.", + "install_devices_macos_list_2": "Виберіть «Мережа».", "install_devices_macos_list_3": "Виберіть перше з'єднання зі списку та натисніть кнопку Додатково.", "install_devices_macos_list_4": "Виберіть вкладку DNS і введіть адреси сервера AdGuard Home.", "install_devices_android_list_1": "На головному екрані меню Android торкніться Налаштування.", @@ -356,7 +356,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": "Введіть ваше доменне ім'я", @@ -367,7 +367,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}} або придбати його в одному з надійних Центрів Сертифікації.", @@ -378,20 +378,20 @@ "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": "Посібник з налаштування", From ea6e033daecf5861c5bc40d2f8c8759edec2d163 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Tue, 1 Mar 2022 20:35:44 +0300 Subject: [PATCH 131/135] Pull request: all: upd chlog Merge in DNS/adguard-home from upd-chlog to master Squashed commit of the following: commit 5933ed86b41646c61a595c94068890a1675a3ad1 Author: Ainar Garipov Date: Tue Mar 1 20:31:47 2022 +0300 all: upd chlog --- CHANGELOG.md | 52 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a54f8c57..5b83fc01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,7 +26,7 @@ and this project adheres to - Domain-specific private reverse DNS upstream servers are now validated to allow only `*.in-addr.arpa` and `*.ip6.arpa` domains pointing to locally-served networks ([#3381]). **Note:** If you already have invalid - entires in your configuration, consider removing them manually, since they + entries in your configuration, consider removing them manually, since they essentially had no effect. - Response filtering is now performed using the record types of the answer section of messages as opposed to the type of the question ([#4238]). @@ -66,20 +66,13 @@ 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 - -- Optimistic cache now responds with expired items even if those can't be - resolved again ([#4254]). -- Unnecessarily complex hosts-related logic leading to infinite recursion in - some cases ([#4216]). - ### Removed - Go 1.16 support. ### Security -- Enforced password strength policy ([3503]). +- Enforced password strength policy ([#3503]). - Weaker cipher suites that use the CBC (cipher block chaining) mode of operation have been disabled ([#2993]). @@ -90,22 +83,46 @@ In this release, the schema version has changed from 12 to 13. [#3381]: https://github.com/AdguardTeam/AdGuardHome/issues/3381 [#3503]: https://github.com/AdguardTeam/AdGuardHome/issues/3503 [#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 -[#4254]: https://github.com/AdguardTeam/AdGuardHome/issues/4254 [repr]: https://reproducible-builds.org/docs/source-date-epoch/ + + + +## [v0.107.4] - 2022-03-01 See also the [v0.107.4 GitHub milestone][ms-v0.107.4]. -[ms-v0.107.4]: https://github.com/AdguardTeam/AdGuardHome/milestone/41?closed=1 ---> +### Fixed + +- Optimistic cache now responds with expired items even if those can't be + resolved again ([#4254]). +- Unnecessarily complex hosts-related logic leading to infinite recursion in + some cases ([#4216]). + +### Security + +- Go version was updated to prevent the possibility of exploiting + [CVE-2022-23806], [CVE-2022-23772], and [CVE-2022-23773]. + +[#4216]: https://github.com/AdguardTeam/AdGuardHome/issues/4216 +[#4254]: https://github.com/AdguardTeam/AdGuardHome/issues/4254 + +[CVE-2022-23772]: https://www.cvedetails.com/cve/CVE-2022-23772 +[CVE-2022-23773]: https://www.cvedetails.com/cve/CVE-2022-23773 +[CVE-2022-23806]: https://www.cvedetails.com/cve/CVE-2022-23806 +[ms-v0.107.4]: https://github.com/AdguardTeam/AdGuardHome/milestone/41?closed=1 @@ -824,11 +841,12 @@ See also the [v0.104.2 GitHub milestone][ms-v0.104.2]. -[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.3...HEAD +[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.4...HEAD +[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 [v0.107.1]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.0...v0.107.1 From e0b557eda2680e63037ae0eee2106a1f9466d141 Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Wed, 2 Mar 2022 14:21:33 +0300 Subject: [PATCH 132/135] Pull request: 4166 udp upstream Merge in DNS/adguard-home from 4166-udp-upstream to master Closes #4166. Squashed commit of the following: commit b8b6d1c7ac1e11e83c0c68e46e7f66fdc6043839 Merge: e5f01273 ea6e033d Author: Eugene Burkov Date: Tue Mar 1 20:36:40 2022 +0300 Merge branch 'master' into 4166-udp-upstream commit e5f0127384d84c4395da5b79a1fd4a47acbe122c Author: Eugene Burkov Date: Tue Mar 1 19:41:33 2022 +0300 client: upd upstream examples commit bd974f22231f11f4c57e19d6d13bc45dbfdf2fdf Author: Eugene Burkov Date: Tue Mar 1 18:36:10 2022 +0300 all: upd proxy commit badf1325090ecd1dc86e42e7406dfb6653e07bf1 Author: Eugene Burkov Date: Fri Feb 4 14:36:50 2022 +0300 WIP --- CHANGELOG.md | 3 +++ client/src/__locales/en.json | 2 ++ .../src/components/Settings/Dns/Upstream/Examples.js | 12 +++++++++--- go.mod | 4 ++-- go.sum | 9 ++++----- internal/dnsforward/http.go | 2 +- internal/dnsforward/http_test.go | 10 +++++++++- 7 files changed, 30 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b83fc01..57adf5bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ and this project adheres to ### Added +- Support for hostnames for plain UDP upstream servers using the `udp://` scheme + ([#4166]). - Logs are now collected by default on FreeBSD and OpenBSD when AdGuard Home is installed as a service ([#4213]). - `windows/arm64` support ([#3057]). @@ -82,6 +84,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 +[#4166]: https://github.com/AdguardTeam/AdGuardHome/issues/4166 [#4213]: https://github.com/AdguardTeam/AdGuardHome/issues/4213 [#4221]: https://github.com/AdguardTeam/AdGuardHome/issues/4221 [#4238]: https://github.com/AdguardTeam/AdGuardHome/issues/4238 diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index 1559a24e..f1e1eac0 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -210,11 +210,13 @@ "example_comment_hash": "# Also a comment.", "example_regex_meaning": "block access to domains matching the specified regular expression.", "example_upstream_regular": "regular DNS (over UDP);", + "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_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);", "all_lists_up_to_date_toast": "All lists are already up-to-date", "updated_upstream_dns_toast": "Upstream servers successfully saved", "dns_test_ok_toast": "Specified DNS servers are working correctly", diff --git a/client/src/components/Settings/Dns/Upstream/Examples.js b/client/src/components/Settings/Dns/Upstream/Examples.js index 2f145b3a..b4e0ce09 100644 --- a/client/src/components/Settings/Dns/Upstream/Examples.js +++ b/client/src/components/Settings/Dns/Upstream/Examples.js @@ -10,6 +10,15 @@ const Examples = (props) => (
  • 94.140.14.140: {props.t('example_upstream_regular')}
  • +
  • + udp://dns-unfiltered.adguard.com: example_upstream_udp +
  • +
  • + tcp://94.140.14.140: example_upstream_tcp +
  • +
  • + tcp://dns-unfiltered.adguard.com: example_upstream_tcp_hostname +
  • tls://dns-unfiltered.adguard.com: @@ -67,9 +76,6 @@ const Examples = (props) => (
  • -
  • - tcp://94.140.14.140: example_upstream_tcp -
  • sdns://...: diff --git a/go.mod b/go.mod index 00182235..91fee199 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module github.com/AdguardTeam/AdGuardHome go 1.17 require ( - github.com/AdguardTeam/dnsproxy v0.41.1 - github.com/AdguardTeam/golibs v0.10.5 + github.com/AdguardTeam/dnsproxy v0.41.3 + github.com/AdguardTeam/golibs v0.10.6 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 99f20fd1..4ae0c523 100644 --- a/go.sum +++ b/go.sum @@ -7,14 +7,13 @@ 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.1 h1:sDWami83ZNp0XNdWsLECwIX/hPI5UnVrotRtPnrgDuo= -github.com/AdguardTeam/dnsproxy v0.41.1/go.mod h1:PZ9l22h3Er+5mxFQB7oHZMTvx+aa9R6LbzA/ikXQlS0= +github.com/AdguardTeam/dnsproxy v0.41.3 h1:FJnIf2pHaABUjAvB0P79nIXN5sBAvsUf2368NNw50+s= +github.com/AdguardTeam/dnsproxy v0.41.3/go.mod h1:GCdEbTw683vBqksJIccPSYzBg2yIFbRiDnXltyIinug= 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.3/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw= github.com/AdguardTeam/golibs v0.10.4/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw= -github.com/AdguardTeam/golibs v0.10.5 h1:4/nl1yIBJOv5luVu9SURW8LfgOjI3zQ2moIUy/1k0y4= -github.com/AdguardTeam/golibs v0.10.5/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/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/dnsforward/http.go b/internal/dnsforward/http.go index d653fa1e..b7fb66a6 100644 --- a/internal/dnsforward/http.go +++ b/internal/dnsforward/http.go @@ -459,7 +459,7 @@ func ValidateUpstreamsPrivate(upstreams []string, lnc LocalNetChecker) (err erro return nil } -var protocols = []string{"tls://", "https://", "tcp://", "sdns://", "quic://"} +var protocols = []string{"udp://", "tcp://", "tls://", "https://", "sdns://", "quic://"} func validateUpstream(u string) (useDefault bool, err error) { // Check if the user tries to specify upstream for domain. diff --git a/internal/dnsforward/http_test.go b/internal/dnsforward/http_test.go index 66931f4d..6e28ab41 100644 --- a/internal/dnsforward/http_test.go +++ b/internal/dnsforward/http_test.go @@ -306,6 +306,14 @@ func TestValidateUpstream(t *testing.T) { name: "valid_default", upstream: "sdns://AQMAAAAAAAAAFDE3Ni4xMDMuMTMwLjEzMDo1NDQzINErR_JS3PLCu_iZEIbq95zkSV2LFsigxDIuUso_OQhzIjIuZG5zY3J5cHQuZGVmYXVsdC5uczEuYWRndWFyZC5jb20", wantErr: ``, + }, { + wantDef: assert.True, + name: "default_udp_host", + upstream: "udp://dns.google", + }, { + wantDef: assert.True, + name: "default_udp_ip", + upstream: "udp://8.8.8.8", }, { wantDef: assert.False, name: "valid", @@ -389,7 +397,7 @@ func TestValidateUpstreams(t *testing.T) { }, }, { name: "invalid", - wantErr: `cannot prepare the upstream dhcp://fake.dns ([]): unsupported URL scheme: dhcp`, + wantErr: `cannot prepare the upstream dhcp://fake.dns ([]): unsupported url scheme: dhcp`, set: []string{"dhcp://fake.dns"}, }} From 9a764b9b82ca418bd72bd897f7dd8e99312c7099 Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Thu, 3 Mar 2022 17:52:11 +0300 Subject: [PATCH 133/135] Pull request: 3978 Query Log ECS Merge in DNS/adguard-home from 3978-ecs-ip to master Updates #3978. Squashed commit of the following: commit 915b94afa4b6d90169f73d4fa171bc81bcc267a7 Author: Eugene Burkov Date: Thu Mar 3 17:46:40 2022 +0300 all: rm dot commit 2dd2ed081b199de7e5d8269dae5d08d53b5eea6d Author: Eugene Burkov Date: Thu Mar 3 17:42:45 2022 +0300 client: imp txt commit 8d5a23df739f0b650f9f3870141fd83e8fa0c1e0 Author: Eugene Burkov Date: Thu Mar 3 14:36:04 2022 +0300 client: imp text commit 69c856749a20144822ef3f1f67c5f3e3c24f5374 Author: Eugene Burkov Date: Thu Mar 3 14:24:56 2022 +0300 client: imp description commit cd0150128ad29d1874492735a5d621c0803ad0bd Merge: 28181fbc e0b557ed Author: Eugene Burkov Date: Wed Mar 2 21:02:16 2022 +0300 Merge branch 'master' into 3978-ecs-ip commit 28181fbc79eb22e7fd13cbd1d5a3c040af9fa2a4 Author: Ainar Garipov Date: Wed Mar 2 20:45:50 2022 +0300 client: show ecs commit cdc5e7f8c4155b798426d815eed0da547ef6efb7 Author: Eugene Burkov Date: Thu Feb 17 20:15:56 2022 +0300 openapi: fix milestone commit 404d6d822fa1ba4ed4cd41d92d4c1b805342fe55 Author: Eugene Burkov Date: Thu Feb 17 20:08:21 2022 +0300 all: fix deps, docs commit 8fb80526f1e251d3b7b193c53a4a6dee0e22c145 Author: Eugene Burkov Date: Thu Feb 17 19:39:34 2022 +0300 all: add querylog ecs backend --- CHANGELOG.md | 4 + client/src/__locales/en.json | 3 +- .../src/components/Logs/Cells/DomainCell.js | 9 ++ client/src/components/Logs/Cells/index.js | 1 + client/src/helpers/helpers.js | 2 + internal/dnsforward/stats.go | 84 +++++++++++-------- internal/querylog/decode.go | 12 ++- internal/querylog/decode_test.go | 2 + internal/querylog/json.go | 4 + internal/querylog/qlog.go | 6 ++ internal/querylog/querylog.go | 4 + internal/querylog/searchcriterion.go | 18 +--- openapi/CHANGELOG.md | 9 +- openapi/openapi.yaml | 6 ++ 14 files changed, 108 insertions(+), 56 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57adf5bf..988d4066 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ and this project adheres to ### Added +- 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 ([#4166]). - Logs are now collected by default on FreeBSD and OpenBSD when AdGuard Home is @@ -84,8 +86,10 @@ 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 +[#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 diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index f1e1eac0..4d1dc857 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -287,7 +287,7 @@ "form_enter_rate_limit": "Enter rate limit", "rate_limit": "Rate limit", "edns_enable": "Enable EDNS client subnet", - "edns_cs_desc": "Send clients' subnets to the DNS servers.", + "edns_cs_desc": "Add the EDNS Client Subnet option (ECS) to upstream requests and log the values sent by the clients in the query log.", "rate_limit_desc": "The number of requests per second allowed per client. Setting it to 0 means no limit.", "blocking_ipv4_desc": "IP address to be returned for a blocked A request", "blocking_ipv6_desc": "IP address to be returned for a blocked AAAA request", @@ -502,6 +502,7 @@ "interval_days": "{{count}} day", "interval_days_plural": "{{count}} days", "domain": "Domain", + "ecs": "ECS", "punycode": "Punycode", "answer": "Answer", "filter_added_successfully": "The list has been successfully added", diff --git a/client/src/components/Logs/Cells/DomainCell.js b/client/src/components/Logs/Cells/DomainCell.js index 5ab18280..620d6711 100644 --- a/client/src/components/Logs/Cells/DomainCell.js +++ b/client/src/components/Logs/Cells/DomainCell.js @@ -20,6 +20,7 @@ const DomainCell = ({ time, tracker, type, + ecs, }) => { const { t } = useTranslation(); const dnssec_enabled = useSelector((state) => state.dnsConfig.dnssec_enabled); @@ -56,6 +57,13 @@ const DomainCell = ({ }; } + if (ecs) { + requestDetailsObj = { + ...requestDetailsObj, + ecs, + }; + } + requestDetailsObj = { ...requestDetailsObj, type_table_header: type, @@ -168,6 +176,7 @@ DomainCell.propTypes = { time: propTypes.string.isRequired, type: propTypes.string.isRequired, tracker: propTypes.object, + ecs: propTypes.string, }; export default DomainCell; diff --git a/client/src/components/Logs/Cells/index.js b/client/src/components/Logs/Cells/index.js index 2287f8d1..273d9495 100644 --- a/client/src/components/Logs/Cells/index.js +++ b/client/src/components/Logs/Cells/index.js @@ -238,6 +238,7 @@ Row.propTypes = { type: propTypes.string.isRequired, client_proto: propTypes.string.isRequired, client_id: propTypes.string, + ecs: propTypes.string, client_info: propTypes.shape({ name: propTypes.string.isRequired, whois: propTypes.shape({ diff --git a/client/src/helpers/helpers.js b/client/src/helpers/helpers.js index 2546d5b9..5fb42c05 100644 --- a/client/src/helpers/helpers.js +++ b/client/src/helpers/helpers.js @@ -76,6 +76,7 @@ export const normalizeLogs = (logs) => logs.map((log) => { original_answer, upstream, cached, + ecs, } = log; const { name: domain, unicode_name: unicodeName, type } = question; @@ -118,6 +119,7 @@ export const normalizeLogs = (logs) => logs.map((log) => { elapsedMs, upstream, cached, + ecs, }; }); diff --git a/internal/dnsforward/stats.go b/internal/dnsforward/stats.go index d113a5fd..56cc19c5 100644 --- a/internal/dnsforward/stats.go +++ b/internal/dnsforward/stats.go @@ -41,55 +41,65 @@ func (s *Server) processQueryLogsAndStats(dctx *dnsContext) (rc resultCode) { // uninitialized while in use. This can happen after proxy server has been // stopped, but its workers haven't yet exited. if shouldLog && s.queryLog != nil { - p := &querylog.AddParams{ - Question: msg, - Answer: pctx.Res, - OrigAnswer: dctx.origResp, - Result: dctx.result, - Elapsed: elapsed, - ClientID: dctx.clientID, - ClientIP: ip, - AuthenticatedData: dctx.responseAD, - } - - switch pctx.Proto { - case proxy.ProtoHTTPS: - p.ClientProto = querylog.ClientProtoDoH - case proxy.ProtoQUIC: - p.ClientProto = querylog.ClientProtoDoQ - case proxy.ProtoTLS: - p.ClientProto = querylog.ClientProtoDoT - case proxy.ProtoDNSCrypt: - p.ClientProto = querylog.ClientProtoDNSCrypt - default: - // Consider this a plain DNS-over-UDP or DNS-over-TCP request. - } - - if pctx.Upstream != nil { - p.Upstream = pctx.Upstream.Address() - } else if cachedUps := pctx.CachedUpstreamAddr; cachedUps != "" { - p.Upstream = pctx.CachedUpstreamAddr - p.Cached = true - } - - s.queryLog.Add(p) + s.logQuery(dctx, pctx, elapsed, ip) } - s.updateStats(dctx, elapsed, *dctx.result, ip) + if s.stats != nil { + s.updateStats(dctx, elapsed, *dctx.result, ip) + } return resultCodeSuccess } +// logQuery pushes the request details into the query log. +func (s *Server) logQuery( + dctx *dnsContext, + pctx *proxy.DNSContext, + elapsed time.Duration, + ip net.IP, +) { + p := &querylog.AddParams{ + Question: pctx.Req, + ReqECS: pctx.ReqECS, + Answer: pctx.Res, + OrigAnswer: dctx.origResp, + Result: dctx.result, + Elapsed: elapsed, + ClientID: dctx.clientID, + ClientIP: ip, + AuthenticatedData: dctx.responseAD, + } + + switch pctx.Proto { + case proxy.ProtoHTTPS: + p.ClientProto = querylog.ClientProtoDoH + case proxy.ProtoQUIC: + p.ClientProto = querylog.ClientProtoDoQ + case proxy.ProtoTLS: + p.ClientProto = querylog.ClientProtoDoT + case proxy.ProtoDNSCrypt: + p.ClientProto = querylog.ClientProtoDNSCrypt + default: + // Consider this a plain DNS-over-UDP or DNS-over-TCP request. + } + + if pctx.Upstream != nil { + p.Upstream = pctx.Upstream.Address() + } else if cachedUps := pctx.CachedUpstreamAddr; cachedUps != "" { + p.Upstream = pctx.CachedUpstreamAddr + p.Cached = true + } + + s.queryLog.Add(p) +} + +// updatesStats writes the request into statistics. func (s *Server) updateStats( ctx *dnsContext, elapsed time.Duration, res filtering.Result, clientIP net.IP, ) { - if s.stats == nil { - return - } - pctx := ctx.proxyCtx e := stats.Entry{} e.Domain = strings.ToLower(pctx.Req.Question[0].Name) diff --git a/internal/querylog/decode.go b/internal/querylog/decode.go index a9810629..b4cfd7e5 100644 --- a/internal/querylog/decode.go +++ b/internal/querylog/decode.go @@ -14,7 +14,7 @@ import ( "github.com/miekg/dns" ) -type logEntryHandler (func(t json.Token, ent *logEntry) error) +type logEntryHandler func(t json.Token, ent *logEntry) error var logEntryHandlers = map[string]logEntryHandler{ "CID": func(t json.Token, ent *logEntry) error { @@ -109,6 +109,16 @@ var logEntryHandlers = map[string]logEntryHandler{ return err }, + "ECS": func(t json.Token, ent *logEntry) error { + v, ok := t.(string) + if !ok { + return nil + } + + ent.ReqECS = v + + return nil + }, "Cached": func(t json.Token, ent *logEntry) error { v, ok := t.(bool) if !ok { diff --git a/internal/querylog/decode_test.go b/internal/querylog/decode_test.go index 3d651c81..c5d45280 100644 --- a/internal/querylog/decode_test.go +++ b/internal/querylog/decode_test.go @@ -32,6 +32,7 @@ func TestDecodeLogEntry(t *testing.T) { `"QT":"A",` + `"QC":"IN",` + `"CP":"",` + + `"ECS":"1.2.3.0/24",` + `"Answer":"` + ansStr + `",` + `"Cached":true,` + `"AD":true,` + @@ -58,6 +59,7 @@ func TestDecodeLogEntry(t *testing.T) { QClass: "IN", ClientID: "cli42", ClientProto: "", + ReqECS: "1.2.3.0/24", Answer: ans, Cached: true, Result: filtering.Result{ diff --git a/internal/querylog/json.go b/internal/querylog/json.go index e4bb63aa..d6adebe4 100644 --- a/internal/querylog/json.go +++ b/internal/querylog/json.go @@ -78,6 +78,10 @@ func (l *queryLog) entryToJSON(entry *logEntry, anonFunc aghnet.IPMutFunc) (json jsonEntry["client_id"] = entry.ClientID } + if entry.ReqECS != "" { + jsonEntry["ecs"] = entry.ReqECS + } + if len(entry.Result.Rules) > 0 { if r := entry.Result.Rules[0]; len(r.Text) > 0 { jsonEntry["rule"] = r.Text diff --git a/internal/querylog/qlog.go b/internal/querylog/qlog.go index 7dc38824..8856fd9c 100644 --- a/internal/querylog/qlog.go +++ b/internal/querylog/qlog.go @@ -81,6 +81,8 @@ type logEntry struct { QType string `json:"QT"` QClass string `json:"QC"` + ReqECS string `json:"ECS,omitempty"` + ClientID string `json:"CID,omitempty"` ClientProto ClientProto `json:"CP"` @@ -189,6 +191,10 @@ func (l *queryLog) Add(params *AddParams) { AuthenticatedData: params.AuthenticatedData, } + if params.ReqECS != nil { + entry.ReqECS = params.ReqECS.String() + } + if params.Answer != nil { var a []byte a, err = params.Answer.Pack() diff --git a/internal/querylog/querylog.go b/internal/querylog/querylog.go index 18b52938..bd6e1569 100644 --- a/internal/querylog/querylog.go +++ b/internal/querylog/querylog.go @@ -77,6 +77,10 @@ type Config struct { type AddParams struct { Question *dns.Msg + // ReqECS is the IP network extracted from EDNS Client-Subnet option of a + // request. + ReqECS *net.IPNet + // Answer is the response which is sent to the client, if any. Answer *dns.Msg diff --git a/internal/querylog/searchcriterion.go b/internal/querylog/searchcriterion.go index 0595fd6e..a9bd4cff 100644 --- a/internal/querylog/searchcriterion.go +++ b/internal/querylog/searchcriterion.go @@ -99,24 +99,10 @@ func (c *searchCriterion) quickMatch(line string, findClient quickMatchClientFun } if c.strict { - return ctDomainOrClientCaseStrict( - c.value, - c.asciiVal, - clientID, - name, - host, - ip, - ) + return ctDomainOrClientCaseStrict(c.value, c.asciiVal, clientID, name, host, ip) } - return ctDomainOrClientCaseNonStrict( - c.value, - c.asciiVal, - clientID, - name, - host, - ip, - ) + return ctDomainOrClientCaseNonStrict(c.value, c.asciiVal, clientID, name, host, ip) case ctFilteringStatus: // Go on, as we currently don't do quick matches against // filtering statuses. diff --git a/openapi/CHANGELOG.md b/openapi/CHANGELOG.md index 0762fdf2..1e2852be 100644 --- a/openapi/CHANGELOG.md +++ b/openapi/CHANGELOG.md @@ -2,7 +2,12 @@ -## v0.107.3: API changes +## v0.108.0: API changes + +### The new optional field `"ecs"` in `QueryLogItem` + +* The new optional field `"ecs"` in `GET /control/querylog` contains the IP + network from an EDNS Client-Subnet option from the request message if any. ### The new possible status code in `/install/configure` response. @@ -10,6 +15,8 @@ `POST /install/configure` which means that the specified password does not meet the strength requirements. +## v0.107.3: API changes + ### The new field `"version"` in `AddressesInfo` * The new field `"version"` in `GET /install/get_addresses` is the version of diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index 85c372a3..8b21a01f 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -1905,6 +1905,12 @@ - 'doq' - 'dnscrypt' - '' + 'ecs': + 'type': 'string' + 'example': '192.168.0.0/16' + 'description': > + The IP network defined by an EDNS Client-Subnet option in the + request message if any. 'elapsedMs': 'type': 'string' 'example': '54.023928' From f1d05a49f092fa80b01105fd1432dbc5b63e8232 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Thu, 3 Mar 2022 20:45:14 +0300 Subject: [PATCH 134/135] Pull request: client: fix en i18n Merge in DNS/adguard-home from fix-en-i18n to master Squashed commit of the following: commit 406e6ece25c6581937a7c7bed34950d7bb2a856e Author: Ainar Garipov Date: Thu Mar 3 19:07:02 2022 +0300 client: imp unsafe port msg commit bd117695be387617facbe57479f0e3d6e81bf151 Author: Ainar Garipov Date: Thu Mar 3 18:51:48 2022 +0300 client: fix more commit cd9ed04d019b26960541569c38bf40ee252da94b Author: Ainar Garipov Date: Thu Mar 3 18:30:27 2022 +0300 client: fix en i18n --- client/src/__locales/en.json | 86 ++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index 4d1dc857..706ddf55 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -35,24 +35,24 @@ "dhcp_config_saved": "DHCP configuration successfully saved", "dhcp_ipv4_settings": "DHCP IPv4 Settings", "dhcp_ipv6_settings": "DHCP IPv6 Settings", - "form_error_required": "Required field.", - "form_error_ip4_format": "Invalid IPv4 address.", - "form_error_ip4_range_start_format": "Invalid IPv4 address of the range start.", - "form_error_ip4_range_end_format": "Invalid IPv4 address of the range end.", - "form_error_ip4_gateway_format": "Invalid IPv4 address of the gateway.", - "form_error_ip6_format": "Invalid IPv6 address.", - "form_error_ip_format": "Invalid IP address.", - "form_error_mac_format": "Invalid MAC address.", - "form_error_client_id_format": "ClientID must contain only numbers, lowercase letters, and hyphens.", - "form_error_server_name": "Invalid server name.", - "form_error_subnet": "Subnet \"{{cidr}}\" does not contain the IP address \"{{ip}}\".", - "form_error_positive": "Must be greater than 0.", - "out_of_range_error": "Must be out of range \"{{start}}\"-\"{{end}}\".", - "lower_range_start_error": "Must be lower than range start.", - "greater_range_start_error": "Must be greater than range start.", - "greater_range_end_error": "Must be greater than range end.", - "subnet_error": "Addresses must be in one subnet.", - "gateway_or_subnet_invalid": "Subnet mask invalid.", + "form_error_required": "Required field", + "form_error_ip4_format": "Invalid IPv4 address", + "form_error_ip4_range_start_format": "Invalid IPv4 address of the range start", + "form_error_ip4_range_end_format": "Invalid IPv4 address of the range end", + "form_error_ip4_gateway_format": "Invalid IPv4 address of the gateway", + "form_error_ip6_format": "Invalid IPv6 address", + "form_error_ip_format": "Invalid IP address", + "form_error_mac_format": "Invalid MAC address", + "form_error_client_id_format": "ClientID must contain only numbers, lowercase letters, and hyphens", + "form_error_server_name": "Invalid server name", + "form_error_subnet": "Subnet \"{{cidr}}\" does not contain the IP address \"{{ip}}\"", + "form_error_positive": "Must be greater than 0", + "out_of_range_error": "Must be out of range \"{{start}}\"-\"{{end}}\"", + "lower_range_start_error": "Must be lower than range start", + "greater_range_start_error": "Must be greater than range start", + "greater_range_end_error": "Must be greater than range end", + "subnet_error": "Addresses must be in one subnet", + "gateway_or_subnet_invalid": "Subnet mask invalid", "dhcp_form_gateway_input": "Gateway IP", "dhcp_form_subnet_input": "Subnet mask", "dhcp_form_range_title": "Range of IP addresses", @@ -67,7 +67,7 @@ "dhcp_table_hostname": "Hostname", "dhcp_table_expires": "Expires", "dhcp_warning": "If you want to enable DHCP server anyway, make sure that there is no other active DHCP server in your network, as this may break the Internet connectivity for devices on the network!", - "dhcp_error": "AdGuard Home could not determine if there is another active DHCP server on the network.", + "dhcp_error": "AdGuard Home could not determine if there is another active DHCP server on the network", "dhcp_static_ip_error": "In order to use DHCP server a static IP address must be set. AdGuard Home failed to determine if this network interface is configured using a static IP address. Please set a static IP address manually.", "dhcp_dynamic_ip_found": "Your system uses dynamic IP address configuration for interface <0>{{interfaceName}}. In order to use DHCP server, a static IP address must be set. Your current IP address is <0>{{ipAddress}}. AdGuard Home will automatically set this IP address as static if you press the \"Enable DHCP server\" button.", "dhcp_lease_added": "Static lease \"{{key}}\" successfully added", @@ -196,8 +196,8 @@ "choose_allowlist": "Choose allowlists", "enter_valid_blocklist": "Enter a valid URL to the blocklist.", "enter_valid_allowlist": "Enter a valid URL to the allowlist.", - "form_error_url_format": "Invalid URL format.", - "form_error_url_or_path_format": "Invalid URL or absolute path of the list.", + "form_error_url_format": "Invalid URL format", + "form_error_url_or_path_format": "Invalid URL or absolute path of the list", "custom_filter_rules": "Custom filtering rules", "custom_filter_rules_hint": "Enter one rule on a line. You can use either adblock rules or hosts files syntax.", "system_host_files": "System hosts files", @@ -261,10 +261,10 @@ "query_log_strict_search": "Use double quotes for strict search", "query_log_retention_confirm": "Are you sure you want to change query log retention? If you decrease the interval value, some data will be lost", "anonymize_client_ip": "Anonymize client IP", - "anonymize_client_ip_desc": "Don't save the client's full IP address to logs or statistics.", + "anonymize_client_ip_desc": "Don't save the client's full IP address to logs or statistics", "dns_config": "DNS server configuration", "dns_cache_config": "DNS cache configuration", - "dns_cache_config_desc": "Here you can configure DNS cache.", + "dns_cache_config_desc": "Here you can configure DNS cache", "blocking_mode": "Blocking mode", "default": "Default", "nxdomain": "NXDOMAIN", @@ -311,7 +311,7 @@ "install_settings_listen": "Listen interface", "install_settings_port": "Port", "install_settings_interface_link": "Your AdGuard Home admin web interface will be available on the following addresses:", - "form_error_port": "Enter valid port number.", + "form_error_port": "Enter valid port number", "install_settings_dns": "DNS server", "install_settings_dns_desc": "You will need to configure your devices or router to use the DNS server on the following addresses:", "install_settings_all_interfaces": "All interfaces", @@ -358,7 +358,7 @@ "open_dashboard": "Open Dashboard", "install_saved": "Saved successfully", "encryption_title": "Encryption", - "encryption_desc": "Encryption (HTTPS/TLS) support for both DNS and admin web interface.", + "encryption_desc": "Encryption (HTTPS/QUIC/TLS) support for both DNS and admin web interface", "encryption_config_saved": "Encryption configuration saved", "encryption_server": "Server name", "encryption_server_enter": "Enter your domain name", @@ -380,26 +380,26 @@ "encryption_key_input": "Copy/paste your PEM-encoded private key for your certificate here.", "encryption_enable": "Enable Encryption (HTTPS, DNS-over-HTTPS, and DNS-over-TLS)", "encryption_enable_desc": "If encryption is enabled, AdGuard Home admin interface will work over HTTPS, and the DNS server will listen for requests over DNS-over-HTTPS and DNS-over-TLS.", - "encryption_chain_valid": "Certificate chain is valid.", - "encryption_chain_invalid": "Certificate chain is invalid.", - "encryption_key_valid": "This is a valid {{type}} private key.", - "encryption_key_invalid": "This is an invalid {{type}} private key.", + "encryption_chain_valid": "Certificate chain is valid", + "encryption_chain_invalid": "Certificate chain is invalid", + "encryption_key_valid": "This is a valid {{type}} private key", + "encryption_key_invalid": "This is an invalid {{type}} private key", "encryption_subject": "Subject", "encryption_issuer": "Issuer", "encryption_hostnames": "Hostnames", "encryption_reset": "Are you sure you want to reset encryption settings?", "topline_expiring_certificate": "Your SSL certificate is about to expire. Update <0>Encryption settings.", "topline_expired_certificate": "Your SSL certificate is expired. Update <0>Encryption settings.", - "form_error_port_range": "Enter port number in the range of 80-65535.", - "form_error_port_unsafe": "This is an unsafe port.", - "form_error_equal": "Must not be equal.", - "form_error_password": "Password mismatched.", + "form_error_port_range": "Enter port number in the range of 80-65535", + "form_error_port_unsafe": "Unsafe port", + "form_error_equal": "Must not be equal", + "form_error_password": "Password mismatch", "reset_settings": "Reset settings", "update_announcement": "AdGuard Home {{version}} is now available! <0>Click here for more info.", "setup_guide": "Setup Guide", "dns_addresses": "DNS addresses", "dns_start": "DNS server is starting up", - "dns_status_error": "Error checking the DNS server status.", + "dns_status_error": "Error checking the DNS server status", "down": "Down", "fix": "Fix", "dns_providers": "Here is a <0>list of known DNS providers to choose from.", @@ -408,7 +408,7 @@ "manual_update": "Please follow these steps to update manually.", "processing_update": "Please wait, AdGuard Home is being updated", "clients_title": "Persistent clients", - "clients_desc": "Configure persistent client records for devices connected to AdGuard Home.", + "clients_desc": "Configure persistent client records for devices connected to AdGuard Home", "settings_global": "Global", "settings_custom": "Custom", "table_client": "Client", @@ -435,9 +435,9 @@ "client_confirm_delete": "Are you sure you want to delete client \"{{key}}\"?", "list_confirm_delete": "Are you sure you want to delete this list?", "auto_clients_title": "Runtime clients", - "auto_clients_desc": "Devices not on the list of Persistent clients that may still use AdGuard Home.", + "auto_clients_desc": "Devices not on the list of Persistent clients that may still use AdGuard Home", "access_title": "Access settings", - "access_desc": "Here you can configure access rules for the AdGuard Home DNS server.", + "access_desc": "Here you can configure access rules for the AdGuard Home DNS server", "access_allowed_title": "Allowed clients", "access_allowed_desc": "A list of CIDRs, IP addresses, or ClientIDs. If this list has entries, AdGuard Home will accept requests only from these clients.", "access_disallowed_title": "Disallowed clients", @@ -477,8 +477,8 @@ "dns_rewrites": "DNS rewrites", "form_domain": "Enter domain name or wildcard", "form_answer": "Enter IP address or domain name", - "form_error_domain_format": "Invalid domain format.", - "form_error_answer_format": "Invalid answer format.", + "form_error_domain_format": "Invalid domain format", + "form_error_answer_format": "Invalid answer format", "configure": "Configure", "main_settings": "Main settings", "block_services": "Block specific services", @@ -510,7 +510,7 @@ "filter_updated": "The list has been successfully updated", "statistics_configuration": "Statistics configuration", "statistics_retention": "Statistics retention", - "statistics_retention_desc": "If you decrease the interval value, some data will be lost.", + "statistics_retention_desc": "If you decrease the interval value, some data will be lost", "statistics_clear": "Clear statistics", "statistics_clear_confirm": "Are you sure you want to clear statistics?", "statistics_retention_confirm": "Are you sure you want to change statistics retention? If you decrease the interval value, some data will be lost", @@ -520,7 +520,7 @@ "interval_hours_plural": "{{count}} hours", "filters_configuration": "Filters configuration", "filters_enable": "Enable filters", - "filters_interval": "Filters update interval", + "filters_interval": "Filter update interval", "disabled": "Disabled", "username_label": "Username", "username_placeholder": "Enter username", @@ -609,7 +609,7 @@ "enter_cache_ttl_max_override": "Enter maximum TTL (seconds)", "cache_ttl_min_override_desc": "Extend short time-to-live values (seconds) received from the upstream server when caching DNS responses.", "cache_ttl_max_override_desc": "Set a maximum time-to-live value (seconds) for entries in the DNS cache.", - "ttl_cache_validation": "Minimum cache TTL override must be less than or equal to the maximum.", + "ttl_cache_validation": "Minimum cache TTL override must be less than or equal to the maximum", "cache_optimistic": "Optimistic caching", "cache_optimistic_desc": "Make AdGuard Home respond from the cache even when the entries are expired and also try to refresh them.", "filter_category_general": "General", @@ -631,5 +631,5 @@ "parental_control": "Parental Control", "safe_browsing": "Safe Browsing", "served_from_cache": "{{value}} (served from cache)", - "form_error_password_length": "Password must be at least {{value}} characters long." + "form_error_password_length": "Password must be at least {{value}} characters long" } From 89d9b03dfec8a5f1406507d45e582e852e748859 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Fri, 4 Mar 2022 15:50:35 +0300 Subject: [PATCH 135/135] Pull request: all: upd go Merge in DNS/adguard-home from upd-go to master Squashed commit of the following: commit 3b6c960afe073223dd73eaf650561509f0d13019 Author: Ainar Garipov Date: Fri Mar 4 15:45:15 2022 +0300 all: upd go --- bamboo-specs/release.yaml | 6 +++--- bamboo-specs/test.yaml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bamboo-specs/release.yaml b/bamboo-specs/release.yaml index 796d874d..50bf1362 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.1' + 'dockerGo': 'adguard/golang-ubuntu:4.2' 'stages': - 'Make release': @@ -266,7 +266,7 @@ # need to build a few of these. 'variables': 'channel': 'beta' - 'dockerGo': 'adguard/golang-ubuntu:4.1' + 'dockerGo': 'adguard/golang-ubuntu:4.2' # release-vX.Y.Z branches are the branches from which the actual final release # is built. - '^release-v[0-9]+\.[0-9]+\.[0-9]+': @@ -281,4 +281,4 @@ # are the ones that actually get released. 'variables': 'channel': 'release' - 'dockerGo': 'adguard/golang-ubuntu:4.1' + 'dockerGo': 'adguard/golang-ubuntu:4.2' diff --git a/bamboo-specs/test.yaml b/bamboo-specs/test.yaml index e41f172f..fa410195 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.1' + 'dockerGo': 'adguard/golang-ubuntu:4.2' 'stages': - 'Tests':