Compare commits
39 Commits
v0.107.1
...
v0.108.0-b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
41e8db4221 | ||
|
|
3f5605c42e | ||
|
|
f7ff02f3b1 | ||
|
|
5ec4a4dab8 | ||
|
|
13871977f9 | ||
|
|
2fdda8a22c | ||
|
|
d82b290251 | ||
|
|
eb15304ff4 | ||
|
|
1a3bf5ebda | ||
|
|
813a06d09a | ||
|
|
061136508e | ||
|
|
008f58c863 | ||
|
|
0e4ffd339f | ||
|
|
1458600c37 | ||
|
|
34c95f99f8 | ||
|
|
e9c59b098e | ||
|
|
a0bb5ce8a4 | ||
|
|
01947bedb4 | ||
|
|
a6ca824064 | ||
|
|
380cff07f2 | ||
|
|
d2ce06e1ca | ||
|
|
2ed1f939b5 | ||
|
|
dea8a585f8 | ||
|
|
313555b10c | ||
|
|
661f4ece48 | ||
|
|
52f36f201e | ||
|
|
46cd974e2a | ||
|
|
201ef10de6 | ||
|
|
d9df7c13be | ||
|
|
64e751e579 | ||
|
|
e6e5958595 | ||
|
|
ff3df0ec33 | ||
|
|
ebe86ce00e | ||
|
|
d317e19291 | ||
|
|
39c4999d2d | ||
|
|
7f55bd8461 | ||
|
|
2968a65f14 | ||
|
|
779fbe79b8 | ||
|
|
da0d1cb754 |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -1,7 +1,7 @@
|
||||
'name': 'build'
|
||||
|
||||
'env':
|
||||
'GO_VERSION': '1.16'
|
||||
'GO_VERSION': '1.17'
|
||||
'NODE_VERSION': '14'
|
||||
|
||||
'on':
|
||||
|
||||
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -1,7 +1,7 @@
|
||||
'name': 'lint'
|
||||
|
||||
'env':
|
||||
'GO_VERSION': '1.16'
|
||||
'GO_VERSION': '1.17'
|
||||
|
||||
'on':
|
||||
'push':
|
||||
|
||||
42
CHANGELOG.md
42
CHANGELOG.md
@@ -7,38 +7,65 @@ The format is based on
|
||||
and this project adheres to
|
||||
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
<!--
|
||||
## [v0.108.0] - 2021-06-01 (APPROX.)
|
||||
## [v0.108.0] - 2022-06-01 (APPROX.)
|
||||
-->
|
||||
|
||||
### Added
|
||||
|
||||
- Support for a `$dnsrewrite` modifier with an empty `NOERROR` response
|
||||
([#4133]).
|
||||
- `windows/arm64` support ([#3057]).
|
||||
|
||||
### Deprecated
|
||||
|
||||
<!--
|
||||
TODO(a.garipov): Remove this deprecation, if v0.108.0 is released before
|
||||
the Go 1.18 release.
|
||||
TODO(a.garipov): Remove this deprecation, if v0.108.0 is released before the Go
|
||||
1.18 release.
|
||||
-->
|
||||
- Go 1.17 support. v0.109.0 will require at least Go 1.18 to build.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Wrong set of ports checked for duplicates during the initial setup ([#4095]).
|
||||
- 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]).
|
||||
|
||||
### 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
|
||||
[#4120]: https://github.com/AdguardTeam/AdGuardHome/issues/4120
|
||||
[#4133]: https://github.com/AdguardTeam/AdGuardHome/issues/4133
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
## [v0.107.2] - 2021-01-19 (APPROX.)
|
||||
## [v0.107.3] - 2022-02-08 (APPROX.)
|
||||
-->
|
||||
|
||||
|
||||
|
||||
## [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
|
||||
@@ -668,11 +695,12 @@ In this release, the schema version has changed from 10 to 12.
|
||||
|
||||
|
||||
<!--
|
||||
[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
|
||||
[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
|
||||
-->
|
||||
|
||||
[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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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]+':
|
||||
@@ -281,4 +281,4 @@
|
||||
# are the ones that actually get released.
|
||||
'variables':
|
||||
'channel': 'release'
|
||||
'dockerGo': 'adguard/golang-ubuntu:3.8'
|
||||
'dockerGo': 'adguard/golang-ubuntu:4.0'
|
||||
|
||||
@@ -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':
|
||||
|
||||
@@ -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}} <i>(атрымана з кэша)</i>"
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 باشد",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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</0>.",
|
||||
"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</0> da cui scegliere.",
|
||||
"dns_providers": "Qui c'è un <0>elenco di fornitori DNS noti</0> da cui scegliere.",
|
||||
"update_now": "Aggiorna ora",
|
||||
"update_failed": "Aggiornamento automatico non riuscito. Ti suggeriamo di <a>seguire questi passaggi</a> 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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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": "Разрешённые",
|
||||
|
||||
@@ -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é",
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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": "<a>Filtreler</a> sayfasından engelleme kurallarını ayarlayabilirsiniz.",
|
||||
"filters_block_toggle_hint": "<a>Filtreler</a> 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</0> 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ı</0> güncelleyin.",
|
||||
"topline_expired_certificate": "SSL sertifikanızın süresi doldu. <0>Şifreleme ayarlarını</0> güncelleyin.",
|
||||
"topline_expiring_certificate": "SSL sertifikanızın süresi sona erdi. <0>Şifreleme ayarlarını</0> güncelleyin.",
|
||||
"topline_expired_certificate": "SSL sertifikanızın süresi sona erdi. <0>Şifreleme ayarlarını</0> 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</0> 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}} <i>(önbellekten kullanıldı)</i>"
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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": "已过滤",
|
||||
|
||||
@@ -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 允許清單",
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Trans, withTranslation } from 'react-i18next';
|
||||
import ReactTable from 'react-table';
|
||||
|
||||
import { MODAL_TYPE } from '../../../helpers/constants';
|
||||
import { splitByNewLine, countClientsStatistics } from '../../../helpers/helpers';
|
||||
import { splitByNewLine, countClientsStatistics, sortIp } from '../../../helpers/helpers';
|
||||
import Card from '../../ui/Card';
|
||||
import Modal from './Modal';
|
||||
import CellWrap from '../../ui/CellWrap';
|
||||
@@ -106,6 +106,7 @@ class ClientsTable extends Component {
|
||||
</div>
|
||||
);
|
||||
},
|
||||
sortMethod: sortIp,
|
||||
},
|
||||
{
|
||||
Header: this.props.t('table_name'),
|
||||
|
||||
@@ -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 (
|
||||
<div className="version">
|
||||
<div className="version__text">
|
||||
{dnsVersion
|
||||
&& <>
|
||||
<Trans>version</Trans>:
|
||||
<span className="version__value" title={dnsVersion}>{dnsVersion}</span>
|
||||
</>}
|
||||
{version && (
|
||||
<>
|
||||
<Trans>version</Trans>:
|
||||
<span className="version__value" title={version}>{version}</span>
|
||||
</>
|
||||
)}
|
||||
{checkUpdateFlag && <button
|
||||
type="button"
|
||||
className="btn btn-icon btn-icon-sm btn-outline-primary btn-sm ml-2"
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -12,13 +12,19 @@ const install = handleActions({
|
||||
[actions.getDefaultAddressesRequest]: (state) => ({ ...state, processingDefault: true }),
|
||||
[actions.getDefaultAddressesFailure]: (state) => ({ ...state, processingDefault: false }),
|
||||
[actions.getDefaultAddressesSuccess]: (state, { payload }) => {
|
||||
const { interfaces } = payload;
|
||||
const { interfaces, version } = payload;
|
||||
const web = { ...state.web, port: payload.web_port };
|
||||
const dns = { ...state.dns, port: payload.dns_port };
|
||||
|
||||
const newState = {
|
||||
...state, web, dns, interfaces, processingDefault: false,
|
||||
...state,
|
||||
web,
|
||||
dns,
|
||||
interfaces,
|
||||
processingDefault: false,
|
||||
dnsVersion: version,
|
||||
};
|
||||
|
||||
return newState;
|
||||
},
|
||||
|
||||
@@ -64,6 +70,7 @@ const install = handleActions({
|
||||
error: '',
|
||||
},
|
||||
interfaces: {},
|
||||
dnsVersion: '',
|
||||
});
|
||||
|
||||
export default combineReducers({
|
||||
|
||||
51
go.mod
51
go.mod
@@ -1,25 +1,25 @@
|
||||
module github.com/AdguardTeam/AdGuardHome
|
||||
|
||||
go 1.16
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/AdguardTeam/dnsproxy v0.40.3-0.20211229125141-da9b0c6cf76a
|
||||
github.com/AdguardTeam/golibs v0.10.3
|
||||
github.com/AdguardTeam/urlfilter v0.15.1
|
||||
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
|
||||
github.com/ameshkov/dnscrypt/v2 v2.2.3
|
||||
github.com/digineo/go-ipset/v2 v2.2.1
|
||||
github.com/fsnotify/fsnotify v1.5.1
|
||||
github.com/go-ping/ping v0.0.0-20210506233800-ff8be3320020
|
||||
github.com/google/go-cmp v0.5.5
|
||||
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.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.45
|
||||
github.com/satori/go.uuid v1.2.0
|
||||
github.com/stretchr/testify v1.7.0
|
||||
@@ -30,7 +30,36 @@ require (
|
||||
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
|
||||
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/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-20210107192922-496545a6307b // indirect
|
||||
honnef.co/go/tools v0.2.2 // indirect
|
||||
)
|
||||
|
||||
87
go.sum
87
go.sum
@@ -7,18 +7,19 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr
|
||||
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
|
||||
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
|
||||
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
||||
github.com/AdguardTeam/dnsproxy v0.40.3-0.20211229125141-da9b0c6cf76a h1:m+84VGYbDBq55L5apbHj1UqbZOcK1lqmnZVlBvzycmk=
|
||||
github.com/AdguardTeam/dnsproxy v0.40.3-0.20211229125141-da9b0c6cf76a/go.mod h1:+NlQl9lcVKjbecYlCumfjMzDk2BblySEX7WOHhQBbXk=
|
||||
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.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=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/AdguardTeam/urlfilter v0.15.2 h1:LZGgrm4l4Ys9eAqB+UUmZfiC6vHlDlYFhx0WXqo6LtQ=
|
||||
github.com/AdguardTeam/urlfilter v0.15.2/go.mod h1:46YZDOV1+qtdRDuhZKVPSSp7JWWes0KayqHrKAFBdEI=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw=
|
||||
github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/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=
|
||||
@@ -40,6 +41,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=
|
||||
@@ -52,6 +55,7 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn
|
||||
github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
|
||||
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
|
||||
@@ -61,8 +65,8 @@ github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aev
|
||||
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/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
@@ -91,8 +95,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=
|
||||
@@ -101,6 +106,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=
|
||||
@@ -109,8 +117,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-20210310193751-cfd4d47082c2 h1:NpTIlXznCStsY88jU+Gh1Dy5dt/jYV4z4uU8h2TUOt4=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20210310193751-cfd4d47082c2/go.mod h1:TKl4jN3Voofo4UJIicyNhWGp/nlQqQkFxmwIFTvBkKI=
|
||||
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/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||
@@ -123,8 +131,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=
|
||||
@@ -132,6 +142,7 @@ 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=
|
||||
@@ -150,8 +161,9 @@ github.com/marten-seemann/qtls-go1-17 v0.1.0/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz
|
||||
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=
|
||||
@@ -164,12 +176,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/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=
|
||||
@@ -257,12 +276,14 @@ 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=
|
||||
@@ -308,7 +329,6 @@ 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=
|
||||
@@ -317,13 +337,18 @@ golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||
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-20210908191846-a5e095526f91/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210929193557-e81a3d93ecf6/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f 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=
|
||||
@@ -368,25 +393,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-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=
|
||||
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210909193231-528a39cd75f3/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e 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-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
@@ -410,8 +443,10 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
|
||||
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/tools v0.1.8 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=
|
||||
@@ -454,6 +489,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=
|
||||
@@ -468,7 +504,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=
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Package aghalgo contains common generic algorithms and data structures.
|
||||
// Package aghalg contains common generic algorithms and data structures.
|
||||
//
|
||||
// TODO(a.garipov): Update to use type parameters in Go 1.18.
|
||||
package aghalgo
|
||||
package aghalg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -14,20 +14,20 @@ import (
|
||||
// TODO(a.garipov): Remove in Go 1.18.
|
||||
type comparable = interface{}
|
||||
|
||||
// UniquenessValidator allows validating uniqueness of comparable items.
|
||||
type UniquenessValidator map[comparable]int64
|
||||
// UniqChecker allows validating uniqueness of comparable items.
|
||||
type UniqChecker map[comparable]int64
|
||||
|
||||
// Add adds a value to the validator. v must not be nil.
|
||||
func (v UniquenessValidator) Add(elems ...comparable) {
|
||||
func (uc UniqChecker) Add(elems ...comparable) {
|
||||
for _, e := range elems {
|
||||
v[e]++
|
||||
uc[e]++
|
||||
}
|
||||
}
|
||||
|
||||
// Merge returns a validator containing data from both v and other.
|
||||
func (v UniquenessValidator) Merge(other UniquenessValidator) (merged UniquenessValidator) {
|
||||
merged = make(UniquenessValidator, len(v)+len(other))
|
||||
for elem, num := range v {
|
||||
// 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 {
|
||||
merged[elem] += num
|
||||
}
|
||||
|
||||
@@ -41,9 +41,9 @@ func (v UniquenessValidator) Merge(other UniquenessValidator) (merged Uniqueness
|
||||
// Validate returns an error enumerating all elements that aren't unique.
|
||||
// isBefore is an optional sorting function to make the error message
|
||||
// deterministic.
|
||||
func (v UniquenessValidator) Validate(isBefore func(a, b comparable) (less bool)) (err error) {
|
||||
func (uc UniqChecker) Validate(isBefore func(a, b comparable) (less bool)) (err error) {
|
||||
var dup []comparable
|
||||
for elem, num := range v {
|
||||
for elem, num := range uc {
|
||||
if num > 1 {
|
||||
dup = append(dup, elem)
|
||||
}
|
||||
@@ -62,13 +62,13 @@ func (v UniquenessValidator) Validate(isBefore func(a, b comparable) (less bool)
|
||||
return fmt.Errorf("duplicated values: %v", dup)
|
||||
}
|
||||
|
||||
// IntIsBefore is a helper sort function for UniquenessValidator.Validate.
|
||||
// IntIsBefore is a helper sort function for UniqChecker.Validate.
|
||||
// a and b must be of type int.
|
||||
func IntIsBefore(a, b comparable) (less bool) {
|
||||
return a.(int) < b.(int)
|
||||
}
|
||||
|
||||
// StringIsBefore is a helper sort function for UniquenessValidator.Validate.
|
||||
// StringIsBefore is a helper sort function for UniqChecker.Validate.
|
||||
// a and b must be of type string.
|
||||
func StringIsBefore(a, b comparable) (less bool) {
|
||||
return a.(string) < b.(string)
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,111 +278,158 @@ 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)
|
||||
|
||||
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,
|
||||
},
|
||||
}, {
|
||||
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,
|
||||
},
|
||||
}}
|
||||
|
||||
@@ -411,20 +446,33 @@ 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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 +481,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 +524,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)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
44
internal/aghnet/ipmut_test.go
Normal file
44
internal/aghnet/ipmut_test.go
Normal file
@@ -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))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
10
internal/aghnet/testdata/etc_hosts
vendored
10
internal/aghnet/testdata/etc_hosts
vendored
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -27,7 +27,6 @@ type DHCPServer interface {
|
||||
Start() (err error)
|
||||
// Stop - stop server
|
||||
Stop() (err error)
|
||||
|
||||
getLeasesRef() []*Lease
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghalgo"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
@@ -214,7 +214,7 @@ func validateAccessSet(list *accessListJSON) (err error) {
|
||||
}
|
||||
|
||||
merged := allowed.Merge(disallowed)
|
||||
err = merged.Validate(aghalgo.StringIsBefore)
|
||||
err = merged.Validate(aghalg.StringIsBefore)
|
||||
if err != nil {
|
||||
return fmt.Errorf("items in allowed and disallowed clients intersect: %w", err)
|
||||
}
|
||||
@@ -223,13 +223,13 @@ func validateAccessSet(list *accessListJSON) (err error) {
|
||||
}
|
||||
|
||||
// validateStrUniq returns an informative error if clients are not unique.
|
||||
func validateStrUniq(clients []string) (uv aghalgo.UniquenessValidator, err error) {
|
||||
uv = make(aghalgo.UniquenessValidator, len(clients))
|
||||
func validateStrUniq(clients []string) (uc aghalg.UniqChecker, err error) {
|
||||
uc = make(aghalg.UniqChecker, len(clients))
|
||||
for _, c := range clients {
|
||||
uv.Add(c)
|
||||
uc.Add(c)
|
||||
}
|
||||
|
||||
return uv, uv.Validate(aghalgo.StringIsBefore)
|
||||
return uc, uc.Validate(aghalg.StringIsBefore)
|
||||
}
|
||||
|
||||
func (s *Server) handleAccessSet(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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++
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghalgo"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
|
||||
@@ -288,9 +288,9 @@ func parseConfig() (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
uv := aghalgo.UniquenessValidator{}
|
||||
uc := aghalg.UniqChecker{}
|
||||
addPorts(
|
||||
uv,
|
||||
uc,
|
||||
config.BindPort,
|
||||
config.BetaBindPort,
|
||||
config.DNS.Port,
|
||||
@@ -298,14 +298,14 @@ func parseConfig() (err error) {
|
||||
|
||||
if config.TLS.Enabled {
|
||||
addPorts(
|
||||
uv,
|
||||
uc,
|
||||
config.TLS.PortHTTPS,
|
||||
config.TLS.PortDNSOverTLS,
|
||||
config.TLS.PortDNSOverQUIC,
|
||||
config.TLS.PortDNSCrypt,
|
||||
)
|
||||
}
|
||||
if err = uv.Validate(aghalgo.IntIsBefore); err != nil {
|
||||
if err = uc.Validate(aghalg.IntIsBefore); err != nil {
|
||||
return fmt.Errorf("validating ports: %w", err)
|
||||
}
|
||||
|
||||
@@ -321,10 +321,10 @@ func parseConfig() (err error) {
|
||||
}
|
||||
|
||||
// addPorts is a helper for ports validation. It skips zero ports.
|
||||
func addPorts(uv aghalgo.UniquenessValidator, ports ...int) {
|
||||
func addPorts(uc aghalg.UniqChecker, ports ...int) {
|
||||
for _, p := range ports {
|
||||
if p != 0 {
|
||||
uv.Add(p)
|
||||
uc.Add(p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,9 +14,10 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghalgo"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/version"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
)
|
||||
@@ -24,13 +25,23 @@ 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"`
|
||||
|
||||
// Version is the version of AdGuard Home.
|
||||
//
|
||||
// TODO(a.garipov): In the new API, rename this endpoint to something more
|
||||
// general, since there will be more information here than just network
|
||||
// interfaces.
|
||||
Version string `json:"version"`
|
||||
|
||||
WebPort int `json:"web_port"`
|
||||
DNSPort int `json:"dns_port"`
|
||||
}
|
||||
|
||||
// handleInstallGetAddresses is the handler for /install/get_addresses endpoint.
|
||||
func (web *Web) handleInstallGetAddresses(w http.ResponseWriter, r *http.Request) {
|
||||
data := getAddrsResponse{
|
||||
Version: version.Version(),
|
||||
|
||||
WebPort: defaultPortHTTP,
|
||||
DNSPort: defaultPortDNS,
|
||||
}
|
||||
@@ -62,19 +73,19 @@ func (web *Web) handleInstallGetAddresses(w http.ResponseWriter, r *http.Request
|
||||
}
|
||||
}
|
||||
|
||||
type checkConfigReqEnt struct {
|
||||
type checkConfReqEnt struct {
|
||||
IP net.IP `json:"ip"`
|
||||
Port int `json:"port"`
|
||||
Autofix bool `json:"autofix"`
|
||||
}
|
||||
|
||||
type checkConfigReq struct {
|
||||
Web checkConfigReqEnt `json:"web"`
|
||||
DNS checkConfigReqEnt `json:"dns"`
|
||||
SetStaticIP bool `json:"set_static_ip"`
|
||||
type checkConfReq struct {
|
||||
Web checkConfReqEnt `json:"web"`
|
||||
DNS checkConfReqEnt `json:"dns"`
|
||||
SetStaticIP bool `json:"set_static_ip"`
|
||||
}
|
||||
|
||||
type checkConfigRespEnt struct {
|
||||
type checkConfRespEnt struct {
|
||||
Status string `json:"status"`
|
||||
CanAutofix bool `json:"can_autofix"`
|
||||
}
|
||||
@@ -85,79 +96,110 @@ type staticIPJSON struct {
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
type checkConfigResp struct {
|
||||
StaticIP staticIPJSON `json:"static_ip"`
|
||||
Web checkConfigRespEnt `json:"web"`
|
||||
DNS checkConfigRespEnt `json:"dns"`
|
||||
type checkConfResp struct {
|
||||
StaticIP staticIPJSON `json:"static_ip"`
|
||||
Web checkConfRespEnt `json:"web"`
|
||||
DNS checkConfRespEnt `json:"dns"`
|
||||
}
|
||||
|
||||
// Check if ports are available, respond with results
|
||||
func (web *Web) handleInstallCheckConfig(w http.ResponseWriter, r *http.Request) {
|
||||
reqData := checkConfigReq{}
|
||||
respData := checkConfigResp{}
|
||||
// validateWeb returns error is the web part if the initial configuration can't
|
||||
// be set.
|
||||
func (req *checkConfReq) validateWeb(uc aghalg.UniqChecker) (err error) {
|
||||
defer func() { err = errors.Annotate(err, "validating ports: %w") }()
|
||||
|
||||
err := json.NewDecoder(r.Body).Decode(&reqData)
|
||||
port := req.Web.Port
|
||||
addPorts(uc, config.BetaBindPort, port)
|
||||
if err = uc.Validate(aghalg.IntIsBefore); err != nil {
|
||||
// Avoid duplicating the error into the status of DNS.
|
||||
uc[port] = 1
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
switch port {
|
||||
case 0, config.BindPort:
|
||||
return nil
|
||||
default:
|
||||
// Go on and check the port binding only if it's not zero or won't be
|
||||
// unbound after install.
|
||||
}
|
||||
|
||||
return aghnet.CheckPort("tcp", req.Web.IP, port)
|
||||
}
|
||||
|
||||
// validateDNS returns error if the DNS part of the initial configuration can't
|
||||
// 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") }()
|
||||
|
||||
port := req.DNS.Port
|
||||
addPorts(uc, port)
|
||||
if err = uc.Validate(aghalg.IntIsBefore); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
switch port {
|
||||
case 0:
|
||||
return false, nil
|
||||
case config.BindPort:
|
||||
// Go on and only check the UDP port since the TCP one is already bound
|
||||
// by AdGuard Home for web interface.
|
||||
default:
|
||||
// Check TCP as well.
|
||||
err = aghnet.CheckPort("tcp", req.DNS.IP, port)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
err = aghnet.CheckPort("udp", req.DNS.IP, port)
|
||||
if !aghnet.IsAddrInUse(err) {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Try to fix automatically.
|
||||
canAutofix = checkDNSStubListener()
|
||||
if canAutofix && req.DNS.Autofix {
|
||||
if derr := disableDNSStubListener(); derr != nil {
|
||||
log.Error("disabling DNSStubListener: %s", err)
|
||||
}
|
||||
|
||||
err = aghnet.CheckPort("udp", req.DNS.IP, port)
|
||||
canAutofix = false
|
||||
}
|
||||
|
||||
return canAutofix, err
|
||||
}
|
||||
|
||||
// handleInstallCheckConfig handles the /check_config endpoint.
|
||||
func (web *Web) handleInstallCheckConfig(w http.ResponseWriter, r *http.Request) {
|
||||
req := &checkConfReq{}
|
||||
|
||||
err := json.NewDecoder(r.Body).Decode(req)
|
||||
if err != nil {
|
||||
aghhttp.Error(r, w, http.StatusBadRequest, "Failed to parse 'check_config' JSON data: %s", err)
|
||||
aghhttp.Error(r, w, http.StatusBadRequest, "decoding the request: %s", err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
uv := aghalgo.UniquenessValidator{}
|
||||
addPorts(
|
||||
uv,
|
||||
config.BindPort,
|
||||
config.BetaBindPort,
|
||||
reqData.Web.Port,
|
||||
)
|
||||
if err = uv.Validate(aghalgo.IntIsBefore); err != nil {
|
||||
err = fmt.Errorf("validating ports: %w", err)
|
||||
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()
|
||||
}
|
||||
resp := &checkConfResp{}
|
||||
uc := aghalg.UniqChecker{}
|
||||
|
||||
if err = req.validateWeb(uc); err != nil {
|
||||
resp.Web.Status = err.Error()
|
||||
}
|
||||
|
||||
addPorts(uv, reqData.DNS.Port)
|
||||
if err = uv.Validate(aghalgo.IntIsBefore); err != nil {
|
||||
err = fmt.Errorf("validating ports: %w", err)
|
||||
respData.DNS.Status = err.Error()
|
||||
} else if reqData.DNS.Port != 0 {
|
||||
err = aghnet.CheckPort("udp", reqData.DNS.IP, reqData.DNS.Port)
|
||||
|
||||
if aghnet.IsAddrInUse(err) {
|
||||
canAutofix := checkDNSStubListener()
|
||||
if canAutofix && reqData.DNS.Autofix {
|
||||
|
||||
err = disableDNSStubListener()
|
||||
if err != nil {
|
||||
log.Error("Couldn't disable DNSStubListener: %s", err)
|
||||
}
|
||||
|
||||
err = aghnet.CheckPort("udp", reqData.DNS.IP, reqData.DNS.Port)
|
||||
canAutofix = false
|
||||
}
|
||||
|
||||
respData.DNS.CanAutofix = canAutofix
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
err = aghnet.CheckPort("tcp", reqData.DNS.IP, reqData.DNS.Port)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
respData.DNS.Status = err.Error()
|
||||
} else if !reqData.DNS.IP.IsUnspecified() {
|
||||
respData.StaticIP = handleStaticIP(reqData.DNS.IP, reqData.SetStaticIP)
|
||||
}
|
||||
if resp.DNS.CanAutofix, err = req.validateDNS(uc); err != nil {
|
||||
resp.DNS.Status = err.Error()
|
||||
} else if !req.DNS.IP.IsUnspecified() {
|
||||
resp.StaticIP = handleStaticIP(req.DNS.IP, req.SetStaticIP)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
err = json.NewEncoder(w).Encode(respData)
|
||||
err = json.NewEncoder(w).Encode(resp)
|
||||
if err != nil {
|
||||
aghhttp.Error(r, w, http.StatusInternalServerError, "Unable to marshal JSON: %s", err)
|
||||
aghhttp.Error(r, w, http.StatusInternalServerError, "encoding the response: %s", err)
|
||||
|
||||
return
|
||||
}
|
||||
@@ -279,10 +321,11 @@ type applyConfigReqEnt struct {
|
||||
}
|
||||
|
||||
type applyConfigReq struct {
|
||||
Web applyConfigReqEnt `json:"web"`
|
||||
DNS applyConfigReqEnt `json:"dns"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
|
||||
Web applyConfigReqEnt `json:"web"`
|
||||
DNS applyConfigReqEnt `json:"dns"`
|
||||
}
|
||||
|
||||
// copyInstallSettings copies the installation parameters between two
|
||||
@@ -482,13 +525,13 @@ func (web *Web) handleInstallCheckConfigBeta(w http.ResponseWriter, r *http.Requ
|
||||
return
|
||||
}
|
||||
|
||||
nonBetaReqData := checkConfigReq{
|
||||
Web: checkConfigReqEnt{
|
||||
nonBetaReqData := checkConfReq{
|
||||
Web: checkConfReqEnt{
|
||||
IP: reqData.Web.IP[0],
|
||||
Port: reqData.Web.Port,
|
||||
Autofix: reqData.Web.Autofix,
|
||||
},
|
||||
DNS: checkConfigReqEnt{
|
||||
DNS: checkConfReqEnt{
|
||||
IP: reqData.DNS.IP[0],
|
||||
Port: reqData.DNS.Port,
|
||||
Autofix: reqData.DNS.Autofix,
|
||||
@@ -533,10 +576,11 @@ type applyConfigReqEntBeta struct {
|
||||
// TODO(e.burkov): This should removed with the API v1 when the appropriate
|
||||
// functionality will appear in default applyConfigReq.
|
||||
type applyConfigReqBeta struct {
|
||||
Web applyConfigReqEntBeta `json:"web"`
|
||||
DNS applyConfigReqEntBeta `json:"dns"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
|
||||
Web applyConfigReqEntBeta `json:"web"`
|
||||
DNS applyConfigReqEntBeta `json:"dns"`
|
||||
}
|
||||
|
||||
// handleInstallConfigureBeta is a substitution of /install/configure handler
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghalgo"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
|
||||
@@ -296,23 +296,23 @@ func setupConfig(args options) (err error) {
|
||||
Context.clients.Init(config.Clients, Context.dhcpServer, Context.etcHosts)
|
||||
|
||||
if args.bindPort != 0 {
|
||||
uv := aghalgo.UniquenessValidator{}
|
||||
uc := aghalg.UniqChecker{}
|
||||
addPorts(
|
||||
uv,
|
||||
uc,
|
||||
args.bindPort,
|
||||
config.BetaBindPort,
|
||||
config.DNS.Port,
|
||||
)
|
||||
if config.TLS.Enabled {
|
||||
addPorts(
|
||||
uv,
|
||||
uc,
|
||||
config.TLS.PortHTTPS,
|
||||
config.TLS.PortDNSOverTLS,
|
||||
config.TLS.PortDNSOverQUIC,
|
||||
config.TLS.PortDNSCrypt,
|
||||
)
|
||||
}
|
||||
if err = uv.Validate(aghalgo.IntIsBefore); err != nil {
|
||||
if err = uc.Validate(aghalg.IntIsBefore); err != nil {
|
||||
return fmt.Errorf("validating ports: %w", err)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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") {
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghalgo"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
@@ -251,9 +251,9 @@ func (t *TLSMod) handleTLSValidate(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if setts.Enabled {
|
||||
uv := aghalgo.UniquenessValidator{}
|
||||
uc := aghalg.UniqChecker{}
|
||||
addPorts(
|
||||
uv,
|
||||
uc,
|
||||
config.BindPort,
|
||||
config.BetaBindPort,
|
||||
config.DNS.Port,
|
||||
@@ -263,7 +263,7 @@ func (t *TLSMod) handleTLSValidate(w http.ResponseWriter, r *http.Request) {
|
||||
setts.PortDNSCrypt,
|
||||
)
|
||||
|
||||
err = uv.Validate(aghalgo.IntIsBefore)
|
||||
err = uc.Validate(aghalg.IntIsBefore)
|
||||
if err != nil {
|
||||
aghhttp.Error(r, w, http.StatusBadRequest, "validating ports: %s", err)
|
||||
|
||||
@@ -344,9 +344,9 @@ func (t *TLSMod) handleTLSConfigure(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if data.Enabled {
|
||||
uv := aghalgo.UniquenessValidator{}
|
||||
uc := aghalg.UniqChecker{}
|
||||
addPorts(
|
||||
uv,
|
||||
uc,
|
||||
config.BindPort,
|
||||
config.BetaBindPort,
|
||||
config.DNS.Port,
|
||||
@@ -356,7 +356,7 @@ func (t *TLSMod) handleTLSConfigure(w http.ResponseWriter, r *http.Request) {
|
||||
data.PortDNSCrypt,
|
||||
)
|
||||
|
||||
err = uv.Validate(aghalgo.IntIsBefore)
|
||||
err = uc.Validate(aghalg.IntIsBefore)
|
||||
if err != nil {
|
||||
aghhttp.Error(r, w, http.StatusBadRequest, "%s", err)
|
||||
|
||||
|
||||
@@ -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{},
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -62,18 +62,10 @@ func Version() (v string) {
|
||||
return version
|
||||
}
|
||||
|
||||
// Common formatting constants.
|
||||
const (
|
||||
sp = " "
|
||||
nl = "\n"
|
||||
tb = "\t"
|
||||
nltb = nl + tb
|
||||
)
|
||||
|
||||
// Constants defining the format of module information string.
|
||||
const (
|
||||
modInfoAtSep = "@"
|
||||
modInfoDevSep = sp
|
||||
modInfoDevSep = " "
|
||||
modInfoSumLeft = " (sum: "
|
||||
modInfoSumRight = ")"
|
||||
)
|
||||
@@ -142,6 +134,7 @@ const (
|
||||
func Verbose() (v string) {
|
||||
b := &strings.Builder{}
|
||||
|
||||
const nl = "\n"
|
||||
stringutil.WriteToBuilder(
|
||||
b,
|
||||
vFmtAGHHdr,
|
||||
@@ -178,7 +171,7 @@ func Verbose() (v string) {
|
||||
stringutil.WriteToBuilder(b, nl, vFmtDepsHdr)
|
||||
for _, dep := range info.Deps {
|
||||
if depStr := fmtModule(dep); depStr != "" {
|
||||
stringutil.WriteToBuilder(b, nltb, depStr)
|
||||
stringutil.WriteToBuilder(b, "\n\t", depStr)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,16 @@
|
||||
|
||||
<!-- TODO(a.garipov): Reformat in accordance with the KeepAChangelog spec. -->
|
||||
|
||||
## v0.107: API changes
|
||||
## v0.107.3: API changes
|
||||
|
||||
## The new field `"cached"` in `QueryLogItem`
|
||||
### The new field `"version"` in `AddressesInfo`
|
||||
|
||||
* The new field `"version"` in `GET /install/get_addresses` is the version of
|
||||
the AdGuard Home instance.
|
||||
|
||||
## v0.107.0: 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.
|
||||
|
||||
@@ -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':
|
||||
@@ -1262,7 +1264,7 @@
|
||||
'type': 'boolean'
|
||||
'version':
|
||||
'type': 'string'
|
||||
'example': '0.1'
|
||||
'example': 'v0.123.4'
|
||||
'language':
|
||||
'type': 'string'
|
||||
'example': 'en'
|
||||
@@ -2219,19 +2221,23 @@
|
||||
'description': 'AdGuard Home addresses configuration'
|
||||
'required':
|
||||
- 'dns_port'
|
||||
- 'web_port'
|
||||
- 'interfaces'
|
||||
- 'version'
|
||||
- 'web_port'
|
||||
'properties':
|
||||
'dns_port':
|
||||
'type': 'integer'
|
||||
'format': 'uint16'
|
||||
'example': 53
|
||||
'interfaces':
|
||||
'$ref': '#/components/schemas/NetInterfaces'
|
||||
'version':
|
||||
'type': 'string'
|
||||
'example': 'v0.123.4'
|
||||
'web_port':
|
||||
'type': 'integer'
|
||||
'format': 'uint16'
|
||||
'example': 80
|
||||
'interfaces':
|
||||
'$ref': '#/components/schemas/NetInterfaces'
|
||||
'AddressesInfoBeta':
|
||||
'type': 'object'
|
||||
'description': 'AdGuard Home addresses configuration'
|
||||
|
||||
@@ -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'
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -49,10 +49,10 @@ trap not_found EXIT
|
||||
|
||||
# Warnings
|
||||
|
||||
go_version="$( "$GO" version )"
|
||||
go_version="$( "${GO:-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.
|
||||
@@ -62,7 +62,6 @@ for example:
|
||||
"
|
||||
readonly go_min_version go_version_msg
|
||||
|
||||
|
||||
case "$go_version"
|
||||
in
|
||||
('go version'*"$go_min_version"*)
|
||||
@@ -80,11 +79,11 @@ esac
|
||||
# blocklist_imports is a simple check against unwanted packages. The following
|
||||
# packages are banned:
|
||||
#
|
||||
# * Package io/ioutil is soft-deprecated.
|
||||
#
|
||||
# * Packages errors and log are replaced by our own packages in the
|
||||
# github.com/AdguardTeam/golibs module.
|
||||
#
|
||||
# * Package io/ioutil is soft-deprecated.
|
||||
#
|
||||
# * Package reflect is often an overkill, and for deep comparisons there are
|
||||
# much better functions in module github.com/google/go-cmp. Which is
|
||||
# already our indirect dependency and which may or may not enter the stdlib
|
||||
@@ -94,6 +93,8 @@ esac
|
||||
#
|
||||
# * Package unsafe is… unsafe.
|
||||
#
|
||||
# * Package golang.org/x/net/context has been moved into stdlib.
|
||||
#
|
||||
blocklist_imports() {
|
||||
git grep\
|
||||
-e '[[:space:]]"errors"$'\
|
||||
@@ -101,33 +102,55 @@ blocklist_imports() {
|
||||
-e '[[:space:]]"log"$'\
|
||||
-e '[[:space:]]"reflect"$'\
|
||||
-e '[[:space:]]"unsafe"$'\
|
||||
-- '*.go' || exit 0;
|
||||
-e '[[:space:]]"golang.org/x/net/context"$'\
|
||||
-n\
|
||||
-- '*.go'\
|
||||
| sed -e 's/^\([^[:space:]]\+\)\(.*\)$/\1 blocked import:\2/'\
|
||||
|| exit 0
|
||||
}
|
||||
|
||||
# method_const is a simple check against the usage of some raw strings and
|
||||
# numbers where one should use named constants.
|
||||
method_const() {
|
||||
git grep -F -e '"GET"' -e '"POST"' -- '*.go' || exit 0;
|
||||
git grep -F\
|
||||
-e '"DELETE"'\
|
||||
-e '"GET"'\
|
||||
-e '"POST"'\
|
||||
-e '"PUT"'\
|
||||
-n\
|
||||
-- '*.go'\
|
||||
| sed -e 's/^\([^[:space:]]\+\)\(.*\)$/\1 http method literal:\2/'\
|
||||
|| exit 0
|
||||
}
|
||||
|
||||
# underscores is a simple check against Go filenames with underscores.
|
||||
# underscores is a simple check against Go filenames with underscores. Add new
|
||||
# build tags and OS as you go. The main goal of this check is to discourage the
|
||||
# use of filenames like client_manager.go.
|
||||
underscores() {
|
||||
git ls-files '*_*.go' | {
|
||||
grep -F\
|
||||
-e '_big.go'\
|
||||
-e '_bsd.go'\
|
||||
-e '_darwin.go'\
|
||||
-e '_freebsd.go'\
|
||||
-e '_openbsd.go'\
|
||||
-e '_linux.go'\
|
||||
-e '_little.go'\
|
||||
-e '_others.go'\
|
||||
-e '_test.go'\
|
||||
-e '_unix.go'\
|
||||
-e '_windows.go' \
|
||||
-v\
|
||||
|| exit 0
|
||||
}
|
||||
underscore_files="$(
|
||||
git ls-files '*_*.go'\
|
||||
| grep -F\
|
||||
-e '_big.go'\
|
||||
-e '_bsd.go'\
|
||||
-e '_darwin.go'\
|
||||
-e '_freebsd.go'\
|
||||
-e '_openbsd.go'\
|
||||
-e '_linux.go'\
|
||||
-e '_little.go'\
|
||||
-e '_others.go'\
|
||||
-e '_test.go'\
|
||||
-e '_unix.go'\
|
||||
-e '_windows.go' \
|
||||
-v\
|
||||
| sed -e 's/./\t\0/'
|
||||
)"
|
||||
readonly underscore_files
|
||||
|
||||
if [ "$underscore_files" != '' ]
|
||||
then
|
||||
echo 'found file names with underscores:'
|
||||
echo "$underscore_files"
|
||||
fi
|
||||
}
|
||||
|
||||
# TODO(a.garipov): Add an analyser to look for `fallthrough`, `goto`, and `new`?
|
||||
@@ -151,7 +174,7 @@ exit_on_output() (
|
||||
|
||||
output="$( "$cmd" "$@" 2>&1 )"
|
||||
exitcode="$?"
|
||||
if [ "$exitcode" != '0' ]
|
||||
if [ "$exitcode" -ne '0' ]
|
||||
then
|
||||
echo "'$cmd' failed with code $exitcode"
|
||||
fi
|
||||
@@ -160,9 +183,9 @@ exit_on_output() (
|
||||
then
|
||||
if [ "$*" != '' ]
|
||||
then
|
||||
echo "combined output of '$cmd $*':"
|
||||
echo "combined output of linter '$cmd $*':"
|
||||
else
|
||||
echo "combined output of '$cmd':"
|
||||
echo "combined output of linter '$cmd':"
|
||||
fi
|
||||
|
||||
echo "$output"
|
||||
@@ -178,13 +201,6 @@ exit_on_output() (
|
||||
|
||||
|
||||
|
||||
# Constants
|
||||
|
||||
go_files='./main.go ./internal/'
|
||||
readonly go_files
|
||||
|
||||
|
||||
|
||||
# Checks
|
||||
|
||||
exit_on_output blocklist_imports
|
||||
@@ -193,7 +209,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 ./...
|
||||
|
||||
@@ -208,8 +224,6 @@ gocyclo --over 10 ./internal/aghio/ ./internal/aghnet/ ./internal/aghos/\
|
||||
./internal/aghtest/ ./internal/stats/ ./internal/tools/\
|
||||
./internal/updater/ ./internal/version/ ./main.go
|
||||
|
||||
gosec --quiet $go_files
|
||||
|
||||
ineffassign ./...
|
||||
|
||||
unparam ./...
|
||||
@@ -222,6 +236,9 @@ nilness ./...
|
||||
|
||||
exit_on_output shadow --strict ./...
|
||||
|
||||
# TODO(a.garipov): Enable in v0.108.0.
|
||||
# gosec --quiet ./...
|
||||
|
||||
# TODO(a.garipov): Enable --blank?
|
||||
errcheck --asserts ./...
|
||||
|
||||
|
||||
@@ -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" ./...
|
||||
|
||||
Reference in New Issue
Block a user