0

I'm using the NsdManager to resolve a service on the local network (iot device). The resolveService returns me a NsdServiceInfo with a host and a port. The host is a Inet6Address object with a link-local address (fe80::xxxx:xxxx:xxxx:9718) and no scope set. It also returns me a true for isLinkLocalAddress. How can I use this link-local address without a scope to make any network call?

The only way I can ping the service with my local machine is by also specifying a network interface e.g. like this: ping6 fe80::xxxx:xxxx:xxxx:9718%en0.

It feels like I'm missing some vital aspect of the Android API or the IPv6 spec here. Personally, I'd rather just get a IPv4 address but there doesn't seem to be a way to tell the NsdManager that either.

Oliver Metz
  • 2,712
  • 2
  • 20
  • 32

2 Answers2

1

you can try to retrieve the name of the interface programmatically using the NetworkInterface class from the Java networking API. For example:

val interfacename = NetworkInterface.getNetworkInterfaces()
    .toList()
    .find { interface ->
        interface.inetAddresses.any { address ->
            address is Inet6Address && address.isLinkLocalAddress
        }
    }
    ?.name

val baseUrl = "http://[fe80::xxxx:xxxx:xxxx:9718%$interfacename]:port/"

val retrofit = Retrofit.Builder()
    .baseUrl(baseUrl)
    .build()
Jaspalsinh Gohil
  • 941
  • 1
  • 9
  • 20
  • Turns out Retrofit/OkHttp doesn't support link-local addresses with scope. PR rejected here: https://github.com/square/okhttp/pull/4865. This might work with other libraries though. – Oliver Metz May 10 '23 at 04:13
0

First, understand that IPv6 Link-Local addresses have specific uses, and are not typically used for normal network traffic.

From RFC 4291, IP Version 6 Addressing Architecture:

Link-Local addresses are designed to be used for addressing on a single link for purposes such as automatic address configuration, neighbor discovery, or when no routers are present.

Next, because all interfaces in a device use the same Link-Local network, you must use a Zone ID to distinguish the interface meant for the destination. Remember that even hosts (PCs, printers, etc.) have routing tables, so they must distinguish Link-Local addresses using Zone IDs.

From RFC 6874, Representing IPv6 Zone Identifiers in Address Literals and Uniform Resource Identifiers:

Because the same non-global address may be in use in more than one zone of the same scope (e.g., the use of link-local address fe80::1 in two separate physical links) and a node may have interfaces attached to different zones of the same scope (e.g., a router normally has multiple interfaces attached to different links), a node requires an internal means to identify to which zone a non-global address belongs. This is accomplished by assigning, within the node, a distinct "zone index" to each zone of the same scope to which that node is attached, and by allowing all internal uses of an address to be qualified by a zone index.

Use of a Zone ID for IPv6 Link-Local addressing is a requirement. In fact, Link-Local addressing is currently the only allowed use of Zone IDs.

From RFC 6874, Representing IPv6 Zone Identifiers in Address Literals and Uniform Resource Identifiers:

To limit this risk, implementations MUST NOT allow use of this format except for well-defined usages, such as sending to link-local addresses under prefix fe80::/10. At the time of writing, this is the only well-defined usage known.

You could use some other unique addressing, e.g. ULA (RFC 4193, Unique Local IPv6 Unicast Addresses), to avoid that requirement. For ULA, you use addressing in the fc00::/7 range, with restrictions that limit you to the fd00::/8 range, where the next 40 bits must be randomly chosen, giving you a /48 prefix from which you get 65,536 standard /64 IPv6 networks.

Ron Maupin
  • 6,180
  • 4
  • 29
  • 36