开源路由器系统——VyOS家庭网络配置双栈路由
开源的软路由系统没什么稀奇的,但这个叫VyOS路由器系统真的很不一样……我们在配置路由器的过程中,继续深入的学习Linux网络栈和网络协议,并最终越过重重困难,成功实现自由的家庭网络……
路由器是一个非常典型的三层网络设备,主要的工作目标,是在两个不同的网络之间交换数据,就是我们俗称的“路由”。一台典型的路由器通常需要正确的与ISP建立连接,并且申请自身的网络地址,同时发现内网设备、配置这些设备的网络地址、转发它向外部网络发送的数据包,从而让内网的设备可以“上网”。路由器还是家庭网络边防的哨兵,负责把握整个家庭网络的入口,也是连接家庭网络和公共网络的唯一通道,其重要性可想而知。
一般情况,路由器都是长期开启的,时刻处理家庭网络中的各种主机的联网需求。由于我们对家庭网络的需求日益扩大,而现代优秀的商业路由器价格昂贵且不自由,所以更多的人把目标投向了“软路由”和一些开源路由器系统上。软路由和开源系统琳琅满目,让众多爱好者难以抉择适合自己的系统。
VyOS是我们最近找到的一款开源Linux软路由系统。这个系统的操作方法类似思科等专业的企业级路由器,通过命令行控制Linux里的各种网络软件的配置,进而搭配出一台能实现复杂网络功能的服务器。VyOS的基本使用方法,在网上已经有许多详细的入门教程,这篇文章不会过多缀述。我们主要介绍一下,如何用VyOS解决组网中复杂的配置问题,以及在配置中加深对网络协议和网络地址分配过程的理解。
我认为本文中最值得期待的部分就是我们重点而深入的介绍IPv6地址是如何在不同的物理设备中被层层分配和下发的。这一部分的内容,我们会结合我们最近搭建的一个实验环境来说明,我觉得这是非常令人感兴趣的话题,希望通过这篇文章能让大家对专业的开源路由器系统有更深层次的认知,并能自己动手实践,在家庭网络中部署一个这样的开源系统做路由器系统。
选择合适的路由器
Neboer确实很久没更新文章了。主要是最近我们成立了一个叫道达软件(UntilSoftware)的开发小组,我们的基础网络设施——服务器、主机、路由器等等还在不断的筹划和建设中。毕竟我们需要对外提供稳定的网络服务,所以路由器也绝对不能含糊。一开始我们使用商业路由器做我们的路由器,比如华硕路由器、华为路由器等等,这些路由器都很优秀,我承认——在现在,只要一个路由器支持WiFi6、支持千兆以太网、支持IPv6,那么它就是一个很好的路由器。不过这些路由器都有共同的特点——复杂而简陋。
为什么需要软路由
许多路由器,尤其是国产路由器,内部软件庞大而复杂,功能繁多——但同时,给用户提供的控制和管理UI又非常简单,即使是专业用户,也无法过多的控制其工作细节,甚至有的时候他们缺少那些让你抓狂的功能——比如华为路由器使用的固件在最近一次更新后,取消了“关闭IPv6防火墙”的功能,你要么将防火墙打开,要么将它关闭,你无法控制详细的防火墙规则。当然也有一些路由器确实做得很不错,提供了复杂而详细的防火墙配置等(比如我们之前用的华硕路由器,一分钱一分货),但是和硬件强绑定的、闭源的固件也让人望而却步——用户数据收集、行为分析、隐私监控……谁能保证路由器没有背着你做不好的事情?谁能保证这些路由器背后的技术团队总能第一时间修复安全漏洞?再说,这些路由器实在是太昂贵了,这些路由器的价格足够我们组出性能强出他们很多的x86主机做软路由了。当然也有一个很重要的一点,这些路由器都非常不专业,家用路由器面向的是消费级市场,有很多类似家长控制、无线信号调节、IPTV等等多余的功能,这和家庭服务器部署的需求不相匹配;而这些消费级路由器又不太能做到精细的防火墙控制等我们场景需要的功能,所以说其实家庭路由器是不适合应用在我们场景的——当然不是说我们一定要用专业路由器,就是我们能不能在易用性、功能性和专业性之间做一个平衡呢?所以我们想到了软路由这个解决方案。
所谓软路由,就是指一台普通的家用计算机,里面安装了一些操作系统,使得它可以当一个路由器来使用。比起闭源商业家用路由器,软路由有非常非常多的优势,比如依托服务器使得它有更强大的性能、使用的开源技术栈会获得更快的更新,功能强大,灵活安全……当我们将目光投放到软路由上时,一些非常经典的路由器系统便出现在了大家的脑海中——
一些软路由的简单对比
OpenWRT
我知道很多人已经等不及了。我前面说了这么一堆,说的好啊,为什么不用OpenWRT呢?OpenWRT可以解决我们的所有问题!真的吗?实际上,OpenWRT确实是很好的软路由系统,它应用广泛,历史悠久,支持得也很不错,我们一开始也在用OpenWRT,持续用了很长时间。但很快我们就发现OpenWRT对IPv6支持得并不好。我们自己在使用的时候也遇到过IPv6连接不稳定的情况,并且很多人也是这么认为的。OpenWRT与其说是一个软路由系统,其实更不如说是一个嵌入式Linux系统,它主要的目的是流畅运行在大多数品牌的路由器上,可以直接通过刷机的方法刷入,而软路由的话这种优势反而没什么用处,毕竟软路由已经跑在普通的家庭主机上了,任何系统都不会存在兼容性的问题。
爱快
在国内的爱好者社区里,爱快是一个挺出名的系统。不过我们就不要用了,毕竟它根本就不是开源软件,而且商业性质浓厚,使用高级功能需要付费,只能进行有限的功能拓展。并且还存在兼容性、安全性、政策相关的一系列问题,说到这大家应该都知道了,它肯定不是很适合我们使用的软路由系统。
pfsense/OPNsense
pfsense和OPNsense都是非常优秀的开源路由器系统,并且都配套了很好的WebUI供大家使用。WebUI确实是好东西,但是这些系统是基于FreeBSD开发的。这个操作系统确实没有Linux应用更广泛,不过FreeBSD的集中性使得它确实比Linux更稳定,在某种意义上更适合用来做路由器的操作系统。不过我在这里要指出两点,第一,即使是漏洞较少的OPNsense也拥有多达19个CVE,其中有5个高分漏洞,不过可利用性都比较差。第二,WebUI需要Web服务器支持,要额外消耗一些处理资源,带来多余的安全性的问题。并且配置分散,不如集中化配置直观。
systemd
如果对Linux网络结构有一定的认识的话,也可以抛弃软路由系统,自己实现一套路由器方案。在systemd项目旗下的systemd-networkd是目前Linux较为成熟的常用的网络管理工具之一,能够完成Linux内核支持的所有网络设备类型的创建/管理,以及与网络协议栈相关的地址分配等工作。除此以外它还能和各种外部工具(如dnsmasq,systemd-resolved,pppd)良好协作。systemd旗下系统管理套件的一大亮点是与现代Linux常用的防火墙系统nftables的良好协同,典型案例如systemd-networkd和systemd-nspawn在配置netfilter转发的时候只会管理nat行为,而将更改filter行为的任务交给用户,避免破坏系统的防火墙状态。正确使用sytemd-networkd和netfilter可以构建出一套精简和稳定的路由器系统。文档参见systemd.network和nftables。(这段话是Krusl写的,我觉得他说的对,但是)
不过,这样操作虽然适合专业用户,它还是会遇到一些问题。首先零散的配置文件分布在系统的每个角落,需要你手动维护,操作麻烦,配置风格不统一。其次,因为涉及到许多软件共同协作,导致你每次查阅文档时都需要参考不同的文档网站和手册,比较浪费时间。还有就是,软件之间可能存在一些冲突,不一定总能实现预期的目标。还有有些复杂的功能往往需要多个软件共同协作,同样的配置可能需要重复多次。当然你也可以选择一个使用统一配置的发行版,比如NixOS,当然也是Krusl最喜欢的系统,只是对于我来说,这是完全没有必要的负担罢了。
所以,选什么?就在我们纠结选择什么合适的路由器的时候,一个同样很优秀的软路由系统出现在了我们的眼前,它就是VyOS。
为什么选择VyOS
选择VyOS的原因其实非常简单,因为这个路由器系统足够的复杂,同时又足够的简单。它的工作原理非常简单,就是普通的将一些Linux中常用的路由工具集合起来,放进一个系统中,然后通过统一的配置文件动态的生成这些软件的配置,最后实现路由功能。它没有WebUI,但cli界面也比较易用,只需要把系统关键的配置信息输入进去,剩下的事情它就可以处理。
VyOS的知名度很高,根据其在官网上所说,其产品被各大企业和机构所使用。虽然总体来说VyOS还是一个相对小众的系统,但它在支持者中的口碑普遍比OpenWRT要好一些。具体可以参考他们官网中所说的成功之路。
VyOS是一个自由而开源的操作系统,分免费版和商业版两个版本,已经有了很多年的开发历史。安全性上,VyOS确实曾经爆出过两个比较严重的漏洞,不过相较于隔壁爆出更多漏洞的pfsense/OPNsense,也不是很让人惊讶了。
VyOS没有图形化界面,只有最基础的命令行配置方法。虽然有人曾经尝试为它编写一个WebUI——VyOSControl,但这个项目最终还是被放弃了。我认为这也不错,毕竟官方不需要去维护一个复杂的UI,可以将更多的精力放到系统本身。而且对有经验的用户来说,管理面板掩盖了系统本身的复杂性,而且必须强制接受它的逻辑,让人不爽。
VyOS有一些更不爽的问题,比如VyOS的LTS版本,也就是稳定版,是需要赞助才可以获取的,普通的用户只能下载到并不稳定的Nightly Build,而且它的商业模式很昂贵,每年高达数千美元的授权费用让人望而却步。
VyOS的配置系统不支持用户覆写配置,你只能按VyOS的规范来配置路由器,即使你明知VyOS的系统软件支持你的配置项,但还是不能越过VyOS的配置器强行更改它,除非你构建一份自己的VyOS。这个问题直接导致了比如不支持kea服务器进行更详细的日志、不支持不支持地区特性的无线网卡进行无线广播等功能(实际上VyOS对无线网卡支持反而非常非常不好)。
VyOS的开源,很值得玩味,比如VyOS曾经说,任何用户都可以从源代码的LTS分支自己构建一份LTS版本,但这其实是错误的,VyOS的LTS分支在发布LTS版本之后,仍然在滚动更新,你自己从LTS分支构建的镜像和VyOS为付费用户发布的LTS Release肯定是对不上的。这个问题在这个PR中被指出,开发者一开始有些误会,不过后来确实大方的承认了——VyOS分为“LTS”版和“开源”版,二者的代码是对不上的,使用开源代码肯定是构建不出他们发布的LTS版本的。
VyOS绝对不是一个100%好用的系统,类似以上的问题太多太多,在我仅仅使用VyOS不到一周的时间里,就发现了这么多奇奇怪怪的问题。
尽管。
尽管VyOS有许许多多的问题,但我依然固执的认为它是相当优秀的路由器系统。VyOS的功能繁杂,文档详细,在系统内部也有很多说明文本,补全流畅而舒适,基于Linux的本质使得你可以直接在shell里调用各种Linux系统命令,比如ping/curl等等,近似于通过一套配置机制,实现了和专业路由器系统相似的功能和操作方法,是相当天才的设计。
VyOS所使用的内核版本是Linux 6,对各种新硬件和新协议支持得都非常好,在内核里对IPv6提供了相当好的支持。同时VyOS里的软件版本也很新,都是属于你能找到的在Linux社区里最积极维护且专业性最强的路由器软件了。比如pppd,比如hostapd,比如dhcpcd,比如kea(dhcp server),还有对应的IPv6版本的软件……这些软件的配置被VyOS抽象出来,集中形成了一个由配置块组成的统一配置系统,可以进行方便的修改和更新。
VyOS运行速度快,而且开发维护积极且活跃,官方网站制作精美,文档全面,提供了比较完善的构建工具,源代码易懂,易于上手修改……总之,它作为一开源项目来说,已经相当合格了。VyOS的商业模式虽然昂贵,不过他们承诺对维护者、非盈利组织、应急部门、大学等人或机构无偿提供自己的LTS版本,也算是值得继续观察。
综上所述,我们使用VyOS做我们的路由器系统,便不难理解了。
构建VyOS LTS——难道,还是来晚了吗?
VyOS有很多问题,其中之一就是,它虽然是一个自由软件,但它并不免费——它的LTS构建只有赞助者、贡献者等人才能获取,并不对一般用户开放。但这并不意味着它不自由——它的所有代码都是开源的,想要任何版本,你可以自行构建。
很快我就会发现,VyOS可能是世界上最难以构建的开源项目,拜其开发团队所赐——他们成功的将构建VyOS的门槛实在是提高到了一个它本不该有的档次。
既然不能直接获得LTS版本……
那么我们要不要使用它每晚动态更新的RollingRelease版本呢?
……不,还是要部署一下LTS版本的。虽然经过我这段时间的研究,VyOS的滚动更新版本已经足够使用,没有必要为了追求真正的“稳定”,而使用一个落后的LTS版本;不过LTS三个大字对人还是非常有吸引力的。不过……要怎么获得他们呢?这里Neboer代表了NerChat!作为一个“非盈利组织”,向VyOS申请了一份“LTS”的名额,不过还没有得到回复。功利性的来说,这篇文章可能也符合“VyOS宣传”的需求,从而可以被用来获取一个VyOS的名额——但这绝对不是我写这篇文章的目的、这也绝对不会影响这篇文章的中立和客观性的立场。
对于个人来说,合法的获取到VyOS的最佳办法就是通过亲身使用并解决实际问题,在社交媒体或者其他的个人空间里分享使用VyOS的具体经验,并附上自己的文章的链接一并发送给VyOS的开发者,这样或许可以成功,我还没有尝试。
……那么是不是可以从源代码构建……
作为一个开源项目,VyOS当然支持源码构建。虽然VyOS官方的GitHub仓库中的LTS分支,并不是真正用来供给专业支持的LTS镜像使用的代码,但相对于Rolling Release来说LTS版本还是比较稳定的。VyOS给出了比较详细的构建指南,不过我认为VyOS的文档存在很大的问题,那就是“零散”。 VyOS的文档和Python的大多数项目文档一样,喜欢从API开始介绍,但对具体使用情况下应该如何配置的实例教程实在太少 ——这对于刚刚使用这个复杂系统的人,想要实现某个特定功能来说,是非常非常糟糕的。不是每个使用专业路由器的人都必须是网络工程师,我们需要有一些更面向爱好者的基础教程。
VyOS的文档零散,缺少教程,这个安装指南并不直接。不过没有关系,这里给大家一份“消毒”过的构建指南。首先大家先参考VyOS有关不同版本的介绍,挑一个适合自己需求的目标版本。然后大家准备一个合适的Linux主机,在里面安装docker环境。(这里使用ArchLinux举例,不过都应该是通用的)
这里我们选择的安装版本是目前的LTS版本LTS v1.4.0,别名“sagitta”。以下的教程只适用于1.4和1.5版本的构建。因为在中国大陆下载镜像、连接github等都比较缓慢,所以这里默认您有一个稳定的代理服务器开在本地,这份修改过的指南可以帮助你通过代理快速构建一份镜像,不用再担心因为网络问题卡死报错。
首先,你需要切换到一个全新的工作目录,比如/home/<name>/build_vyos
参考ArchWiki,安装Docker。
直接下载镜像肯定网络卡死,但请注意,文章发稿的最近中国大陆官方出台了相关规定,要求相关网站关停未经审核的开源软件镜像,docker的国内镜像很快将不再可用,比如上海交通大学docker镜像站就即将被关闭。所以这里提供了一份代理配置方法。编辑
/etc/systemd/system/docker.service.d/http-proxy.conf
文件,在其中添加类似[Service] Environment="HTTP_PROXY=http://127.0.0.1:1234" Environment="http_proxy=http://127.0.0.1:1234" Environment="HTTPS_PROXY=http://127.0.0.1:1234" Environment="https_proxy=http://127.0.0.1:1234"
的环境变量信息,配置HTTP/HTTPS代理。注意Docker的运行比较特殊,dockerd是守护进程,它需要在启动的时候被指定环境变量,而不是在docker pull的时候。所以我们直接在systemd配置中修改。
sudo docker pull vyos/vyos-build:sagitta
git clone -b sagitta --single-branch https://github.com/vyos/vyos-build
sudo docker run --rm -it --privileged --network host -v $(pwd):/vyos -w /vyos vyos/vyos-build:sagitta bash
注意,这里我们使用
--network host
来使容器直接使用主机网络,这样有一个好处就是容器内可以直接使用主机网络中的代理服务器。(在容器内)
export http_proxy=http://127.0.0.1:1234 export HTTP_PROXY=http://127.0.0.1:1234 export https_proxy=http://127.0.0.1:1234 export HTTPS_PROXY=http://127.0.0.1:1234
(在容器内)
cd vyos-build
(在容器内)
sudo -E make clean
注意这里使用-E
可以保留自己的http_proxy*环境变量。(在容器内)
sudo -E ./build-vyos-image iso --architecture amd64 --build-by "<你的邮箱地址>"
- 如果一切配置正常,这里应该有丰富的命令输出。如果卡死并输出类似
E: Could not retrieve vyos-1x from branch sagitta: GitCommandError
,则说明你的代理软件配置存在问题,请重新检查自己是否正确的配置了代理。
- 如果一切配置正常,这里应该有丰富的命令输出。如果卡死并输出类似
然后……不出意外的,就要出意外了。你发现你的终端中报了如下错误:
Err:12 https://sagitta-packages.vyos.net sagitta InRelease
403 Forbidden
在经过一段时间的搜索后,发现……
……VyOS在几个月前关闭了公众对LTS分支预构建软件包仓库的访问权限……
VyOS在2024年4月,发布了一篇博客*Community, Contributors, User Base and LTS builds*,讲了一大堆,其实主要概括下来就一件事:
VyOS太好构建了,你们到处分发我们的LTS版本, 惹到我们了 ,所以我们决定关闭我们Jekins仓库中对LTS版本的软件包的下载,给你们上上强度!
可以参考VyOS论坛中的文章LTS release package repositories permanently closed for public access来获取更多信息,来看他们是怎么狡辩的。
……呃,好吧,说实话,其实我觉得这很正常,毕竟构建工具链掌握在人家手里。
我真的如此冷静吗?当然不是!我和大家一样,感觉到非常困惑而且愤怒!请看:
- https://forum.vyos.io/t/unable-to-build-iso-1-4/14262
- https://www.reddit.com/r/vyos/comments/1d66510/anyone_have_a_link_on_how_to_build_vyos_14_with/
- https://forum.vyos.io/t/cant-build-image-blocked-from-sagitta-packages-vyos-net/14337
- https://forum.vyos.io/t/cloudflare-blocks/14601
- ……
每个讨论串下都有大量困惑的用户在到处询问,原来不只我们有这种问题。大家在这些讨论中尽情的表达自己对VyOS团队的看法,而VyOS团队的成员则非常有耐心、细致的给这些用户讲自己这么做的原因。总之,我认为概括起来就是六个字—— 怎么,你不服气?
VyOS本身是一个操作系统, 在构建中是由许多软件包组成。绝大部分软件包都来自debian等镜像,但其中有大约50个软件包是VyOS自己维护和开发、使用他们自己编写的Jenkins CI系统进行持续集成、测试与分发的。在构建操作系统的时候,直接克隆vyos-build项目,在他们团队准备好的docker环境里启动构建,就可以生成一个ISO文件,不需要你自己去构建复杂的近50个软件包——这是因为VyOS软件仓库如sagitta-packages.vyos.net
里已经保存了这些软件包,这使得构建可以直接从build-vyos中进行,只需要从仓库中拉取就可以了。
而VyOS团队,关闭了近两个版本LTS软件包的开放下载权限,也就是说,用户执行构建iso的流程时无法再下载到他们的预构建的软件包,这就让构建工作的难度加大了很多——用户需要自己先在本地通过构建这50多个项目的源代码,得到一份VyOS近50个软件包组成的软件源,然后才能启动iso的构建流程。VyOS团队就是通过这种方法,从而起到“控制用户分发LTS版本镜像”的作用。这对系统的主要目标用户——网络工程师而言,无疑是一道难以逾越的障碍。不得不说,他们做的相当成功。
……但是在GitHub上发现了一种解决方案……
可惜Neboer不是网络工程师。
好巧不巧,就在刚才“到处分发”那个链接指向的GitHub搜索页面,我看到了一个项目 vyos-jenkins,这就是可以构建出我们心心念念的“LTS”版本的工具。
VyOS希望通过阻止用户直接编译源代码的方法,来控制二进制的分发,但其实只要项目的源代码还在,构建一个LTS版本的VyOS就不是不可能。不过VyOS毕竟是一个操作系统,构建确实比较复杂,他们的开发者使用jenkins做持续集成,方便的自动化构建、部署、测试,但这种持续集成也不是非用他们的网站不可。VyOS的开发者肯定非常满意现状:网上终于没有人再构建自己的LTS镜像了——但是我们相信用户的智慧是无穷的,这个开源项目就在尝试妥善解决这个问题。
vyos-jenkins项目做了很多工作,它让因人为限制而几乎不可能被普通用户构建的VyOS的LTS版本,重新可以被普通用户构建。这个仓库的开发者对VyOS的构建原理非常非常了解,为它编写了完善的指南,从0开始教你如何在本地形成一个VyOS的LTS版本的Jenkins CI环境,并通过构建软件包形成一个VyOS的Debian软件仓库,并最终被patch过的构建镜像所用,最终构建出一份“十分接近”VyOS官方LTS版本的镜像。
真的可以构建吗?经过大量的尝试,最终……
……最终,经过重重困难,终于编译出了一份VyOS 1.4.x Sagitta (LTS)的镜像。
真的很不容易。
如果你看到这里,也想构建属于自己的VyOS LTS镜像,我只能说去阅读vyos-jenkins的README文件,里面说得非常非常详细,我没有必要再转述一遍了。你就按里面的方法,从头到尾完整的执行一遍,就可以成功,整个过程几乎不会出任何意外。
如果你确信你有能力完成这个几乎不可能完成的任务,那么我作为“过来人”,提一些建议。
请使用Debian Bookworm,请尽量使用物理机或虚拟机。
我只在Debian Bookworm上做了测试,是可以成功的。如果你没有Debian Bookworm系统的物理机,那么你可以建一个虚拟机。虚拟机要分配的系统资源,在README中已经有写,这里不再赘述。如果你的磁盘空间吃紧,不要怕,只要分配100G的硬盘空间就足够了,不需要150G。但如果你反复构建,请记得及时清理不需要的docker镜像。
为什么一定要用物理机或虚拟机呢,因为整个过程中要调用docker容器构建和编译,你如果使用基于namespace隔离的容器(如docker、nspawn)可能会出现未知的问题。我没有测试,不清楚是否可以实现,不过我非常建议使用虚拟机。
如果在中国大陆构建,必须开全局透明代理。
我相信你肯定没有一台海外的高性能主机,所以你必须在中国大陆内的服务器构建这个东西。而构建过程中需要大量的访问GitHub、docker.io等在大陆几乎无法正常访问的网站,层层的docker容器又让代理设置变得非常非常复杂,你几乎无法通过环境变量或软件配置等方法代理所有的网络请求。所以,你有必要为容器或主机开一个全局的透明代理,在Windows下推荐使用Proxifier,在Linux下可以试试sing-box,都是不错的软件。
Jenkins系统需要安装额外的插件 Git plugin,否则无法设置global library. 推荐再安装一个Purge Build Queue Plugin,可以方便的一键取消所有进行中的构建。同时作者还推荐大家安装一个插件View Job Filters,可以方便的查看某个构建是否成功。
如果有软件包构建出错,不要着急,看看日志,如果是因为网络原因,就多试几次。
./seed-jobs.sh create
之后,需要等待所有的任务成功后,再执行./seed-jobs.sh build
以确保成功。这个仓库的作者dd010101是一个秒回人,有问题欢迎开issue和他讨论交流。
不要怀疑自己,构建是 可以成功 的!我就亲自构建出了一个VyOS 1.4.x Sagitta的镜像,没有任何问题。如果实在构建不出来,可以试着朝别人索要一份镜像,当然,安全性由你自己保证。
实际的构建时间会很长,流量大约消耗10-30G左右,如果分配核心过少,算力过低,可能会因为部分Jenkins任务长期阻塞而被取消,因此推荐你至少在一个现代CPU上运行构建,并分配至少10个CPU线程的算力。
我和这个构建项目的开发者在issue交流了很多,我问了一个最关心的问题就是,这个项目会不会有Release,以简化普通用户的构建成本和流程。开发者表示相关的工作也在推进中,大家可以继续关注这个仓库以获取它的最新动态。或许在不远的未来,构建VyOS的开源LTS版本将不是一件费力的事情。
安装VyOS
终于,我们经过千辛万苦,现在已经拿到了VyOS的稳定版本的镜像!那么,你要做的第一件事当然就是需要安装它!可惜的是,安装VyOS并不是简单的工作。需要考虑的问题还是很多:比如用虚拟机还是物理机安装?需要准备一个什么配置的机器?使用UEFI还是MBR引导?是否支持UEFI启动等等等等。
不要在Live CD中配置
VyOS的安装介质本身也是一个VyOS的操作系统,启动后可以直接使用,不用安装。但在这种状态下做的任何修改都无法持久化保存,所以启动后先不要急,还是先安装到硬盘里,然后将USB从系统中移除,然后再启动安装好的VyOS。
推荐使用虚拟化部署
在下载好最新版本的镜像ISO之后,你面临着两个选择——虚拟机安装和实机安装。
我个人建议在虚拟机中安装VyOS。因为VyOS对虚拟化的支持是比较好的,并且虚拟机提供了相当稳定的运行环境,非常适合VyOS的启动和部署。经过我的实际测试,VyOS在物理机的启动比较困难,首次启动有概率kp,这个系统的bug真的让人服气……不过在虚拟机中启动则没有任何问题,可以稳定运行,不会出错。
有条件的读者们可以选择类似PVE这种虚拟化平台进行安装,也可以选择在Linux中用kvm直接安装,你甚至用WindowsServer起HyperV虚拟机也是可以的,这些都可以正常运行,不会出错,我已经在本地启动了很多次类似的实验环境,可以保证这一点。
启动系统以后,在引导界面选择KVM Console登录即可,无论你是否有KVM Console都不重要。
从VyOS启动盘中安装
好吧……看来你一定要在物理主机里安装VyOS,不妨先参考一下这篇文章中的内容先购置一下设备……(笑)那么这就涉及到如何制作一个启动盘。很多人可能会喜欢用类似Ventoy的启动U盘系统,虽然我们可以看到Ventoy在镜像支持列表中标榜自己支持VyOS的启动镜像,但实际上如果你按这个镜像启动是很容易遇到Kernel Panic的问题的。这里更推荐直接使用Rufus制作一个启动盘,制作方法推荐使用UEFI GPT——是的,VyOS是支持UEFI安装的。文件系统exfat或fat32,在实际安装的时候,可以选择一个硬盘分区安装,vyos会自动在这个分区中展开自己启动的必要文件。类似的安装可以进行多次方便升级系统,VyOS支持多版本共存。不过VyOS并不支持安全启动,所以使用新一代Hyper-v虚拟机运行LTS iso镜像时请注意把安全启动选项关闭,在本地运行时也请将Secure Boot选项关闭。
VyOS一定要安装后再使用,否则配置文件不会永久保存。当然如果希望将一个临时的配置持久化也非常容易,可以直接插个U盘上去,mount到系统目录,在configure模式下输入save /usb/file.conf,也可以起到一样的效果。
家庭网络中的路由器
在开始之前,我们先熟悉一下家庭网络。
家庭网络
家庭网络的结构,往往是一根进户光纤,连接到光猫,光猫通过光电信号转换,将一根WAN网线连接到家庭路由器上。家庭路由器负责完成所有从拨号到内网设备上网的所有过程,同时向外发射无线信号,接受有线网络连接,让内网设备能够访问互联网,等等等等。其具体的结构可以参考这张图中所示。
家用路由器
现代常用的家庭网络路由器,一般有无线功能和有线功能,但不管是无线还是有线,路由器一般都分为WAN和LAN两个部分。其中LAN指局域网,无论是无线还是有线都在局域网中,而路由器还有WAN部分,负责连接互联网,进行实际的请求。
虽然现代商业家用路由器的功能非常繁杂,但是归根到底大家使用路由器就是为了上网(我们也是)。而上网从来都不是一件简单的事情。所以,搞清楚路由器到底有哪些部分非常重要。请大家打开本科时期的计算机网络课本,我们一起回顾一下这个迷人的三层设备到底做了哪些工作。
路由器的基本功能
一个典型的(不考虑无线网络的)适配现代小型家庭网络的路由器应该有如下基本功能:
- IPv4
- 地址和子网
- PPPoE客户端
- DHCP客户端
- DHCP服务器
- DNS服务器
- IPv6
- 地址和子网
- DHCPv6客户端
- DHCPv6服务器
- Router Advertise服务器
- IPv6前缀委派
- NAT(主要是IPv4的SNAT)
- 防火墙
- 内网网桥
这也是我们配置的目标,这篇文章将会手把手,让读者从熟悉VyOS开始,每一步辅以详细的配置流程,一步步打造属于自己的自由的家庭网络!
使用VyOS配置家庭网络
家庭网络的结构并不复杂,前面也提到了。那么如何使用VyOS配置家庭网络?对于专业的网络工程师来说,这并不困难,但是我们……并不专业。这几天我们一直在不断的摸索这个系统的使用方法,终于搞出了一套还不错的配置,拿来做我们家庭网络的路由器足够了。
本文内容保证绝对的正确,我们已经搭建了大量的实验环境,用来验证我们的配置是否正确。目前我们适配的路由器版本是1.5,不过我觉得版本本身不应该成为任何问题。
接下来我们会详细的完成整个路由器系统的配置,大概的顺序是先配好IPv4,然后再讲解IPv6的配置。在讲解的过程中,我们会顺便做一些扩展,以及结合网络协议规范带大家细致入微的学会VyOS组网的配置。在整个文档的最后会提供这两份完整的配置文件,闲话少说,让我们开始吧!
路由器的物理结构
路由器,有WAN口,有一些LAN口。想要让VyOS发挥路由的功能,你首先就需要一个至少有两个网络接口的主机——这可以通过很多方法来实现。你可以在一个普通的主机上额外安装一块网卡,也可以直接插一根USB网卡,你也可以直接购买一个多网口主机,甚至如果主机只有一个网口也没有关系——我们可以将主机配置成单臂路由,用两个VLAN划分出WAN口和LAN口的功能。单臂路由配置比较复杂,这里不做详细阐述,我们主要来讨论一个普通的主板+板载双口网卡的情况,用这个主机模拟一个最基本的路由器。这些配置在虚拟机中也是一样,虚拟平台的主机本身也需要有多个网口,这才使路由变得可能。
假设路由器有三个网口,eth0, eth1, eth2,我们接下来就讨论一下,如何 以eth2做WAN,以eth0和eth1组LAN ,让连接到eth1/2的内网设备可以正确访问运营商提供的互联网。
VyOS的基本用法
进入VyOS后,你会看到一个shell,输入configure进入配置模式,再输入exit退出配置模式。
VyOS的配置语言非常朴素,整个VyOS系统就是一个巨大的配置文件,进入配置模式后,可以通过 set a b c d e value的形式,来新建一个配置项a.b.c.d.e,并设置它的值为value。
每次commit,系统都会根据配置文件的文件的内容自动完成对系统的所有修改,你只需要改配置文件,剩下的事情交给系统就可以了。
VyOS的基本用法可以参考这份Cheatsheet,里面有较为详细的描述。本文默认你已经掌握了其基本的配置方法。
内网网桥
每个路由器中都会有一个网桥,用来将许多局域网设备组合在一个内网。我们在VyOS中也不例外,搭建网桥将局域网与运营商外部网络隔离开,是我们要做的第一件事情。如果你的主板只有两个网口,那么你没必要建一个网桥,直接使用内网网口做为内网、外网网口作为外网即可。
我们都知道,所谓网桥就是一个交换机,用来将多个物理网络设备连接在一起的数据通道。在不知道目标的物理接口时,网桥会将自己收到的每个数据包都广播给所有连接到自己的主机,引入了学习功能后,网桥可以实现数据包的精准投递。连接到同一个网桥上的两个主机分别给自己分配一个IP地址,就可以互相通信了。
那么在Linux主机中的网桥设备是什么?其实也好理解,既然网桥是一个交换机,那么所谓的网桥设备就是主机插在交换机上的网络接口——是不是豁然开朗?那么网桥设备当然也可以有IP地址,这个地址就是在网桥上的其他设备访问主机的目标地址,也应该是主机向其他网络上设备通信的源地址。
在你登录VyOS之后,第一件事就是检查主机中的网络接口,在看到eth0, eth1, eth2只有物理地址被分配,并没有IP地址之后,我们首先要将路由器内部网桥正确的配置起来,让eth0, eth1连接在一起。
interfaces {
bridge br0 {
member {
interface eth0 { }
interface eth1 { }
}
}
}
以上配置转换成命令,就是
set interfaces bridge br0 member interface eth0
set interfaces bridge br0 member interface eth1
你看到了,我们并不需要在配置文件中显式的创建任何网络设备,我们只需要告诉它“存在”这样一个“拥有”2个成员的网桥即可。当我们输入
commit
时,VyOS可以自动解析我们的配置文件,知道我们是要创建一个包含两个网络接口的网桥。它会自动把网桥创建好,并将两个网络接口添加进桥中,不再需要我们敲复杂的命令,就可以 声明式 的完成路由的配置。
VyOS的set
命令,并没有什么神奇的。我们在之后的配置中不会给任何set的命令,相反,我们会直接提供配置文件。如何将配置文件正确的输入呢?只需要按key的路径,将配置文件中的每一项顺次输入,用空格分开就可以了(如果一项中遇到空格等特殊字符,可以使用单引号包裹)。比如set interfaces bridge br0 member interface eth0
,只需要按照配置文件中从顶层到底层的顺序依次输入key值和最后的value,就可以完成配置。
我们可以选择现在分配给网桥一个IPv4地址,不过现在分配没有任何意义,我们会在接下来的步骤完成这些设置。
IPv4下WAN的PPPoE拨号或DHCP地址获取
接下来,我们要做的是让路由器上网。我们将光猫的有线网口与路由器的WAN口,也就是eth2接口相连。
现在中国大陆的运营商普遍采用PPPoE拨号的形式认证路由器上网,而如果你的光猫已经完成了这个步骤,或者说你们的网络环境中不需要PPPoE,那么你大概率需要网络中的DHCP服务器为你分配一个地址。注意,以下两种配置对应不同的网络情况,
通过DHCP获取Wan口IPv4地址
如果你的WAN口不用拨号就能上网,那么它大概率是通过DHCP服务器获得到自己的地址的。
interfaces {
ethernet eth2 {
address dhcp
}
}
通过PPPoE拨号获取Wan口IPv4地址
当然,如果你需要拨号才能上网,那么下面的配置才是你需要的:
interfaces {
pppoe pppoe0 {
authentication {
password "your pppoe password"
username "your pppoe username"
}
service-name "CMCC"
source-interface "eth2"
}
}
像这样配好PPPoE,设置好运营商提供的用户名和密码后,别忘了提供一个source-interface
,指向路由器的WAN口,也就是eht2。service-name是你这个拨号服务的名字,随便起一个就可以。
这样,路由器会多一个名字叫pppoe0的网络接口,这是一个虚拟接口,就像br0一样。
注意,PPPoE拨号成功后,pppoe0接口会自动被分配一个IPv4地址,这是PPPoE协议本身所规范的,不需要额外的配置类似address dhcp
之类的项目。
网络出口
当你使用DHCP方法配置eth2的网络地址时,eth2本身就是网络出口,所以你需要在之后的配置中将数据包从eth2路由出去;而如果你是使用PPPoE的方法配置的网络地址,那么pppoe0应该成为出口,负责实际数据包的发送。很快我们就会用到这个细节。
IPv4 子网规划
路由器的重要功能就是将两个不同的网络连接在一起,这就是“路由”。在IPv4——这个互联网的古早协议中,两个不同的网络被两个不同的IPv4网段划分开来,通过网络地址转换让路由器“代替”内网主机向远端地址发起连接。
所以,在进一步配置之前,我们需要规划好内网的IPv4网段。根据RFC 1918,私有IP地址(Private IP Addresses)共分为10.0.0.0/8、172.16.0.0/12和192.168.0.0/16三段。这里的/x指的是子网掩码的长度位数,比如192.168.1.0/24这个子网可以支持最多254个网络地址,为192.168.1.1-192.168.1.254,剩下的192.168.1.0是网络地址,192.168.1.255是广播地址,这两个地址不能分配给设备。IPv4采用点分十进位的原则,每小段长度为8位,总地址长度24位。
必须慎重选用一段确保不会和WAN口的网络地址发生冲突,且确保是私有地址的地址段,一般情况下我们选择192.168.1.0/24。因此我们对IPv4子网的规划如下:
192.168.1.0/24 路由器内网网段
192.168.1.1 路由器LAN口内网地址
192.168.1.100-254 路由器内网地址区间,通过DHCP服务器动态分配地址。
所以我们必须先给br0分配一个IPv4地址。
interfaces {
bridge br0 {
address "192.168.1.1/24"
}
}
注意,之前我们配bridge br0的时候,已经在它的下级配置了member选项。在配置这个address的时候我们无需关心并列的选项,正常执行
set interfaces bridge br0 address "192.168.1.1/24"
即可。新选项会自动添加到并列的选项中。
注意,这里在给br0分配地址后,必须立即提交一次,否则DHCP服务器可能因为无法找到可绑定的网络接口而报错,这是预期行为。
commit
save
exit
这三个命令的含义是,提交配置、保存配置和退出配置模式。注意,配置必须先提交后保存,如果提交失败,保存配置会触发警告;无论以何种方法保存,未提交的配置都无法被保存,提交失败的配置也不会被保存。不要想着将一切配好再把路由器放到网络环境中,要先在稳定的环境中部署路由器,然后再动态的配置。如果觉得这样配置非常麻烦,可以先给路由器一个IPv4地址后,打开它的SSH功能。
service {
ssh {
listen-address 192.168.1.1
}
}
这样,你就可以从和路由器一个网段下的网络设备里直接ssh到路由器了。使用vyos用户登录,密码和登录密码一致。
IPv4 NAT
在配置DHCP路由器之前,我们必须完成一个特别的配置,那就是IPv4 NAT。之前也说过,我们需要将内网的数据包转发到公网上,靠的就是SNAT(源网络地址转换)。在IPv4网络中,公共IP地址是有限的资源,而私有IP地址(如192.168.x.x、10.x.x.x和172.16.x.x至172.31.x.x)可以在局域网内部自由使用,但不能直接用于与互联网通信。为了让内网设备能够访问互联网,必须进行NAT转换。NAT分为SNAT和DNAT两类。
源网络地址转换(SNAT):
内网设备发送数据包到互联网时,路由器将数据包的源IP地址从私有IP地址转换为公共IP地址,并记录转换映射。
当互联网的返回数据包到达路由器时,路由器根据记录的映射,将目的IP地址转换回原来的私有IP地址,并将数据包转发给内网设备。
目的网络地址转换(DNAT)(端口转发):
- 用于将外部请求转发到内网中的特定设备。例如,外部访问路由器的某个端口,路由器将请求转发到内网设备的相应端口。
在我们的配置环境下,我们只需要正确配置SNAT,让路由器将从192.168.1.100-192.168.1.254
范围内收到的数据包转发到pppoe0
或eth2
接口上即可。具体转发到哪个接口,取决于之前所说的实际连接着公网的路由出口的接口名称。
nat {
source {
rule 20 {
outbound-interface {
name "pppoe0"
}
source {
address "192.168.1.100-192.168.1.254"
}
translation {
address "masquerade"
}
}
}
}
这里的“Masquerade”是SNAT的一种形式,用于动态将源地址发来的数据包的源地址,改为路由器出口的实际IP地址,与防火墙的masquerade是一个含义。
VyOS直接将NAT——这个非常常见的路由功能,从防火墙中单独拿出来,成了一个独立的顶级模块。这也从一个角度体现了系统配置的统一性所带来的方便。
DNS服务器
路由器本身需要一台DNS服务器才能解析域名,在系统内正常上网。而路由器最好也同时对内网提供DNS服务,以提高DNS性能,降低上游DNS服务器的解析压力,这是非常推荐的标准做法,因此需要在路由器中配置DNS解析服务器。
正常情况下,无论路由器是用PPPoE方法,还是用DHCP方法上网,都应该会分配到来自运营商指定的DNS服务器。大家不要嫌弃这个服务器——它的解析速度很快,按照规范应该成为路由器的默认上位DNS服务器。我们接下来的配置就实现这一点:在内网建立一个DNS服务器,以运营商分配的DNS为上游做递归解析。
设置系统DNS
当你让路由器获取到了IPv4地址之后,你洋洋得意的ping
起了1.1.1.1
,看到一切正常,不禁高兴起来。
VyOS是标准的Linux系统,提供了curl
等基础命令。所以你迫不及待的输入curl www.baidu.com
,想要看到成功请求的网页界面,然后你盯着cannot resolve hostname
的输出陷入了沉思。
路由器只是能上网,现在还并没有设置DNS,所以路由器不能正常的解析域名。设置DNS的第一步,先不要管其他的机器能否解析,我们先让路由器能够正常解析域名。
system {
name-server eth2
}
等等等等,什么什么,name-server怎么能设置成一个网络接口?
在VyOS的官方文档中没有说明这个功能的细节,我们转向VyOS的源代码来看看这个部分,原来这个设置是更新了hosts['nameservers_dhcp_interfaces']
。可以从这个文件后面的代码中看出,实际上这句话的作用是,将系统DNS设置成与对应接口的DHCP/DHCPv6所广播的DNS地址。
VyOS的设置过程中,有许多地方会直接用到“接口的DHCP DNS”的概念。也就是说可以理解成,DHCP接口本身就相当于一个特殊的DNS服务器,需要使用特殊的方法配置,起到和普通DNS服务器(比如8.8.8.8)一样的效果。当然,你也可以将这个设置为其他的DNS,这都是小问题。
如果你是使用PPPoE建立的连接,情况会变得略有不同。
PPPoE拨号后,PPP连接建立,进入IPCP(IPv4 Control Protocol)协商阶段,在这个过程中服务器可以告知客户端自身的IP地址和DNS服务器。所以PPPoE不需要依赖DHCP等手段,就可以自动获得DNS信息,通常有两个地址:一个主服务器一个备用服务器。
因为pppoe0接口并不依赖DHCP获取DNS服务器,所以如果你是通过PPPoE拨号上网的方法建立的连接,在尝试设置系统dns为PPPoE接口时
system {
name-server pppoe0
}
会遇到一个报错
WARNING: "pppoe0" is not a DHCP interface but uses DHCP name-server option!
这个错误其实没有什么用……因为当你cat /etc/resolv.conf
的时候,会发现其实路由器的DNS已经设置好了,这可能是VyOS的一个bug。
对于这种情况,本文建议用户采用本地DNS方案,参考后面的内容在本地建立DNS服务器后,让本地的DNS服务器作为路由器的默认DNS服务器。
system {
name-server 127.0.0.1
}
当然,你也可以设置系统DNS为一个你喜欢的DNS服务器,跳过所有运营商指定的服务器。
system {
name-server 114.114.114.114
}
启动DNS服务器
我们要通过IPv4 DHCP为连接到网络上的客户端告知他们要使用的DNS服务器的地址,但是运营商提供的DNS可能会改变。非常遗憾的是,你没有办法通过set service dhcp-server shared-network-name xxx name-server
的方法来动态的让内网DHCP服务器所汇报的DNS服务器地址和一个DHCP接口的DNS地址保持一致,因此在本地启动DNS服务器似乎是最佳的选择。通过在本地启动DNS服务器,可以在本地的DHCP服务器中报告DNS服务器的地址为路由器网桥的地址,而在本地的DNS服务器中就可以设置“与系统DNS一致”或“与DHCP接口的DNS一致”了。
如果你已经设置好了系统DNS为额外的服务器,你可以直接使用系统DNS作为路由器的默认DNS服务器的上游查询地址。
service {
dns {
forwarding {
allow-from 0.0.0.0/0
allow-from ::/0
system
listen-address 0.0.0.0
listen-address ::1
}
}
}
或者与某个DHCP接口保持一致……
service {
dns {
forwarding {
allow-from 0.0.0.0/0
allow-from ::/0
dhcp eth2
listen-address 0.0.0.0
listen-address ::1
}
}
}
这样,系统本地就启动了DNS服务器。这个DNS服务器的allow-from允许所有设备(无论公网还是内网)使用这个DNS,在实际使用中需要避免,最好设置成仅能从内网网段访问。
如果你使用PPPoE连接互联网,可以直接设置DNS服务器的上游与PPPoE接口保持一致。至于为什么直接将PPPoE接口的DNS设置成系统DNS会报错,而设置成这里的DNS就一切正常,我确实一时半会想不明白。
service {
dns {
forwarding {
allow-from 0.0.0.0/0
allow-from ::/0
dhcp pppoe0
listen-address 0.0.0.0
listen-address ::1
}
}
}
这样,我们就在本地启动了DNS服务器——这个服务器监听所有的IPv4地址和IPv6地址。
IPv4 DHCP 服务器
DHCP服务器不仅仅是想内网设备分配IP地址的——它有更重要的功能,就是向内网设备通告网关地址、DNS地址等基本信息。
service {
dhcp-server {
shared-network-name NAT1 {
option {
default-router "192.168.1.1"
name-server "192.168.1.1"
}
subnet 192.168.1.0/24 {
range 0 {
start "192.168.1.100"
stop "192.168.1.254"
}
subnet-id "1"
}
}
}
}
DHCP的配置非常简单直观,这里不需要做过多阐述,只是提一下这个subnet-id是强制设置的,不要忘了加。这里的default-router是路由器的内网地址,注意如果没有配default-router,则客户端获取不到网关信息,无法更新自己的路由表,也就无法正确向互联网建立网络连接。
这里的name-server可以保证客户端使用路由器的局域网地址做自己的DNS服务器,然后路由器再将DNS转发到运营商提供的DNS地址上,形成相对稳定的DNS多级解析和缓冲。
注意,在VyOS中,有一些选项是可以并列存在的,比如interfaces bridge br0
层级下的address
可以设置多个,表示网桥有多个网络地址。而也有一些配置项是不能并列存在的,比如service dhcp-server shared-network-name NAT1 subnet 192.168.1.0/24 range 0 start
就只能设置一个,再在这里重新设置一个start值会将旧值覆盖,需要引起注意。具体有关“叶子节点”相关的设置,可以直接参考VyOS项目源码中的注释。
IPv4 端口转发
如果你的路由器可以被分配到公网IPv4地址,那么你或许可以考虑部署一个端口转发,这样就可以对外提供网络服务了,这需要通过配置DNAT来完成。
参考VyOS中这篇有关NAT的文章,配置DNAT的方法非常简单,假设我们需要将外部访问80端口的流量重定向到内网的192.168.1.100设备上,只需要配置如下内容即可。
nat {
destination {
rule 10 {
description "Port Forward: HTTP to 192.168.1.100"
destination {
port 80
}
inbound-interface {
name pppoe0
}
protocol tcp
translation {
address 192.168.1.100
}
}
}
}
这样就配置了从公网的80端口到192.168.1.100的80端口转发。
不过如果192.168.1.100这个地址是来自之前的DHCP分配的话,可能会无法保证总能稳定的分配到同一台内网主机。这个时候就需要搭配Static mappings来固定某台具体设备的IP地址。只需要添加对应的ip-address/mac对为一个static-mapping,就可以保证某个mac地址的设备永远分配到某个特定的内网IPv4地址。
service {
dhcp-server {
shared-network-name NAT1 {
subnet 192.168.1.0/24 {
static-mapping WebServer {
ip-address 192.168.1.100
mac aa:bb:11:22:33:00
}
subnet-id 1
}
}
……
好了,成功配置好这些之后,先commit再保存一下吧!让客户端重新连接一下路由器的局域网,看看是不是能正确获得自己的IPv4网络地址,并且能有正常的IPv4外网访问?正常情况下,一切应该是正常的!
现在我们已经完成了基础的配置,接下来我们来处理情况非常不同的IPv6。有关IPv6的地址配置及路由发现等协议的实现原理,网上实在是有太多教程了,感兴趣的读者欢迎继续去详细学习,我们这里只提供一个在宏观上的联系供大家快速掌握基本概念,当然,你并不需要了解全部的细节就可以配置路由器,但是必须得对这个协议的基础——DHCPv6、SLAAC和RA有基本的了解。
首先需要说明一点的是,很多朋友可能对IPv6存在误解,认为IPv6只是“更大地址空间的IPv4”,这种想法是大错特错的。IPv6不仅仅是地址空间变多,它还引入了许多新特性和改进:
- 无状态地址自动配置(SLAAC):设备可以自动生成IPv6地址,无需手动配置或DHCP服务器。
- 内建安全性(IPsec):IPv6要求支持IPsec,为数据传输提供更高的安全性。
- 更高效的路由:简化的报头格式提高了路由效率,减少了路由器的处理负担。
- 多播代替广播:消除了广播,改用多播和任播,更加高效地处理网络流量。
- 端到端连接:消除NAT,恢复了端到端的通信模式,简化了网络结构。
- ……
这些改进使IPv6不仅适用于现有的互联网,还为未来的发展提供了更广阔的空间和更多的可能性。可以说,IPv6是新一代的IP协议,比IPv4更好、更快、更强大,目前的主流操作系统几乎全部支持IPv6,主流的软件也都支持了IPv6,主流的运营商也都支持了IPv6——当然,受限于成本等因素考虑,世界上大多数企业还在使用IPv4网络,迁移和升级进展相对缓慢,距离IPv6彻底占领世界还有一段距离,不过我们期待这个新的互联网协议会为我们的未来带来更多可能。
值得一提的是,IPv6网络的配置和IPv4网络的配置是几乎没有任何关系的。在路由器中,很多协议都被分成了v4和v6两个部分,比如防火墙、DHCP服务器等等使用的时候注意区分——但是DNS有些例外,具体会在后面展开。
IPv6网络地址
IPv6协议,是新一代网络协议,是用来取代IPv4协议的。在国内,大多数运营商在家宽及移动网络中都部署了IPv6接入的服务,只要你使用新设备,都可以正常获取IPv6地址,并获得IPv6的网络连接。你可以访问 https://test-ipv6.com 来检查自己是否已经拥有良好的IPv6网络。
为什么我们要在家庭网络中费力的支持IPv6?因为这非常有意义——IPv6可以为内网中的每个设备都分配一个独特的IPv6地址,内网可以独立的决定自己要如何对外提供网络服务,不再需要复杂的端口转发之类的机制,数据包会自动找到合适的目标进行路由。但这并不意味着IPv6不存在局域网地址的概念了。
IPv6提供了更加丰富的网络地址类型,大概分为以下几种:
全球单播地址(Global Unicast Address, GUA): 这些地址类似于IPv4中的公网地址,是唯一的、全球可路由的IPv6地址。全球单播地址用于通过Internet进行通信,范围从2000::/3到3FFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF。一个典型的全球单播地址的前缀通常由ISP分配,常见前缀如2001:db8::/32(用于文档和示例)。
链路本地地址(Link-Local Address): 这些地址用于同一链路(或子网)中的设备之间的通信,不可路由到其他链路。链路本地地址以FE80::/10开头,常用于邻居发现协议(NDP)、无状态地址自动配置(SLAAC)、以及本地网络管理。
唯一本地地址(Unique Local Address, ULA): 类似于IPv4中的私有地址(如10.0.0.0/8, 192.168.0.0/16),这些地址用于组织内部通信,默认不可在全球互联网路由。ULA地址以FC00::/7开头,通常使用FD00::/8范围。
多播地址(Multicast Address): 用于将数据包发送到一组特定的设备。IPv6多播地址以FF00::/8开头,常用于发送广播消息到多个节点,如邻居发现协议中的路由器通告(RA)消息。
任播地址(Anycast Address): 这些地址分配给多个接口,数据包会发送到距离发送者最近的一个接口。任播地址没有特定的前缀,可以是任何单播地址。
临时地址和隐私扩展地址: 为了增强隐私保护,设备可以使用临时地址进行外部通信。隐私扩展地址通过随机生成的接口标识符生成,定期更换,以防止跟踪设备。临时地址通常是全球单播地址的一种变体。
IPv6的地址长度为128位,对一个内网中的设备,我们一般会将这128位地址分为前64位和后64位两个部分。一般来说前64位被称为前缀(prefix),它通常是由一个拥有一些可以委派的前缀的网关(比如后文中我们要讲的路由器)分配给这个内网设备的,而后64位通常是根据设备自身的mac地址和一些可配置的值共同计算出的接口标识符,它是由设备自己计算出来,并且经过查重之后保留下来的地址。
一般来说,我们所说的公网IPv6地址,指的就是GUA地址。如果所有的网络链路都按预期设计,那么通过GUA地址可以在公网中直接访问到一个具体的设备。我们本文中所讨论的IPv6地址分配,也主要是针对GUA地址的分配的。不过当然,这种配置理论上也可以在任何其他网络环境中正常使用。
DHCPv6、SLAAC与RA
IPv6最大的好处,就是可以为互联网中的每个具体的设备分配一个独特的网络地址,但这也为网络地址的分配带来了不小的麻烦——IPv6网络地址是如何被正确分配的?
IPv6网络中,从总体上来说,设备可以使用两种不同的机制来获得自身的IPv6地址——SLAAC自动获取和DHCPv6显式指派。一般来说,SLAAC为内网设备分配地址;DHCPv6用于为网关分配地址和前缀(如果网关请求并且网络支持的话)。(这种说法并不准确,但最起码在家庭网络中,这么理解一般没有问题)在DHCPv6协议中,路由器向运营商申请一段前缀,运营商就会为路由器分配一段前缀,通常这段前缀是/60的(通常,但因运营商而异)。路由器将这段/60的短前缀内网拆成/64的子前缀内网,然后向内网广播携带这个前缀的RA消息(SLAAC只能在/64的子网上进行)。内网设备看到RA消息后,通过SLAAC的方法自动计算出自己的地址,然后验重通过后,最终这个地址就是此内网设备的全局唯一的IPv6地址了。
如果一个网络支持IPv6地址分配,无论是用何种方法,网络中必然需要广播RA消息,同时,RA消息也仅与IPv6有关,如果一个网络不支持IPv6,那么它就没必要广播RA。RA消息不只是在网络支持SLAAC自动计算前缀时才有用,RA更像是一种“通告”,是一种路由器向网络中的所有设备公布当前网络对IPv6地址分配的支持情况的方法。路由器可以在RA中说自己支持DHCPv6,也可以说自己支持SLAAC。客户端需要按照获得的RA消息中的方法向路由器建立连接获取IPv6地址,还可以根据RA中的指示,获得更多关于网络的信息,比如网关地址,DNS服务器等等。
虽然网络有可能既支持SLAAC获取IPv6地址,也支持DHCPv6获取IPv6地址,但是客户端却只能从两个方法中选一个——如果选择了SLAAC,则不可能有可分配的前缀,只能让路由器自己上网;如果选择了DHCPv6,路由器可以选择性的请求IANA和IAPD两个字段——前者是一个IPv6地址,用来分配给路由器网络接口自身上网,而后者则是一段前缀,运营商分配给路由器的、可以被路由器继续分配的前缀。
因此,配置一个家庭IPv6网络的一般步骤,大概可以分为 获取IPv6前缀 -> 委派IPv6子前缀 -> 广播SLAAC 这三个过程。完成了这三步,一个基本的家庭网络就配置好了。其实IPv6的配置反而比IPv4简单很多,毕竟不需要考虑复杂的子网/NAT等(因为协议设计缺陷而导致每个网络工程师不得不面对的)问题。
IPv6前缀委派
配置IPv6的第一步,是确认你的运营商支持IPv6——在中国大陆的大多数地区应该是支持的。如果你不清楚你们家的网络是否支持IPv6,那么请默认按照它支持处理。
启用IPv6
参考VyOS中关于PPPoE家庭网络IPv6配置的文档,我们先在PPPoE的配置中加入以下信息。
interfaces {
pppoe pppoe0 {
ipv6 {
address {
autoconf
}
}
}
}
如果你使用DHCPv6网络,你可以用如下方法启用IPv6:
interfaces {
ethernet eth2 {
address dhcpv6
}
}
没什么好说的,和IPv4是一样的。
这里需要注意,不同的接口中的相同配置可能会有不同的行为。比如在PPPoE中,使用ipv6 address autoconf
会让PPPoE开始支持IPv6,而在普通的网络接口(比如eth0)上设置的含义是让这个接口使用SLAAC的方法为自己自动分配IPv6地址。
有关PPPoE中获取IPv6地址的具体流程,可以参考juniper上的文章来看。这里并不会纠结于协议的具体实现过程,只是想指出在相同的配置在不同的接口中起到的作用也是不同的,需要引起注意。
通过ping测试IPv6是否联通,根据这篇回答中的建议,可以试试Sprint的主站地址:2600::
,好记好用。
IPv6前缀的获取与委派
接下来的步骤是最复杂的部分:**根据运营商分配给你的IPv6网络前缀,划分一个IPv6前缀长度为64的子网,并将这个子前缀委派到br0网络接口上。**使用DHCPv6获取IPv6地址的过程中也包含相似的配置。这段配置是本文中的唯一重点,正确配置IPv6-PD是本文所讨论内容的核心。
所有的IPv6前缀都是通过DHCPv6协议获取的。用户发送的DHCPv6请求中包含IA-PD请求,DHCPv6服务器就会把带前缀的响应发送给用户,用户便可以自由的指派这段前缀到自己内网的主机上了。SLAAC无法获取到前缀,只能给设备自身分配一个IPv6地址。
在PPPoE协议中,情况稍有不同——客户端通过IPv6 Control Protocol (IPv6CP)进行IPv6链路本身的协商,建立链路本地地址(通常是链路本地的FE80::地址,这只是为了让客户端可以通过此连接进一步获取IPv6网络的其他信息),这个地址可以用来向运营商发送DHCPv6请求,进而获得一个前缀。所以说就算是PPPoE,网络前缀的获取还是要通过在建立的链路上发送DHCPv6数据包来完成。运营商通常不会直接分配给路由器的pppoe0接口一个GUA地址,只有一个本地地址——但这就足够了,因为路由器还会被分到一个GUA前缀,它可以被委派到下级网络接口(如br0)中,供设备使用。
interfaces {
pppoe pppoe0 {
dhcpv6-options {
pd 0 {
interface br0 {
sla-id "0"
}
length "60"
}
}
}
}
我们好好解释一下这段配置。
前面说过,运营商是否发送前缀到路由器,取决于路由器是否向运营商发送带IAPD的DHCPv6请求——只有在配置了pd
选项后,路由器才会请求前缀。
pd 0
指第一段可分配的pd前缀,里面的interface br0
指将前缀分配给br0设备,里面的sla-id "0"
指第一段子网。什么是第一段子网?前面说过,运营商分配的前缀长度是/60的,我们需要把它划分成多个/64的子网,这个设置整体来说主要讲了一件事:取运营商分配的地址段中的第1段前缀委派给设备br0。
运营商将前缀分配到路由器上之后,其实我们并不知道前缀的长度是多少。所以,length "60"
这个配置项其实不需要先配置。最好的方法是:如果你不知道你们运营商响应的PD前缀的长度,那么就在不设置length的情况下请求一次,看看br0分配到了多长的前缀,然后重新配置带length
的版本,将正确长度的前缀委派到网桥br0上。
DHCPv6以太网接口也是一样——不过,一下配置不太可能会生效,因为如果你的拨号已经由光猫代理了,那么pd大概率是已经完成了的——不再需要你额外手动配置了。这个时候,你只需要让路由器桥接所有IPv6的流量就可以。下面的配置不太可能会用到。
interfaces {
ethernet eth2 {
dhcpv6-options {
pd 0 {
interface br0 {
sla-id "0"
}
length "60"
}
}
}
}
如果是在这种情况下,v6不需要路由,创建一个新网桥br1,直接将eth2
的WAN口和br0一起并入br1网桥中,然后用防火墙规则屏蔽br1网桥中的v4流量即可——其实并不复杂。这种时候,br1网桥就只工作在IPv6模式下,IPv4不受此桥的影响。
如果你设置了正确的length
,那么你会发现实际上br0
获取到了一个GUA前缀,长度是/64。如果是这样那么恭喜你……你已经完成了最复杂的部分。
在内网启用路由广播
RA消息是整个IPv6配置的最后一站。如果RA配置正确,那么内网设备可以直接用SLAAC获取到自身的IPv6地址。
service {
router-advert {
interface br0 {
link-mtu "1492"
prefix ::/64 {}
}
}
}
interface br0
表示RA广播的目标接口,是向网络br0中广播。
1492的MTU保证了RA报文的完整性,而这个prefix ::/64
就非常有意思了:
RA中广播的前缀必须与br0中获取的前缀一致,否则客户端就算错了嘛!但这个前缀如何保证一致?写法其实非常简单,直接写::/64
就可以。VyOS通过这个::/64保证了RA广播的前缀始终与目标接口的第一个GUA地址前缀保持一致,不需要你多余操心。
虽然它的写法中有/64
,但其实它广播的前缀长度是与br0实际获取的前缀长度一致的。如果你将PD到的/60前缀不划分任何子网,直接委派到br0上,那么ra就会广播/60的前缀——从而导致内网设备无法SLAAC。这个问题困扰了我们好久,后来是通过抓包才分析清楚的——遇到问题多抓包,数据包自己会说话。
IPv6 DNS
操作系统对于DNS信息往往是没有“v4、v6”的区分的,v4也好,v6也罢,操作系统对待他们网络中提供的DNS从来都是“照单全收”,当需要解析的时候,会向所有的DNS服务器发起请求,并等待最快的回复。但是,为什么我们需要IPv6 DNS呢?很简单,因为我们的DNS服务器地址是IPv6的——DHCPv4响应无法承载IPv6的DNS地址,所以我们需要新的协议来为系统指派IPv6的DNS。当然其实,为了便于记忆,其实我们印象里的大多数DNS是IPv4的,比如1.1.1.1,比如114.114.114.114,比如8.8.8.8。
在IPv6中,DNS可以有三个不同的方式设置:
DHCPv6中Option 23字段中的DNS
使用:这个DNS的使用方法与IPv4相同,都是直接指定DHCP接口的DNS地址即可。
广播:不建议使用DHCPv6对内网设备进行IPv6地址分配,如果一定要用,直接参考文档即可。
SLAAC中的RA消息中的RDNSS字段
使用:未知。我查阅了VyOS的文档和全部源代码,觉得似乎VyOS并不支持直接使用RA消息中提供的RDNSS地址作为DNS服务器的上游地址。这里存疑的原因是,我认为深入研究这个没有意义——因为使用SLAAC指派DNS是一个不太常见的行为,在家庭网络中尤其意义不大。
广播:在IPv6协议里,可以使用RA的RDNSS功能向客户端广播IPv6 DNS地址,具体配置就是在router-advert中加一行
name-server
。PPPoE时也可以提供DNS
使用:这个DNS的使用方法与IPv4相同,直接指定DHCP接口的DNS就会自动设置。其实PPPoE的过程也可以设置IPv6 DNS(甚至可以设置最多3个,多余IPv4 DNS的最多2个),可以直接像IPv4 DNS一样直接获取,没有问题。
以上,我们就实现了在家庭网络中配置VyOS,并正确分配给内网设备IPv4/IPv6地址并让内网设备上网的功能。示例配置会贴在文章最后。
防火墙配置
……距离万事大吉,还有最后一步,配好防火墙。其实防火墙是非常难配的。
在家庭网络中部署这个路由器,最后一部当然是将防火墙配置好,避免所有安全隐患。在VyOS中也不例外,你需要手动制定防火墙规则,
VyOS 4以后引入了一种“基于区域的防火墙”机制,可以针对具体的网络区域做精准的数据包过滤,极大的简化了配置的流程,而且这个规则和任何已有的规则都不冲突,它只描述了数据包在不同的网络接口中流动的行为应该如何被管制而已。你可以搭配使用这两种防火墙,起到最好的保护效果。
路由器中对防火墙配置的一般要求
家庭网络中的路由器是家庭网络最边界的“门神”,所有进入、流出家庭网络的数据包都需要经过路由器控制,而路由器的防火墙又是所有抵达路由器的数据包的第一站,同时又是内网的最后一道防线,因此,正确理解并配置防火墙非常有必要。
不同的网络需求对防火墙的配置要求也不同,比如如果你只是希望配置路由器让内网设备正常上网,则只需要拦截所有向内的数据包即可。如果你需要允许一些内网设备可以被公网正常向内访问,或者只开放这些设备的一些端口,则需要配置额外的例外规则。不过我们这里只讨论基本的原则,不涉及额外的配置项。一般来说,家庭网络中的路由器需要对数据包做以下基本处理,注意这些限制只作用在传入连接中,所有传出连接默认都要放通。
公网(eth2或pppoe0):
- 默认丢弃一切数据包。
- 允许所有ICMPv6的流量(允许来自运营商RA)。
- 允许所有已建立的连接中的数据包通过(允许所有向外建立的连接中返回的数据包,这包括DHCPv6等过程中的流量)。
内网(br0):
默认丢弃一切数据包。
允许所有已建立的连接中的数据包通过(允许所有向外建立的连接中返回的数据包)。
允许所有被路由的数据包通过(允许来自客户端的数据包被路由到公网)。
允许所有目标端口为DNS的数据包通过(允许来自客户端向路由器的DNS查询)。
允许所有ICMPv6的数据包通过(允许来自客户端的RS、NDP)。
允许所有其他接口的传入连接。
IPv4中有一些奇妙的协议,比如ARP——它并不归防火墙规则管理。除此之外还有PING包,你可以自由决定是否禁用PING,它并不会影响网络的主要功能。不过ICMPv6的包必须允许,因为其中包含了正确建立IPv6网络的重要信息。
Linux网络防火墙的简单结构
Linux防火墙是一个已经被讲烂了的话题,本文不对防火墙做过多的说明,而是提供一些中文和英文的参考网站,供需要的读者学习。
https://brinnatt.com/further/%E7%AC%AC-2-%E7%AB%A0-linux-%E9%98%B2%E7%81%AB%E5%A2%99/
(重点阅读)https://zhuanlan.zhihu.com/p/618848653
(nftables,扩展阅读)https://zhuanlan.zhihu.com/p/552721425
其中,我们需要重点关注iptables的配置方法,因为VyOS的配置与iptables的配法相似。
VyOS家庭网络配置路由器的防火墙规则
我们大概了解到了路由器的网络防火墙需要对公网和内网进行的不同处理,不过这个配置应该如何在路由器中实现呢?VyOS有自己的路由器配置方法,相当于将Linux的nftables规则用VyOS自己的配置语言又包装了一遍,不过并不特别复杂。
我们来看看官方文档中对家庭网络IPv6防火墙的配置是什么样的:
firewall {
ipv6 {
forward {
filter {
rule 10 {
action "jump"
inbound-interface {
name "pppoe0"
}
jump-target "WAN_IN"
}
}
}
input {
filter {
rule 10 {
action "jump"
inbound-interface {
name "pppoe0"
}
jump-target "WAN_LOCAL"
}
}
}
name WAN_IN {
default-action "drop"
rule 10 {
action "accept"
}
rule 20 {
action "accept"
protocol "icmpv6"
}
}
name WAN_LOCAL {
default-action "drop"
rule 10 {
action "accept"
}
rule 20 {
action "accept"
protocol "icmpv6"
}
rule 30 {
action "accept"
destination {
port "546"
}
protocol "udp"
source {
port "547"
}
}
}
}
}
注意这份文档中的配置已经过时了,我们不要参考官方文档中的配置进行。可以参考我下面提供的防火墙配置。
我们参考这份文档,可以看到,我们主要配置的项除了global-options外,就是ipv4和ipv6两个块。每个块配置不同,只针对一种IP层的网络协议。
在每个块中,会有forward, input, output, preouting, name这五个可定义的块,其中forward, input, output, preouting是iptables中INET的五大hook点中的四个(没有postrouting,因为它的功能被SNAT代替了),他们直接定义了一条链,并且filter里定义ruleset,每条rule由匹配部分和动作部分组成,动作可以是Accpet Drop,也可以是Jump,和iptables一样。name是一个特殊的block,在里面可以定义一个规则集set,
iptables有四种表,分别是raw、mangle、nat、filter,根据文档这里只用到了filter和raw,因为filter是防火墙主要的规则点,而raw则与conntrack息息相关。而mangle表不常用,nat的功能又集成进NAT模块,所以这里只需要两个表就足够了。
jump到具体的name block中,每个name block可以根据连接属性来匹配连接,有自己的默认行为,经过一系列规则的匹配和动作,最后结束一个简单的流程。
防火墙的具体配置过于复杂,超出了本文所讲的内容范畴。所以本文只提供一份简单的、实现了上面过程的基本配置。希望可以通过这份配置,让大家快速有一个可抄的作业,你可以根据自己的理解和我们提供的配置,结合自己具体的网络情况完成修改。
实现上述防火墙功能的网络配置(VyOS 1.4 Sagitta)
虽然我们也知道困难重重……但最终还是走到了这一步。我们为VyOS 1.4 LTS Sagitta版本编写了一份实现了“路由器中对防火墙配置的一般要求”的防火墙配置,以pppoe拨号、eth0, eht1物理接口组成br0网桥,并以eth2做PPPoE的源端口实现的主机,配置防火墙。
firewall {
ipv4 {
forward {
filter {
default-action accept
}
}
input {
filter {
default-action drop
rule 10 {
action accept
description "allow dns query"
destination {
port domain
}
inbound-interface {
name br0
}
protocol tcp_udp
}
}
}
}
ipv6 {
forward {
filter {
default-action accept
}
}
input {
filter {
default-action drop
rule 10 {
action accept
description "allow wan/lan ra"
inbound-interface {
name br0
}
protocol icmpv6
}
rule 20 {
action accept
description "allow lan dns query"
destination {
port domain
}
inbound-interface {
name br0
}
protocol tcp_udp
}
}
}
}
}
我们不需要在防火墙中显式的处理connection tracker,因为它被整合进了VyOS中的conntrack系统模块中。
我们大概完成了对所有VyOS在家庭网络中需要配置的部分的解释,按照以上部分配置VyOS,就可以在家庭网络中快速、安全、稳定的部署一台软路由服务器,为内网提供不错的上网服务了。VyOS本身还是比较节约性能的,这大概是你能用到的最“专业”的路由器套件了——最重要的,只要你有技术力前文这些工作,这一切都是免费的。
感谢大家看到这里。我们将最后的配置文件在文章的放出来供大家参考(限于篇幅不带防火墙配置,防火墙请根据上面的内容自行添加)。
interfaces {
bridge br0 {
address "192.168.1.1/24"
member {
interface eth0 {
}
interface eth1 {
}
}
}
ethernet eth0 {
hw-id "a0:36:9f:0f:5b:20"
}
ethernet eth1 {
hw-id "a0:36:9f:0f:5b:21"
}
ethernet eth2 {
hw-id "50:e5:49:21:e3:4a"
}
loopback lo {
}
pppoe pppoe0 {
authentication {
password "password"
username "username"
}
dhcpv6-options {
pd 0 {
interface br0 {
sla-id "0"
}
length "60"
}
}
ipv6 {
address {
autoconf
}
}
service-name "CMCC"
source-interface "eth2"
}
}
nat {
source {
rule 20 {
outbound-interface {
name "pppoe0"
}
source {
address "192.168.1.100-192.168.1.254"
}
translation {
address "masquerade"
}
}
}
}
service {
dhcp-server {
shared-network-name NAT1 {
option {
default-router "192.168.1.1"
}
subnet 192.168.1.0/24 {
range 0 {
start "192.168.1.100"
stop "192.168.1.254"
}
subnet-id "1"
}
}
}
router-advert {
interface br0 {
link-mtu "1492"
prefix ::/64 {
}
}
}
dns {
forwarding {
allow-from 0.0.0.0/0
allow-from ::/0
dhcp pppoe0
listen-address 0.0.0.0
listen-address ::1
}
}
}
system {
conntrack {
modules {
ftp
h323
nfs
pptp
sip
sqlnet
tftp
}
}
name-server 127.0.0.1
}
VyOS、GPL与开源软件
VyOS确实是一个自由的开源软件,它符合自由软件和开源软件的所有定义。同时,VyOS也是一个商业软件,因为它付费分发自己的二进制,获得稳定版本和技术支持需要购买昂贵的许可和订阅。这些本身无可厚非,很多开源软件本身也带有商业属性——要恰饭的嘛!但VyOS的开源恐怕只是因为它不得已而为之——毕竟它使用了大量GNU GPL协议的代码,它必须遵守开源协议,将源码放出来——真的仅仅是这样吗?
在我看来,VyOS完全没有必要成为一个完全开源的项目,因为它还有很多不是基于GPL协议代码修改而来的模块,这些模块都没有必要开源,也就是说,一个低耦合程度的操作系统约等于许多软件包之和,如果缺少专有软件包,最终的操作系统就无法构建,但它依然是符合开源协议的。VyOS选择将整个系统开源,可能也是考虑到避免麻烦,以及赚个好名声的考虑,或者只是单纯的想开源——这都是无可厚非的。
VyOS将源代码放出,但尽力阻止用户方便的构建这个项目——只要它的项目是可以构建的,它就是理论上的开源软件,与构建的方便程度其实关系不大。VyOS团队更是找到这个点切入,直接向公众提供Rolling Release的版本,同时通过关闭LTS版本软件包仓库的方法阻止公众获取LTS版本预构建二进制包,提高获得LTS版本二进制的门槛,进而让更多的人转而去购买自己的长期支持服务……这也是无可厚非的商业模式,毕竟开源软件并不代表免费,开源也不代表要开放一切,预构建二进制之类的资源,其实没有必要和源代码一起放出。
我们可以看出,VyOS是一个你无法挑出毛病的开源软件,软件本身没有什么问题。不过VyOS的一个很大的问题是,他作为一个开源软件,却不太践行开源精神。VyOS在自己的讨论社区中随意关闭帖子,在博客中以“用户随意分发二进制”为由关闭软件源仓库,并且在GitHub的众多发布VyOS LTS版本的开源仓库中进行“劝说”……其实我想VyOS可能搞错了一些事情。它可以禁止用户发布LTS版本的二进制镜像吗?VyOS的LTS版本依然是开源软件,为什么构建和发布开源软件的镜像也成了问题?我不理解……而且我在查阅资料的时候,在很多地方都看到大家抱怨VyOS团队作风随意,随意关闭帖子、封禁用户,说实话我对此表示无话可说,毕竟社区是人家的,软件是人家的,什么什么都是人家的,我们只是用户而已,而用户,人微言轻,毕竟我们没有能力开发一款庞大的开源软件解决企业级路由的问题。
在前面提到的VyOS关于关闭LTS软件包仓库的帖子中,他们说只是单纯的关闭了LTS版本的软件包仓库,并没有留给用户任何替代的解决方案,也没有编写任何方便用户构建LTS版本的脚本。只是单纯的提高了构建的门槛,让本来就比较困难的、获取LTS版本的镜像的过程变得更加困难了而已。这越来越体现出类似vyos-jenkins这种项目的重要性——它重新让这个开源项目变得可以构建,这实在很好。在这篇帖子中,VyOS开发者还类比了Monzilla和Redhat的商业模式,我只能说,您是真的牛逼。
Monzilla是开源界的老大哥,没有任何人可以否认Monzilla对全球互联网的贡献,这个名字在全球开发者中如雷贯耳。Monzilla制作自己的浏览器、贩卖服务和广告,是完全的基金会组织,专门为全球自由软件的普及做伟大的贡献,而你VyOS除了千方百计阻挠用户,不让他们妨碍你们赚钱之外,你们做了什么对吧?用户的所作所为对软件本身没有什么好处,那难道你们删帖封号、匿藏软件包、提高授权费用的行为就对社区有多大贡献了?自由软件从来都不只是一个口号——自由软件之所以难能可贵,是因为它映衬出了由开源精神所带来的、潜在的无限可能性之光辉——而如果没有开源的重要参与者信任,这一切都无法发生。VyOS团队视用户为敌,把自己放在全体使用者的对立面,尝试以一种温和的面孔来执行自己的可憎价值观,其行为着实令人不悦,他们挨骂我觉得并不意外。
至于Redhat,我真的不知道该说什么。VyOS都已经在把自己和Redhat比了,那我还能说什么?本来我还想在前面说,VyOS的商业模式比起Redhat,确实开放了不少,毕竟企业用户想获得Redhat的源代码,那么就不要再想获得他们的技术支持了——他们用这种“聪明”的方法与开源协议玩捉迷藏,我并不觉得这种躲猫猫游戏对全球开源事业的发展有什么意义——我想他们也不会关心。但现在VyOS都已经拿Redhat来和自己比较了,只能说明他们对自己的底线要求的有点太低了。这样的开源开发者团队,未来还会做出什么事情?会不会直接把自己编写的私有软件直接闭源,再让整个软件仓库包含10种不同的许可证的代码?我不知道……
VyOS是个好软件,但我依然期待社区赶紧行动起来,找到一个更好的、基于Linux的开源软路由解决方案。
写在后面
感谢各位的阅读。这篇文章又是一篇超级超级长长长的详细论述,Neboer从实验到编写这篇文章足足用了10天左右的时间——我们主要还是从一个比较高的视角概述了NAT、DHCP、PPPoE、DNS、SLAAC、DHCPv6、RA等复杂的协议通信过程,并且深入其中的原理,结合VyOS的具体配置,Learn-by-doing的详细介绍了如何使用VyOS处理家庭网络中的各种问题,最后还小小的吐槽了一下VyOS的逆天开发者们,表达了自己的一些小小的意见……希望大家可以理解我们的工作,尝试使用开源操作系统解决自己的问题,并积极建设社区,分享自己的使用体验。
本文只是借VyOS这个操作系统,来为展示网络世界中,大家日常使用,而又常常被人们忽略的隐蔽的角落——IPv4/IPv6周边的协议原理。在OSI模型的2层和3层中所发生的事情,总是这样的迷人,总是这样的引人入胜,让人欲罢不能。就像我在和vyos-jenkins开发者dd010101的issue中提到的那样,我“第一眼就爱上了这个路由器系统”,然后就用一周的时间不断的深入研究,最终从实验结果和配置中学习到了这些复杂的技术原理,总结出来,写成文章,希望能对你有用。受限于篇幅,我们实在无法再把事情讲得更加详细,我们对很多协议缺少深入的研究,比如IPv6中至关重要的邻居发现机制NDP——这些实在和路由器配置没什么关系,只能暂时按下不表,实在感兴趣的读者,欢迎翻开计算机网络的课本,重新复习一下这些尘封的知识。
如果你也在中国大陆使用家庭网络对外提供简单的网络服务,而苦于没有好用的路由器系统可以使用的话,不如试试VyOS这个开源的软路由系统,它真的太棒了。希望我的研究能让你有小小的收获,如果你觉得这篇文章中所讲的内容有一部分帮到了你,那就是对我最大的赞赏了,Neboer会承诺继续努力,为“让开源更好的服务于人类”这个目标做更多的贡献。
谢谢大家。
花絮
感谢我们Until Software的硬件工程师Eibon为我们第一次构建提供了Debian Bookworm的虚拟机环境,我当时用那个机器构建了一晚上——结果因为代理配置得不够完善,出了非常非常多的问题,构建失败。第二天吸取教训,在另一台ArchLinux主机上配置了同样的虚拟机并在里面配好了透明代理,终于解决了所有的网络问题。
感谢Until Software资深的网络工程师和技术专家Krusl,在第二天的实验中配好了虚拟机中的透明代理,为成功构建VyOS LTS镜像提供了坚实的基础。
感谢vyos-jenkins仓库的开发者dd010101,不但在VyOS官方镜像LTS包不提供下载后以一己之力做了大量的工作恢复了源代码库的可构建性,热心的帮忙解决问题,并且积极回答我的提问,是非常敬业的开发者。
那么Until Software里的同事们是如何看待Neboer对VyOS的研究的呢?
(Until Software三人组在交界地团建)Eibon:欸怎么卡了——Krusl:可能是Neboer在编译VyOS😅
(问Krusl对VyOS有什么想法)Krusl:感觉不如我直接用ArchLinux或者NixOS手搓一个出来。
(问Krusl对IPv6协议的研究)Krusl:太trival了,没兴趣,我们研究一下怎么在仅支持SLAAC的环境里配路由器吧(掏出某篇博客)欸,你看,只要这么配就可以让所有的流量都走路由器了!(那为什么不直接桥接v6?)欸,你不懂对吧,因为需要让路由器去管理内网设备的流量对吧……
(当Neboer成功构建出了LTS镜像)Eibon:构建得好对吧,离我的路由器远亿点对吧(……)为什么不用华为路由器呢?是因为不喜欢吗?(随手拿出自己的华为全家桶)欸,喜欢我的华为企业交换机、华为路由器、华为电源吗?已经给服务器全换上了,不用感谢我(然后第二天路由器的2.4G网卡全坏了)。
(写到这里的)Neboer:受不了了,赶紧毁灭吧😅