Merge "Add bypass private DNS test case and null network test for DnsResolver cts" am: 3df5aa1233
am: fbc990bf3b Change-Id: I3cdfc9093915ceb27c5161c5b2f7dc9149b0dcb8
This commit is contained in:
@@ -21,20 +21,25 @@ import static android.net.DnsResolver.FLAG_EMPTY;
|
|||||||
import static android.net.DnsResolver.FLAG_NO_CACHE_LOOKUP;
|
import static android.net.DnsResolver.FLAG_NO_CACHE_LOOKUP;
|
||||||
import static android.net.DnsResolver.TYPE_A;
|
import static android.net.DnsResolver.TYPE_A;
|
||||||
import static android.net.DnsResolver.TYPE_AAAA;
|
import static android.net.DnsResolver.TYPE_AAAA;
|
||||||
import static android.system.OsConstants.EBADF;
|
import static android.system.OsConstants.ETIMEDOUT;
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.ContentResolver;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
|
import android.net.ConnectivityManager.NetworkCallback;
|
||||||
import android.net.DnsPacket;
|
import android.net.DnsPacket;
|
||||||
import android.net.DnsResolver;
|
import android.net.DnsResolver;
|
||||||
|
import android.net.LinkProperties;
|
||||||
import android.net.Network;
|
import android.net.Network;
|
||||||
import android.net.NetworkCapabilities;
|
import android.net.NetworkCapabilities;
|
||||||
|
import android.net.NetworkRequest;
|
||||||
import android.net.ParseException;
|
import android.net.ParseException;
|
||||||
import android.os.CancellationSignal;
|
import android.os.CancellationSignal;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
import android.provider.Settings;
|
||||||
import android.system.ErrnoException;
|
import android.system.ErrnoException;
|
||||||
import android.test.AndroidTestCase;
|
import android.test.AndroidTestCase;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -53,20 +58,63 @@ public class DnsResolverTest extends AndroidTestCase {
|
|||||||
private static final char[] HEX_CHARS = {
|
private static final char[] HEX_CHARS = {
|
||||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static final String TEST_DOMAIN = "www.google.com";
|
||||||
|
static final String INVALID_PRIVATE_DNS_SERVER = "invalid.google";
|
||||||
|
static final byte[] TEST_BLOB = new byte[]{
|
||||||
|
/* Header */
|
||||||
|
0x55, 0x66, /* Transaction ID */
|
||||||
|
0x01, 0x00, /* Flags */
|
||||||
|
0x00, 0x01, /* Questions */
|
||||||
|
0x00, 0x00, /* Answer RRs */
|
||||||
|
0x00, 0x00, /* Authority RRs */
|
||||||
|
0x00, 0x00, /* Additional RRs */
|
||||||
|
/* Queries */
|
||||||
|
0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65,
|
||||||
|
0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */
|
||||||
|
0x00, 0x01, /* Type */
|
||||||
|
0x00, 0x01 /* Class */
|
||||||
|
};
|
||||||
static final int TIMEOUT_MS = 12_000;
|
static final int TIMEOUT_MS = 12_000;
|
||||||
static final int CANCEL_TIMEOUT_MS = 3_000;
|
static final int CANCEL_TIMEOUT_MS = 3_000;
|
||||||
static final int CANCEL_RETRY_TIMES = 5;
|
static final int CANCEL_RETRY_TIMES = 5;
|
||||||
static final int NXDOMAIN = 3;
|
static final int NXDOMAIN = 3;
|
||||||
|
static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 2_000;
|
||||||
|
|
||||||
|
private ContentResolver mCR;
|
||||||
private ConnectivityManager mCM;
|
private ConnectivityManager mCM;
|
||||||
private Executor mExecutor;
|
private Executor mExecutor;
|
||||||
private DnsResolver mDns;
|
private DnsResolver mDns;
|
||||||
|
|
||||||
|
private String mOldMode;
|
||||||
|
private String mOldDnsSpecifier;
|
||||||
|
|
||||||
|
@Override
|
||||||
protected void setUp() throws Exception {
|
protected void setUp() throws Exception {
|
||||||
super.setUp();
|
super.setUp();
|
||||||
mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
|
mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||||
mDns = DnsResolver.getInstance();
|
mDns = DnsResolver.getInstance();
|
||||||
mExecutor = new Handler(Looper.getMainLooper())::post;
|
mExecutor = new Handler(Looper.getMainLooper())::post;
|
||||||
|
mCR = getContext().getContentResolver();
|
||||||
|
storePrivateDnsSetting();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void tearDown() throws Exception {
|
||||||
|
restorePrivateDnsSetting();
|
||||||
|
super.tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void storePrivateDnsSetting() {
|
||||||
|
// Store private DNS setting
|
||||||
|
mOldMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE);
|
||||||
|
mOldDnsSpecifier = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void restorePrivateDnsSetting() {
|
||||||
|
// restore private DNS setting
|
||||||
|
Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldMode);
|
||||||
|
Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, mOldDnsSpecifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String byteArrayToHexString(byte[] bytes) {
|
private static String byteArrayToHexString(byte[] bytes) {
|
||||||
@@ -94,6 +142,9 @@ public class DnsResolverTest extends AndroidTestCase {
|
|||||||
"This test requires that at least one network be connected. " +
|
"This test requires that at least one network be connected. " +
|
||||||
"Please ensure that the device is connected to a network.",
|
"Please ensure that the device is connected to a network.",
|
||||||
testableNetworks.size() >= 1);
|
testableNetworks.size() >= 1);
|
||||||
|
// In order to test query with null network, add null as an element.
|
||||||
|
// Test cases which query with null network will go on default network.
|
||||||
|
testableNetworks.add(null);
|
||||||
return testableNetworks.toArray(new Network[0]);
|
return testableNetworks.toArray(new Network[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,15 +156,12 @@ public class DnsResolverTest extends AndroidTestCase {
|
|||||||
public DnsParseException(String msg) {
|
public DnsParseException(String msg) {
|
||||||
super(msg);
|
super(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DnsParseException(String msg, Throwable cause) {
|
|
||||||
super(msg, cause);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class DnsAnswer extends DnsPacket {
|
private static class DnsAnswer extends DnsPacket {
|
||||||
DnsAnswer(@NonNull byte[] data) throws DnsParseException {
|
DnsAnswer(@NonNull byte[] data) throws DnsParseException {
|
||||||
super(data);
|
super(data);
|
||||||
|
|
||||||
// Check QR field.(query (0), or a response (1)).
|
// Check QR field.(query (0), or a response (1)).
|
||||||
if ((mHeader.flags & (1 << 15)) == 0) {
|
if ((mHeader.flags & (1 << 15)) == 0) {
|
||||||
throw new DnsParseException("Not an answer packet");
|
throw new DnsParseException("Not an answer packet");
|
||||||
@@ -123,10 +171,12 @@ public class DnsResolverTest extends AndroidTestCase {
|
|||||||
int getRcode() {
|
int getRcode() {
|
||||||
return mHeader.rcode;
|
return mHeader.rcode;
|
||||||
}
|
}
|
||||||
int getANCount(){
|
|
||||||
|
int getANCount() {
|
||||||
return mHeader.getRecordCount(ANSECTION);
|
return mHeader.getRecordCount(ANSECTION);
|
||||||
}
|
}
|
||||||
int getQDCount(){
|
|
||||||
|
int getQDCount() {
|
||||||
return mHeader.getRecordCount(QDSECTION);
|
return mHeader.getRecordCount(QDSECTION);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,7 +223,7 @@ public class DnsResolverTest extends AndroidTestCase {
|
|||||||
mRcode = rcode;
|
mRcode = rcode;
|
||||||
try {
|
try {
|
||||||
mDnsAnswer = new DnsAnswer(answer);
|
mDnsAnswer = new DnsAnswer(answer);
|
||||||
} catch (DnsParseException e) {
|
} catch (ParseException | DnsParseException e) {
|
||||||
fail(mMsg + e.getMessage());
|
fail(mMsg + e.getMessage());
|
||||||
}
|
}
|
||||||
Log.d(TAG, "Reported blob: " + byteArrayToHexString(answer));
|
Log.d(TAG, "Reported blob: " + byteArrayToHexString(answer));
|
||||||
@@ -222,90 +272,76 @@ public class DnsResolverTest extends AndroidTestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testRawQuery() {
|
public void testRawQuery() throws InterruptedException {
|
||||||
final String dname = "www.google.com";
|
final String msg = "RawQuery " + TEST_DOMAIN;
|
||||||
final String msg = "RawQuery " + dname;
|
|
||||||
for (Network network : getTestableNetworks()) {
|
for (Network network : getTestableNetworks()) {
|
||||||
final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
|
final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
|
||||||
mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
|
mDns.rawQuery(network, TEST_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
|
||||||
mExecutor, null, callback);
|
mExecutor, null, callback);
|
||||||
try {
|
|
||||||
assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
|
assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
|
||||||
callback.waitForAnswer());
|
callback.waitForAnswer());
|
||||||
callback.assertHasAnswer();
|
callback.assertHasAnswer();
|
||||||
} catch (InterruptedException e) {
|
|
||||||
fail(msg + " Waiting for DNS lookup was interrupted");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testRawQueryBlob() {
|
public void testRawQueryBlob() throws InterruptedException {
|
||||||
final byte[] blob = new byte[]{
|
final byte[] blob = new byte[]{
|
||||||
/* Header */
|
/* Header */
|
||||||
0x55, 0x66, /* Transaction ID */
|
0x55, 0x66, /* Transaction ID */
|
||||||
0x01, 0x00, /* Flags */
|
0x01, 0x00, /* Flags */
|
||||||
0x00, 0x01, /* Questions */
|
0x00, 0x01, /* Questions */
|
||||||
0x00, 0x00, /* Answer RRs */
|
0x00, 0x00, /* Answer RRs */
|
||||||
0x00, 0x00, /* Authority RRs */
|
0x00, 0x00, /* Authority RRs */
|
||||||
0x00, 0x00, /* Additional RRs */
|
0x00, 0x00, /* Additional RRs */
|
||||||
/* Queries */
|
/* Queries */
|
||||||
0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65,
|
0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65,
|
||||||
0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */
|
0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */
|
||||||
0x00, 0x01, /* Type */
|
0x00, 0x01, /* Type */
|
||||||
0x00, 0x01 /* Class */
|
0x00, 0x01 /* Class */
|
||||||
};
|
};
|
||||||
final String msg = "RawQuery blob " + byteArrayToHexString(blob);
|
final String msg = "RawQuery blob " + byteArrayToHexString(blob);
|
||||||
for (Network network : getTestableNetworks()) {
|
for (Network network : getTestableNetworks()) {
|
||||||
final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
|
final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
|
||||||
mDns.rawQuery(network, blob, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback);
|
mDns.rawQuery(network, blob, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback);
|
||||||
try {
|
|
||||||
assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
|
assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
|
||||||
callback.waitForAnswer());
|
callback.waitForAnswer());
|
||||||
callback.assertHasAnswer();
|
callback.assertHasAnswer();
|
||||||
} catch (InterruptedException e) {
|
|
||||||
fail(msg + " Waiting for DNS lookup was interrupted");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testRawQueryRoot() {
|
public void testRawQueryRoot() throws InterruptedException {
|
||||||
final String dname = "";
|
final String dname = "";
|
||||||
final String msg = "RawQuery empty dname(ROOT) ";
|
final String msg = "RawQuery empty dname(ROOT) ";
|
||||||
for (Network network : getTestableNetworks()) {
|
for (Network network : getTestableNetworks()) {
|
||||||
final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
|
final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
|
||||||
mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
|
mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
|
||||||
mExecutor, null, callback);
|
mExecutor, null, callback);
|
||||||
try {
|
|
||||||
assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
|
assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
|
||||||
callback.waitForAnswer());
|
callback.waitForAnswer());
|
||||||
// Except no answer record because the root does not have AAAA records.
|
// Except no answer record because the root does not have AAAA records.
|
||||||
callback.assertEmptyAnswer();
|
callback.assertEmptyAnswer();
|
||||||
} catch (InterruptedException e) {
|
|
||||||
fail(msg + " Waiting for DNS lookup was interrupted");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testRawQueryNXDomain() {
|
public void testRawQueryNXDomain() throws InterruptedException {
|
||||||
final String dname = "test1-nx.metric.gstatic.com";
|
final String dname = "test1-nx.metric.gstatic.com";
|
||||||
final String msg = "RawQuery " + dname;
|
final String msg = "RawQuery " + dname;
|
||||||
for (Network network : getTestableNetworks()) {
|
for (Network network : getTestableNetworks()) {
|
||||||
final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
|
final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
|
||||||
mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
|
mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
|
||||||
mExecutor, null, callback);
|
mExecutor, null, callback);
|
||||||
try {
|
|
||||||
assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
|
assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
|
||||||
callback.waitForAnswer());
|
callback.waitForAnswer());
|
||||||
callback.assertNXDomain();
|
callback.assertNXDomain();
|
||||||
} catch (InterruptedException e) {
|
|
||||||
fail(msg + " Waiting for DNS lookup was interrupted");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testRawQueryCancel() throws ErrnoException {
|
public void testRawQueryCancel() throws InterruptedException {
|
||||||
final String dname = "www.google.com";
|
final String msg = "Test cancel RawQuery " + TEST_DOMAIN;
|
||||||
final String msg = "Test cancel RawQuery " + dname;
|
|
||||||
// Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect
|
// Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect
|
||||||
// that the query is cancelled before it succeeds. If it is not cancelled before it
|
// that the query is cancelled before it succeeds. If it is not cancelled before it
|
||||||
// succeeds, retry the test until it is.
|
// succeeds, retry the test until it is.
|
||||||
@@ -319,39 +355,22 @@ public class DnsResolverTest extends AndroidTestCase {
|
|||||||
final CountDownLatch latch = new CountDownLatch(1);
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
final CancellationSignal cancelSignal = new CancellationSignal();
|
final CancellationSignal cancelSignal = new CancellationSignal();
|
||||||
final VerifyCancelCallback callback = new VerifyCancelCallback(msg, cancelSignal);
|
final VerifyCancelCallback callback = new VerifyCancelCallback(msg, cancelSignal);
|
||||||
mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_EMPTY,
|
mDns.rawQuery(network, TEST_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_EMPTY,
|
||||||
mExecutor, cancelSignal, callback);
|
mExecutor, cancelSignal, callback);
|
||||||
mExecutor.execute(() -> {
|
mExecutor.execute(() -> {
|
||||||
cancelSignal.cancel();
|
cancelSignal.cancel();
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
});
|
});
|
||||||
try {
|
|
||||||
retry = callback.needRetry();
|
retry = callback.needRetry();
|
||||||
assertTrue(msg + " query was not cancelled",
|
assertTrue(msg + " query was not cancelled",
|
||||||
latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
|
latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
|
||||||
} catch (InterruptedException e) {
|
|
||||||
fail(msg + " Waiting for DNS lookup was interrupted");
|
|
||||||
}
|
|
||||||
} while (retry);
|
} while (retry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testRawQueryBlobCancel() throws ErrnoException {
|
public void testRawQueryBlobCancel() throws InterruptedException {
|
||||||
final byte[] blob = new byte[]{
|
final String msg = "Test cancel RawQuery blob " + byteArrayToHexString(TEST_BLOB);
|
||||||
/* Header */
|
|
||||||
0x55, 0x66, /* Transaction ID */
|
|
||||||
0x01, 0x00, /* Flags */
|
|
||||||
0x00, 0x01, /* Questions */
|
|
||||||
0x00, 0x00, /* Answer RRs */
|
|
||||||
0x00, 0x00, /* Authority RRs */
|
|
||||||
0x00, 0x00, /* Additional RRs */
|
|
||||||
/* Queries */
|
|
||||||
0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6c, 0x65,
|
|
||||||
0x03, 0x63, 0x6f, 0x6d, 0x00, /* Name */
|
|
||||||
0x00, 0x01, /* Type */
|
|
||||||
0x00, 0x01 /* Class */
|
|
||||||
};
|
|
||||||
final String msg = "Test cancel RawQuery blob " + byteArrayToHexString(blob);
|
|
||||||
// Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect
|
// Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect
|
||||||
// that the query is cancelled before it succeeds. If it is not cancelled before it
|
// that the query is cancelled before it succeeds. If it is not cancelled before it
|
||||||
// succeeds, retry the test until it is.
|
// succeeds, retry the test until it is.
|
||||||
@@ -365,37 +384,30 @@ public class DnsResolverTest extends AndroidTestCase {
|
|||||||
final CountDownLatch latch = new CountDownLatch(1);
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
final CancellationSignal cancelSignal = new CancellationSignal();
|
final CancellationSignal cancelSignal = new CancellationSignal();
|
||||||
final VerifyCancelCallback callback = new VerifyCancelCallback(msg, cancelSignal);
|
final VerifyCancelCallback callback = new VerifyCancelCallback(msg, cancelSignal);
|
||||||
mDns.rawQuery(network, blob, FLAG_EMPTY, mExecutor, cancelSignal, callback);
|
mDns.rawQuery(network, TEST_BLOB, FLAG_EMPTY, mExecutor, cancelSignal, callback);
|
||||||
mExecutor.execute(() -> {
|
mExecutor.execute(() -> {
|
||||||
cancelSignal.cancel();
|
cancelSignal.cancel();
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
});
|
});
|
||||||
try {
|
|
||||||
retry = callback.needRetry();
|
retry = callback.needRetry();
|
||||||
assertTrue(msg + " cancel is not done",
|
assertTrue(msg + " cancel is not done",
|
||||||
latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
|
latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
|
||||||
} catch (InterruptedException e) {
|
|
||||||
fail(msg + " Waiting for DNS lookup was interrupted");
|
|
||||||
}
|
|
||||||
} while (retry);
|
} while (retry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testCancelBeforeQuery() throws ErrnoException {
|
public void testCancelBeforeQuery() throws InterruptedException {
|
||||||
final String dname = "www.google.com";
|
final String msg = "Test cancelled RawQuery " + TEST_DOMAIN;
|
||||||
final String msg = "Test cancelled RawQuery " + dname;
|
|
||||||
for (Network network : getTestableNetworks()) {
|
for (Network network : getTestableNetworks()) {
|
||||||
final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
|
final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
|
||||||
final CancellationSignal cancelSignal = new CancellationSignal();
|
final CancellationSignal cancelSignal = new CancellationSignal();
|
||||||
cancelSignal.cancel();
|
cancelSignal.cancel();
|
||||||
mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_EMPTY,
|
mDns.rawQuery(network, TEST_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_EMPTY,
|
||||||
mExecutor, cancelSignal, callback);
|
mExecutor, cancelSignal, callback);
|
||||||
try {
|
|
||||||
assertTrue(msg + " should not return any answers",
|
assertTrue(msg + " should not return any answers",
|
||||||
!callback.waitForAnswer(CANCEL_TIMEOUT_MS));
|
!callback.waitForAnswer(CANCEL_TIMEOUT_MS));
|
||||||
} catch (InterruptedException e) {
|
|
||||||
fail(msg + " Waiting for DNS lookup was interrupted");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -462,27 +474,21 @@ public class DnsResolverTest extends AndroidTestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testQueryForInetAddress() {
|
public void testQueryForInetAddress() throws InterruptedException {
|
||||||
final String dname = "www.google.com";
|
final String msg = "Test query for InetAddress " + TEST_DOMAIN;
|
||||||
final String msg = "Test query for InetAddress " + dname;
|
|
||||||
for (Network network : getTestableNetworks()) {
|
for (Network network : getTestableNetworks()) {
|
||||||
final VerifyCancelInetAddressCallback callback =
|
final VerifyCancelInetAddressCallback callback =
|
||||||
new VerifyCancelInetAddressCallback(msg, null);
|
new VerifyCancelInetAddressCallback(msg, null);
|
||||||
mDns.query(network, dname, FLAG_NO_CACHE_LOOKUP,
|
mDns.query(network, TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback);
|
||||||
mExecutor, null, callback);
|
|
||||||
try {
|
assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
|
||||||
assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
|
callback.waitForAnswer());
|
||||||
callback.waitForAnswer());
|
assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
|
||||||
assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
fail(msg + " Waiting for DNS lookup was interrupted");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testQueryCancelForInetAddress() throws ErrnoException {
|
public void testQueryCancelForInetAddress() throws InterruptedException {
|
||||||
final String dname = "www.google.com";
|
final String msg = "Test cancel query for InetAddress " + TEST_DOMAIN;
|
||||||
final String msg = "Test cancel query for InetAddress " + dname;
|
|
||||||
// Start a DNS query and the cancel it immediately. Use VerifyCancelInetAddressCallback to
|
// Start a DNS query and the cancel it immediately. Use VerifyCancelInetAddressCallback to
|
||||||
// expect that the query is cancelled before it succeeds. If it is not cancelled before it
|
// expect that the query is cancelled before it succeeds. If it is not cancelled before it
|
||||||
// succeeds, retry the test until it is.
|
// succeeds, retry the test until it is.
|
||||||
@@ -497,57 +503,131 @@ public class DnsResolverTest extends AndroidTestCase {
|
|||||||
final CancellationSignal cancelSignal = new CancellationSignal();
|
final CancellationSignal cancelSignal = new CancellationSignal();
|
||||||
final VerifyCancelInetAddressCallback callback =
|
final VerifyCancelInetAddressCallback callback =
|
||||||
new VerifyCancelInetAddressCallback(msg, cancelSignal);
|
new VerifyCancelInetAddressCallback(msg, cancelSignal);
|
||||||
mDns.query(network, dname, FLAG_EMPTY, mExecutor, cancelSignal, callback);
|
mDns.query(network, TEST_DOMAIN, FLAG_EMPTY, mExecutor, cancelSignal, callback);
|
||||||
mExecutor.execute(() -> {
|
mExecutor.execute(() -> {
|
||||||
cancelSignal.cancel();
|
cancelSignal.cancel();
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
});
|
});
|
||||||
try {
|
|
||||||
retry = callback.needRetry();
|
retry = callback.needRetry();
|
||||||
assertTrue(msg + " query was not cancelled",
|
assertTrue(msg + " query was not cancelled",
|
||||||
latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
|
latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
|
||||||
} catch (InterruptedException e) {
|
|
||||||
fail(msg + " Waiting for DNS lookup was interrupted");
|
|
||||||
}
|
|
||||||
} while (retry);
|
} while (retry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testQueryForInetAddressIpv4() {
|
public void testQueryForInetAddressIpv4() throws InterruptedException {
|
||||||
final String dname = "www.google.com";
|
final String msg = "Test query for IPv4 InetAddress " + TEST_DOMAIN;
|
||||||
final String msg = "Test query for IPv4 InetAddress " + dname;
|
|
||||||
for (Network network : getTestableNetworks()) {
|
for (Network network : getTestableNetworks()) {
|
||||||
final VerifyCancelInetAddressCallback callback =
|
final VerifyCancelInetAddressCallback callback =
|
||||||
new VerifyCancelInetAddressCallback(msg, null);
|
new VerifyCancelInetAddressCallback(msg, null);
|
||||||
mDns.query(network, dname, TYPE_A, FLAG_NO_CACHE_LOOKUP,
|
mDns.query(network, TEST_DOMAIN, TYPE_A, FLAG_NO_CACHE_LOOKUP,
|
||||||
mExecutor, null, callback);
|
mExecutor, null, callback);
|
||||||
try {
|
|
||||||
assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
|
assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
|
||||||
callback.waitForAnswer());
|
callback.waitForAnswer());
|
||||||
assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
|
assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
|
||||||
assertTrue(msg + " returned Ipv6 results", !callback.hasIpv6Answer());
|
assertTrue(msg + " returned Ipv6 results", !callback.hasIpv6Answer());
|
||||||
} catch (InterruptedException e) {
|
|
||||||
fail(msg + " Waiting for DNS lookup was interrupted");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testQueryForInetAddressIpv6() {
|
public void testQueryForInetAddressIpv6() throws InterruptedException {
|
||||||
final String dname = "www.google.com";
|
final String msg = "Test query for IPv6 InetAddress " + TEST_DOMAIN;
|
||||||
final String msg = "Test query for IPv6 InetAddress " + dname;
|
|
||||||
for (Network network : getTestableNetworks()) {
|
for (Network network : getTestableNetworks()) {
|
||||||
final VerifyCancelInetAddressCallback callback =
|
final VerifyCancelInetAddressCallback callback =
|
||||||
new VerifyCancelInetAddressCallback(msg, null);
|
new VerifyCancelInetAddressCallback(msg, null);
|
||||||
mDns.query(network, dname, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
|
mDns.query(network, TEST_DOMAIN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
|
||||||
mExecutor, null, callback);
|
mExecutor, null, callback);
|
||||||
try {
|
|
||||||
assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
|
assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
|
||||||
callback.waitForAnswer());
|
callback.waitForAnswer());
|
||||||
assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
|
assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
|
||||||
assertTrue(msg + " returned Ipv4 results", !callback.hasIpv4Answer());
|
assertTrue(msg + " returned Ipv4 results", !callback.hasIpv4Answer());
|
||||||
} catch (InterruptedException e) {
|
}
|
||||||
fail(msg + " Waiting for DNS lookup was interrupted");
|
}
|
||||||
|
|
||||||
|
private void awaitPrivateDnsSetting(@NonNull String msg,
|
||||||
|
@NonNull Network network, @NonNull String server) throws InterruptedException {
|
||||||
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
|
||||||
|
NetworkCallback callback = new NetworkCallback() {
|
||||||
|
@Override
|
||||||
|
public void onLinkPropertiesChanged(Network n, LinkProperties lp) {
|
||||||
|
if (network.equals(n) && server.equals(lp.getPrivateDnsServerName())) {
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
mCM.registerNetworkCallback(request, callback);
|
||||||
|
assertTrue(msg, latch.await(PRIVATE_DNS_SETTING_TIMEOUT_MS, TimeUnit.MILLISECONDS));
|
||||||
|
mCM.unregisterNetworkCallback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testPrivateDnsBypass() throws InterruptedException {
|
||||||
|
final Network[] testNetworks = getTestableNetworks();
|
||||||
|
|
||||||
|
// Set an invalid private DNS server
|
||||||
|
Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname");
|
||||||
|
Settings.Global.putString(mCR,
|
||||||
|
Settings.Global.PRIVATE_DNS_SPECIFIER, INVALID_PRIVATE_DNS_SERVER);
|
||||||
|
|
||||||
|
final String msg = "Test PrivateDnsBypass " + TEST_DOMAIN;
|
||||||
|
for (Network network : testNetworks) {
|
||||||
|
// This test cannot be ran with null network because we need to explicitly pass a
|
||||||
|
// private DNS bypassable network or bind one.
|
||||||
|
if (network == null) continue;
|
||||||
|
|
||||||
|
// wait for private DNS setting propagating
|
||||||
|
awaitPrivateDnsSetting(msg + " wait private DNS setting timeout",
|
||||||
|
network, INVALID_PRIVATE_DNS_SERVER);
|
||||||
|
|
||||||
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
final DnsResolver.Callback<List<InetAddress>> errorCallback =
|
||||||
|
new DnsResolver.Callback<List<InetAddress>>() {
|
||||||
|
@Override
|
||||||
|
public void onAnswer(@NonNull List<InetAddress> answerList, int rcode) {
|
||||||
|
fail(msg + " should not get valid answer");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(@NonNull DnsResolver.DnsException error) {
|
||||||
|
assertEquals(DnsResolver.ERROR_SYSTEM, error.code);
|
||||||
|
assertEquals(ETIMEDOUT, ((ErrnoException) error.getCause()).errno);
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Private DNS strict mode with invalid DNS server is set
|
||||||
|
// Expect no valid answer returned but ErrnoException with ETIMEDOUT
|
||||||
|
mDns.query(network, TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, mExecutor, null, errorCallback);
|
||||||
|
|
||||||
|
assertTrue(msg + " invalid server round. No response after " + TIMEOUT_MS + "ms.",
|
||||||
|
latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
|
||||||
|
|
||||||
|
final VerifyCancelInetAddressCallback callback =
|
||||||
|
new VerifyCancelInetAddressCallback(msg, null);
|
||||||
|
// Bypass privateDns, expect query works fine
|
||||||
|
mDns.query(network.getPrivateDnsBypassingCopy(),
|
||||||
|
TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback);
|
||||||
|
|
||||||
|
assertTrue(msg + " bypass private DNS round. No answer after " + TIMEOUT_MS + "ms.",
|
||||||
|
callback.waitForAnswer());
|
||||||
|
assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
|
||||||
|
|
||||||
|
// To ensure private DNS bypass still work even if passing null network.
|
||||||
|
// Bind process network with a private DNS bypassable network.
|
||||||
|
mCM.bindProcessToNetwork(network.getPrivateDnsBypassingCopy());
|
||||||
|
final VerifyCancelInetAddressCallback callbackWithNullNetwork =
|
||||||
|
new VerifyCancelInetAddressCallback(msg + " with null network ", null);
|
||||||
|
mDns.query(null,
|
||||||
|
TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callbackWithNullNetwork);
|
||||||
|
|
||||||
|
assertTrue(msg + " with null network bypass private DNS round. No answer after " +
|
||||||
|
TIMEOUT_MS + "ms.", callbackWithNullNetwork.waitForAnswer());
|
||||||
|
assertTrue(msg + " with null network returned 0 results",
|
||||||
|
!callbackWithNullNetwork.isAnswerEmpty());
|
||||||
|
|
||||||
|
// Reset process network to default.
|
||||||
|
mCM.bindProcessToNetwork(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user