Merge pull request #4065 from alim0x/master

[translated]Should distributors disable IPv4-mapped IPv6
This commit is contained in:
Ezio 2016-06-16 09:34:00 -05:00 committed by GitHub
commit d66a7980c9
2 changed files with 60 additions and 62 deletions

View File

@ -1,62 +0,0 @@
alim0x translating
Should distributors disable IPv4-mapped IPv6?
=============================================
By all accounts, the Internet's transition to IPv6 has been a slow affair. In recent years, though, perhaps inspired by the exhaustion of the IPv4 address space, IPv6 usage has been [on the rise][1]. There is a corresponding interest in ensuring that applications work with both IPv4 and IPv6. But, as a recent discussion on the OpenBSD mailing list has highlighted, a mechanism designed to ease the transition to an IPv6 network may also make the net less secure — and Linux distributions may be configured insecurely by default.
### Address mapping
IPv6 may look like IPv4 in many ways, but it is a different protocol with a different address space. Server programs wanting to receive connections using either protocol must thus open separate sockets for the two different address families — AF_INET for IPv4, and AF_INET6 for IPv6. In particular, a program wishing to accept connections to any of a host's interfaces using either protocol will need to create an AF_INET socket bound to the all-zeroes wild-card address (0.0.0.0) and an AF_INET6 socket bound to the IPv6 equivalent (written as "::"). It must then listen for connections on both sockets — or so one would think.
Many years ago, in [RFC 3493][2], the IETF specified a mechanism by which a program could work with either protocol using a single IPv6 socket. With a socket enabled for this behavior, the program need only bind to :: to receive connections to all interfaces with both protocols. When an IPv4 connection is made to the bound port, the source address will be mapped into IPv6 as described in [RFC 2373][3]. So, for example, a program using this mode would see an incoming connection from 192.168.1.1 as originating from ::ffff:192.168.1.1 (the mixed notation is how such addresses are ordinarily written). The program can also open connections to IPv4 addresses by mapping them in the same manner.
The RFC calls for this behavior to be implemented by default, so most systems do so. There are exceptions, though, one of which is OpenBSD; there, programs wishing to work with both protocols can only do so by creating two independent sockets. A program that opens two sockets on Linux, though, will run into trouble: both the IPv4 and the IPv6 socket will try to bind to the IPv4 address(es), so whichever attempt comes second will fail. In other words, a program that binds a socket to a given port on :: will be bound to that port on both the IPv6 :: and the IPv4 0.0.0.0. If it then tries to bind an IPv4 socket to the same port on 0.0.0.0, the operation will fail as the port is already bound.
There is a way around that problem, of course; the program can call setsockopt() to turn on the IPV6_V6ONLY option. A program that opens two sockets and sets IPV6_V6ONLY should be portable across all systems.
Readers may be less than thoroughly shocked to learn that not every program out there gets all of this right. One of those, it turns out, is the [OpenNTPD][4] implementation of the Network Time Protocol. Brent Cook recently [proposed a small patch][5] adding the requisite setsockopt() call to the upstream OpenNTPD source, which lives within OpenBSD itself. That patch does not look likely to be accepted, though, for the most OpenBSD-like of reasons.
### Security concerns
As mentioned above, OpenBSD does not support IPv4-mapped IPv6 sockets at all. Even if a program tries to explicitly enable address mapping by setting the IPV6_V6ONLY option to zero, its author will be disappointed; that setting has no effect on OpenBSD systems. The reasoning behind this decision is that this mapping brings some security concerns with it. There are various types of attack surface that it opens up, but it all comes down to the provision of two different ways to reach the same port, each with its own access-control rules.
Any given server system may have set up firewall rules describing the allowed access to the port in question. There may also be mechanisms like TCP wrappers or a BPF-based filter in place, or a router on the net could be doing its own stateful connection filtering. The result is likely to be gaps in firewall protection and the potential for all kinds of confusion resulting from the same IPv4 address being reachable via two different protocols. If the address mapping is done at the edge of the network, the situation gets even more complex; see [this draft RFC from 2003][6] for a description of some other attack scenarios that come about if mapped addresses are transmitted between hosts.
Adapting systems and software to properly handle IPv4-mapped IPv6 addresses can certainly be done. But that adds to the overall complexity of the system, and it's a sure bet that this adaptation has not actually been done anywhere near as widely as it should be. As Theo de Raadt [put it][7]:
**Sometimes people put a bad idea into an RFC. Later they discover it is impossible to walk the idea back to the garbagebin. The result is concepts so complicated that everyone has to be a fulltime expert, on admin side and coder side**.
It is not at all clear how many of these full-time experts are actually out there configuring systems and networks where IPv4-mapped IPv6 addresses are in use.
One might well argue that, while IPv4-mapped IPv6 addresses create security hazards, there should be no harm in changing a program so that it turns off address mapping on systems that implement it. But Theo argues that this should not be done, for a couple of reasons. The first is that there are many broken programs out there, and it will never be possible to fix them all. But the real reason is to put pressure on distributors to turn off address mapping by default. As he put it: "**Eventually someone will understand the damage is systematic, and change the system defaults to 'secure by default'**."
### Address mapping on Linux
On Linux systems, address mapping is controlled by a sysctl knob called net.ipv6.bindv6only; it is set to zero (enabling address mapping) by default. Administrators (or distributors) can turn off mapping by setting this knob to one, but they would be well advised to be sure that their applications all work properly before deploying such a system in production. A quick survey suggests that none of the primary distributors change the default for this knob; Debian [changed the default][9] for the "squeeze" release in 2009, but the change broke enough packages ([anything involving Java][10], for example) that it was, [after a certain amount of Debian-style discussion][11], reverted. It would appear that quite a few programs rely on address mapping being enabled by default.
OpenBSD has the freedom to break things outside of its core system in the name of "secure by default"; Linux distributors tend to have a harder time getting away with such changes. So those distributors, being generally averse to receiving abuse from their users, are unlikely to change the default of the bindv6only knob anytime soon. The good news is that this functionality has been the default for years and stories of exploits are hard to find. But, as we all know, that provides no guarantees that exploits are not possible.
--------------------------------------------------------------------------------
via: https://lwn.net/Articles/688462/
作者:[Jonathan Corbet][a]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://lwn.net/
[1]: https://www.google.com/intl/en/ipv6/statistics.html
[2]: https://tools.ietf.org/html/rfc3493#section-3.7
[3]: https://tools.ietf.org/html/rfc2373#page-10
[4]: https://github.com/openntpd-portable/
[5]: https://lwn.net/Articles/688464/
[6]: https://tools.ietf.org/html/draft-itojun-v6ops-v4mapped-harmful-02
[7]: https://lwn.net/Articles/688465/
[8]: https://lwn.net/Articles/688466/
[9]: https://lists.debian.org/debian-devel/2009/10/msg00541.html
[10]: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=560056
[11]: https://lists.debian.org/debian-devel/2010/04/msg00099.html

View File

@ -0,0 +1,60 @@
发行版分发者应该禁用 IPv4 映射的 IPv6 地址吗
=============================================
大家都说,互联网向 IPv6 的过渡是件很缓慢的事情。不过在最近几年,可能是由于 IPv4 地址资源的枯竭IPv6 的使用处于[上升态势][1]。相应的,开发者也有兴趣确保软件能在 IPv4 和 IPv6 下工作。但是,正如近期 OpenBSD 邮件列表的讨论所关注的,一个使得向 IPv6 转换更加轻松的机制设计同时也可能导致网络更不安全——并且 Linux 发行版们的默认配置可能并不安全。
### 地址映射
IPv6 在很多方面看起来可能很像 IPv4但它是带有不同地址空间的不同的协议。服务器程序想要接受使用二者之中任意一个协议的连接必须给两个不同的地址族分别打开一个套接字——IPv4 的 AF_INET 和 IPv6 的 AF_INET6。特别是一个程序希望接受使用任意协议到任意主机接口的连接的话需要创建一个绑定到全零通配符地址0.0.0.0)的 AF_INET 套接字和一个绑定到 IPv6 等效地址(写作“::”)的 AF_INET6 套接字。它必须在两个套接字上都监听连接——或者有人会这么认为。
多年前,在 [RFC 3493][2]IETF 指定了一个机制,程序可以使用一个单独的 IPv6 套接字工作在两个协议之上。有了一个启用这个行为的套接字,程序只需要绑定到 :: 来接受使用这两个协议到达所有接口的连接。当创建了一个 IPv4 连接到绑定端口,源地址会像 [RFC 2373][3] 中描述的那样映射到 IPv6。所以举个例子一个使用了这个模式的程序会将一个 192.168.1.1 的传入连接看作来自 ::ffff:192.168.1.1(这个混合的写法就是这种地址通常的写法)。程序也能通过相同的映射方法打开一个到 IPv4 地址的连接。
RFC 要求这个行为要默认实现所以大多数系统这么做了。不过也有些例外OpenBSD 就是其中之一;在那里,希望在两种协议下工作的程序能做的只能是创建两个独立的套接字。但一个在 Linux 中打开两个套接字的程序会遇到麻烦IPv4 和 IPv6 套接字都会尝试绑定到 IPv4 地址,所以不论是哪个后者都会失败。换句话说,一个绑定到 :: 指定端口的套接字的程序会同时绑定到 IPv6 :: 和 IPv4 0.0.0.0 地址的那个端口上。如果程序之后尝试绑定一个 IPv4 套接字到 0.0.0.0 的相同端口上时,这个操作会失败,因为这个端口已经被绑定了。
当然有个办法可以解决这个问题;程序可以调用 setsockopt() 来打开 IPV6_V6ONLY 选项。一个打开两个套接字并且设置了 IPV6_V6ONLY 的程序应该可以在所有的系统间移植。
读者们可能对不是每个程序都能正确处理这一问题没那么震惊。事实证明这些程序的其中之一是网络时间协议Network Time Protocol的 [OpenNTPD][4] 实现。Brent Cook 最近给上游 OpenNTPD 源码[提交了一个小补丁][5],添加了必要的 setsockopt() 调用,它也被提交到了 OpenBSD 中了。尽管那个补丁看起来不大可能被接受,最可能是因为 OpenBSD 式的理由LCTT 译注如前文提到的OpenBSD 并不受这个问题的影响)。
### 安全担忧
正如上文所提到OpenBSD 根本不支持 IPv4 映射的 IPv6 套接字。即使一个程序试着通过将 IPV6_V6ONLY 选项设置为 0 显式地启用地址映射,它的作者会感到沮丧,因为这个设置在 OpenBSD 系统中无效。这个决定背后的原因是这个映射带来了一些安全担忧。攻击打开接口的攻击类型有很多种,但它们最后都会回到规定的两个途径到达相同的端口,每个端口都有它自己的控制规则。
任何给定的服务器系统可能都设置了防火墙规则,描述端口的允许访问权限。也许还会有适当的机制,比如 TCP wrappers 或一个基于 BPF 的过滤器,或一个网络上的路由可以做连接状态协议过滤。结果可能是导致防火墙保护和潜在的所有类型的混乱连接之间的缺口导致同一 IPv4 地址可以通过两个不同的协议到达。如果地址映射是在网络边界完成的,情况甚至会变得更加复杂;参看[这个 2003 年的 RFC 草案][6],它描述了如果映射地址在主机之间传送,一些随之而来的其它攻击场景。
改变系统和软件合适地处理 IPv4 映射的 IPv6 地址当然可以实现。但那增加了系统的整体复杂度,并且可以确定这个改动没有实际完整实现到它应该实现的范围内。如同 Theo de Raadt [说的][7]
**有时候人们将一个坏主意放进了 RFC。之后他们发现不可能将这个主意扔回垃圾箱了。结果就是概念变得如此复杂每个人都得在管理和编码方面是个全职专家。**
我们也根本不清楚这些全职专家有多少在实际配置使用 IPv4 映射的 IPv6 地址的系统和网络。
有人可能会说,尽管 IPv4 映射的 IPv6 地址造成了安全危险,更改一下程序让它关闭部署实现它的系统上的地址映射应该没什么危害。但 Theo 认为不应该这么做,有两个理由。第一个是有许多破损的程序,它们永远不会被修复。但实际的原因是给发行版分发者压力去默认关闭地址映射。正如他说的:“**最终有人会理解这个危害是系统性的并更改系统默认行为使之secure by default**。”
### Linux 上的地址映射
在 Linux 系统,地址映射由一个叫做 net.ipv6.bindv6only 的 sysctl 开关控制;它默认设置为 0启用地址映射。管理员或发行版分发者可以通过将它设置为 1 关闭地址映射但在部署这样一个系统到生产环境之前最好确认软件都能正常工作。一个快速调查显示没有哪个主要发行版分发者改变这个默认值Debian 在 2009 年的 “squeeze” 中[改变了这个默认值][9],但这个改动破坏了足够多的软件包(比如[任何包含 Java 的][10][在经过了一定数量的 Debian 式讨论之后][11],它恢复到了原来的设置。看上去不少程序依赖于默认启用地址映射。
OpenBSD 有自由以“secure by default”的名义打破其核心系统之外的东西Linux 发行版分发者倾向于更难以作出这样的改变。所以那些一般不愿意收到他们用户的不满的发行版分发者,不太可能很快对 bindv6only 的默认设置作出改变。好消息是这个功能作为默认已经很多年了,但很难找到利用的例子。但是,正如我们都知道的,谁都无法保证这样的利用不可能发生。
--------------------------------------------------------------------------------
via: https://lwn.net/Articles/688462/
作者:[Jonathan Corbet][a]
译者:[alim0x](https://github.com/alim0x)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://lwn.net/
[1]: https://www.google.com/intl/en/ipv6/statistics.html
[2]: https://tools.ietf.org/html/rfc3493#section-3.7
[3]: https://tools.ietf.org/html/rfc2373#page-10
[4]: https://github.com/openntpd-portable/
[5]: https://lwn.net/Articles/688464/
[6]: https://tools.ietf.org/html/draft-itojun-v6ops-v4mapped-harmful-02
[7]: https://lwn.net/Articles/688465/
[8]: https://lwn.net/Articles/688466/
[9]: https://lists.debian.org/debian-devel/2009/10/msg00541.html
[10]: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=560056
[11]: https://lists.debian.org/debian-devel/2010/04/msg00099.html