如何在Android VpnService中实现VPN分流,排除特定IP不走隧道?
Android VPN分流实现:默认全流量走VPN,特定IP绕过
需求说明
默认所有流量通过VPN传输,仅指定IP/子网绕过VPN,使用常规互联网连接。基于Shadowsocks Android项目的VpnService.kt代码进行修改。
原代码分析
以下是Shadowsocks中配置VPN路由的核心片段:
when (profile.route) { Acl.ALL, Acl.BYPASS_CHN, Acl.CUSTOM_RULES -> { builder.addRoute("0.0.0.0", 0) if (profile.ipv6) builder.addRoute("::", 0) } else -> { resources.getStringArray(R.array.bypass_private_route).forEach { val subnet = Subnet.fromString(it)!! builder.addRoute(subnet.address.hostAddress!!, subnet.prefixSize) } builder.addRoute(PRIVATE_VLAN4_ROUTER, 32) // https://issuetracker.google.com/issues/149636790 if (profile.ipv6) builder.addRoute("2000::", 3) } }
当路由模式为ALL、BYPASS_CHN或CUSTOM_RULES时,代码会添加默认路由(0.0.0.0/0和::/0),将所有IPv4/IPv6流量导入VPN。
修改方案
在默认路由配置后,使用addDisallowedRoute方法添加需要绕过的IP/子网规则,告诉系统这些目标的流量无需经过VPN。
修改后的代码示例
when (profile.route) { Acl.ALL, Acl.BYPASS_CHN, Acl.CUSTOM_RULES -> { builder.addRoute("0.0.0.0", 0) if (profile.ipv6) builder.addRoute("::", 0) // 新增:添加需要绕过VPN的IP/子网 // IPv4规则示例 builder.addDisallowedRoute("192.168.1.0", 24) // 绕过整个局域网子网 builder.addDisallowedRoute("203.0.113.5", 32) // 绕过单个公网IP // IPv6规则示例(仅当启用IPv6时添加) if (profile.ipv6) { builder.addDisallowedRoute("2606:4700::", 32) } } else -> { resources.getStringArray(R.array.bypass_private_route).forEach { val subnet = Subnet.fromString(it)!! builder.addRoute(subnet.address.hostAddress!!, subnet.prefixSize) } builder.addRoute(PRIVATE_VLAN4_ROUTER, 32) // https://issuetracker.google.com/issues/149636790 if (profile.ipv6) builder.addRoute("2000::", 3) } }
补充说明
- 域名绕过处理:若需绕过特定网站,需先将域名解析为对应IP(可提前配置静态IP列表,或在运行时动态解析并更新规则,但动态修改需重建VPN连接)。
- 批量规则管理:如果需要支持用户自定义绕过列表,可参考原代码中
bypass_private_route的处理方式,将规则存入数组后循环调用addDisallowedRoute。 - IP版本兼容:确保IPv4和IPv6规则分别对应,启用IPv6时需添加对应的绕过规则。
内容的提问来源于stack exchange,提问作者Katarina Zivkovic
相关产品推荐
相关产品推荐

