DNS: add Use System DNS as upstream DNS. close #113

This commit is contained in:
PeratX 2019-10-22 18:11:08 +08:00
parent 77c7ce2135
commit 37fa796303
8 changed files with 210 additions and 26 deletions

View File

@ -4,6 +4,7 @@
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR"/> <uses-permission android:name="android.permission.EXPAND_STATUS_BAR"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18"/> android:maxSdkVersion="18"/>

View File

@ -18,10 +18,7 @@ import com.google.gson.JsonParseException;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
import org.itxtech.daedalus.activity.MainActivity; import org.itxtech.daedalus.activity.MainActivity;
import org.itxtech.daedalus.service.DaedalusVpnService; import org.itxtech.daedalus.service.DaedalusVpnService;
import org.itxtech.daedalus.util.Configurations; import org.itxtech.daedalus.util.*;
import org.itxtech.daedalus.util.Logger;
import org.itxtech.daedalus.util.Rule;
import org.itxtech.daedalus.util.RuleResolver;
import org.itxtech.daedalus.util.server.DNSServer; import org.itxtech.daedalus.util.server.DNSServer;
import org.itxtech.daedalus.util.server.DNSServerHelper; import org.itxtech.daedalus.util.server.DNSServerHelper;
@ -217,6 +214,17 @@ public class Daedalus extends Application {
public static void activateService(Context context) { public static void activateService(Context context) {
DaedalusVpnService.primaryServer = DNSServerHelper.getAddressById(DNSServerHelper.getPrimary()); DaedalusVpnService.primaryServer = DNSServerHelper.getAddressById(DNSServerHelper.getPrimary());
DaedalusVpnService.secondaryServer = DNSServerHelper.getAddressById(DNSServerHelper.getSecondary()); 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) if (getInstance().prefs.getBoolean("settings_foreground", false)
&& Build.VERSION.SDK_INT > Build.VERSION_CODES.O) { && Build.VERSION.SDK_INT > Build.VERSION_CODES.O) {
Logger.info("Starting foreground service"); Logger.info("Starting foreground service");

View File

@ -9,6 +9,8 @@ import org.itxtech.daedalus.activity.AppFilterActivity;
import org.itxtech.daedalus.activity.MainActivity; import org.itxtech.daedalus.activity.MainActivity;
import org.itxtech.daedalus.util.server.DNSServerHelper; import org.itxtech.daedalus.util.server.DNSServerHelper;
import java.util.ArrayList;
/** /**
* Daedalus Project * Daedalus Project
* *
@ -31,23 +33,21 @@ public class GlobalConfigFragment extends PreferenceFragmentCompat {
addPreferencesFromResource(R.xml.perf_settings); addPreferencesFromResource(R.xml.perf_settings);
ListPreference primaryServer = findPreference("primary_server"); boolean visible = !Daedalus.getPrefs().getBoolean("settings_use_system_dns", false);
primaryServer.setEntries(DNSServerHelper.getNames(Daedalus.getInstance())); for (String k : new ArrayList<String>() {{
primaryServer.setEntryValues(DNSServerHelper.getIds()); add("primary_server");
primaryServer.setSummary(DNSServerHelper.getDescription(primaryServer.getValue(), Daedalus.getInstance())); add("secondary_server");
primaryServer.setOnPreferenceChangeListener((preference, newValue) -> { }}) {
preference.setSummary(DNSServerHelper.getDescription((String) newValue, Daedalus.getInstance())); ListPreference listPref = findPreference(k);
return true; listPref.setVisible(visible);
}); listPref.setEntries(DNSServerHelper.getNames(Daedalus.getInstance()));
listPref.setEntryValues(DNSServerHelper.getIds());
ListPreference secondaryServer = findPreference("secondary_server"); listPref.setSummary(DNSServerHelper.getDescription(listPref.getValue(), Daedalus.getInstance()));
secondaryServer.setEntries(DNSServerHelper.getNames(Daedalus.getInstance())); listPref.setOnPreferenceChangeListener((preference, newValue) -> {
secondaryServer.setEntryValues(DNSServerHelper.getIds()); preference.setSummary(DNSServerHelper.getDescription((String) newValue, Daedalus.getInstance()));
secondaryServer.setSummary(DNSServerHelper.getDescription(secondaryServer.getValue(), Daedalus.getInstance())); return true;
secondaryServer.setOnPreferenceChangeListener((preference, newValue) -> { });
preference.setSummary(DNSServerHelper.getDescription((String) newValue, Daedalus.getInstance())); }
return true;
});
EditTextPreference testDNSServers = findPreference("dns_test_servers"); EditTextPreference testDNSServers = findPreference("dns_test_servers");
testDNSServers.setSummary(testDNSServers.getText()); testDNSServers.setSummary(testDNSServers.getText());
@ -110,6 +110,13 @@ public class GlobalConfigFragment extends PreferenceFragmentCompat {
updateOptions(advanced.isChecked(), "settings_advanced"); updateOptions(advanced.isChecked(), "settings_advanced");
updateOptions(appFilter.isChecked(), "settings_app_filter"); 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) { private void updateOptions(boolean checked, String pref) {

View File

@ -346,7 +346,7 @@ public class DaedalusVpnService extends VpnService implements Runnable {
if (time - lastUpdate >= 1000) { if (time - lastUpdate >= 1000) {
lastUpdate = time; lastUpdate = time;
if (notification != null) { 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); NotificationManager manager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(NOTIFICATION_ACTIVATED, notification.build()); manager.notify(NOTIFICATION_ACTIVATED, notification.build());
} }
@ -358,11 +358,8 @@ public class DaedalusVpnService extends VpnService implements Runnable {
public VpnNetworkException(String s) { public VpnNetworkException(String s) {
super(s); super(s);
} }
public VpnNetworkException(String s, Throwable t) { public VpnNetworkException(String s, Throwable t) {
super(s, t); super(s, t);
} }
} }
} }

View File

@ -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
* <p>
* 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<String> priorityServersArrayList = new ArrayList<>();
ArrayList<String> 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<InetAddress> 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<String> 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<String> serversSet = methodExecParseProps(lineNumberReader);
if (serversSet.size() > 0) {
return serversSet.toArray(new String[0]);
}
} catch (Exception ex) {
Logger.logException(ex);
}
return null;
}
private static Set<String> methodExecParseProps(BufferedReader lineNumberReader) throws Exception {
String line;
Set<String> serversSet = new HashSet<String>(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;
}
}

View File

@ -67,6 +67,7 @@
<string name="settings_dark_theme">使用暗主题</string> <string name="settings_dark_theme">使用暗主题</string>
<string name="settings_dns_query_method">DNS 查询方式</string> <string name="settings_dns_query_method">DNS 查询方式</string>
<string name="settings_foreground">运行前台服务</string> <string name="settings_foreground">运行前台服务</string>
<string name="settings_use_system_dns">使用系統DNS作為上游DNS</string>
<string name="settings_rule_name">规则名称</string> <string name="settings_rule_name">规则名称</string>
<string name="settings_rule_type">规则类型</string> <string name="settings_rule_type">规则类型</string>

View File

@ -66,6 +66,7 @@
<string name="settings_dark_theme">Use Dark Theme</string> <string name="settings_dark_theme">Use Dark Theme</string>
<string name="settings_dns_query_method">DNS Query Method</string> <string name="settings_dns_query_method">DNS Query Method</string>
<string name="settings_foreground">Run service in Foreground</string> <string name="settings_foreground">Run service in Foreground</string>
<string name="settings_use_system_dns">Use System DNS as upstream DNS</string>
<string name="settings_dns_tcp">TCP</string> <string name="settings_dns_tcp">TCP</string>
<string name="settings_dns_udp">UDP</string> <string name="settings_dns_udp">UDP</string>

View File

@ -6,12 +6,15 @@
android:key="settingsServer" android:key="settingsServer"
android:title="@string/settings_server"> android:title="@string/settings_server">
<SwitchPreference
android:key="settings_use_system_dns"
android:title="@string/settings_use_system_dns"
android:defaultValue="false"/>
<ListPreference <ListPreference
android:key="primary_server" android:key="primary_server"
android:title="@string/primary_server" android:title="@string/primary_server"
android:defaultValue="0"> android:defaultValue="0">
</ListPreference> </ListPreference>
<ListPreference <ListPreference
android:key="secondary_server" android:key="secondary_server"
android:title="@string/secondary_server" android:title="@string/secondary_server"