全球主机交流论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

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

写算法是真耗脑子

[复制链接]
发表于 2023-5-17 21:22:49 | 显示全部楼层 |阅读模式
Louis.M.LX 弄机器,他买了个 akile.io 家的小鸡,纯 IPv6,无 IPv4 地址,而且 IPv6 是手动配置的,之前一键重装脚本代码里对纯 IPv6 静态的适配不太好,改了一下判断逻辑,把从系统里读取到的 IPv6,掩码,网关,和默认指定的 DNS 传过去就行了。



结果 Debian 安装程序读取了配置不成功,又爆红框,于是我开始查看填写的信息是哪出了问题。





分析 preseed.cfg 里的内容,我判断问题可能出在掩码上,Linux 里 IPv6 的掩码作为后缀,附加在 IPv6 地址后面,是 0-128 位的纯数字,我就是给的脚本里获取的这个后缀值,然后传递到 preseed 配置 IPv6 网关里,然后又看了一下 Debian 官方给的配置文件案例,看看填写格式是不是有问题。

https://www.debian.org/releases/stable/i386/apbs04.en.html

好家伙,官方给的配置案例里,IPv6 掩码是从后缀转换成的纯 IPv6 地址,而且它应该是不认那种纯数字后缀简写,报错的原因找到了,下面就是搞一种方式,能把转换完成。



找了半天,全网竟然没有一个用 shell 写的,能把 IPv6 0-128 位掩码转换成对应位数,算出对应的地址范围,然后取范围内首个 IPv6 地址,作为输入的掩码的工具,没办法,只好我自己写了。

计算原理还好比较简单,一个完整的 IPv6 地址一共有 32 个数,其中每个数都是 16 进制,0 1 2 3 4 5 6 7 8 9 a b c d e f,如果是满的 128 位,对应的掩码就是 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff,说明该范围内只有一个计算机能获得 IPv6 地址,每减少一位,范围扩大 2 倍,直到 2 的 128 次方,对应的范围里最小数就要往前挪相应的位数,以下是一个简单演示,到接近 0 的时候,由于包含的地址太多,所以仅展示对应范围里的第一个 IPv6 掩码:

  1. 128:
  2. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF

  3. 127:
  4. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFE
  5. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF

  6. 126:
  7. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFC
  8. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFD
  9. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFE
  10. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF

  11. 125:
  12. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFF8
  13. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFF9
  14. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFA
  15. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFB
  16. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFC
  17. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFD
  18. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFE
  19. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF

  20. 124:
  21. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFF0
  22. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFF1
  23. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFF2
  24. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFF3
  25. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFF4
  26. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFF5
  27. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFF6
  28. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFF7
  29. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFF8
  30. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFF9
  31. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFA
  32. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFB
  33. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFC
  34. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFD
  35. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFE
  36. FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF

  37. ...........

  38. 4:
  39. F000:0000:0000:0000:0000:0000:0000:0000

  40. 3:
  41. E000:0000:0000:0000:0000:0000:0000:0000

  42. 2:
  43. C000:0000:0000:0000:0000:0000:0000:0000

  44. 1:
  45. 8000:0000:0000:0000:0000:0000:0000:0000

  46. 0:
  47. 0000:0000:0000:0000:0000:0000:0000:0000
复制代码


计算方法就是先用后缀与 4 相除,余数为 0,即正好除完,后缀就是 0,128 位后缀除外,余数为 1,后缀是 8,同理,余数 2,后缀 c,余数 3,后缀 e。

掩码计算简单的地方就是原后缀被 4 整除的结果,即 f 出现的次数。用循环把 f 都列出来。

然后把以上算出的,对应  0 8 c e IPv6 后缀,直接拼在 f 后面即可。

除了 f 和拼接的 0 8 c e,剩下的值就全用 0 填充即可,需要填多少个 0 呢?用 32 减原后缀除 4 获得的整数部分即可。

最后得出来的纯字符不带冒号分割的 IPv6 地址如果超过 32 位,把多填充的最后一位 0 去掉即可。

然后把这段字符每 4 个隔开,然后用冒号填充,当然最后一个冒号也是要去掉的。

以下是实现代码:



随机输入一个结果,跟网站计算器里的结果交叉验证,结果相符。













如果说给一个死值,比如就 128 对应的 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff,或 64 对应的 ffff:ffff:ffff:ffff:0000:0000:0000:0000,好不好?当然好,给个死值不用费劲巴拉地算,也不用费这么多脑子去想算法,但我觉得不应该止步于此,如果实际环境中出现了别的后缀呢?96 位?84 位?如果给不对,网络配置不成功怎么办?人还是应该有点追求的。

计算 IPv6 是真的烦,求求以后别再出个 IPv8 了,但愿。
发表于 2023-5-17 23:12:12 | 显示全部楼层
你管这叫算法?
发表于 2023-5-17 23:50:20 | 显示全部楼层
本帖最后由 C₆H₁₂O₆ 于 2023-5-17 23:52 编辑

还能更短

  1. #!/bin/bash

  2. # 获取用户输入的数字
  3. read -p "请输入一个数字(0-128): " bits

  4. # 验证输入是否在有效范围内
  5. if (( bits < 0 || bits > 128 )); then
  6.   echo "输入无效,请输入一个介于 0 到 128 之间的数字。"
  7.   exit 1
  8. fi

  9. # 生成IPv6子网掩码
  10. mask=()
  11. for (( i=0; i<8; i++ )); do
  12.   if (( i < bits/16 )); then
  13.     mask+=('FFFF')
  14.   elif (( i == bits/16 )); then
  15.     mask+=($(printf '%04X' $((0xFFFF<<(16-bits%16)&0xFFFF))))
  16.   else
  17.     mask+=('0000')
  18.   fi
  19. done

  20. # 输出子网掩码
  21. echo "IPv6 子网掩码为: ${mask[*]/%/::}"

复制代码
发表于 2023-5-17 21:47:44 | 显示全部楼层
天权璇玑 发表于 2023-5-17 21:34
不需要,ipv6 掩码计算原理还是比较简单的,我只要保证算出来的结果和网站计算器一样就行 ...
  1. #!/bin/bash

  2. # 获取用户输入的数字
  3. read -p "请输入一个数字(0-128): " number

  4. # 验证输入是否在有效范围内
  5. if (( number < 0 || number > 128 )); then
  6.   echo "输入无效,请输入一个介于 0 到 128 之间的数字。"
  7.   exit 1
  8. fi

  9. # 将输入的数字转换为二进制字符串
  10. binary=""
  11. for (( i=0; i<number; i++ )); do
  12.   binary+="1"
  13. done
  14. for (( i=number; i<128; i++ )); do
  15.   binary+="0"
  16. done

  17. # 将二进制字符串转换为 IPv6 子网掩码
  18. subnet=""
  19. for (( i=0; i<128; i+=16 )); do
  20.   hex=$(printf "%04X" $((2#${binary:i:16})))
  21.   subnet+="$hex:"
  22. done

  23. # 去除末尾的冒号并输出结果
  24. subnet=${subnet%:}
  25. echo "IPv6 子网掩码为 ${subnet}"
复制代码
发表于 2023-5-18 09:07:16 来自手机 | 显示全部楼层
点进来还以为是啥吐槽二叉树或者排序之类的,emmmm,这个也可以称为算法没毛病。只是这个算法过于简单
发表于 2023-5-18 10:06:31 | 显示全部楼层
搞这种 脱裤子放屁

直接内存系统DD官方镜像不香嘛

发表于 2023-5-18 00:16:11 | 显示全部楼层
本帖最后由 tows3 于 2023-5-18 00:17 编辑


问了下new bing ,简化的代码

  1. #!/bin/bash

  2. read -p "请输入一个数字(0-128): " n
  3. (( n < 0 || n > 128 )) && echo "输入无效,请输入一个介于 0 到 128 之间的数字。" && exit 1
  4. subnet=$(printf "%032x" $((2**n-1)) | sed 's/.\{4\}/&:/g;s/:$//')
  5. echo "IPv6 子网掩码为 ${subnet}"
复制代码

发表于 2023-5-17 23:55:57 | 显示全部楼层
为什么不是抄一个python或者其他语言写的然后用shell调用python
发表于 2023-5-17 21:33:17 | 显示全部楼层
这难道不应该用位运算?
 楼主| 发表于 2023-5-17 21:34:33 | 显示全部楼层
无神通 发表于 2023-5-17 21:33
这难道不应该用位运算?

不需要,ipv6 掩码计算原理还是比较简单的,我只要保证算出来的结果和网站计算器一样就行
发表于 2023-5-17 21:43:14 来自手机 | 显示全部楼层
,我写过python 和php的。好像没这么复杂吧!
发表于 2023-5-17 22:07:22 | 显示全部楼层
泰库辣 IPv8 pro plus max 在等你哦
发表于 2023-5-17 22:10:22 | 显示全部楼层
记得这个有公式直接 128减去前缀长度
发表于 2023-5-17 22:11:20 | 显示全部楼层
一直觉得shell脚本写的牛逼的都是大佬
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2025-9-15 07:33 , Processed in 0.066629 second(s), 11 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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