# meow_mdns — 自研极简 IPv4-only mDNS 应答器(mipsel-linux-muslsf 静态) > 目的:让 R3 Pro II / MeowOS 设备在**纯 IPv4**(内核无 IPv6)下应答 `*.local`, > 使主机 `avahi-resolve .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 大小写不敏感): - `.local` **A** → 设备 wlan0 IPv4。 - `_ssh._tcp.local` **PTR** → `._ssh._tcp.local`。 - `._ssh._tcp.local` **SRV**(port 22,target `.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 ) | | `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 .local A` 或 python 探测。 ## 已知限制(重要) - **手机热点丢弃客户端间组播**:设备能收到主机发来的组播查询并组播+单播应答,但**设备→主机组播被热点丢弃**(主机加入 224.0.0.251 组后 5s 收不到设备组播应答)。avahi 又**只接受组播应答**(对组播查询的单播应答, avahi 拒绝, 已实测)。故此刻 `avahi-resolve .local` **超时**——这是**网络层热点隔离**,非应答器缺陷。主机需 DNS 兜底(如 `getent hosts meowos.local` 走库, 或主机 `/etc/hosts` 静态条目, 或设备侧起一个 UDP:53 应答器)。 - 本机(多接口 phone-Linux host)自测时, 应答器组播发送在同机环回也偶发不达(与接口/多默认路由相关),但单播回源始终正确;单接口设备上的组播发送不受此影响。 ## bin/ 内容 - `bin/meow_mdns` = 部署版(mipsel 静态, 79,468 B, md5 b23de7ce…)