作者:琪米 时间: 2018.8.02
引言: 最近就要离职了,总觉得不把自己做过的技术分享出来是一种遗憾。而且我认为技术要分享才能促进世界的进步(不好意思装了逼了),我怀着这个伟大的理想就开始了这个系列的文章。废话讲完下面开始讲正事。
我相信同是程序员很多人应该都对Google搜索情有独钟,奈何国内的墙太过厉害。阻碍了很多人的梦想,此时会有一批有志之士发挥了智慧建造了通向外面世界的梯子。这个梯子是怎么实现的呢?继续往下看吧!!
Google爸爸在4.0之后的Android系统放出一个强大的一个服务,叫做VpnServer,它位于android SDK的android.net的包下面。通过这个服务我们可以实现在应用层通过配置一些参数来打开底层luinx内核的tun网卡,通过这个tun网卡能够实现对android手机上的ip层的网络数据进行读写操作。
继承VpnServer服务
要使用这个服务,不能够直接使用,要先对这个服务进行继承。
public class DemoVpnServer extends VpnService
复制代码
配置基本参数建立一个底层的tun虚拟网卡
private ParcelFileDescriptor openTun()
{
Builder builder = new Builder();
//设置一个网卡的名字
builder.setSession("VpnDemo");
//设置ip数据包长度大小
builder.setMtu(1500);
//设置虚拟网卡ip地址
builder.addAddress("10.0.0.11",32);
//设置路由地址 0.0.0.0/0表示所有网络数据路由到虚拟网卡上面去 ps:可以设置多个
builder.addRoute("0.0.0.0",0);
//设置这个虚拟网卡的dns地址 ps:可以设置多个
builder.addDnsServer("8.8.8.8");
//建立虚拟网卡返回一个读取网卡数据的文件描述符
return builder.establish();
}
复制代码
打开了一个网卡之后,程序就可以直接读取底层网卡的ip数据包了。 具体代码如下:
public class DemoVpnServer extends VpnService implements Runnable{
private Thread mVpnRunThread;
private AtomicBoolean mVpnThreadRun;
private ParcelFileDescriptor openTun()
{
Builder builder = new Builder();
//设置一个网卡的名字
builder.setSession("VpnDemo");
//设置ip数据包长度大小
builder.setMtu(1500);
//设置虚拟网卡ip地址
builder.addAddress("10.0.0.11",32);
//设置路由地址 0.0.0.0/0表示所有网络数据路由到虚拟网卡上面去 ps:可以设置多个
builder.addRoute("0.0.0.0",0);
//设置这个虚拟网卡的dns地址 ps:可以设置多个
builder.addDnsServer("8.8.8.8");
//建立虚拟网卡返回一个读取网卡数据的文件描述符
return builder.establish();
}
public DemoVpnServer()
{
mVpnRunThread = new Thread(this);
mVpnThreadRun = new AtomicBoolean();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
mVpnRunThread.start();
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
mVpnThreadRun.set(false);
}
@Override
public void run() {
mVpnThreadRun.set(true);
ParcelFileDescriptor fd = openTun();
FileOutputStream fileOutputStream = new FileOutputStream(fd.getFileDescriptor());
FileInputStream fileInputStream = new FileInputStream(fd.getFileDescriptor());
byte[] buffer = new byte[1600];
while (mVpnThreadRun.get())
{
try {
int length = fileInputStream.read(buffer);
if(length <= 0)
Thread.sleep(50);
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
//关闭底层虚拟网卡
fd.close();
fileInputStream.close();
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
复制代码
由于在虚拟网卡哪里配置的路由是0.0.0.0/0所以所有通过手机物理网卡得网络数据包都会路由到程序建立得tun虚拟网卡中去,然后从builder.establish();返回得文件描述符中可以把网卡得数据读出来,读得操作在这里
虽然在配置网卡数据得时候设置得ip数据包大小为1500,事实上偶然还是会有一些数据包得长度会超出1500,但是超出得幅度不大,所以我给读取每个buffer的时候大小是1600。而且读出来的长度也不一定是1500,这点需要自己根据返回的长度进行处理,ps:int length = fileInputStream.read(buffer)。最后还要在AndroidManifest.xml加上:
<service android:name=".DemoVpnServer"
android:permission="android.permission.BIND_VPN_SERVICE">
<intent-filter>
<action android:name="android.net.VpnService" />
</intent-filter>
</service>
复制代码
下面运行一下程序看下前后的ip情况: vpnServer还没跑起来的情况:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = VpnService.prepare(this);
if(intent!=null)
startActivityForResult(intent,1);
else
startService(new Intent(this,DemoVpnServer.class));
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == 1 && resultCode == RESULT_OK)
startService(new Intent(this,DemoVpnServer.class));
}
复制代码
启动一个VpnServer大致的流程图如下:
至此就完成了接管手机上网络数据的要求了。但是接管了手机的网络我们能干些什么呢?其实使用场景还是有不少地方,例如比较熟悉的VPN翻墙,代理翻墙,网络捉包工具,网络防火墙,广告拦截器等都可以使用VpnServer来实现。(如有转发请注明出处哦!!!)