非Root环境下基于VPN实现APP网络拦截的开发技术咨询
非Root环境下Android防火墙应用开发疑问
背景
Play商店中有多款防火墙应用支持用户选择允许哪些APP使用Wi-Fi或移动网络,这类应用通过VPN技术实现网络管控。
已尝试内容
- VPN服务实现尝试
我参考了ToyVpn示例但觉得过于复杂,于是从零编写代码搭建了一个VPN服务,选择Google Chrome作为测试拦截对象,但无法实现拦截效果。相关代码如下:
Manifest文件
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" tools:ignore="QueryAllPackagesPermission" /> <application android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.Firewall" tools:targetApi="31"> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".MyVpnService" android:exported="true" android:permission="android.permission.BIND_VPN_SERVICE"> <intent-filter> <action android:name="android.net.VpnService" /> </intent-filter> </service> </application> </manifest>
MainActivity.kt
class MainActivity : AppCompatActivity() { private val requestVpn = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { if (it.resultCode == RESULT_OK) startService(Intent(this, MyVpnService::class.java)) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val vpnIntent = VpnService.prepare(this@MainActivity) if (vpnIntent != null) requestVpn.launch(vpnIntent) else startService(Intent(this, MyVpnService::class.java)) } }
MyVpnService.kt
class MyVpnService : VpnService() { override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { val builder = Builder() builder.setSession("MyVPNService") .addAddress("192.168.0.1", 24) .addDnsServer("8.8.8.8") .addRoute("0.0.0.0", 0) .addDisallowedApplication("com.android.chrome") .establish() return START_STICKY } }
- Root权限下的iptables实现
找到了一种需要Root权限的实现方式,通过批处理文件完成APP网络拦截:
set package_name="com.android.browser" for /f "delims=" %%A in ('adb shell dumpsys package %package_name% ^| findstr "userId="') do ( for /f "tokens=2 delims== " %%B in ("%%A") do ( echo Extracted UID: %%B adb shell "su -c 'iptables -A OUTPUT -m owner --uid-owner %%B -j DROP'" ) )
取消拦截时,将-A OUTPUT替换为-D OUTPUT;查看拦截状态可使用:
set package_name="com.android.browser" for /f "delims=" %%A in ('adb shell dumpsys package %package_name% ^| findstr "userId="') do ( for /f "tokens=2 delims== " %%B in ("%%A") do ( set uid=%%B echo Extracted UID: %%B adb shell "su -c 'iptables -L OUTPUT -v -n --line-numbers | grep \"owner UID match %%B\"'" ) ) pause
该方式有效,但我需要非Root环境下的实现方案。
技术疑问
- 当前创建和维护VPN服务的方式是否正确?
- 当前代码无法实现APP网络拦截,需进行哪些修改才能达成目标?
- 如何像主流防火墙应用一样,设置拦截Wi-Fi或移动数据的网络类型?
内容的提问来源于stack exchange,提问作者android developer
相关产品推荐
相关产品推荐

