pdnsd
pdnsd 是一款旨在实现 DNS 信息本地缓存的 DNS 服务器。配置得当后,它可以显著提高宽带连接的网页浏览速度。与 BIND 或 dnsmasq 相比,它可以在重启后保留缓存;“p”代表持久性(persistent)。关于与其他 DNS 服务器的比较,请参阅 域名解析#DNS 服务器。
安装
配置
该软件包附带了一个示例配置文件,位于 /usr/share/doc/pdnsd/pdnsd.conf。自定义配置文件应创建在 /etc/pdnsd.conf。
格式
pdnsd.conf 文件使用一种相当简单的格式,但与你可能遇到的大多数其他配置文件有所不同。它包含一系列不同类型的片段。片段以片段类型名称和一个左花括号 ({) 开始,以一个右花括号 (}) 结束。片段不能嵌套。
每个块内部是一系列格式如下的选项
option_name=option_value;
请注意末尾的分号;与某些格式不同,它是不可省略的。
注释以 # 或 /* 开头。前者持续到行尾,后者持续到遇到 */ 为止。
DNS 服务器
pdnsd 需要知道至少一个 DNS 服务器的地址才能从中收集 DNS 信息。这部分的设置取决于你是宽带连接还是拨号连接。宽带用户应以第一个服务器片段作为起点,拨号用户则使用第二个,并将其他服务器片段注释掉。
- label
label选项用于唯一标识一个服务器片段。它是完全任意的,但一个好的选择是你的 ISP 名称。- ip
- 此选项用于默认的宽带配置,告诉 pdnsd 要使用的 DNS 服务器地址。多个地址应以单个逗号分隔,逗号前后可留有可选的空格。你可以直接从
/etc/resolv.conf复制地址。 - file
- 可以使用
file选项代替ip来指定一组 DNS 服务器 IP。其值是采用resolv.conf格式列出服务器的文件路径。默认的拨号配置使用它,因为 PPP 客户端会将从 PPP 服务器获取的地址写入/etc/ppp/resolv.conf。除非你想使用 ISP 默认分配之外的 DNS 服务器,否则无需更改此项。 - interface
- 用于 uptest=if 选项的网络接口。默认值为 eth0,这很可能是错误的。如果 pdnsd 服务已启动但不返回任何 DNS 记录,可能是此处设置有误。
其余的服务器片段无需更多更改即可正常工作。有关所有可用选项的详细信息,请参阅 pdnsd 手册。
使用 DHCP 连接的 DNS 服务器
安装 netctl 后,openresolv 可以通知 pdnsd 域名服务器的 IP 地址,并且当你使用 配置文件的自动切换 时,这些通知将变为动态。
要配置此功能,请删除宽带服务器片段,并按以下更改更新拨号服务器片段
label = resolvconf; file = /etc/pdnsd-resolv.conf;
编辑 /etc/resolvconf.conf,将 openresolv 配置为使用 pdnsd 作为其订阅者之一
name_servers=127.0.0.1 pdnsd_resolv=/etc/pdnsd-resolv.conf
然后运行 resolvconf -u 以使用域名服务器的地址更新 /etc/pdnsd-resolv.conf(忽略关于无法访问 pdnsd 套接字的错误消息)。此更新仅需在手动启动 pdnsd 之前执行一次。
OpenDNS
pdnsd.conf 文件自带了内置的 OpenDNS 设置;你可以简单地删除(或注释掉)其上方的拨号和宽带片段(注意不要删除文件最顶部的必要全局设置),然后取消注释即可使用 OpenDNS 解析。
然而,OpenDNS 对 Google 的处理方式有些奇怪。如果你想避免这种行为(对许多人来说,这会将 Google 的请求时间从 15ms 增加到 75ms 以上),你需要拒绝来自 OpenDNS 且指向 OpenDNS 的 Google 代理服务器的结果。确切的服务器 IP 会变动,但你可以运行 drill www.google.com @208.67.222.222(由 ldns 提供)来查找当前的 IP。如果查询被代理,你会知道,因为服务器名称会解析为类似 google.navigation.opendns.com 的地址。在某次尝试中,这些地址是 208.67.216.230 和 208.67.216.231。
一旦确定了 IP,就可以在 OpenDNS 的 server { … } 声明中替换 pdnsd.conf 中已存在的 rejected IP。确保保留前缀。
OpenNIC 是 OpenDNS 的一个可靠替代方案。
测试
现在你应该拥有一个正常工作的 pdnsd 守护进程。启动它。
测试它现在是否正常工作。
第二次使用 127.0.0.1 查询任何地址时,查询时间应低于 1 毫秒。
系统设置
确保 启用 pdnsd.service。
它在 network.target 之后立即启动,因为使用网络的各种服务依赖于有效的 DNS,即 network-online.target(参见上游说明)。
对于任何拥有两个或多个网卡的 PC,为了使 pdnsd 在任何有线和无线连接上都能运行,请通过指定正确的 interface 为每个网卡在 pdnsd.conf 中配置单独的片段。
技巧与提示
家庭宽带用户的性能设置
许多用户的宽带连接 DNS 服务器缓慢或不可靠,他们希望使用 pdnsd 作为缓存服务器来最小化需要执行的 DNS 查询数量。在完成上述详细设置后,/etc/pdnsd.conf 中的以下设置将有助于在此场景下提高性能
在全局设置下
neg_rrs_pol=on; par_queries=1;
在服务器设置下
proxy_only=on; purge_cache=off;
neg_rrs_pol=on; 策略意味着当查询返回负面响应时,即使响应不是“权威的”,pdnsd 服务器也会缓存该结果。这一点很重要,因为观察 DNS 查询会发现有很多针对 AAAA 记录(IPv6 的 DNS 查询)的请求,由于许多域名不使用 IPv6,它们永远不会返回结果;MX 记录也是如此,因为并非每个域名都有 MX 记录。如果没有负面缓存,即使域名已被缓存,这些请求仍会被发送。在此场景下,你不希望产生额外的 DNS 请求。将此选项与 proxy_only=on; 选项结合使用,对于最小化系统发出的查询数量非常重要。
如果你在下方的“server”片段中指定了不止一个 DNS 服务器,par_queries=1; 选项非常有用。它指定了一次并行查询的增量。例如,如果在“server”片段中列出了四个 DNS 服务器,且 par_queries=2;(默认值),则会同时查询前两个服务器;如果前两个服务器都失败,pdnsd 将继续查询后两个。上述设置意味着一次只查询一个 DNS 服务器,因此你可以在“server”片段中列出两个或多个 DNS 服务器,只有当第一个失败时才会查询第二个。这有助于最大限度地减少流量,但如果第一个服务器失败,你必须等待超时后才会查询第二个。请根据自己的偏好调整此设置;如果你在“server”片段中只指定了一个服务器,则无需担心此问题。
proxy_only=on; 设置在下方的 FAQ 中有提到,对于家庭宽带用户很重要,因为你通常只使用一个或两个 DNS 服务器,而不是尝试进行完整的层级名称解析(这是完整 DNS 服务器会做的)。此设置将阻止 pdnsd 一直回溯到“权威”名称服务器,而是接受已在“server”片段中指定的 DNS 服务器的结果。同样,这减少了你需要进行的 DNS 查询数量,提高了性能。
purge_cache=off; 设置告诉 pdnsd 即使缓存条目已超过 DNS 记录的生存时间(TTL)也不要删除它们。当你的 ISP 的 DNS 服务器宕机,而你又希望在宕机期间仍能访问常用域名的名称解析时,这非常有用。一旦缓存填满,记录仍会根据存活时间被逐出缓存(关于如何设置缓存大小,请参阅 pdnsd.conf(5))。
其他性能设置
TTL(生存时间)
从服务器返回的每个 DNS 资源记录都包含一个最大生存时间,即 TTL。这告诉接收者将记录存储多长时间,以及何时对其执行新的查找。许多 DNS 记录的 TTL 相对较短,例如 3600(一小时)。这意味着一小时后,无论 pdnsd 是否有可用的缓存记录,它都会尝试执行新的查找。通过设置全局最小 TTL 来覆盖此默认 TTL,可以减少执行的查找次数,从而提高性能。使用过长的最小 TTL 的缺点是缓存记录可能已过期(主机的 IP 地址可能已更改,但你的客户端因收到缓存的地址而无法获知)。然而,大多数 IP 地址并不会每小时甚至每天更改一次。
时间默认以秒为单位指定,或者你可以通过在时间后附加“m”、“h”、“d”或“w”来指定分钟、小时、天或周。
全局设置中的 min_ttl 设置了缓存记录的最小 TTL,导致 pdnsd 忽略从服务器收到的记录中的默认 TTL。在连接缓慢或 DNS 服务器缓慢的情况下,你可能希望将其设置为几个小时以减少查找次数(例如 min_ttl=6h;)。
全局设置中的 neg_ttl 为不存在的域名设置了最小 TTL。如果服务器告诉 pdnsd 某个域名不存在,它将不会在该时间段过后再次尝试查找该域名。
超时时间
设置较短的超时时间意味着 pdnsd 会更快地放弃整个查询或特定的服务器查询,从而实现更快的性能。设置过短超时时间的缺点是,pdnsd 可能仅仅因为没有给予服务器足够的响应时间就返回查找错误。
全局设置中的 timeout 决定了 pdnsd 何时放弃整个查询并向你的浏览器或其他客户端返回错误。设置全局超时选项使得在服务器片段中指定相当短的超时时间成为可能(见下文)。这将产生这样的效果:如果第一批服务器响应缓慢,pdnsd 会相当快地开始查询其他服务器(但仍会继续监听来自第一批服务器的响应)。(如果你使用 query_method=tcp_udp,建议将全局超时至少设为最大服务器超时的两倍,否则如果 TCP 连接超时,pdnsd 可能没有时间尝试 UDP 查询。)
全局设置中的 tcp_qtimeout 决定了 TCP 查询连接可以保持打开的时间。
服务器设置中的 timeout 决定了 pdnsd 等待每个服务器响应的时间。将其设置为较短的时间意味着 pdnsd 会更快地放弃无响应的服务器并转向下一个可用服务器,有时会带来更快的整体响应时间。在快速连接上,将其设置为 4 或 5 秒是合理的。
调试
要查看 pdnsd 在特定查找中使用了哪些服务器、超时是如何工作的以及域名使用了哪些默认 TTL,请在全局设置中开启调试功能
debug=on;
重启 pdnsd 并使用 systemd journal 监控 pdnsd.service 的变化
# journalctl -f -u pdnsd.service
确保在一般使用时关闭调试功能,因为保持开启可能会降低性能。
缓存大小
默认情况下,pdnsd 会自动为 /etc/hosts 中的所有条目创建权威记录。如果你有很多条目,例如将它用于广告屏蔽,/etc/pdnsd.conf 提供的默认最大缓存大小可能不够,导致 DNS 请求无法按预期时间被缓存。
要增加缓存大小,请编辑配置文件“全局设置”片段中的 perm_cache 行(大小以 kB 为单位)。
或者,你可以通过在“source”片段中添加 authrec=off 选项来防止 pdnsd 预先加载你的 hosts 文件。如果出于某种原因设置 authrec=off 不起作用,一个简单的变通方法是创建一个单独的 hosts 文件(例如 /etc/hosts-pdnsd)只包含你的系统信息,并将“source”片段指向该文件,同时保留原始的 hosts 文件。这样,pdnsd 仅在执行查找时才会引用 /etc/hosts。例如
/etc/hosts-pdnsd
#<ip-address> <hostname.domain.org> <hostname> 127.0.0.1 localhost.localdomain my_hostname ::1 localhost.localdomain localhost
局域网共享服务器
如果你网络中有几台计算机,可能希望让 pdnsd 成为它们共同的 DNS 服务器。这允许整个网络共享一个 DNS 缓存,从而使重复查找快得多。要允许这样做,只需在 global 片段中将 server_ip 设置为你的网络接口名称(通常是 eth0)。如果你配置了防火墙,请告知它允许来自网络上任何地址的 53 端口连接。
现在,你可以将网络上的其他计算机配置为使用运行 pdns 的计算机作为其主 DNS 服务器。
域名屏蔽
pdnsd 允许你指定永远不应返回结果的主机或域名。这允许你将其用作原始的广告或内容拦截器等。在 pdnsd.conf 中创建一个新的 neg 片段。neg 片段有两个主要选项。name 是你要屏蔽的主机或域名名称。types 可以设置为 domain 以屏蔽给定域名下的所有主机。默认的 pdnsd.conf 提供了一个屏蔽 doubleclick.net 所有广告的示例。
由于每个块只能设置一个域名,这对于直接在 pdnsd.conf 中屏蔽广告、跟踪器或恶意内容来说扩展性不好。你可能希望专门为这些列表创建单独的配置文件,例如 /etc/pdnsd.d/spam_domains,并在 pdnsd.conf 中添加 include 片段,像这样
include {file="/etc/pdnsd.d/spam_domains";}
或者,可以添加一个 source 片段(除加载 /etc/hosts 的现有片段外),加载一个将域名绑定到特殊 IP 地址 0.0.0.0 的 /etc/hosts 格式文件——但这不会屏蔽子域名,因为 /etc/hosts 不允许通配符。这样做等同于将规则添加到 /etc/hosts,但避免了拥有一个庞大的 /etc/hosts,这可能会破坏某些应用程序。
pdnsd-ctl
- pdnsd-ctl 控制 pdnsd,一个具有持久缓存功能的代理 DNS 服务器。请注意,在使用 pdnsd-ctl 之前,必须启用状态控制套接字(通过在 pdnsd 命令行或配置文件中指定选项)。
为此,请包含以下选项
status_ctl = on;
在 /etc/pdnsd.conf 的全局片段中。
如果你更改了 /etc/pdnsd.conf 中的缓存目录,则必须使用 -c 选项运行 pdnsd-ctl
# pdnsd-ctl -c path/to/cache
一些有用的入门命令……
查看缓存
# pdnsd-ctl dump
清除缓存
# pdnsd-ctl empty-cache
DNSCrypt
pdnsd 可以与 DNSCrypt 一起使用。DNSCrypt 会加密域名查找。pdnsd 在必要时会查询 DNSCrypt。配置示例可以在 DNSCrypt#pdnsd 中找到。
故障排除
192.168.x.x 的 uptest 结果:失败
即使日志显示以下内容,你也可以成功 ping 通 ISP 的 动态 DNS 服务器
# journalctl -f -u pdnsd.service
result of uptest for 192.168.x.x: failed
检查 /etc/pdnsd.conf 全局片段中配置的接口是否存在
interface = any;
或者服务器片段中的那个
interface=enp2s0;
可以通过运行 ifconfig 找到正确的名称。
常见问题
- 问)我感觉不到它快多少。为什么?
- 答) 运行本地 DNS 缓存获得的额外速度全在于连接服务器所需的时间。人们通常认为的“速度”(吞吐量)不会受到影响。当你浏览网页时差异最明显,因为这通常涉及从多个服务器进行小文件下载。对于较慢的连接(尤其是拨号上网),吞吐量是主要瓶颈,因此百分比上的差异不会那么大。
- 问)为什么现在比以前慢多了?
- 答) 你几乎肯定在
pdnsd.conf的某个服务器片段中关闭了proxy_only选项。默认情况下,pdnsd 会频繁询问多个 DNS 服务器以获取尽可能准确的响应。proxy_only选项禁用了此功能。如果你使用 ISP 提供的 DNS 服务器,则应开启该选项。