NsdService should set the Inet6Address scope ids
Link local Inet6Address cannot be used without scope id being set
properly. NsdService should set the Inet6Address scopes everywhere
NsdServiceInfo.setHost or NsdServiceInfo.setHostAddresses is used.
Test: atest CtsNetTestCases:android.net.cts.NsdManagerTest
Bug: 273391977
Change-Id: I45da6aebeba4e2e398e0b58ce3b88470fb60863b
diff --git a/service-t/src/com/android/server/NsdService.java b/service-t/src/com/android/server/NsdService.java
index cbe6691..c00f1ae 100644
--- a/service-t/src/com/android/server/NsdService.java
+++ b/service-t/src/com/android/server/NsdService.java
@@ -72,6 +72,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
@@ -1155,22 +1156,7 @@
Log.e(TAG, "Invalid attribute", e);
}
}
- final List<InetAddress> addresses = new ArrayList<>();
- for (String ipv4Address : serviceInfo.getIpv4Addresses()) {
- try {
- addresses.add(InetAddresses.parseNumericAddress(ipv4Address));
- } catch (IllegalArgumentException e) {
- Log.wtf(TAG, "Invalid ipv4 address", e);
- }
- }
- for (String ipv6Address : serviceInfo.getIpv6Addresses()) {
- try {
- addresses.add(InetAddresses.parseNumericAddress(ipv6Address));
- } catch (IllegalArgumentException e) {
- Log.wtf(TAG, "Invalid ipv6 address", e);
- }
- }
-
+ final List<InetAddress> addresses = getInetAddresses(serviceInfo);
if (addresses.size() != 0) {
info.setHostAddresses(addresses);
clientInfo.onResolveServiceSucceeded(clientId, info);
@@ -1202,21 +1188,7 @@
}
}
- final List<InetAddress> addresses = new ArrayList<>();
- for (String ipv4Address : serviceInfo.getIpv4Addresses()) {
- try {
- addresses.add(InetAddresses.parseNumericAddress(ipv4Address));
- } catch (IllegalArgumentException e) {
- Log.wtf(TAG, "Invalid ipv4 address", e);
- }
- }
- for (String ipv6Address : serviceInfo.getIpv6Addresses()) {
- try {
- addresses.add(InetAddresses.parseNumericAddress(ipv6Address));
- } catch (IllegalArgumentException e) {
- Log.wtf(TAG, "Invalid ipv6 address", e);
- }
- }
+ final List<InetAddress> addresses = getInetAddresses(serviceInfo);
info.setHostAddresses(addresses);
clientInfo.onServiceUpdated(clientId, info);
break;
@@ -1232,6 +1204,36 @@
}
}
+ @NonNull
+ private static List<InetAddress> getInetAddresses(@NonNull MdnsServiceInfo serviceInfo) {
+ final List<String> v4Addrs = serviceInfo.getIpv4Addresses();
+ final List<String> v6Addrs = serviceInfo.getIpv6Addresses();
+ final List<InetAddress> addresses = new ArrayList<>(v4Addrs.size() + v6Addrs.size());
+ for (String ipv4Address : v4Addrs) {
+ try {
+ addresses.add(InetAddresses.parseNumericAddress(ipv4Address));
+ } catch (IllegalArgumentException e) {
+ Log.wtf(TAG, "Invalid ipv4 address", e);
+ }
+ }
+ for (String ipv6Address : v6Addrs) {
+ try {
+ final InetAddress addr = InetAddresses.parseNumericAddress(ipv6Address);
+ if (addr.isLinkLocalAddress()) {
+ final Inet6Address v6Addr = Inet6Address.getByAddress(
+ null /* host */, addr.getAddress(),
+ serviceInfo.getInterfaceIndex());
+ addresses.add(v6Addr);
+ } else {
+ addresses.add(addr);
+ }
+ } catch (IllegalArgumentException | UnknownHostException e) {
+ Log.wtf(TAG, "Invalid ipv6 address", e);
+ }
+ }
+ return addresses;
+ }
+
private static void setServiceNetworkForCallback(NsdServiceInfo info, int netId, int ifaceIdx) {
switch (netId) {
case NETID_UNSET:
diff --git a/tests/cts/net/src/android/net/cts/NsdManagerTest.kt b/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
index db4f937..da0341a 100644
--- a/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
+++ b/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
@@ -96,6 +96,8 @@
import com.android.testutils.waitForIdle
import java.io.File
import java.io.IOException
+import java.net.Inet6Address
+import java.net.InetAddress
import java.net.NetworkInterface
import java.net.ServerSocket
import java.nio.charset.StandardCharsets
@@ -132,6 +134,7 @@
@AppModeFull(reason = "Socket cannot bind in instant app mode")
@RunWith(AndroidJUnit4::class)
+@ConnectivityModuleTest
class NsdManagerTest {
// Rule used to filter CtsNetTestCasesMaxTargetSdkXX
@get:Rule
@@ -696,6 +699,20 @@
}
}
+ private fun checkAddressScopeId(iface: TestNetworkInterface, address: List<InetAddress>) {
+ val targetSdkVersion = context.packageManager
+ .getTargetSdkVersion(context.applicationInfo.packageName)
+ if (targetSdkVersion <= Build.VERSION_CODES.TIRAMISU) {
+ return
+ }
+ val ifaceIdx = NetworkInterface.getByName(iface.interfaceName).index
+ address.forEach {
+ if (it is Inet6Address && it.isLinkLocalAddress) {
+ assertEquals(ifaceIdx, it.scopeId)
+ }
+ }
+ }
+
@Test
fun testNsdManager_ResolveOnNetwork() {
// This test requires shims supporting T+ APIs (NsdServiceInfo.network)
@@ -731,6 +748,7 @@
assertEquals(registeredInfo.serviceName, it.serviceName)
assertEquals(si.port, it.port)
assertEquals(testNetwork1.network, nsdShim.getNetwork(it))
+ checkAddressScopeId(testNetwork1.iface, it.hostAddresses)
}
// TODO: check that MDNS packets are sent only on testNetwork1.
} cleanupStep {
@@ -970,6 +988,7 @@
for (hostAddress in hostAddresses) {
assertTrue(addresses.contains(hostAddress))
}
+ checkAddressScopeId(testNetwork1.iface, serviceInfoCb.serviceInfo.hostAddresses)
} cleanupStep {
nsdManager.unregisterService(registrationRecord)
registrationRecord.expectCallback<ServiceUnregistered>()