android VPN编程

VPN的英文全称是“Virtual Private Network”,翻译过来就是“虚拟专用网络”。顾名思义,虚拟专用网络我们可以把它理解成是虚拟出来的企业内部专线。它可以通过特殊的加密的通讯协议在连接在Internet上的位于不同地方的两个或多个企业内部网之间建立一条专有的通讯线路,就好比是架设了一条专线一样,但是它并不需要真正的去铺设光缆之类的物理线路。这就好比去电信局申请专线,但是不用给铺设线路的费用,也不用购买路由器等硬件设备。VPN技术原是路由器具有的重要技术之一,目前在交换机,防火墙设备或WINDOWS2000等软件里也都支持VPN功能,一句话,VPN的核心就是在利用公共网络建立虚拟私有网。虚拟专用网(VPN)被定义为通过一个公用网络(通常是因特网)建立一个临时的、安全的连接,是一条穿过混乱的公用网络的安全、稳定的隧道。虚拟专用网是对企业公司分支机构、商业伙伴及供应商同公司的内部网建立可信的安全连接,并保证数据的安全传输。

 

关于Android VPN编程,网上的资料比较少,本人最近有一个关于在Android平台下开发VPN 客户端的项目,在项目刚开始的时候,进行比较艰难,主要是android(4.0之前)的VPN领域鲜有API可供直接调用,也没有官方的说明文档。经过将近一个星期的研究,终于有些头绪,在此本人愿将一些经验与大家共享。

为了研究android vpn,本人下载一些apk,通过反编译工具apktool,查看了一些代码片段,虽然反编译之后的代码不易于阅读,但是还是提供了一些有用的信息。通过对apk的

debug,本人发现很多apk都引入了xinkvpn开发包。非常感谢xinkvpn的开发者,抽取并封装了Android系统不对外访问的API,并提供了完整的代码,到目前为止可能对于SDK10之后的访问还存在问题,对于SDK14之前可以在此基础上进行一些修改,对于SDK14(Android4.0)后,则无法调用到公开的Android API接口,因此需要另外的研究。

需要注意的是,对于android 4.0之前的版本,如果采用l2tp secret,ipsec 方式,则需要获得root权限,并写入Keystore;对于PPTP和L2tp则不需要,但是因为其采用的是非加密方式,因此安全性要差一些。

关于xinkvpn,有兴趣的读者可以到https://github.com/xinthink/xinkvpn进行下载并运行,在此不再重复。

本人的项目要求是用户不需要输入用户名/密码/服务器IP等和VPN设置有关的参数,就可以直接连接到VPN。因此链接VPN的操作要在后台进行,这样就要对账户进行封装。当然本文的代码也可以供非此类情况的使用。

首先建立一个保存VPN Profile的抽象类,供PPTP,L2tp,L2tpIpsecPsk等扩展,此抽象类如下

[java] view plaincopy

  1. package vink.vpn.whyonly.editor;  
  2.   
  3. import xink.vpn.VpnProfileRepository;  
  4. import xink.vpn.wrapper.InvalidProfileException;  
  5. import xink.vpn.wrapper.KeyStore;  
  6. import xink.vpn.wrapper.VpnProfile;  
  7. import xink.vpn.wrapper.VpnState;  
  8. import android.content.Context;  
  9.   
  10. /** 
  11.  * @author Whyonly 
  12.  *  
  13.  */  
  14. public abstract class OWLVpnProfileEditor {  
  15.   
  16.     private VpnProfile profile;  
  17.     private VpnProfileRepository repository;  
  18.     private KeyStore keyStore;  
  19.     private Runnable resumeAction;  
  20.   
  21.     protected Context mContext;  
  22.   
  23.     public OWLVpnProfileEditor(final Context context) {  
  24.         mContext = context;  
  25.         repository = VpnProfileRepository.getInstance(context);  
  26.         keyStore = new KeyStore(context);  
  27.     }  
  28.   
  29.     public void onSave() {  
  30.         try {  
  31.             profile = createProfile();  
  32.             populateProfile();  
  33.             saveProfile();  
  34.         } catch (InvalidProfileException e) {  
  35.             throw e;  
  36.         }  
  37.     }  
  38.   
  39.     private void populateProfile() {  
  40.         profile.setState(VpnState.IDLE);  
  41.         doPopulateProfile();  
  42.         repository.checkProfile(profile);  
  43.     }  
  44.   
  45.     private void saveProfile() {  
  46.         repository.addVpnProfile(profile);  
  47.     }  
  48.   
  49.     @SuppressWarnings("unchecked")  
  50.     protected <T extends VpnProfile> T getProfile() {  
  51.         return (T) profile;  
  52.     }  
  53.       
  54.     protected abstract VpnProfile createProfile();  
  55.   
  56.     protected abstract void doPopulateProfile();  
  57. }  

PPTP的扩展如下

[java] view plaincopy

  1. package vink.vpn.whyonly.editor;  
  2.   
  3. import xink.vpn.wrapper.PptpProfile;  
  4. import xink.vpn.wrapper.VpnProfile;  
  5. import android.content.Context;  
  6.   
  7. /** 
  8.  * @author Whyonly 
  9.  *  
  10.  */  
  11. public class OWLPptpProfileEditor extends OWLVpnProfileEditor {  
  12.   
  13.     public OWLPptpProfileEditor(final Context context) {  
  14.         super(context);  
  15.     }  
  16.   
  17.     @Override  
  18.     protected VpnProfile createProfile() {  
  19.         return new PptpProfile(mContext);  
  20.     }  
  21.   
  22.   
  23.     @Override  
  24.     protected void doPopulateProfile() {  
  25.         PptpProfile profile = getProfile();  
  26.         profile.setName("OWLPPTP");  
  27.         profile.setServerName("0.0.0.0");  
  28.         profile.setDomainSuffices("8.8.8.8");  
  29.         profile.setUsername("whyonly");  
  30.         profile.setPassword(".....");  
  31.         profile.setEncryptionEnabled(true);  
  32.     }  
  33.   
  34. }  

请自行填入关于PPTP的账户信息,如果没有的话,可以到网上找一个VPN的免费代理,申请帐号。

L2TP IP Sec的代码如下,

[java] view plaincopy

  1. package vink.vpn.whyonly.editor;  
  2.   
  3. import xink.vpn.wrapper.L2tpIpsecPskProfile;  
  4. import xink.vpn.wrapper.VpnProfile;  
  5. import android.content.Context;  
  6.   
  7. /** 
  8.  * @author Whyonly 
  9.  *  
  10.  */  
  11. public class OWLL2tpIpsecPskProfileEditor extends OWLVpnProfileEditor {  
  12.   
  13.     public OWLL2tpIpsecPskProfileEditor(final Context context) {  
  14.         super(context);  
  15.     }  
  16.   
  17.     @Override  
  18.     protected VpnProfile createProfile() {  
  19.         return new L2tpIpsecPskProfile(mContext);  
  20.     }  
  21.   
  22.   
  23.     @Override  
  24.     protected void doPopulateProfile() {  
  25.         L2tpIpsecPskProfile p = getProfile();  
  26.   
  27.         p.setName("OWLL2tpIpsecPsk");  
  28.         p.setServerName("0.0.0.0");  
  29.         p.setDomainSuffices("8.8.8.8");  
  30.         p.setUsername("xxxxxxx");  
  31.         p.setPassword("xxxx");  
  32.   
  33.         p.setPresharedKey("xxxxx");  
  34.         boolean secretEnabled = false;  
  35.         p.setSecretEnabled(secretEnabled);  
  36.         p.setSecretString(secretEnabled ? "xxxx" : "");  
  37.     }  
  38.   
  39. }  

请自行填入关于账户的相关信息。

建立好账户的类之后,就是把账户存入Profile,

[java] view plaincopy

  1. OWLVpnProfileEditor pptp = new OWLPptpProfileEditor(this);  
  2.             pptp.onSave();  
  3.             OWLVpnProfileEditor lwtpIpsec = new OWLL2tpIpsecPskProfileEditor(this);  
  4.             lwtpIpsec.onSave();  

接着是连接到账户

[java] view plaincopy

  1. VpnActor actor = new VpnActor(getApplicationContext());  
  2. actor.connect(profile);  

最后需要对连接的状态进行监听,

[java] view plaincopy

  1. private void registerReceivers() {  
  2.     IntentFilter filter = new IntentFilter();  
  3.     filter.addAction(ACTION_VPN_CONNECTIVITY);  
  4.     stateBroadcastReceiver = new BroadcastReceiver() {  
  5.         @Override  
  6.         public void onReceive(final Context context, final Intent intent) {  
  7.             String action = intent.getAction();  
  8.   
  9.             if (ACTION_VPN_CONNECTIVITY.equals(action)) {  
  10.                 onStateChanged(intent);  
  11.             } else {  
  12.                 Log.d(TAG, "VPNSettings receiver ignores intent:" + intent); //$NON-NLS-1$  
  13.             }  
  14.         }  
  15.     };  
  16.     registerReceiver(stateBroadcastReceiver, filter);  
  17. }  
  18.   
  19. private void onStateChanged(final Intent intent) {  
  20.     //Log.d(TAG, "onStateChanged: " + intent); //$NON-NLS-1$  
  21.   
  22.     final String profileName = intent.getStringExtra(BROADCAST_PROFILE_NAME);  
  23.     final VpnState state = Utils.extractVpnState(intent);  
  24.     final int err = intent.getIntExtra(BROADCAST_ERROR_CODE, VPN_ERROR_NO_ERROR);  
  25.   
  26.     runOnUiThread(new Runnable() {  
  27.         @Override  
  28.         public void run() {  
  29.             stateChanged(profileName, state, err);  
  30.         }  
  31.     });  
  32. }  
  33.   
  34. private void stateChanged(final String profileName, final VpnState state, final int errCode) {  
  35. processing change  
时间: 2024-09-28 22:58:59

android VPN编程的相关文章

android socket编程问题

问题描述 android socket编程问题 代码:运行在pc端的代码:public class SimpleServer { public static void main(String[] args) throws IOException InterruptedException { ServerSocket ss = new ServerSocket(30000); while (true) { System.out.print(""before accept"&qu

《Android游戏编程入门经典》——4.4节对比模拟器和Android设备

4.4 对比模拟器和Android设备 Android游戏编程入门经典 模拟器允许您在不同的Android操作系统上并以不同的屏幕分辨率测试程序,但是模拟器(之前称为Android虚拟设备或AVD)存在限制.即使在高端开发PC上,模拟器也很缓慢.现在,高端机器将拥有类似6核处理器(或者是服务器主板上有两个这样的处理器)和8GB或更多RAM的配置.AVD通常配有512MB或1GB的RAM.图4.19显示了AVD配置对话框,注意Hardware(硬件)列表底部的Device RAM Size(设备R

Android高级编程笔记(四)深入探讨Activity(转)

在应用程序中至少包含一个用来处理应用程序的主UI功能的主界面屏幕.这个主界面一般由多个Fragment组成,并由一组次要Activity支持.要在屏幕之间切换,就必须要启动一个新的Activity.一般的Activity都占据了整个显示屏,但可以创建成半透明或二者浮动的Activity. 一.创建Activity 通过继承Activity类可以创建一个Activity窗口,基本框架如下: 1 public class MyActivity extends Activity { 2 @Overri

【Android】Android网络编程概述

Android网络编程概述 原文来自:http://blog.csdn.net/kieven2008/article/details/8210737 首先,应该了解的几个问题: 1)Android平台网络相关API接口  a) java.net.*(标准Java接口)  java.net.*提供与联网有关的类,包括流.数据包套接字(socket).Internet协议.常见Http处理等.比如:创建URL,以及URLConnection/HttpURLConnection对象.设置链接参数.链接

《Android游戏编程入门经典》——1.3节Android NDK简介

1.3 Android NDK简介 Android游戏编程入门经典 Android NDK(与SDK不同)支持您以本机C++代码而非Java语言编写应用程序或游戏的组件.NDK是一个单独的工具,可在Android SDK安装以后再安装它.NDK不允许以C++语言编写整个应用程序或游戏.更确切地说,它用来补充SDK,支持C++代码和库,并旨在充当许多没有Java库的硬件设备的桥梁.我们可以使用NDK优化游戏代码.除了许多C++库外,NDK还支持实现3D渲染的OpenGL ES 2.0.针对音频的O

Android多线程编程AsyncTask详解教程

Android中多线程编程中AsyncTask类的详细解释1.Android单线程模型2.耗时操作放在非主线程中执行 Android主线程和子线程之间的通信封装类:AsyncTask类1.子线程中更新UI2.封装.简化异步操作.3.AsyncTask机制:底层是通过线程池来工作的,当一个线程没有执行完毕,后边的线程是无法执行的.必须等前边的线程执行完毕后,后边的线程才能执行. AsyncTask类使用注意事项: 1.在UI线程中创建AsyncTask的实例2.必须在UI线程中调用AsyncTas

Android实现编程修改手机静态IP的方法_Android

本文实例讲述了Android实现编程修改手机静态IP的方法.分享给大家供大家参考.具体如下: 这里演示通过编程方式动态修改手机静态IP的方法,可以用于wifi接入点切换 public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ContentResolver cr = this.getContentResolver();

《Android游戏编程入门经典》——14.2节使用SoundPool播放音频

14.2 使用SoundPool播放音频Android游戏编程入门经典类android.media.SoundPool用于一次播放多个音频示例,因此使用它在游戏中播放音效. 注意: 忽略了资产文件扩展名.因此,不考虑扩展名,资产文件名必须是唯一的.无法在同一文件夹中保存sound1.mp3和sound1.ogg,因为两个文件都使用关键字sound1将文件添加到资源管理器中. 14.2.1 初始化SoundPool首先,我们将创建SoundPool变量: 通常,在程序的onCreate()事件方法

《Android游戏编程入门经典》——14.3节小结

14.3 小结Android游戏编程入门经典(通常)可以使用MediaPlayer针对音乐编写Android音频系统的代码,而使用SoundPool针对音效或任意其他音频需要编写代码.加载和播放音频文件的源代码并不难,但是却有些复杂,因此这是可从包装类受益的一个Android SDK组件,包装类可整合代码并使代码易于使用.在构建Android游戏引擎时我们必须这样做.