创建家庭IPv6网络

2020-09-21 18:50:49

Linux Plumbers Conference最近的一次经历让我确信,如果你想成为真正开源的基于WebRTC的点对点音频/视频交互的一部分,你需要一个不在NAT后面的互联网地址。实际上,只要您可以联系STUN服务器告诉您外部地址是什么,并且如果两个端点都是NAT的,可能还可以联系TURN服务器来代理数据包,协议仍然可以工作,但是所有这些寻找外部服务器都需要时间,就像那些抱怨回声测试的人所发现的那样。所有这一切的解决方案是通过IPv6连接,IPv6的地址空间足够大,足以支持地球上每台拥有自己地址的设备。所有现代Linux发行版都支持IPv6开箱即用,因此您很有可能在不知不觉中意外地使用了它,这是IPv6自动配置的优点之一(它应该可以正常工作)。

然而,我最近搬家了,所以我的光纤互联网连接断了,但电缆确实附带了IPv6地址,所以这就是我让一切正常工作的故事。如果您并不真正关心协议基础知识,您可以跳到如何操作。本指南还重点介绍“双堆栈”配置(既有IPv6地址又有IPv4地址的配置)。纯IPv6配置是可能的,但是因为Internet的某些部分仍然只有IPv4,所以除非您设置IPv4封装网桥,否则它们是不完整的。

IPv6已经是一个成熟的协议很长一段时间了,所以我错误地认为它会有很多好的HOWTO。然而,在阅读了20种关于IPv6 128位地址空间如何工作的不同描述之后,我绝望地放弃了,转而阅读RFC。我假设您已经阅读了这些HOWTO中的至少一个,所以我不必深入到IPv6地址前缀、后缀、接口ID或子网,所以我将从大多数HOWTO结束的地方开始。

在IPv4中,有一种称为动态主机配置协议(DHCP)的协议,因此只要找到DHCP服务器,就可以获得连接所需的所有信息(本地地址、路由器、DNS服务器、时间服务器等)。但是,此服务必须由某人设置,而IPv6的设计目的是在没有该服务的情况下配置网络。

IPv6无状态地址自动配置(SLAAC)做出的第一个假设是它位于/64子网上(因此IPv6中的每个子网包含的地址是整个IPv4互联网的10-10倍)。这意味着,由于大多数真实子网包含<;100系统,它们只需选择一个随机地址,就不太可能与现有系统发生冲突。事实上,当前在/64中选择地址的方式有三种:

基于MAC地址的EUI-64(RFC 4291),MAC地址基本上是翻转一位的MAC,中间放置ff:Fe。

稳定专用(RFC 7217),根据基于静态密钥、接口、前缀和计数器的散列生成(如果存在冲突,则计数器递增)。与EUI-64相比,EUI-64首选EUI-64,EUI-64提供与MAC地址相关的任何配置(例如您拥有的网卡类型)。

隐私扩展地址(RFC 4941)非常类似于稳定的私有地址,不同之处在于它们使用IPv6地址弃用机制随时间更改,并且适用于希望保持匿名性的客户端系统。

Linux中的下一个问题是由谁配置接口?内核IPv6堆栈实际上就是这样设计的,除非被告知不要这样做,否则会这样做,但大多数现代网络控制器(如NetworkManager)都是控制怪胎,会关闭内核的自动配置,这样他们就可以自己做了。它们还默认使用文件系统中维护的静态秘密(/var/lib/networkManager/secrekey)进行稳定的私有寻址。

关于IPv6地址,下一件要了解的事情是,它们被划分为作用域,其中最重要的是链路本地(不可路由)地址,这些地址通常都具有前缀fe80::/64。链路本地地址首先使用上述方法之一进行配置,然后用于探测网络。

与IPv4不同,IPv6没有广播功能,因此所有发现都是通过组播完成的。网络上的节点通过交换机截获的特殊数据包订阅特定的组播地址,并且不会接收到它们未订阅的任何组播。通常,所有链路本地组播地址都具有前缀ff02::/64(有关其他类型的组播地址,请参阅RFC 4291)。所有节点都订阅“All Nodes”多播地址ff02::1,并且还必须订阅它们自己的请求节点多播地址ff02::1:ffXX:XXXX,其中最后24位对应于节点IPv6地址的最低24位。后者是为了避免过去在IPv4中发生的ARP广播中断,因为现在您可以针对特定节点子集进行地址解析。

IPv6地址解析协议称为邻居请求(NS),在RFC 4861中描述,它与RFC 4862中描述的SLAAC一起使用,通过向您要发现的包含您想要知道的完整IPv6地址的节点的邻居请求地址发送多播来实现,具有匹配地址的节点使用邻居通告(NA)数据包中的链路层(MAC)地址进行回复。

一旦节点选择了其链路本地地址,它首先向其选择的地址发送NS分组,以查看是否有人应答,如果没有人应答,则假定保留该分组是可以的,否则它遵循与其特定地址形式相关联的冲突避免协议。一旦找到唯一地址,节点就会配置此链路本地地址并查找路由器。请注意,如果不存在IPv6网络,发现将在此停止,这就是为什么大多数网络接口总是显示链路本地IPv6地址的原因。

一旦该节点具有其自己的唯一链路本地地址,它就使用它将路由器请求(RS)分组发送到“所有路由器”多播地址ff02::2。网络上的每个路由器用路由器通告(RA)分组进行响应,该分组描述(除其他外)路由器生命周期、网络MTU、路由器负责的一组一个或多个前缀、路由器的链路地址和一组选项标志,包括M(受管理的)和O(其他配置)标志以及可能的一组DNS服务器。

每个通告的前缀包含前缀和前缀长度、包括A(自主配置)和L(链路本地)的一组标志以及一组生存期。链路本地前缀告诉您本地网络用户的全局前缀是什么(可能有多个),以及是否允许您在全局前缀上执行SLAAC(如果A标志已清除,您必须使用DHCPv6向路由器请求地址)。如果路由器的生命周期非零,您可以假定它是子网的默认路由器。

现在节点已经发现了一个或多个路由器,它可以配置自己的全局地址(请注意,每个IPv6可路由节点至少有两个地址:一个本地链路和一个全局地址)。它如何做到这一点取决于路由器和前缀标志

节点需要知道的第一件事是将SLAAC用于全局地址还是使用DHCPv6。这完全由RA分组中的任何链路本地前缀的A标志确定。如果设置了A,则节点可以使用SLAAC,如果清除了A,则节点必须使用DHCPv6来获取地址。如果设置了A并且还设置了M(被管理)标志,则节点可以使用SLAAC或DHCPv6(或两者)来获得地址,并且如果M标志是清除的,但是存在O(其他配置)标志,则节点必须使用SLAAC,但是可以使用DHCPv6来获得关于网络的其他信息(通常是DNS)。

一旦中的节点有了全局地址,现在就需要默认路由。它根据路由器寿命非零的RA数据包形成默认路由列表。所有这些都配置为使用RA指定的跳数到达其链路本地地址的默认路由。最后,节点可以从具有零路由器寿命但非链路本地前缀的RA分组添加特定的前缀路由。

DHCPv6是一个相当复杂的配置协议(请参阅RFC 8415),但它既不能指定前缀长度(意味着所有获取的地址都配置为/128),也不能指定路由(这些地址必须从RA数据包获取)。这会导致微妙的出站地址选择,因为最具体的地址总是首选的,因此如果您同时按SLAAC和DHCPv6配置,则SLAAC地址将添加为/64,DHCPv6地址将添加为/128,这意味着您的出站IP地址将始终是DHCPv6地址(尽管如果外部实体知道您的SLAAC地址,他们仍可以通过该地址联系到您)。

从上面可以看出,ipv6总是自动配置的,确实,如果您只需将笔记本电脑插入电缆调制解调器的以太网端口,它就会自动配置,但大多数人都有涉及路由器的更复杂的家庭设置,这需要一些特殊的诱骗才能正常工作。这意味着您需要使用特殊的DHCPv6请求从ISP获取其他功能。

这一节是从我自己的角度写的:我有一个相当复杂的IPv4网络,它有一个完全开放但带宽有限(对不信任的客户端)的WiFi网络,以及几个受保护的内部网络(一个用于我的实验室,一个用于我的手机,一个用于家用摄像机),因此我需要至少4个子网来为我家中的每台设备提供IPv6地址。我还使用OpenWRT作为我的路由器发行版,因此所有IPv6配置信息都高度特定于它(尽管应该注意,如果您准备深入阅读文档,NetworkManager等工具也可以完成所有这些操作)。

由于DHCPv6只分发/128地址,这是不够的,因为它是路由器本身的IP地址。要成为路由器,您必须通过DHCPv6的前缀删除身份关联(IA_PD)选项请求部分IPv6地址空间的委派。一旦完成此操作,ISP将假定路由器IP地址是所有委派前缀的路由。这里的微妙之处在于,如果您想要多个子网,您必须明确地请求它(客户端必须指定它正在查找的确切前缀长度),并且由于它是前缀长度,并且您的默认子网应该是/64,如果您请求的前缀长度为64,则您只有一个子网。如果您请求63,则有2个,以此类推。问题是您如何知道ISP愿意为您分配多少个子网?不幸的是,没有办法找到这一点(我不得不进行互联网搜索才发现我的ISP Comcast愿意委托前缀长度为60,即16个子网)。如果搜索没有告诉你你的ISP愿意委派多少,你可以试着从48开始,以1为增量逐步增加到64,看看你能摆脱的最大委派是什么(有报道称,ISP将你锁定在第一个委派的前缀长度,所以不要从64开始)。最后一个微妙之处是,您被委派的前缀可能与您的路由器获得的地址不同(我当前的Comcast配置使我的路由器的地址为2001:558:600A:…。但我的委托前缀是2601:600:8280:66d0:/60)。注如果您必须探测您的ISP以了解您可以获得的前缀大小,您可以使用-P选项手动运行odhcp6c。

在OpenWRT术语中,路由器WAN DHCP(V6)配置由/etc/default/network控制。您已经有一个用于DHCPv4的WAN接口(可能称为‘wan’),所以您只需添加一个额外的‘wan6’接口就可以获得额外的IPv6并成为双堆栈。在我的配置中,这看起来像。

稍微奇怪的是ifname:@wan只是告诉配置使用与‘wan’接口相同的ifname。如果您的WAN是一座桥,那么这样命名是必不可少的,但无论如何这都是很好的做法。另一个选项‘reqprefix’告诉DHCPv6请求/60前缀委派。

事实证明,这非常简单。首先,您必须为路由器上的每个其他接口分配一个委托前缀,但是您无需为每个接口添加新的OpenWRT接口就可以做到这一点。我的内部IPv4网络都是静态地址,因此您可以向每个接口添加三条指令:

配置接口';LAN';...。接口指定(我的网桥)选项PROTO';STATE';...。IPv4地址选项ip6assign';64';选项ip6hint';1';选项ip6ifaceid';::FF';

Ip6assign‘N’表示您是/N网络(因此对我来说,这始终是/64),ip6hint‘N’表示使用N作为子网ID,ip6ifaceid‘S’表示使用S作为IPv6后缀(默认值为::1,因此如果您同意,请省略此指令)。因此,假设我的前缀为2601:600:8280:66d0::/60,则此接口的全局地址将为2601:600:8280:66d1::FF。现在关键的测试是,如果您没有弄错,这个全局地址应该可以从IPv6互联网上的任何地方ping通(如果不是,很可能是防火墙问题,见下文)。

仅仅在本地路由器接口上获得委派的前缀是不够的。现在,您需要让路由器响应ff02::2上的路由器请求,还可以选择执行DHCPv6。不幸的是,OpenWRT有两种机制来实现这一点,通常都安装了:odhcpd和dnsmasq。我发现,在完全禁用odhcpd之前,/etc/config/dhcp中的任何指令都不会生效。

由于我在其他地方广泛使用dnsmasq(内部/外部网络拆分DNS),所以很适合我。我将首先描述dnsmasq中需要哪些选项,然后描述如何使用OpenWRT/etc/config/dhcp文件中的条目来实现这一点(我发现这很有用,因为检查OpenWRT在/var/etc/dnsmasq.conf文件中放了什么总是明智的做法)。

您需要的第一个dnsmasq选项是‘enable-ra’,它是指示dnsmasq处理路由器通告的全局参数。您需要的下一个参数是每个接口的‘ra-param’,它指定全局路由器通告参数,并且必须为您要通告的每个接口出现一次。最后,‘dhcp-range’选项允许更详细地配置RA标志和可选DHCPv6的类型。

在很多方面,这是个人选择的问题。如果您允许SLAAC,想要使用隐私扩展地址的主机(如Android手机)可以这样做,这是一件好事。如果您还允许DHCPv6地址选择,您将拥有一个分配给主机的地址列表,dnsmasq将为它们执行DNS解析(尽管它可以为SLAAC地址执行DNS,前提是它被告知了这些地址)。‘dhcp-range’选项有一个特殊的标记‘structor’,它告诉它从指定接口的IPv6全局前缀构造提供的地址(用于RA或DHCPv6),这是您分发委派前缀地址的方式。‘dhcp-range’的模式是‘ra-only’,表示完全禁止DHCPv6;‘slac’,表示允许DHCPv6地址选择;‘ra-statless’,表示不允许DHCPv6地址选择,但允许其他DHCPv6配置信息。

基于反复试验(最后检查/etc/init.d/dnsmasq中的脚本),实现上述dnsmasq选项所需的OpenWRT选项如下

配置dhcp lan选件接口lan选件start 100选件限制150选件leasetime 1h选件dhcpv6';server;选件ra_management&1;选件ra';server';

关键选项为‘ra_management’,‘0’表示带有DHCPv6选项的SLAAC,‘1’表示具有完整DHCPv6的SLAAC,‘2’表示仅DHCPv6,‘3’表示仅SLAAC。OpenWRT的另一个奇怪之处在于,似乎没有一种方法可以设置租用范围:它总是缺省为static only或::1000 to::ffff。

让人们绊倒的一件事是Linux有两个完全独立的防火墙:一个用于IPv4,另一个用于IPv6。如果您曾经为它们编写过任何自定义规则,那么您很可能是在OpenWRT/etc/Firewall.user文件中编写的,并且使用了iptables命令,这意味着您只将规则添加到了IPv4防火墙。要为IPv6添加相同的规则,您需要使用ip6tables命令复制它。另一个重要的问题是,如果您像我一样使用连接跟踪进行端口敲门检测,那么Linux连接跟踪在IPv6多播方面有困难,因此发送到多播但作为单播返回的数据包(就像大多数发现协议一样)会获得错误的连接跟踪状态。要解决这个问题,我最终必须有一个输入规则,只接受所有ICMPv6和DHCPv6(UDP端口546[客户端]和547[服务器])。其他防火墙注意事项是,现在每个人都有自己的IP地址,没有必要进行NAT(可以说服OpenWRT自动处理此问题,但如果您要手动复制IPv4规则,请不要复制NAT规则)。最后一个可能更适用于我:我的wifi接口被设计成本地互联网的延伸,所有连接到它的机器都应该能够保护自己,因为它们会迁移到机场wifi这样的恶劣环境,因此我会将连接wifi的设备完全暴露在所有端口的一般互联网上,包括端口探测器。对于我的内部设备,我有一个相关的既定规则,以确保它们不会被探测,因为它们不是为从内部网络迁移而设计的。

现在OpenWRT的问题是:因为您想要IPv4上的NAT,而不是IPv6上的NAT,所以您必须为它们有两个单独的WAN区域:如果您尝试组合它们(就像我第一次做的那样),那么OpenWRT将添加一个IPv6-ctstate无效规则,该规则将因为IPv6多播的连接问题而阻止邻居发现工作,所以我的WAN区域是(嗯,这是一个谎言,因为我的防火墙现在是手工创建的,但这是我在安装手动创建的防火墙之前检查过的):

配置区域选项名称';WAN';选项网络';WAN';选项Masq';1';...配置区域选项名称';wan6';选项网络';wan6';...。

配置转发选件src';lan';选件DEST';wan';配置转发选件src';lan';选件DEST';wan6';配置转发选件src';wan6';选件DEST';lan';选件DEST';lan';

现在您已经配置了路由器,一切都应该正常工作。如果是这样的话,您的笔记本电脑WiFi接口现在应该有一个全局IPv6地址。

如果返回的结果为空,则需要在您的发行版上启用IPv6。如果它只有一个本地链路地址(fe80::prefix),则IPv6已启用,但您的路由器没有通告(发现数据包或dnsmasq错误配置可能存在防火墙问题)。如果您看到一个全球地址,那么您就完成了。现在您应该能够访问https://testv6.com并获得10/10的分数。

最后一个难题是,当DNS提供IPv4或IPv6地址选择时,您更喜欢新的IPv6连接。如果连接到双协议栈网络,所有现代Linux客户机都应该更喜欢IPv6,所以尝试使用…。如果你ping,比如说www.google.com,看到一个IPv6地址,你就完了。如果不是,您需要进入IPv6地址标签(RFC6724)和gai.conf的黑暗世界。

将IPv6添加到现有IPv4设置当前不是简单的即插即用操作。但是,只要您了解两个协议之间的一些不同之处,这也不是一个无法克服的问题。我还略过了您与ISP之间可能遇到的许多问题。有人报告说,他们的ISP只分发一个IPv6地址,没有前缀委派,在这种情况下,我认为找一个新的ISP是最明智的。其他人报告说ISP将只委派一个/64前缀,因此您在这里的选择要么是只运行一个子网(可能足够很多家庭网络使用),要么是子网大于/64并禁止SLAAC,这绝对不是建议的配置。但是,如果您的ISP是合理的,

.