0%

记一次使用iKuai ByPass替换旁路由模式分流的全过程

前言

自从使用PVE搭建双软路由系统(iKuai+OpenWRT),使用DHCP分段使用不同网关通过旁路由的方式实现了家里不同设备分段上网的方案之后,家里的网络一直稳定运行,各司其职,没出什么大问题。直至我购买了TP-Link的摄像头安装在老家,并在尝试将老家接人到深圳的NVR时,出现了问题。

问题

NVR无法接入异地摄像头

国庆回老家安装好摄像头之后,就想着用深圳的NVR把新装的摄像头接入管理,为了安全考虑,深圳的NVR网关指向的是iKuai而不是安装有WireGuardOpenWRT,于是乎发现想要接入老家这边新安装的摄像头时提示找不到对应设备的情况:

image-20241017001818470

经过检查,老家的摄像头接的网关是安装有WireGuardOpenWRT,深圳的NVR接的网关也是安装有WireGuardOpenWRT,于是想到有可能是ACL影响到了。为了防止IPCNVR联网,深圳的iKuai我是加了阻断出站的ACL规则:

image-20241017002401842

知道原因那就好办了,只需要增加允许出站到老家网络的网段(我这里是10.0.1.0/24)即可:

image-20241017002746776

iKuai限制NVR和IPC联网的ACL不生效

在老家安装好摄像头并接入到TP-Link物联APP之后,顺手启用了iKuai阻断摄像头出站的ACL规则。但是启用后再打开APP发现居然还能通过外网访问摄像头。经排查发现,原来是因为老家网络默认将网关指向了OpenWRT,这导致流量没有先流到iKuai,所以导致了阻断摄像头出站的ACL规则不生效。那么解决的办法只有将网关改为指向iKuai,但是因为WireGuard是安装在OpenWRT上,流量不能不流经OpenWRT,经过搜索发现了iKuai ByPass。原理是网关统一指向iKuai,然后由iKuai的分流规则再将流量流向OpenWRT,这样就能完美解决我遇到的问题,而且还能将不需要代理的流量直接拦截在iKuai处理,不需要再通过不同网关的这种旁路模式实现科学上网,同时即使OpenWRT宕机也不影响直连网络的访问,妙哉妙哉。找到解决方案之后,接下来当然是想办法实施了。

方案

iKuai ByPass有两种方式可以实现,分别是多WAN负载和指定下一跳网关。两种分流方式主要区别是:指定下一跳不需要多WAN,OpenWRT不需要多网口,但是只支持纯IP分流规则;多WAN负载需要多WAN口,OpenWRT需要一WAN一LAN,优势是支持域名和IP分流规则。我这里选择的是多WAN分流,也即iKuai上的多线负载。全程不会导致网络失联,在重启的时候会加上保底机制。

iKuai方面设置

增加WAN口用来做负载出口

那么第一步当然是先在iKuai上先增加一个用来做分流国外流量的WAN口,如果你是远程操作异地的iKuai的话,这里切记不要勾选设此线路为默认网关,以免断网;IP不重要,随意定义一个就行,网关的IP需要给OpenWRT的LAN口用;其他保持默认即可:

image-20241018081232980

同步域名和IP规则

我这里选择了使用joyanhui/ikuai-bypass这个项目来做规则自动同步,你也可以直接维护规则。

设置分流规则

首先在端口分流里面添加防止环回的策略:

image-20241025090027598

其他的分流规则上面的自动脚本会同步,只需要修改对应的网口名为自己iKuai中的网口名即可。这是我使用的配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
ikuai-url: http://10.0.0.254 # 爱快网页控制台登陆地址 结尾不要加 "/",如在爱快docker内运行,网关就是爱快地址,可以不写,如不填写,则使用第一个接口的网关地址,
username: admin # ikuai username 爱快登陆用户名
password: password # ikuai user password爱快登陆密码
cron: 0 7 * * * # crontab 执行更新的周期 格式为linux crontab 格式 注意时区问题,也可以用 @every 24h00m00s 表示每间隔24小时执行一次
AddErrRetryWait: 10s # 自动重试时间间隔 时间格式为 10s 120s
AddWait: 1s # 添加规则后等待时间 等待爱快反应 适合性能低的设备

ip-group: # IP分组 和端口分流配合使用
- name: 国内 # IP分组名称,分为多个时在名称后面拼接“序号”,如“国内_1” 因为爱快的ip分组没有备注功能,这里使用 IKUAI_BYPASS_<国内>_<01>来区分
## IP分组 cidr 列表网址,每行一个,超过1000行会自动分为多个,ipv6 地址会被删除
url: https://ghp.ci/https://raw.githubusercontent.com/Loyalsoldier/geoip/release/text/cn.txt
stream-ipport: # 端口分流,与IP分组组合使用
- type: 0 # 分流方式:0-外网线路,1-下一跳网关
interface: adsl1 # 分流线路 这里默认到adsl1 运营商
src-addr: 10.0.0.1-10.0.0.250 # 分流的源地址 对应 ip-group: 国内 的目标地址
ip-group: 国内

custom-isp: # 自定义运营商 IP分流
- name: 国内IP列表 # 自定义运营商名称
## 自定义运营商 cidr 列表网址,每行一个,超过5000行会自动分为多个,ipv6 地址会被删除
## 下面演示规则使用了ghproxy.com的代理,如果失效请自行更换或另外想办法,建议使用https://github.com/hunshcn/gh-proxy自建
url: https://ghp.ci/https://raw.githubusercontent.com/Loyalsoldier/geoip/release/text/cn.txt
tag: ipcn # 规则的备注标签后缀 如果留空默认为自定义运营商名称

stream-domain: # 域名分流 可选功能,优先级比ip分流高
# 下面是强制走wan2的
- interface: wan2
src-addr: 10.0.0.1-10.0.0.250
url: https://ghp.ci/https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/gfw.txt
tag: gfw
- interface: wan2
src-addr: 10.0.0.1-10.0.0.250
# 作者自己维护的自定义的域名列表 强制走代理的域名
url: https://ghp.ci/https://raw.githubusercontent.com/joyanhui/ikuai-bypass/main/private/bypass-domain-list.txt
tag: private_bypass
# 下面是自动走adsl1直连的,
- interface: adsl1
src-addr: 10.0.0.1-10.0.0.250
# 作者自己维护的自定义的域名列表 主要存放github的镜像网站等国内可以直连的镜像或其他类型域名
url: https://ghp.ci/https://raw.githubusercontent.com/joyanhui/ikuai-bypass/main/private/direct-domain-list.txt
tag: private_direct
- interface: adsl1
src-addr: 10.0.0.1-10.0.0.250
url: https://ghp.ci/https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/apple-cn.txt
tag: apple

执行一下写入命令:

1
./ikuai-bypass -r nocron -c config.yaml

执行成功后就会自动在iKuai的分流规则中添加对应的分流规则,然后我们还需要在多线负载这里引入一下规则进行分流,把国内的IP绑定到iKuai的WAN1出口,我这里命名是adsl1,改为你自己的对应网口即可:

image-20241026004708417

image-20241026004518177

如果你像我一样有玩PT,又不希望PT的流量流到OpenWRT中,防止被标盒的话,那可以自己在域名分流中添加对应的域名:

image-20241026004853748

照猫画虎,如果还有其他需要直连不需要流经OpenWRT的流量都可以在这里配置一下。这里为什么需要特殊设置走国内流量的域名呢?因为国外的规则集比较大,所以取国内域名相对较少,这是一种取巧的方式。

如果需要持续更新分流规则,那么把这个命令加到守护进程中常驻运行即可,下面是systemd的配置示例:

1
2
3
4
5
6
7
8
9
10
11
12
[Unit]
Description=Ikuai Bypass Service
After=network.target

[Service]
Type=simple
ExecStart=/path/to/ikuai-bypass/ikuai-bypass -r cronAft -c /path/to/ikuai-bypass/config.yml
ExecStop=/usr/bin/pkill -f ikuai-bypass
Restart=on-failure

[Install]
WantedBy=multi-user.target

再多提供一个OpenWRTservice的配置示例:

1
2
3
4
5
6
7
8
9
10
11
#!/bin/sh /etc/rc.common
START=99
start(){
/path/to/ikuai-bypass -r cronAft -c /path/to/ikuai-bypass.yml > /dev/null 2>&1 &
echo "ikuai-bypass is start"
}

stop(){
killall -q -9 ikuai-bypass
echo "ikuai-bypass is stop"
}

创建新的虚拟机安装新的OpenWRT系统

创建虚拟机首先需要确定需要使用的系统。我们都知道,OpenWRT百花齐放,有各路大神制作了各式各样的固件,我这里选择了不自带各种插件但是已经编译好各种依赖的ImmortalWRT,只需要按自己需求安装对应的软件包即可。

General

这里需要记住VM ID,因为下面的镜像导入操作时需要用到。其他配置项建议保持默认,切记不要勾选Start at boot,千万不要手欠:

image-20241012002528305

OS

这里选择Do not use any media,因为等下我们会通过qm importdisk命令将OpenWRT的镜像导入到这个VM中来:

image-20241012003434598

System

这里选q35OVMF(UEFI),不要添加EFI的磁盘,Add EFI Disk不勾选,其他保持默认即可:

image-20241012003719391

Disks

我们不需要虚拟磁盘,因为OpenWRT镜像里面已经有了,所以这里的磁盘我选择删掉,你也可以先点下一步,后面再删掉:

image-20241012004039402

image-20241012004108723

CPU

CPU按需分配即可,我是拉满,直接host给4个Cores(因为我是J4125,所以只有可怜的4 Cores 和 1 Sockets),其他保持默认即可:

image-20241012004206637

Memory

我只用来跑OpenClash+DDNS+WireGuard,所以我只分配了最高512M,最低256M,够用了:

image-20241012004445229

Network

网卡可以先不启用,后面再一起添加,因为使用iKuai ByPassOpenWRT需要两个网口:

image-20241012004614968

Confirm

这里点Finish就好,你也可以自行检查一下是否都符合自己的配置:

image-20241013231423923

导入OpenWRT镜像

首先下载对应版本的系统镜像,我这里选择的是ImmortalWRT;因为我是J4125的处理器,所以我这里选择的是x86_64的版本;至于ext4squashfs的区别,查了一些资料说是ext4是可修改的,而squashfs是只读的,我这里选择的是熟悉的ext4;需要下载img.gz结尾的文件:

image-20241016001842930

下载后传到PVE上:

image-20241016002120375

上传之后登录PVE,然后解压镜像:

image-20241016002331142

然后进行磁盘导入操作:

image-20241016003719761

看到导入成功的提示:

image-20241016003746254

然后到PVEWeb UI上找到这个未使用的硬盘:

image-20241016003935733

双击Unused Disk 0,其他保持默认,点Add

image-20241016005822392

添加虚拟网卡

因为我网口有限,但是使用ByPass的方案需要多一个网口,故我这里使用虚拟网卡节约真实网口,所以你如果只有两个网口也不用担心,一样适用。如果你网口超级多,也不用担心,你只需要把虚拟网卡改成直通网卡即可。

点左上角的Add添加硬件:

image-20241016013203415

添加两个虚拟网卡,这里选默认即可:

image-20241016013300243

到这网卡就添加完成了,检查一下:

image-20241016013334467

修改启动项

点击Options,然后点Boot Order修改启动项,选择上面导入的镜像:

image-20241016013514714

到这安装OpenWRT的步骤就走完了,接下来就需要启动系统修改系统的网络设置。

网络配置

为了避免IP冲突,我这里LAN口IP设置为192.168.10.1,这个无所谓,因为只有iKuaiWAN2口会需要用到,只要不跟其他设备的IP冲突即可:

image-20241025002528780

WAN口我这里偷懒设置为了DHCP,如果你需要固定IP,也可以参照LAN口的设置,将WAN口设置为静态IP,比如我iKuai的网关地址是10.0.0.254,如果需要科学上网,因为我原来的OpenWRT是已经配置好科学上网的,所以我这里网关还可以设置为OpenWRT的IP10.0.0.253。这里我将新安装的OpenWRT的IP设置为10.0.0.249,因为启动后还需要安装一些软件,所以这里切记不要与现有的OpenWRT的IP一样,避免断网:

image-20241026005523880

这里需要注意netmask不要忘了设置,我就是因为忘记设置netmask导致上不了网,折腾了一会儿才发现是因为这个没有设置导致的;还有就是DNS地址最好设置一下,因为在另一台机器上我设置的时候发现没有设置DNS导致重启OpenWRT之后无法访问网络。WAN6就用DHCPV6就好,如果不需要IPV6也可以删掉。

设置完成之后,执行/etc/init.d/network restart命令重启网络即可。

防火墙配置

设置完网络之后,还需要设置一下防火墙,编辑防火墙配置文件/etc/config/firewall,把input(入站)、output(出站)以及forward(转发)都改为ACCEPT

image-20241026005727311

设置好防火墙之后,不要忘记重启一下防火墙,执行/etc/init.d/firewall restart命令重启即可。不出意外的话,此时只需要在浏览器打开10.0.0.249即可进入OpenWRT的Web访问页面:

image-20241025004420680

ImmortalWRT默认没有设置密码,点击登录即可:

image-20241025004453986

测试一下网络:

image-20241025004540292

软件安装

上面测试发现网络是OK的,那么我们就开始安装必备的软件。我个人需要WireGuard(组网)、DDNS-GO(DDNS)以及OpenClash,这些可以按需安装。可以很方便的到Web界面上安装,入口是系统-软件包

image-20241026010117318

点一下更新列表

image-20241026010148760

更新列表完成后直接过滤自己需要安装的软件包即可:

image-20241026010234523

如果你熟悉命令行,记得包名,你也可以自己在命令行中用opkg包管理命令执行安装命令,此处不多赘述。

配置WireGuard

如果你没有在OpenWRT中使用WireGuard的话,跳过这一步即可。因为我是组网需求,原来的OpenWRT中也已经配置好了,所以我这里直接从原来OpenWRTWireGuard的网络配置直接搬过来,打开/etc/config/network文件,复制WireGuard相关的配置,然后到新装的OpenWRT中一样打开/etc/config/network文件,然后把配置贴进去即可:

image-20241025004809533

然后当然还需要设置一下WireGuard接口的防火墙,打开/etc/config/firewall文件,然后在wan口的区域添加wg0接口,当然还要记得把input(入站)、output(出站)以及forward(转发)都改为ACCEPT

image-20241025005038595

变更网络配置

软件包安装配置好之后,我们就可以将新的OpenWRT中的网络改成跟原有的OpenWRT中的IP一样,作为替代项了。因为不确定是否一次成功,所以这里先不要将新安装的OpenWRT虚拟机改成开机自启动,因为我们需要利用这个特性做保底策略,防止我们彻底失联。这里只需要变更WAN口的IP即可,将WAN口协议改为静态IP,IP改为10.0.0.253,网关改为10.0.0.254,然后保存。我自建了内网DNS,所以首选的DNS是内网DNS服务器IP,这个可以按需设置:

image-20241026010932984

移花接木

那么我们就准备开始替换操作,首先我们需要设置保底机制,也就是PVE延时重启,我这里设置20分钟后重启:

1
shutdown -h +20

然后需要找到两个虚拟机对应的VMID用来做启用和停用操作:

1
qm list

image-20241026011401307

记住新旧虚拟机的VMID,然后就可以开始移花接木了:

1
2
# 比如我这里新的VMID是107,旧的VMID是101
qm stop 101 && qm start 107

回车之后如果没有意外,那么只有等WireGuard重新上线即可。如果有意外,那么20分钟后重启PVE也会将网络设置回滚回去。我一次成功,所以我没有等待PVE重启,我等待新OpenWRTWireGuard上线后就登录查看是否有问题,确认没有问题后就可以取消PVE的重启计划:

1
shutdown -c

然后将VMID=101的虚拟机自启动停掉,开启VMID=107的虚拟机的自启动选项即可完成本次迁移工作。这个时候前往TP-Link物联APP查看摄像头就会发现已经离线,说明我们的ACL规则终于生效了,喜大普奔。然后我们需要测试一下墙外分流是否正常(此处假设上面已经配置好了OpenClash等科学上网工具),如果也正常,那就说明已经大功告成!

Happy Ending

费了很大劲才终于把文章写完,折腾网络其实只花了满打满算2天时间。折腾完之后本来想着写个备忘录给自己,方便后面还有设备需要迁移的时候做参考,不过没想到写作对我来说已经如此艰难,前后花了半个月才终于把文章写完。临写完还发现自己前面思路不对,没有把全程不失联这个关键因素加进来,于是乎只能大改。还好终于在历时17天后,终于把文章写完了,希望对你有帮助。Happy Life!