Skip to content

内网主机名与 LAN 后缀

给内网设备一个统一的域名后缀, 让 nas / nas.lan 这样的名字能直接解析到内网 IP, 同时通过 DHCP 把这个后缀告知客户端, 使客户端只输入短主机名也能补全.

对应配置是 landscape.toml[lan_hostname] 节:

toml
[lan_hostname]
enable = true
lan_suffix = "lan"
字段类型默认值说明
enablebooltrue关闭后正解、反解、DHCP option 全部停止
lan_suffixstring"lan"域名后缀, 可以多级如 home.arpa

主机名从哪来

登记表有两个来源:

来源怎么产生特点
已录入设备在设备管理里填 hostname 字段, 见 设备管理长期有效, 优先级更高
DHCP 客户端自报客户端在 DHCP 请求里带 option 12 (Host Name)随租约来去, 无需手工维护

两者冲突时

已录入设备优先. 如果某个主机名已经由录入设备占用, DHCP 自报同名不会覆盖它; 反过来, 租约过期只会清掉 DHCP 学来的记录, 不会动录入设备的.

正向解析

配置 lan_suffix = "lan" 且某设备主机名是 nas 时:

sh
dig @<router> nas.lan A       # → 该设备的 IPv4
dig @<router> nas.lan AAAA    # → 该设备的 IPv6 (仅当登记了 IPv6 时)

WARNING

匹配的是整个后缀, 不是最后一个 label. lan_suffix = "home.lan" 时只有 nas.home.lan 能解析, nas.lan 不能. 后缀比较忽略大小写.

反向解析 (PTR)

反查会返回 <hostname>.<lan_suffix>.:

sh
dig @<router> -x 192.168.5.10   # → nas.lan.

同一个 IP 上挂了多个主机名时, 取已录入设备里字典序最小的那个; 没有录入设备记录才回落到 DHCP 学来的名字.

PTR 只对内网地址应答

只有这些地址范围会返回 PTR, 公网地址一律不应答 (避免污染公网反解):

  • IPv4: 私有地址 (10/8、172.16/12、192.168/16)、回环、链路本地 (169.254/16)、 运营商共享段 (100.64/10)、未指定地址、广播地址
  • IPv6: 唯一本地地址 (fc00::/7)、回环、链路本地 (fe80::/10)、未指定地址

local 区始终本地应答

除了配置的后缀, local 这个区永远由本地应答, 与 lan_suffix 设成什么无关. 这是给 mDNS 留的保护: local 属于 mDNS 命名空间, 不应该被转发到上游 DNS.

也因此 lan_suffix 不允许local (见下方保留后缀).

DHCP 下发的 option 15 / 119

启用后, DHCP 服务会按后缀下发两个 option, 让客户端能只输入 nas 就访问到 nas.lan:

Option名称内容
15Domain Name后缀本身, 如 lan
119Domain Search后缀的 DNS 线格式名字, 如 lan.

只在客户端点名请求时下发

这两个 option 走的是客户端参数请求列表 (option 55) 这条路: 客户端没在 option 55 里 要求 15 / 119, 服务端就不会塞给它. 这一点和 custom_options 不同, 后者是无条件注入的.

抓包核对时请确认客户端确实请求了这两个 code. 例如 dhcpcd 默认会请求:

sh
dhcpcd -T <iface> | grep -E 'new_domain_name|new_domain_search'

另外, option 119 需要后缀能解析成合法 DNS 名字. 万一不能, 只跳过 option 119, 其余响应内容照常返回, 日志里会有一条 warn.

运行时修改

这一节支持热改, 不需要重启服务:

  • DNS 的正解 / 反解立刻按新后缀生效
  • 下一个 DHCP 响应就会带上新的 option 15 / 119

API 是先取 hash 再带 hash 提交的乐观并发形式:

sh
B=https://<router>:6443/api/v1/system
# 1. 读当前配置, 同时拿到 hash
H=$(curl -sk $B/config/edit/lan_hostname -H "Authorization: Bearer $TOKEN" | jq -r .data.hash)
# 2. 带 hash 提交
curl -sk -X POST $B/config/edit/lan_hostname -H "Authorization: Bearer $TOKEN" \
  -d "{\"new_lan_hostname\":{\"enable\":true,\"lan_suffix\":\"home.arpa\"},\"expected_hash\":\"$H\"}"

hash 不匹配说明配置已被别处改过, 会返回冲突错误, 重新取 hash 再提交即可. 另有一个只读的快速接口 GET /config/lan_hostname (不返回 hash).

后缀校验规则

提交的后缀会先归一化: 去掉首尾空格与首尾的 ., 转小写, 非 ASCII 走 IDNA 转 punycode (如 BÜCHER.xn--bcher-kva).

然后按下表校验, 不通过返回 400, 且不会污染现有配置:

error_id触发条件
lan_hostname.invalid_suffix.empty_label出现空 label, 如 home..arpa
lan_hostname.invalid_suffix.invalid_idnaIDNA 转换失败
lan_hostname.invalid_suffix.too_long总长 > 253, 或单个 label > 63
lan_hostname.invalid_suffix.invalid_hyphenlabel 以 - 开头或结尾, 如 -lan
lan_hostname.invalid_suffix.invalid_character出现字母数字和 - 以外的字符, 如 lan_name
lan_hostname.invalid_suffix.reserved命中下方保留后缀

后缀留空 (或只填空格) 不算错误, 会回落到默认值 lan.

保留后缀

这些后缀会被拒绝, 因为它们属于解析器自己的命名空间, 占用会导致解析行为混乱:

  • 保留 TLD (含其子域): invalidtestonionlocalhostlocal —— 所以 corp.testoffice.local 也不行
  • arpa 相关: arpa 本身, 以及 in-addr.arpaip6.arparesolver.arpaipv4only.arpa 及其子域

TIP

home.arpa允许的 —— 它正是 RFC 8375 为家庭网络指定的后缀, 不在上面的保留列表里. mylan.arpain-addr.home.arpa 同样可用.

从旧版本升级

这一节以前叫 [hostname_registry]. 为兼容旧配置文件, 读取时仍然接受这个旧键名, 但程序导出配置时一律写成 [lan_hostname].

DANGER

[hostname_registry][lan_hostname] 同时出现会直接解析失败, 程序起不来. 手工编辑配置文件时请只保留一个 —— 推荐直接改成新名字.