你是否遇到过这样的场景? 工控现场有两个不同网段的设备(如 192.168.1.0/24 和 10.0.0.0/24),需要让它们互通;或者说手头有一块双网口的Linux开发板(如树莓派、RK3568等),想把它改造成“迷你路由器”。
为什么能实现跨网段通信 #
核心原理 #
- 路由器的本质:路由器通过多个网口连接不同子网,并根据路由表转发数据包。
- IP转发(IP Forwarding):Linux内核支持IP转发功能,可将开发板变成“软件路由器”。
- *子网隔离与通信:不同网段的设备默认无法直接通信,需通过路由设备中转。
IP转发 #
那么稍微陌生一点的应该是IP转发了,那什么是IP转发呢?
IP转发(IP Forwarding) 是Linux内核的一项核心功能,允许系统将接收到的网络数据包从一个网络接口(如 eth0)转发到另一个接口(如 eth1)。这本质上实现了路由器的核心功能——在不同网络之间传递数据包。
IP转发的工作原理
- 数据包处理流程
- 当数据包到达开发板的某个网口(如 eth0)时,内核会检查目标IP地址。
- 如果目标地址属于另一个子网(如 10.0.0.0/24),且IP转发已启用,内核会将数据包转发到对应的接口(如 eth1)。
- 若未启用IP转发,内核会直接丢弃非本机接收的数据包。
- 依赖条件
- 路由表:内核通过路由表决定数据包的转发路径。
- 防火墙规则:需允许转发流量(如 iptables 或 nftables 规则)。
- NAT(可选):若需要隐藏内部网络或共享公网IP,需配置网络地址转换。
- 实现方式
- 直接路由:开发板直接连接两个子网,仅需启用IP转发即可,那么下面小哥也会跟大家重点谈谈这种方式。
- NAT转发:若需访问外网,需额外配置NAT。
环境准备 #
- 软硬件准备:双网口Linux开发板,两个子网的设备,下面相关的配置小哥会以Systemd启动服务进行说明。
- 拓扑示意:
分步配置教程 #
- 配置双网口IP地址(Systemd-networkd)
目标:为 eth0
和 eth1
分配静态IP。
- 创建配置文件:
# 配置 eth0(子网A)
sudo vim /etc/systemd/network/10-eth0.network
输入以下内容:
[Match]
Name=eth0
[Network]
Address=192.168.1.100/24
# 若需设置网关(如连接外网)
# Gateway=192.168.1.1
- 同理配置 eth1:
sudo nano /etc/systemd/network/10-eth1.network
[Match]
Name=eth1
[Network]
Address=10.0.0.100/24
- 重启服务生效:
sudo systemctl restart systemd-networkd
验证IP配置:
ip addr show eth0 && ip addr show eth1
- 启用IP转发
编辑sysctl配置文件:
sudo vim /etc/sysctl.d/99-ip-forward.conf
添加内容:
net.ipv4.ip_forward=1
立即生效:
sudo sysctl --system
验证:
cat /proc/sys/net/ipv4/ip_forward
# 输出应为 1
- 配置防火墙(允许流量转发)
创建iptables规则文件:
sudo nano /etc/iptables/rules.v4
添加规则:
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A FORWARD -i eth0 -o eth1 -j ACCEPT
-A FORWARD -i eth1 -o eth0 -j ACCEPT
COMMIT
创建Systemd服务加载规则:
sudo nano /etc/systemd/system/load-iptables.service
内容:
[Unit]
Description=Load iptables rules
After=network.target
[Service]
Type=oneshot
ExecStart=/sbin/iptables-restore /etc/iptables/rules.v4
[Install]
WantedBy=multi-user.target
启用服务:
sudo systemctl daemon-reload
sudo systemctl enable --now load-iptables.service
- 配置路由(可选)
若子网A或B需要访问其他外部网络(如互联网),需添加默认路由,后面小哥会聊一下,为什么访问外网需要设置网关:
# 示例:通过 eth0 的网关访问外网
sudo vim /etc/systemd/network/10-eth0.network
在 [Network] 部分添加:
Gateway=192.168.1.1
测试与验证 #
- 从子网A设备ping子网B设备
ping 10.0.0.200
- 从子网B设备ping子网A设备
ping 192.168.1.200
- 检查路由表
ip route show
预期输出包含两个直连子网:
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.100
10.0.0.0/24 dev eth1 proto kernel scope link src 10.0.0.100
前面谈到访问外网需要配置路由,可能有些朋友还不太好理解,这里详细说明下:
假设你生活在一个小镇(子网A,地址范围 192.168.1.0/24),镇上每家每户都有一个门牌号(如 192.168.1.2、192.168.1.3)。
- 本地通信
如果你想给邻居送一封信(数据包),可以直接投递到邻居家的信箱(ARP协议直接通信)。
而且当采用双网口Linux开发板,由于启动了IP转发,允许了内核转发跨接口的数据包,两个端口设置好IP口那么直连子网的IP会自动的生成,也就是上面通过ip route show命令看到的,不过这个的前提是两个子网都不访问外网的情况。总结起来就是双网口开发板连接两个本地子网时,必须配置接口IP、启用IP转发,并确保子网设备将开发板设为网关。开发板会自动管理直连子网的路由,无需额外设置路由IP(如静态路由或默认网关)。
- 外部通信
如果你想给另一个城市的朋友(如互联网上的服务器 8.8.8.8)寄信,必须通过小镇的邮局(网关)中转,属于非直连子网,若开发板需要访问另一个子网(如 172.16.0.0/24),且该子网需通过网关 192.168.1.1到达,则需设置网关或静态路由。
- 注意
在双网口开发板中,通常只有一个网口需要设置网关(通常是连接外网的接口),避免路由冲突。
Gateway=192.168.1.1 # 关键:定义默认路由
验证路由表
$ ip route show
default via 192.168.1.1 dev eth0 # 默认路由指向网关
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.100
10.0.0.0/24 dev eth1 proto kernel scope link src 10.0.0.100
配置NAT访问外网 #
若子网B设备需通过开发板访问外网,添加NAT规则:
# 修改 /etc/iptables/rules.v4
*nat
-A POSTROUTING -o eth0 -j MASQUERADE
COMMIT
重启服务:
sudo systemctl restart load-iptables.service
通过一块双网口开发板 就搭建了一个跨网段路由系统。无论是工业现场还是智能家居,这种低成本、高灵活性的方案都值得尝试!