如何使用 IPv6 链路本地地址作为 Retrofit 的基本 URL

huangapple go评论85阅读模式
英文:

How to use a IPv6 link-local address with Retrofit as baseUrl

问题

我正在使用NsdManager来解析本地网络上的服务(物联网设备)。resolveService会返回带有主机和端口的NsdServiceInfo。主机是一个带有链路本地地址(fe80::xxxx:xxxx:xxxx:9718)和无范围设置的Inet6Address对象。它还返回isLinkLocalAddress的true。我怎样才能使用这个没有范围的链路本地地址进行网络调用

唯一能用本地机器对服务进行ping的方法是同时指定网络接口,例如:ping6 fe80::xxxx:xxxx:xxxx:9718%en0

感觉我可能遗漏了Android API或IPv6规范的一些重要方面。个人而言,我宁愿获得IPv4地址,但似乎没有办法告诉NsdManager这一点。

英文:

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.

答案1

得分: 1

你可以尝试使用 Java 网络 API 中的 NetworkInterface 类以编程方式检索接口的名称。例如:

    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()
英文:

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()

答案2

得分: 0

首先,了解IPv6链路本地地址具有特定的用途,通常不用于正常网络流量。

来自_RFC 4291, IPv6地址架构_:

链路本地地址设计用于在单个链路上进行寻址,用于自动地址配置、邻居发现或在没有路由器存在时。

其次,因为设备中的所有接口都使用相同的链路本地网络,您必须使用区域标识 (Zone ID) 来区分用于目的地的接口。请记住,即使是主机(例如PC、打印机等)也有路由表,因此它们必须使用区域标识来区分链路本地地址。

来自_RFC 6874, 在地址文字和统一资源标识符中表示IPv6区域标识符_:

因为相同的非全局地址可能在同一作用域的多个区域中使用(例如,在两个单独的物理链路中使用链路本地地址fe80::1)并且节点可能连接到同一作用域的不同区域(例如,路由器通常具有连接到不同链路的多个接口),节点需要一种内部手段来识别非全局地址属于哪个区域。这是通过在节点内部为该节点附加到的同一作用域的每个区域分配一个不同的“区域索引”,并允许将地址的所有内部使用都限定为区域索引来实现的。

对于IPv6链路本地寻址,使用区域标识 (Zone ID) 是一个要求。实际上,目前链路本地寻址是唯一允许使用区域标识的情况。

来自_RFC 6874, 在地址文字和统一资源标识符中表示IPv6区域标识符_:

为了限制这种风险,实现必须不允许除了一些明确定义的用途之外使用这种格式,例如发送到fe80::/10前缀下的链路本地地址。在撰写本文时,这是唯一已知的明确定义用途。

您可以使用其他独特的寻址方式,例如ULA(RFC 4193, 唯一本地IPv6单播地址),以避免该要求。对于ULA,您可以在fc00::/7范围内使用寻址,但有限制,限制您在fd00::/8范围内,其中下一个40位必须随机选择,从中获得一个包含65,536个标准/64 IPv6网络的/48前缀。

英文:

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.

huangapple
  • 本文由 发表于 2023年4月11日 15:22:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/75983365.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定