diff --git a/app/build.gradle b/app/build.gradle index 965d9ee..c9f6ca0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,7 +9,7 @@ android { ndk { abiFilters 'arm64-v8a', 'x86_64' } - versionName "1.2.8" + versionName "1.2.9" } buildTypes { diff --git a/app/libs/arm64-v8a/libvnt_jni.so b/app/libs/arm64-v8a/libvnt_jni.so index 98e9d6c..74b2a49 100644 Binary files a/app/libs/arm64-v8a/libvnt_jni.so and b/app/libs/arm64-v8a/libvnt_jni.so differ diff --git a/app/libs/x86_64/libvnt_jni.so b/app/libs/x86_64/libvnt_jni.so index 408b15a..e10a355 100644 Binary files a/app/libs/x86_64/libvnt_jni.so and b/app/libs/x86_64/libvnt_jni.so differ diff --git a/app/src/main/java/top/wherewego/vnt/AddActivity.java b/app/src/main/java/top/wherewego/vnt/AddActivity.java index 66331b1..ef272f6 100644 --- a/app/src/main/java/top/wherewego/vnt/AddActivity.java +++ b/app/src/main/java/top/wherewego/vnt/AddActivity.java @@ -1,7 +1,6 @@ package top.wherewego.vnt; import android.content.Intent; -import android.os.Build; import android.util.Log; import android.widget.EditText; import android.widget.Spinner; @@ -13,13 +12,13 @@ import com.hjq.bar.TitleBar; import java.util.ArrayList; +import java.util.Objects; import java.util.UUID; import top.wherewego.vnt.app.AppActivity; import top.wherewego.vnt.app.AppApplication; -import top.wherewego.vnt.util.IpRouteUtils; +import top.wherewego.vnt.config.ConfigurationInfoBean; import top.wherewego.vnt.util.SPUtils; -import top.wherewego.vnt.jni.ConfigurationInfoBean; public class AddActivity extends AppActivity { private TitleBar mTitleBar; @@ -28,14 +27,16 @@ public class AddActivity extends AppActivity { private EditText mDeviceId; private EditText mPassword; private EditText mServer; - private EditText mStun; private EditText mInIps; private EditText mOutIps; + private EditText mIp; + private EditText mVnpName; + private EditText mPorts; + private EditText mMtu; private Spinner mCipherModel; private Spinner mConnectType; private Spinner mFinger; private Spinner mPriority; - private EditText mPort; private int position; @@ -71,14 +72,17 @@ public void onRightClick(TitleBar titleBar) { mDeviceId.setText(id); mPassword = findViewById(R.id.et_add_password_value); mServer = findViewById(R.id.et_add_server_value); - mStun = findViewById(R.id.et_add_stun_value); +// mStun = findViewById(R.id.et_add_stun_value); mInIps = findViewById(R.id.et_add_in_ip_value); mOutIps = findViewById(R.id.et_add_out_ip_value); mCipherModel = findViewById(R.id.et_add_cipher_model_value); mConnectType = findViewById(R.id.et_add_connect_type_value); mFinger = findViewById(R.id.et_add_finger_value); mPriority = findViewById(R.id.et_add_priority_value); - mPort = findViewById(R.id.et_add_port_value); + mIp = findViewById(R.id.et_add_ip_value); + mVnpName = findViewById(R.id.et_add_net_name_value); + mPorts = findViewById(R.id.et_add_port_value); + mMtu = findViewById(R.id.et_add_mtu_value); } @@ -95,7 +99,7 @@ public void setSpinnerItemSelectedByValue(Spinner spinner, String value) { public int findIndex(ArrayList array, String target) { for (int i = 0; i < array.size(); i++) { - if (array.get(i).getToken() == target) { + if (Objects.equals(array.get(i).getToken(), target)) { return i; } } @@ -104,35 +108,47 @@ public int findIndex(ArrayList array, String target) { private ConfigurationInfoBean getPrevConfigurationInfo() { - try { - return this.position > -1 ? AppApplication.configList.get(this.position) : null; - } catch (Exception e){ - return null; - } + try { + return this.position > -1 ? AppApplication.configList.get(this.position) : null; + } catch (Exception e) { + return null; + } } @Override protected void initData() { Intent intent = getIntent(); - this.position = (int) intent.getIntExtra("position", -1); + this.position = intent.getIntExtra("position", -1); ConfigurationInfoBean configurationInfoBean = this.getPrevConfigurationInfo(); if (configurationInfoBean != null) { + this.mVnpName.setText(configurationInfoBean.getVpnName()); + this.mIp.setText(configurationInfoBean.getIp()); this.mToken.setText(configurationInfoBean.getToken()); this.mName.setText(configurationInfoBean.getName()); this.mDeviceId.setText(configurationInfoBean.getDeviceId()); this.mPassword.setText(configurationInfoBean.getPassword()); this.mServer.setText(configurationInfoBean.getServer()); - this.mStun.setText(configurationInfoBean.getStun()); - this.mInIps.setText(configurationInfoBean.getInIps()); - this.mOutIps.setText(configurationInfoBean.getOutIps()); + if (configurationInfoBean.getPorts() != null) { + StringBuilder ports = new StringBuilder(); + for (int port : configurationInfoBean.getPorts()) { + ports.append(port).append(","); + } + this.mPorts.setText(ports.deleteCharAt(ports.length() - 1).toString()); + } + if (configurationInfoBean.getInIps() != null) { + this.mInIps.setText(String.join("\n", configurationInfoBean.getInIps())); + } + if (configurationInfoBean.getOutIps() != null) { + this.mOutIps.setText(String.join("\n", configurationInfoBean.getOutIps())); + } + if (configurationInfoBean.getMtu() != null) { + mMtu.setText(String.valueOf(configurationInfoBean.getMtu())); + } this.setSpinnerItemSelectedByValue(this.mCipherModel, configurationInfoBean.getCipherModel()); - String tu = configurationInfoBean.isTcp() ? "TCP" : "UDP"; - this.setSpinnerItemSelectedByValue(this.mConnectType, tu); + this.setSpinnerItemSelectedByValue(this.mConnectType, configurationInfoBean.isTcp() ? "TCP" : "UDP"); this.setSpinnerItemSelectedByValue(this.mFinger, configurationInfoBean.isFinger() ? "open" : "close"); this.setSpinnerItemSelectedByValue(this.mPriority, configurationInfoBean.isFirstLatency() ? "latency" : "p2p"); - int port = configurationInfoBean.getPort(); - this.mPort.setText(port == 0 ? "" : port + ""); } } @@ -153,105 +169,102 @@ private void save() { Toast.makeText(this, "Server不能为空", Toast.LENGTH_SHORT).show(); return; } - if (mStun.getText().toString().trim().isEmpty()) { - Toast.makeText(this, "stun不能为空", Toast.LENGTH_SHORT).show(); - return; - } + String ip = mIp.getText().toString().trim(); + String vpnName = mVnpName.getText().toString().trim(); + String token = mToken.getText().toString().trim(); String name = mName.getText().toString().trim(); String deviceId = mDeviceId.getText().toString().trim(); String password = mPassword.getText().toString().trim(); String server = mServer.getText().toString().trim(); - String stun = mStun.getText().toString().trim(); String cipherModel = mCipherModel.getSelectedItem().toString().trim(); - String connectType = mConnectType.getSelectedItem().toString().trim(); - String finger = mFinger.getSelectedItem().toString().trim(); - String priority = mPriority.getSelectedItem().toString().trim(); + boolean isTcp = mConnectType.getSelectedItem().toString().trim().equalsIgnoreCase("tcp"); + boolean finger = mFinger.getSelectedItem().toString().trim().equalsIgnoreCase("open"); + boolean latency = mPriority.getSelectedItem().toString().trim().equalsIgnoreCase("latency"); String inIps = mInIps.getText().toString().trim(); - String portStr = mPort.getText().toString().trim(); - int port = 0; - if (!portStr.isEmpty()) { + String portsStr = mPorts.getText().toString().trim(); + int[] ports = null; + if (!portsStr.isEmpty()) { try { - port = Integer.parseInt(portStr); - if (port < 0 || port >= 65535) { - Toast.makeText(this, "port错误", Toast.LENGTH_SHORT).show(); - return; + String[] portsStrArr = portsStr.split(","); + ports = new int[portsStrArr.length]; + for (int i = 0; i < portsStrArr.length; i++) { + int port = Integer.parseInt(portsStrArr[i]); + if (port < 0 || port >= 65535) { + Toast.makeText(this, "port错误", Toast.LENGTH_SHORT).show(); + return; + } + ports[i] = port; } + } catch (Exception e) { Toast.makeText(this, "port错误", Toast.LENGTH_SHORT).show(); return; } } - if (inIps.isEmpty()) { - inIps = null; - } + String outIps = mOutIps.getText().toString().trim(); - if (outIps.isEmpty()) { - outIps = null; + String mtu = mMtu.getText().toString().trim(); + + ConfigurationInfoBean bean; + if (this.position < 0) { + bean = new ConfigurationInfoBean(); + } else { + bean = AppApplication.configList.get(this.position); } - ConfigurationInfoBean configurationInfoBean = new ConfigurationInfoBean( - token, name, deviceId, password, server, stun, - cipherModel, "TCP".equalsIgnoreCase(connectType), "OPEN".equalsIgnoreCase(finger), inIps, outIps, - "latency".equalsIgnoreCase(priority), port - ); - ConfigurationInfoBean prevConf = this.getPrevConfigurationInfo(); - if (prevConf != null) { - configurationInfoBean.setKey(prevConf.getKey()); + if (!ip.isEmpty()) { + bean.setIp(ip); + } else { + bean.setIp(null); } - try { - String err = check(configurationInfoBean); - if (err != null) { - Toast.makeText(this, err, Toast.LENGTH_SHORT).show(); - return; - } - } catch (Exception e) { - Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show(); - return; + if (vpnName.isEmpty()) { + bean.setVpnName(token); + } else { + bean.setVpnName(vpnName); } - - - if (this.position < 0) { - Log.i("false", "false"); - AppApplication.configList.add(configurationInfoBean); + bean.setToken(token); + bean.setName(name); + if (!password.isEmpty()) { + bean.setPassword(password); } else { - Log.i("true", "true"); - AppApplication.configList.set(this.position, configurationInfoBean); + bean.setPassword(null); } - - SPUtils.putString(getApplicationContext(), "keyset", AppApplication.getKeysString()); - SPUtils.putString(getApplicationContext(), configurationInfoBean.getKey(), new Gson().toJson(configurationInfoBean)); - - finish(); - } - - String check(ConfigurationInfoBean configurationInfoBean) { - String[] parts = configurationInfoBean.getServer().split(":"); - - if (parts.length != 2) { - return "服务器地址错误"; + if (!mtu.isEmpty()) { + bean.setMtu(Integer.parseInt(mtu)); } - int port = 0; - try { - port = Integer.parseInt(parts[1]); - } catch (Exception ignored) { + bean.setPorts(ports); + bean.setCipherModel(cipherModel); + bean.setServerEncrypt(true); + bean.setDeviceId(deviceId); + bean.setServer(server); + bean.setStunServer(new String[]{"stun1.l.google.com:19302", "stun2.l.google.com:19302", "stun.miwifi.com:3478"}); + bean.setTcp(isTcp); + bean.setFinger(finger); + bean.setFirstLatency(latency); + if (!inIps.isEmpty()) { + bean.setInIps(inIps.split("\n")); } - if (port <= 0 || port >= 65536) { - return "服务端口错误"; + if (!outIps.isEmpty()) { + bean.setOutIps(outIps.split("\n")); } - String err; - err = IpRouteUtils.checkInIps(configurationInfoBean.getInIps()); - if (err != null) { - return "inIps错误:" + err; + if (this.position < 0) { + bean.setKey("" + System.currentTimeMillis()); + AppApplication.configList.add(bean); + //新增 + String keyset = SPUtils.getString(getApplicationContext(), "keyset", null); + if (keyset == null) { + SPUtils.putString(getApplicationContext(), "keyset", bean.getKey()); + } else { + SPUtils.putString(getApplicationContext(), "keyset", keyset + "," + bean.getKey()); + } } - err = IpRouteUtils.checkOutIps(configurationInfoBean.getOutIps()); - if (err != null) { - return "outIps错误:" + err; - } - return null; + SPUtils.putString(getApplicationContext(), bean.getKey(), new Gson().toJson(bean)); + + finish(); } } diff --git a/app/src/main/java/top/wherewego/vnt/ConnectActivity.java b/app/src/main/java/top/wherewego/vnt/ConnectActivity.java index 3121231..b3a03f2 100644 --- a/app/src/main/java/top/wherewego/vnt/ConnectActivity.java +++ b/app/src/main/java/top/wherewego/vnt/ConnectActivity.java @@ -2,6 +2,7 @@ import android.annotation.SuppressLint; import android.content.Intent; +import android.util.Log; import android.view.View; import android.widget.TextView; import android.widget.Toast; @@ -21,7 +22,7 @@ import top.wherewego.base.BaseAdapter; import top.wherewego.vnt.adapter.ConnectAdapter; import top.wherewego.vnt.app.AppActivity; -import top.wherewego.vnt.jni.ConfigurationInfoBean; +import top.wherewego.vnt.config.ConfigurationInfoBean; import top.wherewego.vnt.jni.DeviceBean; import top.wherewego.widget.layout.WrapRecyclerView; @@ -37,6 +38,7 @@ public class ConnectActivity extends AppActivity implements OnRefreshLoadMoreLis @SuppressLint("StaticFieldLeak") public static ConnectAdapter mAdapter; ConfigurationInfoBean selectConfigurationInfoBean; + @Override protected int getLayoutId() { return R.layout.activity_connect; @@ -64,6 +66,7 @@ public void onLeftClick(TitleBar titleBar) { finish(); } }); + Log.i("startMyVpnService", "startMyVpnService "+selectConfigurationInfoBean); startMyVpnService(); } @@ -82,11 +85,12 @@ private void startMyVpnService() { Toast.makeText(this, "服务已经启动", Toast.LENGTH_SHORT).show(); return; } + String token = selectConfigurationInfoBean.getToken().trim(); String deviceId = selectConfigurationInfoBean.getDeviceId().trim(); String name = selectConfigurationInfoBean.getName().trim(); String server = selectConfigurationInfoBean.getServer().trim(); - String stun = selectConfigurationInfoBean.getStun().trim(); + String[] stun = selectConfigurationInfoBean.getStunServer(); String cipherModel = selectConfigurationInfoBean.getCipherModel().trim(); if (token.isEmpty()) { Toast.makeText(this, "Token不能为空", Toast.LENGTH_SHORT).show(); @@ -104,31 +108,18 @@ private void startMyVpnService() { Toast.makeText(this, "ServerAddress不能为空", Toast.LENGTH_SHORT).show(); return; } - if (stun.isEmpty()) { + if (stun == null || stun.length == 0) { Toast.makeText(this, "Stun不能为空", Toast.LENGTH_SHORT).show(); return; } - if (cipherModel.isEmpty()){ + if (cipherModel.isEmpty()) { Toast.makeText(this, "加密模式不能为空", Toast.LENGTH_SHORT).show(); return; } - String[] parts = server.split(":"); - if (parts.length != 2) { - Toast.makeText(this, "服务器地址错误", Toast.LENGTH_SHORT).show(); - return; - } - int port = 0; - try { - port = Integer.parseInt(parts[1]); - } catch (Exception ignored) { - } - if (port <= 0 || port >= 65536) { - Toast.makeText(this, "ServerAddress error", Toast.LENGTH_SHORT).show(); - return; - } + Intent serviceIntent = new Intent(this, MyVpnService.class); serviceIntent.setAction("start"); - serviceIntent.putExtra("config",selectConfigurationInfoBean); + serviceIntent.putExtra("config", selectConfigurationInfoBean); startService(serviceIntent); } diff --git a/app/src/main/java/top/wherewego/vnt/MainActivity.java b/app/src/main/java/top/wherewego/vnt/MainActivity.java index f5ca07a..4afd7d1 100644 --- a/app/src/main/java/top/wherewego/vnt/MainActivity.java +++ b/app/src/main/java/top/wherewego/vnt/MainActivity.java @@ -1,6 +1,7 @@ package top.wherewego.vnt; import android.content.Intent; +import android.util.Log; import android.view.View; import androidx.activity.result.ActivityResultLauncher; @@ -19,8 +20,8 @@ import top.wherewego.vnt.adapter.StatusAdapter; import top.wherewego.vnt.app.AppActivity; import top.wherewego.vnt.app.AppApplication; +import top.wherewego.vnt.config.ConfigurationInfoBean; import top.wherewego.vnt.util.SPUtils; -import top.wherewego.vnt.jni.ConfigurationInfoBean; import top.wherewego.widget.layout.WrapRecyclerView; @@ -93,14 +94,20 @@ public void onRightClick(TitleBar titleBar) { public void deleteItem(String key) { - String keyset = SPUtils.getString(getApplicationContext(), "keyset", ""); - StringBuilder newKeySet = new StringBuilder(); - if (keyset.isEmpty()) { + String keyset = SPUtils.getString(getApplicationContext(), "keyset", null); + if (keyset==null) { return; } else { - SPUtils.putString(getApplicationContext(), "keyset", AppApplication.getKeysString()); + StringBuilder newKeySet = new StringBuilder(); + String[] keys = keyset.split(","); + for (String s : keys) { + if (!s.equals(key)) { + newKeySet.append(s).append(","); + } + } + SPUtils.putString(getApplicationContext(), "keyset", newKeySet.toString()); } - SPUtils.deleteShare(getApplicationContext(), key); + SPUtils.deleteShare(getApplicationContext(),key); } @Override @@ -132,6 +139,7 @@ public void onItemClick(RecyclerView recyclerView, View itemView, int position) private void connect() { Intent intent = new Intent(this, ConnectActivity.class); + Log.i("connect", "connect "+selectConfigurationInfoBean); intent.putExtra("selectConfigurationInfoBean", selectConfigurationInfoBean); startActivity(intent); } diff --git a/app/src/main/java/top/wherewego/vnt/MyVpnService.java b/app/src/main/java/top/wherewego/vnt/MyVpnService.java index 2997dee..aae2b52 100644 --- a/app/src/main/java/top/wherewego/vnt/MyVpnService.java +++ b/app/src/main/java/top/wherewego/vnt/MyVpnService.java @@ -2,6 +2,7 @@ import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.VpnService; import android.os.Build; @@ -9,25 +10,28 @@ import android.os.Looper; import android.os.ParcelFileDescriptor; import android.system.OsConstants; +import android.util.Log; import android.widget.Toast; import java.io.IOException; import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.List; -import java.util.Objects; +import top.wherewego.vnt.config.ConfigurationInfoBean; +import top.wherewego.vnt.jni.CallBack; import top.wherewego.vnt.jni.Config; -import top.wherewego.vnt.jni.ConfigurationInfoBean; import top.wherewego.vnt.jni.DeviceBean; import top.wherewego.vnt.jni.IpUtils; -import top.wherewego.vnt.jni.PeerDeviceInfo; -import top.wherewego.vnt.jni.RegResponse; +import top.wherewego.vnt.jni.PeerRouteInfo; import top.wherewego.vnt.jni.Vnt; -import top.wherewego.vnt.jni.VntUtil; -import top.wherewego.vnt.jni.exception.AddressExhaustedException; -import top.wherewego.vnt.jni.exception.TimeoutException; -import top.wherewego.vnt.jni.exception.TokenErrorException; +import top.wherewego.vnt.jni.param.ConnectInfo; +import top.wherewego.vnt.jni.param.DeviceConfig; +import top.wherewego.vnt.jni.param.DeviceInfo; +import top.wherewego.vnt.jni.param.ErrorInfo; +import top.wherewego.vnt.jni.param.HandshakeInfo; +import top.wherewego.vnt.jni.param.PeerClientInfo; +import top.wherewego.vnt.jni.param.RegisterInfo; import top.wherewego.vnt.util.IpRouteUtils; public class MyVpnService extends VpnService implements Runnable { @@ -36,13 +40,13 @@ public class MyVpnService extends VpnService implements Runnable { private ParcelFileDescriptor mInterface; private Vnt eVnt; private Config config; - private volatile boolean isRun; + private HandshakeInfo handshakeInfo = new HandshakeInfo(); - public static PeerDeviceInfo[] peerList() { + public static PeerRouteInfo[] peerList() { if (myVpnService != null && myVpnService.eVnt != null) { return myVpnService.eVnt.list(); } - return new PeerDeviceInfo[0]; + return new PeerRouteInfo[0]; } public static boolean isStart() { @@ -51,7 +55,6 @@ public static boolean isStart() { public static void stop() { if (myVpnService != null) { - myVpnService.stopSelf(); myVpnService.stop0(); } } @@ -69,23 +72,7 @@ public void onCreate() { public synchronized int onStartCommand(Intent intent, int flags, int startId) { switch (intent.getAction()) { case "start": { - isRun = true; - ConfigurationInfoBean selectConfigurationInfoBean = (ConfigurationInfoBean) intent.getSerializableExtra("config"); - String token = selectConfigurationInfoBean.getToken(); - String deviceId = selectConfigurationInfoBean.getDeviceId(); - String name = selectConfigurationInfoBean.getName(); - String password = selectConfigurationInfoBean.getPassword(); - String server = selectConfigurationInfoBean.getServer(); - String stunServer = selectConfigurationInfoBean.getStun(); - String cipherModel = selectConfigurationInfoBean.getCipherModel(); - boolean tcp = selectConfigurationInfoBean.isTcp(); - boolean finger = selectConfigurationInfoBean.isFinger(); - String inIps = selectConfigurationInfoBean.getInIps(); - String outIps = selectConfigurationInfoBean.getOutIps(); - boolean firstLatency = selectConfigurationInfoBean.isFirstLatency(); - int port = selectConfigurationInfoBean.getPort(); - config = new Config(token, name, deviceId, server, stunServer, password.isEmpty() ? null : password, - cipherModel, tcp, finger,inIps,outIps,firstLatency,port); + config = (ConfigurationInfoBean) intent.getSerializableExtra("config"); if (mThread == null) { mThread = new Thread(this, "VntVPN"); mThread.start(); @@ -112,7 +99,7 @@ public void run() { run0(); } catch (Throwable e) { Handler handler = new Handler(Looper.getMainLooper()); - handler.post(() -> Toast.makeText(getApplicationContext(), "启动失败:"+e.getMessage(), Toast.LENGTH_LONG).show()); + handler.post(() -> Toast.makeText(getApplicationContext(), "启动失败:" + e.getMessage(), Toast.LENGTH_LONG).show()); } Handler handler = new Handler(Looper.getMainLooper()); handler.post(() -> { @@ -125,110 +112,158 @@ public void run() { } private synchronized void stop0() { - isRun = false; if (eVnt != null) { eVnt.stop(); } - try { - if (mInterface != null) { + if (myVpnService != null) { + myVpnService.stopSelf(); + + } + if (mInterface != null) { + try { mInterface.close(); + } catch (IOException e) { + Log.e("mInterface", "mInterface", e); } - } catch (IOException ignored) { - } - if (mThread != null) { - mThread.interrupt(); } } private void run0() { try { - String[] parts = config.getServer().split(":"); - new InetSocketAddress(parts[0], Integer.parseInt(parts[1])); - } catch (Exception ignored) { - Handler handler = new Handler(Looper.getMainLooper()); - handler.post(() -> Toast.makeText(getApplicationContext(), "ServerAddress error", Toast.LENGTH_SHORT).show()); - return; - } - VntUtil vntUtil = new VntUtil(config); - RegResponse connect; - for (; ; ) { - if (!isRun) { - return; - } - try { - vntUtil.connect(); - connect = vntUtil.register(); - break; - } catch (AddressExhaustedException e) { - Handler handler = new Handler(Looper.getMainLooper()); - handler.post(() -> Toast.makeText(getApplicationContext(), "Address Exhausted", Toast.LENGTH_SHORT).show()); - return; - } catch (TimeoutException e) { - Handler handler = new Handler(Looper.getMainLooper()); - handler.post(() -> Toast.makeText(getApplicationContext(), "Connect Timeout", Toast.LENGTH_SHORT).show()); - try { - Thread.sleep(3000); - } catch (InterruptedException ignored) { + + eVnt = new Vnt(config, new CallBack() { + @Override + public void success() { + + } + + @Override + public void createTun(DeviceInfo info) { + + } + + @Override + public void connect(ConnectInfo info) { + + } + + @Override + public boolean handshake(HandshakeInfo info) { + handshakeInfo = info; + return true; + } + + @Override + public boolean register(RegisterInfo info) { + Handler handler = new Handler(Looper.getMainLooper()); + handler.post(() -> Toast.makeText(getApplicationContext(), "注册成功", Toast.LENGTH_SHORT).show()); + return true; + } + + @Override + public int generateTun(DeviceConfig info) { + String ip = IpUtils.intToIpAddress(info.getVirtualIp()); + { + Handler handler = new Handler(Looper.getMainLooper()); + handler.post(() -> { + ConnectActivity.headerView.setText("Token:" + config.getToken() + + "\nName:" + config.getName() + + "\nServer:" + config.getServer() + + "\nServer Version:" + handshakeInfo.getVersion() + + "\nServer Finger:" + handshakeInfo.getFinger() + + "\nIp:" + ip); + }); + } + + Builder builder = new Builder(); + int prefixLength = IpUtils.subnetMaskToPrefixLength(info.getVirtualNetmask()); + String ipRoute = IpUtils.intToIpAddress(info.getVirtualGateway() & info.getVirtualNetmask()); + List routeItems = IpRouteUtils.inIp(String.join("\n", info.getExternalRoute())); + int mtu = config.getMtu() == null ? 1410 : config.getMtu(); + builder.setSession("VntVPN") + //.addDisallowedApplication("top.wherewego.vnt") + .setBlocking(false) + .setMtu(mtu) + .addAddress(ip, prefixLength) + .addRoute(ipRoute, prefixLength); + for (IpRouteUtils.RouteItem routeItem : routeItems) { + builder.addAddress(routeItem.address, routeItem.prefixLength); + } + builder.allowFamily(OsConstants.AF_INET); + mInterface = builder.establish(); + return mInterface.getFd(); + } + + @Override + public void peerClientList(PeerClientInfo[] infoArray) { + + } + + @Override + public void error(ErrorInfo info) { + switch (info.code) { + case TokenError: + case AddressExhausted: + case IpAlreadyExists: + case InvalidIp: { + eVnt.stop(); + Handler handler = new Handler(Looper.getMainLooper()); + handler.post(() -> Toast.makeText(getApplicationContext(), "启动失败:" + info.code, Toast.LENGTH_SHORT).show()); + break; + } + case Disconnect: + { + Handler handler = new Handler(Looper.getMainLooper()); + handler.post(() -> Toast.makeText(getApplicationContext(), "断开连接" , Toast.LENGTH_SHORT).show()); + break; + } + case Unknown: + Handler handler = new Handler(Looper.getMainLooper()); + handler.post(() -> Toast.makeText(getApplicationContext(), "启动失败:" + info.msg, Toast.LENGTH_SHORT).show()); + break; + } + + } + + @Override + public void stop() { + Handler handler = new Handler(Looper.getMainLooper()); + handler.post(() -> Toast.makeText(getApplicationContext(), "vnt服务停止", Toast.LENGTH_SHORT).show()); } - } catch (TokenErrorException e) { - Handler handler = new Handler(Looper.getMainLooper()); - handler.post(() -> Toast.makeText(getApplicationContext(), "Token Error", Toast.LENGTH_SHORT).show()); - return; - } - } - String ip = IpUtils.intToIpAddress(connect.getVirtualIp()); -// String gateway = IpUtils.intToIpAddress(connect.getVirtualGateway()); -// String netmask = IpUtils.intToIpAddress(connect.getVirtualNetmask()); - { - Handler handler = new Handler(Looper.getMainLooper()); - handler.post(() -> { - ConnectActivity.headerView.setText("Token:" + config.getToken() - + "\nName:" + config.getName() - + "\nServer:" + config.getServer() - + "\nIp:" + ip); }); + } catch (Exception e) { + e.printStackTrace(); + Log.i("vnt", "vnt ", e); + Handler handler = new Handler(Looper.getMainLooper()); + handler.post(() -> Toast.makeText(getApplicationContext(), "启动失败:" + e.getMessage(), Toast.LENGTH_SHORT).show()); + return; } - Builder builder = new Builder(); - int prefixLength = IpUtils.subnetMaskToPrefixLength(connect.getVirtualNetmask()); - String ipRoute = IpUtils.intToIpAddress(connect.getVirtualGateway() & connect.getVirtualNetmask()); - List routeItems = IpRouteUtils.inIp(config.getInIps()); - builder.setSession("VntVPN") - .setBlocking(true) - .setMtu(1410) - .addAddress(ip, prefixLength) - .addDnsServer("8.8.8.8") - .addRoute(ipRoute, prefixLength); - for (IpRouteUtils.RouteItem routeItem : routeItems) { - builder.addAddress(routeItem.address,routeItem.prefixLength); - } - builder.allowFamily(OsConstants.AF_INET); - mInterface = builder.establish(); - int fd = mInterface.getFd(); - vntUtil.createIface(fd); - Vnt eVntC = vntUtil.build(); - eVnt = eVntC; Handler handler = new Handler(Looper.getMainLooper()); for (; ; ) { handler.post(() -> { List list = new ArrayList<>(); - for (PeerDeviceInfo peer : eVnt.list()) { - String rt = ""; - String type = ""; - if (peer.getRoute() != null) { - rt = "" + peer.getRoute().getRt(); - type = peer.getRoute().getMetric() == 1 ? "p2p" : "relay"; + PeerRouteInfo[] peerRouteInfos = eVnt.list(); + if (peerRouteInfos != null) { + for (PeerRouteInfo peer : peerRouteInfos) { + String rt = ""; + String type = ""; + if (peer.getRoute() != null) { + rt = "" + peer.getRoute().getRt(); + type = peer.getRoute().getMetric() == 1 ? "p2p" : "relay"; + } + DeviceBean deviceBean = new DeviceBean(peer.getName(), IpUtils.intToIpAddress(peer.getVirtualIp()), + peer.getStatus(), rt, type); + list.add(deviceBean); } - DeviceBean deviceBean = new DeviceBean(peer.getName(), IpUtils.intToIpAddress(peer.getVirtualIp()), - peer.getStatus(), rt, type); - list.add(deviceBean); - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - list.sort(DeviceBean::compareTo); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + list.sort(DeviceBean::compareTo); + } + ConnectActivity.mAdapter.setData(list); } - ConnectActivity.mAdapter.setData(list); + }); - boolean out = eVntC.waitStopMs(2000); + boolean out = eVnt.awaitTimeout(2000); if (out) { break; } diff --git a/app/src/main/java/top/wherewego/vnt/adapter/StatusAdapter.java b/app/src/main/java/top/wherewego/vnt/adapter/StatusAdapter.java index e5f8830..e66042b 100644 --- a/app/src/main/java/top/wherewego/vnt/adapter/StatusAdapter.java +++ b/app/src/main/java/top/wherewego/vnt/adapter/StatusAdapter.java @@ -8,7 +8,7 @@ import top.wherewego.vnt.R; import top.wherewego.vnt.app.AppAdapter; -import top.wherewego.vnt.jni.ConfigurationInfoBean; +import top.wherewego.vnt.config.ConfigurationInfoBean; /** * author : Android 轮子哥 @@ -44,7 +44,7 @@ private ViewHolder() { @Override public void onBindView(int position) { - mTokenValue.setText(getItem(position).getToken()); + mTokenValue.setText(getItem(position).getVpnName()); mNameValue.setText(getItem(position).getName()); mServerValue.setText(getItem(position).getServer()); } diff --git a/app/src/main/java/top/wherewego/vnt/app/AppApplication.java b/app/src/main/java/top/wherewego/vnt/app/AppApplication.java index 2448904..0f80435 100644 --- a/app/src/main/java/top/wherewego/vnt/app/AppApplication.java +++ b/app/src/main/java/top/wherewego/vnt/app/AppApplication.java @@ -14,8 +14,8 @@ import java.util.ArrayList; import top.wherewego.vnt.R; +import top.wherewego.vnt.config.ConfigurationInfoBean; import top.wherewego.vnt.util.SPUtils; -import top.wherewego.vnt.jni.ConfigurationInfoBean; /** * author : Android 轮子哥 @@ -32,21 +32,13 @@ public void onCreate() { initSdk(this); } - public static String getKeysString (){ - String keyStr = ""; - for (int i = 0; i < configList.size(); i++) { - keyStr += keyStr.isEmpty() ? configList.get(i).getKey(): ","+configList.get(i).getKey(); - } - return keyStr; - } - @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); - String keyset = SPUtils.getString(this, "keyset", "0"); - if (!keyset.equals("0")) { + String keyset = SPUtils.getString(this, "keyset", null); + if (keyset!=null) { String[] strArray = null; strArray = keyset.split(","); //拆分字符为"," ,然后把结果交给数组strArray Log.d("swichapp", "attachBaseContext: keyset : " + keyset); diff --git a/app/src/main/java/top/wherewego/vnt/config/ConfigurationInfoBean.java b/app/src/main/java/top/wherewego/vnt/config/ConfigurationInfoBean.java new file mode 100644 index 0000000..a5ad781 --- /dev/null +++ b/app/src/main/java/top/wherewego/vnt/config/ConfigurationInfoBean.java @@ -0,0 +1,34 @@ +package top.wherewego.vnt.config; + +import java.io.Serializable; + +import top.wherewego.vnt.jni.Config; + +public class ConfigurationInfoBean extends Config implements Serializable { + private String key; + private String vpnName; + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getVpnName() { + return vpnName; + } + + public void setVpnName(String vpnName) { + this.vpnName = vpnName; + } + + @Override + public String toString() { + return "ConfigurationInfoBean{" + + "key='" + key + '\'' + + "config"+super.toString()+ + '}'; + } +} diff --git a/app/src/main/java/top/wherewego/vnt/jni/CallBack.java b/app/src/main/java/top/wherewego/vnt/jni/CallBack.java new file mode 100644 index 0000000..84f5771 --- /dev/null +++ b/app/src/main/java/top/wherewego/vnt/jni/CallBack.java @@ -0,0 +1,79 @@ +package top.wherewego.vnt.jni; + +import android.content.pm.PackageManager; + +import top.wherewego.vnt.jni.param.*; + +/** + * 回调 + * + * @author https://github.com/lbl8603/vnt + */ +public interface CallBack { + /** + * 连接成功的回调 + */ + void success(); + + /** + * 创建虚拟网卡成功的回调方法 + * 仅在 windows/linux/macos上使用 + * + * @param info 网卡信息 + */ + void createTun(DeviceInfo info); + + /** + * 连接服务端 + * + * @param info 将要连接的服务端信息 + */ + void connect(ConnectInfo info); + + /** + * 和服务端握手 + * + * @param info 握手信息 + * @return 是否确认握手 + */ + boolean handshake(HandshakeInfo info); + + /** + * 注册成功回调 + * + * @param info 注册信息 + * @return 是否确认注册信息 + */ + boolean register(RegisterInfo info); + + /** + * 创建网卡回调 + * 仅在android上使用 + * + * @param info 创建配置 + * @return 网卡fd + */ + + int generateTun(DeviceConfig info) throws PackageManager.NameNotFoundException; + + /** + * 对端用户列表 + * + * @param infoArray + */ + void peerClientList(PeerClientInfo[] infoArray); + + + /** + * 异常回调 + * + * @param info 错误信息 + */ + void error(ErrorInfo info); + + /** + * 服务停止 + */ + void stop(); + +} diff --git a/app/src/main/java/top/wherewego/vnt/jni/Config.java b/app/src/main/java/top/wherewego/vnt/jni/Config.java index 1bdcf39..2bfe7ee 100644 --- a/app/src/main/java/top/wherewego/vnt/jni/Config.java +++ b/app/src/main/java/top/wherewego/vnt/jni/Config.java @@ -1,37 +1,120 @@ package top.wherewego.vnt.jni; -public class Config { +import java.io.Serializable; +import java.util.Arrays; + +/** + * 启动配置 + * + * @author https://github.com/lbl8603/vnt + */ +public class Config implements Serializable { + /** + * 是否是tap模式,仅支持windows + */ + private boolean tap; + /** + * 组网标识 + */ private String token; + /** + * 设备名称 + */ private String name; - private String deviceId; - private String server; - private String stunServer; + /** + * 客户端间加密的密码 + */ private String password; + /** + * 客户端间加密模式 aes_gcm/aes_cbc/aes_ecb/sm4_cbc + */ private String cipherModel; + /** + * 打洞模式 ipv4/ipv6/all + */ + private String punchModel; + /** + * mtu 默认自动计算 + */ + private Integer mtu; + /** + * 是否开启服务端加密 + */ + private boolean serverEncrypt; + /** + * 设备id,请使用唯一值 + */ + private String deviceId; + /** + * 服务端地址 + */ + private String server; + /** + * dns地址 + */ + private String[] dns; + /** + * 端口映射 + */ + private String[] portMapping; + /** + * stun服务地址 + */ + private String[] stunServer; + /** + * 和服务端使用tcp通信,默认使用udp + */ private boolean tcp; + /** + * 指定组网IP + */ + private String ip; + /** + * 开启加密指纹校验 + */ private boolean finger; + /** + * 延迟优先,默认p2p优先 + */ private boolean firstLatency; - private int port; - private String inIps; - private String outIps; + /** + * 点对网入口 格式 192.168.0.0/26,10.26.0.2 + */ + private String[] inIps; + /** + * 点对网出口 格式 192.168.0.0/26 + */ + private String[] outIps; + /** + * 端口组,udp会监听一组端口,tcp监听ports[0]端口 + */ + private int[] ports; + /** + * 虚拟网卡名称 仅在linux、windows、macos上支持 + */ + private String deviceName; + /** + * enum: relay/p2p/all + */ + private String useChannel; + /** + * 模拟丢包率,取0~1之间的数,为null表示不丢包,1表示全部丢包 + */ + private Double packetLossRate; + /** + * 模拟延迟 单位毫秒(ms) + */ + private Integer packetDelay; + public Config() { + } - public Config(String token, String name, String deviceId, String server, - String stunServer, String password, String cipherModel, boolean tcp,boolean finger, - String inIps,String outIps,boolean firstLatency,int port) { - this.token = token; - this.name = name; - this.deviceId = deviceId; - this.server = server; - this.stunServer = stunServer; - this.password = password; - this.cipherModel = cipherModel; - this.tcp = tcp; - this.finger = finger; - this.inIps = inIps; - this.outIps = outIps; - this.firstLatency = firstLatency; - this.port = port; + public boolean isTap() { + return tap; + } + + public void setTap(boolean tap) { + this.tap = tap; } public String getToken() { @@ -50,6 +133,47 @@ public void setName(String name) { this.name = name; } + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getCipherModel() { + return cipherModel; + } + + public void setCipherModel(String cipherModel) { + this.cipherModel = cipherModel; + } + + public String getPunchModel() { + return punchModel; + } + + public void setPunchModel(String punchModel) { + this.punchModel = punchModel; + } + + public Integer getMtu() { + return mtu; + } + + public void setMtu(Integer mtu) { + this.mtu = mtu; + } + + public boolean isServerEncrypt() { + return serverEncrypt; + } + + public void setServerEncrypt(boolean serverEncrypt) { + this.serverEncrypt = serverEncrypt; + } + + public String getDeviceId() { return deviceId; } @@ -66,28 +190,27 @@ public void setServer(String server) { this.server = server; } - public String getStunServer() { - return stunServer; + public String[] getDns() { + return dns; } - public void setStunServer(String stunServer) { - this.stunServer = stunServer; + public void setDns(String[] dns) { + this.dns = dns; } - - public String getPassword() { - return password; + public String[] getPortMapping() { + return portMapping; } - public void setPassword(String password) { - this.password = password; + public void setPortMapping(String[] portMapping) { + this.portMapping = portMapping; } - public String getCipherModel() { - return cipherModel; + public String[] getStunServer() { + return stunServer; } - public void setCipherModel(String cipherModel) { - this.cipherModel = cipherModel; + public void setStunServer(String[] stunServer) { + this.stunServer = stunServer; } public boolean isTcp() { @@ -98,6 +221,14 @@ public void setTcp(boolean tcp) { this.tcp = tcp; } + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + public boolean isFinger() { return finger; } @@ -106,35 +237,97 @@ public void setFinger(boolean finger) { this.finger = finger; } - public String getInIps() { + public boolean isFirstLatency() { + return firstLatency; + } + + public void setFirstLatency(boolean firstLatency) { + this.firstLatency = firstLatency; + } + + public String[] getInIps() { return inIps; } - public void setInIps(String inIps) { + public void setInIps(String[] inIps) { this.inIps = inIps; } - public String getOutIps() { + public String[] getOutIps() { return outIps; } - public void setOutIps(String outIps) { + public void setOutIps(String[] outIps) { this.outIps = outIps; } - public boolean isFirstLatency() { - return firstLatency; + public int[] getPorts() { + return ports; } - public void setFirstLatency(boolean firstLatency) { - this.firstLatency = firstLatency; + public void setPorts(int[] ports) { + this.ports = ports; + } + + public String getDeviceName() { + return deviceName; + } + + public void setDeviceName(String deviceName) { + this.deviceName = deviceName; + } + + public String getUseChannel() { + return useChannel; + } + + public void setUseChannel(String useChannel) { + this.useChannel = useChannel; + } + + public Double getPacketLossRate() { + return packetLossRate; + } + + public void setPacketLossRate(Double packetLossRate) { + this.packetLossRate = packetLossRate; + } + + public Integer getPacketDelay() { + return packetDelay; } - public int getPort() { - return port; + public void setPacketDelay(Integer packetDelay) { + this.packetDelay = packetDelay; } - public void setPort(int port) { - this.port = port; + @Override + public String toString() { + return "Config{" + + "tap=" + tap + + ", token='" + token + '\'' + + ", name='" + name + '\'' + + ", password='" + password + '\'' + + ", cipherModel='" + cipherModel + '\'' + + ", punchModel='" + punchModel + '\'' + + ", mtu=" + mtu + + ", serverEncrypt=" + serverEncrypt + + ", deviceId='" + deviceId + '\'' + + ", server='" + server + '\'' + + ", dns=" + Arrays.toString(dns) + + ", portMapping=" + Arrays.toString(portMapping) + + ", stunServer=" + Arrays.toString(stunServer) + + ", tcp=" + tcp + + ", ip='" + ip + '\'' + + ", finger=" + finger + + ", firstLatency=" + firstLatency + + ", inIps=" + Arrays.toString(inIps) + + ", outIps=" + Arrays.toString(outIps) + + ", ports=" + Arrays.toString(ports) + + ", deviceName='" + deviceName + '\'' + + ", useChannel='" + useChannel + '\'' + + ", packetLossRate=" + packetLossRate + + ", packetDelay=" + packetDelay + + '}'; } } diff --git a/app/src/main/java/top/wherewego/vnt/jni/ConfigurationInfoBean.java b/app/src/main/java/top/wherewego/vnt/jni/ConfigurationInfoBean.java deleted file mode 100644 index 6efc000..0000000 --- a/app/src/main/java/top/wherewego/vnt/jni/ConfigurationInfoBean.java +++ /dev/null @@ -1,151 +0,0 @@ -package top.wherewego.vnt.jni; - -import java.io.Serializable; - -public class ConfigurationInfoBean implements Serializable { - private String key; - private String token; - private String name; - private String deviceId; - private String password; - private String server; - private String stun; - private String cipherModel; - private boolean tcp; - private boolean finger; - private String inIps; - private String outIps; - private boolean firstLatency; - private int port; - - public ConfigurationInfoBean(String token, String name, String deviceId, String password, - String server, String stun, String cipherModel, boolean tcp, boolean finger, - String inIps, String outIps,boolean firstLatency,int port) { - this.key = String.valueOf(System.currentTimeMillis()); - this.token = token; - this.name = name; - this.deviceId = deviceId; - this.password = password; - this.server = server; - this.stun = stun; - this.cipherModel = cipherModel; - this.tcp = tcp; - this.finger = finger; - this.inIps = inIps; - this.outIps = outIps; - this.firstLatency = firstLatency; - this.port = port; - } - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; - } - - public String getToken() { - return token; - } - - public void setToken(String token) { - this.token = token; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getDeviceId() { - return deviceId; - } - - public void setDeviceId(String deviceId) { - this.deviceId = deviceId; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public String getServer() { - return server; - } - - public void setServer(String server) { - this.server = server; - } - - public String getStun() { - return stun; - } - - public void setStun(String stun) { - this.stun = stun; - } - - public String getCipherModel() { - return cipherModel; - } - - public void setCipherModel(String cipherModel) { - this.cipherModel = cipherModel; - } - - public boolean isTcp() { - return tcp; - } - - public void setTcp(boolean tcp) { - this.tcp = tcp; - } - - public boolean isFinger() { - return finger; - } - - public void setFinger(boolean finger) { - this.finger = finger; - } - - public String getInIps() { - return inIps; - } - - public void setInIps(String inIps) { - this.inIps = inIps; - } - - public String getOutIps() { - return outIps; - } - - public void setOutIps(String outIps) { - this.outIps = outIps; - } - - public boolean isFirstLatency() { - return firstLatency; - } - - public void setFirstLatency(boolean firstLatency) { - this.firstLatency = firstLatency; - } - - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } -} diff --git a/app/src/main/java/top/wherewego/vnt/jni/IpUtils.java b/app/src/main/java/top/wherewego/vnt/jni/IpUtils.java index eae6894..607666f 100644 --- a/app/src/main/java/top/wherewego/vnt/jni/IpUtils.java +++ b/app/src/main/java/top/wherewego/vnt/jni/IpUtils.java @@ -1,6 +1,17 @@ package top.wherewego.vnt.jni; +/** + * ip转换 + * + * @author https://github.com/lbl8603/vnt + */ public class IpUtils { + /** + * 将整数的ip地址转成字符串,例如 0 转成 "0.0.0.0" + * + * @param ipAddress + * @return + */ public static String intToIpAddress(int ipAddress) { return ((ipAddress & 0xFF000000) >>> 24) + "." + @@ -8,6 +19,13 @@ public static String intToIpAddress(int ipAddress) { ((ipAddress & 0x0000FF00) >>> 8) + "." + (ipAddress & 0x000000FF); } + + /** + * 返回掩码的长度 + * + * @param subnetMask + * @return + */ public static int subnetMaskToPrefixLength(int subnetMask) { int prefixLength = 0; int bit = 1 << 31; diff --git a/app/src/main/java/top/wherewego/vnt/jni/PeerDeviceInfo.java b/app/src/main/java/top/wherewego/vnt/jni/PeerRouteInfo.java similarity index 75% rename from app/src/main/java/top/wherewego/vnt/jni/PeerDeviceInfo.java rename to app/src/main/java/top/wherewego/vnt/jni/PeerRouteInfo.java index 209f3ec..adc92a7 100644 --- a/app/src/main/java/top/wherewego/vnt/jni/PeerDeviceInfo.java +++ b/app/src/main/java/top/wherewego/vnt/jni/PeerRouteInfo.java @@ -1,12 +1,17 @@ package top.wherewego.vnt.jni; -public class PeerDeviceInfo { +/** + * 对端设备信息 + * + * @author https://github.com/lbl8603/vnt + */ +public class PeerRouteInfo { private final int virtualIp; private final String name; private final String status; private final Route route; - public PeerDeviceInfo(int virtualIp, String name, String status, Route route) { + public PeerRouteInfo(int virtualIp, String name, String status, Route route) { this.virtualIp = virtualIp; this.name = name; this.status = status; @@ -32,7 +37,7 @@ public Route getRoute() { @Override public String toString() { return "PeerDeviceInfo{" + - "virtualIp=" + virtualIp + + "virtualIp=" + IpUtils.intToIpAddress(virtualIp) + ", name='" + name + '\'' + ", status='" + status + '\'' + ", route=" + route + diff --git a/app/src/main/java/top/wherewego/vnt/jni/RegResponse.java b/app/src/main/java/top/wherewego/vnt/jni/RegResponse.java deleted file mode 100644 index f6da82a..0000000 --- a/app/src/main/java/top/wherewego/vnt/jni/RegResponse.java +++ /dev/null @@ -1,34 +0,0 @@ -package top.wherewego.vnt.jni; - -public class RegResponse { - private final int virtualIp; - private final int virtualGateway; - private final int virtualNetmask; - - public RegResponse(int virtualIp, int virtualGateway, int virtualNetmask) { - this.virtualIp = virtualIp; - this.virtualGateway = virtualGateway; - this.virtualNetmask = virtualNetmask; - } - - public int getVirtualIp() { - return virtualIp; - } - - public int getVirtualGateway() { - return virtualGateway; - } - - public int getVirtualNetmask() { - return virtualNetmask; - } - - @Override - public String toString() { - return "RegResponse{" + - "virtualIp=" + virtualIp + - ", virtualGateway=" + virtualGateway + - ", virtualNetmask=" + virtualNetmask + - '}'; - } -} diff --git a/app/src/main/java/top/wherewego/vnt/jni/Route.java b/app/src/main/java/top/wherewego/vnt/jni/Route.java index 60b5bf7..fe68702 100644 --- a/app/src/main/java/top/wherewego/vnt/jni/Route.java +++ b/app/src/main/java/top/wherewego/vnt/jni/Route.java @@ -1,16 +1,31 @@ package top.wherewego.vnt.jni; +/** + * 路由信息 + * + * @author https://github.com/lbl8603/vnt + */ public class Route { + /** + * 是否使用tcp + */ + private final boolean tcp; private final String address; private final byte metric; private final int rt; - public Route(String address, byte metric, int rt) { + + public Route(boolean tcp, String address, byte metric, int rt) { + this.tcp = tcp; this.address = address; this.metric = metric; this.rt = rt; } + public boolean isTcp() { + return tcp; + } + public String getAddress() { return address; } @@ -26,7 +41,8 @@ public int getRt() { @Override public String toString() { return "Route{" + - "address='" + address + '\'' + + "tcp=" + tcp + + ", address='" + address + '\'' + ", metric=" + metric + ", rt=" + rt + '}'; diff --git a/app/src/main/java/top/wherewego/vnt/jni/Vnt.java b/app/src/main/java/top/wherewego/vnt/jni/Vnt.java index 4c802c6..e931a56 100644 --- a/app/src/main/java/top/wherewego/vnt/jni/Vnt.java +++ b/app/src/main/java/top/wherewego/vnt/jni/Vnt.java @@ -1,44 +1,53 @@ package top.wherewego.vnt.jni; -public class Vnt { +import java.io.Closeable; +import java.io.IOException; + +/** + * vnt的Java映射 + * + * @author https://github.com/lbl8603/vnt + */ +public class Vnt implements Closeable { private final long raw; - Vnt(long raw) { - if (raw == 0) { + public Vnt(Config config, CallBack callBack) throws Exception { + this.raw = new0(config, callBack); + if (this.raw == 0) { throw new RuntimeException(); } - this.raw = raw; } public void stop() { stop0(raw); } - public void waitStop() { - waitStop0(raw); + public void await() { + wait0(raw); } - public boolean waitStopMs(long ms) { - return waitStopMs0(raw, ms); + public boolean awaitTimeout(long ms) { + return waitTimeout0(raw, ms); } - public PeerDeviceInfo[] list() { + public PeerRouteInfo[] list() { return list0(raw); } - private native void stop0(long raw); + private native long new0(Config config, CallBack callBack) throws Exception; - private native void waitStop0(long raw); + private native void stop0(long raw); - private native boolean waitStopMs0(long raw, long ms); + private native void wait0(long raw); - private native PeerDeviceInfo[] list0(long raw); + private native boolean waitTimeout0(long raw, long ms); private native void drop0(long raw); + private native PeerRouteInfo[] list0(long raw); + @Override - protected void finalize() throws Throwable { - super.finalize(); + public void close() throws IOException { drop0(raw); } } diff --git a/app/src/main/java/top/wherewego/vnt/jni/VntUtil.java b/app/src/main/java/top/wherewego/vnt/jni/VntUtil.java deleted file mode 100644 index 6ef5130..0000000 --- a/app/src/main/java/top/wherewego/vnt/jni/VntUtil.java +++ /dev/null @@ -1,50 +0,0 @@ -package top.wherewego.vnt.jni; - -import top.wherewego.vnt.jni.exception.AddressExhaustedException; -import top.wherewego.vnt.jni.exception.TimeoutException; -import top.wherewego.vnt.jni.exception.TokenErrorException; - -public class VntUtil { - private final long raw; - private boolean isBuild; - - public VntUtil(Config config) { - raw = new0(config); - if (raw == 0) { - throw new RuntimeException(); - } - } - - public void connect() { - connect0(raw); - } - - public RegResponse register() throws AddressExhaustedException, TimeoutException, TokenErrorException { - return register0(raw); - } - - public void createIface(int fd) { - if (fd == 0) { - throw new RuntimeException(); - } - createIface0(raw, fd); - } - - public synchronized Vnt build() { - if (!isBuild) { - isBuild = true; - return new Vnt(build0(raw)); - } - throw new RuntimeException(); - } - - private native void connect0(long raw); - - private native RegResponse register0(long raw) throws AddressExhaustedException, TimeoutException, TokenErrorException; - - private native void createIface0(long raw, int fd); - - private native long new0(Config config); - - private native long build0(long raw); -} diff --git a/app/src/main/java/top/wherewego/vnt/jni/exception/AddressExhaustedException.java b/app/src/main/java/top/wherewego/vnt/jni/exception/AddressExhaustedException.java deleted file mode 100644 index 9e79cd0..0000000 --- a/app/src/main/java/top/wherewego/vnt/jni/exception/AddressExhaustedException.java +++ /dev/null @@ -1,7 +0,0 @@ -package top.wherewego.vnt.jni.exception; - -public class AddressExhaustedException extends Exception{ - public AddressExhaustedException(String message) { - super(message); - } -} diff --git a/app/src/main/java/top/wherewego/vnt/jni/exception/TimeoutException.java b/app/src/main/java/top/wherewego/vnt/jni/exception/TimeoutException.java deleted file mode 100644 index d6c9c8c..0000000 --- a/app/src/main/java/top/wherewego/vnt/jni/exception/TimeoutException.java +++ /dev/null @@ -1,7 +0,0 @@ -package top.wherewego.vnt.jni.exception; - -public class TimeoutException extends Exception{ - public TimeoutException(String message) { - super(message); - } -} diff --git a/app/src/main/java/top/wherewego/vnt/jni/exception/TokenErrorException.java b/app/src/main/java/top/wherewego/vnt/jni/exception/TokenErrorException.java deleted file mode 100644 index b726338..0000000 --- a/app/src/main/java/top/wherewego/vnt/jni/exception/TokenErrorException.java +++ /dev/null @@ -1,7 +0,0 @@ -package top.wherewego.vnt.jni.exception; - -public class TokenErrorException extends Exception{ - public TokenErrorException(String message) { - super(message); - } -} diff --git a/app/src/main/java/top/wherewego/vnt/jni/param/ConnectInfo.java b/app/src/main/java/top/wherewego/vnt/jni/param/ConnectInfo.java new file mode 100644 index 0000000..414fb96 --- /dev/null +++ b/app/src/main/java/top/wherewego/vnt/jni/param/ConnectInfo.java @@ -0,0 +1,32 @@ +package top.wherewego.vnt.jni.param; + +/** + * 连接信息 + * + * @author https://github.com/lbl8603/vnt + */ +public class ConnectInfo { + private final long count; + private final String address; + + public ConnectInfo(long count, String address) { + this.count = count; + this.address = address; + } + + public long getCount() { + return count; + } + + public String getAddress() { + return address; + } + + @Override + public String toString() { + return "ConnectInfo{" + + "count=" + count + + ", address='" + address + '\'' + + '}'; + } +} diff --git a/app/src/main/java/top/wherewego/vnt/jni/param/DeviceConfig.java b/app/src/main/java/top/wherewego/vnt/jni/param/DeviceConfig.java new file mode 100644 index 0000000..91aa843 --- /dev/null +++ b/app/src/main/java/top/wherewego/vnt/jni/param/DeviceConfig.java @@ -0,0 +1,72 @@ +package top.wherewego.vnt.jni.param; + +import top.wherewego.vnt.jni.IpUtils; + +import java.util.Arrays; + +/** + * 创建网卡所需信息,仅在android上使用 + * + * @author https://github.com/lbl8603/vnt + */ +public class DeviceConfig { + /** + * 虚拟IP + */ + public final int virtualIp; + /** + * 掩码 + */ + public final int virtualNetmask; + /** + * 网关 + */ + public final int virtualGateway; + /** + * 虚拟网段 + */ + public final int virtualNetwork; + /** + * 额外路由,来自点对网的路由配置 + */ + public final String[] externalRoute; + + public DeviceConfig(int virtualIp, int virtualNetmask, int virtualGateway, int virtualNetwork, String[] externalRoute) { + this.virtualIp = virtualIp; + this.virtualNetmask = virtualNetmask; + this.virtualGateway = virtualGateway; + this.virtualNetwork = virtualNetwork; + this.externalRoute = externalRoute; + } + + public int getVirtualIp() { + return virtualIp; + } + + public int getVirtualNetmask() { + return virtualNetmask; + } + + public int getVirtualGateway() { + return virtualGateway; + } + + public int getVirtualNetwork() { + return virtualNetwork; + } + + public String[] getExternalRoute() { + return externalRoute; + } + + @Override + public String toString() { + return "DeviceConfig{" + + "virtualIp=" + IpUtils.intToIpAddress(virtualIp) + + ", virtualNetmask=" + IpUtils.intToIpAddress(virtualNetmask) + + ", virtualGateway=" + IpUtils.intToIpAddress(virtualGateway) + + ", virtualNetwork=" + IpUtils.intToIpAddress(virtualNetwork) + + ", externalRoute=" + Arrays.toString(externalRoute) + + '}'; + } +} diff --git a/app/src/main/java/top/wherewego/vnt/jni/param/DeviceInfo.java b/app/src/main/java/top/wherewego/vnt/jni/param/DeviceInfo.java new file mode 100644 index 0000000..ddb8f0a --- /dev/null +++ b/app/src/main/java/top/wherewego/vnt/jni/param/DeviceInfo.java @@ -0,0 +1,38 @@ +package top.wherewego.vnt.jni.param; + +/** + * 网卡信息 仅在 windows/linux/macos上使用 + * + * @author https://github.com/lbl8603/vnt + */ +public class DeviceInfo { + /** + * 虚拟网卡名称 + */ + private final String name; + /** + * 虚拟网卡版本 + */ + private final String version; + + public DeviceInfo(String name, String version) { + this.name = name; + this.version = version; + } + + public String getName() { + return name; + } + + public String getVersion() { + return version; + } + + @Override + public String toString() { + return "DeviceInfo{" + + "name='" + name + '\'' + + ", version='" + version + '\'' + + '}'; + } +} diff --git a/app/src/main/java/top/wherewego/vnt/jni/param/ErrorInfo.java b/app/src/main/java/top/wherewego/vnt/jni/param/ErrorInfo.java new file mode 100644 index 0000000..f24e443 --- /dev/null +++ b/app/src/main/java/top/wherewego/vnt/jni/param/ErrorInfo.java @@ -0,0 +1,65 @@ +package top.wherewego.vnt.jni.param; + +/** + * 异常回调信息 + * + * @author https://github.com/lbl8603/vnt + */ +public class ErrorInfo { + /** + * 错误码 + */ + public final ErrorCodeEnum code; + /** + * 错误信息,可能为空 + */ + public final String msg; + + public ErrorInfo(int code, String msg) { + switch (code) { + case 1: + this.code = ErrorCodeEnum.TokenError; + break; + case 2: + this.code = ErrorCodeEnum.Disconnect; + break; + case 3: + this.code = ErrorCodeEnum.AddressExhausted; + break; + case 4: + this.code = ErrorCodeEnum.IpAlreadyExists; + break; + case 5: + this.code = ErrorCodeEnum.InvalidIp; + break; + default: + this.code = ErrorCodeEnum.Unknown; + } + this.msg = msg; + } + + public ErrorCodeEnum getCode() { + return code; + } + + public String getMsg() { + return msg; + } + + public enum ErrorCodeEnum { + TokenError, + Disconnect, + AddressExhausted, + IpAlreadyExists, + InvalidIp, + Unknown, + } + + @Override + public String toString() { + return "ErrorInfo{" + + "code=" + code + + ", msg='" + msg + '\'' + + '}'; + } +} diff --git a/app/src/main/java/top/wherewego/vnt/jni/param/HandshakeInfo.java b/app/src/main/java/top/wherewego/vnt/jni/param/HandshakeInfo.java new file mode 100644 index 0000000..b440942 --- /dev/null +++ b/app/src/main/java/top/wherewego/vnt/jni/param/HandshakeInfo.java @@ -0,0 +1,54 @@ +package top.wherewego.vnt.jni.param; + +/** + * 握手回调信息 + * + * @author https://github.com/lbl8603/vnt + */ +public class HandshakeInfo { + /** + * 公钥 pem格式 CRLF分隔,不加密时为空 + */ + private final String publicKey; + /** + * 公钥签名,不加密时为空 + */ + private final String finger; + /** + * 服务端版本 + */ + private final String version; + + public HandshakeInfo() { + this.publicKey = ""; + this.finger = ""; + this.version = ""; + } + + public HandshakeInfo(String publicKey, String finger, String version) { + this.publicKey = publicKey; + this.finger = finger; + this.version = version; + } + + public String getPublicKey() { + return publicKey; + } + + public String getFinger() { + return finger; + } + + public String getVersion() { + return version; + } + + @Override + public String toString() { + return "HandshakeInfo{" + + "publicKey='" + publicKey + '\'' + + ", finger='" + finger + '\'' + + ", version='" + version + '\'' + + '}'; + } +} diff --git a/app/src/main/java/top/wherewego/vnt/jni/param/PeerClientInfo.java b/app/src/main/java/top/wherewego/vnt/jni/param/PeerClientInfo.java new file mode 100644 index 0000000..f19a759 --- /dev/null +++ b/app/src/main/java/top/wherewego/vnt/jni/param/PeerClientInfo.java @@ -0,0 +1,60 @@ +package top.wherewego.vnt.jni.param; + +import top.wherewego.vnt.jni.IpUtils; + +/** + * 创建网卡所需信息,仅在android上使用 + * + * @author https://github.com/lbl8603/vnt + */ +public class PeerClientInfo { + /** + * 虚拟IP + */ + public final int virtualIp; + /** + * 名称 + */ + public final String name; + /** + * 是否在线 + */ + public final boolean online; + /** + * 是否开启客户端加密,不同加密状态的不能通信 + */ + public final boolean clientSecret; + + public PeerClientInfo(int virtualIp, String name, boolean online, boolean clientSecret) { + this.virtualIp = virtualIp; + this.name = name; + this.online = online; + this.clientSecret = clientSecret; + } + + public int getVirtualIp() { + return virtualIp; + } + + public String getName() { + return name; + } + + public boolean isOnline() { + return online; + } + + public boolean isClientSecret() { + return clientSecret; + } + + @Override + public String toString() { + return "PeerDeviceInfo{" + + "virtualIp=" + IpUtils.intToIpAddress(virtualIp) + + ", name='" + name + '\'' + + ", online=" + online + + ", clientSecret=" + clientSecret + + '}'; + } +} diff --git a/app/src/main/java/top/wherewego/vnt/jni/param/RegisterInfo.java b/app/src/main/java/top/wherewego/vnt/jni/param/RegisterInfo.java new file mode 100644 index 0000000..3ff5cd0 --- /dev/null +++ b/app/src/main/java/top/wherewego/vnt/jni/param/RegisterInfo.java @@ -0,0 +1,50 @@ +package top.wherewego.vnt.jni.param; + +import top.wherewego.vnt.jni.IpUtils; + +/** + * 注册回调信息 + * + * @author https://github.com/lbl8603/vnt + */ +public class RegisterInfo { + /** + * 虚拟IP + */ + public final int virtualIp; + /** + * 掩码 + */ + public final int virtualNetmask; + /** + * 网关 + */ + public final int virtualGateway; + + public RegisterInfo(int virtualIp, int virtualNetmask, int virtualGateway) { + this.virtualIp = virtualIp; + this.virtualNetmask = virtualNetmask; + this.virtualGateway = virtualGateway; + } + + public int getVirtualIp() { + return virtualIp; + } + + public int getVirtualNetmask() { + return virtualNetmask; + } + + public int getVirtualGateway() { + return virtualGateway; + } + + @Override + public String toString() { + return "RegisterInfo{" + + "virtualIp='" + IpUtils.intToIpAddress(virtualIp) + '\'' + + ", virtualNetmask='" + IpUtils.intToIpAddress(virtualNetmask) + '\'' + + ", virtualGateway='" + IpUtils.intToIpAddress(virtualGateway) + '\'' + + '}'; + } +} diff --git a/app/src/main/res/layout/activity_add.xml b/app/src/main/res/layout/activity_add.xml index f81ce0c..633ae46 100644 --- a/app/src/main/res/layout/activity_add.xml +++ b/app/src/main/res/layout/activity_add.xml @@ -5,69 +5,103 @@ android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" - android:orientation="vertical" - android:fitsSystemWindows="true"> + android:fitsSystemWindows="true" + android:orientation="vertical"> + app:rightIcon="@mipmap/save" + app:rightIconHeight="30dp" + app:rightIconWidth="30dp" /> - + + + + - + android:hint="" + android:inputType="textVisiblePassword" + android:maxLength="@integer/sms_code_length" + android:singleLine="true" /> - + - + + + + + + + + + + + android:textStyle="bold" /> @@ -77,15 +111,44 @@ + + + + + + + + + @@ -96,91 +159,90 @@ style="@style/EditTextStyle" android:layout_width="match_parent" android:layout_height="wrap_content" - android:textColor="#aaaaaa" - android:hint="请输入device id" android:enabled="false" + android:hint="" android:inputType="textVisiblePassword" - android:textSize="14dp" android:maxLength="@integer/sms_code_length" - android:singleLine="true" /> + android:singleLine="true" + android:textColor="#aaaaaa" + android:textSize="14dp" /> - + - + - + - + - + - + + + + + + android:textStyle="bold" /> + android:singleLine="true" + android:text="nat1.wherewego.top:29872" /> - + + android:hint="" + android:inputType="number" + android:singleLine="true" + android:maxLength="4" + android:text="1410" /> + + \ No newline at end of file diff --git a/app/src/main/res/layout/status_config_info_item.xml b/app/src/main/res/layout/status_config_info_item.xml index ebf066f..7883ac9 100644 --- a/app/src/main/res/layout/status_config_info_item.xml +++ b/app/src/main/res/layout/status_config_info_item.xml @@ -18,17 +18,17 @@ @@ -37,7 +37,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="10dp" - android:text="Token:" + android:text="VpnName:" android:textSize="@dimen/sp_16" android:textStyle="bold" app:layout_constraintStart_toStartOf="parent" diff --git a/app/src/main/res/mipmap-hdpi/edit.png b/app/src/main/res/mipmap-hdpi/edit.png new file mode 100644 index 0000000..4e91825 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/edit.png differ diff --git a/app/src/main/res/mipmap-hdpi/save.png b/app/src/main/res/mipmap-hdpi/save.png new file mode 100644 index 0000000..4c715b2 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/save.png differ