diff --git a/app/build.gradle b/app/build.gradle index 105fc3f..68baabd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,6 +9,7 @@ android { ndk { abiFilters 'arm64-v8a', 'x86_64' } + versionName "1.2.3" } buildTypes { diff --git a/app/libs/arm64-v8a/libvnt_jni.so b/app/libs/arm64-v8a/libvnt_jni.so index 01effba..77756e1 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 e6a20d5..1f9e7ed 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 f5b71db..4b99d87 100644 --- a/app/src/main/java/top/wherewego/vnt/AddActivity.java +++ b/app/src/main/java/top/wherewego/vnt/AddActivity.java @@ -12,6 +12,7 @@ import top.wherewego.vnt.app.AppActivity; import top.wherewego.vnt.app.AppApplication; +import top.wherewego.vnt.util.IpRouteUtils; import top.wherewego.vnt.util.SPUtils; import top.wherewego.vnt.jni.ConfigurationInfoBean; @@ -23,6 +24,8 @@ public class AddActivity extends AppActivity { private EditText mPassword; private EditText mServer; private EditText mStun; + private EditText mInIps; + private EditText mOutIps; private Spinner mCipherModel; private Spinner mConnectType; private Spinner mFinger; @@ -60,6 +63,8 @@ public void onRightClick(TitleBar titleBar) { mPassword = findViewById(R.id.et_add_password_value); mServer = findViewById(R.id.et_add_server_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); @@ -91,14 +96,38 @@ private void save() { Toast.makeText(this, "stun不能为空", Toast.LENGTH_SHORT).show(); return; } + 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 inIps = mInIps.getText().toString().trim(); + if (inIps.isEmpty()) { + inIps = null; + } + String outIps = mOutIps.getText().toString().trim(); + if (outIps.isEmpty()) { + outIps = null; + } ConfigurationInfoBean configurationInfoBean = new ConfigurationInfoBean( - mToken.getText().toString().trim(), mName.getText().toString().trim(), mDeviceId.getText().toString().trim(), - mPassword.getText().toString().trim(), mServer.getText().toString().trim(), mStun.getText().toString().trim(), - cipherModel, "TCP".equalsIgnoreCase(connectType),"OPEN".equalsIgnoreCase(finger) + token, name, deviceId, password, server, stun, + cipherModel, "TCP".equalsIgnoreCase(connectType), "OPEN".equalsIgnoreCase(finger), inIps, outIps ); + 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; + } String keyset = SPUtils.getString(getApplicationContext(), "keyset", "0"); if (keyset.equals("0")) { @@ -111,4 +140,32 @@ private void save() { finish(); } + String check(ConfigurationInfoBean configurationInfoBean) { + String[] parts = configurationInfoBean.getServer().split(":"); + + if (parts.length != 2) { + return "服务器地址错误"; + } + int port = 0; + try { + port = Integer.parseInt(parts[1]); + } catch (Exception ignored) { + } + if (port <= 0 || port >= 65536) { + return "服务端口错误"; + } + String err; + err = IpRouteUtils.checkInIps(configurationInfoBean.getInIps()); + if (err != null) { + return "inIps错误:" + err; + + } + err = IpRouteUtils.checkOutIps(configurationInfoBean.getOutIps()); + if (err != null) { + return "outIps错误:" + err; + + } + return null; + } + } \ No newline at end of file diff --git a/app/src/main/java/top/wherewego/vnt/ConnectActivity.java b/app/src/main/java/top/wherewego/vnt/ConnectActivity.java index deea25c..3121231 100644 --- a/app/src/main/java/top/wherewego/vnt/ConnectActivity.java +++ b/app/src/main/java/top/wherewego/vnt/ConnectActivity.java @@ -87,10 +87,7 @@ private void startMyVpnService() { String name = selectConfigurationInfoBean.getName().trim(); String server = selectConfigurationInfoBean.getServer().trim(); String stun = selectConfigurationInfoBean.getStun().trim(); - String password = selectConfigurationInfoBean.getPassword().trim(); String cipherModel = selectConfigurationInfoBean.getCipherModel().trim(); - boolean tcp = selectConfigurationInfoBean.isTcp(); - boolean finger = selectConfigurationInfoBean.isFinger(); if (token.isEmpty()) { Toast.makeText(this, "Token不能为空", Toast.LENGTH_SHORT).show(); return; @@ -131,15 +128,8 @@ private void startMyVpnService() { } Intent serviceIntent = new Intent(this, MyVpnService.class); serviceIntent.setAction("start"); - serviceIntent.putExtra("token", token); - serviceIntent.putExtra("deviceId", deviceId); - serviceIntent.putExtra("name", name); - serviceIntent.putExtra("server", server); - serviceIntent.putExtra("stunServer", stun); - serviceIntent.putExtra("password",password); - serviceIntent.putExtra("cipherModel",cipherModel); - serviceIntent.putExtra("tcp",tcp); - serviceIntent.putExtra("finger",finger); + serviceIntent.putExtra("config",selectConfigurationInfoBean); + startService(serviceIntent); } diff --git a/app/src/main/java/top/wherewego/vnt/MyVpnService.java b/app/src/main/java/top/wherewego/vnt/MyVpnService.java index 27291d9..6a388ae 100644 --- a/app/src/main/java/top/wherewego/vnt/MyVpnService.java +++ b/app/src/main/java/top/wherewego/vnt/MyVpnService.java @@ -15,8 +15,10 @@ import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.List; +import java.util.Objects; 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; @@ -26,6 +28,7 @@ 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.util.IpRouteUtils; public class MyVpnService extends VpnService implements Runnable { private static MyVpnService myVpnService; @@ -67,16 +70,20 @@ public synchronized int onStartCommand(Intent intent, int flags, int startId) { switch (intent.getAction()) { case "start": { isRun = true; - String token = intent.getStringExtra("token"); - String deviceId = intent.getStringExtra("deviceId"); - String name = intent.getStringExtra("name"); - String password = intent.getStringExtra("password"); - String server = intent.getStringExtra("server"); - String stunServer = intent.getStringExtra("stunServer"); - String cipherModel = intent.getStringExtra("cipherModel"); - boolean tcp = intent.getBooleanExtra("tcp", false); - boolean finger = intent.getBooleanExtra("finger", false); - config = new Config(token, name, deviceId, server, stunServer, password.isEmpty() ? null : password, cipherModel, tcp,finger); + 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(); + config = new Config(token, name, deviceId, server, stunServer, password.isEmpty() ? null : password, + cipherModel, tcp, finger,inIps,outIps); if (mThread == null) { mThread = new Thread(this, "VntVPN"); mThread.start(); @@ -103,7 +110,7 @@ public void run() { run0(); } catch (Throwable e) { Handler handler = new Handler(Looper.getMainLooper()); - handler.post(() -> Toast.makeText(getApplicationContext(), "启动失败", Toast.LENGTH_LONG).show()); + handler.post(() -> Toast.makeText(getApplicationContext(), "启动失败:"+e.getMessage(), Toast.LENGTH_LONG).show()); } Handler handler = new Handler(Looper.getMainLooper()); handler.post(() -> { @@ -183,12 +190,16 @@ private void run0() { 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(1420) + .setMtu(1410) .addAddress(ip, prefixLength) -// .addDnsServer("8.8.8.8") + .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(); 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 7063fa0..6699da7 100644 --- a/app/src/main/java/top/wherewego/vnt/jni/Config.java +++ b/app/src/main/java/top/wherewego/vnt/jni/Config.java @@ -10,9 +10,13 @@ public class Config { private String cipherModel; private boolean tcp; private boolean finger; + private String inIps; + private String outIps; - public Config(String token, String name, String deviceId, String server, String stunServer, String password, String cipherModel, boolean tcp,boolean finger) { + public Config(String token, String name, String deviceId, String server, + String stunServer, String password, String cipherModel, boolean tcp,boolean finger, + String inIps,String outIps) { this.token = token; this.name = name; this.deviceId = deviceId; @@ -22,6 +26,8 @@ public Config(String token, String name, String deviceId, String server, String this.cipherModel = cipherModel; this.tcp = tcp; this.finger = finger; + this.inIps = inIps; + this.outIps = outIps; } public String getToken() { @@ -95,4 +101,20 @@ public boolean isFinger() { 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; + } } diff --git a/app/src/main/java/top/wherewego/vnt/jni/ConfigurationInfoBean.java b/app/src/main/java/top/wherewego/vnt/jni/ConfigurationInfoBean.java index ead5879..ec1c3a2 100644 --- a/app/src/main/java/top/wherewego/vnt/jni/ConfigurationInfoBean.java +++ b/app/src/main/java/top/wherewego/vnt/jni/ConfigurationInfoBean.java @@ -13,8 +13,12 @@ public class ConfigurationInfoBean implements Serializable { private String cipherModel; private boolean tcp; private boolean finger; + private String inIps; + private String outIps; - public ConfigurationInfoBean(String token, String name, String deviceId, String password, String server, String stun, String cipherModel, boolean tcp, boolean finger) { + public ConfigurationInfoBean(String token, String name, String deviceId, String password, + String server, String stun, String cipherModel, boolean tcp, boolean finger, + String inIps, String outIps) { this.key = String.valueOf(System.currentTimeMillis()); this.token = token; this.name = name; @@ -25,6 +29,8 @@ public ConfigurationInfoBean(String token, String name, String deviceId, String this.cipherModel = cipherModel; this.tcp = tcp; this.finger = finger; + this.inIps = inIps; + this.outIps = outIps; } public String getKey() { @@ -102,4 +108,20 @@ public boolean isFinger() { 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; + } } diff --git a/app/src/main/java/top/wherewego/vnt/util/IpRouteUtils.java b/app/src/main/java/top/wherewego/vnt/util/IpRouteUtils.java new file mode 100644 index 0000000..38af958 --- /dev/null +++ b/app/src/main/java/top/wherewego/vnt/util/IpRouteUtils.java @@ -0,0 +1,94 @@ +package top.wherewego.vnt.util; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; + +public class IpRouteUtils { + public static class RouteItem { + public InetAddress address; + public int prefixLength; + + public RouteItem(InetAddress address, int prefixLength) { + this.address = address; + this.prefixLength = prefixLength; + } + } + + public static List inIp(String inIps) { + if (inIps == null || inIps.isEmpty()) { + return new ArrayList<>(); + } + List list = new ArrayList<>(); + for (String s : inIps.split("\n")) { + String s1 = s.split(",")[0]; + String[] split = s1.split("/"); + InetAddress address; + try { + address = InetAddress.getByName(split[0]); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + int prefixLengt = Integer.parseInt(split[1]); + list.add(new RouteItem(address, prefixLengt)); + } + return list; + } + + public static String checkInIps(String inIps) { + if (inIps == null || inIps.isEmpty()) { + return null; + } + for (String s : inIps.split("\n")) { + String[] split = s.split(","); + if (split.length != 2) { + return "not ipv4/mask,ipv4"; + } + try { + InetAddress.getByName(split[1]); + } catch (Exception e) { + return "not ipv4"; + } + String s1 = s.split(",")[0]; + String[] split1 = s1.split("/"); + try { + InetAddress.getByName(split1[0]); + } catch (Exception e) { + return "not ipv4"; + } + try { + int mask = Integer.parseInt(split1[1]); + if (mask >= 32 || mask < 0) { + return "mask >= 32 || mask < 0"; + } + } catch (Exception e) { + return "no netmask"; + } + } + return null; + } + + public static String checkOutIps(String outIps) { + if (outIps == null || outIps.isEmpty()) { + return null; + } + for (String s : outIps.split("\n")) { + String[] split1 = s.split("/"); + try { + InetAddress.getByName(split1[0]); + } catch (Exception e) { + return "not ipv4"; + } + try { + int mask = Integer.parseInt(split1[1]); + if (mask >= 32 || mask < 0) { + return "mask >= 32 || mask < 0"; + } + } catch (Exception e) { + return "no netmask"; + } + } + return null; + } +} diff --git a/app/src/main/res/layout/activity_add.xml b/app/src/main/res/layout/activity_add.xml index dfc4004..f2a3519 100644 --- a/app/src/main/res/layout/activity_add.xml +++ b/app/src/main/res/layout/activity_add.xml @@ -216,6 +216,60 @@ android:entries="@array/finger" android:singleLine="true" /> + + + + + + + + + + + +