diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4000d81..c6f3837 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,6 +4,7 @@ + diff --git a/app/src/main/java/org/itxtech/daedalus/Daedalus.java b/app/src/main/java/org/itxtech/daedalus/Daedalus.java index 97f3e5a..066a836 100644 --- a/app/src/main/java/org/itxtech/daedalus/Daedalus.java +++ b/app/src/main/java/org/itxtech/daedalus/Daedalus.java @@ -18,10 +18,7 @@ import com.google.gson.JsonParseException; import com.google.gson.stream.JsonReader; import org.itxtech.daedalus.activity.MainActivity; import org.itxtech.daedalus.service.DaedalusVpnService; -import org.itxtech.daedalus.util.Configurations; -import org.itxtech.daedalus.util.Logger; -import org.itxtech.daedalus.util.Rule; -import org.itxtech.daedalus.util.RuleResolver; +import org.itxtech.daedalus.util.*; import org.itxtech.daedalus.util.server.DNSServer; import org.itxtech.daedalus.util.server.DNSServerHelper; @@ -217,6 +214,17 @@ public class Daedalus extends Application { public static void activateService(Context context) { DaedalusVpnService.primaryServer = DNSServerHelper.getAddressById(DNSServerHelper.getPrimary()); DaedalusVpnService.secondaryServer = DNSServerHelper.getAddressById(DNSServerHelper.getSecondary()); + if (getPrefs().getBoolean("settings_use_system_dns", false)) { + String[] servers = DnsServersDetector.getServers(context); + if (servers != null) { + if (servers.length >= 2) { + DaedalusVpnService.primaryServer = servers[0]; + DaedalusVpnService.secondaryServer = servers[1]; + } else { + DaedalusVpnService.primaryServer = DaedalusVpnService.secondaryServer = servers[0]; + } + } + } if (getInstance().prefs.getBoolean("settings_foreground", false) && Build.VERSION.SDK_INT > Build.VERSION_CODES.O) { Logger.info("Starting foreground service"); diff --git a/app/src/main/java/org/itxtech/daedalus/fragment/GlobalConfigFragment.java b/app/src/main/java/org/itxtech/daedalus/fragment/GlobalConfigFragment.java index 6864fe0..53f917e 100644 --- a/app/src/main/java/org/itxtech/daedalus/fragment/GlobalConfigFragment.java +++ b/app/src/main/java/org/itxtech/daedalus/fragment/GlobalConfigFragment.java @@ -9,6 +9,8 @@ import org.itxtech.daedalus.activity.AppFilterActivity; import org.itxtech.daedalus.activity.MainActivity; import org.itxtech.daedalus.util.server.DNSServerHelper; +import java.util.ArrayList; + /** * Daedalus Project * @@ -31,23 +33,21 @@ public class GlobalConfigFragment extends PreferenceFragmentCompat { addPreferencesFromResource(R.xml.perf_settings); - ListPreference primaryServer = findPreference("primary_server"); - primaryServer.setEntries(DNSServerHelper.getNames(Daedalus.getInstance())); - primaryServer.setEntryValues(DNSServerHelper.getIds()); - primaryServer.setSummary(DNSServerHelper.getDescription(primaryServer.getValue(), Daedalus.getInstance())); - primaryServer.setOnPreferenceChangeListener((preference, newValue) -> { - preference.setSummary(DNSServerHelper.getDescription((String) newValue, Daedalus.getInstance())); - return true; - }); - - ListPreference secondaryServer = findPreference("secondary_server"); - secondaryServer.setEntries(DNSServerHelper.getNames(Daedalus.getInstance())); - secondaryServer.setEntryValues(DNSServerHelper.getIds()); - secondaryServer.setSummary(DNSServerHelper.getDescription(secondaryServer.getValue(), Daedalus.getInstance())); - secondaryServer.setOnPreferenceChangeListener((preference, newValue) -> { - preference.setSummary(DNSServerHelper.getDescription((String) newValue, Daedalus.getInstance())); - return true; - }); + boolean visible = !Daedalus.getPrefs().getBoolean("settings_use_system_dns", false); + for (String k : new ArrayList() {{ + add("primary_server"); + add("secondary_server"); + }}) { + ListPreference listPref = findPreference(k); + listPref.setVisible(visible); + listPref.setEntries(DNSServerHelper.getNames(Daedalus.getInstance())); + listPref.setEntryValues(DNSServerHelper.getIds()); + listPref.setSummary(DNSServerHelper.getDescription(listPref.getValue(), Daedalus.getInstance())); + listPref.setOnPreferenceChangeListener((preference, newValue) -> { + preference.setSummary(DNSServerHelper.getDescription((String) newValue, Daedalus.getInstance())); + return true; + }); + } EditTextPreference testDNSServers = findPreference("dns_test_servers"); testDNSServers.setSummary(testDNSServers.getText()); @@ -110,6 +110,13 @@ public class GlobalConfigFragment extends PreferenceFragmentCompat { updateOptions(advanced.isChecked(), "settings_advanced"); updateOptions(appFilter.isChecked(), "settings_app_filter"); + + findPreference("settings_use_system_dns").setOnPreferenceChangeListener((preference, newValue) -> { + boolean vis = !(boolean) newValue; + findPreference("primary_server").setVisible(vis); + findPreference("secondary_server").setVisible(vis); + return true; + }); } private void updateOptions(boolean checked, String pref) { diff --git a/app/src/main/java/org/itxtech/daedalus/service/DaedalusVpnService.java b/app/src/main/java/org/itxtech/daedalus/service/DaedalusVpnService.java index ccae93f..7d3e54e 100644 --- a/app/src/main/java/org/itxtech/daedalus/service/DaedalusVpnService.java +++ b/app/src/main/java/org/itxtech/daedalus/service/DaedalusVpnService.java @@ -346,7 +346,7 @@ public class DaedalusVpnService extends VpnService implements Runnable { if (time - lastUpdate >= 1000) { lastUpdate = time; if (notification != null) { - notification.setContentTitle(getResources().getString(R.string.notice_queries) + " " + String.valueOf(provider.getDnsQueryTimes())); + notification.setContentTitle(getResources().getString(R.string.notice_queries) + " " + provider.getDnsQueryTimes()); NotificationManager manager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE); manager.notify(NOTIFICATION_ACTIVATED, notification.build()); } @@ -358,11 +358,8 @@ public class DaedalusVpnService extends VpnService implements Runnable { public VpnNetworkException(String s) { super(s); } - public VpnNetworkException(String s, Throwable t) { super(s, t); } - } - } diff --git a/app/src/main/java/org/itxtech/daedalus/util/DnsServersDetector.java b/app/src/main/java/org/itxtech/daedalus/util/DnsServersDetector.java new file mode 100644 index 0000000..cace002 --- /dev/null +++ b/app/src/main/java/org/itxtech/daedalus/util/DnsServersDetector.java @@ -0,0 +1,166 @@ +package org.itxtech.daedalus.util; + +import android.content.Context; +import android.net.*; +import android.os.Build; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.LineNumberReader; +import java.lang.reflect.Method; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Daedalus Project + * + * @author iTX Technologies + * @link https://itxtech.org + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + */ +public class DnsServersDetector { + //https://stackoverflow.com/a/48973823 + private static final String METHOD_EXEC_PROP_DELIM = "]: ["; + + public static String[] getServers(Context context) { + String[] result; + result = getServersMethodSystemProperties(); + if (result != null && result.length > 0) { + return result; + } + result = getServersMethodConnectivityManager(context); + if (result != null && result.length > 0) { + return result; + } + result = getServersMethodExec(); + if (result != null && result.length > 0) { + return result; + } + return null; + } + + private static String[] getServersMethodConnectivityManager(Context context) { + ArrayList priorityServersArrayList = new ArrayList<>(); + ArrayList serversArrayList = new ArrayList<>(); + ConnectivityManager connectivityManager = + (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + if (connectivityManager != null) { + for (Network network : connectivityManager.getAllNetworks()) { + NetworkInfo networkInfo = connectivityManager.getNetworkInfo(network); + if (networkInfo.isConnected()) { + LinkProperties linkProperties = connectivityManager.getLinkProperties(network); + List dnsServersList = linkProperties.getDnsServers(); + if (linkPropertiesHasDefaultRoute(linkProperties)) { + for (InetAddress element : dnsServersList) { + String dnsHost = element.getHostAddress(); + priorityServersArrayList.add(dnsHost); + } + } else { + for (InetAddress element : dnsServersList) { + String dnsHost = element.getHostAddress(); + serversArrayList.add(dnsHost); + } + } + } + } + } + if (priorityServersArrayList.isEmpty()) { + priorityServersArrayList.addAll(serversArrayList); + } + if (priorityServersArrayList.size() > 0) { + return priorityServersArrayList.toArray(new String[0]); + } + return null; + } + + private static String[] getServersMethodSystemProperties() { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { + final String re1 = "^\\d+(\\.\\d+){3}$"; + final String re2 = "^[0-9a-f]+(:[0-9a-f]*)+:[0-9a-f]+$"; + ArrayList serversArrayList = new ArrayList<>(); + try { + Class SystemProperties = Class.forName("android.os.SystemProperties"); + Method method = SystemProperties.getMethod("get", new Class[]{String.class}); + final String[] netdns = new String[]{"net.dns1", "net.dns2", "net.dns3", "net.dns4"}; + for (int i = 0; i < netdns.length; i++) { + Object[] args = new Object[]{netdns[i]}; + String v = (String) method.invoke(null, args); + if (v != null && (v.matches(re1) || v.matches(re2)) && !serversArrayList.contains(v)) { + serversArrayList.add(v); + } + } + if (serversArrayList.size() > 0) { + return serversArrayList.toArray(new String[0]); + } + + } catch (Exception ex) { + Logger.logException(ex); + } + } + return null; + } + + private static String[] getServersMethodExec() { + try { + Process process = Runtime.getRuntime().exec("getprop"); + InputStream inputStream = process.getInputStream(); + LineNumberReader lineNumberReader = new LineNumberReader(new InputStreamReader(inputStream)); + Set serversSet = methodExecParseProps(lineNumberReader); + if (serversSet.size() > 0) { + return serversSet.toArray(new String[0]); + } + } catch (Exception ex) { + Logger.logException(ex); + } + return null; + } + + private static Set methodExecParseProps(BufferedReader lineNumberReader) throws Exception { + String line; + Set serversSet = new HashSet(10); + while ((line = lineNumberReader.readLine()) != null) { + int split = line.indexOf(METHOD_EXEC_PROP_DELIM); + if (split == -1) { + continue; + } + String property = line.substring(1, split); + int valueStart = split + METHOD_EXEC_PROP_DELIM.length(); + int valueEnd = line.length() - 1; + if (valueEnd < valueStart) { + continue; + } + String value = line.substring(valueStart, valueEnd); + if (value.isEmpty()) { + continue; + } + if (property.endsWith(".dns") || property.endsWith(".dns1") || + property.endsWith(".dns2") || property.endsWith(".dns3") || + property.endsWith(".dns4")) { + InetAddress ip = InetAddress.getByName(value); + if (ip == null) continue; + value = ip.getHostAddress(); + if (value == null) continue; + if (value.length() == 0) continue; + serversSet.add(value); + } + } + return serversSet; + } + + private static boolean linkPropertiesHasDefaultRoute(LinkProperties linkProperties) { + for (RouteInfo route : linkProperties.getRoutes()) { + if (route.isDefaultRoute()) { + return true; + } + } + return false; + } +} diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 884fb2d..3a7b0b9 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -67,6 +67,7 @@ 使用暗主题 DNS 查询方式 运行前台服务 + 使用系統DNS作為上游DNS 规则名称 规则类型 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d85f09d..84be857 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -66,6 +66,7 @@ Use Dark Theme DNS Query Method Run service in Foreground + Use System DNS as upstream DNS TCP UDP diff --git a/app/src/main/res/xml/perf_settings.xml b/app/src/main/res/xml/perf_settings.xml index cb4ed66..10320a6 100644 --- a/app/src/main/res/xml/perf_settings.xml +++ b/app/src/main/res/xml/perf_settings.xml @@ -6,12 +6,15 @@ android:key="settingsServer" android:title="@string/settings_server"> + -