What’s the Deal with IPv6 Link-Local Addresses?

栏目: IT技术 · 发布时间: 4年前

内容简介:IPv6 link-local addresses are addresses that can be used to communicate with nodes (hosts and routers) on an attached link. Packets with those addresses are not forwarded by routers. At least, they should not be. There have been cases where routers would h

Introduction

IPv6 link-local addresses are addresses that can be used to communicate with nodes (hosts and routers) on an attached link. Packets with those addresses are not forwarded by routers. At least, they should not be. There have been cases where routers would happily forward packets with a link-local source address.

IPv6 link-local addresses are defined by RFC 4291 (IPv6 Addressing Architecture) and are covered by the prefix fe80::/10. In practice, only fe80::/64 is used.

At first glance, IPv6 link-local addresses are similar to IPv4 link-local addresses, which are defined in RFC 3927 (Dynamic Configuration of IPv4 Link-Local Addresses). IPv4 link-local addresses are taken from the prefix 169.254.0.0/16.

However, there is a big difference: an IPv4 link-local address is typically assigned to an interface when DHCP fails to supply an address. So IPv4 link-local addresses show up when there are no other IPv4 addresses.

In contrast, IPv6 link-local addresses are used next to other IPv6 addresses. Typically, a node will assign IPv6 link-local addresses to interfaces as soon as they have become available. Beyond that, IPv6 routers advertise link-local addresses to hosts (and other routers). IPv6 link-local addresses are used quite a lot.

For example, if you run "ip addr" on a Linux system, you will get something like this:

$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: enp0s5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:11:22:33:44:55 brd ff:ff:ff:ff:ff:ff
    inet 192.0.2.42/24 brd 192.0.2.255 scope global noprefixroute dynamic enp0s5
       valid_lft 767sec preferred_lft 767sec
    inet6 2001:db8::8c28:c929:72db:49fe/64 scope global noprefixroute dynamic
       valid_lft 2591998sec preferred_lft 604798sec
    inet6 fe80::9656:d028:8652:66b6/64 scope link noprefixroute
       valid_lft forever preferred_lft forever

This host has two interfaces, a loopback interface "lo", and an ethernet interface "enp0s5". The ethernet interface has an IPv4 address and two IPv6 addresses:

  • A global address "2001:db8::8c28:c929:72db:49fe" 
  • A link-local address "fe80::9656:d028:8652:66b6"

Link-locals and sockets

IPv6 link-local addresses would have been just a tiny detail of the whole IPv6 ecosystem if it was not for sockets API. The sockets API is a series of system calls, with names like socket() , bind() , connect() , send() , sendto() , recv() , recvfrom() , that were first introduced in version 4.2 of the BSD Unix operating system and later became a standard for almost all Unix-like operating systems.

Specifying an outgoing interface for a connection or a packet is a long standing problem with sockets API. In most cases, the kernel can pick a suitable interface. However, when that fails or when the user wants to override the kernel's decision, there is only an indirect way of specifying an interface.

To make it work, you need to explicitly select a local address on the desired interface (assuming that addresses are unique among interfaces). For IPv6 link-local addresses, we can assume that this is not the case. For example, a router may use the address fe80::1 on all interfaces as shown in Figure 1:

What’s the Deal with IPv6 Link-Local Addresses?

Figure 1: A router with four interfaces

RFC 3493 (Basic Socket Interface Extensions for IPv6) describes extensions to the socket interface to make it usable for IPv6. The RFC describes a field called sin6_scope_id that can be used to specify an interface. Because this field is part of the socket address structure, struct sockaddr_in6 , it transparently extends existing socket calls such as connect() or sendto() with the ability to specify an outgoing interface.

The RFC also defines function calls if_nametoindex() and if_indextoname() to convert interface names to numbers suitable for the  sin6_scope_id and the other way around. However, the RFC does not define if or when these numbers have to be used.

At this point, it is important to keep in mind that an organisation called The Open Group maintains a specification that provides a standard for Unix and Unix-like operating systems. This is the official reference for Unix system calls and Unix-specific library calls.

The Open Group Base Specifications Issue 7, 2018 edition , IEEE Std 1003.1-2017 (Revision of IEEE Std 1003.1-2008) has this to say about the sin6_scope_id field:

The sin6_scope_id field is a 32-bit integer that identifies a set of interfaces as appropriate for the scope of the address carried in the sin6_addr field. For a link scope sin6_addr, the application shall ensure that sin6_scope_id is a link index. For a site scope sin6_addr, the application shall ensure that sin6_scope_id is a site index. The mapping of sin6_scope_id to an interface or set of interfaces is implementation-defined.

In short, it is not possible to use an IPv6 link-local address in sockets API without selecting an appropriate interface as well. This is a significant departure from the past: knowing an IP address is no longer enough.

Textual representation of scoped addresses

One question remains: is there a textual representation that contains both an IPv6 address and an outgoing interface? The answer is yes. RFC 4007 (IPv6 Scoped Address Architecture) introduces the percent sign ("%") as a separator between an IPv6 address literal and a zone_id . It describes that a zone identifier can be numeric or a string. Therefore, we can refer to the address fe80::1 on interface eth0 as fe80::1%eth0 and (if eth0 maps to interface number 1) as fe80::1%1 .

What’s the Deal with IPv6 Link-Local Addresses?

RFC 3493 introduced new library calls called getaddrinfo() and getnameinfo() to perform DNS lookups. These calls can also parse (and generate) address literals. Surprisingly, there doesn't seem to be a standard that requires the functions to handle zone identifiers. All I could find is an Internet-Draft . In practice, this format is generally supported and many applications that use getaddrinfo() can transparently accept link-local addresses with zone identifiers as well.

Some applications use the function inet_pton to parse address literals. This function cannot deal with a zone identifier because it operates on struct in6_addr , which contains only an IPv6 address and has no space for a zone identifier.

Finally, RFC 6874 (Representing IPv6 Zone Identifiers in Address Literals and Uniform Resource Identifiers) describes how zone identifiers can be encoded in URLs. The problem is that the percent sign is special in URLs. Indeed, the percent sign that separates the zone identifier from the address literal has to be written as "%25".

DNS resolvers with link-local addresses

How does all of this relate to RIPE Atlas, which performs measurements over the Internet and goes to great length to prevent people from measuring a probe's local network? The answer is that RIPE Atlas does support measurements that involve a probe's DNS resolvers. And these DNS resolvers can have link-local addresses.

Please note that in the following I will only consider hardware probes and will excluded anchors and software probes. For a long time, RIPE Atlas probes did not have a mechanism to recognise DNS resolvers with IPv6 addresses. Neither DHCPv6 was supported nor the Recursive DNS Server (RDNSS) option in Router Advertisements ( RFC 8106 , IPv6 Router Advertisement Options for DNS Configuration).

Later, when we were working on supporting the RDNSS option, we decided to leave out zone identifiers in the first implementation. The reason is that the use of link-local addresses for DNS resolvers is quite rare and dealing with zone identifiers is complex.

Supporting zone identifiers not only required changes to our code but the libevent library, which is used to perform asynchronous DNS lookups also had to be changed to support them. The changes to libevent have been shared with the maintainers of libevent.

Impact on RIPE Atlas

This would have been a tiny detail of how RIPE Atlas probes work, if it was not for the textual representation of IPv6 addresses. Measurement results have fields called src_addr and dst_addr that contain respectively the local address and the target address of measurement instance. When the measurement target is a link-local address with a zone identifier these fields can be expected to contain addresses with zone identifers as well. This is likely to break existing address parsers that do not take zone identifiers into account.

Reality is even more complex than that. The current measurement code uses inet_ntop() , which cannot handle zone identifiers, to print dst_addr . Whereas src_addr is generated using getnameinfo() , which can handle zone identifiers on Version 4 probes, but not on Version 3 probes. Version 3 probes run an older version of OpenWRT. Presumably, support for zone identifiers has been added later, but we didn't verify that. A future firmware relase should make this more consistent.

Version 1 and Version 2 probes will only get firmware updates to address security problems, so they will probably never support IPv6 link-Local addresses. For anchors and software probes, the measurement code will use whatever it finds in /etc/resolv.conf . So far, none of those contained link-local addresses.

Conclusion

In this post, we gave an overview of what IPv6 address zone identifiers are ("the thing after the %-sign") and show how we handle so called zone identifiers in RIPE Atlas. We hope this was useful for those dealing with making legacy systems IPv6 ready. Comments and questions are, as always, very welcome in the dedicated section below.


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Egret——HTML5游戏开发指南

Egret——HTML5游戏开发指南

张鑫磊 等 / 电子工业出版社 / 2016-3 / 85

《Egret——HTML5游戏开发指南》由浅入深,在讲解游戏开发基础的同时提供众多实战案例供读者学习。《Egret——HTML5游戏开发指南》章节内容包含Egret基础概念及基础图形图像处理方法、网络相关操作、移动设备适配、性能优化、文本动画相关知识、调试技巧、DragonBones骨骼动画系统和P2物理引擎等。通过《Egret——HTML5游戏开发指南》,读者可以了解并掌握HTML5游戏开发技能......一起来看看 《Egret——HTML5游戏开发指南》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具