|
|
上一篇講 VLAN,這篇專門講最容易卡住的那一關:mDNS。

先搞懂 mDNS 在幹嘛
mDNS(Multicast DNS) 是一種「不用 DNS 伺服器也能找到彼此」的機制。
運作方式:
- 裝置把自己的名字註冊成 xxx.local
- 要找某個服務的時候,往多播位址 224.0.0.251:5353 喊一聲
- 符合的裝置直接回應
關鍵:它用的是多播(multicast),而多播預設不會跨越路由器。
所以 VLAN 一分開,兩邊就聽不到彼此了。
哪些東西依賴 mDNS
- HomeKit —— 整個配對和通訊都靠它
- Chromecast / Google Home
- AirPlay / AirPrint
- ESPHome 裝置的自動發現
- Shelly、Tasmota、WLED 等的自動發現
- 大部分的網路印表機
- Spotify Connect
- HA 的很多整合的「自動發現」功能
症狀:VLAN 設好之後,HA 的「自動發現」什麼都找不到,
Chromecast 在手機上消失,印表機不見了。
解法一:Avahi reflector(最常見)
Avahi 是 Linux 上的 mDNS 實作,它的 reflector 功能會
把一個介面收到的 mDNS 封包轉發到其他介面。
OpenWrt 設定
- opkg update
- opkg install avahi-daemon
複製代碼
編輯 /etc/avahi/avahi-daemon.conf:
- [server]
- use-ipv4=yes
- use-ipv6=no
- # 只列出要互通的介面,不要留空(留空=所有介面)
- allow-interfaces=br-lan,br-iot
- ratelimit-interval-usec=1000000
- ratelimit-burst=1000
- [wide-area]
- enable-wide-area=no
- [publish]
- publish-addresses=yes
- publish-hinfo=no
- publish-workstation=no
- disable-publishing=no
- [reflector]
- enable-reflector=yes
- reflect-ipv=no
- # 新版 Avahi 支援只反射特定服務(見下方)
- # reflect-filters=_googlecast._tcp.local,_hap._tcp.local
複製代碼
啟用:
- /etc/init.d/avahi-daemon enable
- /etc/init.d/avahi-daemon restart
複製代碼
還要開防火牆
Avahi 能轉發,但防火牆要放行 5353:
- # /etc/config/firewall
- config rule
- option name 'Allow-mDNS'
- option src '*'
- option dest_port '5353'
- option proto 'udp'
- option target 'ACCEPT'
- option family 'ipv4'
複製代碼- /etc/init.d/firewall restart
複製代碼

解法二:各平台的內建功能
UniFi
設定 → 網路 → 選那個網路 → 進階 → 開啟 Multicast DNS。
UniFi 的實作是每個網路各自開關,兩邊都要開才會互通。
pfSense / OPNsense
安裝 Avahi 套件(系統 → 套件管理員),
然後在設定裡勾選要橋接的介面。
MikroTik RouterOS
原生沒有 mDNS reflector。選項:
- 用 RouterOS 7 的 container 功能跑一個 avahi 容器
- 或者另外放一台小機器(樹莓派)當 reflector
- 或者放棄自動發現,全部手動指定 IP
OpenWrt 的替代方案:mdns-repeater
比 Avahi 輕量很多,只做一件事:
- opkg install mdns-repeater
- # 或從 GitHub 編譯
複製代碼- mdns-repeater br-lan br-iot
複製代碼
優點:極輕量、單一用途、不會有 Avahi 那些額外的服務發布。
缺點:功能少,不能過濾服務類型。
安全上的取捨(一定要理解)
開了 reflector 之後:
- IoT 網段看得到主網段所有廣播服務的名稱
- 主網段也看得到 IoT 的
- 等於洩漏了一份裝置清單
這削弱了 VLAN 隔離的一部分效果。
但要看清楚:reflector 只轉發「服務廣播」,不會讓實際的連線通過。
實際連線還是被防火牆規則管著。
所以風險是「資訊洩漏」而不是「存取權限」。
對家用環境來說通常可以接受。
降低風險的三個做法
1. 只反射需要的介面
不要在 allow-interfaces 裡列出訪客網路。
訪客不需要看到你的 Chromecast。
2. 用服務過濾(如果你的 Avahi 版本支援)
新版 Avahi 有 reflect-filters,只轉發特定的服務類型:
- [reflector]
- enable-reflector=yes
- reflect-filters=_googlecast._tcp.local,_hap._tcp.local,_esphomelib._tcp.local
複製代碼
常見的服務類型:
- _googlecast._tcp — Chromecast / Google Home
- _hap._tcp — HomeKit
- _airplay._tcp 和 _raop._tcp — AirPlay
- _ipp._tcp 和 _printer._tcp — 印表機
- _esphomelib._tcp — ESPHome
- _http._tcp — 很多小裝置的網頁介面
3. 完全不開,改用手動設定
這是最安全的做法。
多數 HA 整合都支援手動輸入 IP,只是不會自動跳出來。
- 設定 → 裝置與服務 → 新增整合 → 選那個整合
- → 有些會問「要自動發現還是手動輸入」
複製代碼
配合 DHCP 保留把 IP 固定住,設定一次就不用再管。
缺點:
- HomeKit 幾乎不能用(它的配對流程依賴 mDNS)
- Chromecast 投放不能用
- 新增裝置比較麻煩

怎麼決定
我的建議:
- 家裡有 HomeKit / Chromecast / AirPlay → 開 reflector,用服務過濾
- 只有 Zigbee + 少量 Wi-Fi 裝置 → 不用開,手動設定就好
- 完全不在意那點資訊洩漏 → 直接開,最省事
Zigbee 的隱藏優勢又出現了:
Zigbee 裝置根本不上 IP 網路,完全沒有 mDNS 的問題。
只有網關需要連網,而網關可以手動指定。
除錯:怎麼確認 mDNS 有沒有通
在 HA 主機上(或任何 Linux 機器):
- # 掃描所有 mDNS 服務
- avahi-browse -a -t
- # 只看某一類
- avahi-browse -t _esphomelib._tcp
- # 看某個名字解析到哪個 IP
- avahi-resolve -n myesp.local
複製代碼
用 Python(HA 裡就有):
- python3 -c "
- from zeroconf import Zeroconf, ServiceBrowser
- import time
- class L:
- def add_service(self,zc,t,n): print('找到:', n)
- def remove_service(self,zc,t,n): pass
- def update_service(self,zc,t,n): pass
- zc = Zeroconf()
- ServiceBrowser(zc, '_esphomelib._tcp.local.', L())
- time.sleep(5)
- zc.close()
- "
複製代碼
直接抓封包:
- tcpdump -i any -n port 5353
複製代碼
在路由器上跑這個,你會看到 mDNS 的查詢和回應。
有轉發成功的話,會看到同樣的封包出現在兩個介面上。
常見的失敗原因
- 防火牆擋 5353 —— 最常見,Avahi 設定對了但封包過不去
- allow-interfaces 寫錯介面名 —— 用 ip link 確認實際名稱
- IGMP snooping —— 交換器上的這個功能可能擋掉多播,試著關掉
- AP 的 client isolation 開著 —— 同一個 SSID 內的裝置也看不到彼此
- IPv6 —— 有些裝置用 IPv6 的 mDNS,記得設 use-ipv6 或直接關掉裝置的 IPv6
---
我自己的設定是開 reflector 但用服務過濾,
只放行 Chromecast、ESPHome、印表機三類。
其他的全部手動指定 IP,反正設定一次而已。 |
|