引言
有些“网络加速”工具并不会提供传统意义上的 HTTP、SOCKS5 或 Clash 节点,而是给出一组更底层的三层网络参数:一个私有加速 IP、一个私有网关,以及对应的出口链路。
单台设备使用时,通常只需要在设备上手动配置 IP、掩码、网关即可。但如果希望让局域网内的多台设备共享这条加速链路,并且只让部分目标 IP 走加速,就需要在路由器上完成策略路由和源地址转换。
本文记录一次在 iStoreOS / OpenWrt 上接入私有加速网关的完整过程。为避免暴露具体软件特征,文中的加速网段使用虚构的 RFC1918 私有地址,目标 IP 使用 RFC 5737 文档示例地址。实际使用时请替换为自己的参数。
需求与网络模型
实际需求是:局域网内的设备仍然默认走原有宽带出口,只让少数特定目标 IP 走私有加速网关。
本文统一使用以下虚构示例参数:
路由器系统:iStoreOS / OpenWrtLAN 设备:br-lanLAN 网段:192.168.50.0/24路由器 LAN 地址:192.168.50.1示例客户端地址:192.168.50.23
虚构加速网段:10.88.7.0/24虚构加速 IP:10.88.7.10/24虚构加速网关:10.88.7.1虚构加速掩码:255.255.255.0
需要走加速的目标 IP 示例: 203.0.113.10/32 203.0.113.20/32其中 10.88.7.0/24 是本文自造的私有网段,用来模拟加速软件分配的私有链路;203.0.113.0/24 是 RFC 5737 定义的文档示例地址段,不是真实目标。实际使用时,把这些示例参数替换成自己的加速 IP、加速网关和目标 IP。如果你的局域网、VPN、容器网络或其他隧道已经使用 10.88.7.0/24,请换成不会冲突的私有网段。
目标流量模型如下:
普通访问:LAN 客户端 → iStoreOS → 普通 WAN / PPPoE 出口
指定目标访问:LAN 客户端 → iStoreOS → SNAT 为 10.88.7.10 → 10.88.7.1 → 加速出口这不是全局代理,也不是透明代理。它更接近“基于目标 IP 的策略路由 + 源地址转换”。
为什么不能只加静态路由
如果只在路由器上添加:
203.0.113.10/32 via 10.88.7.1203.0.113.20/32 via 10.88.7.1那么路由器只知道这些目标应该发给加速网关,但局域网客户端原始源地址仍然是:
192.168.50.23而私有加速网关通常只接受分配给你的加速 IP,例如本文示例里的:
10.88.7.10因此,LAN 客户端流量必须在路由器出站时被 SNAT 成加速 IP:
192.168.50.23 → 10.88.7.10这就是本方案的核心。
实现思路
完整实现分为四步:
- 在
br-lan上增加加速 IP:10.88.7.10/24 - 为指定目标 IP 添加静态路由,经由
10.88.7.1 - 在 nftables / fw4 中添加 SNAT,把 LAN 源地址改成
10.88.7.10 - 验证路由、邻居表、SNAT 计数器和实际访问结果
其中第 3 步是最容易踩坑的地方。本次最终确认:SNAT 规则应尽量靠前执行,最终放在:
/usr/share/nftables.d/chain-pre/srcnat/05-accel-snat.nft本案例中不建议放在:
/usr/share/nftables.d/chain-post/srcnat/90-accel-snat.nft后者虽然能在 nft list chain inet fw4 srcnat 中看到规则,但执行位置偏后,可能无法达到与临时 nft insert rule 相同的效果。
先定义示例变量
为了让后续命令更清晰,先定义统一变量。本文后面的命令都基于同一组变量。
LAN_IF="br-lan"LAN_CIDR="192.168.50.0/24"
ACCEL_IP="10.88.7.10"ACCEL_PREFIX="24"ACCEL_NETMASK="255.255.255.0"ACCEL_GW="10.88.7.1"
TARGETS="203.0.113.10 203.0.113.20"实际部署时,只需要把这一段改成自己的真实参数,后面的命令逻辑保持不变。后文的验证和回滚命令也依赖这些变量;如果重新打开了 SSH 会话,需要先重新执行这一段变量定义。
前置验证:先用单台设备直连测试
在改路由器之前,建议先用一台手机、电脑或临时测试设备直连这条加速链路。测试设备手动配置加速 IP、子网掩码和加速网关后,直接访问真实目标服务。
这一步的目的不是配置路由器,而是确认加速链路本身可用:
测试设备 IP:10.88.7.10子网掩码:255.255.255.0网关:10.88.7.1如果单设备直配后仍然无法走加速,问题大概率不在 OpenWrt;应先检查加速软件、链路授权、网关可达性或目标是否匹配。
如果单设备直配正常,再继续下面的路由器接管配置。
第一步:确认加速网关二层可达
在做持久化配置前,先确认路由器能不能在二层上找到加速网关。
先临时让路由器持有加速 IP:
ip addr add "$ACCEL_IP/$ACCEL_PREFIX" dev "$LAN_IF" 2>/dev/null || true然后清理邻居缓存并测试:
ip neigh flush dev "$LAN_IF"ping -c 3 -W 1 -I "$ACCEL_IP" "$ACCEL_GW"ip neigh show dev "$LAN_IF" | grep "$ACCEL_GW"理想结果类似:
10.88.7.1 lladdr xx:xx:xx:xx:xx:xx REACHABLE这里重点看邻居表状态。REACHABLE 说明路由器能解析到网关 MAC,二层链路成立。
如果看到的是:
FAILEDINCOMPLETE则说明路由器到加速网关的二层链路不通。此时继续配置静态路由和 SNAT 也没有意义,应先检查加速软件所在设备、交换网络、桥接模式或 IP 是否被其他设备占用。
部分私有加速网关可能对 ICMP 有限速或特殊处理,所以不能仅凭 ping 延迟判断 TCP/UDP 加速效果。
第二步:配置 accel 接口
在 OpenWrt / iStoreOS 中,可以通过 UCI 增加一个静态接口。这里让 br-lan 额外持有加速 IP。
uci -q delete network.accel
uci set network.accel='interface'uci set network.accel.proto='static'uci set network.accel.device="$LAN_IF"uci set network.accel.ipaddr="$ACCEL_IP"uci set network.accel.netmask="$ACCEL_NETMASK"uci set network.accel.gateway="$ACCEL_GW"uci set network.accel.metric='500'uci set network.accel.defaultroute='0'uci set network.accel.peerdns='0'
uci commit network/etc/init.d/network reload这里有两个参数很关键:
defaultroute='0'peerdns='0'原因是:本需求并不是让整个路由器默认出口都切到加速网关,而是只让指定目标 IP 走加速。普通流量仍应走原来的 WAN / PPPoE 出口。
如果你的加速 IP 不是 /24,需要同时修改:
ACCEL_PREFIX="24"ACCEL_NETMASK="255.255.255.0"例如 /16 对应 255.255.0.0,/24 对应 255.255.255.0。
配置后检查:
ip -4 addr show dev "$LAN_IF"ip route | grep default期望结果是:
br-lan 上同时存在原 LAN 地址和加速 IP默认路由仍然指向原来的 WAN / PPPoE 出口第三步:添加目标 IP 静态路由
先清理旧的目标路由,避免重复。
for ip in $TARGETS; do while true; do section=$(uci show network | grep "\.target='$ip/32'" | cut -d. -f2 | cut -d= -f1 | head -n 1) [ -z "$section" ] && break echo "Deleting network.$section target=$ip/32" uci delete network.$section donedone
uci commit network/etc/init.d/network reload再添加新的静态路由:
for ip in $TARGETS; do uci add network route uci set network.@route[-1].interface='accel' uci set network.@route[-1].target="$ip/32" uci set network.@route[-1].gateway="$ACCEL_GW"done
uci commit network/etc/init.d/network reload验证路由:
for ip in $TARGETS; do ip route get "$ip"done正确结果应类似:
203.0.113.10 via 10.88.7.1 dev br-lan src 10.88.7.10203.0.113.20 via 10.88.7.1 dev br-lan src 10.88.7.10这说明路由器自己访问这些目标时,已经会从加速 IP 出去。
但这还不够。LAN 客户端访问时,源地址仍然是内网地址,还需要 SNAT。
第四步:配置 SNAT
OpenWrt 22.03 之后使用 fw4 和 nftables。自定义 nft 规则可以通过 /usr/share/nftables.d/ 下的 include 目录加载。
本次踩坑点在这里:最初把 SNAT 规则放到了:
/usr/share/nftables.d/chain-post/srcnat/90-accel-snat.nft规则可以显示在 nft list chain inet fw4 srcnat 中,但实际没有达到预期效果。
后来用临时命令测试:
for ip in $TARGETS; do nft insert rule inet fw4 srcnat ip saddr "$LAN_CIDR" ip daddr "$ip" oifname "$LAN_IF" counter snat ip to "$ACCEL_IP"done临时规则可以正常加速。由此判断,问题不是路由器不能转发,也不是加速网关拒绝 NAT 流量,而是持久化规则的加载位置或执行顺序不对。
最终改为放到 chain-pre/srcnat:
mkdir -p /usr/share/nftables.d/chain-pre/srcnat
{ for ip in $TARGETS; do echo "ip saddr $LAN_CIDR ip daddr $ip oifname \"$LAN_IF\" counter snat ip to $ACCEL_IP" done} > /usr/share/nftables.d/chain-pre/srcnat/05-accel-snat.nft
/etc/init.d/firewall reload如果之前创建过 chain-post 规则文件,建议移走,避免重复或干扰:
mkdir -p /root/accel-clean-backup
mv /usr/share/nftables.d/chain-post/srcnat/90-accel-snat.nft \ /root/accel-clean-backup/90-accel-snat.nft.disabled.$(date +%Y%m%d-%H%M%S) 2>/dev/null
/etc/init.d/firewall reload检查规则是否加载:
nft list chain inet fw4 srcnat | grep -E "$(echo $TARGETS | sed 's/ /|/g')|$ACCEL_IP"应看到类似:
ip saddr 192.168.50.0/24 ip daddr 203.0.113.10 oifname "br-lan" counter snat ip to 10.88.7.10ip saddr 192.168.50.0/24 ip daddr 203.0.113.20 oifname "br-lan" counter snat ip to 10.88.7.10完整一键配置命令
下面是一组可直接执行的完整配置模板。执行前请根据自己的环境修改变量。
# ===== 修改这里 =====LAN_IF="br-lan"LAN_CIDR="192.168.50.0/24"
ACCEL_IP="10.88.7.10"ACCEL_PREFIX="24"ACCEL_NETMASK="255.255.255.0"ACCEL_GW="10.88.7.1"
TARGETS="203.0.113.10 203.0.113.20"# ====================
# 1. 配置 accel 接口uci -q delete network.accel
uci set network.accel='interface'uci set network.accel.proto='static'uci set network.accel.device="$LAN_IF"uci set network.accel.ipaddr="$ACCEL_IP"uci set network.accel.netmask="$ACCEL_NETMASK"uci set network.accel.gateway="$ACCEL_GW"uci set network.accel.metric='500'uci set network.accel.defaultroute='0'uci set network.accel.peerdns='0'
uci commit network/etc/init.d/network reload
# 2. 清理旧目标路由for ip in $TARGETS; do while true; do section=$(uci show network | grep "\.target='$ip/32'" | cut -d. -f2 | cut -d= -f1 | head -n 1) [ -z "$section" ] && break uci delete network.$section donedone
uci commit network/etc/init.d/network reload
# 3. 添加目标路由for ip in $TARGETS; do uci add network route uci set network.@route[-1].interface='accel' uci set network.@route[-1].target="$ip/32" uci set network.@route[-1].gateway="$ACCEL_GW"done
uci commit network/etc/init.d/network reload
# 4. 移除旧 chain-post 规则,使用 chain-pre 规则mkdir -p /root/accel-clean-backupmv /usr/share/nftables.d/chain-post/srcnat/90-accel-snat.nft \ /root/accel-clean-backup/90-accel-snat.nft.disabled.$(date +%Y%m%d-%H%M%S) 2>/dev/null
mkdir -p /usr/share/nftables.d/chain-pre/srcnat{ for ip in $TARGETS; do echo "ip saddr $LAN_CIDR ip daddr $ip oifname \"$LAN_IF\" counter snat ip to $ACCEL_IP" done} > /usr/share/nftables.d/chain-pre/srcnat/05-accel-snat.nft
/etc/init.d/firewall reload验证配置是否生效
配置完成后,建议按以下顺序验证。如果已经重新打开 SSH 会话,请先重新执行前文的变量定义部分。
1. 检查地址
ip -4 addr show dev "$LAN_IF"应看到原 LAN 地址和加速 IP。
2. 检查目标路由
for ip in $TARGETS; do ip route get "$ip"done应看到:
via 10.88.7.1 dev br-lan src 10.88.7.103. 检查 SNAT 规则
nft -a list chain inet fw4 srcnat | grep -E "$(echo $TARGETS | sed 's/ /|/g')"将 TARGETS 替换成真实目标 IP 后,从 LAN 客户端访问对应服务;如果 counter packets 增长,说明规则命中。
4. 抓包确认源地址
# 将 203.0.113.10 / 203.0.113.20 替换成你的真实目标 IPtcpdump -ni "$LAN_IF" "(host 203.0.113.10 or host 203.0.113.20 or host $ACCEL_GW)"正常情况下,访问目标 IP 时可以看到源地址已经变成:
10.88.7.105. 确认默认路由没有被污染
ip route | grep defaultip route get 1.1.1.1普通流量应继续走原 WAN / PPPoE 出口,而不是加速网关。
如何清理或回滚
如果后续不再让路由器占用加速 IP,需要先释放相关配置。以下命令同样依赖前文变量;如果已经重新打开 SSH 会话,请先重新执行变量定义部分,或手动把变量替换成真实值。
删除 accel 接口和相关路由
while true; do section=$(uci show network | grep "\.interface='accel'" | cut -d. -f2 | cut -d= -f1 | head -n 1) [ -z "$section" ] && break uci delete network.$sectiondone
uci -q delete network.acceluci commit network/etc/init.d/network reload删除运行时残留地址
ip addr del "$ACCEL_IP/$ACCEL_PREFIX" dev "$LAN_IF" 2>/dev/nullip neigh del "$ACCEL_GW" dev "$LAN_IF" 2>/dev/null移走 SNAT 文件
mkdir -p /root/accel-clean-backup
mv /usr/share/nftables.d/chain-pre/srcnat/05-accel-snat.nft \ /root/accel-clean-backup/05-accel-snat.nft.disabled.$(date +%Y%m%d-%H%M%S) 2>/dev/null
mv /usr/share/nftables.d/chain-post/srcnat/90-accel-snat.nft \ /root/accel-clean-backup/90-accel-snat.nft.disabled.$(date +%Y%m%d-%H%M%S) 2>/dev/null
/etc/init.d/firewall reload检查清理结果
ip -4 addr show dev "$LAN_IF"ip route | grep -E "$(echo $TARGETS | sed 's/ /|/g')|$ACCEL_GW|$ACCEL_IP"uci show network | grep -E "accel|$(echo $TARGETS | sed 's/ /|/g')|$ACCEL_GW|$ACCEL_IP"nft list chain inet fw4 srcnat | grep -E "$(echo $TARGETS | sed 's/ /|/g')|$ACCEL_IP"理想状态是:
br-lan 只剩原 LAN 地址没有 accel 接口没有目标静态路由没有相关 SNAT 规则本次踩坑总结
这次问题最容易误判的地方是:
ip route get 正确nft list chain 也能看到规则但实际没有加速这说明“能看到规则”不等于“规则在正确的位置被优先命中”。
最终有效的判断链路是:
- 单设备直配加速 IP 能用,说明加速网关本身可用。
- 路由器邻居表为
REACHABLE,说明 br-lan 到加速网关二层可达。 - 临时
nft insert rule正常,说明路由器转发 + SNAT 这种模式可行。 - 把规则从
chain-post/srcnat改到chain-pre/srcnat后正常,说明关键差异是 fw4/nftables 的规则执行顺序。
所以本方案真正的关键不是“加一条 SNAT”这么简单,而是:
在 OpenWrt fw4 中,把这条 SNAT 放到足够靠前的位置。结语
对于这类只提供私有 IP 和私有网关的加速服务,路由器接管的本质是“目标路由 + 源地址转换”。
如果只是单台设备使用,手动配置加速 IP 和网关即可。如果希望局域网内多个设备共享,并且只让指定目标走加速,那么在 OpenWrt/iStoreOS 上实现是可行的,但需要特别注意 fw4/nftables 的规则顺序。
本次最终稳定配置可以概括为:
br-lan 持有加速 IP目标 IP 静态路由到加速网关LAN 访问目标 IP 时 SNAT 为加速 IPSNAT 文件放到 chain-pre/srcnat这套方式不会污染普通默认路由,也不会让所有流量都走加速链路,适合只针对少数目标 IP 做定向加速的场景。