mirror of
https://github.com/emanuele-f/PCAPdroid.git
synced 2026-07-03 21:21:12 +08:00
Add ability to choose DNS servers
The DNS servers used in VPN mode are now configurable. It's now possible to ignore the system DNS server and use the specified ones. Cloudflare DNS is now the default DNS server, which has a no-logs policy. Closes #275
This commit is contained in:
parent
85e1ceb88e
commit
68bd85b615
@ -160,9 +160,6 @@ public class CaptureService extends VpnService implements Runnable {
|
||||
* Max estimated memory usage: less than 4 MB (+8 MB with payload mode minimal). */
|
||||
public static final int CONNECTIONS_LOG_SIZE = 8192;
|
||||
|
||||
public static final String FALLBACK_DNS_SERVER = "8.8.8.8";
|
||||
public static final String IPV6_DNS_SERVER = "2001:4860:4860::8888";
|
||||
|
||||
/* The IP address of the virtual network interface */
|
||||
public static final String VPN_IP_ADDRESS = "10.215.173.1";
|
||||
public static final String VPN_IP6_ADDRESS = "fd00:2:fd00:1:fd00:1:fd00:1";
|
||||
@ -259,7 +256,8 @@ public class CaptureService extends VpnService implements Runnable {
|
||||
mSettings.root_capture = false;
|
||||
|
||||
// Retrieve DNS server
|
||||
dns_server = FALLBACK_DNS_SERVER;
|
||||
String fallbackDnsV4 = Prefs.getDnsServerV4(mPrefs);
|
||||
dns_server = fallbackDnsV4;
|
||||
mBlockPrivateDns = false;
|
||||
mStrictDnsNoticeShown = false;
|
||||
mDnsEncrypted = false;
|
||||
@ -284,13 +282,16 @@ public class CaptureService extends VpnService implements Runnable {
|
||||
if(net != null) {
|
||||
handleLinkProperties(cm.getLinkProperties(net));
|
||||
|
||||
dns_server = Utils.getDnsServer(cm, net);
|
||||
if(dns_server == null)
|
||||
dns_server = FALLBACK_DNS_SERVER;
|
||||
else {
|
||||
mMonitoredNetwork = net.getNetworkHandle();
|
||||
registerNetworkCallbacks();
|
||||
}
|
||||
if(Prefs.useSystemDns(mPrefs) || mSettings.root_capture) {
|
||||
dns_server = Utils.getDnsServer(cm, net);
|
||||
if (dns_server == null)
|
||||
dns_server = fallbackDnsV4;
|
||||
else {
|
||||
mMonitoredNetwork = net.getNetworkHandle();
|
||||
registerNetworkCallbacks();
|
||||
}
|
||||
} else
|
||||
dns_server = fallbackDnsV4;
|
||||
}
|
||||
}
|
||||
|
||||
@ -405,7 +406,7 @@ public class CaptureService extends VpnService implements Runnable {
|
||||
builder.addRoute("2000::", 3);
|
||||
|
||||
try {
|
||||
builder.addDnsServer(InetAddress.getByName(IPV6_DNS_SERVER));
|
||||
builder.addDnsServer(InetAddress.getByName(Prefs.getDnsServerV6(mPrefs)));
|
||||
} catch (UnknownHostException e) {
|
||||
Log.w(TAG, "Could not set IPv6 DNS server");
|
||||
}
|
||||
@ -688,6 +689,7 @@ public class CaptureService extends VpnService implements Runnable {
|
||||
if(mNetworkCallback != null)
|
||||
return;
|
||||
|
||||
String fallbackDns = Prefs.getDnsServerV4(mPrefs);
|
||||
ConnectivityManager cm = (ConnectivityManager) getSystemService(Service.CONNECTIVITY_SERVICE);
|
||||
mNetworkCallback = new ConnectivityManager.NetworkCallback() {
|
||||
@Override
|
||||
@ -697,8 +699,8 @@ public class CaptureService extends VpnService implements Runnable {
|
||||
// If the network goes offline we roll back to the fallback DNS server to
|
||||
// avoid possibly using a private IP DNS server not reachable anymore
|
||||
if(network.getNetworkHandle() == mMonitoredNetwork) {
|
||||
Log.i(TAG, "Main network " + network + " lost, using fallback DNS " + FALLBACK_DNS_SERVER);
|
||||
dns_server = FALLBACK_DNS_SERVER;
|
||||
Log.i(TAG, "Main network " + network + " lost, using fallback DNS " + fallbackDns);
|
||||
dns_server = fallbackDns;
|
||||
mMonitoredNetwork = 0;
|
||||
unregisterNetworkCallbacks();
|
||||
|
||||
@ -728,7 +730,7 @@ public class CaptureService extends VpnService implements Runnable {
|
||||
e.printStackTrace();
|
||||
|
||||
Log.w(TAG, "registerNetworkCallback failed, DNS server detection disabled");
|
||||
dns_server = FALLBACK_DNS_SERVER;
|
||||
dns_server = fallbackDns;
|
||||
mNetworkCallback = null;
|
||||
}
|
||||
}
|
||||
@ -1195,7 +1197,7 @@ public class CaptureService extends VpnService implements Runnable {
|
||||
return(dns_server);
|
||||
}
|
||||
|
||||
public String getIpv6DnsServer() { return(IPV6_DNS_SERVER); }
|
||||
public String getIpv6DnsServer() { return(Prefs.getDnsServerV4(mPrefs)); }
|
||||
|
||||
public int getSocks5Enabled() { return mSocks5Enabled ? 1 : 0; }
|
||||
|
||||
|
||||
@ -127,6 +127,7 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Random;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
@ -1432,6 +1433,19 @@ public class Utils {
|
||||
}
|
||||
}
|
||||
|
||||
// https://mkyong.com/regular-expressions/how-to-validate-ip-address-with-regular-expression/
|
||||
private static final Pattern IPV4_PATTERN = Pattern.compile(
|
||||
"^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\\.(?!$)|$)){4}$");
|
||||
|
||||
public static boolean validateIpv4Address(String s) {
|
||||
Matcher matcher = IPV4_PATTERN.matcher(s);
|
||||
return matcher.matches();
|
||||
}
|
||||
|
||||
public static boolean validateIpv6Address(String s) {
|
||||
return validateIpAddress(s) && !validateIpv4Address(s);
|
||||
}
|
||||
|
||||
// rough validation
|
||||
public static boolean validateHost(String host) {
|
||||
int len = host.length();
|
||||
|
||||
@ -44,6 +44,7 @@ import com.emanuelef.remote_capture.Log;
|
||||
import com.emanuelef.remote_capture.PCAPdroid;
|
||||
import com.emanuelef.remote_capture.Utils;
|
||||
import com.emanuelef.remote_capture.MitmAddon;
|
||||
import com.emanuelef.remote_capture.fragments.DnsSettings;
|
||||
import com.emanuelef.remote_capture.fragments.GeoipSettings;
|
||||
import com.emanuelef.remote_capture.model.Prefs;
|
||||
import com.emanuelef.remote_capture.R;
|
||||
@ -83,6 +84,9 @@ public class SettingsActivity extends BaseActivity implements PreferenceFragment
|
||||
if(prefKey.equals("geolocation")) {
|
||||
targetFragment = new GeoipSettings();
|
||||
setTitle(R.string.geolocation);
|
||||
} else if(prefKey.equals("dns_settings")) {
|
||||
targetFragment = new DnsSettings();
|
||||
setTitle(R.string.dns_servers);
|
||||
}
|
||||
|
||||
if(targetFragment != null) {
|
||||
@ -131,6 +135,7 @@ public class SettingsActivity extends BaseActivity implements PreferenceFragment
|
||||
private DropDownPreference mIpMode;
|
||||
private DropDownPreference mCapInterface;
|
||||
private Preference mVpnExceptions;
|
||||
private Preference mDnsSettings;
|
||||
private Preference mPortMapping;
|
||||
private Preference mMitmWizard;
|
||||
private SwitchPreference mMalwareDetectionEnabled;
|
||||
@ -238,21 +243,25 @@ public class SettingsActivity extends BaseActivity implements PreferenceFragment
|
||||
|
||||
private void setupCapturePrefs() {
|
||||
mCapInterface = requirePreference(Prefs.PREF_CAPTURE_INTERFACE);
|
||||
mVpnExceptions = requirePreference(Prefs.PREF_VPN_EXCEPTIONS);
|
||||
mPortMapping = requirePreference(Prefs.PREF_PORT_MAPPING);
|
||||
refreshInterfaces();
|
||||
|
||||
mRootCaptureEnabled = requirePreference(Prefs.PREF_ROOT_CAPTURE);
|
||||
if(Utils.isRootAvailable()) {
|
||||
mRootCaptureEnabled.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
rootCaptureHideShow((Boolean) newValue);
|
||||
checkDecrpytionWithRoot((Boolean) newValue, mTlsDecryption.isChecked());
|
||||
return true;
|
||||
});
|
||||
} else
|
||||
mRootCaptureEnabled.setVisible(false);
|
||||
|
||||
mDnsSettings = requirePreference("dns_settings");;
|
||||
mVpnExceptions = requirePreference(Prefs.PREF_VPN_EXCEPTIONS);
|
||||
mVpnExceptions.setOnPreferenceClickListener(preference -> {
|
||||
Intent intent = new Intent(requireContext(), VpnExemptionsActivity.class);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
});
|
||||
|
||||
mPortMapping.setOnPreferenceClickListener(preference -> {
|
||||
Intent intent = new Intent(requireContext(), PortMapActivity.class);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void setupSecurityPrefs() {
|
||||
@ -351,23 +360,18 @@ public class SettingsActivity extends BaseActivity implements PreferenceFragment
|
||||
});
|
||||
|
||||
DropDownPreference appTheme = requirePreference(Prefs.PREF_APP_THEME);
|
||||
|
||||
appTheme.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
Utils.setAppTheme(newValue.toString());
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
mRootCaptureEnabled = requirePreference(Prefs.PREF_ROOT_CAPTURE);
|
||||
|
||||
if(Utils.isRootAvailable()) {
|
||||
mRootCaptureEnabled.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
rootCaptureHideShow((Boolean) newValue);
|
||||
checkDecrpytionWithRoot((Boolean) newValue, mTlsDecryption.isChecked());
|
||||
return true;
|
||||
});
|
||||
} else
|
||||
mRootCaptureEnabled.setVisible(false);
|
||||
mPortMapping = requirePreference(Prefs.PREF_PORT_MAPPING);
|
||||
mPortMapping.setOnPreferenceClickListener(preference -> {
|
||||
Intent intent = new Intent(requireContext(), PortMapActivity.class);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
});
|
||||
|
||||
mIpMode = requirePreference(Prefs.PREF_IP_MODE);
|
||||
|
||||
@ -398,6 +402,7 @@ public class SettingsActivity extends BaseActivity implements PreferenceFragment
|
||||
mIpMode.setVisible(!enabled);
|
||||
mCapInterface.setVisible(enabled);
|
||||
mVpnExceptions.setVisible(!enabled);
|
||||
mDnsSettings.setVisible(!enabled);
|
||||
mPortMapping.setVisible(!enabled);
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* This file is part of PCAPdroid.
|
||||
*
|
||||
* PCAPdroid 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.
|
||||
*
|
||||
* PCAPdroid is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PCAPdroid. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2020-22 - Emanuele Faranda
|
||||
*/
|
||||
|
||||
package com.emanuelef.remote_capture.fragments;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.preference.EditTextPreference;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
|
||||
import com.emanuelef.remote_capture.R;
|
||||
import com.emanuelef.remote_capture.Utils;
|
||||
import com.emanuelef.remote_capture.model.Prefs;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class DnsSettings extends PreferenceFragmentCompat {
|
||||
@Override
|
||||
public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable String rootKey) {
|
||||
setPreferencesFromResource(R.xml.dns_preferences, rootKey);
|
||||
|
||||
EditTextPreference p1 = Objects.requireNonNull(findPreference(Prefs.PREF_DNS_SERVER_V4));
|
||||
p1.setOnPreferenceChangeListener((preference, newValue) -> Utils.validateIpv4Address(newValue.toString()));
|
||||
|
||||
EditTextPreference p2 = Objects.requireNonNull(findPreference(Prefs.PREF_DNS_SERVER_V6));
|
||||
p2.setOnPreferenceChangeListener((preference, newValue) -> Utils.validateIpv6Address(newValue.toString()));
|
||||
}
|
||||
}
|
||||
@ -91,6 +91,9 @@ public class Prefs {
|
||||
public static final String PREF_PAYLOAD_NOTICE_ACK = "payload_notice";
|
||||
public static final String PREF_REMOTE_COLLECTOR_ACK = "remote_collector_notice";
|
||||
public static final String PREF_MITMPROXY_OPTS = "mitmproxy_opts";
|
||||
public static final String PREF_DNS_SERVER_V4 = "dns_v4";
|
||||
public static final String PREF_DNS_SERVER_V6 = "dns_v6";
|
||||
public static final String PREF_USE_SYSTEM_DNS = "system_dns";
|
||||
|
||||
public enum DumpMode {
|
||||
NONE,
|
||||
@ -192,6 +195,9 @@ public class Prefs {
|
||||
public static boolean isFirewallWhitelistInitialized(SharedPreferences p) { return(p.getInt(PREF_FIREWALL_WHITELIST_INIT_VER, 0) == FIREWALL_WHITELIST_INIT_VER); }
|
||||
public static String getMitmproxyOpts(SharedPreferences p) { return(p.getString(PREF_MITMPROXY_OPTS, "")); }
|
||||
public static boolean isPortMappingEnabled(SharedPreferences p) { return(p.getBoolean(PREF_PORT_MAPPING_ENABLED, true)); }
|
||||
public static boolean useSystemDns(SharedPreferences p) { return(p.getBoolean(PREF_USE_SYSTEM_DNS, true)); }
|
||||
public static String getDnsServerV4(SharedPreferences p) { return(p.getString(PREF_DNS_SERVER_V4, "1.1.1.1")); }
|
||||
public static String getDnsServerV6(SharedPreferences p) { return(p.getString(PREF_DNS_SERVER_V6, "2606:4700:4700::1111")); }
|
||||
|
||||
public static String asString(Context ctx) {
|
||||
SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(ctx);
|
||||
|
||||
@ -386,6 +386,8 @@ static void load_dns_servers(pcapdroid_t *pd) {
|
||||
blacklist_add_ipstr(pd->vpn.known_dns_servers, "2001:4860:4860::8844");
|
||||
blacklist_add_ipstr(pd->vpn.known_dns_servers, "2606:4700:4700::64");
|
||||
blacklist_add_ipstr(pd->vpn.known_dns_servers, "2606:4700:4700::6400");
|
||||
blacklist_add_ipstr(pd->vpn.known_dns_servers, "2606:4700:4700::1111");
|
||||
blacklist_add_ipstr(pd->vpn.known_dns_servers, "2606:4700:4700::1001");
|
||||
|
||||
// Domains (only private DNS)
|
||||
// https://help.firewalla.com/hc/en-us/articles/360060661873-Dealing-DNS-over-HTTPS-and-DNS-over-TLS-on-your-network
|
||||
|
||||
@ -436,4 +436,10 @@
|
||||
<string name="items_delete_confirm">Delete the selected items?</string>
|
||||
<string name="ip_address">IP address</string>
|
||||
<string name="rule_exists">Rule already defined</string>
|
||||
<string name="dns_servers">DNS servers</string>
|
||||
<string name="dns_servers_summary">Configure the DNS servers to use during the capture</string>
|
||||
<string name="ipv4_dns_server">IPv4 DNS server</string>
|
||||
<string name="ipv6_dns_server">IPv6 DNS server</string>
|
||||
<string name="use_system_dns">Use system DNS</string>
|
||||
<string name="use_system_dns_summary">Use the system DNS servers if possible</string>
|
||||
</resources>
|
||||
|
||||
25
app/src/main/res/xml/dns_preferences.xml
Normal file
25
app/src/main/res/xml/dns_preferences.xml
Normal file
@ -0,0 +1,25 @@
|
||||
<PreferenceScreen
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<SwitchPreference
|
||||
app:key="system_dns"
|
||||
android:title="@string/use_system_dns"
|
||||
app:iconSpaceReserved="false"
|
||||
app:summary="@string/use_system_dns_summary"
|
||||
android:defaultValue="true" />
|
||||
|
||||
<EditTextPreference
|
||||
app:key="dns_v4"
|
||||
app:title="@string/ipv4_dns_server"
|
||||
app:iconSpaceReserved="false"
|
||||
app:defaultValue="1.1.1.1"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<EditTextPreference
|
||||
app:key="dns_v6"
|
||||
app:title="@string/ipv6_dns_server"
|
||||
app:iconSpaceReserved="false"
|
||||
app:defaultValue="2606:4700:4700::1111"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
</PreferenceScreen>
|
||||
@ -113,12 +113,6 @@
|
||||
app:iconSpaceReserved="false"
|
||||
app:defaultValue="8050"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<Preference
|
||||
app:key="port_mapping"
|
||||
app:title="@string/port_mapping"
|
||||
app:summary="@string/port_mapping_summary"
|
||||
app:iconSpaceReserved="false" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory app:title="@string/capture_prefs" app:iconSpaceReserved="false" >
|
||||
@ -142,6 +136,13 @@
|
||||
app:summary="@string/vpn_exemptions_summary"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<Preference
|
||||
android:key="dns_settings"
|
||||
app:title="@string/dns_servers"
|
||||
app:summary="@string/dns_servers_summary"
|
||||
app:iconSpaceReserved="false"
|
||||
app:fragment="com.emanuelef.remote_capture.fragments.DnsSettings" />
|
||||
|
||||
<SwitchPreference
|
||||
app:key="start_at_boot"
|
||||
android:title="@string/start_at_boot"
|
||||
@ -201,6 +202,12 @@
|
||||
app:defaultValue="system"
|
||||
app:useSimpleSummaryProvider="true"/>
|
||||
|
||||
<Preference
|
||||
app:key="port_mapping"
|
||||
app:title="@string/port_mapping"
|
||||
app:summary="@string/port_mapping_summary"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<DropDownPreference
|
||||
app:key="ip_mode"
|
||||
app:title="@string/ip_mode"
|
||||
@ -214,7 +221,6 @@
|
||||
app:key="control_permissions"
|
||||
app:title="@string/control_permissions"
|
||||
app:iconSpaceReserved="false"
|
||||
android:summary="@string/control_permissions_summary">
|
||||
</Preference>
|
||||
android:summary="@string/control_permissions_summary" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user