UDM-SE 本地 DNS 记录设置

最近更新了家里的网络设备,用 UDM-SE(Dream Machine Special Edition) 替换了 ER-X。相较于 ER-X 上运行的 EdgeOS,UDM-SE 运行的是 Unifi OS,所有网络设置都收口到了 UniFi Network Application 中,界面更为友好,但是也缺少了一定的自由度。这篇文章记录了内网 DNS 配置的折腾过程。

UDM-SE 本地 DNS 记录设置
Photo by Philipp Katzenberger / Unsplash
最近更新了家里的网络设备,用 UDM-SE(Dream Machine Special Edition) 替换了 ER-X。相较于 ER-X 上运行的 EdgeOS,UDM-SE 运行的是 Unifi OS,所有网络设置都收口到了 UniFi Network Application 中,界面更为友好,但是也缺少了一定的自由度。这篇文章记录了内网 DNS 配置的折腾过程。

0

家里内网的服务器上跑了一些服务,比如 Plex、Home Assistant,为了使用方便,加了一层 Nginx 反向代理,并绑定了内网域名。在 EdgeOS 中可以通过 static-host-mapping 配置来设置本地 DNS 记录,在 Unifi Network Application 中,可以通过 UI 为客户端设置 Local DNS Record。

这种方式设置的 DNS 记录是设备纬度的,只支持设置 1 个域名,而我用 Nginx 反代需要给一个 IP 配置多个域名。于是在不额外部署 DNS 服务器的情况下,我开始了以下一系列对 Unifi OS 的探究😃。

1

首先,先要确认 Unifi OS 用的 DNS 服务是什么。

ps aux | grep dns

# 以下是结果
/usr/sbin/dnsmasq --conf-dir=/run/dnsmasq.conf.d/ --pid-file=/run/dnsmasq.pid --resolv-file=/etc/resolv.dnsmasq

可以看到用的是 dnsmasq,一般来说 dnsmasq 会读取 /etc/hosts 中的记录,那就容易了,立马把 dns 记录添加到 /etc/hosts 中,结果并没有生效😓。根据进程启动信息查看了 /run/dnsmasq.conf.d/ 目录下的配置文件:

  • 目录下 share.conf 中配置了 no-hosts,所以忽略了 /etc/hosts 中的记录。
  • 目录下 dns.conf 中存在 host-record 设置,上面通过 UI 设置的 Local DNS Record 记录也在内。

通过这几个配置文件中的备注可以确认该目录下的配置文件由 ubios-udapi-server 自动生成,每次 dnsmasq 服务启动前会重新生成。因此如果直接修改 share.conf 和 dns.conf ,配置生效需要重启 dnsmasq,而重启 dnsmasq 时 ubios-udapi-server 会重新覆盖配置文件,死循环了。

2

既然 dnsmasq 的配置文件是由 ubios-udapi-server 生成的,那么合理猜测 dnsmasq 进程可能也是由 ubios-udapi-server 管理的,通过查看 dnsmasq 进程的父进程信息验证了这个猜测。

接下来顺藤摸瓜看看 ubios-udapi-server 是什么:

ps aux | grep ubios-udapi-server

# 以下是结果
/usr/bin/ubios-udapi-server -c /data/udapi-config/ubios-udapi-server/ubios-udapi-server.state --silent

ubios-udapi-server --help

Usage: ubios-udapi-server [opts]
Options:
 -h, --help                     show this help
 -v, --verbose                  print more information
 -x, --extremely-verbose        print also UDAPI communication
 -t, --timestamp                print timestamp in milliseconds
 -S, --silent                   stop logging to stdout
 -c, --config            [arg]  configuration file (default /config/ubios-udapi-server/ubios-udapi-server.state)
 -d, --default-config    [arg]  default/factory configuration file (default /usr/share/ubios-udapi-server/udm-pro-se-ea2c.default)
 -f, --fallback-config   [arg]  fallback configuration file (default /usr/share/ubios-udapi-server/udm-pro-se-ea2c.fallback)
 -s, --socket            [arg]  server socket (default /var/run/ubnt-udapi-server.sock)
 -e, --event-socket      [arg]  event socket (default /var/run/ubnt-udapi-bridge-event.sock)

没有详细的介绍,但是根据参数的介绍可以猜测 ubios-udapi-server 是用来管理 Unifi OS 配置及对应服务的。

接下来看一下 /data/udapi-config/ubios-udapi-server/ubios-udapi-server.state 这个配置文件里面都有什么。文件比较大就不贴出来了,实际上就是一个 JSON 格式的配置文件,记录了 UDM-SE 用到的所有配置信息(比如拨号信息、DHCP 等),在 services.dnsForwarder.hostRecords 节点可以看到我们之前通过 UI 设置的 DNS 记录。

{
  ···
  "services":{
    "dnsForwarder": {
        "cnameRecords": [],
        "domainForwards": [],
        "enabled": true,
        "forwardBehavior": "allServers",
        "hostRecords": [{
            "address": {
                "address": "192.168.100.10",
                "origin": null,
                "version": "v4"
            },
            "hostName": "appletv.mydomain.com",
            "registerNonQualified": true
        }]      
    }
  }
  ···
}
    

到这里基本可以确认 Unifi OS 的运作逻辑了,系统启动时,ubios-udapi-server 会根据 ubios-udapi-server.state 去生成不同服务需要的配置文件(放在 /run 目录下),并启动相关服务。那么只要手动把 DNS 记录添加到 ubios-udapi-server.state 中,下次启动后就能生效了。折腾过程中在官方社区还找到了通过 ubios-udapi-client 修改配置的方法,可以实时生效不需要重启系统。由于 ubios-udapi-client 没有官方文档,有网友写了相关脚本 udm-host-records ,这里就不展开了。

3

到这里,已经可以实现配置内网 DNS 静态记录了,但是参考 udm-host-records 作者的描述,修改 ubios-udapi-server.state 的方式不可控,系统可能在某些时候会覆盖我们的配置。

This was a brief attempt at providing local network DNS resolution. But because it's clear that the hostRecords are overwritten by Ubiquiti-owned code in a bunch of scenarios that don't seem to warrant it, it's clear that this approach to gaining a bit of local DNS control isn't sustainable. Please consider running your own local DNS, such as PiHole instead

于是,我还是回到了 dnsmasq 上,系统启动 dnsmasq 的时候设置了 --conf-dir=/run/dnsmasq.conf.d/,因此可以在该目录下新增配置文件:

# hosts.conf
host-record=a.mydomain.im,192.168.100.10
host-record=b.mydomain.im,192.168.100.10

/run 目录下的文件,每次系统启动时会被清空,我们可以放在个人目录下,在 /run/dnsmasq.conf.d 下创建软链接。那么什么时候去创建软链接呢,Unifi OS 2.x 以下版本可以参考 unifios-utilities 添加启动脚本,按作者所说 Unifo OS 3.x 失效了,所以我没有细看。退而求其次,可以在 /etc/ppp/ip-up.d 创建脚本,这样每次拨号成功后会自动执行。

#!/bin/sh
ln -sf /root/config/dnsmasq/hosts.conf /run/dnsmasq.conf.d/hosts.conf
kill -9 "$(cat /run/dnsmasq.pid)"

总结

  • 单条 DNS 记录可以通过 UI 给客户端设置 Local DNS Records。
  • 多条 DNS 记录可以新增 dnsmasq 配置文件来实现。