mirror of
https://gitee.com/willfree/min-vpn-client_v2.git
synced 2026-06-03 15:36:14 +08:00
将connection区分为内网和外网两种,根据mode进行选择
This commit is contained in:
@@ -5,8 +5,10 @@ package com.pkusz.min_vpn_client;
|
||||
public class GlobalSetting {
|
||||
// public static boolean openBiometric = false;
|
||||
|
||||
// 控制与VPNServer的对称加密通信方法,true表示使用sm4,false表示使用AES
|
||||
// 控制内网中与VPNServer的对称加密通信方法,true表示使用sm4,false表示使用AES
|
||||
public static boolean isSM4 = true;
|
||||
// 控制外网中与VPNServer的对称加密通信方法,暂时只支持SM4
|
||||
public static boolean isSM4InExternal = true;
|
||||
|
||||
// 是否开启VPN服务器信息同步
|
||||
public static boolean openSyncVPNInfo = false;
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.pkusz.min_vpn_client.model;
|
||||
/*
|
||||
* @Author: Wang Feng
|
||||
* @Description: 存储路由配置的信息
|
||||
* 最最基础的字段:mtu addr dns
|
||||
* @Version: 1.0.0
|
||||
* @Date: 10:04 2021/8/11
|
||||
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
|
||||
*/
|
||||
|
||||
public class VpnServiceInfo {
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.pkusz.min_vpn_client.services;
|
||||
/*
|
||||
* @Author: Wang Feng
|
||||
* @Description:
|
||||
* @Version: 1.0.0
|
||||
* @Date: 9:04 2021/8/11
|
||||
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
|
||||
*/
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
|
||||
public interface MINVpnConnection extends Runnable{
|
||||
// 三种回调函数接口的声明
|
||||
interface OnEstablishListener {
|
||||
void onEstablish(ParcelFileDescriptor tunInterface);
|
||||
}
|
||||
interface OnConnectFailedListener {
|
||||
void onFailed();
|
||||
}
|
||||
interface OnTimeoutFailedListener {
|
||||
void onTimeout();
|
||||
}
|
||||
// 共有方法
|
||||
void setConfigureIntent(PendingIntent intent);
|
||||
void setOnEstablishListener(OnEstablishListener listener);
|
||||
void setOnConnectFailedListener(OnConnectFailedListener listener);
|
||||
void setOnTimeoutFailedListener(OnTimeoutFailedListener listener);
|
||||
}
|
||||
+636
-707
File diff suppressed because it is too large
Load Diff
@@ -49,7 +49,7 @@ import util.ByteHelper;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
|
||||
public class MINVpnInnerConnection implements Runnable{
|
||||
public class MINVpnInnerConnection implements MINVpnConnection{
|
||||
private static long interestSeq = 0; // 兴趣包序号
|
||||
private String handshakeResponse = null; // 握手应答
|
||||
private ParcelFileDescriptor mParcelFileDescriptor = null; // 读出写入流
|
||||
@@ -91,16 +91,6 @@ public class MINVpnInnerConnection implements Runnable{
|
||||
private OnEstablishListener mOnEstablishListener;
|
||||
private OnConnectFailedListener mOnConnectFailedListener;
|
||||
private OnTimeoutFailedListener mOnTimeoutFailedListener;
|
||||
// 三种回调函数接口的声明
|
||||
public interface OnEstablishListener {
|
||||
void onEstablish(ParcelFileDescriptor tunInterface);
|
||||
}
|
||||
public interface OnConnectFailedListener {
|
||||
void onFailed();
|
||||
}
|
||||
public interface OnTimeoutFailedListener {
|
||||
void onTimeout();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
@@ -141,30 +131,6 @@ public class MINVpnInnerConnection implements Runnable{
|
||||
+" , len: "+realSecret.length);
|
||||
}
|
||||
|
||||
// 测试AES
|
||||
// System.out.println("!!!密钥:"+mSharedSecretString);
|
||||
// byte[] res=AESHelperForConnection.encryptWithAES(mSharedSecretString,
|
||||
// "ilovecodingilovecodingilovecodingilovecodingilovecodingilovecodingilovecodingilovecoding" +
|
||||
// "ilovecodingilovecodingsuygdygyegdw".getBytes(StandardCharsets.UTF_8));
|
||||
// System.out.println("!!!: "+res);
|
||||
// String raw=AESHelperForConnection.decryptWithAES(mSharedSecretString,res);
|
||||
// System.out.println("!!!raw: "+raw);
|
||||
|
||||
// 测试SM4
|
||||
// try {
|
||||
// byte[] enc= Android_SM4.encrypt_ECB_Padding("1234567812345678".getBytes(StandardCharsets.UTF_8),
|
||||
// "wefree".getBytes(StandardCharsets.UTF_8));
|
||||
// System.out.println("enc: "+Arrays.toString(enc));
|
||||
// System.out.println("enc: "+new String(enc));
|
||||
// byte[] dec= Android_SM4.decrypt_ECB_Padding("1234567812345678".getBytes(StandardCharsets.UTF_8),
|
||||
// enc);
|
||||
// System.out.println("dec: "+Arrays.toString(dec));
|
||||
// System.out.println("dec: "+new String(dec));
|
||||
// } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchProviderException
|
||||
// | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
|
||||
// 代理地址(?)
|
||||
if(!TextUtils.isEmpty(proxyHostName)) {
|
||||
mProxyHostName = proxyHostName;
|
||||
@@ -179,6 +145,7 @@ public class MINVpnInnerConnection implements Runnable{
|
||||
}
|
||||
|
||||
// Intend进行activity之间的消息传递
|
||||
@Override
|
||||
public void setConfigureIntent(PendingIntent intent) {
|
||||
mConfigureIntent = intent;
|
||||
}
|
||||
@@ -204,7 +171,7 @@ public class MINVpnInnerConnection implements Runnable{
|
||||
}
|
||||
|
||||
// 2. VPN握手,交换信息
|
||||
boolean flag=handShake(face);
|
||||
boolean flag=handShake(face,true);
|
||||
if((this.mParcelFileDescriptor==null)||(!flag)){
|
||||
LoggerHelper.severe("vpn connection run error: handle shake error");
|
||||
return;
|
||||
@@ -217,6 +184,28 @@ public class MINVpnInnerConnection implements Runnable{
|
||||
startHeartBeatThread(face,500);
|
||||
}
|
||||
|
||||
/**
|
||||
* 现行版本下,由于外网服务器自己并不分配IP,tun的IP分配仍然由内网服务器做
|
||||
* @return
|
||||
*/
|
||||
@RequiresApi(api = Build.VERSION_CODES.Q)
|
||||
public String getAllocatedAddressFromInnerServer(){
|
||||
// 1. 建立一条连接服务器的TCP-LogicFace
|
||||
LogicFace face=initTCPLogicFace(this.mServerName,this.mServerPort);
|
||||
if(face==null){
|
||||
LoggerHelper.severe("vpn connection run error: tcp logic face init error");
|
||||
return "";
|
||||
}
|
||||
|
||||
// 2. VPN握手,交换信息。握手成功则返回内网服务器分配的IP
|
||||
boolean flag=handShake(face,false);
|
||||
if(flag){
|
||||
return this.allocatedAddress;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启心跳包
|
||||
* @param face
|
||||
@@ -446,14 +435,15 @@ public class MINVpnInnerConnection implements Runnable{
|
||||
/**
|
||||
* VPN握手,交换信息。
|
||||
* @param face
|
||||
* @param needConfig 是否需要根据握手信息进行相应路由配置
|
||||
*/
|
||||
@RequiresApi(api = Build.VERSION_CODES.Q)
|
||||
private boolean handShake(LogicFace face){
|
||||
private boolean handShake(LogicFace face,boolean needConfig){
|
||||
// 1. 构造兴趣包
|
||||
// 构造兴趣包负载字段:加密密钥 & 本地前缀
|
||||
ByteBuffer requestBuf = ByteBuffer.allocate(1024);
|
||||
byte len= ByteHelper.uint8ToByte(mEncryptedAESSeed.length);
|
||||
if(!GlobalSetting.isSM4) {
|
||||
if(!this.isSM4) {
|
||||
requestBuf.put((byte) 4).put(len).put(mEncryptedAESSeed).put(localFacePrefix.getBytes()).flip();
|
||||
}else{
|
||||
requestBuf.put((byte) 1).put(len).put(mEncryptedAESSeed).put(localFacePrefix.getBytes()).flip();
|
||||
@@ -555,7 +545,9 @@ public class MINVpnInnerConnection implements Runnable{
|
||||
|
||||
// 4. 分析服务器的数据包应答,根据其中信息进行本地的路由配置
|
||||
System.out.println("handshake result : " + this.handshakeResponse);
|
||||
this.mParcelFileDescriptor = configure(this.handshakeResponse);
|
||||
if(needConfig) {
|
||||
this.mParcelFileDescriptor = configure(this.handshakeResponse);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -589,8 +581,9 @@ public class MINVpnInnerConnection implements Runnable{
|
||||
break;
|
||||
case 'r':
|
||||
// 服务器配置
|
||||
// todo: 测试用
|
||||
if(MINVpnSettingAPI.INSTANCE.getProxyMode() == 2) {
|
||||
builder.addRoute(fields[1], Integer.parseInt(fields[2]));
|
||||
// builder.addRoute(fields[1], Integer.parseInt(fields[2]));
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
@@ -608,10 +601,6 @@ public class MINVpnInnerConnection implements Runnable{
|
||||
if(MINVpnSettingAPI.INSTANCE.getProxyMode() == 0) {
|
||||
configRoute(builder);
|
||||
}
|
||||
// 全局
|
||||
if(MINVpnSettingAPI.INSTANCE.getProxyMode() == 1) {
|
||||
builder.addRoute("0.0.0.0",0);
|
||||
}
|
||||
|
||||
// 2. 创建一个接口
|
||||
final ParcelFileDescriptor vpnInterface;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.pkusz.min_vpn_client.services;
|
||||
/*
|
||||
* @Author: Wang Feng
|
||||
* @Description:
|
||||
* @Description: 参考安卓项目组给出的ToyVPN
|
||||
* @Version: 1.0.0
|
||||
* @Date: 10:52 2021/7/13
|
||||
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
|
||||
@@ -58,16 +58,13 @@ public class MINVpnService extends VpnService implements Handler.Callback{
|
||||
private final AtomicReference<Thread> mConnectingThread = new AtomicReference<>();
|
||||
private final AtomicReference<Connection> mConnection = new AtomicReference<>();
|
||||
|
||||
// vpn 连接
|
||||
private MINVpnInnerConnection minVpnConnection=null;
|
||||
// vpn 连接: 内网或外网
|
||||
private MINVpnConnection minVpnConnection=null;
|
||||
// connection id
|
||||
private AtomicInteger mNextConnectionId = new AtomicInteger(1);
|
||||
// 通信intent
|
||||
private PendingIntent mConfigureIntent;
|
||||
|
||||
// vpn 外网连接 => 支持访问国外网站
|
||||
// private MINVpnExternalConnection minVpnExternalConnection=null;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
// 使用handler显示消息
|
||||
@@ -145,7 +142,6 @@ public class MINVpnService extends VpnService implements Handler.Callback{
|
||||
final String server = MINVpnSettingAPI.INSTANCE.getMirIpAddress();
|
||||
final int port = MINVpnSettingAPI.INSTANCE.getMirPort();
|
||||
// 生成消息加密密钥
|
||||
// final byte[] secret = RSACryptoForConnection.getRandomAESSeed().PlainSeed.getBytes();
|
||||
final byte[] secret = SM4HelperForConnection.getRandomSeed(); // 获取随机16位长度密钥,用于对称加密
|
||||
// 权限控制集合(并不知道为啥弄这个,我只是继承了由多人零零散散写、改了一年的客户端代码。)
|
||||
final boolean allow = false;
|
||||
@@ -155,20 +151,43 @@ public class MINVpnService extends VpnService implements Handler.Callback{
|
||||
final String proxyHost = "";
|
||||
final int proxyPort = 0;
|
||||
|
||||
// 默认开启内网服务器的连接
|
||||
minVpnConnection = new MINVpnInnerConnection(
|
||||
this, mNextConnectionId.getAndIncrement(), server, port, secret,
|
||||
proxyHost, proxyPort, allow, packages, GlobalSetting.isSM4);
|
||||
// 对vpn connection进行各种监听设置,并启动执行其run函数
|
||||
startConnection(minVpnConnection);
|
||||
|
||||
// 根据全局变量,判断 是否开启外网服务器的连接
|
||||
if(GlobalSetting.openFirewall){
|
||||
// final byte[] secretToExtra = SM4HelperForConnection.getRandomSeed(); // 获取随机16位长度密钥,用于对称加密
|
||||
// minVpnExternalConnection = new MINVpnExternalConnection(
|
||||
// this,mNextConnectionId.getAndIncrement(),
|
||||
// MINVpnSettingAPI.INSTANCE.getOneExtranetVpnServerInfo(),secretToExtra,
|
||||
// proxyHost,proxyPort,allow,packages,GlobalSetting.isSM4);
|
||||
// 根据mode,判断是否开启外网服务器的连接
|
||||
// 2表示内网,1表示外网
|
||||
System.out.println("当前VPN模式: "+MINVpnSettingAPI.INSTANCE.getProxyMode());
|
||||
if(MINVpnSettingAPI.INSTANCE.getProxyMode()==2){
|
||||
// 开启内网服务器的连接
|
||||
minVpnConnection = new MINVpnInnerConnection(
|
||||
this, mNextConnectionId.getAndIncrement(), server, port, secret,
|
||||
proxyHost, proxyPort, allow, packages, GlobalSetting.isSM4);
|
||||
// 对vpn connection进行各种监听设置,并启动执行其run函数
|
||||
startConnection(minVpnConnection);
|
||||
}else if(MINVpnSettingAPI.INSTANCE.getProxyMode()==1){
|
||||
// 通过与内网服务器握手,获取tun网卡的IP地址
|
||||
MINVpnInnerConnection innerConnection = new MINVpnInnerConnection(
|
||||
this, mNextConnectionId.getAndIncrement(), server, port, secret,
|
||||
proxyHost, proxyPort, allow, packages, GlobalSetting.isSM4);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
innerConnection.run();
|
||||
}
|
||||
String allocateIP;
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
|
||||
allocateIP=innerConnection.getAllocatedAddressFromInnerServer();
|
||||
System.out.println("已经为外网访问获取到IP: "+allocateIP);
|
||||
}else {
|
||||
System.out.println("外网访问获取到IP失败");
|
||||
return;
|
||||
}
|
||||
if(allocateIP.length()<=0){
|
||||
System.out.println("外网访问获取到IP失败");
|
||||
return;
|
||||
}
|
||||
// 开启外网服务器的连接
|
||||
minVpnConnection = new MINVpnExternalConnection(
|
||||
this,mNextConnectionId.getAndIncrement(),
|
||||
MINVpnSettingAPI.INSTANCE.getOneExtranetVpnServerInfo(),secret,
|
||||
proxyHost,proxyPort,allow,packages,GlobalSetting.isSM4InExternal,allocateIP);
|
||||
// 对vpn connection进行各种监听设置,并启动执行其run函数
|
||||
startConnection(minVpnConnection);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +195,7 @@ public class MINVpnService extends VpnService implements Handler.Callback{
|
||||
* 启动一条vpn连接
|
||||
* @param connection
|
||||
*/
|
||||
private void startConnection(final MINVpnInnerConnection connection) {
|
||||
private void startConnection(final MINVpnConnection connection) {
|
||||
System.out.println("begin start connection...");
|
||||
// 将vpn连接放入一个线程里
|
||||
final Thread thread = new Thread(connection, "MINVpnThread");
|
||||
@@ -210,6 +229,7 @@ public class MINVpnService extends VpnService implements Handler.Callback{
|
||||
* 关掉vpn连接
|
||||
*/
|
||||
private void disconnect(){
|
||||
System.out.println("收到了关掉连接的消息...");
|
||||
mHandler.sendEmptyMessage(R.string.disconnected);
|
||||
setConnectingThread(null);
|
||||
setConnection(null);
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user