Unbound (简体中文)

From ArchWiki

Unbound 是一个具有验证,递归和缓存等功能的 DNS 解析器。根据Wikipedia

Unbound has supplanted the Berkeley Internet Name Domain (BIND) as the default, base-system name server in several open source projects, where it is perceived as smaller, more modern, and more secure for most applications.
翻译状态:本文是 Unbound翻译。上次翻译日期:2019-03-24。如果英文版本有所更改,则您可以帮助同步翻译。

安装

安装 unbound 软件包。 此外, expat 是使用DNSSEC验证请求所必须的。

配置

默认配置已经位于/etc/unbound/unbound.conf文件中。此外,/etc/unbound/unbound.conf.example文件包含了其他的可配置设置项,并以注释的形式给出了示范设置。以下章节重点解释和默认配置文件不同的设置项。如需了解更多细节,参见unbound.conf(5)

除非特别声明,这一节列出的选项都是放置在配置文件的server节中,类似这样:

/etc/unbound/unbound.conf
server:
  ...
  setting: value
  ...
注意: 请确保你的配置文件中已经设置了do-daemonize: no,否则unbound.service会无法启动.

本地DNS服务器

如果你想要使用unbound作为本地DNS服务器,请把resolv.conf中的域名服务器(nameserver)设置到回环地址::1127.0.0.1。你可能想要让你的配置Domain name resolution (简体中文)#覆盖 /etc/resolv.conf

提示: 实现这个目的的一个简便方法是安装openresolv,然后取消文件/etc/resolvconf.conf中包含name_servers="::1 127.0.0.1"的那一行的注释。然后运行resolvconf -u来重新生成/etc/resolv.conf

要了解如何测试设置项,参见Domain name resolution#Lookup utilities

在把resolv.conf中的设置更改为持久化设置后,请特别注意检查正在使用的服务器是::1127.0.0.1

你还需要对“unbound”进行设置,以使它#转发查询到你所选择的DNS服务器。

访问控制

你可以通过IP地址来指定响应请求的端口。默认监听的是localhost

为了在所有端口上监听,使用以下配置:

interface: 0.0.0.0

为了通过IP地址来控制可以访问服务器的系统,使用access-control选项:

access-control: subnet action

例如:

access-control: 192.168.1.0/24 allow

action可以是deny (drop message), refuse (polite error reply), allow (recursive ok), or allow_snoop (recursive and nonrecursive ok)中的任意一个。默认除了localhost之外的所有东西都会被拒绝。

使用DNS over TLS进行转发

为了使用这个功能,你需要设置tls-cert-bundle选项来指定本地系统的根证书认证包,以使得unbound可以转发TLS请求并指定允许DNS over TLS的服务器数量。

对每个服务器你都需要用 @ 来指定连接的端口,同时你也要用 # 来指明它的域名是什么。虽然它看起来像注释,the hashtag name allows for the TLS authentication name to be set for stub-zones and with unbound-control forward control command。在 @ 和 # 之间不应该有空格。

/etc/unbound/unbound.conf
...
server:
...
	tls-cert-bundle: /etc/ssl/certs/ca-certificates.crt
...
forward-zone:
        name: "."
        forward-tls-upstream: yes
        forward-addr: 1.1.1.1@853#cloudflare-dns.com

根域名服务器

为了查询一个没有被缓存成地址的主机,解释器需要从服务器树的根开始、对根服务器进行请求来知道去哪里找到目标地址的顶级域名。Unbound内置了一些根节点,但是推荐你提供一个根节点文件给它以免内置的过于老旧。

首先,告诉unbound使用root.hints文件:

root-hints: root.hints

然后把你的root hints文件放进unbound的配置文件夹。实现这个目标最简单的方法是运行下面的命令:

# curl -o /etc/unbound/root.hints https://www.internic.net/domain/named.cache

建议每六个月更新一次root.hints来保持根服务器列表是最新的。你可以手动完成这个任务,也可以使用Systemd/Timers。详情参见#根域名服务器与systemd timer

DNSSEC验证

Tango-view-refresh-red.pngThis article or section is out of date.Tango-view-refresh-red.png

Reason: DNSSEC默认启用.[1]. (Discuss in Talk:Unbound (简体中文))

为了使用DNSSEC验证,你需要在server:节中添加以下设置来告诉unbound服务器根证书文件的位置:

/etc/unbound/unbound.conf
trust-anchor-file: trusted-key.key

/etc/unbound/trusted-key.key是从依赖项dnssec-anchors所提供的的/etc/trusted-key.key复制而来的,它的PKGBUILD按照unbound-anchor(8)生成了/etc/trusted-key.key

如果总的#转发查询设置到了不支持DNSSEC的DNS服务器,那么请确保已经把这些DNS服务器注释掉,否则DNS请求会失败。DNSSEC验证只会在被请求的DNS服务器支持它的时候成功完成。

注意: 如果使用DNSSEC,在地址被缓存之前DNS查询时间将会显著增加。

测试DNSSEC

为了测试DNSSEC是否工作,在starting unbound.service之后:

$ unbound-host -C /etc/unbound/unbound.conf -v sigok.verteiltesysteme.net

得到的回应应该是附带(secure)字样的ip地址。

$ unbound-host -C /etc/unbound/unbound.conf -v sigfail.verteiltesysteme.net

这次的回应应该包含(BOGUS (security failure))字样。

另外你也可以使用“drill”来测试:

$ drill sigok.verteiltesysteme.net
$ drill sigfail.verteiltesysteme.net

第一个命令应该返回NOERRORrcode;而第二个命令应该返回SERVFAILrcode

转发查询

如果你只想转发请求到外部的DNS服务器,请跳到#转发所有其余的请求

允许本地网络使用DNS

使用openresolv

如果你的网络管理器支持openresolv,你可以通过设置来使它提供本地DNS服务器、使用unbound来查询域名。 [2]

/etc/resolvconf.conf
...
private_interfaces="*"

# Write out unbound configuration file
unbound_conf=/etc/unbound/resolvconf.conf

运行resolvconf -u来生成文件。

配置unbound读取openresolv生成的文件并允许回应private IP address ranges

/etc/unbound/unbound.conf
include: "/etc/unbound/resolvconf.conf"
...
server:
...
   private-domain: "intranet"
   private-domain: "internal"
   private-domain: "private"
   private-domain: "corp"
   private-domain: "home"
   private-domain: "lan"

   unblock-lan-zones: yes
   insecure-lan-zones: yes
   ...

另外你可能想要对私有DNS域名空间禁用DNSSEC[3]

/etc/unbound/unbound.conf

...
server:
...
   domain-insecure: "intranet"
   domain-insecure: "internal"
   domain-insecure: "private"
   domain-insecure: "corp"
   domain-insecure: "home"
   domain-insecure: "lan"
...
手动制定DNS服务器

如果你有一个需要DNS请求的本地网络,同时你想要把请求都转发给一个本地的DNS服务器,那么你需要添加这一行:

private-address: 本地子网/子网掩码

例如:

private-address: 10.0.0.0/24
注意: 你可以使用私有地址来防止DNS劫持攻击。为了达到这个目的,你可能需要允许RFC1918网络(10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 169.254.0.0/16 fd00::/8 fe80::/10)。 Unbound的未来版本可能会默认启用这个功能。
包含本地DNS服务器

为了包含一个本地DNS服务器,以用于转发和反代本地地址,类似下面的一组配置是必要的(请把下面的10.0.0.1替换为本地网络中提供DNS服务的服务器的地址):

local-zone: "10.in-addr.arpa." transparent

上面这一行对于让反向查询正常工作是非常重要的。

forward-zone:
name: "mynetwork.com."
forward-addr: 10.0.0.1
forward-zone:
local-data: "1.0.0.127.in-addr.arpa. 10800 IN PTR localhost."
注意: 转发空间和根空间之间的区别是,根空间只有在直接连接到一个authoritative DNS服务器的时候才能正常工作。如果一个BINDDNS服务器提供authoritative DNS,那么这个特性对于来自于它的请求有用——但是如果你在把请求指向一个unbound服务器(内部查询都被转发到另一个DNS服务器),那么把这个指向定义为该机器上的根空间是不会起作用的。在这种情况下,你必须把它定义为上面所说的转发空间,因为转发空间可以通过链式查询去到别的DNS服务器上,亦即转发空间可以把请求指向递归DNS服务器。这个区别是很重要的,因为如果你不恰当地使用根空间,你不会得到能够说明问题的错误信息。

你可以通过下面的配置来设定localhost的前向和反向查询:

local-zone: "localhost." static
local-data: "localhost. 10800 IN NS localhost."
local-data: "localhost. 10800 IN SOA localhost. nobody.invalid. 1 3600 1200 604800 10800"
local-data: "localhost. 10800 IN A 127.0.0.1"
local-zone: "127.in-addr.arpa." static
local-data: "127.in-addr.arpa. 10800 IN NS localhost."
local-data: "127.in-addr.arpa. 10800 IN SOA localhost. nobody.invalid. 2 3600 1200 604800 10800"
local-data: "1.0.0.127.in-addr.arpa. 10800 IN PTR localhost."

转发所有其余的请求

使用openresolv

如果你的网络管理器支持openresolv,你可以通过配置使它提供上游DNS服务器给unbound。 [4]

/etc/resolvconf.conf
...
# Write out unbound configuration file
unbound_conf=/etc/unbound/resolvconf.conf

运行resolvconf -u来生成文件。

最后配置unound读取openresolv生成的文件:

include: "/etc/unbound/resolvconf.conf"
手动指定DNS服务器

为了使本地机器之外的、本地网络外部的默认转发区域使用指定的服务器,请在配置文件中添加一个名字是.的转发区域。在这个例子里,所有的请求都被转发到谷歌的DNS服务器:

forward-zone:
  name: "."
  forward-addr: 8.8.8.8
  forward-addr: 8.8.4.4

使用

启动unbound

Start/enable unbound.service systemd服务。

远程控制unbound

unbound安装的时候自带了unbound-control工具,利用这个工具我们可以远程控制unbound服务器。它和pdnsdpdnsd-ctl命令很类似。

配置unbound-control

在能够使用它之前你需要做下面的事情:

1) 首先,运行:

# unbound-control-setup

来为你的服务器和客户端生成一个self-signed的证书和private key。生成的文件位于/etc/unbound文件夹。

2) 然后,把下面的内容放进/etc/unbound/unbound.conf文件。control-enable: yes是一定要有的,其余的内容可以按照所需进行调整。

remote-control:
   # Enable remote control with unbound-control(8) here.
   # 用unbound-control-setup生成的keys and certificates进行配置。
   control-enable: yes
   # 设定监听哪个地址.
   # give 0.0.0.0 and ::0 to listen to all interfaces.
   control-interface: 127.0.0.1
   # 远程控制用的端口.
   control-port: 8953
   # unbound server key file.
   server-key-file: "/etc/unbound/unbound_server.key"
   # unbound server certificate file.
   server-cert-file: "/etc/unbound/unbound_server.pem"
   # unbound-control key file.
   control-key-file: "/etc/unbound/unbound_control.key"
   # unbound-control certificate file.
   control-cert-file: "/etc/unbound/unbound_control.pem"

使用unbound-control

下面是unbound-control可以使用的一部分命令:

  • 不重置数据的情况下查看统计数据
 # unbound-control stats_noreset
  • 把cache dump到stdout
 # unbound-control dump_cache
  • 清空cache并且重新加载配置
 # unbound-control reload

请参考unbound-control(8)来了解unbound-control支持的操作。

提示与技巧

域名黑名单

你可以打开这个网页adservers,把它的内容保存到/etc/unbound/adservers,然后把下面的配置直接添加到unbound配置文件里就可以了:

/etc/unbound/unbound.conf
server:
...
  include: /etc/unbound/adservers
提示:
  • 为了在查询这些hosts的时候返回OK状态指示,你可以更改默认的127.0.0.1重定向,改成重定向到你所控制的服务器并让那台服务器返回空的204回应,参考[5]
  • 如果需要把其他格式的hosts文件转换成unbound的格式的,请运行这个命令:
    $ grep '^0\.0\.0\.0' hostsfile | awk '{print "local-zone: \""$2"\" always_nxdomain"}' > /etc/unbound/adservers

添加一个authoritative DNS服务器

Tango-inaccurate.pngThe factual accuracy of this article or section is disputed.Tango-inaccurate.png

Reason: 同时运行两个DNS服务器并不一定比只运行一个提供所有功能的DNS服务器更安全。 (Discuss in Talk:Unbound (简体中文))

对于想要在一台机器上同时两个DNS服务器(一个是提供验证、递归、缓存功能的DNS服务器,另一个是authoritative DNS服务器)的用户来说,参考NSD的维基页面可能会有所帮助。那个页面提供了一个示范配置。一个服务器专门响应authoritative DNS请求,另一个服务器提供验证、递归、缓存等DNS功能,这样会比一个服务器提供所有功能会更安全。很多用户已经在使用Bind作为DNS服务器,而针对从Bind变成Bind和NSD协同工作的过程的帮助在NSD页面有提供。

WAN facing DNS

通过更改配置文件和服务器所监听的接口(地址)来允许来自本地网络之外的机器的DNS请求进入本地网络(LAN)内的某台特定机器,这个想法是可行的。这个功能对于公开的网站服务器和邮件服务器是非常有用的。这个在bind上已经实现了多年的技术,通过正确配置防火墙机器上的端口转发——转发这些请求到正确的机器上——也可以在unbound上实现。

根域名服务器与systemd timer

下面是一个systemd服务和timer的示例文件,它用来每隔一个月更新一次root.hints,所用的方法与#根域名服务器中的相同:

/etc/systemd/system/roothints.service
[Unit]
Description=Update root hints for unbound
After=network.target

[Service]
ExecStart=/usr/bin/curl -o /etc/unbound/root.hints https://www.internic.net/domain/named.cache
/etc/systemd/system/roothints.timer
[Unit]
Description=Run root.hints monthly

[Timer]
OnCalendar=monthly
Persistent=true

[Install]
WantedBy=timers.target

最后Start/enable roothints.timer systemd timer就可以了。

疑难解答

有关num-threads的问题

unbound.conf的man page提到:

     outgoing-range: <number>
           Number of ports to open. This number of file  descriptors  can  be  opened  per thread.

网上的一些人建议num-threads这个参数应该设置成你的CPU的核心数量。示范配置文件unbound.conf.example里关于这个选项只有下面这两行:

       # number of threads to create. 1 disables threading.
       # num-threads: 1

但是人为地把num-threads提高到比1就一定会造成unbound在启动的时候在log里写一个warning提示说exceeding the number of file descriptors。实际上对于大多数在小型网络或是单机上运行unbound的用户来说,通过让num-threads超过1来得到性能提升是徒劳的。如果你一定要这么做,那么请参考official documentation。下面这条经验法则应该对你有所帮助:

Set num-threads equal to the number of CPU cores on the system. E.g. for 4 CPUs with 2 cores each, use 8.

outgoing-range设置得尽可能大,参考上面的链接来突破总数是1024这个限制。这样就会使得unbound可以同时为更多客户端提供服务。1个核心设置950,2个核心设置450,四个核心设置200num-queries-per-thread最好设置成outgoing-range的一半。

因为outgoing-range是有限制的,同时num-queries-per-thread也因此受到了限制,所以最好在编译的时候带上libevent,这样就不会有1024限制了。如果你有一个高负荷DNS服务器使得你不得不这样编译,你需要从源码编译unbound而不是直接安装unbound

参阅