原文地址:https://blog.csdn.net/hanlongfei_dev/article/details/60954902
VPNService是android 4.0以后新添加的一个建立VPN连接,获取数据包的API
一、基本原理
在介绍如何使用这些新增的API之前,先来说说其基本的原理。
Android设备上,如果已经使用了VpnService框架,建立起了一条从设备到远端的VPN链接,那么数据包在设备上大致经历了如下四个过程的转换:
1)应用程序使用socket,将相应的数据包发送到真实的网络设备上。一般移动设备只有无线网卡,因此是发送到真实的WiFi设备上;
2)Android系统通过iptables,使用NAT,将所有的数据包转发到TUN虚拟网络设备上去,端口是tun0;
3)VPN程序通过打开/dev/tun设备,并读取该设备上的数据,可以获得所有转发到TUN虚拟网络设备上的IP包。因为设备上的所有IP包都会被NAT转成原地址是tun0端口发送的,所以也就是说你的VPN程序可以获得进出该设备的几乎所有的数据(也有例外,不是全部,比如回环数据就无法获得);
4)VPN数据可以做一些处理,然后将处理过后的数据包,通过真实的网络设备发送出去。为了防止发送的数据包再被转到TUN虚拟网络设备上,VPN程序所使用的socket必须先被明确绑定到真实的网络设备上去。
二、使用方法
使用Vpnservice需要新建类继承vpnservice;
然后在Manifest文件里声明权限和
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
<service android:name=".VpnServiceDemo"
android:permission="android.permission.BIND_VPN_SERVICE">
<intent-filter>
<action android:name="android.net.VpnService" />
</intent-filter>
</service>
vpnservice 是 service 子类,所以使用方法跟service类似不同之处在于,由于开启 vpn 需要用户点头同意,所以需要弹出对话框让用户确认。在Activity中:
Intent intent = VpnService.prepare(getApplicationContext())
if (intent != null) {
intent.putExtra(PACKAGEKEY, mPn);
startActivityForResult(intent, 0);
} else {
onActivityResult(0, RESULT_OK, null);
}
第一次建立 VPN 才会弹出对话框,用户点击确认,回掉 onActivityResult函数。
protected void onActivityResult(int request, int result, Intent data) {
if (result == RESULT_OK) {
Intent intent = new Intent(this, MyVpnService.class);
startService(intent);
}
}
回家再写吧。
2017年5月16日更新:
最近话费了很多时间在这个vpnservice上,包括拦截数据之后的解包,封包,以及发送,关于vpnservice的原理和简单的使用方法大家可以参考Roland_Sun的博客,链接在上面。
而关于解包,封包,构建PCAP文件 ,以及发送数据包的过程,非常复杂,并且部分代码涉及公司源码,所以不能继续写了。
可以参考github的一个开源项目:
https://github.com/pencil-box/NetKnight