使用dnsmasq搭建局域网DNS解析服务

What

dns服务是啥呢,全名Domain Name System,互联网通信中一般都是使用ip地址进行通信,但是毫无规律的数字很难记,而且服务器可能会更换,随之而来的就是ip也会发生变动,在此之上抽象出了域名这么一层东西。虽然说现在的dns还广泛应用于负载均衡等用途,不过起源还是用来做域名-ip的转换的。

Why

那么,跟我们有啥关系呢?一般来说,用默认的就行,不过我们可能还需要其他一些特殊用途呢?比如说抵抗运营商dns污染,比如说去广告,再比如说内外网区分解析,再比如dns缓存,等等等等。

How

这篇文章的重点不是介绍有啥用途啦,毕竟这不是一篇种草文,也没人给我广告费。。。

dnsmasq

今天的主角是dnsmasq,搭建软路由的童鞋应该很熟悉了。除了可以用作前面提到的dns解析服务,它还有一个很重要的功能就是提供ip分配,即dhcp服务,不过本文重点是在自建dns,dhcp服务还是交给专业的路由器来做比较稳定。

安装很容易啊,不管什么平台,一句命令就能装上。

1
sudo apt install -y dnsmasq

不过大鱼自动接触到docker之后,就跟着了魔似的,什么都想装在容器里,这不,dnsmasq也想部署在容器里面。找了一圈,没有官方镜像,本着安全的原则,自己写了一个,也很简单。基础镜像依旧是用alpine,尽可能小一点。最后一行表示让dnsmasq在前台运行,不然容器就直接退出了。

1
2
3
4
5
FROM alpine:3.10

RUN apk add --no-cache dnsmasq

CMD ["/usr/sbin/dnsmasq", "-k"]

Dockerfile地址在这里

当然了,不是让大家都自己去做镜像,这里直接用现成的就可以。

运行

首先创建一个空的/data/dnsmasq/目录,后续再介绍如何配置。

1
2
3
4
5
6
7
8
9
docker run \
--name dnsmasq \
-d \
--restart always \
--cap-add=NET_ADMIN \
--publish 53:53/udp \
--net host \
--mount type=bind,src=/data/dnsmasq/,dst=/etc/dnsmasq.d/ \
newnius/dnsmasq

这里有一个cap-add参数,其实非常不喜欢给容器特殊权限,找了其他人的镜像,很少有消去这个权限的,而且贼复杂。。。这个权限只有dhcp的时候才需要,dnsmasq强制检查了,比较烦,勉强接受吧。然后别忘了暴露53端口,协议是udp。

这里需要注意一下,我加了--net host这个参数,让容器运行在宿主机相同的网络上,之前没有的时候,外部服务没问题,但是本机其他容器里面域名解析会不正常,你说咯哦酷派显示nslookup: can't resolve '(null)': Name does not resolve。用dig排查了一下,发现是因为请求的ip和返回的ip地址不一致,没有通过验证,会显示以下错误。

1
2
3
4
/ # dig @192.168.0.3 blog.newnius.com
;; reply from unexpected source: 172.17.0.1#53, expected 192.168.0.3#53
;; reply from unexpected source: 172.17.0.1#53, expected 192.168.0.3#53
;; reply from unexpected source: 172.17.0.1#53, expected 192.168.0.3#53

加上--host net解决了这个网络问题,发现其他镜像都没有提到过这个问题。

可以用 dig @192.168.0.3 blog.newnius.com命令来检查服务是否启动成功,这里就实现了一个简单的dns服务。

配置

默认的配置下,没有自定义的解析,所有解析都会走上游dns服务器。这里我们可以自己修改一下。

默认的配置文件在容器的/etc/dnsmasq.conf位置,或者也可以在这里找到默认的配置文件

这里需要需要修改的有这么几处:

配置上游dns,我们要做的毕竟只是修改部分记录,对于其他的,就交给上游dns服务商来处理好了。

默认情况下,dnsmasq会从 /etc/resolv.conf文件读取上游dns,这里我们可以自己来换成其他的。在宿主机/data/dnsmasq/目录创建一个名为global.conf的文件用来覆盖默认配置。加上no-resolv这行,表示不要读取/etc/resolv.conf文件。为啥不是修改成其他路径呢?因为这样可以少挂载一个文件夹😄,把配置都放在/data/dnsmasq/目录就好了,另外就是/etc/resolv.conf是自动生成的,如果路由器上配置了这个地址,自己的上游还是自己,会出现问题。再写上自定义的上游dns,这里可以写公共的dns服务商,但是为了速度起见,推荐使用当前网络分配的,可以看看当前宿主机的/etc/resolv.conf文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
# global.conf

# 不要解析 /etc/resolv.conf
no-resolv

# 缓存的记录数,默认是150,调大一点,免得每次都要花时间重新询问
cache-size=1500

# 这个可以配置多个上游服务器
server=114.114.114.114

# 表示同时查询上游dns,哪个先返回就用哪一个
all-servers

配置自定义的记录

这里只是作为参考,比如说我们想要在dns层面做广告过滤,只需要把他们的广告域名改成127.0.0.1就可以了。比如说要屏蔽google的广告,新建一个文件

1
2
3
# ads_block.conf

address=/doubleclick.net/127.0.0.1

重启docker容器即可生效(似乎dnsmasq也会自己监听文件的变化)。

1
docker restart dnsmasq

配置路由器下dhcp默认dns

自建dns到以上就结束了,不过需要自己指定才会用山,如果希望连入路由器的设备自动使用这个dns的话,就需要在路由器上进行配置。

找到DHCP服务器设置页面,然后首选和备选dns都改成dns服务所在的ip地址。大鱼用的是tp-link路由器,其他路由器可以在类似的地方找到。其他设备重新连入时就会使用自己的dns服务了。

436531648b99b342922c029697c55038.md.png

有一点需要注意一下,可能有多个地方配置dns,之前是在首页配置的,提示不能跟路由器子网相同,感觉挺奇怪的,不知道它那个地方的dns是用在什么地方。。。

本文主要是介绍如何部署,更加详细的广告过滤等配置或许以后再更新。