Flask应用程序支持双重IPv4和IPv6

14

Flask是否可以同时监听IPv4和IPv6(即双重IP堆栈)?据我所知,可以使用以下命令在IPv4上运行:

app.run(host='0.0.0.0', port=80)

但是要想在IPv6上运行,需要使用以下命令:

app.run(host='::', port=80)

这将使Flask应用程序在任何可用的网络接口上均可用。

app.run(host='0.0.0.0', port=port, debug=True)

或使用IPv6

app.run(host='::', port=port, debug=True)

但我还没有找到一种同时在两个IP版本上运行的方法(可以有一个Flask应用程序实例监听IPv4,另一个实例监听IPv6,但两者不能同时监听同一端口)。

谢谢!

更新(额外信息):

根据Sander Steffann的评论(感谢!),我已经开始让我的应用程序在IPv6上进行监听:

* Running on http://[::]:1028/
* Restarting with reloader

接下来使用IPv6和IPv4 curls进行测试:

curl -g [::1]:1028/notify
curl 127.0.0.1:1028/notify

分别获得:

::1 - - [10/Feb/2014 12:04:51] "GET /notify HTTP/1.1" 200 -
::ffff:127.0.0.1 - - [10/Feb/2014 12:05:03] "GET /notify HTTP/1.1" 200 -

我的理解是第二行表明“某些东西”(操作系统?Flask所依赖的底层网络库?)正在将IPv4请求转换成IPv6请求。但我理解这并不等同于在经典的双栈设置中原生支持IPv4,也就是说,我本来希望得到类似这样的结果(当我运行应用程序时会得到这个结果:Running on http://0.0.0.0:1028/

127.0.0.1 - - [10/Feb/2014 12:05:03] "GET /notify HTTP/1.1" 200 -

如果它们无法在同一端口上侦听,则很可能IPv6实例也接受IPv4连接(即V6ONLY已关闭)。你能测试一下吗? - Sander Steffann
感谢@SanderSteffann!我已经完成了那个测试,并相应地更新了问题的内容。 - fgalan
我在下面添加了一个答案。它回答了你的问题吗? - Sander Steffann
2个回答

14
发生的情况是操作系统自动将传入的IPv4请求附加到侦听IPv6套接字上。通过在IPv4地址前加上::ffff:,将IPv4地址mapped映射到IPv6地址。因此,来自127.0.0.1的传入IPv4连接看起来像来自IPv6地址::ffff:127.0.0.1
从客户端的角度来看,它正在与IPv4服务器通信。客户端无法区分差异。从服务器的角度来看,每个人都使用IPv6连接。操作系统执行IPv4数据包和IPv6软件之间的映射。
这样做的效果是,您可以开发软件,而无需手动处理双栈编程。所有软件都可以为IPv6编写,并将所有地址视为IPv6地址进行处理。这可以简化代码(无需处理同时具有侦听IPv4和侦听IPv6套接字等) ,同时仍向“外部”提供完整的双栈体验。

因此,从您系统外部看,您的服务完全是双栈的。在应用程序本身中,您将看到整个世界都用IPv6地址表示,就像您在日志文件中显示的那样。通常不会引起任何问题。但这可能会影响您处理ACL、日志记录和其他类似事情的方式。


采用已接受的解决方案,当在主机名上运行curl -6时,仍然出现问题。它不接受IPv6地址。当我只使用IPv6时,它可以工作。运行我的应用程序只需使用::即可处理所有用例(IPv4和IPv6),同时加上IPv4地址前缀。这可能是Flask的新版本中出现的。 - SKipp

1

不幸的是,尽管Linux使用映射的IPv4地址来确定“::”,但这在其他几个IPv6堆栈上不起作用,例如Microsoft Windows。由于安全原因,Windows和其他IPv6堆栈实现者决定不将IPv4地址映射到IPv6地址空间中,除非应用程序特别发出信号要这样做。据我了解讨论的理由是,否则可能会发生意外的IPv4连接,从而破坏ACL或其他应用层安全机制。


1
在Windows上,您可以通过在绑定到地址之前将IPV6_V6ONLY套接字选项设置为0来选择“双栈套接字”(https://learn.microsoft.com/en-us/windows/win32/winsock/dual-stack-sockets#creating-a-dual-stack-socket)。在Linux上,可以将相同的套接字选项设置为`1`以选择退出此行为(https://man7.org/linux/man-pages/man7/ipv6.7.html)。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接