OpenWrt DNS问题排查

 摘要: 排查 dnsmasg 启动不起来,致DNS解析不成功问题

我们的设备在测试时发现有个别的主机,主程序DNS解释服务器域名失败。
最直接的表现就是 ping 126.com 显示:
ping 126.com失败

对于这个问题,最直接的方式就是打开 /etc/resolv.conf 文件查看DNS服务器是否设置正确。结果该文件显示:

search lan
nameserver 127.0.0.1

博主用 strace ping 126.com 命令,分别比较了好的有问题的设备与没问题的设备。将输出信息用 meld 进行对比,结果看到在这里出现分歧:

日志比较

可见,ping 命令在解释 "126.com" 域名时,是 connect 127.0.0.1:53 服务。而存在问题的一边,connect这个服务被拒绝了。

于是,博主可以分析得到,好的设备一定有一个服务进程bind了53端口,并提供了 DNS 服务。而有问题的设备一定是没有该进程。

博主在好的设备上运行 netstat -nap 找到了该服务:

netstat -nap 同时我们又在问题的设备,执行 netstat -nap,证实,有问题的设备上这个 dnsmasq 服务没有运行起来。

这里,博主查了些资料:

    Dnsmasq is a Domain Name System (DNS) forwarder and Dynamic Host Configuration Protocol (DHCP) server for small computer networks, created as free software. Dnsmasq has low requirements for system resources, can run on Linux, BSDs, Android and OS X, and is included in most Linux distributions.

博主归纳一下:dnsmasq就是一个DNS与DHCP的轻量级的服务。

由于OpenWrt本身就是一个路由器的系统,其自带 Dnsmasq 服务向其网络下的子网设备提供 DNS 与 DHCP 服务。而我们OpenWrt自身的程序解析域名时,也就向本地的 dnsmasq 请求解析。

那么,现在的问题是:为什么个别设备它的 dnsmasq 启动不起来? 对比好的设备,执行 ps 是能看到 dnsmasq 进程存在的。执行 /etc/init.d/dnsmasq stop 能停止它。这时候再 ping 126.com 它也是通的。为什么?博主查了一下 /etc/resolv.conf 文件,在停止 dnsmasq 之前,它的内容是:

search lan
nameserver 127.0.0.1

查一旦停止后,它就会变成:

# Interface lan
nameserver 202.96.128.166
nameserver 202.96.134.133
search bad

这是OpenWrt为了防止 dnsmasq 被停后无法解析域名,所以在停止之前,将其已知的域名服务器写入到 /etc/resolv.conf 文件中来。

相对于有问题的设备,其 /etc/resolv.conf 内容为:

search lan
nameserver 127.0.0.1

而 dnsmasq 进程并未被启动过(执行 ps 命令,列表中没有 dnsmasq 进程)。于是博主尝试执行:/etc/init.d/dnsmasq start,然后执行:ps 查看进程。结果,dnsmasq 进程并没有如愿启动起来。 直接执行 dnsmasq 命令就可以启动服务,然后 ping 126.com 也能拼通。

那么问题应该是在 /etc/init.d/dnsmasq 文件中。博主打开 /etc/init.d/dnsmasq 看了一下,太多了,就不想全部贴出来了。相信大家也没有赖心看。下面只是摘要。 /etc/init.d/dnsmasq start 时会执行到:

PROG=/usr/sbin/dnsmasq
CONFIGFILE="/var/etc/dnsmasq.conf"
<略...>
start_service() {
    include /lib/functions

    config_load dhcp

    procd_open_instance
    procd_set_param command $PROG -C $CONFIGFILE -k
    procd_set_param file $CONFIGFILE
    procd_set_param respawn
    procd_close_instance

    <略...>
}

可以了解到,真正执行的启动命令是:/usr/sbin/dnsmasq -C /var/etc/dnsmasq.conf -k
手动执行这个命令,看能否启动 dnsmasq 服务:

如上,出错了。/var/etc/dnsmasq.conf 文件的第11行有重复的关键字。
这是一个重要的线索!打开 /var/etc/dnsmasq.conf 文件:

如上,第11行的关键字为 dhcp-leasefile。对比好的设备的该文件。经对比,完全一致。

那问题又在哪儿呢? 是不是把 /var/etc/dnsmasq.conf 文件中的11行删除就可以了呢?尝试如此操作,结果还真是可以启动。 但这没有从根本解决问题。

是不是有别的配置文件,也有 dhcp-leasefile 关键字?
打开 /etc/dnsmasq.conf,这个文件与 /var/etc/dnsmasq.conf 完全一样。但是博主尝试用 /etc/dnsmasq.conf 替代 /var/etc/dnsmasq.conf,如下执行:

/usr/sbin/dnsmasq -C /etc/dnsmasq.conf -k

结果没有问题,而如果指定的配置文件为 /var/etc/dnsmasq.conf 就有问题。博主很不理解。为了确保这两个文件是同一个,于是:

rm /var/etc/dnsmasq.conf
cp /etc/dnsmasq.conf /var/etc/dnsmasq.conf
/usr/sbin/dnsmasq -C /var/etc/dnsmasq.conf -k

结果:

博主只想说:What a fuck!
同样是配置文件,同样的内容,只是路径变了而已。为什么放 /var/etc/dnsmasq.conf 就会出错?
是不是 dnsmasq 默认就加载了 /etc/dnsmasq.conf ?如果有指定其它的配置文件,它就会出错?
于是:

rm /var/etc/dnsmasq.conf
mv /etc/dnsmasq.conf /var/etc/dnsmasq.conf
/usr/sbin/dnsmasq -C /var/etc/dnsmasq.conf -k

结果:

证实一点,dnsmasq 确实默认加载了 /etc/dnsmasq.conf,不然为什么在我们将文件移走了,会报找不到 /etc/dnsmasq.conf 文件。这也说明了为什么我们强制性指定配置文件为 /var/etc/dnsmasq.conf 时会报重复关键字了。因为 /etc/dnsmasq.conf 也被加载了的。

对比好的设备里的 /etc/dnsmasq.conf 内容,结果发现:

# Change the following lines if you want dnsmasq to serve SRV
# records.
# You may add multiple srv-host lines.
# The fields are <name>,<target>,<port>,<priority>,<weight>

# A SRV record sending LDAP for the example.com domain to
# ldapserver.example.com port 289
#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389

# Two SRV records for LDAP, each with different priorities
#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389,1
#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389,2

# A SRV record indicating that there is no LDAP server for the domain
# example.com
#srv-host=_ldap._tcp.example.com

# The following line shows how to make dnsmasq serve an arbitrary PTR
# record. This is useful for DNS-SD.
# The fields are <name>,<target>
#ptr-record=_http._tcp.dns-sd-services,"New Employee Page._http._tcp.dns-sd-services"

# Change the following lines to enable dnsmasq to serve TXT records.
# These are used for things like SPF and zeroconf.
# The fields are <name>,<text>,<text>...

#Example SPF.
#txt-record=example.com,"v=spf1 a -all"

#Example zeroconf
#txt-record=_http._tcp.example.com,name=value,paper=A4

# Provide an alias for a "local" DNS name. Note that this _only_ works
# for targets which are names from DHCP or /etc/hosts. Give host
# "bert" another name, bertrand
# The fields are <cname>,<target>
#cname=bertand,bert

里面没有一个配置项,与其 /var/etc/dnsmasg.conf 完全不一样。

OK,大致找到问题了。坏设备的 /etc/dnsmasg.conf 有了 /var/etc/dnsmasg.conf 一样的内容。所以,当 dnsmasq 加载完了 /etc/dnsmasg.conf 后再来加载 /var/etc/dnsmasg.conf 就出错了。
将 /etc/dnsmasg.conf 清空即可:

rm /etc/dnsmasg.conf
touch /etc/dnsmasg.conf

然后,再 /etc/init.d/dnsmasg start,就成功了。

那为什么坏的主机 /etc/dnsmasg.conf 有内容?而不是像好的设备那样全是注释? 我们去 OpenWrt工程中找答案。 dnsmasg 在工程的如下路径上:package/network/services/dnsmasq/ 目录为:

.
├── files
│   ├── dhcp.conf
│   ├── dnsmasq.conf
│   ├── dnsmasq.hotplug
│   └── dnsmasq.init
├── Makefile
└── patches
    ├── 001-Build-config-add-DNO_GMP-for-use-with-nettle-mini-gm.patch
    ├── 002-fix-race-on-interface-flaps.patch
    ├── 100-fix-dhcp-no-address-warning.patch
    └── 110-ipset-remove-old-kernel-support.patch

2 directories, 9 files

目录下的 files/dnsmasq.conf 文件在安装后就是 /etc/dnsmasg.conf 文件。打开看,其内容就与好的设备上的 /etc/dnsmasq.conf 文件一致。
如果一个纯净的系统固件,是不会出这个问题的。

那么有两种可能:

    由于脚本出错,致将 /var/etc/dnsmasg.conf 文件的内容写入到了 /etc/dnsmasg.conf 中
    是我们在进行 sysupgrade 过程中,出错的 /etc/dnsmasg.conf 文件被遗留下来了

验证的方法为:断电重启,看 /etc/dnsmasg.conf 是否会再次变成与 /var/etc/dnsmasg.conf 一致。 结果正常。 本文章由作者:佐须之男 整理编辑,原文地址: OpenWrt DNS问题排查
本站的文章和资源来自互联网或者站长的原创,按照 CC BY -NC -SA 3.0 CN协议发布和共享,转载或引用本站文章应遵循相同协议。如果有侵犯版权的资 源请尽快联系站长,我们会在24h内删除有争议的资源。欢迎大家多多交流,期待共同学习进步。

相关推荐