一箭三雕,Linux一键重装支持纯IPv6环境AlpineLinux Ubuntu Windows

查看 44|回复 3
作者:天权璇玑   
   
论坛主贴:
https://91ai.net/thread-1159839-1-1.html
github:
https://github.com/leitbogioro/Tools
图库为 sm.ms,国内用户需挂梯子全局才能查看。
最近更新内容:
整理并美化 kickstart 中配置各红帽(Redhat)、软呢帽(Fedora)源格式;优化红帽 9+ 、软呢帽多 IPv6 配置策略,以“addr-gen-mode=eui64 nmethod=auto”为关键词,匹配未被初始化的 IPv6 部分,然后再进行改为静态、写入多条 IPv6 操作,避免双栈机 IPv4 栈为动态配置时,仅以“method=auto”为关键词更改 IPv6 配置方法时,把 IPv4 配置部分搞错乱;指定 -windows '版本号' ,以 AlpineLinux 为中介 dd 来自秋水逸冰制作的 Windows 镜像源时,会在目标系统内嵌入一个“SetupComplete.bat”,仅在用户首次桌面后运行,它会自动进行配置静态 IPv4、把 dd 镜像 15GB 分区扩展成系统所在分区全盘容量;对于不规则 IPv4 网络 dd 的 Windows ,如果掩码范围过窄,会导致 wmic nicconfig 命令无法刷入主 IPv4 ,掩码,所以 24 以上的掩码后缀,统一改为 24; 为 Windows 刷入静态 IPv4 配置的步骤为:1. 先刷入主 IPv4 ,掩码;2. 将主 IPv4 当做网关刷入;3. 将真实网关刷入,替换掉第 2 步部分,第 1 2 步目的是为了形成一个受 Windows 网络服务承认的配置,避免刷入失败;如果查询到 ssh 服务中,访客通过内网 IP 访问机器,说明大部分情况下,该机器和访客处于同一个物理区域,此时查询内网 IP 归属地做时区是无意义的,因为统一都是美国纽约。所以一旦发现这种情况,会将本机通过 dns 从公网返回的 IP 归属地做时区;把判断 IPv4 或 IPv6 是否为内网地址封装成了函数,方便各处调用;彻底优化 IPv4 栈和 IPv6 分别属于系统中的哪张网卡的判断,因为一旦以某个栈重启后安装并配置网络时,如果对应栈的网卡并非物理连接到系统中的第一个,会造成配置失败;AlpineLinux 对多网卡的处理规则,和 Debian 系,红帽软呢帽系正好相反,它会优先配置按物理顺序连接到系统中的最后一张,所以如果系统中有多网卡,且只有一个网卡负责与公联通信,重装 AlpineLinux 时会采用静态配置;对应 AlpineLinux Ubuntu 的自动应答文件中的网卡名也不再写死成“eth0”(因为有些环境下 eth1 负责连接外网,eth0 作用不明),而是会在原系统检测,得出正确结果,在再安装时替换掉相关网络配置文件部分;判断 IPv4 IPv6 栈分别所属哪张网卡的基本原理,是先列举中系统中所有网卡,然后把它们分别和 ip route show default ip -6 route show default 的结果相比对,一旦发现某张网卡在其中,就会把它当做分别对应 IPv4 IPv6 栈的网卡;在此基础上,我把记录所有网卡名的数据,存储在数组里,这样可以通过检索对应网络栈中网卡在系统中的顺位(index),反推出如果安装新系统,网卡名需要重定向时,究竟该对应 eth 后的哪个数字,虽然写死“eth0”可以应付绝大部分情况,但仍然会在某些“eth1”负责连接外网的机器上配置失败; 基于 AlpineLinux 对多网卡处理的特性,多网卡环境下,只能采取静态配置,即使原环境是动态配置,这样才能在 ip= 中添加需要配置的网卡名,避免 AlpineLinux 将 eth1 当做主网卡配置而非 eth0;由于在中介系统 AlpineLinux 中 dd Ubuntu 时,AlpineLinux 系统还未被完整展开,仅需加载一些下载工具、需要挂载目标硬盘的组件即可,所以 512MB 内存环境就可以完成 dd 需求,所以 dd 安装 Ubuntu 的内存要求降低为 512MB;如果仅安装 AlpineLinux ,内存要求维持至少 1GB 不变;通过极限微操,软 hack AlpineLinux 内核 init 文件,使之支持单 IPv6 栈环境,动态 dhcp 或静态 static 配置 AlpineLinux 临时环境和安装 AlpineLinux,一箭三雕;由于以上问题解决,纯 IPv6 栈通过 dd 安装 Ubuntu Windows 也不在话下;配置 AlpineLinux 安装时,添加 dhcpcd 组件,使之支持单栈 IPv6 下 dhcp 配置方法;为 AlpineLinux 优化并添加对应 IPv4 IPv6 动静态共 8 种不同组合的网络配置文件,使之能更好地适应更多不同复杂的网络环境;对于为单栈 IPv6 动态环境的目标系统 AlpineLinux ,网络配置中仅配置 IPv6 动态,不配置 IPv4 动态,否则系统中显示的 IPv6 地址会错乱,也无法 ssh 连接;优化 Ubuntu 自动应答文件 Cloud init 配置文件中配置 netplan 部分,对于 IPv6 dhcp ,添加 accept-ra: true ,使之能够更好地适配 IPv6 dhcp 网络;我已在 2023 年 5 月份时,就对 AlpineLinux 开发团队提了在 IPv6 下,支持 AlpineLinux 网络启动的 issues: https://gitlab.alpinelinux.org/alpine/aports/-/issues/15034,官方也给了建设性的回复,乐观估计等 AlpineLinux 3.19 版本发布的时候,该问题可能会得到妥善解决,详情参见:ipv6 support for udhcpc scripts + pxe ,欢迎有志之士也向 AlpineLinux 官方提出合理的、建设性的,有关功能支持、bug 修复等有关的需求。
今天详细讲解的内容,主要是让 AlpineLinux 彻底支持不同情况下的单栈 IPv6 环境。
众所周知,AlpineLinux 官方是不支持单栈 IPv6 环境下,从网络内核启动,成功配置网络的,官方 PXE 启动 文档也自 2021 年后,就很久没有再更新了,里面仅提及配置 IPv4 部分,乏善可陈。
但自从上篇文章 略施巧计,飞跃 Hetzner 重装 AlpineLinux Ubuntu Windows 险阻 中,我们找到了一个绝妙的方法,通过劫持 init 文件中 configure_ip() 函数静态网络配置注释和判断式下,添加 ip route 命令,强制让不规则 IPv4 添加到临时环境,以实现成功配置网络。
正所谓只要招数管用,一次用是用,十次用也是用,屡试不爽,就看能把它巧妙地运用于哪个地方,大方向对了,中间的一些小困难都是能克服的。
中间排坑的地方就不说明了,直接讲解代码吧:
以下是修改 init 文件前,脚本中对应单栈 IPv6 时的处理方法,elif 前面还有一个对应单栈 IPv4 和双栈的判断式,涉及软 hack IPv4 的,之前文章里讲过,就不贴了:
[ol]elif [[ "$IPStackType" == "IPv6Stack" ]]; then
  if [[ "$Network6Config" == "isStatic" ]]; then
    fakeIpv4="172.25.255.72"
    fakeIpMask="255.255.255.0"
    hackIpv6Context="manual configuration"
  elif [[ "$Network6Config" == "isDHCP" ]]; then
    hackIpv6Context="automatic configuration"
  fi
  sed -i '/'"$hackIpv6Context"'/a\\t\tdepmod\n\t\tmodprobe ipv6\n\t\tip link set dev '$interface6' up\n\t\tip -6 addr add '$ip6Addr'/'$actualIp6Prefix' dev '$interface6'\n\t\tip -6 route add '$ip6Gate' dev '$interface6'\n\t\tip -6 route add default via '$ip6Gate' dev '$interface6' onlink\n\t\techo '\''nameserver '$ip6DNS1''\'' > /etc/resolv.conf\n\t\techo '\''nameserver '$ip6DNS2''\'' >> /etc/resolv.conf' /tmp/boot/init
fi[/ol]复制代码
然后是写入 grub 引导 menuentry 菜单时的处理事项:
[ol]elif [[ "$IPStackType" == "IPv6Stack" ]]; then
  [[ "$Network6Config" == "isStatic" ]] && Add_OPTION="ip=$fakeIpv4:::$fakeIpMask::$interface6:::" || Add_OPTION="ip=dhcp"
fi
  BOOT_OPTION="alpine_repo=$LinuxMirror/$DIST/main/ modloop=$ModLoopUrl $Add_OPTION"[/ol]复制代码
好奇怪哦,再看一眼,配置 IPv6 静态的话,我们明明是要写入 IPv6 的相关参数,为什么要给内核启动,静态配置网络参数时,添加“172.25.255.72”、“255.255.255.0”两个写死的,毫不相关的 IPv4 参数呢?下面我连带软 hack IPv6 动态静态的原理,一起好好解释一下吧:
首先我们来看一下,对于处理静态 IPv6 网络(包括公网 IPv6 + fe80::1 内网网关)的方法:
显然,对于这种情况,我们需要劫持并定位的,对应 init 中 configure_ip() 函数中的上下文,根据传参到“hackIpv6Context”变量值,即需要软 hack 匹配的上下文关键词,为“manual configuration”,显然是在其以下,用类似于手动添加 IPv4 各配置的方法,把 IPv6 各配置也写入进去。

网卡, 静态, 网络

天权璇玑
OP
  
   
sed -i 从“manual configuration”下面若干行追加的命令,显然有些冗长难懂,我把它的结果整理成易读格式:
[ol]depmod
modprobe ipv6
ip link set dev eth0 up
ip -6 addr add IPv6 地址/IPv6 掩码后缀 dev eth* 网卡名
ip -6 route add IPv6 网关 dev eth* 网卡名
ip -6 route add default via IPv6 网关 dev eth* 网卡名 onlink
echo 'nameserver 2001:4860:4860::8888' > /etc/resolv.conf
echo 'nameserver 2606:4700:4700::1111' >> /etc/resolv.conf[/ol]复制代码
“depmod”和“modprobe ipv6”负责开启 AlpineLinux 网络启动内核的 IPv6 模块及相关依赖,后面的命令就是对于 IPv6 版的添加本机 IPv6 地址、掩码、网关、设置 DNS ,区别无非就是从 ip 变成了 ip -6 ,对规则的或不规则的 IPv6 都生效,这里就不再赘述。
如果机器的 IPv6 是用 dhcp 配置的,通过读取原系统中的网络配置文件,判断出符合这一情况,那么传参到“hackIpv6Context”变量值,即需要软 hack 匹配的上下文关键词,就变成了“automatic configuration”,添加 IPv6 网络详情的步骤和静态情况下完全一致。
下面我们来看在 grub 引导菜单中,配置“ip=...”,这里对于 IPv6 静态或动态的处理就有了更多不同。
[ol][[ "$Network6Config" == "isStatic" ]] && Add_OPTION="ip=$fakeIpv4:::$fakeIpMask::$interface6:::" || Add_OPTION="ip=dhcp"[/ol]复制代码
显然,主条件是“Network6Config”(IPv6 的配置方法)是否为“isStatic”(静态),如果为是,则指定了以下方法,如果为否(即 IPv6 为动态配置),则指定“ip=dhcp”。
[ol]Add_OPTION="ip=$fakeIpv4:::$fakeIpMask::$interface6:::"[/ol]复制代码
“interface6”很好理解,就是负责处理 IPv6 网络连接的网卡名,细心的小伙伴们发现了,“fakeIpv4”和“fakeIpMask”和上面的代码形成了联动,即强制给 AlpineLinux 网络启动内核一个主 IPv4 为 172.25.255.72 ,IPv4 掩码为 255.255.255.0 的参数。
咱们明明是在配置 IPv6 网络的相关参数,为什么要给一个固定的,且“假的”(fake*) IPv4 地址和掩码呢?
答案很简单,因为直至目前的 AlpineLinux edge(3.18 版本),AlpineLinux 都无法原生支持从内核启动读取“ip=”参数,来获得并承认有效的 IPv6 参数配置格式。
之所以给一套假(fakeIpv4, fakeIpMask)的 IPv4 配置(主 IPv4 、IPv4 掩码),是为了确定让 AlpineLinux 的网络内核程序,以“静态”方式去启动网络服务配置网络,虽然这套假的 IPv4 配置,并不能真正地让网络安装内核按其参数去把网络配置好,但别忘了,刚才我们还有一套添加了真实 IPv6 参数,并让网络安装内核去访问 IPv6 网络的方案。
这套假的 IPv4 配置,作用仅限于让 AlpineLinux 以静态配置方式启动并配置网络服务,至于它是什么,无所谓,我选用“172.25.255.72”这个 IPv4 ,也是参考了全网并没有哪个具体环境,真的把它当做一个有效的 IPv4 去配置,而且它也属于互联网 IP 组织规范中,IPv4 内网地址的范围之内(172.16.0.0 - 172.31.255.255),任何人和组织都可以把它当做内网 IP 去配置,不会影响到任何在公网上服务的计算机。
为了尽量避免,因为设置了一个真实存在的公网 IPv4 ,而导致发生一些其他不可预知的后果,我便选择了这个 IPv4 地址,作为“骗过”AlpineLinux 并强制令其进行静态网络配置的临时 IP,力图把设置为该 IP 而引发的不良后果范围降低到最小。
可能还会有一些探索欲旺盛的朋友问,要让 AlpineLinux 网络启动内核以静态方式配置网络,不配置这套假的 IPv4 行不行?比如给:
[ol]ip=:::::$interface6:::[/ol]复制代码
就让其从 IPv6 网卡,启动静态的网络配置是否可行?
我当然不会没考虑过这一点,怎么可能先用反直觉的“fake IPv4”来“骗过” AlpineLinux ,但经过实际测试,发现用:
[ol]ip=:::::$interface6:::[/ol]复制代码
来配置,发现程序始终不能正确通过“Setting IP”步骤,所以才大费周章,用“假 IPv4”来应付这一难关。
所以,经过以上实验,我们得出了,要通过 ip -6 添加 IPv6 参数、内核启动时,指定假 IPv4 等一系列操作,让 AlpineLinux 网络安装内核能够顺利启动,并配置 IPv6 网络的结论,并且我们在正式为 AlpineLinux 或 Ubuntu 系统中,配置网络环境的时候,给出了适合的 IPv6 配置。
并且由于这套假的 IPv4 参数,仅限定于重启后在内存中加载的,AlpineLinux 网络内核在内存启动时的临时环境,而且由于在添加了 IPv6 相关参数并能够正常访问 IPv6 网络后,AlpineLinux 在执行后续与网络连接相关的命令时,如果发现已配置的 IPv4 部分工作不正常后,会切换到已正常运作的 IPv6 栈部分去进行访问。
再加上刷入到硬盘中的正式系统内,IPv6 部分是按规范进行配置的,所以这套假 IPv4 配置,在原生安装 AlpineLinux 或 dd Ubuntu Windows 后,重启后进行配置时的负面影响,就完全消失了,内存断电重启后数据完全消失,这是人人都知道的公理。
对于 IPv6 dhcp 动态配置下的情景,为什么内核启动参数又变成了“ip=dhcp”呢?
由于我本次测试中的各类环境,IPv6 动态环境仅限于 Vultr 的,Vultr 的 IPv6 only 机型,本质上是有一套完整的 IPv4 IPv6 内网 dhcp 路由 + 阉割了获得公网 IPv4 地址的方式实现的,所以本质上它还是有一套完整的本地 IPv4 dhcp 网络,只不过 IPv4 无法获得公网 IPv4 地址,所以内核启动时,要指定“ip=dhcp”来设置从 IPv4 dhcp 获取地址,手动添加 IPv6 各配置的方法,仍然通过软 hack 实现。
好奇的朋友们可能又会问:反正实现 IPv6 的访问,都是靠 ip -6 手动实现,为什么不将其归类到劫持 AlpineLinux init 文件的函数“configure_ip()”的静态配置方法,即“manual configuration”中。
反而要根据从原系统中读取到的动态配置,单独把它归类到劫持“automatic configuration”方法里呢?
这里面当然是有说道的,下面我们来假设(我试验过)的情形,即 Vultr 环境,服务器支持 IPv4 IPv6 双栈动态配置,且 IPv4 有完整的 dhcp 本地路由,无法获得公网 IP ,且 IPv6 栈支持 dhcp 连接到公网的情况。
通过 grub 内核启动时,指定:
[ol]ip=:::::$interface6:::”或“ip=$fakeIpv4:::$fakeIpMask::$interface6:::[/ol]复制代码
来配置,这里我放一张测试时遇到的截图。

显然,AlpineLinux 网络内核程序,返回了“Installing packages to root filesystem, ICMPv6 RA: ndisc_router_discovery failed to add default route”的错误,即母机 IPv4 配置命令,覆盖了我们指定的, AlpineLinux 网络安装程序的 IPv4 静态命令,并生成、覆盖了一套仅适用于该 IPv4 dhcp 环境下的配置参数,让我们在内核中指定的“糊弄” IPv4 部分徒劳无功:
如果你有志于探索和我 debugging 时一样的排坑之路,那么几乎 99% 的情形下,会被各种错误所击溃,为了造福于后人,我只能把我通过各种艰难险阻之路探索后的结果,忠实公布于众,然后把我为数不多迷雾图中的艰辛分享给你,希望你在至少参考了我无头苍蝇试错的路上,多多少少能避免重复出现我遇到的低级错误,或者能从我试错的路径之上,寻找到一条更接近康庄大道之路的导航规划。
你们也别笑我笨,因为我本非计算机科班出身,仅靠兴趣和毅力坚持到如今。
在内核启动中指定“ip=dhcp”后,由于机器本身 IPv4 网络部分的配置被上游 dhcp 服务器正确配置了,且 init 文件里指定了正确的 IPv6 网络参数,所以临时环境 AlpineLinux 中,IPv6 栈也是能顺利访问的,后期无论是安装 AlpineLinux 到系统,或是 dd Ubuntu 或 Windows ,后续过程自然也是一气呵成,不会有任何阻碍了。
百闻不如一见,打一万句嘴炮,不如久经考验的实测,下面直接放图吧,怀疑我是为了节目效果,故意 PS 的,请大大方方地,在本帖中点上一个“反对”即可,我没这个精力,也不需要去和这类声音对线。相信我的考据、结论的人,自然会保持一份信赖,用我的脚本实现他们需要的功能和目的,然后以真诚去印证我的承诺和结论。
实验机型 idc.wiki 虽然为纯 IPv6 机型,但由于内存仅为 512MB ,无法满足从内存中完整加载整个被配置好的 AlpineLinux 并写入硬盘的要求,故测试前提仅从 AlpineLinux 网络安装内核启动时的 IPv6 网络栈配置情况(注释了原脚本中,正式部署 AlpineLinux 的 chmod a+x $sysroot/etc/local.d/${AlpineInitFileName}; ln -s /etc/init.d/local $sysroot/etc/runlevels/default 部分),不涉及正式安装完整版 AlpineLinux 后从原生系统启动并查看其网络配置部分,但安装 Ubuntu 依然可以成功,且可以展示安装后的效果。
为保持变量结果统一,原系统均为各 VPS 自带的原系统 Debian 12 ,从其他自带模板,如 Debian 11-, AlmaLinux, RockyLinux, CentOS 等也经过测试,脚本均能正确地、自动读取出原系统中是 IPv6 动态或静态配置,然后指定 AlpineLinux 网络安装内核以适应的参数,在单栈 IPv6 网络下正确配置。
天权璇玑
OP
  
环境:idc.wiki ,512MB 内存,单栈不规则 IPv6 静态 static。
idc.wiki Web 后台网络配置详情:

idc.wiki 脚本安装 alpine 界面:

idc.wiki 脚本安装 alpine init:

idc.wiki 脚本安装 alpine grub:

idc.wiki 脚本安装 alpine VNC:

idc.wiki 脚本安装 Ubuntu 界面:

idc.wiki 脚本装完 Ubuntu:

对于部分环境 dd 安装 Ubuntu 需要说明一下,可能由于原环境为 Cloud init ,对脚本自行执行从 Cloud init 配置文件启动配置时产生影响,此时除了“网络配置”外,自定义端口、预置组件等自定义都是不生效的,所以一旦发现安装 Ubuntu 时,且定义端口并非默认的“22”,安装成功后连接自定义端口失败,请尝试采从 22 端口连接,默认密码:
[ol]LeitboGi0ro[/ol]复制代码
不会变,安装后可自行修改 ssh 端口、密码,或设置密钥(key)连接。
环境:Server-Factory ,2GB 内存,单栈 IPv6 静态 static。
server-factory Web 后台网络配置详情:

server-factory 脚本安装 alpine 界面:

server-factory 脚本安装 alpine init:

server-factory 脚本安装 alpine grub:

server-factory 脚本安装 alpine VNC:

server-factory 脚本装完 alpine:

server-factory 脚本安装 Ubuntu 界面:

server-factory 脚本安装 Ubuntu VNC:

server-factory 脚本装完 Ubuntu:

环境:Digital Ocean, 1GB 内存,双栈 IP 静态配置网络,通过“ bash InstallNET.sh -debian 12 --networkstack "ipv6" ”重装成仅配置 IPv6 静态网络,IPv4 栈无法访问,以模拟纯 IPv6 栈情况。
Digital Ocean Web 后台网络配置详情:

Digital Ocean 脚本安装 alpine 界面:

Digital Ocean 脚本安装 alpine init:

Digital Ocean 脚本安装 alpine grub:

Digital Ocean 脚本安装 alpine VNC:

Digital Ocean 脚本装完 alpine:

Digital Ocean 脚本安装 Ubuntu 界面:

Digital Ocean 脚本安装 Ubuntu VNC:

Digital Ocean 脚本装完 Ubuntu:

环境:Vultr, 1GB 内存,IPv4 IPv6 双栈 dhcp 配置,且特意设置成 IPv4 栈无法路由到公网 IP ,且仅 IPv6 能。
Vultr 创建实例时,关闭获得 IPv4:

Vultr Web 后台网络配置详情:

Vultr 脚本安装 alpine 界面:

Vultr 脚本安装 alpine init:

Vultr 脚本安装 alpine grub:

Vultr 脚本安装 alpine VNC:

Vultr 脚本装完 alpine:

Vultr 脚本安装 Ubuntu 界面:

Vultr 脚本安装 Ubuntu VNC:

Vultr 脚本装完 Ubuntu:

后记
我尽己所能,汇集了我手头现有的、能够模拟的,各类纯 IPv6 栈网络环境,实现重装 AlpineLinux 和 Ubuntu 的条件与结果,对于 -windows '版本号' ,且 IPv6 静态配置的情况,只能重装后进 VNC 手动修改 IPv6 静态配置,抱歉,在此深表歉意。我只是提供了一个可能性,因为习惯了桌面环境,图形化“点选点”的操作,我对 Windows 的命令化流程配置是真不熟;如果你在某个确定的单 IPv6 环境中,遇到了相关的困难和阻碍,请立马反馈给我,我将以此为鉴、不吝赐教;IPv6 dhcp 环境,如果也配置了 IPv4 dhcp 条目,IPv6 地址会错乱的问题,煎饼哥 bin4-9 说是因为 AlpineLinux dhcpcd 组件默认自带 IPv6 隐私保护,创建了一个随机 IPv6 地址造成的,此时虽然本机能够通过 IPv6 和公网连接,但外网无法访问通过本机 IPv6 连接,包括 ssh 等,如果要解决这个问题,需要改相关配置文件,但我发现 Vultr 纯 IPv6 dhcp 环境下,不配置 IPv4 dhcp 条目就不会出这个问题,所以就这样吧,懒得改了,代码和人,有一个能跑就行;如果今后出现了某个单纯的,仅支持 IPv6 dhcp 路由通告,且无 IPv4 dhcp 路由和公网 IPv4 的环境,我们又该如何应对?
____________Cc   
沙发 前排??
您需要登录后才可以回帖 登录 | 立即注册

返回顶部