Linux命令 DNSMasq


原文链接: Linux命令 DNSMasq
  1. ubuntu默认装的是dnsmasq-base, 配合resolvconf和network-manager玩的, 不是完整的dnsmasq
    所以在ubuntu上不要卸, 卸载的话可能导致network-manager的依赖出问题
    dnsmasq的bin文件就在/usr/share/dnsmasq-base/里, dnsmasq包只是init脚本 + 配置文件 + 依赖dnsmasq-base的包

  2. 如何禁用内置dnsmasq的版本?
    我是在网上搜到一个方法,修改 sudo vi /etc/NetworkManager/NetworkManager.conf 文件,把dns=dnsmasq注释掉了

#!/bin/bash
#####		一键安装DNSmasq脚本		#####
#####		Author:xiaoz			#####

#自动放行端口
function chk_firewall() {
	if [ -e "/etc/sysconfig/iptables" ]
	then
		iptables -I INPUT -p tcp --dport 53 -j ACCEPT
		iptables -I INPUT -p udp --dport 53 -j ACCEPT
		service iptables save
		service iptables restart
	else
		firewall-cmd --zone=public --add-port=53/tcp --permanent 
		firewall-cmd --zone=public --add-port=53/udp --permanent 
		firewall-cmd --reload
	fi
}

#安装
yum -y install dnsmasq

#获取服务器公网IP
# osip=$(curl http://https.tn/ip/myip.php?type=onlyip)
## 创建并使用新的域名解析文件,默认的resolv.conf 中最多只能配置三个域名服务器(nameserver)
#设置上游DNS
echo "nameserver 119.29.29.29" >> /etc/resolv.dnsmasq.conf
echo "nameserver 114.114.114.114" >> /etc/resolv.dnsmasq.conf

#修改配置文件
#载入DNS
sed -i 's%#resolv-file=%resolv-file=\/etc\/resolv.dnsmasq.conf%g' /etc/dnsmasq.conf
sed -i 's/#strict-order/strict-order/g' /etc/dnsmasq.conf
#设置监听IP
sed -i "s%#listen-address=%listen-address=0.0.0.0%g" /etc/dnsmasq.conf
#科学上网配置
wget -O /etc/dnsmasq.d/gfw.conf https://raw.githubusercontent.com/sy618/hosts/master/dnsmasq/dnsfq
#设置定时任务
echo "10 2 * * * wget -O /etc/dnsmasq.d/gfw.conf https://raw.githubusercontent.com/sy618/hosts/master/dnsmasq/dnsfq && service dnsmasq restart" >> /etc/crontab

#防火墙放行端口
chk_firewall

#重载服务
service dnsmasq restart

#####		安装完成,请注意安全组放行53 tcp/upd端口		#####

1. 安装 dnsmasq

sudo apt install dnsmasq

提示: 配置文件语法检查:
$ dnsmasq --test

2. 配置 dnsmasq

DNSmasq的配置文件主要为:

/etc/dnsmasq.conf文件
/etc/dnsmasq.d/文件夹内的其他配置文件

从优先级来看,后者更高。如今的很多服务器程序都采用类似的配置策略,比如Nginx,只不过DNSmasq是自动加载后者的罢了。之后我们会在dnsmasq.d文件夹内添加本地命名解析表,而dnsmasq.conf则是关于服务器本身的配置信息。

在进行配置前,首先我们需要修改本机的nameserver,这里推荐直接修改 /etc/network/interface 文件,将dns-nameservers一项设置为127.0.0.1即可。

只需要修改配置文件dnsmasq.conf中的listen-address即可,将其修改为

listen-address=0.0.0.0

添加监听地址(其中$lanip为你的lan网关ip)

listen-address=$lanip,127.0.0.1

并发查询所有上游DNS服务器

all-servers

指定上游DNS服务器配置文件路径

resolv-file=/etc/dnsmasq/resolv.conf

添加额外hosts规则路径

addn-hosts=/etc/dnsmasq/noad.conf

IP反查域名

bogus-priv

添加DNS解析文件

conf-file=/etc/dnsmasq.d/ad.conf

设定域名解析缓存池大小

cache-size=10000" >> /etc/dnsmasq.conf

为指定域名设置上游dns的服务器

server=114.114.114.114
server=/qq.com/114.114.114.114#53
server=/baidu.com/114.114.114.114#53
server=/:.google.:/8.8.8.8#53
server=/:.facebook.:/8.8.8.8#53
server=/www.google.com/127.0.0.1 #禁止从上游解析google

DNSmasq处理DNS查询请求的流程如下:

查看DNS缓存
如1失败,则查看本地记录(包括hosts内的记录)
如2失败,则向上一级DNS服务转发查询请求

因此必须为DNSmasq提供上一级DNS服务器的信息,具体的做法是为DNSmasq提供一个resolv,其对应的文件为/etc/resolv.dnsmasq,该文件的格式和resolv.con一样,例如:

nameserver 202.102.93.153
nameserver 8.8.4.4

只需按照如下命令运行即可:

dnsmasq -r /etc/resolv.dnsmasq

这里必须要提供绝对路径,一般而言相对路径对于daemon进程并没有什么意义。

不过很明显,我们应该让systemd来协助管理服务,并且并没有理由去修改dnsmasq.service,毕竟有配置文件。修改前面提到的dnsmasq.conf,添加

resolv-file=/etc/resolv.dnsmasq

为了使上述配置生效,需要重启DNSmasq(如果你之前已经启动过了的话)

sudo systemctl restart dnsmasq

此时,配置应该已经生效了,让我们来测试一下,祭出网络测试专用域名

dig baidu.com

; <<>> DiG 9.10.3-P4-Ubuntu <<>> baidu.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: REFUSED, id: 47004
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;baidu.com. IN A
;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Wed Aug 10 21:58:14 CST 2016
;; MSG SIZE rcvd: 27

然而并没有查到A类记录,ping的结果也是unknow host,似乎配置文件并没有生效啊。

先查看下DNSmasq进程的信息吧。

ps -ax | grep dnsmasq
17218 ? S 0:00 /usr/sbin/dnsmasq -x /var/run/dnsmasq/dnsmasq.pid -u dnsmasq -r /var/run/dnsmasq/resolv.conf -7 /etc/dnsmasq.d,.dpkg-dist,.dpkg-old,.dpkg-new --local-service --trust-anchor=.,19036,8,2,49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5

怎么加载的是/var/run/dnsmasq/resolv.conf?一定是哪里出了问题,既然是systemd管理的服务,那么就从service文件入手,打开/etc/systemd/system/multi-user.target.wants/dnsmasq.service,发现了如下信息:

ExecStart=/etc/init.d/dnsmasq systemd-exec

So,虽然切换到了systemd,但依旧是initrc的那一套?不管了,打开探探究竟。

发现了如下内容:

# Note that if the resolvconf package is installed it is not possible to
# override it just by configuration in /etc/dnsmasq.conf, it is necessary
# to set IGNORE_RESOLVCONF=yes in /etc/default/dnsmasq.

也就是说如果系统安装了resolvconf,那么默认情况下修改/etc/dnsmasq.conf是没有用的,那么就按照注释所说,将/etc/default/dnsmasq中的相关项加上即可(其实就是去掉最后一行的'#')。

然后再次重启dnsmasq服务,此时我们应该就能够获得baidu域名的A类记录了。

好,接下来就是添加本地的记录了,这里可以采用2种方式:

直接修改hosts文件,dnsmasq在启动时会自动加载
在dnsmasq.d中添加相关配置

这里采用的是后者,/etc/dnsmasq.d/cluster.conf的内容如下:

address=/node0.cpv.org/192.168.1.230
address=/node1.cpv.org/192.168.1.231
address=/node2.cpv.org/192.168.1.232
address=/node3.cpv.org/192.168.1.233
address=/node4.cpv.org/192.168.1.234

表达的意思即为如果有host查询nodeX.cpv.org的记录,即强制返回对应的静态IP,不在继续向上发送请求。

除此之外,可能还会用到如下写法:

server=/google.com/10.25.3.4

如果host查询的域名为*.google.com则将请求转发给对应IP的DNS服务器。此处的IP地址为随便指定的,只用来作个示例。

重启服务后,就能用ping或者dig来验证结果了,应该不会再有什么问题,至少我这里是这样的。

Dnsmasq的配置文件是放在 /etc/dnsmasq.conf 中.
打开编辑,配置:resolv-file=/etc/resolv.dnsmasq.conf,表示dnsmasq 会从这个指定的文件中寻找上游dns服务器。同时取消strict-order 前面的注册#号.
检查一下no-hosts前面是不是已经有了#号,默认的情况下是有的,dnsmasq 会首先寻找本地的 hosts 文件再去寻找缓存下来的域名, 最后去上游dns 服务器寻找。
设置:listen-address=127.0.0.1,表示这个 dnsmasq 本机自己使用有效。注意:如果你想让本机所在的局域网的其它电脑也能够使用上Dnsmasq,应该把本机的局域网IP加上去:listen-address=192.168.64.128,127.0.0.1
设置:address=/yangchen.cm/127.0.0.1 ,设置泛域名.

另外我们还需要修改/etc/resolv.conf这个文件,执行以下命令:

$ echo 'nameserver 127.0.0.1' > /etc/resolv.conf
$ cp /etc/resolv.conf /etc/resolv.dnsmasq.conf
$ echo 'nameserver 8.8.8.8' >> /etc/resolv.dnsmasq.conf
$ echo 'nameserver 192.168.64.128' >> /etc/resolv.dnsmasq.conf
$ cp /etc/hosts /etc/dnsmasq.hosts
$ echo 'addn-hosts=/etc/dnsmasq.hosts' >> /etc/dnsmasq.conf
resolv.dnsmasq.conf中设置的是真正的Nameserver,可以用谷歌、V2EX等公共的DNS。

配置Dnsmasq

Dnsmasq处理DNS设置与BIND等其他DNS服务有所不同。所有的配置都在一个文件中完成/etc/dnsmasq.conf。默认情况下dnsmasq.conf中只开启了最后include项,可以在/etc/dnsmasq.d中自己写任意名字的配置文件。
配置文件说明

Dnsmasq配置文件是/etc/dnsmasq.conf,下面对Dnsmasq中和DNS相关的配置项进行说明。

用指定的端口代替默认的DNS 53端口,如果设置为0,则完全禁止DNS功能,只使用dhcp服务
port=5353

以下两个参数告诉Dnsmasq过滤一些查询:1.哪些公共DNS没有回答 2.哪些root根域不可达。

从不转发格式错误的域名
#domain-needed

从不转发不在路由地址中的域名
#bogus-priv

resolv-file配置Dnsmasq额外的向流的DNS服务器,如果不开启就使用linux主机默认的/etc/resolv.conf里的nameserver,通过下面的选项指定其他文件。
resolv-file=/etc/dnsmasq.d/upstream_dns.conf

默认情况下Dnsmasq会发送查询到它的任何上游DNS服务器上,如果取消注释,则Dnsmasq则会严格按照/etc/resolv.conf中的DNS Server顺序进行查询。
#strict-order

以下两个参数控制是否通过/etc/resolv.conf确定上游服务器,是否检测/etc/resolv.conf的变化,则取消注释。

如果你不想Dnsmasq读取/etc/resolv.conf文件或者其他文件,获得它的servers

If you don't want dnsmasq to read /etc/resolv.conf or any other

file, getting its servers from this file instead (see below), then

uncomment this.

#no-resolv

如果你不允许Dnsmasq通过轮询/etc/resolv.conf或者其他文件来获取配置的改变,则取消注释。
#no-poll

增加一个name server,一般用于内网域名
#server=/localnet/192.168.0.1

设置一个反向解析,所有192.168.3.0/24的地址都到10.1.2.3去解析
#server=/3.168.192.in-addr.arpa/10.1.2.3

增加一个本地域名,会在/etc/hosts中进行查询
#local=/localnet/

增加一个域名,强制解析到你指定的地址上
#address=/double-click.net/127.0.0.1

同上,还支持ipv6
#address=/www.thekelleys.org.uk/fe80::20d:60ff:fe36:f83

增加查询yahoo google和它们的子域名到vpn、search查找

Add the IPs of all queries to yahoo.com, google.com, and their

subdomains to the vpn and search ipsets:

#ipset=/yahoo.com/google.com/vpn,search

你还可以控制Dnsmasq和Server之间的查询从哪个网卡出去

server=10.1.2.3@eth1

指定源地址携带10.1.2.3地址和192.168.1.1的55端口进行通讯

and this sets the source (ie local) address used to talk to

10.1.2.3 to 192.168.1.1 port 55 (there must be a interface with that

IP on the machine, obviously).

server=10.1.2.3@192.168.1.1#55

改变Dnsmasq默认的uid和gid
#user=
#group=

如果你想Dnsmasq监听某个端口为dhcp、dns提供服务
#interface=

你还可以指定哪个端口你不想监听
#except-interface=

设置想监听的地址,如果你本机要使用写上127.0.0.1。
#listen-address=

如果你想在某个端口只提供dns服务,则可以进行配置禁止dhcp服务
#no-dhcp-interface=

On systems which support it, dnsmasq binds the wildcard address,

even when it is listening on only some interfaces. It then discards

requests that it shouldn't reply to. This has the advantage of

working even when interfaces come and go and change address. If you

want dnsmasq to really bind only the interfaces it is listening on,

uncomment this option. About the only time you may need this is when

running another nameserver on the same machine.

#bind-interfaces

如果你不想使用/etc/hosts,则取消下面的注释
#no-hosts

如果你项读取其他类似/etc/hosts文件,则进行配置
addn-hosts=/etc/banner_add_hosts

自动的给hosts中的name增加一个域名
#expand-hosts

给dhcp服务赋予一个域名
#domain=thekelleys.org.uk

给dhcp的一个子域赋予一个不同的域名
#domain=wireless.thekelleys.org.uk,192.168.2.0/24

同上,不过子域是一个范围
#domain=reserved.thekelleys.org.uk,192.68.3.100,192.168.3.200

dhcp分发ip的范围,以及每个ip的租约时间
#dhcp-range=192.168.0.50,192.168.0.150,12h

同上,不过给出了掩码
#dhcp-range=192.168.0.50,192.168.0.150,255.255.255.0,12h

自动加载conf-dir目录下的配置文件
conf-dir=/etc/dnsmasq.d

设置dns缓存大小,默认为150条
cache-size=150

配置实例
配置上游服务器地址

resolv-file配置Dnsmasq额外的上游的DNS服务器,如果不开启就使用Linux主机默认的/etc/resolv.conf里的nameserver。

通过下面的选项指定其他文件来管理上游的DNS服务器

$ vi /etc/dnsmasq.conf

resolv-file=/etc/resolv.dnsmasq.conf

在指定文件中增加转发DNS的地址

$ vi /etc/resolv.dnsmasq.conf

nameserver 8.8.8.8
nameserver 8.8.4.4

本地启用Dnsmasq解析

$ vi /etc/resolv.conf

nameserver 127.0.0.1

添加解析记录

使用系统默认hosts

编辑hosts文件,简单列举一下格式

$ vi /etc/hosts

127.0.0.1 localhost
192.168.101.107 web01.mike.com web01
192.168.101.107 web02.mike.com web02

hosts文件的强大之处还在于能够劫持解析,譬如mirror.centos.org是CentOS仓库所在,几乎是机器正常必访问一个域名,我将它解析成一个内网地址,搭建一个内网镜像站,不仅内网机器也可以及时得到安全更新,每月还可以节省很多流量。

使用自定义hosts文件

修改配置,增加自定义hosts文件位置。

$ vi /etc/dnsmasq.conf

addn-hosts=/etc/dnsmasq.hosts

在/etc/dnsmasq.hosts文件中添加DNS记录

$ vi /etc/dnsmasq.hosts

192.168.101.107 web01.mike.com web01
192.168.101.107 web02.mike.com web02

使用自定义conf

$ vi /etc/dnsmasq.d/address.conf

指定dnsmasq默认查询的上游服务器,此处以Google Public DNS为例。

server=8.8.8.8
server=8.8.4.4

把所有.cn的域名全部通过114.114.114.114这台国内DNS服务器来解析

server=/cn/114.114.114.114

给*.apple.com和taobao.com使用专用的DNS

server=/taobao.com/223.5.5.5
server=/.apple.com/223.5.5.5

把www.hi-linux.com解析到特定的IP

address=/www.hi-linux.com/192.168.101.107

在这里hi-linux.com相当于*.mike.com泛解析
address=/hi-linux.com/192.168.101.107

注:也可以直接添加到/etc/dnsmasq.conf中,不过/etc/dnsmasq.d/*.conf的优先级大于/etc/dnsmasq.conf。
修改iptables配置

允许本机的53端口可对外访问

$ iptables -A INPUT -p udp -m udp --dport 53 -j ACCEPT
$ iptables -A INPUT -p tcp -m tcp --dport 53 -j ACCEPT

转发DNS请求

开启流量转发功能

$ echo '1' > /proc/sys/net/ipv4/ip_forward
$ echo '1' > /proc/sys/net/ipv6/ip_forward # IPv6 用户选用

添加流量转发规则,将外部到53的端口的请求映射到Dnsmasq服务器的53端口

$ iptables -t nat -A PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 53
$ iptables -t nat -A PREROUTING -p tcp --dport 53 -j REDIRECT --to-ports 53

如果要限制只允许内网的请求,方法如下

$ iptables -t nat -A PREROUTING -i eth1 -p upd --dport 53 -j REDIRECT --to-port 53

保存规则并重启

$ service iptables save
$ service iptables restart

测试Dnsmasq

启动Dnsmasq

$ service dnsmasq start

测试Dnsmasq

将其他机器的DNS换成dnsmasq所在的IP即可,就这么容易。

$ dig @192.168.101.104 www.hi-linux.com

一些Dnsmasq技巧
Dnsmasq性能优化

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

具体实现步骤

配置dnsmasq

$ vim /etc/dnsmasq.conf

no-hosts
addn-hosts=/dev/shm/dnsrecord.txt

解决同步问题

开机启动

$ echo "cat /etc/hosts > /dev/shm/dnsrecord.txt" >>/etc/rc.local

定时同步内容

$ crontab -e
*/10 * * * * cat /etc/hosts > /dev/shm/dnsrecord.txt

Dnsmasq选择最快的上游DNS服务器

经常会有这样的情景,Dnsmasq服务器配了一堆上游服务器,转发本地的dns请求,缺省是Dnsmasq事实上是只挑了一个上游dns服务器来查询并转发结果,这样如果选错服务器的话会导致DNS响应变慢。

解决方法

$ vi /etc/dnsmasq.conf

all-servers
server=8.8.8.8
server=219.141.136.10

all-servers表示对以下设置的所有server发起查询,选择回应最快的一条作为查询结果返回。
上面我们设置了两个dns server,8.8.8.8(谷歌dns)和219.141.136.10(移动的dns),会同时查询这两个服务器,询问dns地址谁返回快就采用谁的结果。
dnsmasq-china-list项目

dnsmasq-china-list项目维护了一张国内常用但是通过国外DNS会解析错误的网站域名的列表,保证List中的国内域名全部走国内DNS服务器解析。

项目地址: https://github.com/felixonmars/dnsmasq-china-list

dnsmasq-china-list使用

取消dnsmasq.conf里conf-dir=/etc/dnsmasq.d这一行的注释
获取项目文件

$ git clone https://github.com/felixonmars/dnsmasq-china-list.git

将accelerated-domains.china.conf, bogus-nxdomain.china.conf,google.china.conf(可选)放到/etc/dnsmasq.d/目录下(如目录不存在则建立一个)。
将dnsmasq-update-china-list放到/usr/bin/,这是一个批量修改DNS服务器的工具(可选)。

参考文档

http://www.google.com
http://purplegrape.blog.51cto.com/1330104/1083354
https://i-meto.com/archives/iptables_PREROUTING.html
http://blog.itphp.org/archives/225

DNSmasq去广告规则

编辑 /etc/dnsmasq.conf,加入下面一条配置:

#add dnsmasq.ads rule list
conf-dir=/etc/dnsmasq.d
addn-hosts=/etc/dnsmasq.d/simpleu.txt

记得在etc文件夹下新建一个名字为dnsmasq.d的文件夹,以免配置不正确,然后命令行运行以下批处理即可更新过滤规则,可以添加到定时任务脚本或者开机启动脚本里面,方便自动更新,以下为自动更新命令:

wget --no-check-certificate -qO - https://easylist-downloads.adblockplus.org/chinalist+easylist.txt | grep ^\|\|[^\*]*\^$ | sed -e 's:||:address\=\/:' -e 's:\^:/127\.0\.0\.1:' > /etc/dnsmasq.d/chinalist+easylist.conf
wget --no-check-certificate -qO - http://winhelp2002.mvps.org/hosts.txt |awk '{if(/^#/||/^$/) {print $0} else {print "address=/"$2"/"$1"\t"$3,"\n""server=/"$2"/#"}}' > /etc/dnsmasq.d/mvps.conf
wget --no-check-certificate -qO - http://someonewhocares.org/hosts/hosts | \
awk '{if(/^#/||/^$/) {print $0} else {print "address=/"$2"/"$1"\t"$3,"\n""server=/"$2"/#"}}' > /etc/dnsmasq.d/someonewhocares.conf
wget --no-check-certificate -qO - http://www.malwaredomainlist.com/hostslist/hosts.txt | \
awk '{if(/^#/||/^$/) {print $0} else {print "address=/"$2"/"$1"\t"$3,"\n""server=/"$2"/#"}}' > /etc/dnsmasq.d/malwaredomainlist.conf
wget --no-check-certificate -qO - https://raw.githubusercontent.com/vokins/simpleu/master/hosts > /etc/dnsmasq.d/simpleu.txt
/etc/init.d/dnsmasq restart
`