前言
家里物联网设备越来越多——智能灯泡、摄像头、扫地机器人、智能插座……这些设备的安全更新频率远低于手机和电脑,一旦被攻破,攻击者就能在你的内网横向移动。把不同信任级别的设备放进不同网段、用防火墙控制互访,是最低成本的防御手段。
本文用 OpenWrt 实现一套完整的网段隔离方案,覆盖 VLAN 创建、防火墙 Zone 划分、跨子网路由、DHCP 分配和 WireGuard 远程接入。
硬件前提:本文基于 OpenWrt One(单 LAN 口)编写。单 LAN 口做 VLAN 需要外接一台支持 802.1q 的网管交换机,通过 Trunk 口承载多个 VLAN 的 tagged 流量。
替代方案:
- 双网口设备(如 x86 软路由、多口硬路由):可以直接把第二个物理网口独立划为一个 zone 并配不同子网,省去 VLAN 和交换机。也可以把 WAN 口加入
br-lan桥接并启用 VLAN 过滤,将 WAN 口当作第二个 Trunk 口用,节省交换机端口- 多网口设备:每个物理口各接一个 VLAN 的 untagged 流量,等同于交换机的 access 口,不需要交换机即可实现网段隔离
无论用哪种硬件方案,本文的防火墙 zone 划分、DHCP 多池和 WireGuard 接入逻辑完全通用。
网络拓扑与子网规划
物理拓扑
Internet │ [光猫] │[OpenWrt One] (单 LAN 口,做 VLAN Trunk) │ │ tagged: VLAN 10, 20, 30 │[网管交换机] (802.1q) │ ├── Port 2 (untagged VLAN 10) ── 管理设备(你的电脑/NAS) ├── Port 3 (untagged VLAN 20) ── IoT 设备 ├── Port 4 (untagged VLAN 30) ── 访客 WiFi AP └── Port 5 (untagged VLAN 10) ── 另一个 AP(家庭用)子网规划
| VLAN ID | 名称 | 子网 | 网关 | 用途 |
|---|---|---|---|---|
| 10 | mgmt | 192.168.10.0/24 | 192.168.10.1 | 管理网络(你的电脑、NAS、服务器) |
| 20 | iot | 192.168.20.0/24 | 192.168.20.1 | IoT 设备(灯泡、摄像头、音箱) |
| 30 | guest | 192.168.30.0/24 | 192.168.30.1 | 访客网络(完全隔离) |
互通策略
| 源 → 目标 | mgmt | iot | guest | WAN |
|---|---|---|---|---|
| mgmt | ✅ | ✅ | ✅ | ✅ |
| iot | ❌ | ✅ | ❌ | ✅ |
| guest | ❌ | ❌ | ✅ | ✅ |
| WireGuard | ✅ | ✅ | ❌ | — |
设计思路:管理网络可以访问一切;IoT 设备只能自己玩和上网,不能主动访问管理网段;访客完全隔离,只能上网;远程 WireGuard 拨入后可访问管理和 IoT 网络,但不能进访客网络。
第一步:交换机端 VLAN 配置
在配置 OpenWrt 之前,先配好交换机。以常见的 TP-Link / Netgear 网管交换机为例。
不同品牌交换机界面不同,但核心概念一致:创建 802.1q VLAN、设置 PVID、指定 tagged/untagged 端口。以下以概念性配置描述。
交换机 VLAN 表
| VLAN ID | 端口 1(上行,连 OpenWrt) | 端口 2 | 端口 3 | 端口 4 | 端口 5 |
|---|---|---|---|---|---|
| 10 (mgmt) | tagged | untagged (PVID 10) | — | — | untagged (PVID 10) |
| 20 (iot) | tagged | — | untagged (PVID 20) | — | — |
| 30 (guest) | tagged | — | — | untagged (PVID 30) | — |
要点:
- 端口 1(上行):所有 VLAN 都打
tagged,这是通向 OpenWrt 的 Trunk 口 - 其他端口:每个端口只属于一个 VLAN,设
untagged+ PVID 为对应 VLAN ID - 如果某个 AP 需要同时发多个 VLAN 的 SSID(比如一个 AP 同时发家庭 WiFi 和访客 WiFi),它所在的端口需要对多个 VLAN 打 tagged
PVID 解释
PVID(Port VLAN ID)决定未打标签的入站帧被分配到哪个 VLAN。对于接普通设备的 access 口,PVID = 该端口所属的 VLAN ID。对于 Trunk 口(上行口),PVID 通常设为管理 VLAN(VLAN 10)或不设置(取决于交换机实现)。
第二步:OpenWrt VLAN 接口创建
OpenWrt 24.10 使用 DSA(Distributed Switch Architecture),VLAN 配置在 LuCI 的 网络 → 接口 → 设备 选项卡中完成。
2.1 确认物理接口名
SSH 到 OpenWrt,查看网络设备:
ip link show# 或ls /sys/class/net/典型情况下单 LAN 口设备会有一个 lan1 或 eth1 设备,它同时桥接在 br-lan 里。我们需要在物理口上创建 VLAN 子接口。
2.2 创建 VLAN 设备
在 LuCI 中操作(网络 → 接口 → 设备 → 添加设备配置),或直接编辑 /etc/config/network:
# 在 bridge 上启用 VLAN 过滤,显式声明桥接成员端口config device option name 'br-lan' option type 'bridge' option vlan_filtering '1' list ports 'lan1'
# 管理 VLAN 10 —— lan1 端口 tagged 模式(Trunk)config bridge-vlan option device 'br-lan' option vlan '10' list ports 'lan1:t'
# IoT VLAN 20config bridge-vlan option device 'br-lan' option vlan '20' list ports 'lan1:t'
# 访客 VLAN 30config bridge-vlan option device 'br-lan' option vlan '30' list ports 'lan1:t'
# VLAN 10 接口 —— 管理网络config interface 'mgmt' option proto 'static' option device 'br-lan.10' option ipaddr '192.168.10.1' option netmask '255.255.255.0'
# VLAN 20 接口 —— IoT 网络config interface 'iot' option proto 'static' option device 'br-lan.20' option ipaddr '192.168.20.1' option netmask '255.255.255.0'
# VLAN 30 接口 —— 访客网络config interface 'guest' option proto 'static' option device 'br-lan.30' option ipaddr '192.168.30.1' option netmask '255.255.255.0'lan1:t 表示该端口在此 VLAN 中为 tagged 模式。因为是单 LAN 口做 router-on-a-stick,所有 bridge-vlan 条目中的 lan1 都设为 tagged(Trunk),不设 untagged 成员端口——untagged 流量由下游网管交换机的 access 口处理。
注意:如果原来的
config interface 'lan'还在且指向裸br-lan设备,启用 VLAN 过滤后会断连。需要把原有 lan 接口的option device改为br-lan.10(管理 VLAN),或删除原有 lan 接口、用 mgmt 替代。建议保留一个已建立的 SSH 会话,不要只依赖 LuCI。
配置完成后重启网络:
service network restart第三步:DHCP 多池分配
每个子网需要独立的 DHCP 池,让连接到对应交换机端口的设备自动获取正确 IP。
编辑 /etc/config/dhcp:
config dhcp option domainneeded '1' option authoritative '1' option local '/lan/' option domain 'lan' option leasefile '/tmp/dhcp.leases' option resolvfile '/tmp/resolv.conf.d/resolv.conf.auto' option ednspacket_max '1232'
# 管理网络 DHCPconfig dhcp 'mgmt' option interface 'mgmt' option start '100' option limit '150' option leasetime '12h' # option dhcpv4 'server' 可省略,OpenWrt 24.10 默认即为 DHCP 服务器模式
# IoT 网络 DHCPconfig dhcp 'iot' option interface 'iot' option start '100' option limit '150' option leasetime '24h'
# 访客网络 DHCPconfig dhcp 'guest' option interface 'guest' option start '100' option limit '150' option leasetime '2h'关键参数说明:
| 参数 | 说明 |
|---|---|
interface | 必须匹配 /etc/config/network 中 config interface 的名称 |
start | DHCP 池起始偏移,100 表示从 192.168.x.100 开始分配 |
limit | 最大租约数量,150 表示到 192.168.x.249 |
leasetime | 租约时长,访客网络设短一些 |
将
.2–.99预留给静态分配设备(NAS、打印机、摄像头),DHCP 池从.100起步。
如需为特定子网指定不同 DNS 或网关:
config dhcp 'guest' option interface 'guest' list dhcp_option '6,1.1.1.1' # 访客走不同 DNS ...重启 dnsmasq 使配置生效:
service dnsmasq restart第四步:防火墙 Zone 划分与跨网段路由
每个 VLAN 对应一个防火墙 zone,zone 之间通过 forwarding 规则控制互访。这是整个隔离方案的核心。
4.1 Zone 定义
编辑 /etc/config/firewall:
# === 默认策略 ===config defaults option input 'ACCEPT' option output 'ACCEPT' option forward 'REJECT' option synflood_protect '1'
# === Zone 定义 ===
# WAN — 互联网侧config zone option name 'wan' list network 'wan' list network 'wan6' option input 'DROP' option output 'ACCEPT' option forward 'DROP' option masq '1' option mtu_fix '1'
# 管理网络 — 可信config zone option name 'mgmt' list network 'mgmt' option input 'ACCEPT' option output 'ACCEPT' option forward 'ACCEPT'
# IoT — 不可信(设备不能访问路由器本身,除 DHCP/DNS)config zone option name 'iot' list network 'iot' option input 'REJECT' option output 'ACCEPT' option forward 'REJECT'
# 访客 — 完全隔离config zone option name 'guest' list network 'guest' option input 'REJECT' option output 'ACCEPT' option forward 'REJECT'
# === 跨 Zone 转发规则 ===
# mgmt → WAN(管理设备上网)config forwarding option src 'mgmt' option dest 'wan'
# iot → WAN(IoT 设备上网)config forwarding option src 'iot' option dest 'wan'
# guest → WAN(访客上网)config forwarding option src 'guest' option dest 'wan'
# mgmt → iot(从管理网络访问 IoT 设备)config forwarding option src 'mgmt' option dest 'iot'
# mgmt → guest(从管理网络访问访客网络,调试用)config forwarding option src 'mgmt' option dest 'guest'
# === 为不可信 Zone 开放 DHCP 和 DNS ===
config rule option name 'Allow-IoT-DHCP' option src 'iot' option dest_port '67' option proto 'udp' option target 'ACCEPT' option family 'ipv4'
config rule option name 'Allow-IoT-DHCP-Reply' option dest 'iot' option dest_port '68' option proto 'udp' option target 'ACCEPT' option family 'ipv4'
config rule option name 'Allow-IoT-DNS' option src 'iot' option dest_port '53' option proto 'tcp udp' option target 'ACCEPT'
config rule option name 'Allow-Guest-DHCP' option src 'guest' option dest_port '67' option proto 'udp' option target 'ACCEPT' option family 'ipv4'
config rule option name 'Allow-Guest-DHCP-Reply' option dest 'guest' option dest_port '68' option proto 'udp' option target 'ACCEPT' option family 'ipv4'
config rule option name 'Allow-Guest-DNS' option src 'guest' option dest_port '53' option proto 'tcp udp' option target 'ACCEPT'4.2 Zone 策略解读
| Zone | input | forward | 含义 |
|---|---|---|---|
| mgmt | ACCEPT | ACCEPT | 管理设备可以访问路由器(SSH/LuCI)和跨子网通信 |
| iot | REJECT | REJECT | IoT 设备不能访问路由器(除 DHCP/DNS),不能跨子网发起连接 |
| guest | REJECT | REJECT | 同上,访客完全隔离 |
| wan | DROP | DROP | 互联网侧,最严格 |
mgmt zone 安全建议:当前
option input 'ACCEPT'允许管理网段内所有设备直接访问路由器(SSH / LuCI)。为简化演示,此处设为 ACCEPT。生产环境建议按需收紧:将 input 改为REJECT,再单独添加规则仅允许特定管理 IP(如192.168.10.10)访问 SSH(端口 22)和 HTTPS(端口 443)。
关键认知:OpenWrt 的
forward控制的是 zone 之间的转发,不是 zone 内部的。同一 zone 内(比如同一个 VLAN)设备之间的通信不受forward限制——因为它们在同一个广播域,走交换机的二层转发,根本不过路由器。要想隔离同一个 VLAN 内的设备,需要用 无线 AP 的客户端隔离 或交换机的 端口隔离 功能。
4.3 跨 VLAN 通信原理
当 192.168.10.100(管理网络)ping 192.168.20.100(IoT 设备)时:
- 管理设备的网关是
192.168.10.1(OpenWrt br-lan.10 接口),设备发现目标不在本子网,将包发给网关 - OpenWrt 收到包,查询路由表:
192.168.20.0/24直连在br-lan.20接口上 - OpenWrt 检查防火墙:
mgmt → iot的 forwarding 规则存在,放行 - 包从
br-lan.20发出,到达 IoT 设备 - IoT 设备回包时,conntrack 识别这是已有连接的回复,自动放行(不需要反向 forwarding 规则)
OpenWrt 的 fw4(nftables)防火墙是有状态的。
config forwarding只需配单向(发起方向),回复流量会被 conntrack 自动匹配ct state established,related规则放行。
4.4 应用防火墙
service firewall restart或者直接重载全部配置:
/etc/init.d/firewall reloadIPv6 兼容提示:本文防火墙规则以 IPv4 为例(
option family 'ipv4')。如果你的网络同时启用 IPv6,需要为每个 DHCP 和 DNS 规则创建对应的 IPv6 版本(或删除option family限制),并额外放行 DHCPv6 端口(客户端 UDP 546,服务器 UDP 547)和 ICMPv6(IPv6 依赖 ICMPv6 做邻居发现和路由通告,阻止会导致 SLAAC 和 DHCPv6 均不可用)。基本规则示例:config ruleoption name 'Allow-IoT-DHCPv6'option src 'iot'option dest_port '547'option proto 'udp'option target 'ACCEPT'option family 'ipv6'config ruleoption name 'Allow-IoT-ICMPv6'option src 'iot'option proto 'icmp'option target 'ACCEPT'option family 'ipv6'以上示例以 IoT 区域为例,guest 区域也需要复制对应的 ICMPv6 和 DHCPv6 放行规则,否则访客网络的 IPv6 将不可用。
第五步:WireGuard 远程子网接入
配好本地 VLAN 隔离后,加上远程接入能力:当你不在家时,通过 WireGuard 拨入 OpenWrt,能访问管理网络和 IoT 网络。
5.1 创建 WireGuard 接口
编辑 /etc/config/network,追加:
# WireGuard 隧道接口config interface 'wg_remote' option proto 'wireguard' option private_key '<OpenWrt 私钥>' option listen_port '51820' list addresses '10.99.88.1/24'
# 远程终端 Peerconfig wireguard_wg_remote option description 'my_phone' option public_key '<终端公钥>' option preshared_key '<PSK>' option persistent_keepalive '25' option route_allowed_ips '1' # 重要:务必显式设置,其默认值为 1 list allowed_ips '10.99.88.10/32' # 终端隧道 IP list allowed_ips '192.168.10.0/24' # 允许访问管理网络 list allowed_ips '192.168.20.0/24' # 允许访问 IoT 网络 # 注意:不包含 192.168.30.0/24(访客网络)生成密钥:
# 在 OpenWrt 上wg genkey | tee /tmp/private.key | wg pubkey > /tmp/public.keycat /tmp/private.key # 填入 option private_keycat /tmp/public.key # 用于终端 Peer 配置关于
route_allowed_ips:此选项默认即为1,OpenWrt 会自动将 peer 中allowed_ips声明的子网路由安装到主路由表。作为 WireGuard 服务端时,请务必保留option route_allowed_ips '1'(或显式声明为 1)。若 OpenWrt 未来作为客户端连接 VPN 服务商,必须将其设为0并手动添加路由,否则0.0.0.0/0的路由会覆盖默认网关,导致所有流量被劫持。
5.2 创建 WireGuard 防火墙 Zone
在 /etc/config/firewall 中添加:
# WireGuard 远程接入 zoneconfig zone option name 'wg_remote' list network 'wg_remote' option input 'ACCEPT' option output 'ACCEPT' option forward 'ACCEPT'
# 允许 WAN 访问 WireGuard 端口config rule option name 'Allow-WireGuard' option src 'wan' option dest_port '51820' option proto 'udp' option target 'ACCEPT'
# WG remote → 管理网络config forwarding option src 'wg_remote' option dest 'mgmt'
# WG remote → IoT 网络config forwarding option src 'wg_remote' option dest 'iot'
# 双向:管理网络也能主动访问远程终端(可选)config forwarding option src 'mgmt' option dest 'wg_remote'
# WG remote → WAN(远程终端通过家里网络上网,可选)config forwarding option src 'wg_remote' option dest 'wan'安全提示:
list allowed_ips控制的是路由层面——WireGuard 只接受这些目标子网的流量。但真正的访问控制在防火墙 zone 的 forwarding 规则——你的最后一道防线。allowed_ips 只是”允许路由”,forwarding 规则才是”允许通过”。两者缺一不可。
5.3 终端 WireGuard 配置
以手机 WireGuard 客户端为例:
[Interface]PrivateKey = <终端私钥>Address = 10.99.88.10/32DNS = 192.168.10.1
[Peer]PublicKey = <OpenWrt 公钥>PresharedKey = <PSK>Endpoint = <你的公网IP或DDNS>:51820AllowedIPs = 10.99.88.0/24, 192.168.10.0/24, 192.168.20.0/24PersistentKeepalive = 25
AllowedIPs在终端侧控制的是哪些流量走隧道。这里只把家里子网的流量送入隧道,其余流量(比如刷网页)走终端的正常网络,即 split tunneling。
第六步:验证测试
每改完一层配置就验证一层,不要全部配完再测——出了问题很难定位。
6.1 VLAN 与 DHCP 验证
# 检查 VLAN 设备是否创建成功ip -d link show br-lan.10ip -d link show br-lan.20ip -d link show br-lan.30
# 检查接口状态ip addr show | grep "192.168"
# 检查 DHCP 服务是否在监听(优先使用 ss)ss -tuln | grep ':67\b'# 备选:netstat -tuln | grep ':67 '
# 查看 DHCP 租约cat /tmp/dhcp.leases在对应交换机端口上接入设备,确认获取到正确的 IP(管理设备应拿到 192.168.10.x,IoT 设备应拿到 192.168.20.x)。
6.2 跨子网通信验证
从管理网络(192.168.10.x)测试:
# Ping IoT 子网网关ping -c 3 192.168.20.1
# Ping IoT 子网中的设备ping -c 3 192.168.20.100
# Ping 访客子网网关ping -c 3 192.168.30.1
# Traceroute 查看路径traceroute 192.168.20.100从 IoT 网络(192.168.20.x)测试:
# 应失败 — IoT 不能主动访问管理网络ping -c 3 192.168.10.1ping -c 3 192.168.10.100从访客网络(192.168.30.x)测试:
# 都应失败 — 访客完全隔离ping -c 3 192.168.10.1ping -c 3 192.168.20.16.3 端口扫描验证
用 nmap 从管理网络扫 IoT 子网:
# 从 192.168.10.x 执行nmap -sn 192.168.20.0/24应该能看到 IoT 子网中的在线设备。
从 IoT 网络扫管理子网(应失败):
nmap -sn 192.168.10.0/24# 预期:所有 host down(ping 被防火墙阻挡)6.4 WireGuard 验证
在远程终端连上 WireGuard 后:
# 在 OpenWrt 上检查握手wg show
# 应看到:# latest handshake: <几秒前># transfer: <有数据传输>
# 从远程终端 ping OpenWrt 隧道 IPping -c 3 10.99.88.1
# 从远程终端 ping 管理网络设备ping -c 3 192.168.10.100
# 从远程终端 ping IoT 设备ping -c 3 192.168.20.100
# 从远程终端 ping 访客网络(应失败)ping -c 3 192.168.30.16.5 防火墙规则检查
# 查看当前生效的 nftables 规则nft list ruleset
# 只看转发规则nft list chain inet fw4 forward
# 检查 zone 配置uci show firewall | grep forwarding常见问题
Q:配置 VLAN 后把自己锁在外面了,LuCI 和 SSH 都连不上
通常是改错了管理 VLAN 的接口配置。用网线直连 OpenWrt 的 LAN 口(不走交换机),如果 OpenWrt 的 LAN 口还有 untagged 的默认 VLAN 配置,应该还能连上。紧急恢复:OpenWrt 的 failsafe 模式或重置配置。
预防:改 VLAN 配置前,先用
reload而非restart,并保持一个已建立的 SSH 会话不要断开。如果 reload 后新会话连不上,在旧会话里回滚配置。
Q:同一 VLAN 内的设备可以互访,防火墙挡不住
这是预期行为。同一个 VLAN 内的设备在同一个二层广播域,它们的通信走交换机直接转发,不经过 OpenWrt 的三层路由。要隔离同一 VLAN 的设备:
- 无线隔离:在
/etc/config/wireless中对应 SSID 的config wifi-iface段添加option isolate '1',阻止连接同一 SSID 的客户端互访 - 有线端口隔离:在网管交换机上启用 Port Isolation(不同品牌叫法不同:TP-Link 叫”端口隔离”、Netgear 叫”Port Protection”、Cisco 叫”Private VLAN Edge”),将同一 VLAN 内的端口彼此隔离,仅允许与上联口通信
Q:IoT 设备获取不到 IP 地址
三步排查:
- DHCP 服务是否在对应接口上监听:
ss -tuln | grep ':67\b' - 防火墙是否允许 DHCP 请求和回复(UDP 67 和 68):
nft list chain inet fw4 input_iot | grep -E '67|68' - 交换机 VLAN 配置是否正确:检查对应端口的 PVID 和 untagged VLAN 是否匹配
Q:跨 VLAN 能 ping 通网关但 ping 不通设备
检查目标设备的防火墙。Windows 防火墙默认阻止来自其他子网的 ICMP,Linux 的 ufw 也可能 drop。这和 OpenWrt 没关系——网关能通说明路由和 forwarding 都正常,问题在目标设备自身。
Q:WireGuard 握手成功但 ping 不通内网
常见原因:
- 防火墙 zone 的 forwarding 规则漏配——检查
wg_remote → mgmt的 forwarding 是否存在 route_allowed_ips未设置为1——内核没有安装到内网子网的路由- 终端侧的
AllowedIPs不包含内网子网——WireGuard 不会把该流量封装进隧道
总结与扩展思路
本文搭了一套基础的 VLAN 隔离方案。在此基础上可以扩展:
- 策略路由:让 IoT 子网的流量单独走 VPN 出口(适合某些需要特定地区 IP 的智能家居设备),用
ip rule+ip route配合 mwan3 或 pbr 包实现 - mDNS 跨子网转发:IoT 设备如打印机、音箱依赖 mDNS 做发现,跨 VLAN 后失效。用 Avahi 做 mDNS reflector 或重分发可以解决
- IPv6 隔离:本文配的是 IPv4,IPv6 的 VLAN 隔离逻辑类似,但需要额外处理 SLAAC 和 DHCPv6,且防火墙规则要同时覆盖 IPv4 和 IPv6
- Guest Captive Portal:对访客网络加认证门户