mirror of https://github.com/M66B/NetGuard.git
DNS resolving
This commit is contained in:
parent
55042bedd3
commit
b2e7c69af7
|
@ -16,6 +16,7 @@ public class AccessAdapter extends CursorAdapter {
|
|||
|
||||
private int colDaddr;
|
||||
private int colDPort;
|
||||
private int colDName;
|
||||
private int colTime;
|
||||
private int colAllowed;
|
||||
|
||||
|
@ -23,6 +24,7 @@ public class AccessAdapter extends CursorAdapter {
|
|||
super(context, cursor, 0);
|
||||
colDaddr = cursor.getColumnIndex("daddr");
|
||||
colDPort = cursor.getColumnIndex("dport");
|
||||
colDName = cursor.getColumnIndex("dname");
|
||||
colTime = cursor.getColumnIndex("time");
|
||||
colAllowed = cursor.getColumnIndex("allowed");
|
||||
}
|
||||
|
@ -35,8 +37,9 @@ public class AccessAdapter extends CursorAdapter {
|
|||
@Override
|
||||
public void bindView(final View view, final Context context, final Cursor cursor) {
|
||||
// Get values
|
||||
final String dest = cursor.getString(colDaddr);
|
||||
final int dport = (cursor.isNull(colDPort) ? -1 : cursor.getInt(colDPort));
|
||||
String daddr = cursor.getString(colDaddr);
|
||||
int dport = (cursor.isNull(colDPort) ? -1 : cursor.getInt(colDPort));
|
||||
String dname = (cursor.isNull(colDName) ? null : cursor.getString(colDName));
|
||||
long time = cursor.getLong(colTime);
|
||||
int allowed = cursor.getInt(colAllowed);
|
||||
|
||||
|
@ -48,12 +51,6 @@ public class AccessAdapter extends CursorAdapter {
|
|||
// Set values
|
||||
tvTime.setText(new SimpleDateFormat("HH:mm:ss").format(time));
|
||||
cbIp.setChecked(allowed != 0);
|
||||
|
||||
Util.resolveName(dest, new Util.resolveListener() {
|
||||
@Override
|
||||
public void onResolved(String name, boolean resolved) {
|
||||
tvDest.setText(name + (dport > 0 ? ":" + dport : ""));
|
||||
}
|
||||
});
|
||||
tvDest.setText((dname == null ? daddr : dname) + (dport > 0 ? ":" + dport : ""));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
private static final String TAG = "NetGuard.Database";
|
||||
|
||||
private static final String DB_NAME = "Netguard";
|
||||
private static final int DB_VERSION = 9;
|
||||
private static final int DB_VERSION = 10;
|
||||
|
||||
private static boolean once = true;
|
||||
private static List<LogChangedListener> logChangedListeners = new ArrayList<LogChangedListener>();
|
||||
|
@ -69,6 +69,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
", sport INTEGER NULL" +
|
||||
", daddr TEXT" +
|
||||
", dport INTEGER NULL" +
|
||||
", dname TEXT NULL" +
|
||||
", uid INTEGER NULL" +
|
||||
", data TEXT" +
|
||||
", allowed INTEGER NULL" +
|
||||
|
@ -76,7 +77,6 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
", interactive INTEGER NULL" +
|
||||
");");
|
||||
db.execSQL("CREATE INDEX idx_log_time ON log(time)");
|
||||
db.execSQL("CREATE INDEX idx_log_source ON log(saddr)");
|
||||
db.execSQL("CREATE INDEX idx_log_dest ON log(daddr)");
|
||||
db.execSQL("CREATE INDEX idx_log_uid ON log(uid)");
|
||||
}
|
||||
|
@ -88,6 +88,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
", uid INTEGER NOT NULL" +
|
||||
", daddr TEXT NOT NULL" +
|
||||
", dport INTEGER NULL" +
|
||||
", dname TEXT NULL" +
|
||||
", time INTEGER NOT NULL" +
|
||||
", allowed INTEGER NOT NULL" +
|
||||
");");
|
||||
|
@ -141,6 +142,13 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
createTableAccess(db);
|
||||
oldVersion = 9;
|
||||
}
|
||||
if (oldVersion < 10) {
|
||||
db.execSQL("DROP TABLE log");
|
||||
db.execSQL("DROP TABLE access");
|
||||
createTableLog(db);
|
||||
createTableAccess(db);
|
||||
oldVersion = 10;
|
||||
}
|
||||
|
||||
if (oldVersion == DB_VERSION) {
|
||||
db.setVersion(oldVersion);
|
||||
|
@ -158,7 +166,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
|
||||
// Log
|
||||
|
||||
public DatabaseHelper insertLog(Packet packet, int connection, boolean interactive) {
|
||||
public DatabaseHelper insertLog(Packet packet, String dname, int connection, boolean interactive) {
|
||||
synchronized (mContext.getApplicationContext()) {
|
||||
SQLiteDatabase db = this.getWritableDatabase();
|
||||
|
||||
|
@ -185,6 +193,11 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
else
|
||||
cv.put("dport", packet.dport);
|
||||
|
||||
if (dname == null)
|
||||
cv.putNull("dname");
|
||||
else
|
||||
cv.put("dname", dname);
|
||||
|
||||
cv.put("data", packet.data);
|
||||
|
||||
if (packet.uid < 0)
|
||||
|
@ -238,20 +251,24 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
public Cursor searchLog(String find) {
|
||||
SQLiteDatabase db = this.getReadableDatabase();
|
||||
String query = "SELECT ID AS _id, * FROM log";
|
||||
query += " WHERE saddr LIKE ? OR daddr LIKE ? OR uid LIKE ?";
|
||||
query += " WHERE daddr LIKE ? OR uid LIKE ?";
|
||||
query += " ORDER BY time DESC";
|
||||
return db.rawQuery(query, new String[]{"%" + find + "%", "%" + find + "%", "%" + find + "%"});
|
||||
return db.rawQuery(query, new String[]{"%" + find + "%", "%" + find + "%"});
|
||||
}
|
||||
|
||||
// Access
|
||||
|
||||
public DatabaseHelper updateAccess(Packet packet) {
|
||||
public DatabaseHelper updateAccess(Packet packet, String dname) {
|
||||
synchronized (mContext.getApplicationContext()) {
|
||||
SQLiteDatabase db = this.getWritableDatabase();
|
||||
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put("time", packet.time);
|
||||
cv.put("allowed", packet.allowed ? 1 : 0);
|
||||
if (dname == null)
|
||||
cv.putNull("dname");
|
||||
else
|
||||
cv.put("dname", dname);
|
||||
|
||||
int rows = db.update("access", cv, "uid = ? AND daddr = ? AND dport = ?", new String[]{
|
||||
Integer.toString(packet.uid), packet.daddr, Integer.toString(packet.dport)});
|
||||
|
@ -260,6 +277,12 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
cv.put("uid", packet.uid);
|
||||
cv.put("daddr", packet.daddr);
|
||||
cv.put("dport", packet.dport);
|
||||
|
||||
if (dname == null)
|
||||
cv.putNull("dname");
|
||||
else
|
||||
cv.put("dname", dname);
|
||||
|
||||
if (db.insert("access", null, cv) == -1)
|
||||
Log.e(TAG, "Insert access failed");
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import android.content.pm.ApplicationInfo;
|
|||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
@ -34,11 +35,13 @@ public class LogAdapter extends CursorAdapter {
|
|||
private int colSPort;
|
||||
private int colDaddr;
|
||||
private int colDPort;
|
||||
private int colDName;
|
||||
private int colUid;
|
||||
private int colData;
|
||||
private int colAllowed;
|
||||
private int colConnection;
|
||||
private int colInteractive;
|
||||
private InetAddress dns = null;
|
||||
private InetAddress vpn4 = null;
|
||||
private InetAddress vpn6 = null;
|
||||
|
||||
|
@ -53,6 +56,7 @@ public class LogAdapter extends CursorAdapter {
|
|||
colSPort = cursor.getColumnIndex("sport");
|
||||
colDaddr = cursor.getColumnIndex("daddr");
|
||||
colDPort = cursor.getColumnIndex("dport");
|
||||
colDName = cursor.getColumnIndex("dname");
|
||||
colUid = cursor.getColumnIndex("uid");
|
||||
colData = cursor.getColumnIndex("data");
|
||||
colAllowed = cursor.getColumnIndex("allowed");
|
||||
|
@ -61,6 +65,7 @@ public class LogAdapter extends CursorAdapter {
|
|||
|
||||
try {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
dns = SinkholeService.getDns(context);
|
||||
vpn4 = InetAddress.getByName(prefs.getString("vpn4", "10.1.10.1"));
|
||||
vpn6 = InetAddress.getByName(prefs.getString("vpn6", "fd00:1:fd00:1:fd00:1:fd00:1"));
|
||||
} catch (UnknownHostException ex) {
|
||||
|
@ -84,6 +89,7 @@ public class LogAdapter extends CursorAdapter {
|
|||
int sport = (cursor.isNull(colSPort) ? -1 : cursor.getInt(colSPort));
|
||||
String daddr = cursor.getString(colDaddr);
|
||||
int dport = (cursor.isNull(colDPort) ? -1 : cursor.getInt(colDPort));
|
||||
String dname = (cursor.isNull(colDName) ? null : cursor.getString(colDName));
|
||||
int uid = (cursor.isNull(colUid) ? -1 : cursor.getInt(colUid));
|
||||
String data = cursor.getString(colData);
|
||||
int allowed = (cursor.isNull(colAllowed) ? -1 : cursor.getInt(colAllowed));
|
||||
|
@ -94,7 +100,7 @@ public class LogAdapter extends CursorAdapter {
|
|||
TextView tvTime = (TextView) view.findViewById(R.id.tvTime);
|
||||
TextView tvProtocol = (TextView) view.findViewById(R.id.tvProtocol);
|
||||
TextView tvFlags = (TextView) view.findViewById(R.id.tvFlags);
|
||||
final TextView tvSAddr = (TextView) view.findViewById(R.id.tvSAddr);
|
||||
TextView tvSAddr = (TextView) view.findViewById(R.id.tvSAddr);
|
||||
TextView tvSPort = (TextView) view.findViewById(R.id.tvSPort);
|
||||
final TextView tvDaddr = (TextView) view.findViewById(R.id.tvDAddr);
|
||||
TextView tvDPort = (TextView) view.findViewById(R.id.tvDPort);
|
||||
|
@ -171,12 +177,26 @@ public class LogAdapter extends CursorAdapter {
|
|||
tvSAddr.setText(getKnownAddress(saddr));
|
||||
|
||||
if (resolve && !isKnownAddress(daddr))
|
||||
Util.resolveName(daddr, new Util.resolveListener() {
|
||||
@Override
|
||||
public void onResolved(String name, boolean resolved) {
|
||||
tvDaddr.setText(name);
|
||||
}
|
||||
});
|
||||
if (dname == null) {
|
||||
tvDaddr.setText(daddr);
|
||||
new AsyncTask<String, Object, String>() {
|
||||
|
||||
@Override
|
||||
protected String doInBackground(String... args) {
|
||||
try {
|
||||
return InetAddress.getByName(args[0]).toString();
|
||||
} catch (UnknownHostException ignored) {
|
||||
return args[0];
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String name) {
|
||||
tvDaddr.setText(name);
|
||||
}
|
||||
}.execute(daddr);
|
||||
} else
|
||||
tvDaddr.setText(dname);
|
||||
else
|
||||
tvDaddr.setText(getKnownAddress(daddr));
|
||||
|
||||
|
@ -192,7 +212,7 @@ public class LogAdapter extends CursorAdapter {
|
|||
public boolean isKnownAddress(String addr) {
|
||||
try {
|
||||
InetAddress a = InetAddress.getByName(addr);
|
||||
if (a.equals(vpn4) || a.equals(vpn6))
|
||||
if (a.equals(dns) || a.equals(vpn4) || a.equals(vpn6))
|
||||
return true;
|
||||
} catch (UnknownHostException ignored) {
|
||||
}
|
||||
|
@ -202,6 +222,8 @@ public class LogAdapter extends CursorAdapter {
|
|||
private String getKnownAddress(String addr) {
|
||||
try {
|
||||
InetAddress a = InetAddress.getByName(addr);
|
||||
if (a.equals(dns))
|
||||
return "dns";
|
||||
if (a.equals(vpn4) || a.equals(vpn6))
|
||||
return "vpn";
|
||||
} catch (UnknownHostException ignored) {
|
||||
|
|
|
@ -19,17 +19,29 @@ package eu.faircode.netguard;
|
|||
Copyright 2015-2016 by Marcel Bokhorst (M66B)
|
||||
*/
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
public class ResourceRecord {
|
||||
public long Time;
|
||||
public String QName;
|
||||
public String AName;
|
||||
public String Resource;
|
||||
public int TTL;
|
||||
private static DateFormat formater = SimpleDateFormat.getDateTimeInstance();
|
||||
|
||||
public ResourceRecord() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Q " + QName + " A " + AName + " R " + Resource + " TTL " + TTL;
|
||||
return formater.format(
|
||||
new Date(Time).getTime()) +
|
||||
" Q " + QName +
|
||||
" A " + AName +
|
||||
" R " + Resource +
|
||||
" TTL " + TTL +
|
||||
" " + formater.format(new Date(Time + TTL * 1000L).getTime());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@ import java.io.File;
|
|||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
|
@ -88,7 +89,7 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
private boolean last_filter = false;
|
||||
private String last_vpn4 = null;
|
||||
private String last_vpn6 = null;
|
||||
private String last_dns = null;
|
||||
private InetAddress last_dns = null;
|
||||
private boolean phone_state = false;
|
||||
private Object subscriptionsChangedListener = null;
|
||||
private ParcelFileDescriptor vpn = null;
|
||||
|
@ -273,6 +274,7 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
|
||||
case reload:
|
||||
reload();
|
||||
cleanupDNS();
|
||||
break;
|
||||
|
||||
case stop:
|
||||
|
@ -350,7 +352,7 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
boolean filter = prefs.getBoolean("filter", false);
|
||||
String vpn4 = prefs.getString("vpn4", "10.1.10.1");
|
||||
String vpn6 = prefs.getString("vpn6", "fd00:1:fd00:1:fd00:1:fd00:1");
|
||||
String dns = getDns();
|
||||
InetAddress dns = getDns(SinkholeService.this);
|
||||
|
||||
if (state != State.enforcing) {
|
||||
if (state != State.none) {
|
||||
|
@ -637,10 +639,11 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
}
|
||||
|
||||
private void log(Packet packet) {
|
||||
ResourceRecord rr = resolveDNS(packet.daddr);
|
||||
DatabaseHelper dh = new DatabaseHelper(SinkholeService.this);
|
||||
dh.insertLog(packet, (last_connected ? last_metered ? 2 : 1 : 0), last_interactive);
|
||||
dh.insertLog(packet, rr == null ? null : rr.QName, (last_connected ? last_metered ? 2 : 1 : 0), last_interactive);
|
||||
if (packet.uid > 0)
|
||||
dh.updateAccess(packet);
|
||||
dh.updateAccess(packet, rr == null ? null : rr.QName);
|
||||
dh.close();
|
||||
}
|
||||
|
||||
|
@ -676,25 +679,30 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
}
|
||||
}
|
||||
|
||||
private String getDns() {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
String sysDns = Util.getDefaultDNS(SinkholeService.this);
|
||||
public static InetAddress getDns(Context context) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
String sysDns = Util.getDefaultDNS(context);
|
||||
String vpnDns = prefs.getString("dns", sysDns);
|
||||
Log.i(TAG, "DNS system=" + sysDns + " VPN=" + vpnDns);
|
||||
try {
|
||||
if (TextUtils.isEmpty(vpnDns.trim()))
|
||||
throw new IllegalArgumentException("dns");
|
||||
InetAddress.getByName(vpnDns);
|
||||
Log.i(TAG, "DNS using=" + vpnDns);
|
||||
return vpnDns;
|
||||
} catch (Throwable ignored1) {
|
||||
InetAddress vpn = InetAddress.getByName(vpnDns);
|
||||
Log.i(TAG, "DNS using=" + vpn);
|
||||
return vpn;
|
||||
} catch (UnknownHostException ignored1) {
|
||||
try {
|
||||
InetAddress.getByName(sysDns);
|
||||
Log.i(TAG, "DNS using=" + sysDns);
|
||||
return sysDns;
|
||||
} catch (Throwable ignored2) {
|
||||
Log.i(TAG, "DNS using=8.8.8.8");
|
||||
return "8.8.8.8";
|
||||
InetAddress sys = InetAddress.getByName(sysDns);
|
||||
Log.i(TAG, "DNS using=" + sys);
|
||||
return sys;
|
||||
} catch (UnknownHostException ignored2) {
|
||||
try {
|
||||
InetAddress def = InetAddress.getByName("8.8.8.8");
|
||||
Log.i(TAG, "DNS using=" + def);
|
||||
return def;
|
||||
} catch (UnknownHostException ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -708,7 +716,7 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
last_tethering = tethering;
|
||||
last_vpn4 = prefs.getString("vpn4", "10.1.10.1");
|
||||
last_vpn6 = prefs.getString("vpn6", "fd00:1:fd00:1:fd00:1:fd00:1");
|
||||
last_dns = getDns();
|
||||
last_dns = getDns(SinkholeService.this);
|
||||
|
||||
// Build VPN service
|
||||
final Builder builder = new Builder();
|
||||
|
@ -930,9 +938,37 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
}
|
||||
}
|
||||
|
||||
private static HashMap<String, ResourceRecord> mapRR = new HashMap<>();
|
||||
|
||||
// Called from native code
|
||||
private void dnsResolved(ResourceRecord rr) {
|
||||
Log.i(TAG, rr.toString());
|
||||
synchronized (mapRR) {
|
||||
mapRR.put(rr.Resource, rr);
|
||||
}
|
||||
}
|
||||
|
||||
public static ResourceRecord resolveDNS(String ip) {
|
||||
synchronized (mapRR) {
|
||||
if (mapRR.containsKey(ip))
|
||||
return mapRR.get(ip);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanupDNS() {
|
||||
long now = new Date().getTime();
|
||||
synchronized (mapRR) {
|
||||
List<String> ips = new ArrayList<>(mapRR.keySet());
|
||||
for (String ip : ips) {
|
||||
ResourceRecord rr = mapRR.get(ip);
|
||||
if (rr.Time + rr.TTL * 1000L < now &&
|
||||
rr.Time + 10 * 60 * 1000L < now) {
|
||||
mapRR.remove(ip);
|
||||
Log.i(TAG, "Purged " + rr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Called from native code
|
||||
|
|
|
@ -74,8 +74,6 @@ public class Util {
|
|||
|
||||
private static native String jni_getprop(String name);
|
||||
|
||||
private static native String jni_resolve(String ip);
|
||||
|
||||
static {
|
||||
System.loadLibrary("netguard");
|
||||
}
|
||||
|
@ -357,45 +355,6 @@ public class Util {
|
|||
|
||||
private static Map<String, String> mapIPHost = new HashMap<String, String>();
|
||||
|
||||
public interface resolveListener {
|
||||
void onResolved(String name, boolean resolved);
|
||||
}
|
||||
|
||||
public static void resolveName(String name, final resolveListener listener) {
|
||||
// TODO DNS cache timeout
|
||||
synchronized (mapIPHost) {
|
||||
if (mapIPHost.containsKey(name))
|
||||
listener.onResolved(mapIPHost.get(name), true);
|
||||
else {
|
||||
listener.onResolved(name, false);
|
||||
|
||||
new AsyncTask<String, Object, String>() {
|
||||
@Override
|
||||
protected String doInBackground(String... args) {
|
||||
return jni_resolve(args[0]);
|
||||
/*
|
||||
try {
|
||||
// This requires internet permission
|
||||
return InetAddress.getByName(args[0]).getHostName();
|
||||
} catch (UnknownHostException ignored) {
|
||||
return args[0];
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String host) {
|
||||
synchronized (mapIPHost) {
|
||||
if (!mapIPHost.containsKey(host))
|
||||
mapIPHost.put(host, host);
|
||||
}
|
||||
listener.onResolved(host, true);
|
||||
}
|
||||
}.execute(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void setTheme(Context context) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
boolean dark = prefs.getBoolean("dark_theme", false);
|
||||
|
|
|
@ -2616,6 +2616,7 @@ void log_packet(const struct arguments *args, jobject jpacket) {
|
|||
|
||||
static jmethodID midDnsResolved = NULL;
|
||||
static jmethodID midInitRR = NULL;
|
||||
jfieldID fidQTime = NULL;
|
||||
jfieldID fidQName = NULL;
|
||||
jfieldID fidAName = NULL;
|
||||
jfieldID fidResource = NULL;
|
||||
|
@ -2641,18 +2642,21 @@ void dns_resolved(const struct arguments *args,
|
|||
|
||||
jobject jrr = jniNewObject(args->env, clsRR, midInitRR, rr);
|
||||
|
||||
if (fidQName == NULL) {
|
||||
if (fidQTime == NULL) {
|
||||
const char *string = "Ljava/lang/String;";
|
||||
fidQTime = jniGetFieldID(args->env, clsRR, "Time", "J");
|
||||
fidQName = jniGetFieldID(args->env, clsRR, "QName", string);
|
||||
fidAName = jniGetFieldID(args->env, clsRR, "AName", string);
|
||||
fidResource = jniGetFieldID(args->env, clsRR, "Resource", string);
|
||||
fidTTL = jniGetFieldID(args->env, clsRR, "TTL", "I");
|
||||
}
|
||||
|
||||
jlong jtime = time(NULL) * 1000LL;
|
||||
jstring jqname = (*args->env)->NewStringUTF(args->env, qname);
|
||||
jstring janame = (*args->env)->NewStringUTF(args->env, aname);
|
||||
jstring jresource = (*args->env)->NewStringUTF(args->env, resource);
|
||||
|
||||
(*args->env)->SetLongField(args->env, jrr, fidQTime, jtime);
|
||||
(*args->env)->SetObjectField(args->env, jrr, fidQName, jqname);
|
||||
(*args->env)->SetObjectField(args->env, jrr, fidAName, janame);
|
||||
(*args->env)->SetObjectField(args->env, jrr, fidResource, jresource);
|
||||
|
|
|
@ -25,7 +25,7 @@ These issues are caused by bugs in Android, or in the software provided by the m
|
|||
<string name="menu_about">About</string>
|
||||
|
||||
<string name="menu_live">Live updates</string>
|
||||
<string name="menu_resolve">Resolve host names</string>
|
||||
<string name="menu_resolve">Show names</string>
|
||||
<string name="menu_pcap_enabled">PCAP enabled</string>
|
||||
<string name="menu_pcap_export">PCAP export</string>
|
||||
<string name="menu_clear">Clear</string>
|
||||
|
|
Loading…
Reference in New Issue