Compare commits
5 Commits
release-v0
...
v0.106.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
caa90b0340 | ||
|
|
81a5225622 | ||
|
|
199e1f6a60 | ||
|
|
66d47b1462 | ||
|
|
e1ac2590c9 |
23
CHANGELOG.md
23
CHANGELOG.md
@@ -14,9 +14,21 @@ and this project adheres to
|
||||
-->
|
||||
|
||||
<!--
|
||||
## [v0.106.2] - 2021-05-17 (APPROX.)
|
||||
## [v0.106.3] - 2021-05-17 (APPROX.)
|
||||
-->
|
||||
|
||||
|
||||
|
||||
## [v0.106.2] - 2021-05-06
|
||||
|
||||
### Fixed
|
||||
|
||||
- Uniqueness validation for dynamic DHCP leases ([#3056]).
|
||||
|
||||
[#3056]: https://github.com/AdguardTeam/AdGuardHome/issues/3056
|
||||
|
||||
|
||||
|
||||
## [v0.106.1] - 2021-04-30
|
||||
|
||||
### Fixed
|
||||
@@ -334,12 +346,13 @@ and this project adheres to
|
||||
|
||||
|
||||
<!--
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.2...HEAD
|
||||
[v0.107.0]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.2...v0.107.0
|
||||
[v0.106.2]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.1...v0.106.2
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.3...HEAD
|
||||
[v0.107.0]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.3...v0.107.0
|
||||
[v0.106.3]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.2...v0.106.3
|
||||
-->
|
||||
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.1...HEAD
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.2...HEAD
|
||||
[v0.106.2]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.1...v0.106.2
|
||||
[v0.106.1]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.106.0...v0.106.1
|
||||
[v0.106.0]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.105.2...v0.106.0
|
||||
[v0.105.2]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.105.1...v0.105.2
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "Bootstrap DNS servery",
|
||||
"bootstrap_dns_desc": "Servery Bootstrap DNS se používají k řešení IP adres DoH/DoT, které zadáváte jako upstreamy.",
|
||||
"local_ptr_title": "Soukromé DNS servery",
|
||||
"local_ptr_desc": "Servery DNS, které AdGuard Home použije pro dotazy na lokálně poskytované zdroje. Tento server bude například používán k řešení názvů hostitelů pro klienty se soukromými IP adresami. Pokud není nastaveno, AdGuard Home automaticky použije váš výchozí překladač DNS.",
|
||||
"local_ptr_desc": "Servery DNS, které AdGuard Home používá pro lokální dotazy PTR. Tyto servery se používají k rozlišení názvů hostitelů klientů se soukromými adresami IP, například \"192.168.12.34\" pomocí rDNS. Pokud není nastaveno, AdGuard Home automaticky použije výchozí řešitele vašeho OS.",
|
||||
"local_ptr_placeholder": "Zadejte jednu adresu serveru na řádek",
|
||||
"resolve_clients_title": "Povolit zpětné řešení IP adres klientů",
|
||||
"resolve_clients_desc": "Pokud je povoleno, AdGuard Home se pokusí obráceně vyřešit IP adresy klientů na jejich názvy hostitelů zasláním dotazů PTR příslušným řešitelům (soukromé DNS servery pro místní klienty, odchozí server pro klienty s veřejnou IP adresou).",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "Bootstrap DNS-servere",
|
||||
"bootstrap_dns_desc": "Bootstrap DNS-servere bruges til at fortolke IP-adresser for de DoH-/DoT-resolvere, du angiver som upstream.",
|
||||
"local_ptr_title": "Private DNS-servere",
|
||||
"local_ptr_desc": "De DNS-servere som AdGuard Home vil bruge til forespørgsler efter lokalt leverede ressourcer. For eksempel vil denne server blive brugt til at løse klienters værtsnavne for klienter med private IP-adresser. Hvis ikke indstillet, bruger AdGuard Home automatisk din standard DNS-resolver.",
|
||||
"local_ptr_desc": "De DNS-servere, som AdGuard Home bruger til lokale PTR-forespørgsler. Disse servere bruges til at opløse klientværtsnavne med private IP-adresser, f.eks. \"192.168.12.34\", vha. rDNS. Hvis ikke indstillet, bruger AdGuard Home dit operativsystems standard DNS-opløsere.",
|
||||
"local_ptr_placeholder": "Indtast en serveradresse pr. Linje",
|
||||
"resolve_clients_title": "Aktivér omvendt løsning af klienters IP-adresser",
|
||||
"resolve_clients_desc": "Hvis aktiveret, forsøger AdGuard Home automatisk at løse klienters værtsnavne fra deres IP-adresser ved at sende en PTR-forespørgsel til en tilsvarende resolver (privat DNS-server til lokale klienter, upstream-server til klienter med offentlig IP-adresse).",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "Servidores DNS de arranque",
|
||||
"bootstrap_dns_desc": "Los servidores DNS de arranque se utilizan para resolver las direcciones IP de los resolutores DoH/DoT que especifiques como DNS de subida.",
|
||||
"local_ptr_title": "Servidores DNS privados",
|
||||
"local_ptr_desc": "Los servidores DNS que AdGuard Home utilizará para las consultas de recursos servidos localmente. Por ejemplo, este servidor se utilizará para resolver los nombres de hosts de los clientes con direcciones IP privadas. Si no está establecido, AdGuard Home utilizará automáticamente tu resolutor DNS predeterminado.",
|
||||
"local_ptr_desc": "Los servidores DNS que AdGuard Home utiliza para las consultas PTR locales. Estos servidores se utilizan para resolver los nombres de hosts de los clientes a direcciones IP privadas, por ejemplo \"192.168.12.34\", utilizando rDNS. Si no está establecido, AdGuard Home utilizará los resolutores DNS predeterminados de tu sistema operativo.",
|
||||
"local_ptr_placeholder": "Ingresa una dirección de servidor por línea",
|
||||
"resolve_clients_title": "Habilitar la resolución inversa de las direcciones IP de clientes",
|
||||
"resolve_clients_desc": "Si está habilitado, AdGuard Home intentará resolver de manera inversa las direcciones IP de los clientes a sus nombres de hosts enviando consultas PTR a los resolutores correspondientes (servidores DNS privados para clientes locales, servidor DNS de subida para clientes con direcciones IP públicas).",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "Server DNS bootstrap",
|
||||
"bootstrap_dns_desc": "Server Bootstrap DNS dapat digunakan untuk meresolve alamat IP pada DoH/DoT resolvers yang Anda tentukan sebagai upstreams.",
|
||||
"local_ptr_title": "Server DNS pribadi",
|
||||
"local_ptr_desc": "Server atau server DNS yang akan digunakan AdGuard Home untuk kueri sumber daya disajikan secara lokal. Misalnya, server ini akan digunakan untuk menyelesaikan hostname klien untuk klien dengan alamat IP pribadi. Jika tidak disetel, AdGuard Home akan secara otomatis menggunakan resolver DNS default Anda.",
|
||||
"local_ptr_desc": "Server DNS yang digunakan AdGuard Home untuk kueri PTR lokal. Server ini digunakan untuk menetapkan nama host klien bersama alamat IP pribadi, sebagai contoh \"192.168.12.34\", menggunakan rDNS. Jika tidka diatur, AdGuard Home akan menggunakan resolver DNS bawaan/default OS Anda.",
|
||||
"local_ptr_placeholder": "Masukkan satu alamat server per baris",
|
||||
"resolve_clients_title": "Aktifkan resolusi hostname klien",
|
||||
"resolve_clients_desc": "Jika diaktifkan, AdGuard Home akan mencoba menyelesaikan hostname klien secara otomatis dari alamat IP mereka dengan mengirimkan kueri PTR ke penyelesai yang sesuai (server DNS pribadi untuk klien lokal, server upstream untuk klien dengan IP publik).",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "부트스트랩 DNS 서버",
|
||||
"bootstrap_dns_desc": "부트스트랩 DNS 서버는 업스트림으로 지정한 DoH/DoT 서버의 IP 주소를 확인하는 데 사용합니다.",
|
||||
"local_ptr_title": "프라이빗 DNS 서버",
|
||||
"local_ptr_desc": "AdGuard Home이 로컬 리소스에 대한 쿼리에 사용할 DNS 서버입니다. 예를 들어, 사설 IP 주소가 있는 클라이언트의 호스트명을 확인할 때 사용합니다. 설정하지 않으면 기본으로 설정된 DNS 서버를 사용합니다.",
|
||||
"local_ptr_desc": "AdGuard Home이 로컬 PTR 쿼리에 사용하는 DNS 서버입니다. 이러한 서버는 rDNS를 사용하여 개인 IP 주소(예: '192.168.12.34')가 있는 클라이언트의 호스트 이름을 확인하는 데 사용됩니다. 설정되지 않은 경우, AdGuard Home은 OS의 기본 DNS 리졸버를 사용합니다.",
|
||||
"local_ptr_placeholder": "한 줄에 하나씩 서버 주소 입력",
|
||||
"resolve_clients_title": "클라이언트 IP 주소에 대한 호스트명 확인 활성화",
|
||||
"resolve_clients_desc": "활성화된 경우 AdGuard Home은 PTR 쿼리를 해당 서버(로컬 클라이언트의 경우 프라이빗 DNS 서버, 공용 IP 주소가 있는 클라이언트의 경우 업스트림 서버)로 전송하여 IP 주소로부터 클라이언트의 호스트명을 역으로 확인하려고 시도합니다.",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "Servidores DNS de inicialização",
|
||||
"bootstrap_dns_desc": "Servidores DNS de inicialização são usados para resolver endereços IP dos resolvedores DoH/DoT que você especifica como upstreams.",
|
||||
"local_ptr_title": "Servidores DNS privados",
|
||||
"local_ptr_desc": "Os servidores DNS que o AdGuard Home usará para consultas de recursos servidos localmente. Por exemplo, este servidor será usado para resolver nomes de host de clientes para clientes com endereços IP privados. Se não for definido, o AdGuard Home usará automaticamente seu resolvedor DNS padrão.",
|
||||
"local_ptr_desc": "Os servidores DNS que o AdGuard Home usa para consultas PTR locais. Esses servidores são usados para resolver os nomes de host de clientes com endereços IP privados, por exemplo \"192.168.12.34\", usando rDNS. Se não for definido, o AdGuard Home usa os resolvedores DNS padrão do seu sistema operacional.",
|
||||
"local_ptr_placeholder": "Insira um endereço de servidor por linha",
|
||||
"resolve_clients_title": "Ativar resolução reversa de endereços IP de clientes",
|
||||
"resolve_clients_desc": "Se ativado, o AdGuard Home tentará resolver de forma reversa os endereços IP dos clientes em seus nomes de host, enviando consultas PTR aos resolvedores correspondentes (servidores DNS privados para clientes locais, servidor DNS primário para clientes com endereços IP públicos).",
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
"bootstrap_dns": "Servidores DNS de arranque",
|
||||
"bootstrap_dns_desc": "Servidores DNS de inicialização são usados para resolver endereços IP dos resolvedores DoH/DoT que especifica como upstreams.",
|
||||
"local_ptr_title": "Servidores DNS privados",
|
||||
"local_ptr_desc": "Os servidores DNS que o AdGuard Home usará para consultas de recursos servidos localmente. Por exemplo, este servidor será usado para resolver nomes de host de clientes para clientes com endereços IP privados. Se não for definido, o AdGuard Home usará automaticamente seu resolvedor DNS padrão.",
|
||||
"local_ptr_desc": "Os servidores DNS que o AdGuard Home usa para consultas PTR locais. Esses servidores são usados para resolver os nomes de host de clientes com endereços IP privados, por exemplo \"192.168.12.34\", usando rDNS. Se não for definido, o AdGuard Home usa os resolvedores DNS padrão do seu sistema operacional.",
|
||||
"local_ptr_placeholder": "Insira um endereço de servidor por linha",
|
||||
"resolve_clients_title": "Activar resolução reversa de endereços IP de clientes",
|
||||
"resolve_clients_title": "Ativar resolução reversa de endereços IP de clientes",
|
||||
"resolve_clients_desc": "Se activado, o AdGuard Home tentará resolver de forma reversa os endereços IP dos clientes em seus nomes de host, enviando consultas PTR aos resolvedores correspondentes (servidores DNS privados para clientes locais, servidor DNS primário para clientes com endereços IP públicos).",
|
||||
"check_dhcp_servers": "Verificar por servidores DHCP",
|
||||
"save_config": "Guardar definição",
|
||||
@@ -21,10 +21,10 @@
|
||||
"unavailable_dhcp_desc": "O AdGuard Home não pode executar um servidor DHCP em seu sistema operacional",
|
||||
"dhcp_title": "Servidor DHCP (experimental)",
|
||||
"dhcp_description": "Se o seu router não fornecer configurações de DHCP, poderá usar o servidor DHCP integrado do AdGuard.",
|
||||
"dhcp_enable": "Activar servidor DHCP",
|
||||
"dhcp_disable": "Desactivar servidor DHCP",
|
||||
"dhcp_not_found": "É seguro activar o servidor DHCP integrado porque o AdGuard Home não encontrou nenhum servidor DHCP ativo na rede. No entanto, você deve verificar isso manualmente, pois a verificação automática atualmente não oferece 100% de garantia.",
|
||||
"dhcp_found": "Um servidor DHCP activo foi encontrado na rede. Não é seguro activar o servidor DHCP incorporado.",
|
||||
"dhcp_enable": "Ativar servidor DHCP",
|
||||
"dhcp_disable": "Desativar servidor DHCP",
|
||||
"dhcp_not_found": "É seguro ativar o servidor DHCP integrado porque o AdGuard Home não encontrou nenhum servidor DHCP ativo na rede. No entanto, você deve verificar isso manualmente, pois a verificação automática atualmente não oferece 100% de garantia.",
|
||||
"dhcp_found": "Um servidor DHCP ativo foi encontrado na rede. Não é seguro ativar o servidor DHCP incorporado.",
|
||||
"dhcp_leases": "Concessões DHCP",
|
||||
"dhcp_static_leases": "Concessões de DHCP estático",
|
||||
"dhcp_leases_not_found": "Nenhuma concessão DHCP encontrada",
|
||||
@@ -55,10 +55,10 @@
|
||||
"ip": "IP",
|
||||
"dhcp_table_hostname": "Nome do servidor",
|
||||
"dhcp_table_expires": "Expira",
|
||||
"dhcp_warning": "Se tu quiser activar o servidor DHCP de qualquer maneira, certifique-se de que não haja outro servidor DHCP activo em tua rede, pois isso pode quebrar a conectividade com a Internet para dispositivos na rede!",
|
||||
"dhcp_warning": "Se tu quiser ativar o servidor DHCP de qualquer maneira, certifique-se de que não haja outro servidor DHCP ativo em tua rede, pois isso pode quebrar a conectividade com a Internet para dispositivos na rede!",
|
||||
"dhcp_error": "O AdGuard Home não conseguiu determinar se há noutro servidor DHCP ativo na rede.",
|
||||
"dhcp_static_ip_error": "Para usar o servidor DHCP, deve definir um endereço IP estático. AdGuard Home não conseguiu determinar se essa interface de rede está configurada usando o endereço de IP estático. Por favor, defina um endereço IP estático manualmente.",
|
||||
"dhcp_dynamic_ip_found": "O seu sistema usa a configuração de endereço IP dinâmico para a interface <0>{{interfaceName}}</0>. Para usar o servidor DHCP, deve definir um endereço de IP estático. O seu endereço IP actual é <0> {{ipAddress}} </ 0>. AdGuard Home irá definir automaticamente este endereço IP como estático se pressionar o botão \"Activar servidor DHCP\".",
|
||||
"dhcp_dynamic_ip_found": "O seu sistema usa a configuração de endereço IP dinâmico para a interface <0>{{interfaceName}}</0>. Para usar o servidor DHCP, deve definir um endereço de IP estático. O seu endereço IP actual é <0> {{ipAddress}} </ 0>. AdGuard Home irá definir automaticamente este endereço IP como estático se pressionar o botão \"Ativar servidor DHCP\".",
|
||||
"dhcp_lease_added": "Concessão estática \"{{key}}\" adicionada com sucesso",
|
||||
"dhcp_lease_deleted": "Concessão estática \"{{key}}\" excluída com sucesso",
|
||||
"dhcp_new_static_lease": "Nova concessão estática",
|
||||
@@ -92,10 +92,10 @@
|
||||
"homepage": "Página inicial",
|
||||
"report_an_issue": "Comunicar um problema",
|
||||
"privacy_policy": "Política de Privacidade",
|
||||
"enable_protection": "Activar protecção",
|
||||
"enabled_protection": "Activar protecção",
|
||||
"disable_protection": "Desactivar protecção",
|
||||
"disabled_protection": "Desactivar protecção",
|
||||
"enable_protection": "Ativar protecção",
|
||||
"enabled_protection": "Ativar protecção",
|
||||
"disable_protection": "Desativar protecção",
|
||||
"disabled_protection": "Desativar protecção",
|
||||
"refresh_statics": "Repor estatísticas",
|
||||
"dns_query": "Consultas de DNS",
|
||||
"blocked_by": "<0>Bloqueado por filtros</0>",
|
||||
@@ -236,7 +236,7 @@
|
||||
"query_log_updated": "O registro da consulta foi actualizado com sucesso",
|
||||
"query_log_clear": "Limpar registos de consulta",
|
||||
"query_log_retention": "Retenção de registos de consulta",
|
||||
"query_log_enable": "Activar registo",
|
||||
"query_log_enable": "Ativar registo",
|
||||
"query_log_configuration": "Definições do registo",
|
||||
"query_log_disabled": "O registo de consulta está desactivado e pode ser configurado em <0>definições</0>",
|
||||
"query_log_strict_search": "Usar aspas duplas para uma pesquisa rigorosa",
|
||||
@@ -267,7 +267,7 @@
|
||||
"plain_dns": "DNS simples",
|
||||
"form_enter_rate_limit": "Insira o limite de taxa",
|
||||
"rate_limit": "Limite de taxa",
|
||||
"edns_enable": "Activar sub-rede do cliente EDNS",
|
||||
"edns_enable": "Ativar sub-rede do cliente EDNS",
|
||||
"edns_cs_desc": "Se activado, o AdGuard Home enviará sub-redes dos clientes para os servidores DNS.",
|
||||
"rate_limit_desc": "O número de solicitações por segundo permitido por cliente. Configurando para 0 significa sem limite.",
|
||||
"blocking_ipv4_desc": "Endereço IP a ser devolvido para uma solicitação A bloqueada",
|
||||
@@ -359,7 +359,7 @@
|
||||
"encryption_expire": "Expira",
|
||||
"encryption_key": "Chave privada",
|
||||
"encryption_key_input": "Copie/cole aqui a chave privada codificada em PEM para o seu certificado.",
|
||||
"encryption_enable": "Activar criptografia (HTTPS, DNS-sobre-HTTPS e DNS-sobre-TLS)",
|
||||
"encryption_enable": "Ativar criptografia (HTTPS, DNS-sobre-HTTPS e DNS-sobre-TLS)",
|
||||
"encryption_enable_desc": "Se a criptografia estiver activada, a interface administrativa do AdGuard Home funcionará em HTTPS, o servidor DNS irá capturar as solicitações por meio do DNS-sobre-HTTPS e DNS-sobre-TLS.",
|
||||
"encryption_chain_valid": "Cadeia de certificado válida",
|
||||
"encryption_chain_invalid": "A cadeia de certificado é inválida",
|
||||
@@ -495,7 +495,7 @@
|
||||
"interval_hours": "{{count}} hora",
|
||||
"interval_hours_plural": "{{count}} horas",
|
||||
"filters_configuration": "Definição dos filtros",
|
||||
"filters_enable": "Activar filtros",
|
||||
"filters_enable": "Ativar filtros",
|
||||
"filters_interval": "Intervalo de actualização de filtros",
|
||||
"disabled": "Desactivado",
|
||||
"username_label": "Nome do utilizador",
|
||||
@@ -523,12 +523,12 @@
|
||||
"rewrite_domain_name": "Nome de domínio: adicione um registro CNAME",
|
||||
"rewrite_A": "<0>A</0>: valor especial, mantenha <0>A</0> nos registros do upstream",
|
||||
"rewrite_AAAA": "<0>AAAA</0>: valor especial, mantenha <0>AAAA</0> nos registros do servidor DNS primário",
|
||||
"disable_ipv6": "Desactivar IPv6",
|
||||
"disable_ipv6": "Desativar IPv6",
|
||||
"disable_ipv6_desc": "Se este recurso estiver ativado, todas as consultas de DNS para endereços IPv6 (tipo AAAA) serão ignoradas.",
|
||||
"fastest_addr": "Endereço de IP mais rápido",
|
||||
"fastest_addr_desc": "Consulta todos os servidores DNS e retorna o endereço IP mais rápido entre todas as respostas. Isso torna as consultas DNS mais lentas, pois o AdGuard Home tem que esperar pelas respostas de todos os servidores DNS, mas melhora a conectividade geral.",
|
||||
"autofix_warning_text": "Se clicar em \"Corrigir\", o AdGuardHome irá configurar o seu sistema para utilizar o servidor DNS do AdGuardHome.",
|
||||
"autofix_warning_list": "Ele irá realizar estas tarefas: <0>Desactivar sistema DNSStubListener</0> <0>Definir endereço do servidor DNS para 127.0.0.1</0> <0>Substituir o alvo simbólico do link /etc/resolv.conf para /run/systemd/resolv.conf</0> <0>Parar DNSStubListener (recarregar serviço resolvido pelo sistema)</0>",
|
||||
"autofix_warning_list": "Irá realizar estas tarefas: <0>Desativar sistema DNSStubListener</0> <0>Definir endereço do servidor DNS para 127.0.0.1</0> <0>Substituir o alvo simbólico do link /etc/resolv.conf para /run/systemd/resolv.conf</0> <0>Parar DNSStubListener (recarregar serviço resolvido pelo sistema)</0>",
|
||||
"autofix_warning_result": "Como resultado, todos as solicitações DNS do seu sistema serão processadas pelo AdGuard Home por predefinição.",
|
||||
"tags_title": "Etiquetas",
|
||||
"tags_desc": "Tu podes seleccionar as etiquetas que correspondem ao cliente. As etiquetas podem ser incluídas nas regras de filtragem e permitir que tu as aplique com mais precisão. <0>Saiba mais</0>",
|
||||
@@ -560,7 +560,7 @@
|
||||
"confirm_static_ip": "O AdGuard Home irá configurar {{ip}} para ser seu endereço IP estático. Deseja continuar?",
|
||||
"list_updated": "{{count}} lista actualizada",
|
||||
"list_updated_plural": "{{count}} listas actualizadas",
|
||||
"dnssec_enable": "Activar DNSSEC",
|
||||
"dnssec_enable": "Ativar DNSSEC",
|
||||
"dnssec_enable_desc": "Definir a flag DNSSEC nas consultas de DNS em andamento e verificar o resultado (é necessário um resolvedor DNSSEC ativado)",
|
||||
"validated_with_dnssec": "Validado com DNSSEC",
|
||||
"all_queries": "Todas as consultas",
|
||||
@@ -594,7 +594,7 @@
|
||||
"filter_category_security_desc": "Listas especializadas em bloquear domínios de malware, phishing ou fraude",
|
||||
"filter_category_regional_desc": "Listas focadas em anúncios regionais e servidores de monitorização",
|
||||
"filter_category_other_desc": "Outras listas de bloqueio",
|
||||
"setup_config_to_enable_dhcp_server": "Defina a definição para activar o servidor DHCP",
|
||||
"setup_config_to_enable_dhcp_server": "Defina a configuração para ativar o servidor DHCP",
|
||||
"original_response": "Resposta original",
|
||||
"click_to_view_queries": "Clique para ver as consultas",
|
||||
"port_53_faq_link": "A porta 53 é frequentemente ocupada por serviços \"DNSStubListener\" ou \"systemd-resolved\". Por favor leia <0>essa instrução</0> para resolver isso.",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "Zagonski DNS strežniki",
|
||||
"bootstrap_dns_desc": "Zagonski DNS strežniki se uporabljajo za razreševanje IP naslovov DoH/DoT reševalcev, ki jih določite kot navzgornje.",
|
||||
"local_ptr_title": "Zasebni strežniki DNS",
|
||||
"local_ptr_desc": "Strežniki DNS, ki jih bo AdGuard Home uporabil za poizvedbe o lokalno oskrbovanih virih. Ta strežnik bo na primer uporabljen za razreševanje imen gostiteljev odjemalcev z zasebnimi naslovi IP. Če ni nastavljen, bo AdGuard Home samodejno uporabil vaš privzeti razreševalnik DNS.",
|
||||
"local_ptr_desc": "Strežniki DNS, ki jih AdGuard Home uporablja za lokalne poizvedbe PTR. Ti strežniki se uporabljajo za razreševanje imen gostiteljev z zasebnimi naslovi IP, na primer \"192.168.12.34\" uporablja rDNS. Če ni nastavljen, AdGuard Home uporablja privzete rešitve DNS vašega OS.",
|
||||
"local_ptr_placeholder": "V vrstico vnesite en naslov strežnika",
|
||||
"resolve_clients_title": "Omogoči obratno reševanje naslovov IP gostiteljev",
|
||||
"resolve_clients_desc": "Če je omogočeno, bo AdGuard Home poskušal samodejno razrešiti gostiteljska imena odjemalcev iz njihovih naslovov IP tako, da pošlje poizvedbo PTR ustreznemu razreševalniku (zasebni strežniki DNS za lokalne odjemalce, gorvodni strežnik za odjemalce z javnimi naslovi IP).",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "Bootstrap DNS 服务器",
|
||||
"bootstrap_dns_desc": "Bootstrap DNS 服务器用于解析您指定为上游的 DoH / DoT 解析器的 IP 地址。",
|
||||
"local_ptr_title": "私人 DNS 服务器",
|
||||
"local_ptr_desc": "AdGuard Home 用于查询本地服务资源的 DNS 服务器。例如,该服务器将被用作具有私人 IP 地址的客户机解析客户机的主机名。如果没有设置,AdGuard Home 将自动使用您的默认 DNS 解析器",
|
||||
"local_ptr_desc": "AdGuard Home 用于查询本地服务资源的 DNS 服务器。例如,该服务器将被用于解析具有私人 IP 地址的客户机的主机名,比如 \"192.168.12.34\"。如果没有设置,AdGuard Home 将自动使用您的默认 DNS 解析器。",
|
||||
"local_ptr_placeholder": "每行输入一个服务器地址",
|
||||
"resolve_clients_title": "启用客户端的 IP 地址的反向解析",
|
||||
"resolve_clients_desc": "如果启用,AdGuard Home 将尝试通过发送 PTR 查询到对应的解析器 (本地客户端的私人 DNS 服务器,公有 IP 客户端的上游服务器) 将 IP 地址反向解析成其客户端主机名。",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"bootstrap_dns": "自我啟動(Bootstrap)DNS 伺服器",
|
||||
"bootstrap_dns_desc": "自我啟動(Bootstrap)DNS 伺服器被用於解析您明確指定作為上游的 DoH/DoT 解析器之 IP 位址。",
|
||||
"local_ptr_title": "私人 DNS 伺服器",
|
||||
"local_ptr_desc": "AdGuard Home 將用於供在本地服務的資源的查詢之 DNS 伺服器。例如,此伺服器將被用於對於有私人 IP 位址的用戶端解析其主機名稱。如果未被設定,AdGuard Home 將自動地使用您的預設 DNS 解析器。",
|
||||
"local_ptr_desc": "AdGuard Home 用於區域指標(PTR)查詢之 DNS 伺服器。這些伺服器被用於解析含私人 IP 位址的用戶端之主機名稱,例如,\"192.168.12.34\",使用反向的 DNS(rDNS)。如果未被設定,AdGuard Home 使用您的作業系統之預設 DNS 解析器。",
|
||||
"local_ptr_placeholder": "每行輸入一個伺服器位址",
|
||||
"resolve_clients_title": "啟用用戶端的 IP 位址之反向的解析",
|
||||
"resolve_clients_desc": "如果被啟用,透過傳送指標(PTR)查詢到對應的解析器(私人 DNS 伺服器供區域的用戶端,上游的伺服器供有公共 IP 位址的用戶端),AdGuard Home 將試圖反向地解析用戶端的 IP 位址變為它們的主機名稱。",
|
||||
|
||||
@@ -27,6 +27,7 @@ const Form = (props) => {
|
||||
component={renderInputField}
|
||||
placeholder={t('username_placeholder')}
|
||||
autoComplete="username"
|
||||
autocapitalize="none"
|
||||
disabled={processing}
|
||||
validate={[validateRequiredValue]}
|
||||
/>
|
||||
|
||||
@@ -48,32 +48,32 @@ const maxDomainLabelLen = 63
|
||||
// See https://stackoverflow.com/a/32294443/1892060.
|
||||
const maxDomainNameLen = 253
|
||||
|
||||
const invalidCharMsg = "invalid char %q at index %d in %q"
|
||||
|
||||
// ValidateDomainNameLabel returns an error if label is not a valid label of
|
||||
// a domain name.
|
||||
func ValidateDomainNameLabel(label string) (err error) {
|
||||
defer agherr.Annotate("validating label %q: %w", &err, label)
|
||||
|
||||
l := len(label)
|
||||
if l > maxDomainLabelLen {
|
||||
return fmt.Errorf("%q is too long, max: %d", label, maxDomainLabelLen)
|
||||
return fmt.Errorf("label is too long, max: %d", maxDomainLabelLen)
|
||||
} else if l == 0 {
|
||||
return agherr.Error("label is empty")
|
||||
}
|
||||
|
||||
if r := label[0]; !IsValidHostOuterRune(rune(r)) {
|
||||
return fmt.Errorf(invalidCharMsg, r, 0, label)
|
||||
return fmt.Errorf("invalid char %q at index %d", r, 0)
|
||||
} else if l == 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for i, r := range label[1 : l-1] {
|
||||
if !isValidHostRune(r) {
|
||||
return fmt.Errorf(invalidCharMsg, r, i+1, label)
|
||||
return fmt.Errorf("invalid char %q at index %d", r, i+1)
|
||||
}
|
||||
}
|
||||
|
||||
if r := label[l-1]; !IsValidHostOuterRune(rune(r)) {
|
||||
return fmt.Errorf(invalidCharMsg, r, l-1, label)
|
||||
return fmt.Errorf("invalid char %q at index %d", r, l-1)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -87,6 +87,8 @@ func ValidateDomainNameLabel(label string) (err error) {
|
||||
// TODO(a.garipov): After making sure that this works correctly, port this into
|
||||
// module golibs.
|
||||
func ValidateDomainName(name string) (err error) {
|
||||
defer agherr.Annotate("validating domain name %q: %w", &err, name)
|
||||
|
||||
name, err = idna.ToASCII(name)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -96,7 +98,7 @@ func ValidateDomainName(name string) (err error) {
|
||||
if l == 0 {
|
||||
return agherr.Error("domain name is empty")
|
||||
} else if l > maxDomainNameLen {
|
||||
return fmt.Errorf("%q is too long, max: %d", name, maxDomainNameLen)
|
||||
return fmt.Errorf("too long, max: %d", maxDomainNameLen)
|
||||
}
|
||||
|
||||
labels := strings.Split(name, ".")
|
||||
|
||||
@@ -95,40 +95,46 @@ func TestValidateDomainName(t *testing.T) {
|
||||
}, {
|
||||
name: "empty",
|
||||
in: "",
|
||||
wantErrMsg: `domain name is empty`,
|
||||
wantErrMsg: `validating domain name "": domain name is empty`,
|
||||
}, {
|
||||
name: "bad_symbol",
|
||||
in: "!!!",
|
||||
wantErrMsg: `invalid domain name label at index 0: ` +
|
||||
`invalid char '!' at index 0 in "!!!"`,
|
||||
wantErrMsg: `validating domain name "!!!": invalid domain name label at index 0: ` +
|
||||
`validating label "!!!": invalid char '!' at index 0`,
|
||||
}, {
|
||||
name: "bad_length",
|
||||
in: longDomainName,
|
||||
wantErrMsg: `"` + longDomainName + `" is too long, max: 253`,
|
||||
wantErrMsg: `validating domain name "` + longDomainName + `": too long, max: 253`,
|
||||
}, {
|
||||
name: "bad_label_length",
|
||||
in: longLabelDomainName,
|
||||
wantErrMsg: `invalid domain name label at index 0: "` + longLabel +
|
||||
`" is too long, max: 63`,
|
||||
wantErrMsg: `validating domain name "` + longLabelDomainName + `": ` +
|
||||
`invalid domain name label at index 0: validating label "` + longLabel +
|
||||
`": label is too long, max: 63`,
|
||||
}, {
|
||||
name: "bad_label_empty",
|
||||
in: "example..com",
|
||||
wantErrMsg: `invalid domain name label at index 1: label is empty`,
|
||||
name: "bad_label_empty",
|
||||
in: "example..com",
|
||||
wantErrMsg: `validating domain name "example..com": ` +
|
||||
`invalid domain name label at index 1: ` +
|
||||
`validating label "": label is empty`,
|
||||
}, {
|
||||
name: "bad_label_first_symbol",
|
||||
in: "example.-aa.com",
|
||||
wantErrMsg: `invalid domain name label at index 1:` +
|
||||
` invalid char '-' at index 0 in "-aa"`,
|
||||
wantErrMsg: `validating domain name "example.-aa.com": ` +
|
||||
`invalid domain name label at index 1: ` +
|
||||
`validating label "-aa": invalid char '-' at index 0`,
|
||||
}, {
|
||||
name: "bad_label_last_symbol",
|
||||
in: "example-.aa.com",
|
||||
wantErrMsg: `invalid domain name label at index 0:` +
|
||||
` invalid char '-' at index 7 in "example-"`,
|
||||
wantErrMsg: `validating domain name "example-.aa.com": ` +
|
||||
`invalid domain name label at index 0: ` +
|
||||
`validating label "example-": invalid char '-' at index 7`,
|
||||
}, {
|
||||
name: "bad_label_symbol",
|
||||
in: "example.a!!!.com",
|
||||
wantErrMsg: `invalid domain name label at index 1:` +
|
||||
` invalid char '!' at index 1 in "a!!!"`,
|
||||
wantErrMsg: `validating domain name "example.a!!!.com": ` +
|
||||
`invalid domain name label at index 1: ` +
|
||||
`validating label "a!!!": invalid char '!' at index 1`,
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
|
||||
@@ -27,13 +27,13 @@ var webHandlersRegistered = false
|
||||
|
||||
// Lease contains the necessary information about a DHCP lease
|
||||
type Lease struct {
|
||||
// Expiry is the expiration time of the lease. The unix timestamp value
|
||||
// of 1 means that this is a static lease.
|
||||
Expiry time.Time `json:"expires"`
|
||||
|
||||
Hostname string `json:"hostname"`
|
||||
HWAddr net.HardwareAddr `json:"mac"`
|
||||
IP net.IP `json:"ip"`
|
||||
Hostname string `json:"hostname"`
|
||||
|
||||
// Lease expiration time
|
||||
// 1: static lease
|
||||
Expiry time.Time `json:"expires"`
|
||||
}
|
||||
|
||||
// IsStatic returns true if the lease is static.
|
||||
|
||||
@@ -37,30 +37,34 @@ func TestDB(t *testing.T) {
|
||||
SubnetMask: net.IP{255, 255, 255, 0},
|
||||
notify: testNotify,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
s.srv6, err = v6Create(V6ServerConf{})
|
||||
require.Nil(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
leases := []Lease{{
|
||||
IP: net.IP{192, 168, 10, 100},
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
Expiry: time.Now().Add(time.Hour),
|
||||
Expiry: time.Now().Add(time.Hour),
|
||||
Hostname: "static-1.local",
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
IP: net.IP{192, 168, 10, 100},
|
||||
}, {
|
||||
IP: net.IP{192, 168, 10, 101},
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xBB},
|
||||
Hostname: "static-2.local",
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xBB},
|
||||
IP: net.IP{192, 168, 10, 101},
|
||||
}}
|
||||
|
||||
srv4, ok := s.srv4.(*v4Server)
|
||||
require.True(t, ok)
|
||||
|
||||
err = srv4.addLease(&leases[0])
|
||||
require.Nil(t, err)
|
||||
require.Nil(t, s.srv4.AddStaticLease(leases[1]))
|
||||
require.NoError(t, err)
|
||||
|
||||
err = s.srv4.AddStaticLease(leases[1])
|
||||
require.NoError(t, err)
|
||||
|
||||
s.dbStore()
|
||||
t.Cleanup(func() {
|
||||
assert.Nil(t, os.Remove(dbFilename))
|
||||
assert.NoError(t, os.Remove(dbFilename))
|
||||
})
|
||||
s.srv4.ResetLeases(nil)
|
||||
s.dbLoad()
|
||||
|
||||
@@ -36,7 +36,7 @@ type v4Server struct {
|
||||
// leases contains all dynamic and static leases.
|
||||
leases []*Lease
|
||||
|
||||
// leasesLock protects leases and leasedOffsets.
|
||||
// leasesLock protects leases, leaseHosts, and leasedOffsets.
|
||||
leasesLock sync.Mutex
|
||||
}
|
||||
|
||||
@@ -49,6 +49,68 @@ func (s *v4Server) WriteDiskConfig4(c *V4ServerConf) {
|
||||
func (s *v4Server) WriteDiskConfig6(c *V6ServerConf) {
|
||||
}
|
||||
|
||||
// normalizeHostname normalizes a hostname sent by the client. If err is not
|
||||
// nil, norm is an empty string.
|
||||
func normalizeHostname(hostname string) (norm string, err error) {
|
||||
defer agherr.Annotate("normalizing %q: %w", &err, hostname)
|
||||
|
||||
if hostname == "" {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
norm = strings.ToLower(hostname)
|
||||
parts := strings.FieldsFunc(norm, func(c rune) (ok bool) {
|
||||
return c != '.' && !aghnet.IsValidHostOuterRune(c)
|
||||
})
|
||||
|
||||
if len(parts) == 0 {
|
||||
return "", fmt.Errorf("no valid parts")
|
||||
}
|
||||
|
||||
norm = strings.Join(parts, "-")
|
||||
norm = strings.TrimSuffix(norm, "-")
|
||||
|
||||
return norm, nil
|
||||
}
|
||||
|
||||
// validHostnameForClient accepts the hostname sent by the client and returns
|
||||
// either a normalized version of that hostname or a new hostname generated from
|
||||
// the client's IP address. If this new hostname is different from the provided
|
||||
// previous hostname, additional uniqueness check is performed.
|
||||
//
|
||||
// hostname is always a non-empty valid hostname. If err is not nil, it
|
||||
// describes the issues encountered when normalizing cliHostname.
|
||||
func (s *v4Server) validHostnameForClient(
|
||||
cliHostname string,
|
||||
prevHostname string,
|
||||
ip net.IP,
|
||||
) (hostname string, err error) {
|
||||
hostname, err = normalizeHostname(cliHostname)
|
||||
if err == nil && hostname != "" {
|
||||
err = aghnet.ValidateDomainName(hostname)
|
||||
if err != nil {
|
||||
// Go on and assign a hostname made from the IP below,
|
||||
// returning the error that we've got.
|
||||
hostname = ""
|
||||
} else if hostname != prevHostname && s.leaseHosts.Has(hostname) {
|
||||
// Go on and assign a unique hostname made from the IP
|
||||
// below, returning the error about uniqueness.
|
||||
err = agherr.Error("hostname exists")
|
||||
hostname = ""
|
||||
}
|
||||
}
|
||||
|
||||
if hostname == "" {
|
||||
hostname = aghnet.GenerateHostname(ip)
|
||||
}
|
||||
|
||||
if hostname != cliHostname {
|
||||
log.Info("dhcpv4: normalized hostname %q into %q", cliHostname, hostname)
|
||||
}
|
||||
|
||||
return hostname, err
|
||||
}
|
||||
|
||||
// ResetLeases - reset leases
|
||||
func (s *v4Server) ResetLeases(leases []*Lease) {
|
||||
var err error
|
||||
@@ -62,9 +124,13 @@ func (s *v4Server) ResetLeases(leases []*Lease) {
|
||||
s.leases = nil
|
||||
|
||||
for _, l := range leases {
|
||||
l.Hostname, err = s.validHostnameForClient(l.Hostname, l.IP)
|
||||
l.Hostname, err = s.validHostnameForClient(l.Hostname, l.Hostname, l.IP)
|
||||
if err != nil {
|
||||
log.Info("dhcpv4: warning: previous hostname %q is invalid: %s", l.Hostname, err)
|
||||
log.Info(
|
||||
"dhcpv4: warning: previous hostname %q is invalid: %s",
|
||||
l.Hostname,
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
err = s.addLease(l)
|
||||
@@ -204,7 +270,7 @@ func (s *v4Server) rmDynamicLease(lease *Lease) (err error) {
|
||||
|
||||
if bytes.Equal(l.HWAddr, lease.HWAddr) {
|
||||
if l.IsStatic() {
|
||||
return fmt.Errorf("static lease already exists")
|
||||
return agherr.Error("static lease already exists")
|
||||
}
|
||||
|
||||
s.rmLeaseByIndex(i)
|
||||
@@ -215,9 +281,9 @@ func (s *v4Server) rmDynamicLease(lease *Lease) (err error) {
|
||||
l = s.leases[i]
|
||||
}
|
||||
|
||||
if net.IP.Equal(l.IP, lease.IP) {
|
||||
if l.IP.Equal(lease.IP) {
|
||||
if l.IsStatic() {
|
||||
return fmt.Errorf("static lease already exists")
|
||||
return agherr.Error("static lease already exists")
|
||||
}
|
||||
|
||||
s.rmLeaseByIndex(i)
|
||||
@@ -227,54 +293,31 @@ func (s *v4Server) rmDynamicLease(lease *Lease) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *v4Server) addStaticLease(l *Lease) (err error) {
|
||||
if sn := s.conf.subnet; !sn.Contains(l.IP) {
|
||||
return fmt.Errorf("subnet %s does not contain the ip %q", sn, l.IP)
|
||||
}
|
||||
|
||||
s.leases = append(s.leases, l)
|
||||
|
||||
// addLease adds a dynamic or static lease.
|
||||
func (s *v4Server) addLease(l *Lease) (err error) {
|
||||
r := s.conf.ipRange
|
||||
offset, ok := r.offset(l.IP)
|
||||
if ok {
|
||||
s.leasedOffsets.set(offset, true)
|
||||
}
|
||||
offset, inOffset := r.offset(l.IP)
|
||||
|
||||
s.leaseHosts.Add(l.Hostname)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *v4Server) addDynamicLease(l *Lease) (err error) {
|
||||
r := s.conf.ipRange
|
||||
offset, ok := r.offset(l.IP)
|
||||
if !ok {
|
||||
if l.IsStatic() {
|
||||
if sn := s.conf.subnet; !sn.Contains(l.IP) {
|
||||
return fmt.Errorf("subnet %s does not contain the ip %q", sn, l.IP)
|
||||
}
|
||||
} else if !inOffset {
|
||||
return fmt.Errorf("lease %s (%s) out of range, not adding", l.IP, l.HWAddr)
|
||||
}
|
||||
|
||||
s.leases = append(s.leases, l)
|
||||
s.leaseHosts.Add(l.Hostname)
|
||||
s.leasedOffsets.set(offset, true)
|
||||
|
||||
if l.Hostname != "" {
|
||||
s.leaseHosts.Add(l.Hostname)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// addLease adds a dynamic or static lease.
|
||||
func (s *v4Server) addLease(l *Lease) (err error) {
|
||||
err = s.validateLease(l)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if l.IsStatic() {
|
||||
return s.addStaticLease(l)
|
||||
}
|
||||
|
||||
return s.addDynamicLease(l)
|
||||
}
|
||||
|
||||
// Remove a lease with the same properties
|
||||
func (s *v4Server) rmLease(lease Lease) error {
|
||||
// rmLease removes a lease with the same properties.
|
||||
func (s *v4Server) rmLease(lease Lease) (err error) {
|
||||
if len(s.leases) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -296,7 +339,7 @@ func (s *v4Server) rmLease(lease Lease) error {
|
||||
|
||||
// AddStaticLease adds a static lease. It is safe for concurrent use.
|
||||
func (s *v4Server) AddStaticLease(l Lease) (err error) {
|
||||
defer agherr.Annotate("dhcpv4: %w", &err)
|
||||
defer agherr.Annotate("dhcpv4: adding static lease: %w", &err)
|
||||
|
||||
if ip4 := l.IP.To4(); ip4 == nil {
|
||||
return fmt.Errorf("invalid ip %q, only ipv4 is supported", l.IP)
|
||||
@@ -304,11 +347,28 @@ func (s *v4Server) AddStaticLease(l Lease) (err error) {
|
||||
|
||||
l.Expiry = time.Unix(leaseExpireStatic, 0)
|
||||
|
||||
l.Hostname, err = normalizeHostname(l.Hostname)
|
||||
err = aghnet.ValidateHardwareAddress(l.HWAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var hostname string
|
||||
hostname, err = normalizeHostname(l.Hostname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = aghnet.ValidateDomainName(hostname)
|
||||
if err != nil {
|
||||
return fmt.Errorf("validating hostname: %w", err)
|
||||
}
|
||||
|
||||
if s.leaseHosts.Has(hostname) {
|
||||
return agherr.Error("hostname exists")
|
||||
}
|
||||
|
||||
l.Hostname = hostname
|
||||
|
||||
// Perform the following actions in an anonymous function to make sure
|
||||
// that the lock gets unlocked before the notification step.
|
||||
func() {
|
||||
@@ -372,16 +432,19 @@ func (s *v4Server) RemoveStaticLease(l Lease) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Send ICMP to the specified machine
|
||||
// Return TRUE if it doesn't reply, which probably means that the IP is available
|
||||
func (s *v4Server) addrAvailable(target net.IP) bool {
|
||||
// addrAvailable sends an ICP request to the specified IP address. It returns
|
||||
// true if the remote host doesn't reply, which probably means that the IP
|
||||
// address is available.
|
||||
//
|
||||
// TODO(a.garipov): I'm not sure that this is the best way to do this.
|
||||
func (s *v4Server) addrAvailable(target net.IP) (avail bool) {
|
||||
if s.conf.ICMPTimeout == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
pinger, err := ping.NewPinger(target.String())
|
||||
if err != nil {
|
||||
log.Error("ping.NewPinger(): %v", err)
|
||||
log.Error("dhcpv4: ping.NewPinger(): %s", err)
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -393,20 +456,24 @@ func (s *v4Server) addrAvailable(target net.IP) bool {
|
||||
pinger.OnRecv = func(_ *ping.Packet) {
|
||||
reply = true
|
||||
}
|
||||
log.Debug("dhcpv4: Sending ICMP Echo to %v", target)
|
||||
|
||||
log.Debug("dhcpv4: sending icmp echo to %s", target)
|
||||
|
||||
err = pinger.Run()
|
||||
if err != nil {
|
||||
log.Error("pinger.Run(): %v", err)
|
||||
log.Error("dhcpv4: pinger.Run(): %s", err)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
if reply {
|
||||
log.Info("dhcpv4: IP conflict: %v is already used by another device", target)
|
||||
log.Info("dhcpv4: ip conflict: %s is already used by another device", target)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
log.Debug("dhcpv4: ICMP procedure is complete: %v", target)
|
||||
log.Debug("dhcpv4: icmp procedure is complete: %q", target)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -481,58 +548,69 @@ func (s *v4Server) reserveLease(mac net.HardwareAddr) (l *Lease, err error) {
|
||||
func (s *v4Server) commitLease(l *Lease) {
|
||||
l.Expiry = time.Now().Add(s.conf.leaseTime)
|
||||
|
||||
s.leasesLock.Lock()
|
||||
s.conf.notify(LeaseChangedDBStore)
|
||||
s.leasesLock.Unlock()
|
||||
func() {
|
||||
s.leasesLock.Lock()
|
||||
defer s.leasesLock.Unlock()
|
||||
|
||||
s.conf.notify(LeaseChangedDBStore)
|
||||
s.leaseHosts.Add(l.Hostname)
|
||||
}()
|
||||
|
||||
s.conf.notify(LeaseChangedAdded)
|
||||
}
|
||||
|
||||
// Process Discover request and return lease
|
||||
// processDiscover is the handler for the DHCP Discover request.
|
||||
func (s *v4Server) processDiscover(req, resp *dhcpv4.DHCPv4) (l *Lease, err error) {
|
||||
mac := req.ClientHWAddr
|
||||
|
||||
err = aghnet.ValidateHardwareAddress(mac)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.leasesLock.Lock()
|
||||
defer s.leasesLock.Unlock()
|
||||
|
||||
// TODO(a.garipov): Refactor this mess.
|
||||
l = s.findLease(mac)
|
||||
if l == nil {
|
||||
toStore := false
|
||||
for l == nil {
|
||||
l, err = s.reserveLease(mac)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reserving a lease: %w", err)
|
||||
}
|
||||
|
||||
if l == nil {
|
||||
log.Debug("dhcpv4: no more ip addresses")
|
||||
if toStore {
|
||||
s.conf.notify(LeaseChangedDBStore)
|
||||
}
|
||||
|
||||
// TODO(a.garipov): Return a special error?
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
toStore = true
|
||||
|
||||
if !s.addrAvailable(l.IP) {
|
||||
s.blocklistLease(l)
|
||||
l = nil
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
s.conf.notify(LeaseChangedDBStore)
|
||||
} else {
|
||||
if l != nil {
|
||||
reqIP := req.RequestedIPAddress()
|
||||
if len(reqIP) != 0 && !reqIP.Equal(l.IP) {
|
||||
log.Debug("dhcpv4: different RequestedIP: %s != %s", reqIP, l.IP)
|
||||
}
|
||||
|
||||
resp.UpdateOption(dhcpv4.OptMessageType(dhcpv4.MessageTypeOffer))
|
||||
|
||||
return l, nil
|
||||
}
|
||||
|
||||
needsUpdate := false
|
||||
defer func() {
|
||||
if needsUpdate {
|
||||
s.conf.notify(LeaseChangedDBStore)
|
||||
}
|
||||
}()
|
||||
|
||||
leaseReady := false
|
||||
for !leaseReady {
|
||||
l, err = s.reserveLease(mac)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("reserving a lease: %w", err)
|
||||
}
|
||||
|
||||
if l == nil {
|
||||
log.Debug("dhcpv4: no more ip addresses")
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
needsUpdate = true
|
||||
|
||||
if s.addrAvailable(l.IP) {
|
||||
leaseReady = true
|
||||
} else {
|
||||
s.blocklistLease(l)
|
||||
l = nil
|
||||
}
|
||||
}
|
||||
|
||||
resp.UpdateOption(dhcpv4.OptMessageType(dhcpv4.MessageTypeOffer))
|
||||
@@ -569,115 +647,14 @@ func (o *optFQDN) ToBytes() []byte {
|
||||
return b
|
||||
}
|
||||
|
||||
// normalizeHostname normalizes a hostname sent by the client. If err is not
|
||||
// nil, norm is an empty string.
|
||||
func normalizeHostname(name string) (norm string, err error) {
|
||||
if name == "" {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
norm = strings.ToLower(name)
|
||||
parts := strings.FieldsFunc(norm, func(c rune) (ok bool) {
|
||||
return c != '.' && !aghnet.IsValidHostOuterRune(c)
|
||||
})
|
||||
|
||||
if len(parts) == 0 {
|
||||
return "", fmt.Errorf("normalizing hostname %q: no valid parts", name)
|
||||
}
|
||||
|
||||
norm = strings.Join(parts, "-")
|
||||
norm = strings.TrimSuffix(norm, "-")
|
||||
|
||||
return norm, nil
|
||||
}
|
||||
|
||||
// validateHostname validates a hostname sent by the client.
|
||||
func (s *v4Server) validateHostname(name string) (err error) {
|
||||
defer agherr.Annotate("validating hostname: %s", &err)
|
||||
|
||||
if name == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
err = aghnet.ValidateDomainName(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if s.leaseHosts.Has(name) {
|
||||
return agherr.Error("hostname exists")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// validHostnameForClient accepts the hostname sent by the client and returns
|
||||
// either a normalized version of that hostname or a new hostname generated from
|
||||
// the client's IP address.
|
||||
//
|
||||
// hostname is always a non-empty valid hostname. If err is not nil, it
|
||||
// describes the issues encountered when normalizing cliHostname.
|
||||
func (s *v4Server) validHostnameForClient(
|
||||
cliHostname string,
|
||||
ip net.IP,
|
||||
) (hostname string, err error) {
|
||||
hostname, err = normalizeHostname(cliHostname)
|
||||
if err == nil {
|
||||
err = s.validateHostname(hostname)
|
||||
if err != nil {
|
||||
// Go on and assign a hostname made from the IP below,
|
||||
// returning the error that we've got.
|
||||
hostname = ""
|
||||
}
|
||||
}
|
||||
|
||||
if hostname == "" {
|
||||
hostname = aghnet.GenerateHostname(ip)
|
||||
}
|
||||
|
||||
if hostname != cliHostname {
|
||||
log.Info("dhcpv4: normalized hostname %q into %q", cliHostname, hostname)
|
||||
}
|
||||
|
||||
return hostname, err
|
||||
}
|
||||
|
||||
// validateLease returns an error if the lease is invalid.
|
||||
func (s *v4Server) validateLease(l *Lease) (err error) {
|
||||
defer agherr.Annotate("validating lease: %s", &err)
|
||||
|
||||
if l == nil {
|
||||
return agherr.Error("lease is nil")
|
||||
}
|
||||
|
||||
err = aghnet.ValidateHardwareAddress(l.HWAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.validateHostname(l.Hostname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if sn := s.conf.subnet; !sn.Contains(l.IP) {
|
||||
return fmt.Errorf("subnet %s does not contain the ip %q", sn, l.IP)
|
||||
}
|
||||
|
||||
r := s.conf.ipRange
|
||||
if !l.IsStatic() && !r.contains(l.IP) {
|
||||
return fmt.Errorf("dynamic lease range %s does not contain the ip %q", r, l.IP)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Process Request request and return lease
|
||||
// Return false if we don't need to reply
|
||||
func (s *v4Server) processRequest(req, resp *dhcpv4.DHCPv4) (lease *Lease, ok bool) {
|
||||
var err error
|
||||
|
||||
// processDiscover is the handler for the DHCP Request request.
|
||||
func (s *v4Server) processRequest(req, resp *dhcpv4.DHCPv4) (lease *Lease, needsReply bool) {
|
||||
mac := req.ClientHWAddr
|
||||
err := aghnet.ValidateHardwareAddress(mac)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
reqIP := req.RequestedIPAddress()
|
||||
if reqIP == nil {
|
||||
reqIP = req.ClientIPAddr
|
||||
@@ -696,34 +673,49 @@ func (s *v4Server) processRequest(req, resp *dhcpv4.DHCPv4) (lease *Lease, ok bo
|
||||
return nil, false
|
||||
}
|
||||
|
||||
s.leasesLock.Lock()
|
||||
for _, l := range s.leases {
|
||||
if bytes.Equal(l.HWAddr, mac) {
|
||||
if !l.IP.Equal(reqIP) {
|
||||
s.leasesLock.Unlock()
|
||||
log.Debug("dhcpv4: mismatched OptionRequestedIPAddress in request message for %s", mac)
|
||||
mismatch := false
|
||||
func() {
|
||||
s.leasesLock.Lock()
|
||||
defer s.leasesLock.Unlock()
|
||||
|
||||
return nil, true
|
||||
for _, l := range s.leases {
|
||||
if !bytes.Equal(l.HWAddr, mac) {
|
||||
continue
|
||||
}
|
||||
|
||||
lease = l
|
||||
if l.IP.Equal(reqIP) {
|
||||
lease = l
|
||||
} else {
|
||||
log.Debug(
|
||||
`dhcpv4: mismatched OptionRequestedIPAddress `+
|
||||
`in request message for %s`,
|
||||
mac,
|
||||
)
|
||||
mismatch = true
|
||||
}
|
||||
|
||||
break
|
||||
return
|
||||
}
|
||||
}()
|
||||
if mismatch {
|
||||
return nil, true
|
||||
}
|
||||
s.leasesLock.Unlock()
|
||||
|
||||
if lease == nil {
|
||||
log.Debug("dhcpv4: no lease for %s", mac)
|
||||
log.Debug("dhcpv4: no reserved lease for %s", mac)
|
||||
|
||||
return nil, true
|
||||
}
|
||||
|
||||
if !lease.IsStatic() {
|
||||
cliHostname := req.HostName()
|
||||
lease.Hostname, err = s.validHostnameForClient(cliHostname, reqIP)
|
||||
lease.Hostname, err = s.validHostnameForClient(cliHostname, lease.Hostname, reqIP)
|
||||
if err != nil {
|
||||
log.Info("dhcpv4: warning: client hostname %q is invalid: %s", cliHostname, err)
|
||||
log.Info(
|
||||
"dhcpv4: warning: client hostname %q is invalid: %s",
|
||||
cliHostname,
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
s.commitLease(lease)
|
||||
|
||||
@@ -30,8 +30,9 @@ func TestV4_AddRemove_static(t *testing.T) {
|
||||
|
||||
// Add static lease.
|
||||
l := Lease{
|
||||
IP: net.IP{192, 168, 10, 150},
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
Hostname: "static-1.local",
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
IP: net.IP{192, 168, 10, 150},
|
||||
}
|
||||
|
||||
err = s.AddStaticLease(l)
|
||||
@@ -76,11 +77,13 @@ func TestV4_AddReplace(t *testing.T) {
|
||||
require.True(t, ok)
|
||||
|
||||
dynLeases := []Lease{{
|
||||
IP: net.IP{192, 168, 10, 150},
|
||||
HWAddr: net.HardwareAddr{0x11, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
Hostname: "dynamic-1.local",
|
||||
HWAddr: net.HardwareAddr{0x11, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
IP: net.IP{192, 168, 10, 150},
|
||||
}, {
|
||||
IP: net.IP{192, 168, 10, 151},
|
||||
HWAddr: net.HardwareAddr{0x22, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
Hostname: "dynamic-2.local",
|
||||
HWAddr: net.HardwareAddr{0x22, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
IP: net.IP{192, 168, 10, 151},
|
||||
}}
|
||||
|
||||
for i := range dynLeases {
|
||||
@@ -89,11 +92,13 @@ func TestV4_AddReplace(t *testing.T) {
|
||||
}
|
||||
|
||||
stLeases := []Lease{{
|
||||
IP: net.IP{192, 168, 10, 150},
|
||||
HWAddr: net.HardwareAddr{0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
Hostname: "static-1.local",
|
||||
HWAddr: net.HardwareAddr{0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
IP: net.IP{192, 168, 10, 150},
|
||||
}, {
|
||||
IP: net.IP{192, 168, 10, 152},
|
||||
HWAddr: net.HardwareAddr{0x22, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
Hostname: "static-2.local",
|
||||
HWAddr: net.HardwareAddr{0x22, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
IP: net.IP{192, 168, 10, 152},
|
||||
}}
|
||||
|
||||
for _, l := range stLeases {
|
||||
@@ -129,8 +134,9 @@ func TestV4StaticLease_Get(t *testing.T) {
|
||||
s.conf.dnsIPAddrs = []net.IP{{192, 168, 10, 1}}
|
||||
|
||||
l := Lease{
|
||||
IP: net.IP{192, 168, 10, 150},
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
Hostname: "static-1.local",
|
||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||
IP: net.IP{192, 168, 10, 150},
|
||||
}
|
||||
err = s.AddStaticLease(l)
|
||||
require.NoError(t, err)
|
||||
@@ -269,7 +275,12 @@ func TestV4DynamicLease_Get(t *testing.T) {
|
||||
assert.Equal(t, dhcpv4.MessageTypeAck, resp.MessageType())
|
||||
assert.Equal(t, mac, resp.ClientHWAddr)
|
||||
assert.True(t, s.conf.RangeStart.Equal(resp.YourIPAddr))
|
||||
assert.True(t, s.conf.GatewayIP.Equal(resp.Router()[0]))
|
||||
|
||||
router := resp.Router()
|
||||
require.Len(t, router, 1)
|
||||
|
||||
assert.Equal(t, s.conf.GatewayIP, router[0])
|
||||
|
||||
assert.True(t, s.conf.GatewayIP.Equal(resp.ServerIdentifier()))
|
||||
assert.Equal(t, s.conf.subnet.Mask, resp.SubnetMask())
|
||||
assert.Equal(t, s.conf.leaseTime.Seconds(), resp.IPAddressLeaseTime(-1).Seconds())
|
||||
@@ -329,12 +340,12 @@ func TestNormalizeHostname(t *testing.T) {
|
||||
}, {
|
||||
name: "error",
|
||||
hostname: "!!!",
|
||||
wantErrMsg: `normalizing hostname "!!!": no valid parts`,
|
||||
wantErrMsg: `normalizing "!!!": no valid parts`,
|
||||
want: "",
|
||||
}, {
|
||||
name: "error_spaces",
|
||||
hostname: "! ! !",
|
||||
wantErrMsg: `normalizing hostname "! ! !": no valid parts`,
|
||||
wantErrMsg: `normalizing "! ! !": no valid parts`,
|
||||
want: "",
|
||||
}}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package dnsforward
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
@@ -15,7 +16,8 @@ import (
|
||||
func ValidateClientID(clientID string) (err error) {
|
||||
err = aghnet.ValidateDomainNameLabel(clientID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid client id: %w", err)
|
||||
// Replace the domain name label wrapper with our own.
|
||||
return fmt.Errorf("invalid client id %q: %w", clientID, errors.Unwrap(err))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -117,8 +117,8 @@ func TestProcessClientID(t *testing.T) {
|
||||
hostSrvName: "example.com",
|
||||
cliSrvName: "!!!.example.com",
|
||||
wantClientID: "",
|
||||
wantErrMsg: `client id check: invalid client id: invalid char '!' ` +
|
||||
`at index 0 in "!!!"`,
|
||||
wantErrMsg: `client id check: invalid client id "!!!": ` +
|
||||
`invalid char '!' at index 0`,
|
||||
wantRes: resultCodeError,
|
||||
strictSNI: true,
|
||||
}, {
|
||||
@@ -128,9 +128,9 @@ func TestProcessClientID(t *testing.T) {
|
||||
cliSrvName: `abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmno` +
|
||||
`pqrstuvwxyz0123456789.example.com`,
|
||||
wantClientID: "",
|
||||
wantErrMsg: `client id check: invalid client id: "abcdefghijklmno` +
|
||||
`pqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789" ` +
|
||||
`is too long, max: 63`,
|
||||
wantErrMsg: `client id check: invalid client id "abcdefghijklmno` +
|
||||
`pqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789": ` +
|
||||
`label is too long, max: 63`,
|
||||
wantRes: resultCodeError,
|
||||
strictSNI: true,
|
||||
}, {
|
||||
@@ -238,8 +238,8 @@ func TestProcessClientID_https(t *testing.T) {
|
||||
name: "invalid_client_id",
|
||||
path: "/dns-query/!!!",
|
||||
wantClientID: "",
|
||||
wantErrMsg: `client id check: invalid client id: invalid char '!' ` +
|
||||
`at index 0 in "!!!"`,
|
||||
wantErrMsg: `client id check: invalid client id "!!!": ` +
|
||||
`invalid char '!' at index 0`,
|
||||
wantRes: resultCodeError,
|
||||
}}
|
||||
|
||||
|
||||
@@ -1166,8 +1166,9 @@ func TestNewServer(t *testing.T) {
|
||||
in: DNSCreateParams{
|
||||
LocalDomain: "!!!",
|
||||
},
|
||||
wantErrMsg: `local domain: invalid domain name label at index 0: ` +
|
||||
`invalid char '!' at index 0 in "!!!"`,
|
||||
wantErrMsg: `local domain: validating domain name "!!!": ` +
|
||||
`invalid domain name label at index 0: ` +
|
||||
`validating label "!!!": invalid char '!' at index 0`,
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
|
||||
@@ -29,25 +29,25 @@ var webHandlersRegistered = false
|
||||
|
||||
// Client contains information about persistent clients.
|
||||
type Client struct {
|
||||
IDs []string
|
||||
Tags []string
|
||||
Name string
|
||||
UseOwnSettings bool // false: use global settings
|
||||
FilteringEnabled bool
|
||||
SafeSearchEnabled bool
|
||||
SafeBrowsingEnabled bool
|
||||
ParentalEnabled bool
|
||||
|
||||
UseOwnBlockedServices bool // false: use global settings
|
||||
BlockedServices []string
|
||||
|
||||
Upstreams []string // list of upstream servers to be used for the client's requests
|
||||
|
||||
// Custom upstream config for this client
|
||||
// nil: not yet initialized
|
||||
// not nil, but empty: initialized, no good upstreams
|
||||
// not nil, not empty: Upstreams ready to be used
|
||||
// upstreamConfig is the custom upstream config for this client. If
|
||||
// it's nil, it has not been initialized yet. If it's non-nil and
|
||||
// empty, there are no valid upstreams. If it's non-nil and non-empty,
|
||||
// these upstream must be used.
|
||||
upstreamConfig *proxy.UpstreamConfig
|
||||
|
||||
Name string
|
||||
|
||||
IDs []string
|
||||
Tags []string
|
||||
BlockedServices []string
|
||||
Upstreams []string
|
||||
|
||||
UseOwnSettings bool
|
||||
FilteringEnabled bool
|
||||
SafeSearchEnabled bool
|
||||
SafeBrowsingEnabled bool
|
||||
ParentalEnabled bool
|
||||
UseOwnBlockedServices bool
|
||||
}
|
||||
|
||||
type clientSource uint
|
||||
@@ -63,9 +63,9 @@ const (
|
||||
|
||||
// RuntimeClient information
|
||||
type RuntimeClient struct {
|
||||
WhoisInfo *RuntimeClientWhoisInfo
|
||||
Host string
|
||||
Source clientSource
|
||||
WhoisInfo *RuntimeClientWhoisInfo
|
||||
}
|
||||
|
||||
// RuntimeClientWhoisInfo is the filtered WHOIS data for a runtime client.
|
||||
|
||||
@@ -7,31 +7,38 @@ import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// clientJSON is a common structure used by several handlers to deal with
|
||||
// clients. Some of the fields are only necessary in one or two handlers and
|
||||
// are thus made pointers with an omitempty tag.
|
||||
//
|
||||
// TODO(a.garipov): Consider using nullbool and an optional string here? Or
|
||||
// split into several structs?
|
||||
type clientJSON struct {
|
||||
IDs []string `json:"ids"`
|
||||
Tags []string `json:"tags"`
|
||||
Name string `json:"name"`
|
||||
UseGlobalSettings bool `json:"use_global_settings"`
|
||||
FilteringEnabled bool `json:"filtering_enabled"`
|
||||
ParentalEnabled bool `json:"parental_enabled"`
|
||||
SafeSearchEnabled bool `json:"safesearch_enabled"`
|
||||
SafeBrowsingEnabled bool `json:"safebrowsing_enabled"`
|
||||
// Disallowed, if non-nil and false, means that the client's IP is
|
||||
// allowed. Otherwise, the IP is blocked.
|
||||
Disallowed *bool `json:"disallowed,omitempty"`
|
||||
|
||||
UseGlobalBlockedServices bool `json:"use_global_blocked_services"`
|
||||
BlockedServices []string `json:"blocked_services"`
|
||||
// DisallowedRule is the rule due to which the client is disallowed.
|
||||
// If Disallowed is true and this string is empty, the client IP is
|
||||
// disallowed by the "allowed IP list", that is it is not included in
|
||||
// the allowlist.
|
||||
DisallowedRule *string `json:"disallowed_rule,omitempty"`
|
||||
|
||||
Upstreams []string `json:"upstreams"`
|
||||
WhoisInfo *RuntimeClientWhoisInfo `json:"whois_info,omitempty"`
|
||||
|
||||
WhoisInfo *RuntimeClientWhoisInfo `json:"whois_info"`
|
||||
Name string `json:"name"`
|
||||
|
||||
// Disallowed - if true -- client's IP is not disallowed
|
||||
// Otherwise, it is blocked.
|
||||
Disallowed bool `json:"disallowed"`
|
||||
BlockedServices []string `json:"blocked_services"`
|
||||
IDs []string `json:"ids"`
|
||||
Tags []string `json:"tags"`
|
||||
Upstreams []string `json:"upstreams"`
|
||||
|
||||
// DisallowedRule - the rule due to which the client is disallowed
|
||||
// If Disallowed is true, and this string is empty - it means that the client IP
|
||||
// is disallowed by the "allowed IP list", i.e. it is not included in allowed.
|
||||
DisallowedRule string `json:"disallowed_rule"`
|
||||
FilteringEnabled bool `json:"filtering_enabled"`
|
||||
ParentalEnabled bool `json:"parental_enabled"`
|
||||
SafeBrowsingEnabled bool `json:"safebrowsing_enabled"`
|
||||
SafeSearchEnabled bool `json:"safesearch_enabled"`
|
||||
UseGlobalBlockedServices bool `json:"use_global_blocked_services"`
|
||||
UseGlobalSettings bool `json:"use_global_settings"`
|
||||
}
|
||||
|
||||
type runtimeClientJSON struct {
|
||||
@@ -126,8 +133,6 @@ func clientToJSON(c *Client) clientJSON {
|
||||
BlockedServices: c.BlockedServices,
|
||||
|
||||
Upstreams: c.Upstreams,
|
||||
|
||||
WhoisInfo: &RuntimeClientWhoisInfo{},
|
||||
}
|
||||
|
||||
return cj
|
||||
@@ -243,7 +248,8 @@ func (clients *clientsContainer) handleFindClient(w http.ResponseWriter, r *http
|
||||
}
|
||||
} else {
|
||||
cj = clientToJSON(c)
|
||||
cj.Disallowed, cj.DisallowedRule = clients.dnsServer.IsBlockedIP(ip)
|
||||
disallowed, rule := clients.dnsServer.IsBlockedIP(ip)
|
||||
cj.Disallowed, cj.DisallowedRule = &disallowed, &rule
|
||||
}
|
||||
|
||||
data = append(data, map[string]clientJSON{
|
||||
@@ -279,8 +285,8 @@ func (clients *clientsContainer) findRuntime(ip net.IP, idStr string) (cj client
|
||||
|
||||
cj = clientJSON{
|
||||
IDs: []string{idStr},
|
||||
Disallowed: disallowed,
|
||||
DisallowedRule: rule,
|
||||
Disallowed: &disallowed,
|
||||
DisallowedRule: &rule,
|
||||
WhoisInfo: &RuntimeClientWhoisInfo{},
|
||||
}
|
||||
|
||||
@@ -288,7 +294,8 @@ func (clients *clientsContainer) findRuntime(ip net.IP, idStr string) (cj client
|
||||
}
|
||||
|
||||
cj = runtimeClientToJSON(idStr, rc)
|
||||
cj.Disallowed, cj.DisallowedRule = clients.dnsServer.IsBlockedIP(ip)
|
||||
disallowed, rule := clients.dnsServer.IsBlockedIP(ip)
|
||||
cj.Disallowed, cj.DisallowedRule = &disallowed, &rule
|
||||
|
||||
return cj, true
|
||||
}
|
||||
|
||||
@@ -4,6 +4,15 @@
|
||||
|
||||
## v0.106: API changes
|
||||
|
||||
### The field `"supported_tags"` in `GET /control/clients`
|
||||
|
||||
* Prefiously undocumented field `"supported_tags"` in the response is now
|
||||
documented.
|
||||
|
||||
### The field `"whois_info"` in `GET /control/clients`
|
||||
|
||||
* Objects in the `"auto_clients"` array now have the `"whois_info"` field.
|
||||
|
||||
### New response code in `POST /control/login`
|
||||
|
||||
* `429` is returned when user is out of login attempts. It adds the
|
||||
|
||||
@@ -2234,6 +2234,10 @@
|
||||
'type': 'array'
|
||||
'items':
|
||||
'type': 'string'
|
||||
'tags':
|
||||
'items':
|
||||
'type': 'string'
|
||||
'type': 'array'
|
||||
'ClientAuto':
|
||||
'type': 'object'
|
||||
'description': 'Auto-Client information'
|
||||
@@ -2250,6 +2254,8 @@
|
||||
'type': 'string'
|
||||
'description': 'The source of this information'
|
||||
'example': 'etc/hosts'
|
||||
'whois_info':
|
||||
'$ref': '#/components/schemas/WhoisInfo'
|
||||
'ClientUpdate':
|
||||
'type': 'object'
|
||||
'description': 'Client update request'
|
||||
@@ -2384,6 +2390,10 @@
|
||||
'$ref': '#/components/schemas/ClientsArray'
|
||||
'auto_clients':
|
||||
'$ref': '#/components/schemas/ClientsAutoArray'
|
||||
'supported_tags':
|
||||
'items':
|
||||
'type': 'string'
|
||||
'type': 'array'
|
||||
'ClientsArray':
|
||||
'type': 'array'
|
||||
'items':
|
||||
|
||||
Reference in New Issue
Block a user