android V*N開發

V*N的英文全稱是“Virtual Private Network”,翻譯過來就是“虛擬專用網絡”。顧名思義,虛擬專用網絡我們可以把它理解成是虛擬出來的企業內部專線。它可以通過特殊的加密的通訊協議在連接在Internet上的位于不同地方的兩個或多個企業內部網之間建立一條專有的通訊線路,就好比是架設了一條專線一樣,但是它并不需要真正的去鋪設光纜之類的物理線路。這就好比去電信局申請專線,但是不用給鋪設線路的費用,也不用購買路由器等硬件設備。V*N技術原是路由器具有的重要技術之一,目前在交換機,防火墻設備或WINDOWS2000等軟件里也都支持V*N功能,一句話,V*N的核心就是在利用公共網絡建立虛擬私有網。虛擬專用網(V*N)被定義為通過一個公用網絡(通常是因特網)建立一個臨時的、安全的連接,是一條穿過混亂的公用網絡的安全、穩定的隧道。虛擬專用網是對企業公司分支機構、商業伙伴及供應商同公司的內部網建立可信的安全連接,并保證數據的安全傳輸。

關于Android V*N編程,網上的資料比較少,本人最近有一個關于在Android平臺下開發V*N 客戶端的項目,在項目剛開始的時候,進行比較艱難,主要是android(4.0之前)的V*N領域鮮有API可供直接調用,也沒有官方的說明文檔。經過將近一個星期的研究,終于有些頭緒,在此本人愿將一些經驗與大家共享。

為了研究android V*N,本人下載一些apk,通過反編譯工具apktool,查看了一些代碼片段,雖然反編譯之后的代碼不易于閱讀,但是還是提供了一些有用的信息。通過對apk的

debug,本人發現很多apk都引入了xinkV*N開發包。非常感謝xinkV*N的開發者,抽取并封裝了Android系統不對外訪問的API,并提供了完整的代碼,到目前為止可能對于SDK10之后的訪問還存在問題,對于SDK14之前可以在此基礎上進行一些修改,對于SDK14(Android4.0)后,則無法調用到公開的Android API接口,因此需要另外的研究。

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

關于xinkV*N,有興趣的讀者可以到https://github.com/xinthink/xinkV*N進行下載并運行,在此不再重復。

本人的項目要求是用戶不需要輸入用戶名/密碼/服務器IP等和V*N設置有關的參數,就可以直接連接到V*N。因此鏈接V*N的操作要在后臺進行,這樣就要對賬戶進行封裝。當然本文的代碼也可以供非此類情況的使用。

首先建立一個保存V*N Profile的抽象類,供PPTP,L2tp,L2tpIpsecPsk等擴展,此抽象類如下

package vink.V*N.whyonly.editor;  
  
import xink.V*N.V*NProfileRepository;  
import xink.V*N.wrapper.InvalidProfileException;  
import xink.V*N.wrapper.KeyStore;  
import xink.V*N.wrapper.V*NProfile;  
import xink.V*N.wrapper.V*NState;  
import android.content.Context;  
  
/** 
 * @author Whyonly 
 *  
 */  
public abstract class OWLV*NProfileEditor {  
  
    private V*NProfile profile;  
    private V*NProfileRepository repository;  
    private KeyStore keyStore;  
    private Runnable resumeAction;  
  
    protected Context mContext;  
  
    public OWLV*NProfileEditor(final Context context) {  
        mContext = context;  
        repository = V*NProfileRepository.getInstance(context);  
        keyStore = new KeyStore(context);  
    }  
  
    public void onSave() {  
        try {  
            profile = createProfile();  
            populateProfile();  
            saveProfile();  
        } catch (InvalidProfileException e) {  
            throw e;  
        }  
    }  
  
    private void populateProfile() {  
        profile.setState(V*NState.IDLE);  
        doPopulateProfile();  
        repository.checkProfile(profile);  
    }  
  
    private void saveProfile() {  
        repository.addV*NProfile(profile);  
    }  
  
    @SuppressWarnings("unchecked")  
    protected <T extends V*NProfile> T getProfile() {  
        return (T) profile;  
    }  
      
    protected abstract V*NProfile createProfile();  
  
    protected abstract void doPopulateProfile();  
}  

PPTP的擴展如下

package vink.V*N.whyonly.editor;  
  
import xink.V*N.wrapper.PptpProfile;  
import xink.V*N.wrapper.V*NProfile;  
import android.content.Context;  
  
/** 
 * @author Whyonly 
 *  
 */  
public class OWLPptpProfileEditor extends OWLV*NProfileEditor {  
  
    public OWLPptpProfileEditor(final Context context) {  
        super(context);  
    }  
  
    @Override  
    protected V*NProfile createProfile() {  
        return new PptpProfile(mContext);  
    }  
  
  
    @Override  
    protected void doPopulateProfile() {  
        PptpProfile profile = getProfile();  
        profile.setName("OWLPPTP");  
        profile.setServerName("0.0.0.0");  
        profile.setDomainSuffices("8.8.8.8");  
        profile.setUsername("whyonly");  
        profile.setPassword(".....");  
        profile.setEncryptionEnabled(true);  
    }  
  
}  

請自行填入關于PPTP的賬戶信息,如果沒有的話,可以到網上找一個V*N的免費代理,申請帳號。

L2TP IP Sec的代碼如下,

package vink.V*N.whyonly.editor;  
  
import xink.V*N.wrapper.L2tpIpsecPskProfile;  
import xink.V*N.wrapper.V*NProfile;  
import android.content.Context;  
  
/** 
 * @author Whyonly 
 *  
 */  
public class OWLL2tpIpsecPskProfileEditor extends OWLV*NProfileEditor {  
  
    public OWLL2tpIpsecPskProfileEditor(final Context context) {  
        super(context);  
    }  
  
    @Override  
    protected V*NProfile createProfile() {  
        return new L2tpIpsecPskProfile(mContext);  
    }  
  
  
    @Override  
    protected void doPopulateProfile() {  
        L2tpIpsecPskProfile p = getProfile();  
  
        p.setName("OWLL2tpIpsecPsk");  
        p.setServerName("0.0.0.0");  
        p.setDomainSuffices("8.8.8.8");  
        p.setUsername("xxxxxxx");  
        p.setPassword("xxxx");  
  
        p.setPresharedKey("xxxxx");  
        boolean secretEnabled = false;  
        p.setSecretEnabled(secretEnabled);  
        p.setSecretString(secretEnabled ? "xxxx" : "");  
    }  
  
}  

請自行填入關于賬戶的相關信息。

建立好賬戶的類之后,就是把賬戶存入Profile,

OWLV*NProfileEditor pptp = new OWLPptpProfileEditor(this);  
            pptp.onSave();  
            OWLV*NProfileEditor lwtpIpsec = new OWLL2tpIpsecPskProfileEditor(this);  
            lwtpIpsec.onSave();  

接著是連接到賬戶

V*NActor actor = new V*NActor(getApplicationContext());  
actor.connect(profile);  

最后需要對連接的狀態進行監聽,

private void registerReceivers() {  
    IntentFilter filter = new IntentFilter();  
    filter.addAction(ACTION_V*N_CONNECTIVITY);  
    stateBroadcastReceiver = new BroadcastReceiver() {  
        @Override  
        public void onReceive(final Context context, final Intent intent) {  
            String action = intent.getAction();  
  
            if (ACTION_V*N_CONNECTIVITY.equals(action)) {  
                onStateChanged(intent);  
            } else {  
                Log.d(TAG, "V*NSettings receiver ignores intent:" + intent); //$NON-NLS-1$  
            }  
        }  
    };  
    registerReceiver(stateBroadcastReceiver, filter);  
}  
  
private void onStateChanged(final Intent intent) {  
    //Log.d(TAG, "onStateChanged: " + intent); //$NON-NLS-1$  
  
    final String profileName = intent.getStringExtra(BROADCAST_PROFILE_NAME);  
    final V*NState state = Utils.extractV*NState(intent);  
    final int err = intent.getIntExtra(BROADCAST_ERROR_CODE, V*N_ERROR_NO_ERROR);  
  
    runOnUiThread(new Runnable() {  
        @Override  
        public void run() {  
            stateChanged(profileName, state, err);  
        }  
    });  
}  
  
private void stateChanged(final String profileName, final V*NState state, final int errCode) {  
processing change  
}  

 

來自:http://blog.csdn.net/xiangzhihong8/article/details/45420537

 

 本文由用戶 另一顆心 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!