Files
MeowOS b2e7cc8c70 fix(mdns): 启动竞态+运行期接口重检 (agent-194) — 无可用IPv4不再exit(2)改内部2s等待重试(SIGTERM可打断); 5s周期检测掉线/换IP→重新join组播+A记录实时刷新(修IP变更还带旧地址); 接口down时零应答守卫; MEOW_MDNS_IF 落地
meow_mdns b23de7ce→d6b0151b (+3.5KB); mipsel -Wall -Wextra 0 warning; 宿主netns实测等待/换IP/掉线守卫全过
注: 真机源码在 mips-repo/bins/meow_mdns/(非patch_v2); fw_content.conf 的 md5 行打包时更新
2026-08-31 05:16:18 +08:00

6.0 KiB
Raw Permalink Blame History

meow_mdns — 自研极简 IPv4-only mDNS 应答器(mipsel-linux-muslsf 静态)

目的:让 R3 Pro II / MeowOS 设备在纯 IPv4(内核无 IPv6)下应答 *.local, 使主机 avahi-resolve <host>.local / avahi-browse 能识别设备。 产出为自研 C 代码,零 IPv6 依赖,覆盖路径 A(mDNSResponder HAVE_IPV6=0)无法满足的功能缺口。

为什么不用 mDNSResponder / SAResponder

原因 说明
需 IPv6 两者都在 socket(AF_INET6) 处失败:Address family not supported by protocol。mDNSResponder 无 NOT_HAVE_IPV6 宏(0 处),IPv6 是运行时硬编码;即便 make HAVE_IPV6=0 编译通过(见下“路径 A 试验”),仍不解决下一条
不公布主机名 A 记录 完整版 mdnsd 是 IPC 服务型守护进程:它等客户端经 UDS(/var/run/mdnsd) 注册名字,自身不自动登记主机名。-debug 日志证实它只注册接口 wlan0 + _dns-sd 浏览记录,从无 ingenic.local A。应答记录需客户端调用 DNSServiceRegister,没有现成客户端
SAResponder 单服务 只用 mDNS_RegisterService 注册单一服务,不注册主机 A 记录,ingenic.local 无法按名解析

路径 A 试验结论(编译层面 MVP,但功能不达标)

  • 源码无 NOT_HAVE_IPV6;开关是 Makefile Linux 分支的 -DHAVE_IPV6(第 113 行)+ 第 196-200 行 HAVE_IPV6=0/1 可覆盖。
  • make os=linux tls=no HAVE_IPV6=0 CC=zig-mipsel-cc CFLAGS="-Os -static -Wno-date-time" LD=... LINKOPTS="-s" Daemon 能编译出 1015792B 的 mdnsd(md5 7ee68d626d718d0572d4087c5a584d7f), SetupSocket/接口枚举/unicast v6 socket 均被 #if HAVE_IPV6 移除;仅硬件地址那段 socket(AF_INET6) 被 if(sockfd>=0) 守护(无 IPv6 内核返回 -1,无害)。
  • 该 mdnsd 在设备上可运行(绑 0.0.0.0:5353 + 加入 224.0.0.251),但不发布主机名(见上),故不满足 ingenic.local 解析。→ 转路径 B。

功能

  • join IPv4 组播 224.0.0.251:5353(IP_ADD_MEMBERSHIP/SO_REUSEADDR/SO_REUSEPORT)。
  • 应答(QNAME 大小写不敏感):
    • <host>.local A → 设备 wlan0 IPv4。
    • _ssh._tcp.local PTR → <host>._ssh._tcp.local。
    • <host>._ssh._tcp.local SRV(port 22,target <host>.local)+ TXT(空)。
    • _services._dns-sd._udp.local PTR → _ssh._tcp.local(便于 avahi-browse)。
    • 支持 QTYPE=ANY(255)。
  • RFC 1035 名压缩(owner 名若已在响应中出现则回写 0xC0 指针)。
  • IP_PKTINFO 判断查询到组播还是单播:组播查询→组播应答 + 单播冗余回源;单播查询→单播回源。
  • 线程/信号安全;SIGINT/SIGTERM 优雅退出(留组并关 socket)。
  • 启动容错:接口未就绪(无 IPv4/wlan0 未 up)时内部等待重试(每 2s,无限等,stderr 打 waiting),不再 exit;修复开机时 mdns 先于网络就绪的 5×exit=2 崩溃竞态。
  • 运行期容错:每 5s 周期检查设备 IP,掉线(无 IPv4)或换 IP(WiFi 重连)时自动重新 drop/join 组播并刷新应答 IP,避免应答携带旧地址。
  • MEOW_MDNS_IF(已实现):限定要绑定/公布的接口名——既作为 IP 筛选,也决定 join 绑定接口;可用于宿主模拟"无接口"(设为不存在的接口名即进入等待循环)。

环境覆写

变量 默认 说明
MEOW_MDNS_HOST gethostname() 首标签 公布的主机名(设备上=内核 hostname meowos,/etc/hostname 残留 ingenic)
MEOW_MDNS_ADDR 首块非回环 UP 接口 IPv4 应答的 A 记录 IP(设备=wlan0 <device_ip>)
MEOW_MDNS_PORT 5353 监听端口(通常仅宿主单测用)
MEOW_MDNS_TTL 255 IP_MULTICAST_TTL
MEOW_MDNS_CF 0 唯一记录(A/SRV/TXT)是否置 cache-flush 位
MEOW_MDNS_QD 1 应答是否回显问题段(QDCOUNT)
MEOW_MDNS_MCAST 1 组播查询是否同时回组播应答(0=只单播回源)
MEOW_MDNS_MIF 0 是否显式设 IP_MULTICAST_IF 为设备接口 IP
MEOW_MDNS_DBG - (调试用)

ARCH / 运行库

  • ARCH: mipsel (MIPS32r2 little-endian)
  • 目标: mipsel-linux-musleabi (soft-float)
  • 静态链接 musl,无 glibc 依赖。

file 结果(bin/meow_mdns)

ELF 32-bit LSB executable, MIPS, MIPS32 rel2 version 1 (SYSV), statically linked, stripped

体积

  • 部署版:82,972 B ≈ 81.0 KB(strip 后;较旧版 +3.5KB,启动容错 + 运行期重检)
  • MD5 :d6b0151bda26768f19952dae1342610d(旧 b23de7ce54873e926e7601a3b21b66a9)

构建命令

见同目录 build.sh(宿主 gcc -O2 可编译并在本机组播/单播自测;交叉 zig-mipsel-cc -Os -static)。

部署

  • 设备:/usr/data/mnt/sd_0/MeowOS/opt/mdnsd/mdnsd(已部署, 755)。启动 ./mdnsd -v(或经 meow_svcd 托管)。
  • 验证:设备 netstat -uln | grep 5353(0.0.0.0:5353)、cat /proc/net/igmp(wlan0 含 FB0000E0=224.0.0.251)、主机单播 dig @<设备IP> -p 5353 <host>.local A 或 python 探测。

已知限制(重要)

  • 手机热点丢弃客户端间组播:设备能收到主机发来的组播查询并组播+单播应答,但设备→主机组播被热点丢弃(主机加入 224.0.0.251 组后 5s 收不到设备组播应答)。avahi 又只接受组播应答(对组播查询的单播应答, avahi 拒绝, 已实测)。故此刻 avahi-resolve <host>.local 超时——这是网络层热点隔离,非应答器缺陷。主机需 DNS 兜底(如 getent hosts meowos.local 走库, 或主机 /etc/hosts 静态条目, 或设备侧起一个 UDP:53 应答器)。
  • 本机(多接口 phone-Linux host)自测时, 应答器组播发送在同机环回也偶发不达(与接口/多默认路由相关),但单播回源始终正确;单接口设备上的组播发送不受此影响。

bin/ 内容

  • bin/meow_mdns = 部署版(mipsel 静态, 79,468 B, md5 b23de7ce…)