用 dnsmasq + dnscrypt 实现企业级网络的 DNS 解析

DNS 无论在企业内部还是企业外部,都是无比重要的一个互联网工具。在云计算日益风行的今天,恐怕企业内外没有几个人会使用 IP 地址访问一项资源了。

然而各种的 DNS 解析方式和工具,不要说 Linux 就是在微软自己的体系里,也是各有千秋,从 NetBT 到 WINS 到 LMHOSTS 到 LLMNR 到微软自己的 DHCP/DNS 服务器。Sun Microsystem, 老早就发明了 NIS 来解析 Unix 世界里的名字, 苹果有 Apple Talk , 然后有 Bonjour ,这个技术在 Linux 里就是叫做 Avahi 的工具。

可以说微软的 NetBT, LLMNR 和 Linux 上的 Avahi 以及苹果的 Bonjour 是一个体系的,在局域网内没有 DNS服务器存在的时候,他们之间相互解析,就是采用 mDNS的广播技术(NetBT除外). DNS-SD 其实还是蛮有用处的, 不仅仅可以用来解析主机名(RR) 资源,还可以用来解析其他的服务,所以 SD=Service Discovery,就是可以用作微服务的服务发现的一种工具。

然而,如果我们在企业内部部署一套 dnsmasq 作为内网解析并作为转发服务器,在后端采用 dnscrypt-proxy ,把 DNS 数据包加密,就能有效的保护企业的隐私,并采用一定的 DNS Blacklist , 更能保护企业安全,防止用户访问一些有“毒”的网站。

CentOS 默认安装了 Network-Manager 作为本地解析的服务,采用 nmtui 命令或者 nmcli 命令可以管理网卡,然后会自动写入 /etc/resolv.conf ,本机的解析就会采用 Network-Manager 这个服务来实现,不会生成其他的 tcp/udp 端口。如果安装 avahi 软件包,并启用服务的话, 系统会打开 UDP 5353 端口,向外广播自己的地址,一般是 hostname.local 这样的格式。 记得停止 avahi-daemon 服务的是否,同时要停止 avahi-daemon.socket。
如果我们同时安装 systemd-resolved 软件包,那么系统启动 systemd-resolved 后,如果 /etc/systemd/resolved.conf 打开了 LLMNR 的话, 就会启用 tcp/udp 5355 端口,基本上在 CentOS 上,我们无需安装 systemd-resolved 软件包。

Ubuntu 上默认是没有 Network-Manager, 因此我们需要打开 systemd-resolved 服务, 但是在实际应用中,我们无需打开 mDNS 以及 LLMNR,因此,在 /etc/systemd/resolved.conf 中,我们只要配置到 DNS= 以及 Domains= 那两行即可,保持 LLMNR=no, MulticastDNS=no。可以看到会启动一个 127.0.0.53 上的 53 端口,作为本地解析。 /etc/resolv.conf 是一个 /run/systemd/resolve/stub-resolv.conf 的软连接。

Windows 上默认就是拿 DHCP 地址的,在其他软件栈上一般的用户无需做特殊的处理,我们就略过。Mac 笔记本回头再补充()。

基本上从本地 DNS 解析我们就可以说到这里,CentOS 就是 /etc/resolv.conf 直接写解析的 DNS 服务器地址,或者通过 nmtui 指定。 Ubuntu 上就是写 /etc/systemd/resolved.conf 文件,记得修改后 reload 服务。

接下来我们要介绍 dnsmasq 这把瑞士军刀,安装在企业局域网内,提供比传统的 BIND 还要牛逼的一些功能。

安装其实很简单,在 Ubuntu 1904 版本上,就是 apt install dnsmasq。
我的配置文件 /etc/dnsmasq.conf 如下:

domain-needed
bogus-priv
proxy-dnssec
filterwin2k
no-resolv
server=127.0.0.1#5300
local=/yj/
addn-hosts=/etc/pihole/hosts.static
addn-hosts=/etc/pihole/hosts-01.leases
addn-hosts=/etc/pihole/hosts-02.leases
dhcp-script=/sbin/dnsmasq_dhcp.sh
no-negcache
log-queries

附加的一个配置文件:

addn-hosts=/etc/pihole/gravity.list
addn-hosts=/etc/pihole/black.list
addn-hosts=/etc/pihole/local.list
localise-queries
cache-size=10000
log-facility=/var/log/pihole.log
local-ttl=2
dhcp-name-match=set:hostname-ignore,wpad
dhcp-name-match=set:hostname-ignore,localhost
dhcp-ignore-names=tag:hostname-ignore

DHCP 选项:

dhcp-authoritative
dhcp-range=192.168.7.61,192.168.7.90,24h
dhcp-option=option:router,192.168.7.1
dhcp-option=option:dns-server,192.168.7.11,192.168.7.12
dhcp-leasefile=/etc/pihole/dhcp-01.leases
domain=yj
local=/yj/
expand-hosts
dhcp-option=option6:dns-server,[::]
dhcp-range=::100,::1ff,constructor:ens8,ra-names,slaac,24h
ra-param=*,0,0
dhcp-option-force=option:domain-search,yj,yj777.cn

从配置我们可以知道, 提供了一个 61-90 的 DHCP 池,附加本地局域网后缀 .yj,DHCP 每次获取或者删除都会运行一个 /sbin/dnsmasq_dhcp.sh 的脚本。第一个配置文件里, 读取了 /etc/pihole 下三个附加的 hosts 文件, 从名字可以知道 hosts.static 就应该是一个静态解析的文件,企业网络内需要静态配置的地址,都直接修改这个文件即可, hosts-01.leases 和 hosts-02.leases 就是两台 DHCP 解析后,运行以上脚本,生成的“静态”文件。

为什么要这么做呢?

我们在环境里提供了两台 dnsmasq DHCP 服务,为了防止IP 冲突, 提供了两个不同的 DHCP Range,如果某台机器是在 01 服务器上取到的地址,那么通常的话, 通过 02 上的 dnsmasq 是无法解析该机器的,因此, 我们写了 /sbin/dnsmasq_dhcp.sh 脚本, 在两台机器上,分别生成自己的 hosts.leases 文件(一旦有自动 renew IP,两台 DHCP 的脚本都会响应), 而每次有修改后,自动 reload dnsmasq 服务,保证新的 DHCP 地址以“静态”的方式解析。至于静态的 hosts 文件,我们放在共享的 NFS 服务上, /etc/pihole 是一个 NFS 挂接点,每次有修改静态 IP 地址,当然需要 reload 两边的 dnsmasq 服务。

这样子, 通过 DHCP 和 静态 IP 的手工配置,(只需要配置一次),我们就实现了全网络的所有机器之间的 DNS 访问,而无需配置 avahi-daemon 或者打开 LLMNR 这样的端口,减少了机器上的网络堆栈可能引起的各种混乱。

dnscrypt-proxy 软件包的安装和配置也十分简单, apt install 后,systemctl –now enable dnscrypt-proxy 然后 status 命令看下服务状态即可。 配置文件是 /etc/dnscrypt-proxy/dnscrypt-proxy.toml,我们用 cloudflare 来解析。 端口配置为 5300,让 dnsmasq 转发到这个端口即可(参见以上 dnsmasq 配置的 server= 行)。

通过以上,我们设置两台 dns-01 和 dns-02 的服务器,各自运行 dnsmasq 和 dnscrypt-proxy , 共享一个 /etc/pihole 目录,存放相关的 hosts 配置,和动态生成的 hosts.leases 文件。

作者: 甬洁网络

--移动互联网&物联网技术提供商