Compare commits

...

20 Commits

Author SHA1 Message Date
Ildar Kamalov
e667ec1b60 Merge: - client: fix loading of additional search results
Closes #1275

* commit '86df748209cafc14379a0d43d321b4c4ed318dd5':
  - client: fix loading of additional search results
2020-01-14 14:22:40 +03:00
Ildar Kamalov
86df748209 - client: fix loading of additional search results 2020-01-13 17:06:00 +03:00
Ildar Kamalov
ba04b38a5f Merge: * client: update translations
Closes #1334

* commit 'd4789c5d938fbb6903677da6bc76fbff79b274d7':
  * client: update translations
2020-01-13 10:03:24 +03:00
Simon Zolin
318ed0dafb Merge: resolve minor issues
* commit '3b9d758510cd65e483524de1e698076326950ab0':
  * refactor
  * dnsforward: get per-client settings only once
  * clients: manual clients don't exclude auto-clients anymore
  * clients: Upstreams cache: refactor
  * clients: remove WHOIS info for manually-added clients
2020-01-10 19:18:10 +03:00
Simon Zolin
3b9d758510 * refactor 2020-01-10 19:08:07 +03:00
Simon Zolin
0ef8e5cdae * dnsforward: get per-client settings only once
+ dnsforward: add 'ProtectionEnabled = false' test
2020-01-10 19:08:05 +03:00
Simon Zolin
b3ddae7f85 * clients: manual clients don't exclude auto-clients anymore 2020-01-10 15:52:40 +03:00
Simon Zolin
995373c74b * clients: Upstreams cache: refactor
don't use a separate container
2020-01-10 15:52:38 +03:00
Simon Zolin
87bcb67f8f * clients: remove WHOIS info for manually-added clients 2020-01-10 15:51:57 +03:00
Simon Zolin
688a5d84c8 Merge: * dnsfilter: change DNS answer for host rules
Close #1328

* commit '8d2a9ce923eae4673a74f4c4a7e1d9ef840f04d2':
  * dnsfilter: change DNS answer for host rules
2020-01-10 15:29:56 +03:00
Simon Zolin
0cd25cf598 Merge: - clients: fix rename
Close #1340

Squashed commit of the following:

commit 95f0291c681f98c29f4014b651c159d387301af4
Author: Simon Zolin <s.zolin@adguard.com>
Date:   Thu Jan 9 18:56:23 2020 +0300

    add test

commit 293be277e245ff2f430e8c1e9ee3e82dc7da0995
Author: Simon Zolin <s.zolin@adguard.com>
Date:   Thu Jan 9 16:04:36 2020 +0300

    - clients: fix rename
2020-01-10 15:28:58 +03:00
Andrey Meshkov
84b11ff7a5 Merge: * readme: Add note about being able to ad-block IoT devices
* commit '358a36b138b816eba2602b9ab2d44f62ccbfeff3':
  * readme: Add note about being able to ad-block IoT devices
2020-01-10 14:21:58 +03:00
Simon Zolin
d309a7e33c Merge: - clients: settings safebrowsing_enabled and safesearch_enabled were incorrect (reversed)
Close #1339

* commit '4386e8ddde296f270fada3deba43a48b53b5da4c':
  - settings safebrowsing_enabled and safesearch_enabled were incorrect (reversed)
2020-01-10 12:22:00 +03:00
Simon Zolin
e28fdd37cd Merge: - querylog: incorrect client IP when blocked by hosts filter
Close #1329

* commit '29998a8959d9ed4d31d6034eaa3a1ec9d178e191':
  - querylog: incorrect client IP when blocked by hosts filter
2020-01-10 12:21:17 +03:00
mountainsandcode
358a36b138 * readme: Add note about being able to ad-block IoT devices 2020-01-10 12:17:04 +03:00
Ildar Kamalov
d4789c5d93 * client: update translations 2020-01-09 21:42:43 +03:00
Simon Zolin
8d2a9ce923 * dnsfilter: change DNS answer for host rules
When matched by a host rule, return only the IP address specified in rule.
Respond with an empty IP list to another request type.

:: host -- return nothing to A, return :: to AAAA request
0.0.0.0 host -- return 0.0.0.0 to A, return nothing to AAAA request
2020-01-09 19:31:14 +03:00
Simon Zolin
29998a8959 - querylog: incorrect client IP when blocked by hosts filter 2020-01-09 18:27:44 +03:00
Simon Zolin
4386e8ddde - settings safebrowsing_enabled and safesearch_enabled were incorrect (reversed) 2020-01-09 15:01:54 +03:00
Andrey Meshkov
94d86eee10 -(dnsforward): update dnsproxy to v0.23.6 2019-12-31 18:09:55 +03:00
17 changed files with 174 additions and 159 deletions

View File

@@ -118,7 +118,7 @@ AdGuard Home provides a lot of features out-of-the-box with no need to install a
It depends.
"DNS sinkholing" is capable of blocking a big percentage of ads, but it lacks flexibility and power of traditional ad blockers. You can get a good impression about the difference between these methods by reading [this article](https://adguard.com/en/blog/adguard-vs-adaway-dns66/). It compares AdGuard for Android (a traditional ad blocker) to hosts-level ad blockers (which are almost identical to DNS-based blockers in their capabilities). However, this level of protection is enough for some users.
"DNS sinkholing" is capable of blocking a big percentage of ads, but it lacks flexibility and power of traditional ad blockers. You can get a good impression about the difference between these methods by reading [this article](https://adguard.com/en/blog/adguard-vs-adaway-dns66/). It compares AdGuard for Android (a traditional ad blocker) to hosts-level ad blockers (which are almost identical to DNS-based blockers in their capabilities). However, this level of protection is enough for some users. Additionally, using a DNS-based blocker can help to block ads, tracking and analytics requests on other types of devices, such as SmartTVs, smart speakers or other kinds of IoT devices (on which you can't install tradtional ad blockers).
<a id="how-to-build"></a>
## How to build from source

View File

@@ -17,9 +17,14 @@
"dhcp_leases": "Locations des serveurs DHCP",
"dhcp_static_leases": "Baux statiques DHCP",
"dhcp_leases_not_found": "Aucune location des serveurs DHCP trouvée",
"dhcp_config_saved": "La configuration du serveur DHCP est sauvegardée",
"form_error_required": "Champ requis",
"form_error_ip4_format": "Format IPv4 invalide",
"form_error_ip6_format": "Format IPv6 invalide",
"form_error_ip_format": "Format IPv4 invalide",
"form_error_mac_format": "Format MAC invalide",
"form_error_positive": "Doit être supérieur à 0",
"form_error_negative": "Doit être égal à 0 ou supérieur",
"dhcp_form_gateway_input": "IP de la passerelle",
"dhcp_form_subnet_input": "Masque de sous-réseau",
"dhcp_form_range_title": "Rangée des adresses IP",
@@ -41,6 +46,7 @@
"dhcp_new_static_lease": "Nouveau bail statique",
"dhcp_static_leases_not_found": "Aucun bail statique DHCP trouvé",
"dhcp_add_static_lease": "Ajoutez un bail statique",
"dhcp_reset": "Voulez-vous vraiment réinitialiser votre configuration DHCP ?",
"delete_confirm": "Voulez-vous vraiment supprimer \"{{key}}\" ?",
"form_enter_hostname": "Saisissez un nom d'hôte",
"error_details": "Détails des erreurs",
@@ -240,6 +246,13 @@
"install_devices_windows_list_6": "Sélectionnez Utiliser ladresse de serveur DNS suivante et saisissez votre adresse de seveur AdGuard Home.",
"install_devices_macos_list_1": "Cliquez sur l'icône Apple et allez dans les Préférences Système.",
"install_devices_macos_list_2": "Cliquez sur Réseau.",
"encryption_https_desc": "Si le port HTTPS est configuré, l'interface administrateur de AdGuard Home sera accessible via HTTPS et fournira aussi un service DNS-over-HTTPS sur l'emplacement '/dns-query'.",
"encryption_chain_valid": "Chaîne de certificat valide",
"encryption_chain_invalid": "Chaîne de certificat invalide",
"encryption_key_valid": "Ceci est une clé privée {{type}} valide",
"encryption_reset": "Voulez-vous vraiment réinitialiser les paramètres de chiffrement ?",
"topline_expiring_certificate": "Votre certificat SSL est sur le point d'expirer. Mettez à jour vos <0>Paramètres de chiffrement</0>.",
"topline_expired_certificate": "Votre certificat SSL a expiré. Mettez à jour vos <0>Paramètres de chiffrement</0>.",
"form_error_port_range": "Saisissez une valeur de port entre 80 et 65535",
"form_error_port_unsafe": "C'est un port non fiable",
"form_error_equal": "Ne devrait pas être égal",
@@ -329,13 +342,24 @@
"blocked_services": "Services bloqués",
"blocked_services_desc": "Permet de bloquer les sites et services populaires rapidement.",
"blocked_services_saved": "Services bloqués enregistrés",
"blocked_services_global": "Utiliser les services bloqués globaux",
"blocked_service": "Service bloqué",
"block_all": "Tout bloquer",
"unblock_all": "Tout débloquer",
"encryption_certificate_path": "Emplacement du certificat",
"encryption_private_key_path": "Emplacement de la clef privée",
"encryption_certificates_source_path": "Définir un emplacement du fichier des certificats",
"encryption_certificates_source_content": "Coller les contenus des certificats",
"encryption_key_source_path": "Définir un fichier pour la clef privée",
"encryption_key_source_content": "Coller les contenus de la clef privée",
"stats_params": "Configuration des statistiques",
"config_successfully_saved": "Configuration sauvegardée",
"interval_24_hour": "24 heures",
"interval_days": "{{count}} jour",
"interval_days_plural": "{{count}} jours",
"domain": "Domaine",
"answer": "Réponse",
"filter_added_successfully": "Le filtre a été ajouté",
"statistics_configuration": "Configuration des statistiques",
"statistics_retention": "Maintien des statistiques",
"statistics_retention_desc": "Si vous baissez la valeur de l'intervalle, des données seront perdues",
@@ -347,6 +371,7 @@
"interval_hours_plural": "{{count}} heures",
"filters_configuration": "Configuration des filtres",
"filters_enable": "Activer les filtres",
"filters_interval": "Intervalle de mise à jour des filtres",
"disabled": "Désactivé",
"username_label": "Nom d'utilisateur",
"username_placeholder": "Saisir un nom d'utilisateur",

View File

@@ -72,12 +72,14 @@
"stats_malware_phishing": "Blokkert skadevare/phishing",
"stats_adult": "Blokkerte voksennettsteder",
"stats_query_domain": "Mest forespurte domener",
"for_last_days_plural": "de siste {{count}} dagene",
"no_domains_found": "Ingen domener ble funnet",
"requests_count": "Antall forespørsler",
"top_blocked_domains": "Mest blokkerte domener",
"top_clients": "Vanligste klienter",
"no_clients_found": "Ingen klienter ble funnet",
"general_statistics": "Generelle statistikker",
"number_of_dns_query_days_plural": "Antall DNS-forespørsler som ble behandlet de siste {{count}} dagene",
"number_of_dns_query_24_hours": "Antall DNS-forespørsler som ble behandlet de siste 24 timene",
"number_of_dns_query_blocked_24_hours": "Antall DNS-forespørsler som ble blokkert av adblock-filtre, hosts-lister, og domene-lister",
"number_of_dns_query_blocked_24_hours_by_sec": "Antall DNS-forespørsler som ble blokkert av AdGuard sin nettlesersikkerhetsmodul",

View File

@@ -23,6 +23,7 @@
"form_error_ip6_format": "Formato de endereço IPv6 inválido",
"form_error_ip_format": "Formato de endereço IPv inválido",
"form_error_mac_format": "Formato do endereço MAC inválido",
"form_error_client_id_format": "Formato do ID de cliente inválido",
"form_error_positive": "Deve ser maior que 0",
"form_error_negative": "Deve ser igual ou superior a 0",
"dhcp_form_gateway_input": "IP do gateway",
@@ -371,6 +372,7 @@
"rewrite_desc": "Permite configurar uma resposta personalizada do DNS para um nome de domínio específico.",
"rewrite_applied": "Regra de reescrita aplicada",
"dns_rewrites": "Reescritas de DNS",
"form_domain": "Digite o nome do domínio ou wildcard",
"form_answer": "Digite o endereço de IP ou nome de domínio",
"form_error_domain_format": "Formato de domínio inválido",
"form_error_answer_format": "Formato de resposta inválido",
@@ -426,5 +428,8 @@
"whois": "Whois",
"filtering_rules_learn_more": "<0>Saiba mais</0> sobre como criar as suas próprias listas negras de servidores.",
"blocked_by_response": "Bloqueado por CNAME ou IP na resposta",
"try_again": "Tente novamente"
"try_again": "Tente novamente",
"domain_desc": "Digite o nome do domínio ou wildcard que pretende reescrever.",
"example_rewrite_domain": "reescrever respostas apenas para este nome de domínio.",
"example_rewrite_wildcard": "reescrever respostas para todos subdomínios <0>exemplo.org</0>."
}

View File

@@ -9,10 +9,10 @@
"enabled_dhcp": "DHCP 服务器已启用",
"disabled_dhcp": "DHCP 服务器已禁用",
"dhcp_title": "DHCP 服务器(实验性)",
"dhcp_description": "如果你的路由器没有提供动态主机置协议DHCP)设置,你可以使用 AdGuard 内置的 DHCP 服务器。",
"dhcp_description": "如果你的路由器没有提供 DHCP 动态主机置协议)设置,你可以使用 AdGuard 内置的 DHCP 服务器。",
"dhcp_enable": "启用 DHCP 服务器",
"dhcp_disable": "用 DHCP 服务器",
"dhcp_not_found": "在当前网络中未检测到 DHCP 服务器。您可以安全地启用内置 DHCP 服务器。",
"dhcp_disable": "用 DHCP 服务器",
"dhcp_not_found": "您可以安全地启用内置 DHCP 服务器 - 在当前网络中未检测到任何起作用的 DHCP 服务器。然而我们鼓励您以手动方式重新检测因为当前我们的自动检测不能确保100%准确。",
"dhcp_found": "在当前网络中检测到 DHCP 服务器。如果启用内置的 DHCP 服务器可能不安全。",
"dhcp_leases": "DHCP 租约",
"dhcp_static_leases": "DHCP 静态租约",
@@ -38,12 +38,12 @@
"dhcp_ip_addresses": "IP 地址",
"dhcp_table_hostname": "主机名",
"dhcp_table_expires": "到期",
"dhcp_warning": "如果你想要启用内置的 DHCP 服务器,请确保在当前网络中没有其它活动的 DHCP 服务器。否则,此操作可能会破坏已连接设备的网络连接!",
"dhcp_error": "我们无法确定网络是否其它 DHCP 服务器。",
"dhcp_static_ip_error": "要使用 DHCP 服务器,则必须设置静态 IP。我们无法确定此网络接口是否使用静态 IP 配置的。请手动设置静态 IP 地址。",
"dhcp_dynamic_ip_found": "您的系统使用了动态 IP 地址配置 <0>{{interfaceName}}</0> 接口。要使用 DHCP 服务器,则必须设置为静态 IP 地址。您当前的 IP 地址为 <0>{{ipAddress}}</0>。如您点击 启 DHCP 按钮,我们自动设置此 IP 地址为静态。",
"dhcp_lease_added": "静态租约 \"{{key}}\" 添加成功",
"dhcp_lease_deleted": "静态租约 \"{{key}}\" 删除成功",
"dhcp_warning": "如果你想要启用内置的 DHCP 服务器,请确保在当前网络中没有其它起作用的 DHCP 服务器。否则,此操作可能会破坏已连接设备的网络连接!",
"dhcp_error": "我们无法确定在当前网络是否存在其它 DHCP 服务器。",
"dhcp_static_ip_error": "要使用 DHCP 服务器,则必须设置静态 IP 地址。我们无法确定此网络接口是否已被配置为使用静态 IP 地址。请手动为此网络接口设置静态 IP 地址。",
"dhcp_dynamic_ip_found": "您的系统对网络接口 <0>{{interfaceName}}</0> 使用了动态 IP 地址配置。要使用 DHCP 服务器,则必须对此网络接口使用静态 IP 地址配置。此网络接口当前的 IP 地址为 <0>{{ipAddress}}</0>。如您点击 启 DHCP 按钮,我们自动修改此网络接口以使用静态 IP 地址配置。",
"dhcp_lease_added": "静态租约 \"{{key}}\" 已成功添加",
"dhcp_lease_deleted": "静态租约 \"{{key}}\" 已成功删除",
"dhcp_new_static_lease": "新建静态租约",
"dhcp_static_leases_not_found": "未找到 DHCP 静态租约",
"dhcp_add_static_lease": "添加静态租约",
@@ -108,7 +108,7 @@
"encryption_settings": "加密设置",
"dhcp_settings": "DHCP 设置",
"upstream_dns": "上游 DNS 服务器",
"upstream_dns_hint": "如果此处留空AdGuard Home 将会使用 <a href='https://www.quad9.net/' target='_blank'>Quad9</a> 作为上游 DNS。如果想要使用使用 DNS over TLS请以 tls:// 为开头。",
"upstream_dns_hint": "如果此处留空AdGuard Home 将会使用 <a href='https://www.quad9.net/' target='_blank'>Cloudflare DNS</a> 作为上游 DNS。如果想要使用 DNS over TLS请以 tls:// 为开头。",
"test_upstream_btn": "测试上游 DNS",
"upstreams": "上游服务器",
"apply_btn": "应用",

View File

@@ -14,9 +14,9 @@
"dhcp_disable": "禁用動態主機設定協定DHCP伺服器",
"dhcp_not_found": "啟用內建的動態主機設定協定DHCP伺服器為安全的 - 於該網路上,我們未發現任何現行的 DHCP 伺服器。然而,我們鼓勵您手動地重新檢查它,因為我們的自動之測試目前不予 100 保證。",
"dhcp_found": "於該網路上一個現行的動態主機設定協定DHCP伺服器被發現。啟用內建的 DHCP 伺服器為不安全的。",
"dhcp_leases": "動態主機設定協定DHCP",
"dhcp_static_leases": "動態主機設定協定DHCP靜態租",
"dhcp_leases_not_found": "無已發現之動態主機設定協定DHCP",
"dhcp_leases": "動態主機設定協定DHCP",
"dhcp_static_leases": "動態主機設定協定DHCP靜態租",
"dhcp_leases_not_found": "無已發現之動態主機設定協定DHCP",
"dhcp_config_saved": "動態主機設定協定DHCP配置被成功地儲存",
"form_error_required": "必填的欄位",
"form_error_ip4_format": "無效的 IPv4 格式",
@@ -25,14 +25,14 @@
"form_error_mac_format": "無效的媒體存取控制MAC格式",
"form_error_client_id_format": "無效的用戶端 ID 格式",
"form_error_positive": "必須大於 0",
"form_error_negative": "必須等於 0 或更大",
"form_error_negative": "必須等於或大於 0",
"dhcp_form_gateway_input": "閘道 IP",
"dhcp_form_subnet_input": "子網路遮罩",
"dhcp_form_range_title": "IP 位址範圍",
"dhcp_form_range_start": "範圍開始",
"dhcp_form_range_end": "範圍結束",
"dhcp_form_lease_title": "動態主機設定協定DHCP時間(以秒數)",
"dhcp_form_lease_input": "租賃持續時間",
"dhcp_form_lease_title": "動態主機設定協定DHCP時間(以秒數)",
"dhcp_form_lease_input": "租約期間",
"dhcp_interface_select": "選擇動態主機設定協定DHCP介面",
"dhcp_hardware_address": "硬體位址",
"dhcp_ip_addresses": "IP 位址",
@@ -42,11 +42,11 @@
"dhcp_error": "我們無法確定在該網路是否有另外的動態主機設定協定DHCP伺服器。",
"dhcp_static_ip_error": "為了使用動態主機設定協定DHCP伺服器靜態 IP 位址必須被設定。我們未能確定該網路介面是否被配置使用靜態 IP 位址。請手動地設定靜態 IP 位址。",
"dhcp_dynamic_ip_found": "您的系統使用動態 IP 位址配置供介面 <0>{{interfaceName}}</0>。為了使用動態主機設定協定DHCP伺服器靜態 IP 位址必須被設定。您現行的 IP 位址為 <0>{{ipAddress}}</0>。如果您按啟用 DHCP 按鈕,我們將自動地設定此 IP 位址作為靜態。",
"dhcp_lease_added": "靜態租 \"{{key}}\" 被成功地加入",
"dhcp_lease_deleted": "靜態租 \"{{key}}\" 被成功地刪除",
"dhcp_new_static_lease": "新的靜態租",
"dhcp_static_leases_not_found": "無已發現之動態主機設定協定DHCP靜態租",
"dhcp_add_static_lease": "增加靜態租",
"dhcp_lease_added": "靜態租 \"{{key}}\" 被成功地加入",
"dhcp_lease_deleted": "靜態租 \"{{key}}\" 被成功地刪除",
"dhcp_new_static_lease": "新的靜態租",
"dhcp_static_leases_not_found": "無已發現之動態主機設定協定DHCP靜態租",
"dhcp_add_static_lease": "增加靜態租",
"dhcp_reset": "您確定您想要重置動態主機設定協定DHCP配置嗎",
"delete_confirm": "您確定您想要刪除 \"{{key}}\" 嗎?",
"form_enter_hostname": "輸入主機名稱",

View File

@@ -44,7 +44,7 @@ const checkFilteredLogs = async (data, filter, dispatch, total) => {
try {
const additionalLogs = await getLogsWithParams({ older_than: oldest, filter });
if (additionalLogs.logs.length > 0) {
if (additionalLogs.oldest.length > 0) {
return await checkFilteredLogs(additionalLogs, filter, dispatch, {
logs: [...totalData.logs, ...additionalLogs.logs],
oldest: additionalLogs.oldest,

View File

@@ -1,7 +1,6 @@
package dnsfilter
import (
"bytes"
"fmt"
"io/ioutil"
"net"
@@ -538,24 +537,15 @@ func (d *Dnsfilter) matchHost(host string, qtype uint16) (Result, error) {
} else if hostRule, ok := rule.(*rules.HostRule); ok {
res.IP = net.IP{}
if qtype == dns.TypeA && hostRule.IP.To4() != nil {
// either IPv4 or IPv4-mapped IPv6 address
res.IP = hostRule.IP.To4()
return res, nil
} else if qtype == dns.TypeAAAA {
ip4 := hostRule.IP.To4()
if ip4 == nil {
res.IP = hostRule.IP
return res, nil
}
if bytes.Equal(ip4, []byte{0, 0, 0, 0}) {
// send IP="::" response for a rule "0.0.0.0 blockdomain"
res.IP = net.IPv6zero
return res, nil
}
} else if qtype == dns.TypeAAAA && hostRule.IP.To4() == nil {
res.IP = hostRule.IP
}
continue
return res, nil
} else {
log.Tracef("Rule type is unsupported: '%s' list_id: %d",

View File

@@ -98,7 +98,7 @@ func (d *Dnsfilter) checkMatchEmpty(t *testing.T, hostname string) {
func TestEtcHostsMatching(t *testing.T) {
addr := "216.239.38.120"
addr6 := "::1"
text := fmt.Sprintf(" %s google.com www.google.com # enforce google's safesearch \n%s google.com\n0.0.0.0 block.com\n",
text := fmt.Sprintf(" %s google.com www.google.com # enforce google's safesearch \n%s ipv6.com\n0.0.0.0 block.com\n",
addr, addr6)
filters := make(map[int]string)
filters[0] = text
@@ -110,12 +110,19 @@ func TestEtcHostsMatching(t *testing.T) {
d.checkMatchEmpty(t, "subdomain.google.com")
d.checkMatchEmpty(t, "example.org")
// IPv6 address
d.checkMatchIP(t, "google.com", addr6, dns.TypeAAAA)
// block both IPv4 and IPv6
// IPv4
d.checkMatchIP(t, "block.com", "0.0.0.0", dns.TypeA)
d.checkMatchIP(t, "block.com", "::", dns.TypeAAAA)
// ...but empty IPv6
ret, err := d.CheckHost("block.com", dns.TypeAAAA, &setts)
assert.True(t, err == nil && ret.IsFiltered && ret.IP != nil && len(ret.IP) == 0)
// IPv6
d.checkMatchIP(t, "ipv6.com", addr6, dns.TypeAAAA)
// ...but empty IPv4
ret, err = d.CheckHost("ipv6.com", dns.TypeA, &setts)
assert.True(t, err == nil && ret.IsFiltered && ret.IP != nil && len(ret.IP) == 0)
}
// SAFE BROWSING

View File

@@ -445,7 +445,15 @@ func (s *Server) handleDNSRequest(p *proxy.Proxy, d *proxy.DNSContext) error {
// A better approach is for proxy.Stop() to wait until all its workers exit,
// but this would require the Upstream interface to have Close() function
// (to prevent from hanging while waiting for unresponsive DNS server to respond).
res, err := s.filterDNSRequest(d)
var setts *dnsfilter.RequestFilteringSettings
var err error
res := &dnsfilter.Result{}
protectionEnabled := s.conf.ProtectionEnabled && s.dnsFilter != nil
if protectionEnabled {
setts = s.getClientRequestFilteringSettings(d)
res, err = s.filterDNSRequest(d, setts)
}
s.RUnlock()
if err != nil {
return err
@@ -486,9 +494,9 @@ func (s *Server) handleDNSRequest(p *proxy.Proxy, d *proxy.DNSContext) error {
d.Res.Answer = answer
}
} else if res.Reason != dnsfilter.NotFilteredWhiteList {
} else if res.Reason != dnsfilter.NotFilteredWhiteList && protectionEnabled {
origResp2 := d.Res
res, err = s.filterDNSResponse(d)
res, err = s.filterDNSResponse(d, setts)
if err != nil {
return err
}
@@ -602,12 +610,7 @@ func (s *Server) getClientRequestFilteringSettings(d *proxy.DNSContext) *dnsfilt
}
// filterDNSRequest applies the dnsFilter and sets d.Res if the request was filtered
func (s *Server) filterDNSRequest(d *proxy.DNSContext) (*dnsfilter.Result, error) {
if !s.conf.ProtectionEnabled || s.dnsFilter == nil {
return &dnsfilter.Result{}, nil
}
setts := s.getClientRequestFilteringSettings(d)
func (s *Server) filterDNSRequest(d *proxy.DNSContext, setts *dnsfilter.RequestFilteringSettings) (*dnsfilter.Result, error) {
req := d.Req
host := strings.TrimSuffix(req.Question[0].Name, ".")
res, err := s.dnsFilter.CheckHost(host, d.Req.Question[0].Qtype, setts)
@@ -648,7 +651,7 @@ func (s *Server) filterDNSRequest(d *proxy.DNSContext) (*dnsfilter.Result, error
// If response contains CNAME, A or AAAA records, we apply filtering to each canonical host name or IP address.
// If this is a match, we set a new response in d.Res and return.
func (s *Server) filterDNSResponse(d *proxy.DNSContext) (*dnsfilter.Result, error) {
func (s *Server) filterDNSResponse(d *proxy.DNSContext, setts *dnsfilter.RequestFilteringSettings) (*dnsfilter.Result, error) {
for _, a := range d.Res.Answer {
host := ""
@@ -676,7 +679,6 @@ func (s *Server) filterDNSResponse(d *proxy.DNSContext) (*dnsfilter.Result, erro
s.RUnlock()
continue
}
setts := s.getClientRequestFilteringSettings(d)
res, err := s.dnsFilter.CheckHostRules(host, d.Req.Question[0].Qtype, setts)
s.RUnlock()
@@ -788,7 +790,8 @@ func (s *Server) genAAAAAnswer(req *dns.Msg, ip net.IP) *dns.AAAA {
func (s *Server) genResponseWithIP(req *dns.Msg, ip net.IP) *dns.Msg {
if req.Question[0].Qtype == dns.TypeA && ip.To4() != nil {
return s.genARecord(req, ip.To4())
} else if req.Question[0].Qtype == dns.TypeAAAA && ip.To4() == nil {
} else if req.Question[0].Qtype == dns.TypeAAAA &&
len(ip) == net.IPv6len && ip.To4() == nil {
return s.genAAAARecord(req, ip)
}

View File

@@ -340,6 +340,22 @@ var testIPv4 = map[string][]net.IP{
"example.org.": {{127, 0, 0, 255}},
}
func TestBlockCNAMEProtectionEnabled(t *testing.T) {
s := createTestServer(t)
testUpstm := &testUpstream{testCNAMEs, testIPv4, nil}
s.conf.ProtectionEnabled = false
err := s.startWithUpstream(testUpstm)
assert.True(t, err == nil)
addr := s.dnsProxy.Addr(proxy.ProtoUDP)
// 'badhost' has a canonical name 'null.example.org' which is blocked by filters:
// but protection is disabled - response is NOT blocked
req := createTestMessage("badhost.")
reply, err := dns.Exchange(req, addr.String())
assert.True(t, err == nil)
assert.True(t, reply.Rcode == dns.RcodeSuccess)
}
func TestBlockCNAME(t *testing.T) {
s := createTestServer(t)
testUpstm := &testUpstream{testCNAMEs, testIPv4, nil}
@@ -349,35 +365,23 @@ func TestBlockCNAME(t *testing.T) {
// 'badhost' has a canonical name 'null.example.org' which is blocked by filters:
// response is blocked
req := dns.Msg{}
req.Id = dns.Id()
req.Question = []dns.Question{
{Name: "badhost.", Qtype: dns.TypeA, Qclass: dns.ClassINET},
}
reply, err := dns.Exchange(&req, addr.String())
req := createTestMessage("badhost.")
reply, err := dns.Exchange(req, addr.String())
assert.True(t, err == nil)
assert.True(t, reply.Rcode == dns.RcodeNameError)
// 'whitelist.example.org' has a canonical name 'null.example.org' which is blocked by filters
// but 'whitelist.example.org' is in a whitelist:
// response isn't blocked
req = dns.Msg{}
req.Id = dns.Id()
req.Question = []dns.Question{
{Name: "whitelist.example.org.", Qtype: dns.TypeA, Qclass: dns.ClassINET},
}
reply, err = dns.Exchange(&req, addr.String())
req = createTestMessage("whitelist.example.org.")
reply, err = dns.Exchange(req, addr.String())
assert.True(t, err == nil)
assert.True(t, reply.Rcode == dns.RcodeSuccess)
// 'example.org' has a canonical name 'cname1' with IP 127.0.0.255 which is blocked by filters:
// response is blocked
req = dns.Msg{}
req.Id = dns.Id()
req.Question = []dns.Question{
{Name: "example.org.", Qtype: dns.TypeA, Qclass: dns.ClassINET},
}
reply, err = dns.Exchange(&req, addr.String())
req = createTestMessage("example.org.")
reply, err = dns.Exchange(req, addr.String())
assert.True(t, err == nil)
assert.True(t, reply.Rcode == dns.RcodeNameError)

6
go.mod
View File

@@ -3,7 +3,7 @@ module github.com/AdguardTeam/AdGuardHome
go 1.13
require (
github.com/AdguardTeam/dnsproxy v0.23.5
github.com/AdguardTeam/dnsproxy v0.23.6
github.com/AdguardTeam/golibs v0.3.0
github.com/AdguardTeam/urlfilter v0.7.2
github.com/NYTimes/gziphandler v1.1.1
@@ -18,8 +18,8 @@ require (
github.com/sparrc/go-ping v0.0.0-20181106165434-ef3ab45e41b0
github.com/stretchr/testify v1.4.0
go.etcd.io/bbolt v1.3.3 // indirect
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553
golang.org/x/sys v0.0.0-20191224085550-c709ea063b76
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8
gopkg.in/yaml.v2 v2.2.3
)

12
go.sum
View File

@@ -1,5 +1,5 @@
github.com/AdguardTeam/dnsproxy v0.23.5 h1:allfgFioe0e6QvSqKVeS0ZQAo9jHR+2XdNuT1isK7og=
github.com/AdguardTeam/dnsproxy v0.23.5/go.mod h1:2qy8rpdfBzKgMPxkHmPdaNK4XZJ322v4KtVGI8s8Bn0=
github.com/AdguardTeam/dnsproxy v0.23.6 h1:HAiY9muZyc2sNThQjR3M3rLloh1gKIhEuIAftmuae5w=
github.com/AdguardTeam/dnsproxy v0.23.6/go.mod h1:2qy8rpdfBzKgMPxkHmPdaNK4XZJ322v4KtVGI8s8Bn0=
github.com/AdguardTeam/golibs v0.2.4 h1:GUssokegKxKF13K67Pgl0ZGwqHjNN6X7sep5ik6ORdY=
github.com/AdguardTeam/golibs v0.2.4/go.mod h1:R3M+mAg3nWG4X4Hsag5eef/TckHFH12ZYhK7AzJc8+U=
github.com/AdguardTeam/golibs v0.3.0 h1:1zO8ulGEOdXDDM++Ap4sYfTsT/Z4tZBZtiWSA4ykcOU=
@@ -145,8 +145,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
golang.org/x/crypto v0.0.0-20191001170739-f9e2070545dc h1:KyTYo8xkh/2WdbFLUyQwBS0Jfn3qfZ9QmuPbok2oENE=
golang.org/x/crypto v0.0.0-20191001170739-f9e2070545dc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915 h1:aJ0ex187qoXrJHPo8ZasVTASQB7llQP6YeNzgDALPRk=
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876 h1:sKJQZMuxjOAR/Uo2LBfU90onWEf1dF4C+0hPJCc9Mpc=
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20181102091132-c10e9556a7bc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190119204137-ed066c81e75e h1:MDa3fSUp6MdYHouVmCCNz/zaH2a6CRcxY3VhT/K3C5Q=
@@ -181,8 +181,8 @@ golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191002091554-b397fe3ad8ed h1:5TJcLJn2a55mJjzYk0yOoqN8X1OdvBDUnaZaKKyQtkY=
golang.org/x/sys v0.0.0-20191002091554-b397fe3ad8ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191224085550-c709ea063b76 h1:Dho5nD6R3PcW2SH1or8vS0dszDaXRxIw55lBX7XiE5g=
golang.org/x/sys v0.0.0-20191224085550-c709ea063b76/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8 h1:JA8d3MPx/IToSyXZG/RhwYEtfrKO1Fxrqe8KrkiLXKM=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=

View File

@@ -32,12 +32,16 @@ type Client struct {
SafeSearchEnabled bool
SafeBrowsingEnabled bool
ParentalEnabled bool
WhoisInfo [][]string // [[key,value], ...]
UseOwnBlockedServices bool // false: use global settings
BlockedServices []string
Upstreams []string // list of upstream servers to be used for the client's requests
// Upstream objects:
// nil: not yet initialized
// not nil, but empty: initialized, no good upstreams
// not nil, not empty: Upstreams ready to be used
upstreamObjects []upstream.Upstream
}
type clientSource uint
@@ -63,12 +67,7 @@ type clientsContainer struct {
list map[string]*Client // name -> client
idIndex map[string]*Client // IP -> client
ipHost map[string]*ClientHost // IP -> Hostname
// cache for Upstream instances that are used in the case
// when custom DNS servers are configured for a client
upstreamsCache map[string][]upstream.Upstream // name -> []Upstream
lock sync.Mutex
lock sync.Mutex
// dhcpServer is used for looking up clients IP addresses by MAC addresses
dhcpServer *dhcpd.Server
@@ -85,7 +84,6 @@ func (clients *clientsContainer) Init(objects []clientObject, dhcpServer *dhcpd.
clients.list = make(map[string]*Client)
clients.idIndex = make(map[string]*Client)
clients.ipHost = make(map[string]*ClientHost)
clients.upstreamsCache = make(map[string][]upstream.Upstream)
clients.dhcpServer = dhcpServer
clients.addFromConfig(objects)
@@ -102,8 +100,8 @@ type clientObject struct {
UseGlobalSettings bool `yaml:"use_global_settings"`
FilteringEnabled bool `yaml:"filtering_enabled"`
ParentalEnabled bool `yaml:"parental_enabled"`
SafeSearchEnabled bool `yaml:"safebrowsing_enabled"`
SafeBrowsingEnabled bool `yaml:"safesearch_enabled"`
SafeSearchEnabled bool `yaml:"safesearch_enabled"`
SafeBrowsingEnabled bool `yaml:"safebrowsing_enabled"`
UseGlobalBlockedServices bool `yaml:"use_global_blocked_services"`
BlockedServices []string `yaml:"blocked_services"`
@@ -199,6 +197,12 @@ func (clients *clientsContainer) Find(ip string) (Client, bool) {
return clients.findByIP(ip)
}
func upstreamArrayCopy(a []upstream.Upstream) []upstream.Upstream {
a2 := make([]upstream.Upstream, len(a))
copy(a2, a)
return a2
}
// FindUpstreams looks for upstreams configured for the client
// If no client found for this IP, or if no custom upstreams are configured,
// this method returns nil
@@ -211,31 +215,22 @@ func (clients *clientsContainer) FindUpstreams(ip string) []upstream.Upstream {
return nil
}
if len(c.Upstreams) == 0 {
if c.upstreamObjects == nil {
c.upstreamObjects = make([]upstream.Upstream, 0)
for _, us := range c.Upstreams {
u, err := upstream.AddressToUpstream(us, upstream.Options{Timeout: dnsforward.DefaultTimeout})
if err != nil {
log.Error("upstream.AddressToUpstream: %s: %s", us, err)
continue
}
c.upstreamObjects = append(c.upstreamObjects, u)
}
}
if len(c.upstreamObjects) == 0 {
return nil
}
upstreams, ok := clients.upstreamsCache[c.Name]
if ok {
return upstreams
}
for _, us := range c.Upstreams {
u, err := upstream.AddressToUpstream(us, upstream.Options{Timeout: dnsforward.DefaultTimeout})
if err != nil {
log.Error("upstream.AddressToUpstream: %s: %s", us, err)
continue
}
upstreams = append(upstreams, u)
}
if len(upstreams) == 0 {
clients.upstreamsCache[c.Name] = nil
} else {
clients.upstreamsCache[c.Name] = upstreams
}
return upstreams
return upstreamArrayCopy(c.upstreamObjects)
}
// Find searches for a client by IP (and does not lock anything)
@@ -366,17 +361,6 @@ func (clients *clientsContainer) Add(c Client) (bool, error) {
}
}
// remove auto-clients with the same IP address, keeping WHOIS info if possible
for _, id := range c.IDs {
ch, ok := clients.ipHost[id]
if ok {
if len(c.WhoisInfo) == 0 {
c.WhoisInfo = ch.WhoisInfo
}
delete(clients.ipHost, id)
}
}
// update Name index
clients.list[c.Name] = &c
@@ -402,9 +386,6 @@ func (clients *clientsContainer) Del(name string) bool {
// update Name index
delete(clients.list, name)
// update upstreams cache
delete(clients.upstreamsCache, name)
// update ID index
for _, id := range c.IDs {
delete(clients.idIndex, id)
@@ -468,12 +449,12 @@ func (clients *clientsContainer) Update(name string, c Client) error {
// update Name index
if old.Name != c.Name {
delete(clients.list, old.Name)
clients.list[c.Name] = old
}
// update upstreams cache
delete(clients.upstreamsCache, name)
delete(clients.upstreamsCache, old.Name)
c.upstreamObjects = nil
*old = c
return nil
@@ -513,12 +494,6 @@ func (clients *clientsContainer) AddHost(ip, host string, source clientSource) (
clients.lock.Lock()
defer clients.lock.Unlock()
// check existing clients first
_, ok := clients.findByIP(ip)
if ok {
return false, nil
}
// check auto-clients index
ch, ok := clients.ipHost[ip]
if ok && ch.Source > source {

View File

@@ -13,10 +13,8 @@ type clientJSON struct {
UseGlobalSettings bool `json:"use_global_settings"`
FilteringEnabled bool `json:"filtering_enabled"`
ParentalEnabled bool `json:"parental_enabled"`
SafeSearchEnabled bool `json:"safebrowsing_enabled"`
SafeBrowsingEnabled bool `json:"safesearch_enabled"`
WhoisInfo map[string]interface{} `json:"whois_info"`
SafeSearchEnabled bool `json:"safesearch_enabled"`
SafeBrowsingEnabled bool `json:"safebrowsing_enabled"`
UseGlobalBlockedServices bool `json:"use_global_blocked_services"`
BlockedServices []string `json:"blocked_services"`
@@ -116,11 +114,6 @@ func clientToJSON(c *Client) clientJSON {
Upstreams: c.Upstreams,
}
cj.WhoisInfo = make(map[string]interface{})
for _, wi := range c.WhoisInfo {
cj.WhoisInfo[wi[0]] = wi[1]
}
return cj
}

View File

@@ -114,6 +114,7 @@ func TestClients(t *testing.T) {
c = Client{}
c, b = clients.Find("1.1.1.2")
assert.True(t, b && c.Name == "client1-renamed" && c.IDs[0] == "1.1.1.2" && c.UseOwnSettings)
assert.True(t, clients.list["client1"] == nil)
// failed remove - no such name
if clients.Del("client3") {
@@ -167,18 +168,18 @@ func TestClientsWhois(t *testing.T) {
clients.SetWhoisInfo("1.1.1.1", whois)
assert.True(t, clients.ipHost["1.1.1.1"].WhoisInfo[0][1] == "orgname-val")
// Check that we cannot set whois info on existing client
// Check that we cannot set whois info on a manually-added client
c = Client{
IDs: []string{"1.1.1.2"},
Name: "client1",
}
_, _ = clients.Add(c)
clients.SetWhoisInfo("1.1.1.2", whois)
assert.Nil(t, clients.idIndex["1.1.1.2"].WhoisInfo)
assert.True(t, clients.ipHost["1.1.1.2"] == nil)
_ = clients.Del("client1")
}
func TestClientsAddExistingHost(t *testing.T) {
func TestClientsAddExisting(t *testing.T) {
var c Client
clients := clientsContainer{}
clients.testing = true
@@ -197,9 +198,9 @@ func TestClientsAddExistingHost(t *testing.T) {
assert.True(t, ok)
assert.Nil(t, err)
// try adding a duplicate by IP
// add an auto-client with the same IP - it's allowed
ok, err = clients.AddHost("1.1.1.1", "test", ClientSourceRDNS)
assert.False(t, ok)
assert.True(t, ok)
assert.Nil(t, err)
// now some more complicated stuff
@@ -217,13 +218,21 @@ func TestClientsAddExistingHost(t *testing.T) {
})
assert.Nil(t, err)
// try adding a duplicate IP which for a Mac-based client
ok, err = clients.AddHost(testIP, "test", ClientSourceRDNS)
assert.False(t, ok)
// add a new client with the same IP as for a client with MAC
c = Client{
IDs: []string{testIP},
Name: "client2",
}
ok, err = clients.Add(c)
assert.True(t, ok)
assert.Nil(t, err)
// don't allow duplicates by CIDR
ok, err = clients.AddHost("2.2.2.2", "test", ClientSourceRDNS)
assert.False(t, ok)
// add a new client with the IP from the client1's IP range
c = Client{
IDs: []string{"2.2.2.2"},
Name: "client3",
}
ok, err = clients.Add(c)
assert.True(t, ok)
assert.Nil(t, err)
}

View File

@@ -561,7 +561,9 @@ func decode(ent *logEntry, str string) {
}
switch k {
case "IP":
ent.IP = v
if len(ent.IP) == 0 {
ent.IP = v
}
case "T":
ent.Time, err = time.Parse(time.RFC3339, v)