全球主机交流论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

CeraNetworks网络延迟测速工具IP归属甄别会员请立即修改密码
查看: 2790|回复: 17

[经验] 跨越极限,Linux一键重装接受Crunchbits机50条IPv6写入大试炼

[复制链接]
发表于 2023-8-11 17:16:14 | 显示全部楼层 |阅读模式
本帖最后由 天权璇玑 于 2023-8-11 17:39 编辑

论坛主贴:

https://hostloc.me/thread-1159839-1-1.html

github:

https://github.com/leitbogioro/Tools

图库为 sm.ms,国内用户需挂梯子全局才能查看。

以下案例除了我自己在用机型,来自其他坛友反馈报告的案例部分均已做隐**理,各位不必担心自己机器的真实 IP 地址等信息泄露。

省流版

脚本在 Crunchbits 重装,且支持写入多条 IPv6 规则的条件限定为以下,缺一不可。 如果你的机器没有启动项随意变动的问题,设置启动顺序部分可以忽略。

  • 输入 lsblk -ip ,如果发现系统分区在 /dev/sdb ,请务必在后台重新设置一下启动顺序,然后重启系统,再次查看 lsblk -ip ,确保当前系统内,系统所在分区在 /dev/sda
  • 重装为 Debian/Kali,红帽 9+ Fedora 全系,可保证多 IPv6 配置不会丢失;
  • 重装为 AlpineLinux、Ubuntu、Windows 或自定义 dd 后,多 IPv6 配置会丢失切不可逆,除非用后台模板再次重装;
  • 系统本身必须拥有 IPv4 网络,纯 IPv6 栈机器暂不支持多 IPv6 配置添加。
  • Crunchbits 重装时如果发现安装器提示无法找到硬盘,是因为其硬盘、光盘启动顺序经常错乱导致的,而非脚本判断系统安装盘失误,安装时如果出现此类错误提示,在面板里重新设置启动顺序,重启安装器即可解决:
  • Crunchbits 特价机 IPv6 网络部分于 2023 年 8 月 10 日 UTC+8 4:00 时起开始离线,表现特征为 ping 外部 IPv6 服务器时,显示“From _gateway ( fd2e:: ) icmp_seq=1 Destination unreachable: Port unreachable”(来自网关 xxx,目标不可达,端口无法建立),其 IPv6 网络也无法被外界访问。无论是从后台模板建立的系统,还是用我脚本重装过后的系统,目测原因是 IPv6 栈网络正在维护,此时水友们如果面临“系统中 IPv6 配置已有,且 IPv6 不可访问”此种状况,可以在脚本运行时加入 --networkstack "bi 或 bistack 或 dual 或 two" ,如:
    1. bash InstallNET.sh -debian "12" --networkstack "dual"
    2. bash InstallNET.sh -kali "rolling" --networkstack "dual"
    3. bash InstallNET.sh -centos "9" --networkstack "dual"
    4. bash InstallNET.sh -alma "9" --networkstack "dual"
    5. bash InstallNET.sh -rocky "9" --networkstack "dual"
    6. bash InstallNET.sh -fedora "38" --networkstack "dual"
    复制代码
    来让系统以“双栈”配置安装(实际上 IPv6 部分暂时不可用,仅有有效的 IPv6 配置),后续等待商家 IPv6 网络部分修复。IPv4 部分始终正常,不影响重装。

将硬盘设置为启动顺序第一位:



访问 VNC,发现此时安装器停留在磁盘 /dev/sda 无法写入阶段,按图示重启即可:



再次自动进入安装环境,anaconda 完成环境自检,新系统可顺利安装:



Debian 安装器硬盘无法写入报错处理方法和以上红帽系一致。

敬告:本文篇幅“有点”长,可能是我写过的技术类文章里最长的一篇,如果你也和我一样对技术有着狂热追求,欢迎耐心读完。否则读完省流版使用说明后,您就可以放心离开。

以下好戏开场:



Crunchbits 案例机型特点展示

这几天在论坛霸榜的 Crunchbits 特价鸡是真香,2 核 3GB,年付不到 14 刀,在此恐怖如斯的性价比加持下,其他诸如网络会无故突然离线,硬盘容量稍小,库存少等等问题,都不算“demerits”,只能算“features”。

本文不对该机型的详细硬件配置再做过多论述,感兴趣的自搜论坛相关 performance bench 贴。我只把我感兴趣的特点列举一下:

  • 这家面板从界面来看,和我之前做过测试的 Kuroit 几乎一致,现在有不少商家用的都是这套后台,界面清爽,各项功能也不缺,经坛友点拨,提供商来自:https://virtfusion.com/ ;



  • 后台自带模板种类比较丰富,每套大类别下的 Linux 发行版都带有其最新版本,重装速度不慢,部署技术为常见的 cloud init,会瞎改 Debian 系网络配置文件目录,cloud init 传统迷惑操作;



  • 查看 VNC 很方便;
  • 支持挂载光盘,目前仅有一个 Debian 11 iso,但不支持自定义上传或挂载远程的,而且这个功能会对重装造成一些干扰,这个后面会说;



  • IPv4 部分配置“稍微”有点不规则,主 IPv4 为 104.36.84.237,IPv4 网关为 104.36.84.1,掩码为 255.255.255.255,按经验来说,最合适的掩码值应当为 24(255.255.255.0),实际掩码值无疑有点过小,不过这无所谓,我脚本处理这种案例时,能通过先给临时掩码 24,以通过 Debian installer 网关检测,先让系统顺利装完,再在安装后期将掩码改回原来的 32,确保安装、日常使用时都不会有任何问题。其他同类脚本如果只给 dhcp 或按原样 IPv4 参数以静态配置,Debian installer 一定会报错。



  • 重头戏来了,IPv6 才是这台玩具的亮点,商家给了一个 2606:a8c0:3:6f:: 段,其中可以自由添加属于该段中的任意 IPv6,虽然上限只有 50 个,不过这也很炸裂了。



  • 如果开启了多个 IPv6,如 2606:a8c0:3:6f::a/b/c/d/e/f/10/11 等,2606:a8c0:3:6f:: 段第一个 IPv6 地址,即它自己必须要被正确地静态配置,否则 2606:a8c0:3:6f::xxx 无**常连接网络。
  • IPv6 网关为 fd2e:: ,虽然不是常见的 fe80::1 ,但也算符合规范。属于 IPv6 规范中的众多内网 IPv6 地址之一。
  • IPv4 和 IPv6 幸亏都属于同一个 interface ,不然又有大麻烦。


先行研究,确定写入策略

机器抢到手,自然第一时间就要进行重装测试,后台默认给的 IPv6 其实已经有两个,一个是 2606:a8c0:3::64/128 ,另一个是 2606:a8c0:3:6f::a/64 ,第一次重装完发现系统能登陆,欢迎页面也能返回 2606:a8c0:3:6f::a DNS 查询结果,我本以为没什么问题了。

后来发现自己还是 too young,没意识到仅写入 2606:a8c0:3:6f::a/64 IPv6 配置所引发的后果,直到有同款机型的坛友 hostlocmjj 私信我报告了重装后 IPv6 工作不正常的问题,经过我这边的验证,问题确实存在,我才开始重视起来并开展脚本重装后对多 IPv6 的写入研究。

就像上述所言,不配置 2606:a8c0:3::64/128 的情况下,仅配置该段下属的其他 IPv6,系统中 IPv6 网络是不可访问的,原因是脚本之前处理双栈机时,默认的状况是视机器仅有一个 IPv4 和 IPv6,重装前仅会获得他们之中的一个进行配置操作,而 IPv6 部分获得并配置的是 2606:a8c0:3::a ,而非 2606:a8c0:3::64,所以才造成了 IPv6 网络工作不正常。

随着 IPv6 的普及,越来越多的服务器开始拥有双栈配置,许多为了节省 IPv4 成本,仅有 IPv6 的单栈机更是不在少数,而且由于 IPv6 的理论容量为 2 的 128 次方,与 IPv4 的理论容量 2 的 32 次方相比,简直可以用“浩瀚”来形容,以目前人类的需求,应该是不会面临 IPv6 地址资源“枯竭”的那一天。

所以我在脚本中处理 IPv6 的部分,早就下了很大功夫以适配,前瞻性的工作做得多早都不为过。

由于 IPv6 数量大的特性,未来更多双栈,甚至单栈 IPv6 机型,不排除会有被分配一个大 IPv6 段,拥有多个 IPv6 公网地址的特性,本篇文章的聚焦点,就是解决 Crunchbits 双栈机中,多 IPv6 的配置难题。

首先是 Debian/Kali 系,在默认有两个 IPv6 地址配置下,我们先来查看一下模板系统 Debian 12 中网络配置文件详情:

  1. # control-alias eth0
  2. iface eth0 inet6 static
  3.     address 2606:a8c0:3::64/128
  4.     gateway fd2e::

  5. # control-alias eth0
  6. iface eth0 inet6 static
  7.     address 2606:a8c0:3:6f::a/64
复制代码

可以看到,配置文件中共有两个 iface eth0 inet6 static 条目,每个条目下分别对应着各自的 IPv6 地址/掩码后缀,其中 2606:a8c0:3::64/128 被分配了一个 fd2e:: 网关,而 2606:a8c0:3:6f::a/64 并没有,说明两者共享同一个网关配置。

我们很容易就能推测出,如果在后台再添加一条新的 IPv6 地址,如 2606:a8c0:3:6f::b/64 ,那么网络配置文件格式就是如下这样:

  1. # control-alias eth0
  2. iface eth0 inet6 static
  3.     address 2606:a8c0:3::64/128
  4.     gateway fd2e::

  5. # control-alias eth0
  6. iface eth0 inet6 static
  7.     address 2606:a8c0:3:6f::a/64

  8. # control-alias eth0
  9. iface eth0 inet6 static
  10.     address 2606:a8c0:3:6f::b/64
复制代码

如果再添加 10 条,20 条,甚至直接把 Crunchbits 后台允许添加的最多 IPv6 地址给添加满呢?我不敢想象,在 Debian 系适用的自动应答文件 preseed.cfg 中的 d-i preseed/late_command 阶段,考虑到 iface eth0 inet6 static, address IPv6 地址/掩码后缀, 另起一行间隔共 3 行,需要添加 50 条 IPv6 地址的时候,那个画面有多绚烂。
 楼主| 发表于 2023-8-11 17:17:27 | 显示全部楼层
本帖最后由 天权璇玑 于 2023-8-11 17:38 编辑

有没有一种更“灵巧且简洁”的方法,给 Debian 系添加多条 IP 规则呢?这个当然可以有!我翻出来今年(2023 年)5 月份,帮一个 MJJ 解决双栈机重装前陷入寻找网络配置文件关键字卡死的问题,该机型是 Virmach 的,后台模板系统为 Debian 10,网络配置详情如下:

  1. iface eth0 inet static
  2.      address 59.67.82.30
  3.      gateway 59.67.82.1
  4.      netmask 255.255.255.0
  5.      dns-nameservers 1.0.0.1 8.8.4.4
  6.      up ip addr add 2a12:a520:d420::736f/48 dev eth0
  7.      up ip addr add 2a12:a520:2e0b::a89c:11de/40 dev eth0
  8.      up ip -6 route add 2a12:a520:2e0b:0000:0000:0000:0000:0001 dev eth0
  9.      up ip -6 route add default via 2a12:a520:2e0b:0000:0000:0000:0000:0001 dev eth0
复制代码

和以上 Crunchbits 后台模板系统的配置相比,我们很容易就能发现两者的异同:

  • 两者 IPv4 部分配置无区别;
  • Virmach 通过多行 up ip addr add IPv6 地址/掩码后缀 dev 网卡设备名,来添加多条 IPv6 地址;
  • Virmach 通过设置 up ip -6 route add IPv6 网关 dev 网卡设备名,和 up ip -6 route add default via IPv6 网关 dev 网卡设备名,来添加 IPv6 网关并将其设置为默认;
  • Virmach 这种方法与配置 IPv6 有关的条目,均从属于 iface eth0 inet static ,不需要单独开辟一个或多个 iface eth0 inet6 static ,来配置 IPv6 地址;
  • Crunchbits 这种配置 IPv6 的方法,多额外添加一条 IPv6 地址,就需要添加 3 行;
  • 我在测试时采用 Virmach 这种方法来给 Crunchbits 配置多条 IPv6 地址,验证有效。

任何人看了以上总结,根本不需要犹豫,用 up ip addr add 添加 IPv6 地址,up ip -6 route add 添加 IPv6 网关的方法完全满足“灵巧且简洁”的条件,就决定是你了!

Debian/Kali 系 preseed 处理多 IPv6 配置研究

Debian preseed late_command 阶段有一点非常倔驴,它只接受用英文冒号“;”隔开的单条命令,而且如果是要用 sed 或 echo 等命令插入多行内容,一次只能插入一条,就和顺序栈一样,如果试图用:

"$a" 代表另起一行,"\t" 代表缩进,用于表示添加的 up ip add 等项目从属于 iface eth0 inet static 等。

  1. sed -i '$a\\t从末尾起第一行文本内容\n\t接续上一行的第二行文本内容' 文件目录;
复制代码

或:

  1. echo -e "第一行文本内容\n接续上一行的第二行文本内容">> 文件目录;
复制代码

比如我们在正式系统中用一句 sed -i 添加多行内容,执行结果毫无问题:



以这种方法写入 preseed:



恭喜你,Debian installer 红色“幸福提示”如约而至:



若要为某文件添加多条项目,以下方式是完全没问题的:

  1. d-i preseed/late_command string sed -i '$a\\t从末尾起第一行文本内容' 文件目录; sed -i '$a\\t接续上一行的第二行文本内容' 文件目录;
复制代码

我在 Debian installer 这个“feature”上吃过不少苦头,添加一条内容,需要一条 sed -i 的方式虽然繁琐,但它是唯一一种有能有效解决需求的方法,总比没有好,我们只能按规矩办事。

解决并验证完一套行之有效的办法,用于在 preseed late_command 添加多条 IPv6、网关的方式后,我们现在将目光聚焦到如何获取原系统中有多少 IPv6 地址,然后如何按一个或多个方式处理方面。

首先是函数“getipv6address”中,把通过 ip -6 addr 查询到的,属于符合的网卡名,且通过 scope global 连接的 IPv6 都列举出来:

  1. allI6Addrs=`ip -6 addr show | grep -wA 65536 "$interface\|$interface6" | grep -wv "lo\|host" | grep -wv "link" | grep -w "inet6" | grep "scope" | grep "global" | awk -F " " '{for (i=2;i<=NF;i++)printf("%s ", $i);print ""}' | awk '{print $1}'`
复制代码

为保持对仅一个 IPv6 配置的双栈机、单 IPv6 栈机的兼容性,保留原“i6Addr”变量且取第一行,新建“i6AddrNum”变量,用于统计总 IPv6 数量:

  1. i6Addr=`echo "$allI6Addrs" | head -n 1`
  2. i6AddrNum=`echo "$allI6Addrs" | wc -l`
复制代码

如果 IPv6 数量大于等于 2,即有多个 IPv6 配置,则新建数组“i6Addrs”,然后再用 for 循环,把遍历出的所有 IPv6 存储到数组中,为什么要放到数组里,这个后面有大用,因为数组自带 index 下标属性。

相应的,IPv6 配置方法自动变为静态:

  1. [[ "$i6AddrNum" -ge "2" ]] && {
  2.     i6Addrs=()
  3.     for tmpIp6 in $allI6Addrs; do
  4.       i6Addrs[${#i6Addrs[@]}]=$tmpIp6
  5.     done
  6.     Network6Config="isStatic"
  7. }
复制代码

拥有数组“i6Addrs”后,我们新建一个函数“writeMultipleIpv6Addresses”,方便在不同地方调用,为 preseed 或 kickstart 写入多 IPv6:

用于生成 preseed 文件中写入多条 IPv6 的函数代码如下:

  1. function writeMultipleIpv6Addresses() {
  2.   [[ "$1" -ge "2" && "$IPStackType" != "IPv6Stack" ]] && {
  3.     if [[ "$linux_relese" == 'debian' ]] || [[ "$linux_relese" == 'kali' ]]; then
  4.       for writeIp6s in ${i6Addrs[@]}; do
  5.         ip6AddrItem="up ip addr add $writeIp6s dev $interface6"
  6.         tmpWriteIp6sCmd+=''$2' sed -i '\''$a\\t'$ip6AddrItem''\'' '$3'; '
  7.       done
  8.       writeIp6sCmd=$(echo $tmpWriteIp6sCmd)
  9.       writeIp6GateCmd=''$2' sed -i '\''$a\\tup ip -6 route add '$ip6Gate' dev '$interface6''\'' '$3'; '$2' sed -i '\''$a\\tup ip -6 route add default via '$ip6Gate' dev '$interface6''\'' '$3';'
  10.       addIpv6DnsForPreseed=''$2' sed -ri '\''s/'$ipDNS'/'$ipDNS' '$ip6DNS'/g'\'' '$3';'
  11.       SupportIPv6orIPv4=''$writeIp6sCmd' '$writeIp6GateCmd' '$addIpv6DnsForPreseed' '$2' sed -i '\''$alabel 2002::/16'\'' /etc/gai.conf; '$2' sed -i '\''$alabel 2001:0::/32'\'' /etc/gai.conf;'
  12.     fi
  13.   }
  14. }
复制代码

该函数接受 3 个来自外部的参数,$1 为"$i6AddrNum",即 IPv6 数量,表示仅在检查到原系统中存在 2 个及以上 IPv6 时才运作;$2 为“in-target”,表示让 Debian installer 以安装后的 Debian 系统为主体,执行命令操作,而非运行在内存中的临时安装环境;$3 为网络配置文件路径,标准的 Debian/Kali 系统,其路径统一为 /etc/network/interfaces 。

if 条件 [[ "$linux_relese" == 'debian' ]] || [[ "$linux_relese" == 'kali' ]] 没什么好说的,表示目标安装系统为 Debian 或 Kali 时才执行。

for 循环新建一个变量“writeIp6s”,遍历数组“${i6Addrs[@]}”,[@] 表示显示数组 i6Addrs 中的所有元素。

变量“ip6AddrItem”,记录了每一次循环时当前的“up ip addr add IPv6 地址/掩码后缀 dev 有 IPv6 访问的网卡设备名”。

变量“tmpWriteIp6sCmd”,用于接受来自变量“ip6AddrItem”的值,并生成适用于 preseed 中,逐条向网络配置文件中写入新条目的 sed 语法,该变量采用自增形式,以从 1 直到所有 IPv6 数量列举结束。每生成一条的标准内容如下:

  1. in-target sed -i '$a\\tup ip addr add 2606:a8c0:3:6f::1a/64 dev enp3s0' /etc/network/interfaces;
复制代码

处理生成 preseed 命令仍然有几个值得注意的地方:

  • “tmpWriteIp6sCmd”变量接受、处理 preseed 用的命令时,最好用单引号括起来,避免使用双引号时各种莫名其妙的转义;
  • 被首尾单引号括起来内部,若要标注单引号,请使用 ''' ,sed -i 添加的内容需要进行强引用,即内部的 $a 等,不能被当做任何变量处理,所以需要用一对单引号括起来;
  • 被首尾单引号括起来内部,想再次使用当前脚本中传递的各种变量,把变量再用一对单引号括起来即可;
  • $a 表示另起一行,\t 表示为该行添加缩进。


生成完成后,由于循环自增特性,“tmpWriteIp6sCmd”末尾还会多出来一个空格,echo 一下就能将其消除,并存储到最终变量 writeIp6sCmd 中。

“writeIp6GateCmd”用于存储让 preseed 为新系统写入 ip -6 route add 以添加 IPv6 网关,其处理难点和“tmpWriteIp6sCmd”相同。

“addIpv6DnsForPreseed”用于将默认以 IPv4 配置的 DNS 服务器替换并添加 IPv6 DNS。

“SupportIPv6orIPv4”负责把添加多条 IPv6 配置、设置 IPv6 网关、设置 IPv6 DNS、设置目标系统中 IPv6 访问优先若干条命令进行融合。

一条一条拆开来剖析,似乎处理起来并没那么难了,是吧(笑

然后回到函数“DebianModifiedPreseed”部分,这个大函数就是我脚本用于给 Debian/Kali 支持各种高阶配置的大本营,其中 elif [[ "$IPStackType" == "BiStack" ]]; then 部分,即处理双栈机支持 IPv6、还原为原系统真实掩码部分的最后,调用函数“writeMultipleIpv6Addresses”:

  1. writeMultipleIpv6Addresses "$i6AddrNum" "$1" '/etc/network/interfaces'
复制代码

这样,双栈网络且有多个 IPv6 地址机型,其写入 IPv6 条目的方法,就和仅有单 IPv6 机型有所不同,函数放在这个位置,也不会影响到原有的写入策略。
 楼主| 发表于 2023-8-11 17:19:07 | 显示全部楼层
本帖最后由 天权璇玑 于 2023-8-11 17:32 编辑

以上目标实现后,我们还需要做一个大胆假设,一个极有可能被忽略的细节:如果机器原环境中,网络配置文件标注的是 IPv4 dhcp ,且 IPv4 部分为不规则配置,且需要添加多条 IPv6 地址的情况下,会存在一个漏洞。即:

安装 Debian 12+/Kali 时,还是会优先采用某条 IPv6 去配置网络,一旦该 IPv6 配置不属于总网段下的第一个,还是会因为配置 IPv6 后无法联网而导致安装失败。

所以,脚本获取完双栈机 IPv4 IPv6 网络配置,还需要添加的代码如下:

  1. if [[ "$IPStackType" == "BiStack" && "$i6AddrNum" -ge "2" ]]; then
  2.   Network4Config="isStatic"
  3.   [[ "$BiStackPreferIpv6Status" == '1' ]] && {
  4.     BiStackPreferIpv6Status=""
  5.     BurnIrregularIpv4Status='1'
  6.   }
  7. fi
复制代码

简单解释一下以上代码作用:

  • 若发现机器是双栈机,且拥有 2 个及以上 IPv6 ,则 IPv4 部分强制使用静态配置;
  • 如果发现机器 IPv4 部分为不规则配置,且需要优先进行 IPv6 来配置网络时("$BiStackPreferIpv6Status" == '1'),IPv6 优先状态标记为空,即不用 IPv6 为网络安装程序做优先的网络配置;
  • 同时,在 preseed 阶段,强制启用 hack 方式来配置 IPv4 网络(BurnIrregularIpv4Status='1'),确保网络服务能在安装环境中得以正常运行,顺利安装。

这么做的目的是因为 Debian 系环境,用 ip add addr 配置 IPv6 策略下,母条目必须依赖于 iface eth0 inet static ,此时目标机型不能存在任何 iface eth0 inet6 ... 条目,否则 sed -i 添加 IPv6 配置条目时,会因配置所属母条目的改变而导致配置失败。

至此,Debian/Kali 部分的双栈网络多 IPv6 重装后写回的技术细节已阐述完成。

红帽系(CentOS/AlmaLinux/RockyLinux/Fedora) kickstart 处理多 IPv6 配置研究

根据我身经百战见得多的经验,Kickstart 的配置比 preseed 易用性要高一些,双栈机同时分别给单个 IPv4 IPv6 配置也不会有问题,从红帽 8+ 起,对不规则 IPv4 部分的处理也非常自如,不需要 preseed 那种软 hack 。

Kickstart 对应 preseed 中 late_command 功能的部分,由 %post %end 包裹,很多正式系统中的高阶命令格式,anaconda 中读取 Kickstart 配置文件也能正常工作。

首先我们来了解一下,Kickstart 配置双栈机的语法格式,对应的值我都做了标注,非常简单易懂:

network --device=网卡名 --bootproto=IPv4 配置方法,static 为静态,dhcp 为动态 --ip=IPv4 地址 --netmask=IPv4 全写格式掩码 --gateway=IPv4 网关 --ipv6=IPv6 地址/掩码后缀 --ipv6gateway=IPv6 网关 --nameserver=DNS服务器 --hostname=主机网络名 --onboot=on

接下来,我把配置 Kickstart 配置多个 IPv6 所遭遇的坑,悉数给大家分享一下,实验目标系统统一为 CentOS 9 stream:

  • 为“--ipv6=”参数添加多个值:

    之所以想到这个办法,是因为我受到了参数“--nameserver=”的启发,“--nameserver=”允许设置多个 DNS 服务器,无论是 IPv4 的还是 IPv6 的,用英文逗号隔开即可,如:

    1. --nameserver=1.0.0.1,8.8.4.4,2606:4700:4700::1001,2001:4860:4860::8844
    复制代码

    同理,给“--ipv6=”添加多个“IPv6 地址/掩码后缀”,用逗号隔开,如下所示,是否可行呢?

    1. --ipv6=2606:a8c0:3::64/128,2606:a8c0:3:6f::a/64,2606:a8c0:3:6f::e/64
    复制代码

    显然不行,照此填入后,anaconda 报错,它不承认这种填写方法:



  • 在同一个“network”条目下,添加多个“--ipv6=”,精简后的配置尝试如下:

    1. network --ipv6=2606:a8c0:3::64/128 --ipv6=2606:a8c0:3:6f::c/64 --ipv6gateway=fd2e::
    复制代码

    显然,这种方法也是不行的,虽然 anaconda 没有报错,但系统最终安装完显示的结果,是仅“2606:a8c0:3:6f::c/64”被得到了配置,这个策略相当于 anaconda 发现有多个 --ipv6 ,但仅仅配置顺序中的最后一个,并不会把每个 --ipv6 都添加到目标系统中。

  • 添加多个“network”条目,每个条目下分别指定不同的 IPv6 地址,网卡名、网关、DNS 等参数每行都给,以下是精简后的案例演示:

    1. network --ipv6=2606:a8c0:3::64/128
    2. network --ipv6=2606:a8c0:3:6f::1d/64
    3. network --ipv6=2606:a8c0:3:6f::c/64
    复制代码

    很遗憾,anaconda 不允许给同一个网卡(接口),如 eth0 等,添加多条 network 配置,虽然后续安装进程仍能继续,但进入新系统,多条 IPv6 配置的目标仍未达成:



  • 受 github cobbler 项目中这个 issues 的启发:https://github.com/cobbler/cobbler/issues/1857 ,该 reporter 提到了一种为单网卡不同接口(eth0:0 eth0:1)添加多个 IPv4 的尝试,发现失败:

    1. network --bootproto=static --ip=192.168.0.58 --netmask=255.255.255.0 --gateway=192.168.1.1 --nameserver=192.168.1.1 --hostname=test.example.com --device=eth0:1 --onboot=on
    2. network --bootproto=static --ip=192.168.1.58 --netmask=255.255.255.0 --gateway=192.168.1.1 --nameserver=192.168.1.1 --hostname=test.example.com --device=eth0:0 --onboot=on
    复制代码

    目前该 issues 已被关闭,我原本以为红帽已解决了这个问题,于是照猫画虎,将多 IPv6 以以下方式加入 Kickstart,格式仍然是精简过的:

    1. network --device=eth0:0 --ipv6=2606:a8c0:3::64/128
    2. network --device=eth0:1 --ipv6=2606:a8c0:3:6f::c/64
    3. network --device=eth0:2 --ipv6=2606:a8c0:3:6f::1d/64
    复制代码

    又是一次令人失望的尝试,虽然这次 anaconda 不会再报错,但新安装系统中仅发现一条 IPv6 被配置了,预期目标仍未实现。

通过实验,我们可以大致得出结论:

  • Kickstart 仅接受同一网卡,用单条“network”条目,接受一个 IPv4 和一个 IPv6 参数,不支持为单网卡,原生添加多条 IPv4 IPv6 地址;
  • 对于不同网卡,配置了不同的 IPv4 或 IPv6 的情况,Kickstart 是可以处理的,添加多条“network”条目,分别配置即可。

我想,能读到这里的人,既有充足的耐心、强大的好奇心,也已经感到十分疲惫,更何况在测试时承受各种气馁的我。

一次又一次的失败是否会令人绝望?如果轻易认输,就此放弃,不再抱有极致的追求,我和我的脚本也不会拥有如此良好的泛用性,很多人总是说用 VNC 改,挂载 iso 就好了啊,但我觉得这不是力图解决问题的态度。

如果总是预设在理想状态下如何如何,而不去考虑最极端的情况,依赖于手改,那么我们离追求自动化、易用的目标就会渐行渐远,直到所有人又面临着“新三年,旧三年,缝缝补补又三年”的情况。

既然写入多条 IPv6 在 Debian 安装后期可以逐条写入,那为什么不指定 Kickstart 在 %post %end 阶段也这样做呢?

说干就干,即使考虑用这种方式解决,我仍然遭遇了以下几点失败,如果你继续愿意读下去,真的辛苦了。
 楼主| 发表于 2023-8-11 17:20:56 | 显示全部楼层
本帖最后由 天权璇玑 于 2023-8-11 17:35 编辑

若非展示完整代码,以下案例各语句,仍然是只体现我们尝试、排错思维的精简格式。

我只测试了红帽 9+ 的 NetworkManager 格式网络配置文件的操作,红帽 8 及之前 ip up down 格式文件的多 IPv6 写入操作不再考虑支持。

首先我们需要搞清楚,NetworkManager 配置有效的,多条 IPv6 的标准格式应该是什么:

  1. [ipv6]
  2. addr-gen-mode=eui64
  3. address1=2606:a8c0:3:6f::b/64,fd2e::
  4. address2=2606:a8c0:3:6f::c/64,fd2e::
  5. address3=2606:a8c0:3:6f::/64,fd2e::
  6. dns=2606:4700:4700::1001;2001:4860:4860::8844;
  7. method=manual
复制代码

只有以标准格式为目标,尝试去修改并达成,我们才能在 Kickstart post end 阶段,探索出适合的写入策略。

可以看到,NetworkManager 的 IPv6 配置特征如下:

  • 多个 IPv6 地址,用“address序号”隔开,每个条目对应着 IPv6 地址/掩码后缀“英文逗号,”网关;
  • 多个 IPv6 dns 用英文分号隔开,最后一位必须要跟上一个英文分号;
  • method 对应的 manual 和 auto ,分别对应着是以静态还是以动态配置网络。

于是,我尝试的写入过程如下:

1. “network”部分,仅配置 IPv4 网络,指定“--noipv6”,不配置 IPv6,后续阶段刷入多 IPv6 配置。

  1. network IPv4 静态或动态配置 --noipv6
复制代码

系统安装完成后,观察到系统网络配置文件 /etc/NetworkManager/system-connections/eth0.nmconnection 中,IPv6 部分详情如下:

  1. [ipv6]
  2. addr-gen-mode=eui64
  3. method=disabled
复制代码

method 为 disabled ,显然 IPv6 的配置被禁用了,这个值不会使系统中的 IPv6 模块被彻底禁用,与在内核中添加“ipv6.disable=1”参数,禁止内核加载 IPv6 的作用不同。如果把 method 改为 auto 或 manual,并给出正确的 IPv6 配置,IPv6 网络仍能正常工作。

“addr-gen-mode=eui64”部分是 [ipv6] 项目下特有的,[ipv4] 部分无此条目,所以有一套可行的思路如下:

  • 在“addr-gen-mode=eui64”条目下方,追加多行 IPv6 配置;
  • 把“method=disabled”改为“method=manual”。

由于系统安装时是优先以 IPv4 配置的,所以 IPv4 部分要么是“method=auto”,要么是“method=manual”,以“method=disabled”为关键字替换,不会干扰到 IPv4 的正常配置。于是,post end 部分的代码如下:

Kickstart 中指定的系统安装完成,重启前的后续阶段写入条目:

  1. %post
  2. sed -ri 's/method=disabled/method=manual/g' 网络配置文件
  3. sed -i '/addr-gen-mode=eui64/a\address1=第一条 IPv6/掩码后缀,网关\naddress2=第二条 IPv6/掩码后缀,网关\ndns=第一个 IPv6 DNS;第二个 IPv6 DNS;' 网络配置文件
  4. %end
复制代码

安装过程看起来很顺利,结果重启后连用本地宽带 IPv4 访问 ssh 也无法连接了,真的很令人扫兴,只能先进 VNC 里,看看网络配置如何:

  1. [ipv6]
  2. addr-gen-mode=eui64
  3. address1=2603:c020:a:6aa4:a787:6d4:3e72:4902/64,fe80::200:17ff:fe80:551d
  4. method=disabled
  5. method=ignore
复制代码

好家伙,[ipv6] 下额外添加了一条“method=ignore”,导致 IPv4 IPv6 双网挂掉的罪魁祸首或许就是它吧。因为我们在 Kickstart 阶段指定的是不配置 IPv6 网络,然后在安装完成阶段,又写入了一套 IPv6 静态配置,系统启动时,会发现两者产生冲突,于是将 IPv6 部分的配置方法标记成了“ignore”,然后使 IPv4 和 IPv6 所有部分的网络都不工作。

除非有一种手段,可以使 anaconda 在配置完系统后重启后,在新登录系统时,把“method=ignore”删除,这样才能使系统中所有网络都能工作,但仅修改网络配置文件是不行的,还要涉及给系统登陆时设置一个脚本,消除“method=ignore”,但此时系统网络还是不通的,还要让系统再重启一次。

这个路线显然是错误的。

2. 在“network”语句中,先配置一个 --ipv6 条目,然后把其余 IPv6 条目在后续阶段写进去。

这个主意也不咋地,代码也不放了,因为这样做又大大加深了复杂度,虽然我们通过用数组存储所有“IPv6 地址/掩码后缀”,将下标 0 (数组中的第一个元素)设置为在“network”中配置,然后把下标 1 及最后的元素在安装后续添加,但我们不能保证,被添加进去的那条 IPv6 是不依赖于母段就能独立运行的,比如:

  • 添加的正好是 2606:a8c0:3:6f::/128 ,anaconda 环境中 IPv6 就能工作;
  • 如果添加的是 2606:a8c0:3:6f::11/64 ,由于 2606:a8c0:3:6f::/128 还未到后续阶段被写入,anaconda 环境中 IPv6 不能工作;
  • 经过实测发现,CentOS 9 stream 的 anaconda 环境中,如果同时接受了 IPv4 和 IPv6 参数,会对双网进行网络检查,并优先使用 IPv6 连接镜像源;
  • 如果添加的是 2606:a8c0:3:6f::11/64 ,系统就会卡在网络检查环节很久,并导致以 IPv6 连接镜像源失败。

继续死磕,没什么大不了的,如果总是害怕失败,我不会走到今天。

3. network 语句给 IPv4 静态配置,不标记任何配置 IPv6 的参数,也不关闭 IPv6 配置,后续阶段刷入所有 IPv6 配置。
令人振奋的是,这次我们终于找对路了!
Kickstart 中,network 语句如果只配置 IPv4 部分,不输入任何有关配置 IPv6 的参数,重装后的系统中,NetworkManager 针对 IPv6 部分仍然会给一个默认的动态配置,内容如下:

  1. [ipv6]
  2. addr-gen-mode=eui64
  3. method=auto
复制代码

由于该节开始,我就强调了“只配置 IPv4 部分”,隐含的意义就是无论原机器的 IPv4 部分是 dhcp 还是 static ,在新安装的系统中,我们都将 IPv4 部分按静态配置,那么 NetworkManager 中,一定会存在以下条目,且来仅来自 IPv4 部分:

  1. method=manual
复制代码

此时 IPv6 部分仍然为“method=auto”,而 IPv4 部分统一变成了“method=manual”,有这两条区分,就可以确保后续阶段刷入 IPv6,并改变其配置方法的时候,这种改动对 IPv4 部分不会造成任何影响。因为我们需要设置的替换起始关键词是“method=auto”,而此时 IPv4 部分永远是“method=manual”。

为了方便大家理解,我先以程序执行流程的顺序来讲解,首先是脚本内处理 “双栈机,且有多个 IPv6” ,生成 Kickstart 前,需要写入哪种“network”语句的情况:

  1. [[ "$i6AddrNum" -ge "2" ]] && NetConfigManually="network --device=$interface --bootproto=static --ip=$IPv4 --netmask=$actualIp4Subnet --gateway=$GATE --nameserver=$ipDNS --hostname=$(hostname) --onboot=on"
复制代码

"$i6AddrNum" -ge "2" 很好理解,发现本机拥有大于等于两个 IPv6 再进行的操作,这个判断式隶属于母条件式“elif [[ "$IPStackType" == "BiStack" ]]; then”下,即仅在双栈机,多 IPv6 环境下再进行处理,不用担心其会影响到仅 IPv6 栈服务器。

“NetConfigManually=” 对应的变量也很好懂,里面仅包含了令 anaconda 配置 IPv4 ,不包含任何配置 IPv6 的语句,这样做可以有效避免以上所述中,anaconda 由于接受了一个非母 IPv6 段,IPv6 并不能正常工作,导致连接源失败的情况。

以本实验机型为例,最终脚本为生成 Kickstart “network”语句的完整内容如下:

  1. network --device=eth0 --bootproto=static --ip=104.36.84.237 --netmask=255.255.255.255 --gateway=104.36.84.1 --nameserver=1.0.0.1,8.8.4.4 --hostname=237 --onboot=on
复制代码

下面真正的骚操作才正式开始。

还记得刚才那个“writeMultipleIpv6Addresses”函数,“if [[ "$linux_relese" == 'debian' ]] || [[ "$linux_relese" == 'kali' ]]; then”是给 Debian 和 Kali 配置的,elif [[ "$linux_relese" == 'centos' ]] || [[ "$linux_relese" == 'rockylinux' ]] || [[ "$linux_relese" == 'almalinux' ]] || [[ "$linux_relese" == 'fedora' ]]; then 就是给红帽全系配置的,条件式内运行的代码如下:

  1. for (( tmpI6Index=0; tmpI6Index<"$1"; tmpI6Index++ )); do
  2.   writeIp6s="${i6Addrs[$tmpI6Index]}"
  3.   ipv6AddressOrder=$(expr $tmpI6Index + 1)
  4.   ip6AddrItem+='address'$ipv6AddressOrder'='$writeIp6s','$ip6Gate'\n'
  5. done
  6.   ip6AddrItems=''$ip6AddrItem''
  7.   addIpv6DnsForRedhat='dns='$ip6DNS1';'$ip6DNS2';'
  8.   addIpv6AddrsForRedhat='sed -i '\''/addr-gen-mode=eui64/a\'$ip6AddrItems''$addIpv6DnsForRedhat''\'' '$3''
  9.   setIpv6ConfigMethodForRedhat='sed -ri '\''s/method=auto/method=manual/g'\'' '$3''
复制代码

红帽系 Kickstart 由于不需要 Debian 系 preseed 中 "in-target" 那样的设定,所以接受的参数中不需要带 "$2" ,调用需要留空,后面会讲。

"$1" 参数对应的值为“$i6AddrNum”,即机器中所有 IPv6 数量,这个参数用于判断机器中有 2 个以上 IPv6 时该怎么做,不影响以上子判断式中的代码运行。
 楼主| 发表于 2023-8-11 17:22:05 | 显示全部楼层
本帖最后由 天权璇玑 于 2023-8-11 17:37 编辑

唯一需要关注的参数是 "$3",它的定义是接受目标系统中网络配置文件目录,对于红帽 9+ 的 NetworkManager,其文件名为:/etc/NetworkManager/system-connections/网卡名.nmconnection ,如:

  1. /etc/NetworkManager/system-connections/eth0.nmconnection
复制代码

  • 函数从存储所有 IPv6 地址的数组,$tmpI6Index 中开始遍历,起始值为 0 ,以适应数组下标对应元素的规则;
  • ipv6AddressOrder 对应目标网络配置文件中,“address数字序列=”,由于 NetworkManager 配置文件中,“address数字序列=”是从 1 开始的,如:address1= address2= 等等。所以从数组下标 0 开始的序列,要做一个 + 1 的运算;
  • “addIpv6DnsForRedhat”存储配置 IPv6 部分的 DNS,它的值会根据机器在中国大陆境外或境内,给出“addIpv6DnsForRedhat='dns=2606:4700:4700::1001;2001:4860:4860::8844;'”或“addIpv6DnsForRedhat='dns=2402:4e00::;2400:3200::1'”两个不同值;
  • “addIpv6AddrsForRedhat”负责将“[ipv6]”条目下“addr-gen-mode=eui64”部分的下面若干行,添加“address数字序列=”等多个 IPv6 配置;
  • “setIpv6ConfigMethodForRedhat”部分,负责将“[ipv6]”的配置方法,从动态改为静态。

系统安装好后 IPv6 部分默认配置如下:

  1. [ipv6]
  2. addr-gen-mode=eui64
  3. method=auto
复制代码

经过以上功能在 anaconda 在系统安装好后续阶段,即 %post %end 中修改后,IPv6 部分配置如下:

  1. [ipv6]
  2. addr-gen-mode=eui64
  3. address1=2606:a8c0:3::64/128,fd2e::
  4. address2=2606:a8c0:3:6f::a/64,fd2e::
  5. address3=2606:a8c0:3:6f::b/64,fd2e::
  6. address4=2606:a8c0:3:6f::c/64,fd2e::
  7. address5=2606:a8c0:3:6f::d/64,fd2e::
  8. address6=2606:a8c0:3:6f::e/64,fd2e::
  9. address7=2606:a8c0:3:6f::f/64,fd2e::
  10. address8=2606:a8c0:3:6f::10/64,fd2e::
  11. address9=2606:a8c0:3:6f::11/64,fd2e::
  12. address10=2606:a8c0:3:6f::12/64,fd2e::
  13. address11=2606:a8c0:3:6f::13/64,fd2e::
  14. address12=2606:a8c0:3:6f::14/64,fd2e::
  15. address13=2606:a8c0:3:6f::15/64,fd2e::
  16. address14=2606:a8c0:3:6f::16/64,fd2e::
  17. address15=2606:a8c0:3:6f::17/64,fd2e::
  18. address51=2606:a8c0:3:6f::3b/64,fd2e::
  19. dns=2606:4700:4700::1001;2001:4860:4860::8844;
  20. method=manual
复制代码

经过实测,红帽 9+ 新安装系统中,原系统附带的多个 IPv6 地址均已顺利添加到新系统网络配置文件中,折腾终于圆满成功。

后记

Debian 12 preseed late_command 中添加多条 IPv6 语句如下:



Debian 12 重装完成后网络配置文件中写入的多条 IPv6 配置:





Kali rolling preseed late_command 中添加多条 IPv6 语句如下:



Kali rolling 重装完成后网络配置文件中写入的多条 IPv6 配置:





CentOS 9 stream Kickstart network 语句中添加单 IPv4 静态语句如下:



CentOS 9 stream Kickstart 后续执行自定义命令时 %post %end 中为 NetworkManager 配置文件添加多条 IPv6 语句如下:



CentOS 9 stream 重装完成后网络配置文件中写入的多条 IPv6 配置:



 楼主| 发表于 2023-8-11 17:40:22 | 显示全部楼层
排版问题解决了,现在格式不乱了,也没有多余空行
发表于 2023-8-11 18:19:54 来自手机 | 显示全部楼层
重装周伯通
发表于 2023-8-11 19:09:58 来自手机 | 显示全部楼层
干货支持,楼主用心了
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|全球主机交流论坛

GMT+8, 2024-4-28 05:33 , Processed in 0.071473 second(s), 11 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表