diff --git a/tests/cts/net/jni/NativeMultinetworkJni.cpp b/tests/cts/net/jni/NativeMultinetworkJni.cpp index 5bd3013819..2832c3d142 100644 --- a/tests/cts/net/jni/NativeMultinetworkJni.cpp +++ b/tests/cts/net/jni/NativeMultinetworkJni.cpp @@ -145,7 +145,7 @@ int expectAnswersNotValid(JNIEnv* env, int fd, int expectedErrno) { } extern "C" -JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNqueryCheck( +JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNqueryCheck( JNIEnv* env, jclass, jlong nethandle) { net_handle_t handle = (net_handle_t) nethandle; @@ -155,29 +155,15 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNqueryCheck( EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_noerror), "v4 res_nquery check answers"); - // V4 NXDOMAIN - fd = android_res_nquery(handle, kNxDomainName, ns_c_in, ns_t_a, 0); - EXPECT_GE(env, fd, 0, "v4 res_nquery NXDOMAIN"); - EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_nxdomain), - "v4 res_nquery NXDOMAIN check answers"); - // V6 fd = android_res_nquery(handle, kHostname, ns_c_in, ns_t_aaaa, 0); EXPECT_GE(env, fd, 0, "v6 res_nquery"); EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_noerror), "v6 res_nquery check answers"); - - // V6 NXDOMAIN - fd = android_res_nquery(handle, kNxDomainName, ns_c_in, ns_t_aaaa, 0); - EXPECT_GE(env, fd, 0, "v6 res_nquery NXDOMAIN"); - EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_nxdomain), - "v6 res_nquery NXDOMAIN check answers"); - - return 0; } extern "C" -JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNsendCheck( +JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNsendCheck( JNIEnv* env, jclass, jlong nethandle) { net_handle_t handle = (net_handle_t) nethandle; // V4 @@ -200,15 +186,6 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNsendCheck( EXPECT_EQ(env, 0, expectAnswersValid(env, fd1, AF_INET, ns_r_noerror), "v4 res_nsend 1st check answers"); - // V4 NXDOMAIN - memset(buf1, 0, sizeof(buf1)); - len1 = makeQuery(kNxDomainName, ns_t_a, buf1, sizeof(buf1)); - EXPECT_GT(env, len1, 0, "v4 res_mkquery NXDOMAIN"); - fd1 = android_res_nsend(handle, buf1, len1, 0); - EXPECT_GE(env, fd1, 0, "v4 res_nsend NXDOMAIN"); - EXPECT_EQ(env, 0, expectAnswersValid(env, fd1, AF_INET, ns_r_nxdomain), - "v4 res_nsend NXDOMAIN check answers"); - // V6 memset(buf1, 0, sizeof(buf1)); memset(buf2, 0, sizeof(buf2)); @@ -226,21 +203,47 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNsendCheck( "v6 res_nsend 2nd check answers"); EXPECT_EQ(env, 0, expectAnswersValid(env, fd1, AF_INET6, ns_r_noerror), "v6 res_nsend 1st check answers"); - - // V6 NXDOMAIN - memset(buf1, 0, sizeof(buf1)); - len1 = makeQuery(kNxDomainName, ns_t_aaaa, buf1, sizeof(buf1)); - EXPECT_GT(env, len1, 0, "v6 res_mkquery NXDOMAIN"); - fd1 = android_res_nsend(handle, buf1, len1, 0); - EXPECT_GE(env, fd1, 0, "v6 res_nsend NXDOMAIN"); - EXPECT_EQ(env, 0, expectAnswersValid(env, fd1, AF_INET6, ns_r_nxdomain), - "v6 res_nsend NXDOMAIN check answers"); - - return 0; } extern "C" -JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNcancelCheck( +JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNnxDomainCheck( + JNIEnv* env, jclass, jlong nethandle) { + net_handle_t handle = (net_handle_t) nethandle; + + // res_nquery V4 NXDOMAIN + int fd = android_res_nquery(handle, kNxDomainName, ns_c_in, ns_t_a, 0); + EXPECT_GE(env, fd, 0, "v4 res_nquery NXDOMAIN"); + EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_nxdomain), + "v4 res_nquery NXDOMAIN check answers"); + + // res_nquery V6 NXDOMAIN + fd = android_res_nquery(handle, kNxDomainName, ns_c_in, ns_t_aaaa, 0); + EXPECT_GE(env, fd, 0, "v6 res_nquery NXDOMAIN"); + EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET6, ns_r_nxdomain), + "v6 res_nquery NXDOMAIN check answers"); + + uint8_t buf[MAXPACKET] = {}; + // res_nsend V4 NXDOMAIN + int len = makeQuery(kNxDomainName, ns_t_a, buf, sizeof(buf)); + EXPECT_GT(env, len, 0, "v4 res_mkquery NXDOMAIN"); + fd = android_res_nsend(handle, buf, len, 0); + EXPECT_GE(env, fd, 0, "v4 res_nsend NXDOMAIN"); + EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_nxdomain), + "v4 res_nsend NXDOMAIN check answers"); + + // res_nsend V6 NXDOMAIN + memset(buf, 0, sizeof(buf)); + len = makeQuery(kNxDomainName, ns_t_aaaa, buf, sizeof(buf)); + EXPECT_GT(env, len, 0, "v6 res_mkquery NXDOMAIN"); + fd = android_res_nsend(handle, buf, len, 0); + EXPECT_GE(env, fd, 0, "v6 res_nsend NXDOMAIN"); + EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET6, ns_r_nxdomain), + "v6 res_nsend NXDOMAIN check answers"); +} + + +extern "C" +JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNcancelCheck( JNIEnv* env, jclass, jlong nethandle) { net_handle_t handle = (net_handle_t) nethandle; @@ -251,11 +254,10 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNcancelCheck( EXPECT_EQ(env, 0, err, "res_cancel"); // DO NOT call cancel or result with the same fd more than once, // otherwise it will hit fdsan double-close fd. - return 0; } extern "C" -JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNapiMalformedCheck( +JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNapiMalformedCheck( JNIEnv* env, jclass, jlong nethandle) { net_handle_t handle = (net_handle_t) nethandle; @@ -311,8 +313,6 @@ JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNapiMalformedCheck EXPECT_GE(env, fd, 0, "res_nsend 500 bytes filled with 0xFF"); EXPECT_EQ(env, 0, expectAnswersNotValid(env, fd, -EINVAL), "res_nsend 500 bytes filled with 0xFF check answers"); - - return 0; } extern "C" diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index ef8badd32a..c32a7a08fd 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -21,6 +21,7 @@ import static android.net.DnsResolver.FLAG_EMPTY; import static android.net.DnsResolver.FLAG_NO_CACHE_LOOKUP; import static android.net.DnsResolver.TYPE_A; import static android.net.DnsResolver.TYPE_AAAA; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.system.OsConstants.ETIMEDOUT; import android.annotation.NonNull; @@ -36,6 +37,7 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.ParseException; +import android.net.cts.util.CtsNetUtils; import android.os.CancellationSignal; import android.os.Handler; import android.os.Looper; @@ -62,7 +64,9 @@ public class DnsResolverTest extends AndroidTestCase { }; static final String TEST_DOMAIN = "www.google.com"; + static final String TEST_NX_DOMAIN = "test1-nx.metric.gstatic.com"; static final String INVALID_PRIVATE_DNS_SERVER = "invalid.google"; + static final String GOOGLE_PRIVATE_DNS_SERVER = "dns.google"; static final byte[] TEST_BLOB = new byte[]{ /* Header */ 0x55, 0x66, /* Transaction ID */ @@ -86,6 +90,7 @@ public class DnsResolverTest extends AndroidTestCase { private ContentResolver mCR; private ConnectivityManager mCM; + private CtsNetUtils mCtsNetUtils; private Executor mExecutor; private Executor mExecutorInline; private DnsResolver mDns; @@ -101,6 +106,7 @@ public class DnsResolverTest extends AndroidTestCase { mExecutor = new Handler(Looper.getMainLooper())::post; mExecutorInline = (Runnable r) -> r.run(); mCR = getContext().getContentResolver(); + mCtsNetUtils = new CtsNetUtils(getContext()); storePrivateDnsSetting(); } @@ -309,6 +315,14 @@ public class DnsResolverTest extends AndroidTestCase { doTestRawQueryNXDomain(mExecutorInline); } + public void testRawQueryNXDomainWithPrivateDns() throws Exception { + doTestRawQueryNXDomainWithPrivateDns(mExecutor); + } + + public void testRawQueryNXDomainInlineWithPrivateDns() throws Exception { + doTestRawQueryNXDomainWithPrivateDns(mExecutorInline); + } + public void doTestRawQuery(Executor executor) throws InterruptedException { final String msg = "RawQuery " + TEST_DOMAIN; for (Network network : getTestableNetworks()) { @@ -364,11 +378,46 @@ public class DnsResolverTest extends AndroidTestCase { } public void doTestRawQueryNXDomain(Executor executor) throws InterruptedException { - final String dname = "test1-nx.metric.gstatic.com"; - final String msg = "RawQuery " + dname; + final String msg = "RawQuery " + TEST_NX_DOMAIN; + for (Network network : getTestableNetworks()) { + final NetworkCapabilities nc = (network != null) + ? mCM.getNetworkCapabilities(network) + : mCM.getNetworkCapabilities(mCM.getActiveNetwork()); + assertNotNull("Couldn't determine NetworkCapabilities for " + network, nc); + // Some cellular networks configure their DNS servers never to return NXDOMAIN, so don't + // test NXDOMAIN on these DNS servers. + // b/144521720 + if (nc.hasTransport(TRANSPORT_CELLULAR)) continue; final VerifyCancelCallback callback = new VerifyCancelCallback(msg); - mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, + mDns.rawQuery(network, TEST_NX_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, + executor, null, callback); + + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + callback.assertNXDomain(); + } + } + + public void doTestRawQueryNXDomainWithPrivateDns(Executor executor) + throws InterruptedException { + final String msg = "RawQuery " + TEST_NX_DOMAIN + " with private DNS"; + + // Enable private DNS strict mode and set server to dns.google before doing NxDomain test. + // b/144521720 + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); + Settings.Global.putString(mCR, + Settings.Global.PRIVATE_DNS_SPECIFIER, GOOGLE_PRIVATE_DNS_SERVER); + + for (Network network : getTestableNetworks()) { + final Network networkForPrivateDns = + (network != null) ? network : mCM.getActiveNetwork(); + assertNotNull("Can't find network to await private DNS on", networkForPrivateDns); + mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout", + networkForPrivateDns, GOOGLE_PRIVATE_DNS_SERVER, + PRIVATE_DNS_SETTING_TIMEOUT_MS); + final VerifyCancelCallback callback = new VerifyCancelCallback(msg); + mDns.rawQuery(network, TEST_NX_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, executor, null, callback); assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", @@ -615,23 +664,6 @@ public class DnsResolverTest extends AndroidTestCase { } } - 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(); @@ -647,8 +679,8 @@ public class DnsResolverTest extends AndroidTestCase { if (network == null) continue; // wait for private DNS setting propagating - awaitPrivateDnsSetting(msg + " wait private DNS setting timeout", - network, INVALID_PRIVATE_DNS_SERVER); + mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout", + network, INVALID_PRIVATE_DNS_SERVER, PRIVATE_DNS_SETTING_TIMEOUT_MS); final CountDownLatch latch = new CountDownLatch(1); final DnsResolver.Callback> errorCallback = diff --git a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java index c3e65b7bd2..88e86f4063 100644 --- a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java +++ b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java @@ -16,18 +16,22 @@ package android.net.cts; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; + import android.content.Context; +import android.content.ContentResolver; import android.net.ConnectivityManager; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkUtils; +import android.net.cts.util.CtsNetUtils; +import android.provider.Settings; import android.system.ErrnoException; import android.system.OsConstants; import android.test.AndroidTestCase; import java.util.ArrayList; - public class MultinetworkApiTest extends AndroidTestCase { static { @@ -35,6 +39,8 @@ public class MultinetworkApiTest extends AndroidTestCase { } private static final String TAG = "MultinetworkNativeApiTest"; + static final String GOOGLE_PRIVATE_DNS_SERVER = "dns.google"; + static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 2_000; /** * @return 0 on success @@ -43,18 +49,44 @@ public class MultinetworkApiTest extends AndroidTestCase { private static native int runSetprocnetwork(long networkHandle); private static native int runSetsocknetwork(long networkHandle); private static native int runDatagramCheck(long networkHandle); - private static native int runResNapiMalformedCheck(long networkHandle); - private static native int runResNcancelCheck(long networkHandle); - private static native int runResNqueryCheck(long networkHandle); - private static native int runResNsendCheck(long networkHandle); - + private static native void runResNapiMalformedCheck(long networkHandle); + private static native void runResNcancelCheck(long networkHandle); + private static native void runResNqueryCheck(long networkHandle); + private static native void runResNsendCheck(long networkHandle); + private static native void runResNnxDomainCheck(long networkHandle); + private ContentResolver mCR; private ConnectivityManager mCM; + private CtsNetUtils mCtsNetUtils; + private String mOldMode; + private String mOldDnsSpecifier; + @Override protected void setUp() throws Exception { super.setUp(); mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); + mCR = getContext().getContentResolver(); + mCtsNetUtils = new CtsNetUtils(getContext()); + 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 Network[] getTestableNetworks() { @@ -182,13 +214,34 @@ public class MultinetworkApiTest extends AndroidTestCase { } catch (IllegalArgumentException e) {} } - public void testResNApi() { - for (Network network : getTestableNetworks()) { + public void testResNApi() throws InterruptedException { + final Network[] testNetworks = getTestableNetworks(); + + for (Network network : testNetworks) { // Throws AssertionError directly in jni function if test fail. runResNqueryCheck(network.getNetworkHandle()); runResNsendCheck(network.getNetworkHandle()); runResNcancelCheck(network.getNetworkHandle()); runResNapiMalformedCheck(network.getNetworkHandle()); + + final NetworkCapabilities nc = mCM.getNetworkCapabilities(network); + // Some cellular networks configure their DNS servers never to return NXDOMAIN, so don't + // test NXDOMAIN on these DNS servers. + // b/144521720 + if (nc != null && !nc.hasTransport(TRANSPORT_CELLULAR)) { + runResNnxDomainCheck(network.getNetworkHandle()); + } + } + // Enable private DNS strict mode and set server to dns.google before doing NxDomain test. + // b/144521720 + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); + Settings.Global.putString(mCR, + Settings.Global.PRIVATE_DNS_SPECIFIER, GOOGLE_PRIVATE_DNS_SERVER); + for (Network network : testNetworks) { + // Wait for private DNS setting to propagate. + mCtsNetUtils.awaitPrivateDnsSetting("NxDomain test wait private DNS setting timeout", + network, GOOGLE_PRIVATE_DNS_SERVER, PRIVATE_DNS_SETTING_TIMEOUT_MS); + runResNnxDomainCheck(network.getNetworkHandle()); } } } diff --git a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java index e19d2bafb7..f0c34e3eaf 100644 --- a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java +++ b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java @@ -24,12 +24,14 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.annotation.NonNull; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; +import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo; @@ -243,6 +245,23 @@ public final class CtsNetUtils { return s; } + public void awaitPrivateDnsSetting(@NonNull String msg, @NonNull Network network, + @NonNull String server, int timeoutMs) 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(timeoutMs, TimeUnit.MILLISECONDS)); + mCm.unregisterNetworkCallback(callback); + } + /** * Receiver that captures the last connectivity change's network type and state. Recognizes * both {@code CONNECTIVITY_ACTION} and {@code NETWORK_CALLBACK_ACTION} intents.