() {{
+ 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">
+
-
Date: Wed, 23 Oct 2019 12:34:17 +0800
Subject: [PATCH 06/14] Home: remove notice_main
---
app/build.gradle | 3 +--
app/src/main/java/org/itxtech/daedalus/Daedalus.java | 3 +--
.../java/org/itxtech/daedalus/activity/MainActivity.java | 3 +--
.../org/itxtech/daedalus/fragment/DNSTestFragment.java | 2 +-
.../java/org/itxtech/daedalus/fragment/HomeFragment.java | 8 --------
.../java/org/itxtech/daedalus/fragment/LogFragment.java | 2 +-
.../java/org/itxtech/daedalus/provider/TcpProvider.java | 2 +-
.../java/org/itxtech/daedalus/util/RuleResolver.java | 4 ++--
.../java/org/itxtech/daedalus/util/server/DNSServer.java | 2 +-
app/src/main/res/layout/fragment_main.xml | 9 ---------
app/src/main/res/values-zh-rCN/strings.xml | 1 -
app/src/main/res/values-zh-rTW/strings.xml | 1 -
app/src/main/res/values/strings.xml | 1 -
13 files changed, 9 insertions(+), 32 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index 040344c..7f93c67 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -56,7 +56,7 @@ dependencies {
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.percentlayout:percentlayout:1.0.0'
implementation 'androidx.cardview:cardview:1.0.0'
- implementation 'com.google.android.material:material:1.1.0-beta01'
+ implementation 'com.google.android.material:material:1.2.0-alpha01'
implementation 'androidx.recyclerview:recyclerview:1.1.0-beta05'
implementation "androidx.preference:preference:1.1.0"
//DNS
@@ -65,7 +65,6 @@ dependencies {
implementation 'org.minidns:minidns-client:0.3.4'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.squareup.okhttp3:okhttp:4.2.0'
-
//Analytics
googleReleaseImplementation 'com.google.firebase:firebase-core:17.2.0'
googleReleaseImplementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
diff --git a/app/src/main/java/org/itxtech/daedalus/Daedalus.java b/app/src/main/java/org/itxtech/daedalus/Daedalus.java
index 066a836..8cc9453 100644
--- a/app/src/main/java/org/itxtech/daedalus/Daedalus.java
+++ b/app/src/main/java/org/itxtech/daedalus/Daedalus.java
@@ -175,7 +175,6 @@ public class Daedalus extends Application {
@Override
public void onTerminate() {
- Log.d("Daedalus", "onTerminate");
super.onTerminate();
instance = null;
@@ -242,7 +241,7 @@ public class Daedalus extends Application {
public static void updateShortcut(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
- Log.d("Daedalus", "Updating shortcut");
+ Logger.info("Updating shortcut");
boolean activate = DaedalusVpnService.isActivated();
String notice = activate ? context.getString(R.string.button_text_deactivate) : context.getString(R.string.button_text_activate);
ShortcutInfo info = new ShortcutInfo.Builder(context, Daedalus.SHORTCUT_ID_ACTIVATE)
diff --git a/app/src/main/java/org/itxtech/daedalus/activity/MainActivity.java b/app/src/main/java/org/itxtech/daedalus/activity/MainActivity.java
index f8b22c3..78f1ef8 100644
--- a/app/src/main/java/org/itxtech/daedalus/activity/MainActivity.java
+++ b/app/src/main/java/org/itxtech/daedalus/activity/MainActivity.java
@@ -182,7 +182,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
private void updateUserInterface(Intent intent) {
int launchAction = intent.getIntExtra(LAUNCH_ACTION, LAUNCH_ACTION_NONE);
- Log.d(TAG, "Updating user interface with Launch Action " + String.valueOf(launchAction));
+ Log.d(TAG, "Updating user interface with Launch Action " + launchAction);
if (launchAction == LAUNCH_ACTION_ACTIVATE) {
this.activateService();
} else if (launchAction == LAUNCH_ACTION_DEACTIVATE) {
@@ -240,7 +240,6 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
- // Handle navigation view item clicks here.
int id = item.getItemId();
switch (id) {
diff --git a/app/src/main/java/org/itxtech/daedalus/fragment/DNSTestFragment.java b/app/src/main/java/org/itxtech/daedalus/fragment/DNSTestFragment.java
index 79157d9..3d44e6f 100644
--- a/app/src/main/java/org/itxtech/daedalus/fragment/DNSTestFragment.java
+++ b/app/src/main/java/org/itxtech/daedalus/fragment/DNSTestFragment.java
@@ -181,7 +181,7 @@ public class DNSTestFragment extends ToolbarFragment {
}
}
testText.append("\n").append(getString(R.string.test_time_used)).append(" ").
- append(String.valueOf(endTime - startTime)).append(" ms");
+ append(endTime - startTime).append(" ms");
succ = true;
}
} catch (SocketTimeoutException ignored) {
diff --git a/app/src/main/java/org/itxtech/daedalus/fragment/HomeFragment.java b/app/src/main/java/org/itxtech/daedalus/fragment/HomeFragment.java
index 91803a8..82702f3 100644
--- a/app/src/main/java/org/itxtech/daedalus/fragment/HomeFragment.java
+++ b/app/src/main/java/org/itxtech/daedalus/fragment/HomeFragment.java
@@ -49,14 +49,6 @@ public class HomeFragment extends ToolbarFragment {
updateUserInterface();
}
- @Override
- public void setUserVisibleHint(boolean isVisibleToUser) {
- super.setUserVisibleHint(isVisibleToUser);
- if (isVisibleToUser) {
- updateUserInterface();
- }
- }
-
private void updateUserInterface() {
Log.d("DMainFragment", "updateInterface");
Button but = getView().findViewById(R.id.button_activate);
diff --git a/app/src/main/java/org/itxtech/daedalus/fragment/LogFragment.java b/app/src/main/java/org/itxtech/daedalus/fragment/LogFragment.java
index dc8880d..0a418b0 100644
--- a/app/src/main/java/org/itxtech/daedalus/fragment/LogFragment.java
+++ b/app/src/main/java/org/itxtech/daedalus/fragment/LogFragment.java
@@ -44,7 +44,7 @@ public class LogFragment extends ToolbarFragment implements Toolbar.OnMenuItemCl
private void export() {
try {
- String file = Daedalus.logPath + String.valueOf(System.currentTimeMillis()) + ".log";
+ String file = Daedalus.logPath + System.currentTimeMillis() + ".log";
FileWriter fileWriter = new FileWriter(file);
fileWriter.write(Logger.getLog());
fileWriter.close();
diff --git a/app/src/main/java/org/itxtech/daedalus/provider/TcpProvider.java b/app/src/main/java/org/itxtech/daedalus/provider/TcpProvider.java
index 3768ea5..183efc9 100644
--- a/app/src/main/java/org/itxtech/daedalus/provider/TcpProvider.java
+++ b/app/src/main/java/org/itxtech/daedalus/provider/TcpProvider.java
@@ -161,7 +161,7 @@ public class TcpProvider extends UdpProvider {
try {
DataInputStream stream = new DataInputStream(dnsSocket.getInputStream());
int length = stream.readUnsignedShort();
- Log.d(TAG, "Reading length: " + String.valueOf(length));
+ Log.d(TAG, "Reading length: " + length);
byte[] data = new byte[length];
stream.read(data);
dnsSocket.close();
diff --git a/app/src/main/java/org/itxtech/daedalus/util/RuleResolver.java b/app/src/main/java/org/itxtech/daedalus/util/RuleResolver.java
index d52806f..d6638a7 100644
--- a/app/src/main/java/org/itxtech/daedalus/util/RuleResolver.java
+++ b/app/src/main/java/org/itxtech/daedalus/util/RuleResolver.java
@@ -129,7 +129,7 @@ public class RuleResolver implements Runnable {
dataIO.close();
stream.close();
- Logger.info("Loaded " + String.valueOf(count) + " rules");
+ Logger.info("Loaded " + count + " rules");
}
}
} else if (mode == MODE_DNSMASQ) {
@@ -162,7 +162,7 @@ public class RuleResolver implements Runnable {
dataIO.close();
stream.close();
- Logger.info("Loaded " + String.valueOf(count) + " rules");
+ Logger.info("Loaded " + count + " rules");
}
}
}
diff --git a/app/src/main/java/org/itxtech/daedalus/util/server/DNSServer.java b/app/src/main/java/org/itxtech/daedalus/util/server/DNSServer.java
index e6e8be9..865d07b 100644
--- a/app/src/main/java/org/itxtech/daedalus/util/server/DNSServer.java
+++ b/app/src/main/java/org/itxtech/daedalus/util/server/DNSServer.java
@@ -19,7 +19,7 @@ public class DNSServer extends AbstractDNSServer {
private static int totalId = 0;
private String id;
- private int description = 0;
+ private int description;
public DNSServer(String address, int description, int port) {
super(address, port);
diff --git a/app/src/main/res/layout/fragment_main.xml b/app/src/main/res/layout/fragment_main.xml
index 9ada810..30b23a1 100644
--- a/app/src/main/res/layout/fragment_main.xml
+++ b/app/src/main/res/layout/fragment_main.xml
@@ -33,15 +33,6 @@
android:textAppearance="@android:style/TextAppearance.DeviceDefault"
android:fontFamily="sans-serif"
android:layout_centerHorizontal="true" android:id="@+id/textView_app_name"/>
-
开关
- 世界很大,我要去看看。
已启用 iTXTech Daedalus。
正在测试指定的 DNS 服务器……
DNS 查询次数:
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index 965dbe9..ee77d87 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -3,7 +3,6 @@
Daedalus
开关
- 世界很大,我要去看看。
已啟動 iTXTech Daedalus。
正在測試指定的 DNS 伺服器……
DNS 查詢次數:
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 84be857..b4dfce2 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -2,7 +2,6 @@
Daedalus
Toggle
- See the world outside.
iTXTech Daedalus is activated.
Testing specified DNS server…
DNS query times:
From c95b87b5a807fa79d64d0db22dffbeab850ed4d2 Mon Sep 17 00:00:00 2001
From: PeratX <1215714524@qq.com>
Date: Wed, 23 Oct 2019 13:34:21 +0800
Subject: [PATCH 07/14] layout: update layouts with latest SDK
---
.../main/res/layout/activity_app_filter.xml | 3 +-
app/src/main/res/layout/card_appview.xml | 42 ++++++------
app/src/main/res/layout/card_rule.xml | 66 ++++++++-----------
app/src/main/res/layout/card_server.xml | 5 +-
.../main/res/layout/fragment_dns_servers.xml | 3 +-
app/src/main/res/layout/fragment_dns_test.xml | 7 +-
app/src/main/res/layout/fragment_main.xml | 7 +-
app/src/main/res/layout/fragment_rules.xml | 3 +-
8 files changed, 58 insertions(+), 78 deletions(-)
diff --git a/app/src/main/res/layout/activity_app_filter.xml b/app/src/main/res/layout/activity_app_filter.xml
index 0668267..a0e5c87 100644
--- a/app/src/main/res/layout/activity_app_filter.xml
+++ b/app/src/main/res/layout/activity_app_filter.xml
@@ -25,7 +25,6 @@
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
-
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/card_appview.xml b/app/src/main/res/layout/card_appview.xml
index a41bd15..97e14a3 100644
--- a/app/src/main/res/layout/card_appview.xml
+++ b/app/src/main/res/layout/card_appview.xml
@@ -1,32 +1,28 @@
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical">
+ android:id="@+id/app_icon"
+ android:layout_width="46dp"
+ android:layout_height="46dp"
+ android:paddingEnd="10dp"
+ android:paddingStart="14dp"/>
+ android:id="@+id/app_name"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1.0"/>
+ android:id="@+id/app_check"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:clickable="false"
+ android:paddingEnd="6dp"
+ android:paddingStart="2dp"/>
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/card_rule.xml b/app/src/main/res/layout/card_rule.xml
index d448b35..d90ecad 100644
--- a/app/src/main/res/layout/card_rule.xml
+++ b/app/src/main/res/layout/card_rule.xml
@@ -14,47 +14,39 @@
app:cardPreventCornerOverlap="true"
android:id="@+id/cardView_indicator">
-
-
+
-
-
-
-
-
-
+ android:padding="@dimen/margin_small"
+ android:id="@+id/textView_rule_name"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentStart="true"/>
+
+
+
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/card_server.xml b/app/src/main/res/layout/card_server.xml
index 1a350a2..6191267 100644
--- a/app/src/main/res/layout/card_server.xml
+++ b/app/src/main/res/layout/card_server.xml
@@ -5,6 +5,7 @@
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:clickable="true"
+ android:focusable="true"
android:foreground="?attr/selectableItemBackground"
app:cardCornerRadius="10dp"
app:cardPreventCornerOverlap="true"
@@ -23,7 +24,6 @@
android:id="@+id/textView_custom_dns_name"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_alignParentTop="true"
- android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"/>
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/fragment_dns_servers.xml b/app/src/main/res/layout/fragment_dns_servers.xml
index d012c3e..5021ef3 100644
--- a/app/src/main/res/layout/fragment_dns_servers.xml
+++ b/app/src/main/res/layout/fragment_dns_servers.xml
@@ -11,7 +11,6 @@
android:layout_height="match_parent"
android:scrollbars="horizontal"
android:layout_alignParentTop="true"
- android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"/>
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/fragment_dns_test.xml b/app/src/main/res/layout/fragment_dns_test.xml
index 66d3cb2..eb1e1f9 100644
--- a/app/src/main/res/layout/fragment_dns_test.xml
+++ b/app/src/main/res/layout/fragment_dns_test.xml
@@ -41,18 +41,15 @@
android:layout_alignParentStart="true"
android:layout_marginTop="10dp"
android:id="@+id/button_start_test"
- android:layout_alignParentEnd="true"
- android:layout_alignParentRight="true"
- android:layout_alignParentLeft="true"/>
+ android:layout_alignParentEnd="true"/>
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/fragment_main.xml b/app/src/main/res/layout/fragment_main.xml
index 30b23a1..2924b70 100644
--- a/app/src/main/res/layout/fragment_main.xml
+++ b/app/src/main/res/layout/fragment_main.xml
@@ -13,7 +13,6 @@
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="org.itxtech.daedalus.fragment.HomeFragment">
+ app:layout_marginTopPercent="15%"
+ android:layout_alignTop="@+id/textView_app_name" android:layout_centerHorizontal="true"/>
diff --git a/app/src/main/res/layout/fragment_rules.xml b/app/src/main/res/layout/fragment_rules.xml
index 05d0491..f10b62d 100644
--- a/app/src/main/res/layout/fragment_rules.xml
+++ b/app/src/main/res/layout/fragment_rules.xml
@@ -11,7 +11,6 @@
android:layout_height="match_parent"
android:scrollbars="horizontal"
android:layout_alignParentTop="true"
- android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"/>
-
\ No newline at end of file
+
From a2d92d49aa20d0c994b76be4ab8269e3a9a0f05b Mon Sep 17 00:00:00 2001
From: PeratX <1215714524@qq.com>
Date: Wed, 23 Oct 2019 14:33:42 +0800
Subject: [PATCH 08/14] Provider: use DnsServer directly, get rid of magics
---
.../java/org/itxtech/daedalus/Daedalus.java | 29 ++++----
.../daedalus/activity/ConfigActivity.java | 6 +-
.../daedalus/activity/MainActivity.java | 10 ++-
.../daedalus/fragment/AboutFragment.java | 5 +-
...ment.java => DnsServerConfigFragment.java} | 14 ++--
...sFragment.java => DnsServersFragment.java} | 14 ++--
...TestFragment.java => DnsTestFragment.java} | 28 ++++----
.../fragment/GlobalConfigFragment.java | 14 ++--
.../daedalus/fragment/HomeFragment.java | 1 -
.../daedalus/provider/HttpsProvider.java | 10 +--
.../daedalus/provider/ProviderPicker.java | 2 +-
.../daedalus/provider/TcpProvider.java | 6 +-
.../daedalus/provider/TlsProvider.java | 7 +-
.../daedalus/provider/UdpProvider.java | 26 +++----
.../AbstractDnsServer.java} | 15 +++-
.../CustomDnsServer.java} | 6 +-
.../DNSServer.java => server/DnsServer.java} | 12 ++--
.../DnsServerHelper.java} | 68 +++++++------------
.../daedalus/service/DaedalusVpnService.java | 39 +++++------
.../itxtech/daedalus/util/Configurations.java | 6 +-
app/src/main/res/values-zh-rCN/strings.xml | 2 +-
app/src/main/res/values-zh-rTW/strings.xml | 2 +-
app/src/main/res/values/strings.xml | 2 +-
app/src/main/res/xml/perf_settings.xml | 4 +-
24 files changed, 157 insertions(+), 171 deletions(-)
rename app/src/main/java/org/itxtech/daedalus/fragment/{DNSServerConfigFragment.java => DnsServerConfigFragment.java} (91%)
rename app/src/main/java/org/itxtech/daedalus/fragment/{DNSServersFragment.java => DnsServersFragment.java} (93%)
rename app/src/main/java/org/itxtech/daedalus/fragment/{DNSTestFragment.java => DnsTestFragment.java} (91%)
rename app/src/main/java/org/itxtech/daedalus/{util/server/AbstractDNSServer.java => server/AbstractDnsServer.java} (77%)
rename app/src/main/java/org/itxtech/daedalus/{util/server/CustomDNSServer.java => server/CustomDnsServer.java} (83%)
rename app/src/main/java/org/itxtech/daedalus/{util/server/DNSServer.java => server/DnsServer.java} (78%)
rename app/src/main/java/org/itxtech/daedalus/{util/server/DNSServerHelper.java => server/DnsServerHelper.java} (68%)
diff --git a/app/src/main/java/org/itxtech/daedalus/Daedalus.java b/app/src/main/java/org/itxtech/daedalus/Daedalus.java
index 8cc9453..4016e73 100644
--- a/app/src/main/java/org/itxtech/daedalus/Daedalus.java
+++ b/app/src/main/java/org/itxtech/daedalus/Daedalus.java
@@ -10,7 +10,6 @@ import android.graphics.drawable.Icon;
import android.net.Uri;
import android.net.VpnService;
import android.os.Build;
-import android.util.Log;
import androidx.preference.PreferenceManager;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@@ -19,8 +18,8 @@ import com.google.gson.stream.JsonReader;
import org.itxtech.daedalus.activity.MainActivity;
import org.itxtech.daedalus.service.DaedalusVpnService;
import org.itxtech.daedalus.util.*;
-import org.itxtech.daedalus.util.server.DNSServer;
-import org.itxtech.daedalus.util.server.DNSServerHelper;
+import org.itxtech.daedalus.server.DnsServer;
+import org.itxtech.daedalus.server.DnsServerHelper;
import java.io.File;
import java.util.ArrayList;
@@ -42,13 +41,13 @@ public class Daedalus extends Application {
private static final String SHORTCUT_ID_ACTIVATE = "shortcut_activate";
- public static final List DNS_SERVERS = new ArrayList() {{
- add(new DNSServer("101.101.101.101", R.string.server_twnic_primary));
- add(new DNSServer("101.102.103.104", R.string.server_twnic_secondary));
- add(new DNSServer("dns.rubyfish.cn/dns-query", R.string.server_rubyfish));
- add(new DNSServer("cloudflare-dns.com/dns-query", R.string.server_cloudflare));
- add(new DNSServer("dns.google/dns-query", R.string.server_google_ietf));
- add(new DNSServer("dns.google/resolve", R.string.server_google_json));
+ public static final List DNS_SERVERS = new ArrayList() {{
+ add(new DnsServer("101.101.101.101", R.string.server_twnic_primary));
+ add(new DnsServer("101.102.103.104", R.string.server_twnic_secondary));
+ add(new DnsServer("rubyfish.cn/dns-query", R.string.server_rubyfish));
+ add(new DnsServer("cloudflare-dns.com/dns-query", R.string.server_cloudflare));
+ add(new DnsServer("dns.google/dns-query", R.string.server_google_ietf));
+ add(new DnsServer("dns.google/resolve", R.string.server_google_json));
}};
public static final List RULES = new ArrayList() {{
@@ -211,16 +210,16 @@ public class Daedalus extends Application {
}
public static void activateService(Context context) {
- DaedalusVpnService.primaryServer = DNSServerHelper.getAddressById(DNSServerHelper.getPrimary());
- DaedalusVpnService.secondaryServer = DNSServerHelper.getAddressById(DNSServerHelper.getSecondary());
+ DaedalusVpnService.primaryServer = DnsServerHelper.getServerById(DnsServerHelper.getPrimary());
+ DaedalusVpnService.secondaryServer = DnsServerHelper.getServerById(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];
+ DaedalusVpnService.primaryServer = new DnsServer(servers[0], 0);
+ DaedalusVpnService.secondaryServer = new DnsServer(servers[1], 0);
} else {
- DaedalusVpnService.primaryServer = DaedalusVpnService.secondaryServer = servers[0];
+ DaedalusVpnService.primaryServer = DaedalusVpnService.secondaryServer = new DnsServer(servers[0]);
}
}
}
diff --git a/app/src/main/java/org/itxtech/daedalus/activity/ConfigActivity.java b/app/src/main/java/org/itxtech/daedalus/activity/ConfigActivity.java
index 78bda50..b94e6d8 100644
--- a/app/src/main/java/org/itxtech/daedalus/activity/ConfigActivity.java
+++ b/app/src/main/java/org/itxtech/daedalus/activity/ConfigActivity.java
@@ -12,7 +12,7 @@ import androidx.fragment.app.FragmentTransaction;
import org.itxtech.daedalus.Daedalus;
import org.itxtech.daedalus.R;
import org.itxtech.daedalus.fragment.ConfigFragment;
-import org.itxtech.daedalus.fragment.DNSServerConfigFragment;
+import org.itxtech.daedalus.fragment.DnsServerConfigFragment;
import org.itxtech.daedalus.fragment.RuleConfigFragment;
/**
@@ -45,13 +45,13 @@ public class ConfigActivity extends AppCompatActivity {
ConfigFragment fragment;
switch (getIntent().getIntExtra(LAUNCH_ACTION_FRAGMENT, LAUNCH_FRAGMENT_DNS_SERVER)) {
case LAUNCH_FRAGMENT_DNS_SERVER:
- fragment = new DNSServerConfigFragment();
+ fragment = new DnsServerConfigFragment();
break;
case LAUNCH_FRAGMENT_RULE:
fragment = new RuleConfigFragment();
break;
default://should never reach this
- fragment = new DNSServerConfigFragment();
+ fragment = new DnsServerConfigFragment();
break;
}
diff --git a/app/src/main/java/org/itxtech/daedalus/activity/MainActivity.java b/app/src/main/java/org/itxtech/daedalus/activity/MainActivity.java
index 78f1ef8..abc5f20 100644
--- a/app/src/main/java/org/itxtech/daedalus/activity/MainActivity.java
+++ b/app/src/main/java/org/itxtech/daedalus/activity/MainActivity.java
@@ -2,7 +2,6 @@ package org.itxtech.daedalus.activity;
import android.app.Activity;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
import android.net.VpnService;
import android.os.Bundle;
@@ -25,7 +24,6 @@ import org.itxtech.daedalus.R;
import org.itxtech.daedalus.fragment.*;
import org.itxtech.daedalus.service.DaedalusVpnService;
import org.itxtech.daedalus.util.Logger;
-import org.itxtech.daedalus.util.server.DNSServerHelper;
/**
* Daedalus Project
@@ -215,10 +213,10 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
switchFragment(AboutFragment.class);
break;
case FRAGMENT_DNS_SERVERS:
- switchFragment(DNSServersFragment.class);
+ switchFragment(DnsServersFragment.class);
break;
case FRAGMENT_DNS_TEST:
- switchFragment(DNSTestFragment.class);
+ switchFragment(DnsTestFragment.class);
break;
case FRAGMENT_HOME:
switchFragment(HomeFragment.class);
@@ -247,10 +245,10 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
switchFragment(AboutFragment.class);
break;
case R.id.nav_dns_server:
- switchFragment(DNSServersFragment.class);
+ switchFragment(DnsServersFragment.class);
break;
case R.id.nav_dns_test:
- switchFragment(DNSTestFragment.class);
+ switchFragment(DnsTestFragment.class);
break;
case R.id.nav_github:
Daedalus.openUri("https://github.com/iTXTech/Daedalus");
diff --git a/app/src/main/java/org/itxtech/daedalus/fragment/AboutFragment.java b/app/src/main/java/org/itxtech/daedalus/fragment/AboutFragment.java
index 84ca364..9f585dd 100644
--- a/app/src/main/java/org/itxtech/daedalus/fragment/AboutFragment.java
+++ b/app/src/main/java/org/itxtech/daedalus/fragment/AboutFragment.java
@@ -13,6 +13,7 @@ import android.webkit.WebViewClient;
import org.itxtech.daedalus.BuildConfig;
import org.itxtech.daedalus.Daedalus;
import org.itxtech.daedalus.R;
+import org.itxtech.daedalus.util.Logger;
import java.util.Locale;
@@ -64,7 +65,7 @@ public class AboutFragment extends ToolbarFragment {
mWebView.loadUrl("javascript:changeColor('"+(Daedalus.isDarkTheme() ? "#FFFFFF" : "#000000")+"')");
mWebView.loadUrl("javascript:changeVersionInfo('" + Daedalus.getInstance().getPackageManager().getPackageInfo(Daedalus.getInstance().getPackageName(), 0).versionName + "', '" + BuildConfig.BUILD_TIME + "', '" + BuildConfig.GIT_COMMIT + "')");
} catch (Exception e) {
- Log.e("DAboutActivity", e.toString());
+ Logger.logException(e);
}
}
});
@@ -82,8 +83,6 @@ public class AboutFragment extends ToolbarFragment {
super.onDestroyView();
if (mWebView != null) {
- Log.d("DAboutActivity", "onDestroy");
-
mWebView.removeAllViews();
mWebView.setWebViewClient(null);
((ViewGroup) mWebView.getParent()).removeView(mWebView);
diff --git a/app/src/main/java/org/itxtech/daedalus/fragment/DNSServerConfigFragment.java b/app/src/main/java/org/itxtech/daedalus/fragment/DnsServerConfigFragment.java
similarity index 91%
rename from app/src/main/java/org/itxtech/daedalus/fragment/DNSServerConfigFragment.java
rename to app/src/main/java/org/itxtech/daedalus/fragment/DnsServerConfigFragment.java
index 06b0bb2..abc3984 100644
--- a/app/src/main/java/org/itxtech/daedalus/fragment/DNSServerConfigFragment.java
+++ b/app/src/main/java/org/itxtech/daedalus/fragment/DnsServerConfigFragment.java
@@ -11,8 +11,8 @@ import com.google.android.material.snackbar.Snackbar;
import org.itxtech.daedalus.Daedalus;
import org.itxtech.daedalus.R;
import org.itxtech.daedalus.activity.ConfigActivity;
-import org.itxtech.daedalus.util.server.CustomDNSServer;
-import org.itxtech.daedalus.util.server.DNSServer;
+import org.itxtech.daedalus.server.CustomDnsServer;
+import org.itxtech.daedalus.server.DnsServer;
/**
* Daedalus Project
@@ -25,7 +25,7 @@ import org.itxtech.daedalus.util.server.DNSServer;
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*/
-public class DNSServerConfigFragment extends ConfigFragment {
+public class DnsServerConfigFragment extends ConfigFragment {
private int index;
@Override
@@ -58,7 +58,7 @@ public class DNSServerConfigFragment extends ConfigFragment {
index = intent.getIntExtra(ConfigActivity.LAUNCH_ACTION_ID, ConfigActivity.ID_NONE);
if (index != ConfigActivity.ID_NONE) {
- CustomDNSServer server = Daedalus.configurations.getCustomDNSServers().get(index);
+ CustomDnsServer server = Daedalus.configurations.getCustomDNSServers().get(index);
serverName.setText(server.getName());
serverName.setSummary(server.getName());
serverAddress.setText(server.getAddress());
@@ -68,7 +68,7 @@ public class DNSServerConfigFragment extends ConfigFragment {
} else {
serverName.setText("");
serverAddress.setText("");
- String port = String.valueOf(DNSServer.DNS_SERVER_DEFAULT_PORT);
+ String port = String.valueOf(DnsServer.DNS_SERVER_DEFAULT_PORT);
serverPort.setText(port);
serverPort.setSummary(port);
}
@@ -92,9 +92,9 @@ public class DNSServerConfigFragment extends ConfigFragment {
}
if (index == ConfigActivity.ID_NONE) {
- Daedalus.configurations.getCustomDNSServers().add(new CustomDNSServer(serverName, serverAddress, Integer.parseInt(serverPort)));
+ Daedalus.configurations.getCustomDNSServers().add(new CustomDnsServer(serverName, serverAddress, Integer.parseInt(serverPort)));
} else {
- CustomDNSServer server = Daedalus.configurations.getCustomDNSServers().get(index);
+ CustomDnsServer server = Daedalus.configurations.getCustomDNSServers().get(index);
server.setName(serverName);
server.setAddress(serverAddress);
server.setPort(Integer.parseInt(serverPort));
diff --git a/app/src/main/java/org/itxtech/daedalus/fragment/DNSServersFragment.java b/app/src/main/java/org/itxtech/daedalus/fragment/DnsServersFragment.java
similarity index 93%
rename from app/src/main/java/org/itxtech/daedalus/fragment/DNSServersFragment.java
rename to app/src/main/java/org/itxtech/daedalus/fragment/DnsServersFragment.java
index 7e9428a..f6c577d 100644
--- a/app/src/main/java/org/itxtech/daedalus/fragment/DNSServersFragment.java
+++ b/app/src/main/java/org/itxtech/daedalus/fragment/DnsServersFragment.java
@@ -15,8 +15,8 @@ import com.google.android.material.snackbar.Snackbar;
import org.itxtech.daedalus.Daedalus;
import org.itxtech.daedalus.R;
import org.itxtech.daedalus.activity.ConfigActivity;
-import org.itxtech.daedalus.util.server.CustomDNSServer;
-import org.itxtech.daedalus.util.server.DNSServerHelper;
+import org.itxtech.daedalus.server.CustomDnsServer;
+import org.itxtech.daedalus.server.DnsServerHelper;
/**
* Daedalus Project
@@ -29,9 +29,9 @@ import org.itxtech.daedalus.util.server.DNSServerHelper;
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*/
-public class DNSServersFragment extends ToolbarFragment {
+public class DnsServersFragment extends ToolbarFragment {
private DNSServerAdapter adapter;
- private CustomDNSServer server = null;
+ private CustomDnsServer server = null;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@@ -47,7 +47,7 @@ public class DNSServersFragment extends ToolbarFragment {
if (viewHolder instanceof ViewHolder) {
int index = ((ViewHolder) viewHolder).getIndex();
if (index < Daedalus.configurations.getCustomDNSServers().size() &&
- DNSServerHelper.isInUsing(Daedalus.configurations.getCustomDNSServers().get(index))) {
+ DnsServerHelper.isInUsing(Daedalus.configurations.getCustomDNSServers().get(index))) {
return 0;
}
}
@@ -118,7 +118,7 @@ public class DNSServersFragment extends ToolbarFragment {
private class DNSServerAdapter extends RecyclerView.Adapter {
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
- CustomDNSServer server = Daedalus.configurations.getCustomDNSServers().get(position);
+ CustomDnsServer server = Daedalus.configurations.getCustomDNSServers().get(position);
holder.setIndex(position);
holder.textViewName.setText(server.getName());
holder.textViewAddress.setText(server.getRealName());
@@ -159,7 +159,7 @@ public class DNSServersFragment extends ToolbarFragment {
@Override
public void onClick(View v) {
- if (!DNSServerHelper.isInUsing(Daedalus.configurations.getCustomDNSServers().get(index))) {
+ if (!DnsServerHelper.isInUsing(Daedalus.configurations.getCustomDNSServers().get(index))) {
Daedalus.getInstance().startActivity(new Intent(Daedalus.getInstance(), ConfigActivity.class)
.putExtra(ConfigActivity.LAUNCH_ACTION_ID, index)
.putExtra(ConfigActivity.LAUNCH_ACTION_FRAGMENT, ConfigActivity.LAUNCH_FRAGMENT_DNS_SERVER)
diff --git a/app/src/main/java/org/itxtech/daedalus/fragment/DNSTestFragment.java b/app/src/main/java/org/itxtech/daedalus/fragment/DnsTestFragment.java
similarity index 91%
rename from app/src/main/java/org/itxtech/daedalus/fragment/DNSTestFragment.java
rename to app/src/main/java/org/itxtech/daedalus/fragment/DnsTestFragment.java
index 3d44e6f..c08cf3c 100644
--- a/app/src/main/java/org/itxtech/daedalus/fragment/DNSTestFragment.java
+++ b/app/src/main/java/org/itxtech/daedalus/fragment/DnsTestFragment.java
@@ -12,8 +12,8 @@ import android.widget.*;
import org.itxtech.daedalus.Daedalus;
import org.itxtech.daedalus.R;
import org.itxtech.daedalus.util.Logger;
-import org.itxtech.daedalus.util.server.AbstractDNSServer;
-import org.itxtech.daedalus.util.server.DNSServerHelper;
+import org.itxtech.daedalus.server.AbstractDnsServer;
+import org.itxtech.daedalus.server.DnsServerHelper;
import org.minidns.dnsmessage.DnsMessage;
import org.minidns.dnsmessage.Question;
import org.minidns.record.Record;
@@ -36,7 +36,7 @@ import java.util.Random;
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*/
-public class DNSTestFragment extends ToolbarFragment {
+public class DnsTestFragment extends ToolbarFragment {
private class Type {
private Record.TYPE type;
private String name;
@@ -67,9 +67,9 @@ public class DNSTestFragment extends ToolbarFragment {
final TextView textViewTestInfo = view.findViewById(R.id.textView_test_info);
final Spinner spinnerServerChoice = view.findViewById(R.id.spinner_server_choice);
- ArrayAdapter spinnerArrayAdapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_1, DNSServerHelper.getAllServers());
+ ArrayAdapter spinnerArrayAdapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_1, DnsServerHelper.getAllServers());
spinnerServerChoice.setAdapter(spinnerArrayAdapter);
- spinnerServerChoice.setSelection(DNSServerHelper.getPosition(DNSServerHelper.getPrimary()));
+ spinnerServerChoice.setSelection(DnsServerHelper.getPosition(DnsServerHelper.getPrimary()));
ArrayList types = new ArrayList() {{
add(new Type("A", Record.TYPE.A));
@@ -110,38 +110,38 @@ public class DNSTestFragment extends ToolbarFragment {
testDomain = Daedalus.DEFAULT_TEST_DOMAINS[0];
}
StringBuilder testText = new StringBuilder();
- ArrayList dnsServers = new ArrayList() {{
- add(((AbstractDNSServer) spinnerServerChoice.getSelectedItem()));
+ ArrayList dnsServers = new ArrayList() {{
+ add(((AbstractDnsServer) spinnerServerChoice.getSelectedItem()));
String servers = Daedalus.getPrefs().getString("dns_test_servers", "");
if (!servers.equals("")) {
for (String server : servers.split(",")) {
if (server.contains(".") && server.contains(":")) {//IPv4
String[] pieces = servers.split(":");
- int port = AbstractDNSServer.DNS_SERVER_DEFAULT_PORT;
+ int port = AbstractDnsServer.DNS_SERVER_DEFAULT_PORT;
try {
port = Integer.parseInt(pieces[1]);
} catch (Exception e) {
Logger.logException(e);
}
- add(new AbstractDNSServer(pieces[0], port));
+ add(new AbstractDnsServer(pieces[0], port));
} else if (!server.contains(".") && server.contains("|")) {//IPv6
String[] pieces = servers.split("\\|");
- int port = AbstractDNSServer.DNS_SERVER_DEFAULT_PORT;
+ int port = AbstractDnsServer.DNS_SERVER_DEFAULT_PORT;
try {
port = Integer.parseInt(pieces[1]);
} catch (Exception e) {
Logger.logException(e);
}
- add(new AbstractDNSServer(pieces[0], port));
+ add(new AbstractDnsServer(pieces[0], port));
} else {
- add(new AbstractDNSServer(server, AbstractDNSServer.DNS_SERVER_DEFAULT_PORT));
+ add(new AbstractDnsServer(server, AbstractDnsServer.DNS_SERVER_DEFAULT_PORT));
}
}
}
}};
DnsQuery dnsQuery = new DnsQuery();
Record.TYPE type = ((Type) spinnerType.getSelectedItem()).getType();
- for (AbstractDNSServer dnsServer : dnsServers) {
+ for (AbstractDnsServer dnsServer : dnsServers) {
testText = testServer(dnsQuery, type, dnsServer, testDomain, testText);
}
mHandler.obtainMessage(DnsTestHandler.MSG_TEST_DONE).sendToTarget();
@@ -152,7 +152,7 @@ public class DNSTestFragment extends ToolbarFragment {
}
- private StringBuilder testServer(DnsQuery dnsQuery, Record.TYPE type, AbstractDNSServer server, String domain, StringBuilder testText) {
+ private StringBuilder testServer(DnsQuery dnsQuery, Record.TYPE type, AbstractDnsServer server, String domain, StringBuilder testText) {
Logger.debug("Testing DNS server " + server.getRealName());
testText.append(getString(R.string.test_domain)).append(" ").append(domain).append("\n")
.append(getString(R.string.test_dns_server)).append(" ").append(server.getRealName());
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 53f917e..8ad7410 100644
--- a/app/src/main/java/org/itxtech/daedalus/fragment/GlobalConfigFragment.java
+++ b/app/src/main/java/org/itxtech/daedalus/fragment/GlobalConfigFragment.java
@@ -7,7 +7,7 @@ import org.itxtech.daedalus.Daedalus;
import org.itxtech.daedalus.R;
import org.itxtech.daedalus.activity.AppFilterActivity;
import org.itxtech.daedalus.activity.MainActivity;
-import org.itxtech.daedalus.util.server.DNSServerHelper;
+import org.itxtech.daedalus.server.DnsServerHelper;
import java.util.ArrayList;
@@ -27,8 +27,8 @@ public class GlobalConfigFragment extends PreferenceFragmentCompat {
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
Daedalus.getPrefs().edit()
- .putString("primary_server", DNSServerHelper.getPrimary())
- .putString("secondary_server", DNSServerHelper.getSecondary())
+ .putString("primary_server", DnsServerHelper.getPrimary())
+ .putString("secondary_server", DnsServerHelper.getSecondary())
.apply();
addPreferencesFromResource(R.xml.perf_settings);
@@ -40,11 +40,11 @@ public class GlobalConfigFragment extends PreferenceFragmentCompat {
}}) {
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.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()));
+ preference.setSummary(DnsServerHelper.getDescription((String) newValue, Daedalus.getInstance()));
return true;
});
}
diff --git a/app/src/main/java/org/itxtech/daedalus/fragment/HomeFragment.java b/app/src/main/java/org/itxtech/daedalus/fragment/HomeFragment.java
index 82702f3..0cc55ee 100644
--- a/app/src/main/java/org/itxtech/daedalus/fragment/HomeFragment.java
+++ b/app/src/main/java/org/itxtech/daedalus/fragment/HomeFragment.java
@@ -50,7 +50,6 @@ public class HomeFragment extends ToolbarFragment {
}
private void updateUserInterface() {
- Log.d("DMainFragment", "updateInterface");
Button but = getView().findViewById(R.id.button_activate);
if (DaedalusVpnService.isActivated()) {
but.setText(R.string.button_text_deactivate);
diff --git a/app/src/main/java/org/itxtech/daedalus/provider/HttpsProvider.java b/app/src/main/java/org/itxtech/daedalus/provider/HttpsProvider.java
index 2acb812..b94256f 100644
--- a/app/src/main/java/org/itxtech/daedalus/provider/HttpsProvider.java
+++ b/app/src/main/java/org/itxtech/daedalus/provider/HttpsProvider.java
@@ -10,7 +10,7 @@ import okhttp3.OkHttpClient;
import org.itxtech.daedalus.Daedalus;
import org.itxtech.daedalus.service.DaedalusVpnService;
import org.itxtech.daedalus.util.Logger;
-import org.itxtech.daedalus.util.server.DNSServerHelper;
+import org.itxtech.daedalus.server.DnsServerHelper;
import org.minidns.dnsmessage.DnsMessage;
import org.pcap4j.packet.IpPacket;
import org.pcap4j.packet.IpSelector;
@@ -58,8 +58,8 @@ abstract public class HttpsProvider extends Provider {
.header("Accept", accept)
.build()))
.dns(hostname -> {
- if (DNSServerHelper.domainCache.containsKey(hostname)) {
- return DNSServerHelper.domainCache.get(hostname);
+ if (DnsServerHelper.domainCache.containsKey(hostname)) {
+ return DnsServerHelper.domainCache.get(hostname);
}
return Arrays.asList(InetAddress.getAllByName(hostname));
})
@@ -138,7 +138,7 @@ abstract public class HttpsProvider extends Provider {
return;
String uri;
try {
- uri = service.dnsServers.get(destAddr.getHostAddress());//https uri
+ uri = service.dnsServers.get(destAddr.getHostAddress()).getAddress();//https uri
} catch (Exception e) {
Logger.logException(e);
return;
@@ -161,7 +161,7 @@ abstract public class HttpsProvider extends Provider {
return;
}
if (dnsMsg.getQuestion() == null) {
- Log.i(TAG, "handleDnsRequest: Discarding DNS packet with no query " + dnsMsg);
+ Logger.debug("handleDnsRequest: Discarding DNS packet with no query " + dnsMsg);
return;
}
diff --git a/app/src/main/java/org/itxtech/daedalus/provider/ProviderPicker.java b/app/src/main/java/org/itxtech/daedalus/provider/ProviderPicker.java
index 7dcc492..cd882bd 100644
--- a/app/src/main/java/org/itxtech/daedalus/provider/ProviderPicker.java
+++ b/app/src/main/java/org/itxtech/daedalus/provider/ProviderPicker.java
@@ -40,6 +40,6 @@ public class ProviderPicker {
}
public static int getDnsQueryMethod() {
- return Integer.valueOf(Daedalus.getPrefs().getString("settings_dns_query_method", "0"));
+ return Integer.parseInt(Daedalus.getPrefs().getString("settings_dns_query_method", "0"));
}
}
diff --git a/app/src/main/java/org/itxtech/daedalus/provider/TcpProvider.java b/app/src/main/java/org/itxtech/daedalus/provider/TcpProvider.java
index 183efc9..3a8fb34 100644
--- a/app/src/main/java/org/itxtech/daedalus/provider/TcpProvider.java
+++ b/app/src/main/java/org/itxtech/daedalus/provider/TcpProvider.java
@@ -9,7 +9,7 @@ import android.util.Log;
import androidx.annotation.NonNull;
import org.itxtech.daedalus.service.DaedalusVpnService;
import org.itxtech.daedalus.util.Logger;
-import org.itxtech.daedalus.util.server.DNSServerHelper;
+import org.itxtech.daedalus.server.AbstractDnsServer;
import org.pcap4j.packet.IpPacket;
import java.io.*;
@@ -123,7 +123,7 @@ public class TcpProvider extends UdpProvider {
}
@Override
- protected void forwardPacket(DatagramPacket outPacket, IpPacket parsedPacket) throws DaedalusVpnService.VpnNetworkException {
+ protected void forwardPacket(DatagramPacket outPacket, IpPacket parsedPacket, AbstractDnsServer dnsServer) throws DaedalusVpnService.VpnNetworkException {
Socket dnsSocket;
try {
// Packets to be sent to the real DNS server will need to be protected from the VPN
@@ -131,7 +131,7 @@ public class TcpProvider extends UdpProvider {
service.protect(dnsSocket);
- SocketAddress address = new InetSocketAddress(outPacket.getAddress(), DNSServerHelper.getPortOrDefault(outPacket.getAddress(), outPacket.getPort()));
+ SocketAddress address = new InetSocketAddress(outPacket.getAddress(), dnsServer.getPort());
dnsSocket.connect(address, 5000);
dnsSocket.setSoTimeout(5000);
Logger.info("TcpProvider: Sending DNS query request");
diff --git a/app/src/main/java/org/itxtech/daedalus/provider/TlsProvider.java b/app/src/main/java/org/itxtech/daedalus/provider/TlsProvider.java
index 6ca65c9..aeed205 100644
--- a/app/src/main/java/org/itxtech/daedalus/provider/TlsProvider.java
+++ b/app/src/main/java/org/itxtech/daedalus/provider/TlsProvider.java
@@ -3,7 +3,7 @@ package org.itxtech.daedalus.provider;
import android.os.ParcelFileDescriptor;
import org.itxtech.daedalus.service.DaedalusVpnService;
import org.itxtech.daedalus.util.Logger;
-import org.itxtech.daedalus.util.server.DNSServerHelper;
+import org.itxtech.daedalus.server.AbstractDnsServer;
import org.pcap4j.packet.IpPacket;
import javax.net.ssl.SSLContext;
@@ -28,13 +28,12 @@ public class TlsProvider extends TcpProvider{
}
@Override
- protected void forwardPacket(DatagramPacket outPacket, IpPacket parsedPacket) {
+ protected void forwardPacket(DatagramPacket outPacket, IpPacket parsedPacket, AbstractDnsServer dnsServer) {
Socket dnsSocket;
try {
SSLContext context = SSLContext.getInstance("TLSv1.2");
context.init(null, null, null);
- dnsSocket = context.getSocketFactory().createSocket(outPacket.getAddress(),
- DNSServerHelper.getPortOrDefault(outPacket.getAddress(), outPacket.getPort()));
+ dnsSocket = context.getSocketFactory().createSocket(outPacket.getAddress(), dnsServer.getPort());
//Create TLS v1.2 socket
//TODO: SNI
diff --git a/app/src/main/java/org/itxtech/daedalus/provider/UdpProvider.java b/app/src/main/java/org/itxtech/daedalus/provider/UdpProvider.java
index 6e08604..59e35fc 100644
--- a/app/src/main/java/org/itxtech/daedalus/provider/UdpProvider.java
+++ b/app/src/main/java/org/itxtech/daedalus/provider/UdpProvider.java
@@ -9,7 +9,7 @@ import androidx.annotation.NonNull;
import org.itxtech.daedalus.Daedalus;
import org.itxtech.daedalus.service.DaedalusVpnService;
import org.itxtech.daedalus.util.Logger;
-import org.itxtech.daedalus.util.server.DNSServerHelper;
+import org.itxtech.daedalus.server.AbstractDnsServer;
import org.minidns.dnsmessage.DnsMessage;
import org.pcap4j.packet.IpPacket;
import org.pcap4j.packet.IpSelector;
@@ -118,7 +118,7 @@ public class UdpProvider extends Provider {
}
}
- protected void forwardPacket(DatagramPacket outPacket, IpPacket parsedPacket) throws DaedalusVpnService.VpnNetworkException {
+ protected void forwardPacket(DatagramPacket outPacket, IpPacket parsedPacket, AbstractDnsServer dnsServer) throws DaedalusVpnService.VpnNetworkException {
DatagramSocket dnsSocket;
try {
// Packets to be sent to the real DNS server will need to be protected from the VPN
@@ -158,7 +158,6 @@ public class UdpProvider extends Provider {
*/
@Override
protected void handleDnsRequest(byte[] packetData) throws DaedalusVpnService.VpnNetworkException {
-
IpPacket parsedPacket;
try {
parsedPacket = (IpPacket) IpSelector.newPacket(packetData, 0, packetData.length);
@@ -169,17 +168,20 @@ public class UdpProvider extends Provider {
if (!(parsedPacket.getPayload() instanceof UdpPacket)) {
try {
- Log.i(TAG, "handleDnsRequest: Discarding unknown packet type " + parsedPacket.getPayload());
+ Logger.debug("handleDnsRequest: Discarding unknown packet type " + parsedPacket.getPayload());
} catch (Exception ignored) {
}
return;
}
InetAddress destAddr = parsedPacket.getHeader().getDstAddr();
- if (destAddr == null)
+ if (destAddr == null) {
return;
+ }
+ AbstractDnsServer dnsServer;
try {
- destAddr = InetAddress.getByName(service.dnsServers.get(destAddr.getHostAddress()));
+ dnsServer = service.dnsServers.get(destAddr.getHostAddress());
+ destAddr = InetAddress.getByName(dnsServer.getHostAddress());
} catch (Exception e) {
Logger.logException(e);
Logger.error("handleDnsRequest: DNS server alias query failed for " + destAddr.getHostAddress());
@@ -194,9 +196,8 @@ public class UdpProvider extends Provider {
// Let's be nice to Firefox. Firefox uses an empty UDP packet to
// the gateway to reduce the RTT. For further details, please see
// https://bugzilla.mozilla.org/show_bug.cgi?id=888268
- DatagramPacket outPacket = new DatagramPacket(new byte[0], 0, 0, destAddr,
- DNSServerHelper.getPortOrDefault(destAddr, parsedUdp.getHeader().getDstPort().valueAsInt()));
- forwardPacket(outPacket, null);
+ DatagramPacket outPacket = new DatagramPacket(new byte[0], 0, 0, destAddr, dnsServer.getPort());
+ forwardPacket(outPacket, null, dnsServer);
return;
}
@@ -212,14 +213,13 @@ public class UdpProvider extends Provider {
return;
}
if (dnsMsg.getQuestion() == null) {
- Log.i(TAG, "handleDnsRequest: Discarding DNS packet with no query " + dnsMsg);
+ Logger.debug("handleDnsRequest: Discarding DNS packet with no query " + dnsMsg);
return;
}
if (!resolve(parsedPacket, dnsMsg)) {
- DatagramPacket outPacket = new DatagramPacket(dnsRawData, 0, dnsRawData.length, destAddr,
- DNSServerHelper.getPortOrDefault(destAddr, parsedUdp.getHeader().getDstPort().valueAsInt()));
- forwardPacket(outPacket, parsedPacket);
+ DatagramPacket outPacket = new DatagramPacket(dnsRawData, 0, dnsRawData.length, destAddr, dnsServer.getPort());
+ forwardPacket(outPacket, parsedPacket, dnsServer);
}
}
diff --git a/app/src/main/java/org/itxtech/daedalus/util/server/AbstractDNSServer.java b/app/src/main/java/org/itxtech/daedalus/server/AbstractDnsServer.java
similarity index 77%
rename from app/src/main/java/org/itxtech/daedalus/util/server/AbstractDNSServer.java
rename to app/src/main/java/org/itxtech/daedalus/server/AbstractDnsServer.java
index e1b6f39..1026c1e 100644
--- a/app/src/main/java/org/itxtech/daedalus/util/server/AbstractDNSServer.java
+++ b/app/src/main/java/org/itxtech/daedalus/server/AbstractDnsServer.java
@@ -1,4 +1,4 @@
-package org.itxtech.daedalus.util.server;
+package org.itxtech.daedalus.server;
/**
* Daedalus Project
@@ -11,17 +11,26 @@ package org.itxtech.daedalus.util.server;
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*/
-public class AbstractDNSServer {
+public class AbstractDnsServer {
public static final int DNS_SERVER_DEFAULT_PORT = 53;
protected String address;
protected int port;
+ protected String hostAddress;
- public AbstractDNSServer(String address, int port) {
+ public AbstractDnsServer(String address, int port) {
this.address = address;
this.port = port;
}
+ public void setHostAddress(String hostAddress) {
+ this.hostAddress = hostAddress;
+ }
+
+ public String getHostAddress() {
+ return hostAddress;
+ }
+
public void setAddress(String address) {
this.address = address;
}
diff --git a/app/src/main/java/org/itxtech/daedalus/util/server/CustomDNSServer.java b/app/src/main/java/org/itxtech/daedalus/server/CustomDnsServer.java
similarity index 83%
rename from app/src/main/java/org/itxtech/daedalus/util/server/CustomDNSServer.java
rename to app/src/main/java/org/itxtech/daedalus/server/CustomDnsServer.java
index 56056ad..9aae884 100644
--- a/app/src/main/java/org/itxtech/daedalus/util/server/CustomDNSServer.java
+++ b/app/src/main/java/org/itxtech/daedalus/server/CustomDnsServer.java
@@ -1,4 +1,4 @@
-package org.itxtech.daedalus.util.server;
+package org.itxtech.daedalus.server;
import org.itxtech.daedalus.Daedalus;
@@ -13,11 +13,11 @@ import org.itxtech.daedalus.Daedalus;
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*/
-public class CustomDNSServer extends AbstractDNSServer {
+public class CustomDnsServer extends AbstractDnsServer {
private String name;
private String id;
- public CustomDNSServer(String name, String address, int port) {
+ public CustomDnsServer(String name, String address, int port) {
super(address, port);
this.name = name;
this.id = String.valueOf(Daedalus.configurations.getNextDnsId());
diff --git a/app/src/main/java/org/itxtech/daedalus/util/server/DNSServer.java b/app/src/main/java/org/itxtech/daedalus/server/DnsServer.java
similarity index 78%
rename from app/src/main/java/org/itxtech/daedalus/util/server/DNSServer.java
rename to app/src/main/java/org/itxtech/daedalus/server/DnsServer.java
index 865d07b..74aa64d 100644
--- a/app/src/main/java/org/itxtech/daedalus/util/server/DNSServer.java
+++ b/app/src/main/java/org/itxtech/daedalus/server/DnsServer.java
@@ -1,4 +1,4 @@
-package org.itxtech.daedalus.util.server;
+package org.itxtech.daedalus.server;
import android.content.Context;
import org.itxtech.daedalus.Daedalus;
@@ -14,23 +14,27 @@ import org.itxtech.daedalus.Daedalus;
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*/
-public class DNSServer extends AbstractDNSServer {
+public class DnsServer extends AbstractDnsServer {
private static int totalId = 0;
private String id;
private int description;
- public DNSServer(String address, int description, int port) {
+ public DnsServer(String address, int description, int port) {
super(address, port);
this.id = String.valueOf(totalId++);
this.description = description;
}
- public DNSServer(String address, int description) {
+ public DnsServer(String address, int description) {
this(address, description, DNS_SERVER_DEFAULT_PORT);
}
+ public DnsServer(String address) {
+ this(address, 0);
+ }
+
public String getId() {
return id;
}
diff --git a/app/src/main/java/org/itxtech/daedalus/util/server/DNSServerHelper.java b/app/src/main/java/org/itxtech/daedalus/server/DnsServerHelper.java
similarity index 68%
rename from app/src/main/java/org/itxtech/daedalus/util/server/DNSServerHelper.java
rename to app/src/main/java/org/itxtech/daedalus/server/DnsServerHelper.java
index ce8b814..332e682 100644
--- a/app/src/main/java/org/itxtech/daedalus/util/server/DNSServerHelper.java
+++ b/app/src/main/java/org/itxtech/daedalus/server/DnsServerHelper.java
@@ -1,4 +1,4 @@
-package org.itxtech.daedalus.util.server;
+package org.itxtech.daedalus.server;
import android.content.Context;
import android.net.Uri;
@@ -25,31 +25,19 @@ import java.util.List;
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*/
-public class DNSServerHelper {
- private static HashMap portCache = new HashMap<>();
+public class DnsServerHelper {
public static HashMap> domainCache = new HashMap<>();
public static void clearCache() {
- portCache = new HashMap<>();
domainCache = new HashMap<>();
}
public static void buildCache() {
domainCache = new HashMap<>();
- portCache = new HashMap<>();
-
if (ProviderPicker.getDnsQueryMethod() >= ProviderPicker.DNS_QUERY_METHOD_HTTPS_IETF &&
- !Daedalus.getPrefs().getBoolean("settings_dont_build_doh_cache", false)) {
- buildDomainCache(getAddressById(getPrimary()));
- buildDomainCache(getAddressById(getSecondary()));
- }
-
- for (DNSServer server : Daedalus.DNS_SERVERS) {
- portCache.put(server.getAddress(), server.getPort());
- }
-
- for (CustomDNSServer server : Daedalus.configurations.getCustomDNSServers()) {
- portCache.put(server.getAddress(), server.getPort());
+ !Daedalus.getPrefs().getBoolean("settings_dont_build_cache", false)) {
+ buildDomainCache(getServerById(getPrimary()).getAddress());
+ buildDomainCache(getServerById(getSecondary()).getAddress());
}
}
@@ -63,16 +51,6 @@ public class DNSServerHelper {
}
}
- public static int getPortOrDefault(InetAddress address, int defaultPort) {
- String hostAddress = address.getHostAddress();
-
- if (portCache.containsKey(hostAddress)) {
- return portCache.get(hostAddress);
- }
-
- return defaultPort;
- }
-
public static int getPosition(String id) {
int intId = Integer.parseInt(id);
if (intId < Daedalus.DNS_SERVERS.size()) {
@@ -88,18 +66,18 @@ public class DNSServerHelper {
}
public static String getPrimary() {
- return String.valueOf(DNSServerHelper.checkServerId(Integer.parseInt(Daedalus.getPrefs().getString("primary_server", "0"))));
+ return String.valueOf(DnsServerHelper.checkServerId(Integer.parseInt(Daedalus.getPrefs().getString("primary_server", "0"))));
}
public static String getSecondary() {
- return String.valueOf(DNSServerHelper.checkServerId(Integer.parseInt(Daedalus.getPrefs().getString("secondary_server", "1"))));
+ return String.valueOf(DnsServerHelper.checkServerId(Integer.parseInt(Daedalus.getPrefs().getString("secondary_server", "1"))));
}
private static int checkServerId(int id) {
if (id < Daedalus.DNS_SERVERS.size()) {
return id;
}
- for (CustomDNSServer server : Daedalus.configurations.getCustomDNSServers()) {
+ for (CustomDnsServer server : Daedalus.configurations.getCustomDNSServers()) {
if (server.getId().equals(String.valueOf(id))) {
return id;
}
@@ -107,26 +85,26 @@ public class DNSServerHelper {
return 0;
}
- public static String getAddressById(String id) {
- for (DNSServer server : Daedalus.DNS_SERVERS) {
+ public static AbstractDnsServer getServerById(String id) {
+ for (DnsServer server : Daedalus.DNS_SERVERS) {
if (server.getId().equals(id)) {
- return server.getAddress();
+ return server;
}
}
- for (CustomDNSServer customDNSServer : Daedalus.configurations.getCustomDNSServers()) {
+ for (CustomDnsServer customDNSServer : Daedalus.configurations.getCustomDNSServers()) {
if (customDNSServer.getId().equals(id)) {
- return customDNSServer.getAddress();
+ return customDNSServer;
}
}
- return Daedalus.DNS_SERVERS.get(0).getAddress();
+ return Daedalus.DNS_SERVERS.get(0);
}
public static String[] getIds() {
ArrayList servers = new ArrayList<>(Daedalus.DNS_SERVERS.size());
- for (DNSServer server : Daedalus.DNS_SERVERS) {
+ for (DnsServer server : Daedalus.DNS_SERVERS) {
servers.add(server.getId());
}
- for (CustomDNSServer customDNSServer : Daedalus.configurations.getCustomDNSServers()) {
+ for (CustomDnsServer customDNSServer : Daedalus.configurations.getCustomDNSServers()) {
servers.add(customDNSServer.getId());
}
String[] stringServers = new String[Daedalus.DNS_SERVERS.size()];
@@ -135,30 +113,30 @@ public class DNSServerHelper {
public static String[] getNames(Context context) {
ArrayList servers = new ArrayList<>(Daedalus.DNS_SERVERS.size());
- for (DNSServer server : Daedalus.DNS_SERVERS) {
+ for (DnsServer server : Daedalus.DNS_SERVERS) {
servers.add(server.getStringDescription(context));
}
- for (CustomDNSServer customDNSServer : Daedalus.configurations.getCustomDNSServers()) {
+ for (CustomDnsServer customDNSServer : Daedalus.configurations.getCustomDNSServers()) {
servers.add(customDNSServer.getName());
}
String[] stringServers = new String[Daedalus.DNS_SERVERS.size()];
return servers.toArray(stringServers);
}
- public static ArrayList getAllServers() {
- ArrayList servers = new ArrayList<>(Daedalus.DNS_SERVERS.size());
+ public static ArrayList getAllServers() {
+ ArrayList servers = new ArrayList<>(Daedalus.DNS_SERVERS.size());
servers.addAll(Daedalus.DNS_SERVERS);
servers.addAll(Daedalus.configurations.getCustomDNSServers());
return servers;
}
public static String getDescription(String id, Context context) {
- for (DNSServer server : Daedalus.DNS_SERVERS) {
+ for (DnsServer server : Daedalus.DNS_SERVERS) {
if (server.getId().equals(id)) {
return server.getStringDescription(context);
}
}
- for (CustomDNSServer customDNSServer : Daedalus.configurations.getCustomDNSServers()) {
+ for (CustomDnsServer customDNSServer : Daedalus.configurations.getCustomDNSServers()) {
if (customDNSServer.getId().equals(id)) {
return customDNSServer.getName();
}
@@ -166,7 +144,7 @@ public class DNSServerHelper {
return Daedalus.DNS_SERVERS.get(0).getStringDescription(context);
}
- public static boolean isInUsing(CustomDNSServer server) {
+ public static boolean isInUsing(CustomDnsServer server) {
return DaedalusVpnService.isActivated() && (server.getId().equals(getPrimary()) || server.getId().equals(getSecondary()));
}
}
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 7d3e54e..b315426 100644
--- a/app/src/main/java/org/itxtech/daedalus/service/DaedalusVpnService.java
+++ b/app/src/main/java/org/itxtech/daedalus/service/DaedalusVpnService.java
@@ -21,7 +21,8 @@ import org.itxtech.daedalus.provider.ProviderPicker;
import org.itxtech.daedalus.receiver.StatusBarBroadcastReceiver;
import org.itxtech.daedalus.util.Logger;
import org.itxtech.daedalus.util.RuleResolver;
-import org.itxtech.daedalus.util.server.DNSServerHelper;
+import org.itxtech.daedalus.server.AbstractDnsServer;
+import org.itxtech.daedalus.server.DnsServerHelper;
import java.net.Inet4Address;
import java.net.Inet6Address;
@@ -51,8 +52,8 @@ public class DaedalusVpnService extends VpnService implements Runnable {
private static final String CHANNEL_ID = "daedalus_channel_1";
private static final String CHANNEL_NAME = "daedalus_channel";
- public static String primaryServer;
- public static String secondaryServer;
+ public static AbstractDnsServer primaryServer;
+ public static AbstractDnsServer secondaryServer;
private NotificationCompat.Builder notification = null;
@@ -64,7 +65,7 @@ public class DaedalusVpnService extends VpnService implements Runnable {
private Thread mThread = null;
- public HashMap dnsServers;
+ public HashMap dnsServers;
private static boolean activated = false;
@@ -185,7 +186,7 @@ public class DaedalusVpnService extends VpnService implements Runnable {
if (shouldRefresh) {
RuleResolver.clear();
- DNSServerHelper.clearCache();
+ DnsServerHelper.clearCache();
Logger.info("Daedalus VPN service has stopped");
}
@@ -202,27 +203,29 @@ public class DaedalusVpnService extends VpnService implements Runnable {
stopThread();
}
- private InetAddress addDnsServer(Builder builder, String format, byte[] ipv6Template, String addr) throws UnknownHostException {
+ private InetAddress addDnsServer(Builder builder, String format, byte[] ipv6Template, AbstractDnsServer addr) throws UnknownHostException {
int size = dnsServers.size();
size++;
- if (addr.contains("/")) {//https uri
+ if (addr.getAddress().contains("/")) {//https uri
String alias = String.format(format, size + 1);
dnsServers.put(alias, addr);
builder.addRoute(alias, 32);
return InetAddress.getByName(alias);
}
- InetAddress address = InetAddress.getByName(addr);
+ InetAddress address = InetAddress.getByName(addr.getAddress());
if (address instanceof Inet6Address && ipv6Template == null) {
Log.i(TAG, "addDnsServer: Ignoring DNS server " + address);
} else if (address instanceof Inet4Address) {
String alias = String.format(format, size + 1);
- dnsServers.put(alias, address.getHostAddress());
+ addr.setHostAddress(address.getHostAddress());
+ dnsServers.put(alias, addr);
builder.addRoute(alias, 32);
return InetAddress.getByName(alias);
} else if (address instanceof Inet6Address) {
ipv6Template[ipv6Template.length - 1] = (byte) (size + 1);
InetAddress i6addr = Inet6Address.getByAddress(ipv6Template);
- dnsServers.put(i6addr.getHostAddress(), address.getHostAddress());
+ addr.setHostAddress(address.getHostAddress());
+ dnsServers.put(i6addr.getHostAddress(), addr);
return i6addr;
}
return null;
@@ -231,7 +234,7 @@ public class DaedalusVpnService extends VpnService implements Runnable {
@Override
public void run() {
try {
- DNSServerHelper.buildCache();
+ DnsServerHelper.buildCache();
Builder builder = new Builder()
.setSession("Daedalus")
.setConfigureIntent(PendingIntent.getActivity(this, 0,
@@ -275,7 +278,7 @@ public class DaedalusVpnService extends VpnService implements Runnable {
statisticQuery = Daedalus.getPrefs().getBoolean("settings_count_query_times", false);
byte[] ipv6Template = new byte[]{32, 1, 13, (byte) (184 & 0xFF), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- if (primaryServer.contains(":") || secondaryServer.contains(":")) {//IPv6
+ if (primaryServer.getAddress().contains(":") || secondaryServer.getAddress().contains(":")) {//IPv6
try {
InetAddress addr = Inet6Address.getByAddress(ipv6Template);
Log.d(TAG, "configure: Adding IPv6 address" + addr);
@@ -296,15 +299,13 @@ public class DaedalusVpnService extends VpnService implements Runnable {
aliasPrimary = addDnsServer(builder, format, ipv6Template, primaryServer);
aliasSecondary = addDnsServer(builder, format, ipv6Template, secondaryServer);
} else {
- aliasPrimary = InetAddress.getByName(primaryServer);
- aliasSecondary = InetAddress.getByName(secondaryServer);
+ aliasPrimary = InetAddress.getByName(primaryServer.getAddress());
+ aliasSecondary = InetAddress.getByName(secondaryServer.getAddress());
}
- InetAddress primaryDNSServer = aliasPrimary;
- InetAddress secondaryDNSServer = aliasSecondary;
- Logger.info("Daedalus VPN service is listening on " + primaryServer + " as " + primaryDNSServer.getHostAddress());
- Logger.info("Daedalus VPN service is listening on " + secondaryServer + " as " + secondaryDNSServer.getHostAddress());
- builder.addDnsServer(primaryDNSServer).addDnsServer(secondaryDNSServer);
+ Logger.info("Daedalus VPN service is listening on " + primaryServer + " as " + aliasPrimary.getHostAddress());
+ Logger.info("Daedalus VPN service is listening on " + secondaryServer + " as " + aliasSecondary.getHostAddress());
+ builder.addDnsServer(aliasPrimary).addDnsServer(aliasSecondary);
if (advanced) {
builder.setBlocking(true);
diff --git a/app/src/main/java/org/itxtech/daedalus/util/Configurations.java b/app/src/main/java/org/itxtech/daedalus/util/Configurations.java
index 7de91c7..f970666 100644
--- a/app/src/main/java/org/itxtech/daedalus/util/Configurations.java
+++ b/app/src/main/java/org/itxtech/daedalus/util/Configurations.java
@@ -3,7 +3,7 @@ package org.itxtech.daedalus.util;
import com.google.gson.Gson;
import com.google.gson.stream.JsonReader;
import org.itxtech.daedalus.Daedalus;
-import org.itxtech.daedalus.util.server.CustomDNSServer;
+import org.itxtech.daedalus.server.CustomDnsServer;
import java.io.File;
import java.io.FileReader;
@@ -27,7 +27,7 @@ public class Configurations {
private static File file;
- private ArrayList customDNSServers;
+ private ArrayList customDNSServers;
private ArrayList appObjects;
private ArrayList hostsRules;
@@ -60,7 +60,7 @@ public class Configurations {
this.activateCounter = activateCounter;
}
- public ArrayList getCustomDNSServers() {
+ public ArrayList getCustomDNSServers() {
if (customDNSServers == null) {
customDNSServers = new ArrayList<>();
}
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index b7d7d5c..79aca38 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -62,7 +62,7 @@
访问 GitHub wiki 页面。
日志大小限制
调试输出
- 不缓存 DoH DNS 的 IP地址
+ 不缓存 DNS 的 IP地址
使用暗主题
DNS 查询方式
运行前台服务
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index ee77d87..c4d4e93 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -62,7 +62,7 @@
造訪 GitHub wiki 頁面。
紀錄檔大小限制
调试输出 TODO
- 不緩存 DoH DNS 的 IP地址
+ 不緩存 DNS 的 IP地址
使用暗主题
規則名稱
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index b4dfce2..b43264a 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -60,7 +60,7 @@
Log Size Limit
Manual
Visit GitHub wiki page.
- Don\'t build DNS Cache for DoH DNS
+ Don\'t cache ip for DNS servers
Debug Output
Use Dark Theme
DNS Query Method
diff --git a/app/src/main/res/xml/perf_settings.xml b/app/src/main/res/xml/perf_settings.xml
index 10320a6..f4c90fc 100644
--- a/app/src/main/res/xml/perf_settings.xml
+++ b/app/src/main/res/xml/perf_settings.xml
@@ -92,8 +92,8 @@
android:defaultValue="false"
android:enabled="false"/>
Date: Wed, 23 Oct 2019 15:48:02 +0800
Subject: [PATCH 09/14] Daedalus: reformat things
---
app/build.gradle | 2 +-
.../java/org/itxtech/daedalus/Daedalus.java | 60 +++++++++----------
.../daedalus/activity/ConfigActivity.java | 4 +-
.../daedalus/util/DnsServersDetector.java | 30 +++++-----
app/src/main/res/values/strings.xml | 2 +-
5 files changed, 46 insertions(+), 52 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index 7f93c67..0a4bcf8 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -58,7 +58,7 @@ dependencies {
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'com.google.android.material:material:1.2.0-alpha01'
implementation 'androidx.recyclerview:recyclerview:1.1.0-beta05'
- implementation "androidx.preference:preference:1.1.0"
+ implementation 'androidx.preference:preference:1.1.0'
//DNS
implementation 'org.pcap4j:pcap4j-core:1.8.2'
implementation 'org.pcap4j:pcap4j-packetfactory-static:1.8.2'
diff --git a/app/src/main/java/org/itxtech/daedalus/Daedalus.java b/app/src/main/java/org/itxtech/daedalus/Daedalus.java
index 4016e73..2043577 100644
--- a/app/src/main/java/org/itxtech/daedalus/Daedalus.java
+++ b/app/src/main/java/org/itxtech/daedalus/Daedalus.java
@@ -16,10 +16,10 @@ import com.google.gson.GsonBuilder;
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.*;
import org.itxtech.daedalus.server.DnsServer;
import org.itxtech.daedalus.server.DnsServerHelper;
+import org.itxtech.daedalus.service.DaedalusVpnService;
+import org.itxtech.daedalus.util.*;
import java.io.File;
import java.util.ArrayList;
@@ -50,7 +50,7 @@ public class Daedalus extends Application {
add(new DnsServer("dns.google/resolve", R.string.server_google_json));
}};
- public static final List RULES = new ArrayList() {{
+ public static final ArrayList RULES = new ArrayList() {{
add(new Rule("googlehosts/hosts", "googlehosts.hosts", Rule.TYPE_HOSTS,
"https://raw.githubusercontent.com/googlehosts/hosts/master/hosts-files/hosts", false));
add(new Rule("vokins/yhosts", "vokins.hosts", Rule.TYPE_HOSTS,
@@ -62,7 +62,7 @@ public class Daedalus extends Application {
"https://raw.githubusercontent.com/vokins/yhosts/master/dnsmasq/union.conf", false));
}};
- public static final String[] DEFAULT_TEST_DOMAINS = new String[]{
+ public static final String[] DEFAULT_TEST_DOMAINS = {
"google.com",
"twitter.com",
"youtube.com",
@@ -71,12 +71,11 @@ public class Daedalus extends Application {
};
public static Configurations configurations;
+ public static String rulePath;
+ public static String logPath;
+ private static String configPath;
- public static String rulePath = null;
- public static String logPath = null;
- private static String configPath = null;
-
- private static Daedalus instance = null;
+ private static Daedalus instance;
private SharedPreferences prefs;
private Thread mResolver;
@@ -85,12 +84,9 @@ public class Daedalus extends Application {
super.onCreate();
instance = this;
-
Logger.init();
-
mResolver = new Thread(new RuleResolver());
mResolver.start();
-
initData();
}
@@ -131,30 +127,30 @@ public class Daedalus extends Application {
}
public static void initRuleResolver() {
- ArrayList pendingLoad = new ArrayList<>();
- ArrayList usingRules = configurations.getUsingRules();
- if (usingRules != null && usingRules.size() > 0) {
- for (Rule rule : usingRules) {
- if (rule.isUsing()) {
- pendingLoad.add(rulePath + rule.getFileName());
- }
+ ArrayList pendingLoad = new ArrayList<>();
+ ArrayList usingRules = configurations.getUsingRules();
+ if (usingRules != null && usingRules.size() > 0) {
+ for (Rule rule : usingRules) {
+ if (rule.isUsing()) {
+ pendingLoad.add(rulePath + rule.getFileName());
}
- if (pendingLoad.size() > 0) {
- String[] arr = new String[pendingLoad.size()];
- pendingLoad.toArray(arr);
- switch (usingRules.get(0).getType()) {
- case Rule.TYPE_HOSTS:
- RuleResolver.startLoadHosts(arr);
- break;
- case Rule.TYPE_DNAMASQ:
- RuleResolver.startLoadDnsmasq(arr);
- break;
- }
- } else {
- RuleResolver.clear();
+ }
+ if (pendingLoad.size() > 0) {
+ String[] arr = new String[pendingLoad.size()];
+ pendingLoad.toArray(arr);
+ switch (usingRules.get(0).getType()) {
+ case Rule.TYPE_HOSTS:
+ RuleResolver.startLoadHosts(arr);
+ break;
+ case Rule.TYPE_DNAMASQ:
+ RuleResolver.startLoadDnsmasq(arr);
+ break;
}
} else {
RuleResolver.clear();
+ }
+ } else {
+ RuleResolver.clear();
}
}
diff --git a/app/src/main/java/org/itxtech/daedalus/activity/ConfigActivity.java b/app/src/main/java/org/itxtech/daedalus/activity/ConfigActivity.java
index b94e6d8..2252d30 100644
--- a/app/src/main/java/org/itxtech/daedalus/activity/ConfigActivity.java
+++ b/app/src/main/java/org/itxtech/daedalus/activity/ConfigActivity.java
@@ -44,12 +44,10 @@ public class ConfigActivity extends AppCompatActivity {
ConfigFragment fragment;
switch (getIntent().getIntExtra(LAUNCH_ACTION_FRAGMENT, LAUNCH_FRAGMENT_DNS_SERVER)) {
- case LAUNCH_FRAGMENT_DNS_SERVER:
- fragment = new DnsServerConfigFragment();
- break;
case LAUNCH_FRAGMENT_RULE:
fragment = new RuleConfigFragment();
break;
+ case LAUNCH_FRAGMENT_DNS_SERVER:
default://should never reach this
fragment = new DnsServerConfigFragment();
break;
diff --git a/app/src/main/java/org/itxtech/daedalus/util/DnsServersDetector.java b/app/src/main/java/org/itxtech/daedalus/util/DnsServersDetector.java
index cace002..1f24bef 100644
--- a/app/src/main/java/org/itxtech/daedalus/util/DnsServersDetector.java
+++ b/app/src/main/java/org/itxtech/daedalus/util/DnsServersDetector.java
@@ -50,8 +50,7 @@ public class DnsServersDetector {
private static String[] getServersMethodConnectivityManager(Context context) {
ArrayList priorityServersArrayList = new ArrayList<>();
ArrayList serversArrayList = new ArrayList<>();
- ConnectivityManager connectivityManager =
- (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager != null) {
for (Network network : connectivityManager.getAllNetworks()) {
NetworkInfo networkInfo = connectivityManager.getNetworkInfo(network);
@@ -83,15 +82,15 @@ public class DnsServersDetector {
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]+$";
+ String re1 = "^\\d+(\\.\\d+){3}$";
+ 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[] netdns = new String[]{"net.dns1", "net.dns2", "net.dns3", "net.dns4"};
+ for (String dns : netdns) {
+ Object[] args = new Object[]{dns};
String v = (String) method.invoke(null, args);
if (v != null && (v.matches(re1) || v.matches(re2)) && !serversArrayList.contains(v)) {
serversArrayList.add(v);
@@ -100,7 +99,6 @@ public class DnsServersDetector {
if (serversArrayList.size() > 0) {
return serversArrayList.toArray(new String[0]);
}
-
} catch (Exception ex) {
Logger.logException(ex);
}
@@ -125,7 +123,7 @@ public class DnsServersDetector {
private static Set methodExecParseProps(BufferedReader lineNumberReader) throws Exception {
String line;
- Set serversSet = new HashSet(10);
+ HashSet serversSet = new HashSet<>();
while ((line = lineNumberReader.readLine()) != null) {
int split = line.indexOf(METHOD_EXEC_PROP_DELIM);
if (split == -1) {
@@ -141,14 +139,16 @@ public class DnsServersDetector {
if (value.isEmpty()) {
continue;
}
- if (property.endsWith(".dns") || property.endsWith(".dns1") ||
- property.endsWith(".dns2") || property.endsWith(".dns3") ||
- property.endsWith(".dns4")) {
+ 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;
+ if (ip == null) {
+ continue;
+ }
value = ip.getHostAddress();
- if (value == null) continue;
- if (value.length() == 0) continue;
+ if (value == null || value.length() == 0) {
+ continue;
+ }
serversSet.add(value);
}
}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index b43264a..bb9e9e3 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -60,7 +60,7 @@
Log Size Limit
Manual
Visit GitHub wiki page.
- Don\'t cache ip for DNS servers
+ Don\'t cache IP for DNS servers
Debug Output
Use Dark Theme
DNS Query Method
From cb08d9ddeb74b2fdcaf4c9edf4f5e5fd455e3b61 Mon Sep 17 00:00:00 2001
From: PeratX <1215714524@qq.com>
Date: Wed, 23 Oct 2019 20:13:11 +0800
Subject: [PATCH 10/14] DaedalusVpnService: listen network change and update
upstream DNS
---
.../java/org/itxtech/daedalus/Daedalus.java | 21 ++--
.../fragment/GlobalConfigFragment.java | 8 --
.../daedalus/server/AbstractDnsServer.java | 14 ++-
.../daedalus/service/DaedalusVpnService.java | 116 ++++++++++++------
app/src/main/res/values-v21/styles.xml | 20 ---
app/src/main/res/values-zh-rCN/strings.xml | 2 +
app/src/main/res/values-zh-rTW/strings.xml | 2 +
app/src/main/res/values/strings.xml | 2 +
app/src/main/res/values/styles.xml | 17 ++-
app/src/main/res/xml/perf_settings.xml | 8 +-
10 files changed, 123 insertions(+), 87 deletions(-)
delete mode 100644 app/src/main/res/values-v21/styles.xml
diff --git a/app/src/main/java/org/itxtech/daedalus/Daedalus.java b/app/src/main/java/org/itxtech/daedalus/Daedalus.java
index 2043577..bfc3210 100644
--- a/app/src/main/java/org/itxtech/daedalus/Daedalus.java
+++ b/app/src/main/java/org/itxtech/daedalus/Daedalus.java
@@ -16,10 +16,14 @@ import com.google.gson.GsonBuilder;
import com.google.gson.JsonParseException;
import com.google.gson.stream.JsonReader;
import org.itxtech.daedalus.activity.MainActivity;
+import org.itxtech.daedalus.server.AbstractDnsServer;
import org.itxtech.daedalus.server.DnsServer;
import org.itxtech.daedalus.server.DnsServerHelper;
import org.itxtech.daedalus.service.DaedalusVpnService;
-import org.itxtech.daedalus.util.*;
+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 java.io.File;
import java.util.ArrayList;
@@ -206,19 +210,8 @@ public class Daedalus extends Application {
}
public static void activateService(Context context) {
- DaedalusVpnService.primaryServer = DnsServerHelper.getServerById(DnsServerHelper.getPrimary());
- DaedalusVpnService.secondaryServer = DnsServerHelper.getServerById(DnsServerHelper.getSecondary());
- if (getPrefs().getBoolean("settings_use_system_dns", false)) {
- String[] servers = DnsServersDetector.getServers(context);
- if (servers != null) {
- if (servers.length >= 2) {
- DaedalusVpnService.primaryServer = new DnsServer(servers[0], 0);
- DaedalusVpnService.secondaryServer = new DnsServer(servers[1], 0);
- } else {
- DaedalusVpnService.primaryServer = DaedalusVpnService.secondaryServer = new DnsServer(servers[0]);
- }
- }
- }
+ DaedalusVpnService.primaryServer = (AbstractDnsServer) DnsServerHelper.getServerById(DnsServerHelper.getPrimary()).clone();
+ DaedalusVpnService.secondaryServer = (AbstractDnsServer) DnsServerHelper.getServerById(DnsServerHelper.getSecondary()).clone();
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 8ad7410..56a9c19 100644
--- a/app/src/main/java/org/itxtech/daedalus/fragment/GlobalConfigFragment.java
+++ b/app/src/main/java/org/itxtech/daedalus/fragment/GlobalConfigFragment.java
@@ -39,7 +39,6 @@ public class GlobalConfigFragment extends PreferenceFragmentCompat {
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()));
@@ -110,13 +109,6 @@ 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/server/AbstractDnsServer.java b/app/src/main/java/org/itxtech/daedalus/server/AbstractDnsServer.java
index 1026c1e..d7760d5 100644
--- a/app/src/main/java/org/itxtech/daedalus/server/AbstractDnsServer.java
+++ b/app/src/main/java/org/itxtech/daedalus/server/AbstractDnsServer.java
@@ -1,5 +1,7 @@
package org.itxtech.daedalus.server;
+import androidx.annotation.NonNull;
+
/**
* Daedalus Project
*
@@ -11,7 +13,7 @@ package org.itxtech.daedalus.server;
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*/
-public class AbstractDnsServer {
+public class AbstractDnsServer implements Cloneable {
public static final int DNS_SERVER_DEFAULT_PORT = 53;
protected String address;
@@ -63,4 +65,14 @@ public class AbstractDnsServer {
public boolean isHttpsServer() {
return address.contains("/");
}
+
+ @NonNull
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (Exception ignored) {
+ }
+ return new AbstractDnsServer("", 0);
+ }
}
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 b315426..eb410e4 100644
--- a/app/src/main/java/org/itxtech/daedalus/service/DaedalusVpnService.java
+++ b/app/src/main/java/org/itxtech/daedalus/service/DaedalusVpnService.java
@@ -4,14 +4,18 @@ import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
import android.content.Context;
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;
import android.os.ParcelFileDescriptor;
import android.system.OsConstants;
import android.util.Log;
+import androidx.appcompat.app.AlertDialog;
import androidx.core.app.NotificationCompat;
import org.itxtech.daedalus.Daedalus;
import org.itxtech.daedalus.R;
@@ -19,10 +23,12 @@ import org.itxtech.daedalus.activity.MainActivity;
import org.itxtech.daedalus.provider.Provider;
import org.itxtech.daedalus.provider.ProviderPicker;
import org.itxtech.daedalus.receiver.StatusBarBroadcastReceiver;
+import org.itxtech.daedalus.server.AbstractDnsServer;
+import org.itxtech.daedalus.server.DnsServer;
+import org.itxtech.daedalus.server.DnsServerHelper;
+import org.itxtech.daedalus.util.DnsServersDetector;
import org.itxtech.daedalus.util.Logger;
import org.itxtech.daedalus.util.RuleResolver;
-import org.itxtech.daedalus.server.AbstractDnsServer;
-import org.itxtech.daedalus.server.DnsServerHelper;
import java.net.Inet4Address;
import java.net.Inet6Address;
@@ -54,20 +60,19 @@ public class DaedalusVpnService extends VpnService implements Runnable {
public static AbstractDnsServer primaryServer;
public static AbstractDnsServer secondaryServer;
+ private static InetAddress aliasPrimary;
+ private static InetAddress aliasSecondary;
private NotificationCompat.Builder notification = null;
-
private boolean running = false;
private long lastUpdate = 0;
private boolean statisticQuery;
private Provider provider;
private ParcelFileDescriptor descriptor;
-
private Thread mThread = null;
-
public HashMap dnsServers;
-
private static boolean activated = false;
+ private static BroadcastReceiver receiver;
public static boolean isActivated() {
return activated;
@@ -76,6 +81,44 @@ public class DaedalusVpnService extends VpnService implements Runnable {
@Override
public void onCreate() {
super.onCreate();
+ if (Daedalus.getPrefs().getBoolean("settings_use_system_dns", false)) {
+ registerReceiver(receiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ updateUpstreamServers(context);
+ }
+ }, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
+ }
+ }
+
+ public static void updateUpstreamServers(Context context) {
+ String[] servers = DnsServersDetector.getServers(context);
+ if (servers != null) {
+ if (servers.length >= 2 && (aliasPrimary == null || !aliasPrimary.getHostAddress().equals(servers[0])) &&
+ (aliasSecondary == null || !aliasSecondary.getHostAddress().equals(servers[0])) &&
+ (aliasPrimary == null || !aliasPrimary.getHostAddress().equals(servers[1])) &&
+ (aliasSecondary == null || !aliasSecondary.getHostAddress().equals(servers[1]))) {
+ primaryServer.setAddress(servers[0]);
+ primaryServer.setPort(DnsServer.DNS_SERVER_DEFAULT_PORT);
+ secondaryServer.setAddress(servers[1]);
+ secondaryServer.setPort(DnsServer.DNS_SERVER_DEFAULT_PORT);
+ } else if ((aliasPrimary == null || !aliasPrimary.getHostAddress().equals(servers[0])) &&
+ (aliasSecondary == null || !aliasSecondary.getHostAddress().equals(servers[0]))) {
+ primaryServer.setAddress(servers[0]);
+ primaryServer.setPort(DnsServer.DNS_SERVER_DEFAULT_PORT);
+ secondaryServer.setAddress(servers[0]);
+ secondaryServer.setPort(DnsServer.DNS_SERVER_DEFAULT_PORT);
+ } else {
+ StringBuilder buf = new StringBuilder();
+ for (String server : servers) {
+ buf.append(server).append(" ");
+ }
+ Logger.error("Invalid upstream DNS " + buf);
+ }
+ Logger.info("Upstream DNS updated: " + primaryServer.getAddress() + " " + secondaryServer.getAddress());
+ } else {
+ Logger.error("Cannot obtain upstream DNS server!");
+ }
}
@Override
@@ -85,7 +128,6 @@ public class DaedalusVpnService extends VpnService implements Runnable {
case ACTION_ACTIVATE:
activated = true;
if (Daedalus.getPrefs().getBoolean("settings_notification", true)) {
-
NotificationManager manager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationCompat.Builder builder;
@@ -127,12 +169,7 @@ public class DaedalusVpnService extends VpnService implements Runnable {
}
Daedalus.initRuleResolver();
-
- if (this.mThread == null) {
- this.mThread = new Thread(this, "DaedalusVpn");
- this.running = true;
- this.mThread.start();
- }
+ startThread();
Daedalus.updateShortcut(getApplicationContext());
if (MainActivity.getInstance() != null) {
MainActivity.getInstance().startActivity(new Intent(getApplicationContext(), MainActivity.class)
@@ -147,9 +184,20 @@ public class DaedalusVpnService extends VpnService implements Runnable {
return START_NOT_STICKY;
}
+ private void startThread() {
+ if (this.mThread == null) {
+ this.mThread = new Thread(this, "DaedalusVpn");
+ this.running = true;
+ this.mThread.start();
+ }
+ }
+
@Override
public void onDestroy() {
stopThread();
+ if (receiver != null) {
+ unregisterReceiver(receiver);
+ }
}
private void stopThread() {
@@ -203,7 +251,8 @@ public class DaedalusVpnService extends VpnService implements Runnable {
stopThread();
}
- private InetAddress addDnsServer(Builder builder, String format, byte[] ipv6Template, AbstractDnsServer addr) throws UnknownHostException {
+ private InetAddress addDnsServer(Builder builder, String format, byte[] ipv6Template, AbstractDnsServer addr)
+ throws UnknownHostException {
int size = dnsServers.size();
size++;
if (addr.getAddress().contains("/")) {//https uri
@@ -241,7 +290,6 @@ public class DaedalusVpnService extends VpnService implements Runnable {
new Intent(this, MainActivity.class).putExtra(MainActivity.LAUNCH_FRAGMENT, MainActivity.FRAGMENT_SETTINGS),
PendingIntent.FLAG_ONE_SHOT));
- //Set App Filter
if (Daedalus.getPrefs().getBoolean("settings_app_filter_switch", false)) {
ArrayList apps = Daedalus.configurations.getAppObjects();
if (apps.size() > 0) {
@@ -278,22 +326,16 @@ public class DaedalusVpnService extends VpnService implements Runnable {
statisticQuery = Daedalus.getPrefs().getBoolean("settings_count_query_times", false);
byte[] ipv6Template = new byte[]{32, 1, 13, (byte) (184 & 0xFF), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- if (primaryServer.getAddress().contains(":") || secondaryServer.getAddress().contains(":")) {//IPv6
- try {
- InetAddress addr = Inet6Address.getByAddress(ipv6Template);
- Log.d(TAG, "configure: Adding IPv6 address" + addr);
- builder.addAddress(addr, 120);
- } catch (Exception e) {
- Logger.logException(e);
+ try {
+ InetAddress addr = Inet6Address.getByAddress(ipv6Template);
+ Log.d(TAG, "configure: Adding IPv6 address" + addr);
+ builder.addAddress(addr, 120);
+ } catch (Exception e) {
+ Logger.logException(e);
- ipv6Template = null;
- }
- } else {
ipv6Template = null;
}
- InetAddress aliasPrimary;
- InetAddress aliasSecondary;
if (advanced) {
dnsServers = new HashMap<>();
aliasPrimary = addDnsServer(builder, format, ipv6Template, primaryServer);
@@ -303,8 +345,8 @@ public class DaedalusVpnService extends VpnService implements Runnable {
aliasSecondary = InetAddress.getByName(secondaryServer.getAddress());
}
- Logger.info("Daedalus VPN service is listening on " + primaryServer + " as " + aliasPrimary.getHostAddress());
- Logger.info("Daedalus VPN service is listening on " + secondaryServer + " as " + aliasSecondary.getHostAddress());
+ Logger.info("Daedalus VPN service is listening on " + primaryServer.getAddress() + " as " + aliasPrimary.getHostAddress());
+ Logger.info("Daedalus VPN service is listening on " + secondaryServer.getAddress() + " as " + aliasSecondary.getHostAddress());
builder.addDnsServer(aliasPrimary).addDnsServer(aliasSecondary);
if (advanced) {
@@ -325,13 +367,17 @@ public class DaedalusVpnService extends VpnService implements Runnable {
Thread.sleep(1000);
}
}
- } catch (
- InterruptedException ignored) {
- } catch (
- Exception e) {
+ } catch (InterruptedException ignored) {
+ } catch (Exception e) {
+ MainActivity.getInstance().runOnUiThread(() ->
+ new AlertDialog.Builder(MainActivity.getInstance())
+ .setTitle(R.string.error_occurred)
+ .setMessage(Logger.getExceptionMessage(e))
+ .setPositiveButton(android.R.string.ok, (d, id) -> {
+ })
+ .show());
Logger.logException(e);
} finally {
- Log.d(TAG, "quit");
stopThread();
}
}
@@ -354,11 +400,11 @@ public class DaedalusVpnService extends VpnService implements Runnable {
}
}
-
public static class VpnNetworkException extends Exception {
public VpnNetworkException(String s) {
super(s);
}
+
public VpnNetworkException(String s, Throwable t) {
super(s, t);
}
diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml
deleted file mode 100644
index 1a384e6..0000000
--- a/app/src/main/res/values-v21/styles.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index 79aca38..0aa5564 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -104,4 +104,6 @@
google.com
版本:
+
+ 启动时出现了一个错误
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index c4d4e93..0cd2f72 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -101,4 +101,6 @@
google.com
版本:
+
+ 啟動時出現了一個錯誤
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index bb9e9e3..285da87 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -112,4 +112,6 @@
Version:
Git commit:
GitHub
+
+ An error occurred at startup
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index ad9c1a1..a0f82ec 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -1,8 +1,5 @@
-
-
-
-
+
+
diff --git a/app/src/main/res/xml/perf_settings.xml b/app/src/main/res/xml/perf_settings.xml
index f4c90fc..589f1ea 100644
--- a/app/src/main/res/xml/perf_settings.xml
+++ b/app/src/main/res/xml/perf_settings.xml
@@ -6,10 +6,6 @@
android:key="settingsServer"
android:title="@string/settings_server">
-
+
Date: Wed, 23 Oct 2019 22:55:22 +0800
Subject: [PATCH 11/14] AppFilter: update
---
.../org/itxtech/daedalus/activity/AppFilterActivity.java | 8 ++------
.../org/itxtech/daedalus/fragment/DnsTestFragment.java | 1 -
.../org/itxtech/daedalus/provider/ProviderPicker.java | 2 +-
.../org/itxtech/daedalus/service/DaedalusVpnService.java | 3 ++-
4 files changed, 5 insertions(+), 9 deletions(-)
diff --git a/app/src/main/java/org/itxtech/daedalus/activity/AppFilterActivity.java b/app/src/main/java/org/itxtech/daedalus/activity/AppFilterActivity.java
index 65cc4a2..15d8bc3 100644
--- a/app/src/main/java/org/itxtech/daedalus/activity/AppFilterActivity.java
+++ b/app/src/main/java/org/itxtech/daedalus/activity/AppFilterActivity.java
@@ -40,7 +40,6 @@ import java.util.Objects;
* (at your option) any later version.
*/
public class AppFilterActivity extends AppCompatActivity {
-
private RecyclerViewAdapter adapter;
@Override
@@ -78,7 +77,7 @@ public class AppFilterActivity extends AppCompatActivity {
adapter.notifyDataSetChanged();
}
- private class AppObject {
+ private static class AppObject {
private String appName;
private String appPackageName;
private Drawable appIcon;
@@ -111,13 +110,11 @@ public class AppFilterActivity extends AppCompatActivity {
void updateList(ArrayList appObjects) {
appList = appObjects;
-
for (int i = 0; i < appObjects.size(); i++) {
if (Daedalus.configurations.getAppObjects().contains(appObjects.get(i).appPackageName)) {
checkStatus.put(i, true);
}
}
-
runOnUiThread(this::notifyDataSetChanged);
}
@@ -158,7 +155,7 @@ public class AppFilterActivity extends AppCompatActivity {
}
}
- private class RecyclerViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
+ private static class RecyclerViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private ImageView appIcon;
private TextView appName;
private CheckBox appCheck;
@@ -172,7 +169,6 @@ public class AppFilterActivity extends AppCompatActivity {
itemView.setOnClickListener(this);
}
-
@Override
public void onClick(View v) {
if (appCheck.isChecked()) {
diff --git a/app/src/main/java/org/itxtech/daedalus/fragment/DnsTestFragment.java b/app/src/main/java/org/itxtech/daedalus/fragment/DnsTestFragment.java
index c08cf3c..797ef84 100644
--- a/app/src/main/java/org/itxtech/daedalus/fragment/DnsTestFragment.java
+++ b/app/src/main/java/org/itxtech/daedalus/fragment/DnsTestFragment.java
@@ -151,7 +151,6 @@ public class DnsTestFragment extends ToolbarFragment {
}
}
-
private StringBuilder testServer(DnsQuery dnsQuery, Record.TYPE type, AbstractDnsServer server, String domain, StringBuilder testText) {
Logger.debug("Testing DNS server " + server.getRealName());
testText.append(getString(R.string.test_domain)).append(" ").append(domain).append("\n")
diff --git a/app/src/main/java/org/itxtech/daedalus/provider/ProviderPicker.java b/app/src/main/java/org/itxtech/daedalus/provider/ProviderPicker.java
index cd882bd..b1d56eb 100644
--- a/app/src/main/java/org/itxtech/daedalus/provider/ProviderPicker.java
+++ b/app/src/main/java/org/itxtech/daedalus/provider/ProviderPicker.java
@@ -15,7 +15,7 @@ import org.itxtech.daedalus.service.DaedalusVpnService;
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*/
-public class ProviderPicker {
+public abstract class ProviderPicker {
public static final int DNS_QUERY_METHOD_UDP = 0;
public static final int DNS_QUERY_METHOD_TCP = 1;
public static final int DNS_QUERY_METHOD_TLS = 2;
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 eb410e4..03ad1d8 100644
--- a/app/src/main/java/org/itxtech/daedalus/service/DaedalusVpnService.java
+++ b/app/src/main/java/org/itxtech/daedalus/service/DaedalusVpnService.java
@@ -91,7 +91,7 @@ public class DaedalusVpnService extends VpnService implements Runnable {
}
}
- public static void updateUpstreamServers(Context context) {
+ private static void updateUpstreamServers(Context context) {
String[] servers = DnsServersDetector.getServers(context);
if (servers != null) {
if (servers.length >= 2 && (aliasPrimary == null || !aliasPrimary.getHostAddress().equals(servers[0])) &&
@@ -197,6 +197,7 @@ public class DaedalusVpnService extends VpnService implements Runnable {
stopThread();
if (receiver != null) {
unregisterReceiver(receiver);
+ receiver = null;
}
}
From e2cea48c549710b8e3f20217f7fea7a78216cc67 Mon Sep 17 00:00:00 2001
From: PeratX <1215714524@qq.com>
Date: Mon, 18 Nov 2019 09:59:46 +0800
Subject: [PATCH 12/14] gradle: update wrapper
---
README.md | 2 +-
app/build.gradle | 4 +-
.../java/org/itxtech/daedalus/Daedalus.java | 2 +-
build.gradle | 4 +-
gradle/wrapper/gradle-wrapper.jar | Bin 54208 -> 58702 bytes
gradle/wrapper/gradle-wrapper.properties | 3 +-
gradlew | 225 +++++++++---------
gradlew.bat | 18 +-
8 files changed, 142 insertions(+), 116 deletions(-)
diff --git a/README.md b/README.md
index 4e8984a..eccde37 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# iTXTech Daedalus
-[![Donate](https://img.shields.io/badge/alipay-donate-yellow.svg)](https://qr.alipay.com/a6x07022gffiehykicipv1a)
+[![Donate](https://img.shields.io/badge/alipay-donate-yellow.svg)](https://qr.alipay.com/FKX04751EZDP0SQ0BOT137)
[![Build Status](https://travis-ci.org/iTXTech/Daedalus.svg?branch=master)](https://travis-ci.org/iTXTech/Daedalus)
[![Jenkins](https://img.shields.io/jenkins/s/http/dev.itxtech.org:10298/job/Daedalus.svg)](http://dev.itxtech.org:10298/job/Daedalus/)
diff --git a/app/build.gradle b/app/build.gradle
index 0a4bcf8..9922324 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -57,7 +57,7 @@ dependencies {
implementation 'androidx.percentlayout:percentlayout:1.0.0'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'com.google.android.material:material:1.2.0-alpha01'
- implementation 'androidx.recyclerview:recyclerview:1.1.0-beta05'
+ implementation 'androidx.recyclerview:recyclerview:1.1.0-rc01'
implementation 'androidx.preference:preference:1.1.0'
//DNS
implementation 'org.pcap4j:pcap4j-core:1.8.2'
@@ -66,7 +66,7 @@ dependencies {
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.squareup.okhttp3:okhttp:4.2.0'
//Analytics
- googleReleaseImplementation 'com.google.firebase:firebase-core:17.2.0'
+ googleReleaseImplementation 'com.google.firebase:firebase-core:17.2.1'
googleReleaseImplementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
}
diff --git a/app/src/main/java/org/itxtech/daedalus/Daedalus.java b/app/src/main/java/org/itxtech/daedalus/Daedalus.java
index bfc3210..d64a4cd 100644
--- a/app/src/main/java/org/itxtech/daedalus/Daedalus.java
+++ b/app/src/main/java/org/itxtech/daedalus/Daedalus.java
@@ -245,7 +245,7 @@ public class Daedalus extends Application {
}
public static void donate() {
- openUri("https://qr.alipay.com/a6x07022gffiehykicipv1a");
+ openUri("https://qr.alipay.com/FKX04751EZDP0SQ0BOT137");
}
public static void openUri(String uri) {
diff --git a/build.gradle b/build.gradle
index da4865c..8b2c774 100644
--- a/build.gradle
+++ b/build.gradle
@@ -9,8 +9,8 @@ buildscript {
}
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.5.1'
- classpath 'com.google.gms:google-services:4.3.2'
+ classpath 'com.android.tools.build:gradle:3.5.2'
+ classpath 'com.google.gms:google-services:4.3.3'
classpath 'io.fabric.tools:gradle:1.31.0'
}
}
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index b99972fe99807d157125992f11f7c94bb240659a..cc4fdc293d0e50b0ad9b65c16e7ddd1db2f6025b 100644
GIT binary patch
literal 58702
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