Implemented local hosts resolver
This commit is contained in:
parent
e6d6d5ee92
commit
1422bcc737
@ -5,6 +5,8 @@
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
|
||||
<application
|
||||
android:name=".Daedalus"
|
||||
|
@ -14,6 +14,7 @@ import android.util.Log;
|
||||
import org.itxtech.daedalus.activity.MainActivity;
|
||||
import org.itxtech.daedalus.service.DaedalusVpnService;
|
||||
import org.itxtech.daedalus.util.DnsServer;
|
||||
import org.itxtech.daedalus.util.HostsResolver;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -56,12 +57,15 @@ public class Daedalus extends Application {
|
||||
|
||||
private static Daedalus instance = null;
|
||||
private static SharedPreferences prefs;
|
||||
private static Thread mHostsResolver;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
initConfig();
|
||||
mHostsResolver = new Thread(new HostsResolver());
|
||||
mHostsResolver.start();
|
||||
|
||||
instance = this;
|
||||
}
|
||||
@ -81,6 +85,10 @@ public class Daedalus extends Application {
|
||||
|
||||
instance = null;
|
||||
prefs = null;
|
||||
HostsResolver.shutdown();
|
||||
mHostsResolver.interrupt();
|
||||
HostsResolver.clean();
|
||||
mHostsResolver = null;
|
||||
}
|
||||
|
||||
public Intent getServiceIntent() {
|
||||
|
@ -1,11 +1,16 @@
|
||||
package org.itxtech.daedalus.activity;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.FragmentManager;
|
||||
import android.app.FragmentTransaction;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.design.widget.NavigationView;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.view.GravityCompat;
|
||||
import android.support.v4.widget.DrawerLayout;
|
||||
import android.support.v7.app.ActionBarDrawerToggle;
|
||||
@ -22,6 +27,7 @@ import org.itxtech.daedalus.fragment.AboutFragment;
|
||||
import org.itxtech.daedalus.fragment.DnsTestFragment;
|
||||
import org.itxtech.daedalus.fragment.MainFragment;
|
||||
import org.itxtech.daedalus.fragment.SettingsFragment;
|
||||
import org.itxtech.daedalus.util.HostsResolver;
|
||||
|
||||
/**
|
||||
* Daedalus Project
|
||||
@ -49,6 +55,12 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||
public static final int FRAGMENT_SETTINGS = 2;
|
||||
public static final int FRAGMENT_ABOUT = 3;
|
||||
|
||||
private static final int REQUEST_EXTERNAL_STORAGE = 1;
|
||||
private static String[] PERMISSIONS_STORAGE = {
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
};
|
||||
|
||||
private static MainActivity instance = null;
|
||||
|
||||
private MainFragment mMain;
|
||||
@ -72,6 +84,8 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||
setTheme(R.style.AppTheme_NoActionBar_TransparentStatusBar);
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
initHostsResolver();
|
||||
|
||||
instance = this;
|
||||
|
||||
setContentView(R.layout.activity_main);
|
||||
@ -104,6 +118,23 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||
Log.d(TAG, "onCreate");
|
||||
}
|
||||
|
||||
public void initHostsResolver() {
|
||||
if (Daedalus.getPrefs().getBoolean("settings_local_host_resolve", false)) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
int permission = ActivityCompat.checkSelfPermission(this.getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||
if (permission != PackageManager.PERMISSION_GRANTED) {
|
||||
ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
|
||||
}
|
||||
}
|
||||
HostsResolver.startLoad(getExternalFilesDir(null).getPath() + "/hosts");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostCreate(Bundle savedInstanceState) {
|
||||
super.onPostCreate(savedInstanceState);
|
||||
|
@ -11,6 +11,7 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import org.itxtech.daedalus.Daedalus;
|
||||
import org.itxtech.daedalus.R;
|
||||
import org.itxtech.daedalus.activity.MainActivity;
|
||||
import org.itxtech.daedalus.util.DnsServer;
|
||||
|
||||
/**
|
||||
@ -69,12 +70,9 @@ public class SettingsFragment extends PreferenceFragment {
|
||||
});
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
SwitchPreference countQueryTimes = (SwitchPreference) findPreference("settings_count_query_times");
|
||||
countQueryTimes.setChecked(false);
|
||||
countQueryTimes.setEnabled(false);
|
||||
SwitchPreference autoBoot = (SwitchPreference) findPreference("settings_boot");
|
||||
autoBoot.setChecked(false);
|
||||
autoBoot.setEnabled(false);
|
||||
SwitchPreference advanced = (SwitchPreference) findPreference("settings_advanced_switch");
|
||||
advanced.setEnabled(false);
|
||||
advanced.setChecked(false);
|
||||
}
|
||||
|
||||
SwitchPreference advanced = (SwitchPreference) findPreference("settings_advanced_switch");
|
||||
@ -85,6 +83,16 @@ public class SettingsFragment extends PreferenceFragment {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
SwitchPreference localHosts = (SwitchPreference) findPreference("settings_local_host_resolve");
|
||||
localHosts.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
MainActivity.getInstance().initHostsResolver();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
updateAdvancedOptions(advanced.isChecked());
|
||||
}
|
||||
|
||||
|
@ -17,11 +17,14 @@ import android.system.OsConstants;
|
||||
import android.system.StructPollfd;
|
||||
import android.util.Log;
|
||||
import de.measite.minidns.DNSMessage;
|
||||
import de.measite.minidns.Record;
|
||||
import de.measite.minidns.record.A;
|
||||
import de.measite.minidns.util.InetAddressUtil;
|
||||
import org.itxtech.daedalus.Daedalus;
|
||||
import org.itxtech.daedalus.R;
|
||||
import org.itxtech.daedalus.activity.MainActivity;
|
||||
import org.itxtech.daedalus.receiver.StatusBarBroadcastReceiver;
|
||||
import org.itxtech.daedalus.util.HostsResolver;
|
||||
import org.pcap4j.packet.*;
|
||||
import org.pcap4j.packet.factory.PacketFactoryPropertiesLoader;
|
||||
import org.pcap4j.util.PropertiesLoader;
|
||||
@ -61,6 +64,7 @@ public class DaedalusVpnService extends VpnService implements Runnable {
|
||||
private static NotificationCompat.Builder notification = null;
|
||||
|
||||
private static long dnsQueryTimes = 0;
|
||||
private static boolean localHostsResolve = false;
|
||||
|
||||
private Thread mThread = null;
|
||||
private ParcelFileDescriptor descriptor;
|
||||
@ -205,6 +209,7 @@ public class DaedalusVpnService extends VpnService implements Runnable {
|
||||
|
||||
boolean advanced = Daedalus.getPrefs().getBoolean("settings_advanced_switch", false);
|
||||
boolean statisticQuery = Daedalus.getPrefs().getBoolean("settings_count_query_times", false);
|
||||
localHostsResolve = Daedalus.getPrefs().getBoolean("settings_local_host_resolve", false);
|
||||
Log.d(TAG, "tun0 add " + format + " pServ " + primaryServer + " sServ " + secondaryServer);
|
||||
Inet4Address primaryDNSServer = InetAddressUtil.ipv4From(primaryServer);
|
||||
Inet4Address secondaryDNSServer = InetAddressUtil.ipv4From(secondaryServer);
|
||||
@ -503,9 +508,30 @@ public class DaedalusVpnService extends VpnService implements Runnable {
|
||||
return;
|
||||
}
|
||||
String dnsQueryName = dnsMsg.getQuestion().name.toString();
|
||||
Log.i(TAG, "handleDnsRequest: DNS Name " + dnsQueryName + " , sending to " + destAddr);
|
||||
DatagramPacket outPacket = new DatagramPacket(dnsRawData, 0, dnsRawData.length, destAddr, parsedUdp.getHeader().getDstPort().valueAsInt());
|
||||
forwardPacket(outPacket, parsedPacket);
|
||||
|
||||
try {
|
||||
if (localHostsResolve && HostsResolver.canResolve(dnsQueryName)) {
|
||||
String response = HostsResolver.resolve(dnsQueryName);
|
||||
Log.i(TAG, "handleDnsRequest: DNS Name " + dnsQueryName + " Address " + response + ", using local hosts to resolve.");
|
||||
DNSMessage.Builder builder = dnsMsg.asBuilder();
|
||||
int[] ip = new int[4];
|
||||
byte i = 0;
|
||||
for (String block : response.split("\\.")) {
|
||||
ip[i] = Integer.parseInt(block);
|
||||
i++;
|
||||
}
|
||||
Record<A> answer = new Record<>(dnsQueryName, Record.TYPE.getType(A.class), 1, 255, new A(ip[0], ip[1], ip[2], ip[3]));
|
||||
builder.setQuestions(null);
|
||||
builder.addAnswer(answer);
|
||||
handleDnsResponse(parsedPacket, builder.build().toArray());
|
||||
} else {
|
||||
Log.i(TAG, "handleDnsRequest: DNS Name " + dnsQueryName + " , sending to " + destAddr);
|
||||
DatagramPacket outPacket = new DatagramPacket(dnsRawData, 0, dnsRawData.length, destAddr, parsedUdp.getHeader().getDstPort().valueAsInt());
|
||||
forwardPacket(outPacket, parsedPacket);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
static class VpnNetworkException extends Exception {
|
||||
|
109
app/src/main/java/org/itxtech/daedalus/util/HostsResolver.java
Normal file
109
app/src/main/java/org/itxtech/daedalus/util/HostsResolver.java
Normal file
@ -0,0 +1,109 @@
|
||||
package org.itxtech.daedalus.util;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Daedalus Project
|
||||
*
|
||||
* @author iTXTech
|
||||
* @link https://itxtech.org
|
||||
* <p>
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*/
|
||||
public class HostsResolver implements Runnable {
|
||||
private static final String TAG = "DHostsResolver";
|
||||
|
||||
public static final int STATUS_LOADED = 0;
|
||||
public static final int STATUS_LOADING = 1;
|
||||
public static final int STATUS_NOT_LOADED = 2;
|
||||
public static final int STATUS_PENDING_LOAD = 3;
|
||||
|
||||
private static int status = STATUS_NOT_LOADED;
|
||||
private static String fileName;
|
||||
private static HashMap<String, String> hosts;
|
||||
private static boolean shutdown = false;
|
||||
|
||||
public HostsResolver() {
|
||||
status = STATUS_NOT_LOADED;
|
||||
fileName = "";
|
||||
shutdown = false;
|
||||
}
|
||||
|
||||
public static void shutdown() {
|
||||
shutdown = true;
|
||||
}
|
||||
|
||||
public static boolean isLoaded() {
|
||||
return status == STATUS_LOADED;
|
||||
}
|
||||
|
||||
public static void startLoad(String loadFile) {
|
||||
Log.d(TAG, "Loading file " + loadFile);
|
||||
fileName = loadFile;
|
||||
status = STATUS_PENDING_LOAD;
|
||||
}
|
||||
|
||||
public static void clean() {
|
||||
hosts = null;
|
||||
}
|
||||
|
||||
public static boolean canResolve(String hostname) {
|
||||
return hosts.containsKey(hostname);
|
||||
}
|
||||
|
||||
public static String resolve(String hostname) {
|
||||
return hosts.get(hostname);
|
||||
}
|
||||
|
||||
private void load() {
|
||||
try {
|
||||
status = STATUS_LOADING;
|
||||
File file = new File(fileName);
|
||||
if (file.exists() && file.canRead()) {
|
||||
FileInputStream stream = new FileInputStream(file);
|
||||
BufferedReader dataIO = new BufferedReader(new InputStreamReader(stream));
|
||||
hosts = new HashMap<>();
|
||||
String strLine;
|
||||
String[] data;
|
||||
while ((strLine = dataIO.readLine()) != null) {
|
||||
//Log.d(TAG, strLine);
|
||||
if (!strLine.equals("") && !strLine.startsWith("#")) {
|
||||
data = strLine.split("\\s+");
|
||||
hosts.put(data[1], data[0]);
|
||||
Log.d(TAG, "Putting " + data[0] + " " + data[1]);
|
||||
}
|
||||
}
|
||||
|
||||
dataIO.close();
|
||||
stream.close();
|
||||
status = STATUS_LOADED;
|
||||
} else {
|
||||
status = STATUS_NOT_LOADED;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
while (!shutdown) {
|
||||
if (status == STATUS_PENDING_LOAD) {
|
||||
load();
|
||||
}
|
||||
Thread.sleep(100);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, e.toString());
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user