Linux使用dnsmasq开启本地dns缓存

通俗解释 DNS

DNS (Domain Name System) 是域名系统的缩写,它作为可以将域名和 IP 地址相互映射的一个分布式数据库。通俗来讲,互联网上每台电脑都会有一个身份证号来标记电脑,然后电脑相互访问时就需要知道这个身份证号才能到达指定的电脑,这个身份证号就是IP地址。但是,如果仅仅是有限的几台电脑,这个方法足够应对了,然而互联网上有无数的电脑,每次访问某台电脑,就需要查询这台电脑的 IP, 显然一个人不可能记住那么多的IP地址。为了方便人的记忆,我们可以为 IP 起一个别名,也就是域名,比如www.baidu.com,同时把IPwww.baidu.com的对应关系保存在/etc/hosts文件中。 这样每次电脑访问这台电脑时就直接访问www.baidu.com, 然后电脑就会去/etc/hosts查询这个域名对应的IP, 然后根据查到的IP访问对应的电脑。 然而,这样做以后,每个人的电脑就会保存不同的hosts文件,同时也需要每次访问新的电脑都要编辑这个hosts文件,世界很大,维护hosts会耽误大量的时间,同时若自己换了电脑,那必然也要带上这个自己习惯的hosts文件到新的电脑。为了解决这个问题,网络上出现了专门同步IP与域名对应关系的分布式服务器(也是一台电脑), 这台电脑就叫做 DNS 服务器。当我们知道了 DNS 服务器的 IP以后,把这个 IP告诉我们自己的电脑,这样每次访问互联网,我们自己的电脑就会向 DNS 服务器发出申请,返回相应域名的 IP地址,然后再通过这个IP访问域名对应的电脑, 于是hosts文件实现了全网同步。但是,随之而来的问题是 DNS 服务器的性能会因不同的设备而有差异,同时不同 DNS 服务器也会因为通信线路和地理位置等造成访问速度不同,我们肯定希望速度越快越好,于是人们就需要选择那些可靠的大厂 DNS 服务器。

提升网络访问速度

随着互联网的发展,全球的电脑越来越多,同一个网站为了更好的展示效果和更强大的功能而链接到多个网站。有时候,我们可以快速打开一个网站,但是它会花相当长的时间来打开完整的网站,这个体验就不是很好了。 事实上,DNS 服务器再快也不会比自己电脑上保存了hosts文件快,似乎问题又回到了最初,但是又不一样。为了提高访问速度,我们可以通过某些软件记录下每次访问过的域名和相应的IP地址,这样第二次以后速度会实现质的飞越。同时,现在的硬盘价格也是相当便宜,我们平时游览的网站通常也是和自己相关领域的有限数目的网站,因此使用软件自动缓存下这些访问过的记录也是一件相当容易的事情,这会给我们网上冲浪带来质的飞越。

全自动安装脚本

如果您使用的是ArchLinux, 同时不想关注细节,请直接保存脚本syndns.sh后,执行sudo chmod +x syndns.sh && ./syndns -i , 即可一键配置好本地dns缓存。

syndns.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#! /bin/sh
#
# Program : syndns.sh
# Version : v1.1
# Date : 2024-11-30 00:52
# Author : fengzhenhua
# Email : fengzhenhua@outlook.com
# CopyRight: Copyright (C) 2022-2025 FengZhenhua(冯振华)
# License : Distributed under terms of the MIT license.
#
# 检测软件依懒, 若未检测到,则自动安装
SYNDNS_DEPEND(){
for VAR in $1 ;do
if [[ "$(pacman -Q |grep $VAR)" = "" ]]; then
sudo pacman -S $VAR
fi
done
}
SYN_EXE="/usr/local/bin/${0%.sh}"
SYN_AUTO="$HOME/.config/autostart/${0%.sh}.desktop"
SYN_SUDO="/etc/sudoers.d/01_$USER"
if [ $# -gt 0 ]; then
if [ $1 == "-i" -o $1 == "-I" ]; then
SYNDNS_DEPEND "inetutils dnsmasq"
sudo cp -f $0 $SYN_EXE
sudo chmod +x $SYN_EXE
if [ ! -e $SYN_AUTO ]; then
sudo touch $SYN_AUTO
cat > $SYN_AUTO <<EOF
[Desktop Entry]
Name=SynDns
TryExec=syndns
Exec=$SYN_EXE
Type=Application
Categories=GNOME;GTK;System;Utility;TerminalEmulator;
StartupNotify=true
X-Desktop-File-Install-Version=0.22
X-GNOME-Autostart-enabled=true
Hidden=false
NoDisplay=false
EOF
sudo sh -c "cat > /etc/dnsmasq.conf" <<EOA
domain-needed
bogus-priv
resolv-file=/etc/resolv.conf
no-poll
interface=lo
listen-address=127.0.0.1
bind-interfaces
no-hosts
addn-hosts=/dev/shm/dnsrecord.txt
cache-size=9999
port=53
EOA
if [ ! -e $SYN_SUDO ]; then
sudo touch $SYN_SUDO
sudo sh -c "cat > $SYN_SUDO" <<EOB
$USER ALL=(ALL) NOPASSWD: /bin/systemctl start stirling-pdf.service, /bin/systemctl stop stirling-pdf.service, /bin/systemctl restart dnsmasq.service, /bin/systemctl start dnsmasq.service
EOB
fi
fi
fi
fi
SYN_REC=$(grep "addn-hosts" /etc/dnsmasq.conf)
SYN_REC=${SYN_REC#*=}
cat /etc/hosts > $SYN_REC
echo "$(hostname -i) localhost:" >> $SYN_REC
sudo systemctl start dnsmasq.service

本脚本全自动配置好了dnsmasq, 但是若想达到自己快速访问自己习惯的网站,请在/etc/hosts文件中加入IP和域名映射,具体操作参见:Linux解决无法访问学术网站的问题

屏蔽广告

  • 建立屏蔽文件存放目录:sudo mkdir /etc/dnsmasq.d
  • 下载anti-Ad广告列表:
    1
    sudo curl -o /etc/dnsmasq.d/anti-ad-for-dnsmasq.conf https://anti-ad.net/anti-ad-for-dnsmasq.conf
  • 修改配置文件/etc/dnsmasq.conf:
    /etc/dnsmasq.conf
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    domain-needed
    bogus-priv
    resolv-file=/etc/resolv.conf
    no-poll
    interface=lo
    listen-address=127.0.0.1
    bind-interfaces
    no-hosts
    addn-hosts=/dev/shm/dnsrecord.txt
    addn-hosts=/etc/dnsmasq.d
    cache-size=9999
    port=53
  • 重启dnsmasq.service服务
    1
    sudo systemctl restart dnsmasq.service

技术细节

Linux 使用 dnsmasq 开启本地 dns 缓存

dnsmasq 是一个轻量组 DHCP 和缓存 DNS 服务器。

1. 安装 dnsmasq

1
sudo pacman -S dnsmasq

2. 配置 dnsmasq

dnsmasq 的主配置文件为/etc/dnsmasq.conf。一些配置 dns 缓存相关参数(更多参数说明见 https://thekelleys.org.uk/dnsmasq/docs/dnsmasq.conf.example/etc/dnsmasq.conf 内说明)

配置文件设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
cat /etc/dnsmasq.conf

domain-needed

port=53

bogus-priv

interface=lo

bind-interfaces

listen-address=127.0.0.1

cache-size=4000

resolv-file=/etc/resolv.dnsmasq

no-poll

参数说明

(1)domain-needed

如果没有域名后缀的请求(即单个主机名的查询)会被忽略,不会被转发到上游 DNS 服务器。防止将无效的主机名查询发送到外部 DNS 服务器。

(2)port

绑定指定端口

(3)bogus-priv

阻止将私有 IP 地址范围的查询结果返回给客户端。如果上游 DNS 服务器返回的结果是私有 IP 地址,dnsmasq 会将其丢弃。防止意外将私有 IP 地址暴露在外部网络。

(4)interface=lo

指定 dnsmasq 仅监听在本地回环接口 lo 上。限制 dnsmasq 只在本机的回环接口上工作,不对外提供 DNS 服务,增加安全性。

(5)bind-interfaces

强制 dnsmasq 只绑定到配置中明确指定的接口(例如 lo)。确保 dnsmasq 只监听指定接口,防止不必要的接口绑定,增强控制和安全性。

(6)listen-address

指定 dnsmasq 应该监听 DNS 查询的 IP 地址。如果使用 dnsmasq 作为本地 DNS 缓存服务,设置为 127.0.0.1。

(7)resolv-file

设置包含上游 DNS 服务器的文件的路径,不打开的话,默认用 /etc/resolv.conf ,也可以直接指定,例如,我们在 /etc 中创建一个名为 resolv.dnsmasq 的文件,其内容如下:

cat /etc/resolv.dnsmasq

nameserver 8.8.8.8

这些配置将使 dnsmasq 能够从 8.8.8.8 查询 DNS 记录并在本地缓存。

(8)cache-size

定义要缓存的最大 DNS 记录数。

(9)no-resolv

dnsmasq不使用 /etc/resolv.conf 或者其他文件,不做上游DNS查询。取消注释此行以防止 dnsmasq 使用 /etc/resolv.conf 文件。

(10)no-poll

禁用 dnsmasq 对 /etc/resolv.dnsmasq 文件的持续轮询检查。提高性能,避免频繁检查该文件的变动。如果不经常修改该文件,这个选项可以避免不必要的文件系统访问。

3. 启用 dnsmasq 服务

1
sudo systemctl enable --now dnsmasq.service

4. 将默认 DNS 设置为 dnsmasq

如果已经取消注释 dnsmasq 配置中的 no-resolv 选项,则无需编辑 /etc/resolv.conf

注释掉所有涉及 nameserver 的行,并写入127.0.0.1到 /etc/resolv.conf,如下示例:

1
2
3
cat /etc/resolv.conf
# nameserver 8.8.8.8
nameserver 127.0.0.1

dnsmasq 性能优化

我们都知道Bind不配合数据库的情况下,经常需要重新载入并读取配置文件,这是造成性能低下的原因。根据这点教训,我们可以考虑不读取/etc/hosts文件。而是另外指定一个在共享内存里的文件,比如/dev/shm/dnsrecord.txt ,这样就不费劲了,又由于内存的非持久性,重启就消失,可以设置为开机启动服务,实现每次开机自动同步/etc/hosts文件到内存中。

1. 配置 dnsmasq

/etc/dnsmasq.conf
1
2
no-hosts
addn-hosts=/dev/shm/dnsrecord.txt

2. 创建同步脚本 syndns.sh

/usr/local/bin/syndns
1
2
3
4
5
6
7
8
9
#! /bin/sh
#
# syndns.sh
# Copyright (C) 2024 Zhen-hua Feng <fengzhenhua@outlook.com>
#
# Distributed under terms of the MIT license.
#
cat /etc/hosts > /dev/shm/dnsrecord.txt
sudo systemctl start dnsmasq.service

3. 提升权限

/etc/sudoers.d/01_feng
1
feng ALL=(ALL) NOPASSWD: /bin/systemctl start stirling-pdf.service, /bin/systemctl stop stirling-pdf.service, /bin/systemctl restart dnsmasq.service, /bin/systemctl start dnsmasq.service

提升启动dnsmasq.service的开启权限后,开机启动服务就不再需要sudo输入密码了,这样做更加合理。

4. 设置开机时启动

~/.config/autostart/syndns.desktop
1
2
3
4
5
6
7
8
9
10
11
[Desktop Entry]
Name=SynDns
TryExec=syndns
Exec=/usr/local/bin/syndns
Type=Application
Categories=GNOME;GTK;System;Utility;TerminalEmulator;
StartupNotify=true
X-Desktop-File-Install-Version=0.22
X-GNOME-Autostart-enabled=true
Hidden=false
NoDisplay=false

由于本人的桌面环境是Gnome, 所以推荐使用此处的ArchLinux配置自启动程序的方法。同时,在尝试使用systemctl方案时并求成功,原因在于systemctl是系统级服务,启动时cat写入内存的文件dnsrecord.txt就属于具备root权限,因此由于cat权限不足而失败。

针对网站提速

将常用网站的域名和IP放置到 /etc/hosts 文件可以缩短主机访问 DNS服务器的时间,前面将这些常用网站添加到内存文件 /dev/shm/dnsrecord.txt 中,这极大的提高了电脑访问的速度,因为即使是固态硬盘,它的读取速度也是与内存无法相比的,而这个文件却占据很小内存,甚至可以忽略不计。但是,在访问某一网站时,由于网站会借助 cdn 等添加一些js组件,而这一部分会零星的占用不少时间去访问 DNS服务器。为了进一步提速,就需要我们将这些后台访问的网址域名也添加到/etc/hosts文件中。方法是:打开 firefox更多工具Web 开发者工具网络, 然后就可以看到后台访问的许多网站,手动把这些域名解析后有可能获取多个IP, 将这些IP使用Ping工具测速后,把最快的IP添加到hosts中。下次访问主网站,速度就飞起了。

另外需要注意的是:firefox设置隐私和安全→取消关闭Firfox时删除Cookie与网站数据. 这样设置后,下次在访问此网站,那些缓存好的图片等就不需要再次下载了,网站只下载那些发生变动的部分,因此这又可以进一步的提升访问速度。

参考文章