DNS 过滤规则语法
在这篇文章中,我们展示如何编写自定义 DNS 过滤规则,以便在 AdGuard 产品中使用。
前言
用户可以使用 AdGuard DNS 过滤规则语法使规则更加灵活,以便它们能够根据您的偏好屏蔽内容。 AdGuard DNS 过滤规则语法可用于不同的 AdGuard 产品,如 AdGuard Home、 AdGuard DNS、 Windows/Mac/Android 的 AdGuard。
这是三种不同的编写主机拦截列表方法:
Adblock-style 的语法是基于使用 Adblock 风格的规则语法子集编写过滤规则的现代方法。 这样阻止拦截列表与浏览器广告拦截器兼容。
/etc/hosts
语法:使用与操作系统处理其主机文件相同的语法的老式、经过实践检验的语法。Domains-only 语法是一个简单的域名列表。
如果用户要创建拦截列表,我们建议使用 Adblock-style 语法。 与旧式语法相比,它有几个重要的优点:
拦截列表大小。使用模式匹配允许您拥有单个规则,而不是数百个
/etc/hosts
条目。兼容性。您的屏蔽列表将与浏览器广告拦截器兼容,并且与浏览器过滤器列表共享规则会更容易。
可扩展性。在过去的十年中,Adblock 风格的语法有了很大的发展,我们认为我们能进一步扩展它并为网络范围的拦截器提供额外的功能。
如果用户要维护 /etc/hosts
样式的拦截列表或过滤列表(无论类型),我们提供一个用于编写拦截列表的工具。 我们将其命名为 Hostlist 编译器 ,我们自己使用它来创建 AdGuard DNS 过滤器。
基本示例
||example.org^
:阻止访问example.org
域及其所有子域,例如www.example.org
。@@||example.org^
:取消阻止对example.org
域及其所有子域的访问。1.2.3.4 example.org
:(注意,旧的/etc/hosts
语法)在 AdGuard Home 里用1.2.3.4
对example.org
域名的查询,但 没有 其子网域的查询。 在私人 AdGuard DNS 中,阻止对example.org
的访问。www.example.org
仍然允许。在 AdGuard Home 中,对主机使用未指定的 IP 地址(
0.0.0.0
)或本地地址(127.0.0.1
等)基本上等同于拦截该主机。# 返回 example.org 的 IP 地址 1.2.3.4。
1.2.3.4 example.org
通过响应 0.0.0.0 来阻止 example.org。
0.0.0.0 example.org
- `example.org`:一个简单的域规则。 阻止 `example.org` 域,而**不是**其子域。 `www.example.org` 仍然允许。
- `! 这是一行注释`和`# 这也是一行注释`:注释。
- `/REGEX/`:拦截访问与特定的正则表达式匹配的域名。
## Adblock-style 语法 {#adblock-style-syntax}
这是[传统 Adblock-style 语法][] 的子集,浏览器广告拦截程序使用这种语法。
```none
rule = ["@@"] pattern [ "$" modifiers ]
modifiers = [modifier0, modifier1[, ...[, modifierN]]]
pattern
:主机名掩码。 每个主机名都与此掩码匹配。 该模式还可以包含特殊字符,如下所述。@@
: 用于例外的标记规则。 如果用户想取消匹配主机名的过滤,请在规则开头添加此标记。modifiers
:阐明规则参数。 规则参数有可能会限制规则的范围,甚至完全改变它们的工作方式。
特殊字符
*
: 通配符字符。 它用于表示任何字符集。 这也可以是一个空的字符串或者是任意长度的字符串。||
:匹配主机名的开头,包括任何子域名。 例如,||example.org
匹配example.org
和test.example.org
,但不匹配testexample.org
。^
:分隔符字符。 与浏览器广告拦截不同,主机名中没有什么可以分隔的,因此该字符的唯一目的是标记主机名的结尾。|
:指向主机名开头或结尾的指针。 该值取决于掩码中的字符位置。 例如,规则ample.org|
对应于example.org
但不对应于example.org.com
。|example
对应于example.org
但不对应于test.example
。
正则表达式
如果用户希望更加灵活地制定规则,可以使用正则表达式代替默认的简易匹配语法。 如果用户要使用正则表达式,则必须使用如下格式:
pattern = "/" regexp "/"
例如:
/example.*/
将拦截与example.*
正则表达式匹配的主机。@@/example.*/$important
将取消拦截和匹配example.*
的正则表达式。 请注意,此规则也包含important
修饰符。
注释
任何以感叹号或井号开头的行都是注释,过滤引擎将忽略它。 注释通常放在规则之上,用于描述规则。
例如:
! 这是一条注释
# 这也是一条注释
规则修改器
用户可以添加修饰符来更改规则的行为。 修饰符必须位于规则末尾的 $
字符之后,并用逗号分隔。
例如:
||example.org^
是匹配模式。$
是分隔符,表示规则的其余部分是修饰符。important
是修饰符。用户可能希望在一条规则中使用多个修饰符。 在这种情况下,用逗号分隔它们:
||example.org^$client=127.0.0.1,dnstype=A
||example.org^
是匹配模式。$
是分隔符,表明规则的其余部分是修饰符。client=127.0.0.1
是client
修饰符,其值是127.0.0.1
。,
是修饰符之间的分隔符。 最后,dnstype=A
是dnstype
修饰符,其值为A
。
注意: 如果规则包含本文档中未列出的修饰符,整个规则将被忽略。 通过这种方式,当人们尝试使用未经修改的浏览器广告拦截器的过滤器列表(如 EasyList 或 EasyPrivacy)时,我们可以避免误报。
client
client
修饰符允许指定应用此规则的客户端。 识别客户端的主要方法有两种:
通过其 IP 地址或 CIDR 前缀。 这种方式适用于所有类型的客户端。
通过名称。 这种方式仅适用于用户手动添加的持久性客户端(在 AdGuard Home 中)和设备(在私人 AdGuard DNS 中)。
注意: 在 AdGuard Home 中,目前不支持 ClientID,仅支持名称。 如果用户添加了一个客户端,名称为 "My Client",ClientID 为
my-client
,将修饰符拼成$client='My Client'
,而不是$client=my-client
。
语法为:
$client=value1|value2|...
用户还可以通过在值前添加 ~
字符来排除客户端。 在这种情况下,该规则不会应用于此客户端的 DNS 请求。
$client=~value1
客户端名称通常包含空格或其他特殊字符,这也是用户应该将名称括在引号中的原因。 单、双 ASCII 引号都可以。 使用反斜杠 (\
) 来转义引号 ("
和 '
) ,逗号 (,
) 和竖线 (|
) 。
注意: 排除客户端时,用户必须将 ~
放在引号外。
例如:
@@||*^$client=127.0.0.1
: 取消拦截本地主机的所有内容。||example.org^$client='Frank\'s laptop'
:仅对名为Frank's laptop
的客户端拦截example.org
。 请注意,名称中的引号 ('
) 必须转义。||example.org^$client=~'Mary\'s\, John\'s\, and Boris\'s laptops'
: 除了名为Mary's, John's, and Boris's laptops
的客户端,为其他所有人拦截example.org
。 请注意,逗号 (,
) 也必须转义。||example.org^$client=~Mom|~Dad|Kids
:只对Kids
拦截example.org
,但不对Mom
和Dad
拦截它。 此示例演示如何在一个规则中指定多个客户端。||example.org^$client=192.168.0.0/24
:为 IP 地址在192.168.0.0
到192.168.0.255
范围内的所有客户端拦截example.org
。
denyallow
您可以使用 denyallow
修饰符从拦截规则中排除域。 若要将多个域添加到一个规则,请使用 |
字符作为分隔符。
语法为:
$denyallow=domain1|domain2|...
当屏蔽规则覆盖了太多的域名时,该修饰符可避免创建不必要的额外规则。 您可能希望拦截除几个 TLD 域之外的所有内容。 用户可以使用标准方法,即以下规则:
! 屏蔽一切。
/.*/
! 取消对一些 TLD 的屏蔽。
@@||com^
@@||net^
这种方法的问题在于,通过这种方式,用户也会取消拦截位于这些 TLD 上的跟踪域名(即 google-analytics.com
)。 下面是用 denyallow
来解决此问题的方法:
*$denyallow=com|net
例如:
*$denyallow=com|net
: 除了*.com
和*.net
以外拦截所有内容。@@*$denyallow=com|net
:除了*.com
和*.net
以外取消拦截所有内容||example.org^$denyallow=sub.example.org
。 拦截example.org
和*.example.org
,但不拦截sub.example.org
。
dnstype
dnstype
修饰符允许指定将触发此规则的 DNS 请求或响应类型。
语法为:
$dnstype=value1|value2|...
$dnstype=~value1|~value2|~...
类型的名称不区分大小写,但会根据一组实际的 DNS 资源记录(RR)类型进行验证。
不要将排除规则与包含规则结合使用。 例如:
$dnstype=~value1|value2
相当于:
$dnstype=value2
例如:
||example.org^$dnstype= AAAA
:拦截对example.org
的 IPv6 地址的 DNS 查询。||example.org^$dnstype=~A|~CNAME
:只允许A
和CNAME
对example.org
进行 DNS 查询 ,拦截其余部分。
注意: 在 v0.108.0 版本之前,AdGuard Home 会使用请求的类型来过滤响应记录,而不是响应记录本身的类型。 这造成了一些问题,因为这意味着用户不能编写规则,允许在 A
和 AAAA
请求的响应中出现某些 CNAME
记录。 在 v0.108.0 版本中,该行为已更改,因此现在如下所示:
||canon.example.com^$dnstype=~CNAME
允许用户避免过滤以下响应:
应答:
-> example.com
canonical name = canon.example.com.
ttl = 60
-> canon.example.com
internet address = 1.2.3.4
ttl = 60
dnsrewrite
dnsrewrite
响应修饰符允许替换匹配主机的 DNS 请求的响应内容。 请注意,AdGuard Home 中的这个修饰符对所有规则都有效,但在私人 AdGuard DNS 中,只对自定义规则有效。
具有 dnsrewrite
响应修饰符的规则比 AdGuard Home 中的其他规则具有更高的优先级。
所有与匹配 dnsrewrite
规则的主机相关的请求响应将会被替换。 替换响应的应答部分将只包含与请求查询类型匹配的 RR 记录和可能的 CNAME RR 记录。 请注意,这意味着,如果主机匹配了某个 dnsrewrite
规则,一些请求的响应可能会变为空白(NODATA
)。
简写语法是:
$dnsrewrite=1.2.3.4
$dnsrewrite=abcd::1234
$dnsrewrite=example.net
$dnsrewrite=REFUSED
关键字必须全部大写(例如 NOERROR
)。 关键字重写优先于其他,并将导致具有适当响应代码的空响应。
完整的语法格式为 RCODE;RRTYPE;VALUE
:
$dnsrewrite=NOERROR;A;1.2.3.4
$dnsrewrite=NOERROR;AAAA;abcd::1234
$dnsrewrite=NOERROR;CNAME;example.net
$dnsrewrite=REFUSED;;
具有 NOERROR
响应代码的 $dnsrewrite
修饰符也可能具有空的 RRTYPE
和 Value
字端。
CNAME
是特殊的,因为 AdGuard Home 将解析主机并将其信息添加到响应中。 也就是说,如果 example.net
的 IP 是 1.2.3.4
,并且用户的过滤规则中有以下内容:
||example.com^$dnsrewrite=example.net
! 或:
||example.com^$dnsrewrite=NOERROR;CNAME;example.net
然后响应将如下所示:
nslookup example.com my.adguard.local
Server: my.adguard.local
Address: 127.0.0.1#53
Non-authoritative answer:
example.com canonical name = example.net.
Name: example.net
Address: 1.2.3.4
接下来, CNAME
重写。 之后,汇总所有其他记录的值为一个响应,因此:
||example.com^$dnsrewrite=NOERROR;A;1.2.3.4
||example.com^$dnsrewrite=NOERROR;A;1.2.3.5
将产生有两个 A
记录的响应。
当前支持带有示例的 RR 类型:
||4.3.2.1.in-addr.arpa^$dnsrewrite=NOERROR;PTR;example.net.
添加了一个反向 DNS 的PTR
记录。 向 DNS 服务器发出的1.2.3.4
反向 DNS 请求将产生example.net
。注意: IP 地址必须按反向顺序排列。 参见 RFC 1035。
||example.com^$dnsrewrite=NOERROR;A;1.2.3.4
添加了一个值为1.2.3.4
的A
记录。||example.com^$dnsrewrite=NOERROR;AAAA;abcd::1234
添加了一个值为abcd::1234
的AAAA
记录。||example.com^$dnsrewrite=NOERROR;CNAME;example.org
添加一个CNAME
记录。 见上述解释。||example.com^$dnsrewrite=NOERROR;HTTPS;32 example.com alpn=h3
添加一个HTTPS
记录。 仅支持参数值的子集:值必须连续
,并且,如果值列表
是可预见的
,则当前仅支持一个值:ipv4hint=127.0.0.1 // 支持。
ipv4hint="127.0.0.1" // 不支持。
ipv4hint=127.0.0.1,127.0.0.2 // 不支持。
ipv4hint="127.0.0.1,127.0.0.2" // 不支持。这点在将来会有所改变。
||example.com^$dnsrewrite=NOERROR;MX;32 example.mail
添加一个MX
记录,优先级值为32
,交换值为example.mail
。||example.com^$dnsrewrite=NOERROR;SVCB;32 example.com alpn=h3
添加一个SVCB
值。 请参阅上面的HTTPS
示例。||example.com^$dnsrewrite=NOERROR;TXT;hello_world
添加一个TXT
记录,其值为hello_world
。||_svctype._tcp.example.com^$dnsrewrite=NOERROR;SRV;10 60 8080 example.com
添加一条SRV
记录,优先级值10
,权重值60
,端口8080
,目标值example.com
。||example.com^$dnsrewrite=NXDOMAIN;;
以NXDOMAIN
代码进行响应。$dnstype=AAAA,denyallow=example.org,dnsrewrite=NOERROR;;
以空的NOERROR
响应所有AAAA
的请求,除了example.org
。
例外规则可以解除一条或所有规则的拦截。
@@||example.com^$dnsrewrite
删除所有 DNS 重写规则。@@||example.com^$dnsrewrite=1.2.3.4
域名解析到IP地址1.2.3.4
的A
的 DNS 重写规则已解除阻止。
important
应用于规则 important
修饰符,会增加其优先级,高于其他没有修饰符的规则。 甚至高于基本的例外规则。
例如:
例如:
||example.org^$important
@@||example.org^||example.org^$important
将拦截所有对*.example.org
的请求,即使有例外规则。例如:
||example.org^$important
@@||example.org^$important例外规则也有
important
修饰符,所以会起作用。
badfilter
具有 badfilter
修饰符的规则将禁用其所引用的其他基本规则。 这意味着禁用规则的文本应该与 badfilter
规则的文本匹配(没有 badfilter
修饰符)。
例如:
||example.com$badfilter
禁用||example.com
.@@||example.org^$badfilter
禁用@@||example.org^
.注意:目前
badfilter
修饰符不能与/etc/hosts
样式规则一起使用。127.0.0.1 example.org$badfilter
无法禁用原始127.0.0.1 example.org
规则 。
ctag
ctag
修饰符只能在 AdGuard Home 中使用。
它仅允许拦截特定类型的 DNS 客户端标记的域名。 用户可以在 AdGuard Hone 界面中为客户端分配标签。 将来,我们计划通过分析每个客户端的行为来自动分配标签。
语法为:
$ctag=value1|value2|...
如果客户端的一个标签与 ctag
值相匹配,则此规则适用于该客户端。 排除的语法为:
$ctag=~value1|~value2|...
如果客户端的一个标签与 ctag
值相匹配,则此规则不适用于该客户端。
例如:
||example.org^$ctag=device_pc|device_phone
:为标记为device_pc
或device_phone
的客户端拦截example.org
。||example.org^$ctag=~device_phone
:为除了标记为device_phone
的客户端以外的所有客户端,拦截example.org
。
允许的标签列表:
按设备类型:
device_audio
:音频设备device_camera
:相机device_gameconsole
:游戏机device_laptop
:笔记本电脑device_nas
:NAS(网络附属存储)device_pc
:个人计算机device_phone
:手机device_printer
:打印机device_securityalarm
:安全警报device_tablet
:平板电脑device_tv
:电视device_other
:其他设备
按操作系统:
os_android
: Androidos_ios
:iOSos_linux
:Linuxos_macos
:macOSos_windows
:Windowsos_other
:其他操作系统
按用户组:
user_admin
:管理员user_regular
:普通用户user_child
:儿童
/etc/hosts
样式语法
对于每个主机,都应该有一个包含以下信息的单行:
IP_address canonical_hostname [aliases...]
条目的字段由任意数量的空格或制表符分隔。 从 #
字符到行尾的文本是注释,将被忽略。
主机名只能包含字母数字字符、连字符-减号 (-
) 和句号 (.
) 。 它们必须以字母字符开头,以字母数字字符结尾。 可选的别名提供了名称变更、替代拼写、更短的主机名或通用主机名(例如, localhost
)。
例如:
# 这是一个注释
127.0.0.1 example.org example.info
127.0.0.1 example.com
127.0.0.1 example.net # 这也是一个注释
在 AdGuard Home 中,IP 地址用于响应这些域的 DNS 查询。 在私有 AdGuard DNS 中,这些 IP 地址被拦截。
仅限域的语法
一个简单的域名列表,每行一个域名。
例如:
# 这是一个注释
example.com
example.org
example.net # 这也是一个注释
如果字符串不是有效域(例如 *.example.org
),AdGuard Home 将 认为它是 Adblock-style 的语法规则。
主机清单编译器
如果您正在维护一个拦截列表并在其中使用不同的源代码, Hostlist 编译器可能对您有用。 这是一个简单的工具,可以更轻松地编译与 AdGuard Home、私有 AdGuard DNS 或任何其他具有 DNS 过滤功能的 AdGuard 产品兼容的主机拦截列表。
功能:
从多个源编译单个黑名单。
排除不需要的规则。
清理生成的列表:重复数据删除、删除无效规则和压缩列表。