之前在MacOS上遇到过这个问题,这次在Debian上也遇到了,同一个问题在两个不同的类Unix系统上解决起来还有些不一样。
前文写过,在MacOS上,可以通过在/etc/resolver中按需增加域名的文件,系统在发起DNS请求时,就会优先命中,从而使用文件内指明的DNS服务器,但是这个方法在Debian上就行不通了。
1. 原因
MacOS上,DNS查询操作,进程会通过IPC交给内置的引擎mDNSResponder来处理,而/etc/resolver/就是专门用来给查询做分流用,这是在设计层面便支持这个操作。
而Debian的设计,没有分流这个操作,发起DNS查询请求时,会按顺序向 /etc/resolv.conf 中配置的服务器查询,直到得到一个结果(NXDOMAIN也算结果)。而Tailscale在启动后,会修改resolv.conf文件,将全局DNS指向自己的DNS服务器,使得所有DNS查询走的都是 100.100.100.100 。
所以,要想实现DNS分流,就需要再引入一个角色,来接管所有的查询,按需分流,我选的是systemd-resolved,比 dnsmasq 更加合适。
安装和启动:
1 | $ sudo apt update |
2. 原理
systemd-resolved会在本地 127.0.0.53:53 起一个服务,然后修改 /etc/resolv.conf,将全局DNS服务器指向自己,从而接管所有DNS查询。
Tailscale启动时,如果发现systemd-resolved在运行,则不会修改 /etc/resolv.conf,而是把自己的分流规则告诉它。
systemd-resolved运行后,需要重启一下Tailscale,注意是守护进程,而不是服务, tailscale down && tailscale up 是重启服务的:
1 | $ sudo systemctl restart tailscaled |
通过以下命令可查看systemd-resolved的状态:
1 | $ resovlectl status |
3. 配置
默认状态下,resolved没有缺省的全局DNS服务器,需要手动添加一个,它的配置文件在这,systemd开头的服务,都统一在systemd下,而不是独占etc下的一个目录:
1 | /etc/systemd/resolved.conf |
但这个默认配置文件在服务升级时,可能会被修改或者覆盖,更常见的配置方式是,创建一个配置目录,然后在目录中单独增加配置,配置目录中的配置会按字母顺序加载,后面的会覆盖或者追加前面的配置,因此,配置目录中的配置文件一般都以数字开头,数字越大优先级越高:
1 | $ mkdir -p /etc/systemd/resolved.conf.d/ |
还可以按需添加配置文件,比如20-name-dns.conf。
4. libnss-resolve
查看Name Service Switch的配置文件,可以看到有一行是这么写的:
1 | $ cat /etc/nsswitch.conf |
意思是,当需要查询DNS时,先查找/etc/hosts文件,然后再根据 /etc/resov.conf 发起DNS查询请求,这时会向 127.0.0.53:53 发送DNS查询报文。
以上流程,是配置后的正常流程。查询DNS的进程,和resolved的进程,这两个进程实际上可以通过更快的IPC方式进行通信:D-Bus IPC,而不是发送报文,只需再安装个libnss-resolve:
1 | $ sudo apt update |
安装过程中,Debian会自动运行配置脚步,完成之后,再次查看 nsswitch.conf,会发现hosts那行有所变化:
1 | cat /etc/nsswitch.conf |
在进行DNS查询前,会先尝试通过IPC直接将请求发给resolved,当不可用时,才会继续根据resolv.conf发送DNS查询报文。
5. sing-box,clash
如果安装了sing-box这类网络工具,同时开启了DNS拦截,通过增加路由规则,目标端口是TCP/UDP 53的数据包,都会被送入sing-box内部,也包括resolved发送的DNS查询请求,所以,这时最终生效的便是sing-box的DNS分流规则了。