首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >解释linux shell netmask2cdir和cdir2netmask中cidr到网络掩码的转换

解释linux shell netmask2cdir和cdir2netmask中cidr到网络掩码的转换
EN

Stack Overflow用户
提问于 2013-12-24 22:28:16
回答 1查看 16.4K关注 0票数 21

我从这个topic中找到了以下外壳函数

代码语言:javascript
复制
mask2cdr ()
{
   # Assumes there's no "255." after a non-255 byte in the mask
   local x=${1##*255.}
   set -- 0^^^128^192^224^240^248^252^254^ $(( (${#1} - ${#x})*2 )) ${x%%.*}
   x=${1%%$3*}
   echo $(( $2 + (${#x}/4) ))
}


cdr2mask ()
{
   # Number of args to shift, 255..255, first non-255 byte, zeroes
   set -- $(( 5 - ($1 / 8) )) 255 255 255 255 $(( (255 << (8 - ($1 % 8))) & 255 )) 0 0 0
   [ $1 -gt 1 ] && shift $1 || shift
   echo ${1-0}.${2-0}.${3-0}.${4-0}
}

您能否详细解释这些函数如何将cidr转换为网络掩码,并将网络掩码转换为cidr?具体地说,对set、参数扩展${#…}和算术扩展$((…))的调用非常繁重。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-12-25 06:29:58

mask2cdr()

要从以点为十进制的网络掩码中获取CIDR前缀,请执行以下操作:

代码语言:javascript
复制
255.255.192.0

首先必须将四个二进制八位数转换为二进制,然后计算最高有效位(即前导一的数量):

代码语言:javascript
复制
11111111.11111111.11000000.00000000  # 18 ones = /18 in CIDR

这个函数相当有创意地做到了这一点。首先,我们去掉所有前导的255八位字节(即二进制中全部为1的八位字节),并将结果存储在变量x

代码语言:javascript
复制
local x=${1##*255.}

这一步使用了parameter expansion,整个脚本都非常依赖它。如果我们继续使用255.255.192.0的示例网络掩码,我们现在有以下值:

代码语言:javascript
复制
$1: 255.255.192.0
$x: 192.0

接下来,我们设置三个变量:$1$2$3。这些变量称为positional parameters;它们非常类似于普通的命名变量,但通常是在将参数传递给脚本或函数时设置的。我们可以直接使用set --设置这些值,例如:

代码语言:javascript
复制
set -- foo bar  # $1 = foo, $2 = bar

我更喜欢使用命名变量而不是位置参数,因为它使脚本更容易阅读和调试,但最终结果是相同的。我们将$1设置为:

代码语言:javascript
复制
0^^^128^192^224^240^248^252^254^

这实际上只是一个表,用于将特定的十进制值转换为二进制值,并计算1位数。我们稍后再来讨论这个问题。

我们将$2设置为

代码语言:javascript
复制
$(( (${#1} - ${#x})*2 ))

这称为Arithmetic Expansion。它看起来很复杂,但它实际上只是计算我们在第一个命令中剥离的1位的数量。它分解为以下内容:

代码语言:javascript
复制
(number of chars in $1 - number of chars in $x) * 2

在我们的例子中,计算结果是

代码语言:javascript
复制
(13 - 5) * 2 = 16

我们去掉了两个二进制八位数所以我们得到16个。有道理。

我们将$3设置为:

代码语言:javascript
复制
${x%%.*}

这是剔除第一个.之后的$x的值。在我们的示例中,这是192

我们需要将这个数字转换为二进制,并计算其中的1位的数量,所以让我们回到“转换表”。我们可以将表格分成相等的块,每个块有四个字符:

代码语言:javascript
复制
0^^^  128^  192^  224^  240^  248^  252^  254^

以二进制表示,上面的数字是:

代码语言:javascript
复制
00000000 10000000 11000000 11100000 11110000 11111000 11111100 11111110
# 0 ones 1 one    2 ones   3 ones   ...

如果我们从左开始计数,表中的每个四字符块都对应于一个额外的二进制1位。我们正在尝试转换192,所以让我们首先删除表的最右边部分,从192开始,并将其存储在x

代码语言:javascript
复制
x=${1%%$3*}

$x的值现在是

代码语言:javascript
复制
0^^^128^

它包含两个四字符块或两个二进制1位。

现在我们只需要将前导的1位(总共16位,存储在变量$2中)和上一步的1位(总共2位)相加:

代码语言:javascript
复制
echo $(( $2 + (${#x}/4) ))

哪里

代码语言:javascript
复制
${#x}/4

$x中的字符数除以4,即$x中四字符块的数量。

输出:

代码语言:javascript
复制
18

cdr2mask()

让我们继续运行前面的示例,该示例的CIDR前缀为18

我们使用set --来设置位置参数$1到$9:

代码语言:javascript
复制
$1: $(( 5 - ($1 / 8) ))  # 5 - (18 / 8) = 3 [integer math]
$2: 255
$3: 255
$4: 255
$5: 255
$6: $(( (255 << (8 - ($1 % 8))) & 255 ))  # (255 << (8 - (18 % 8))) & 255 = 192
$7: 0
$8: 0
$9: 0

让我们研究一下用于将$1$6设置得更接近的公式。$1设置为:

代码语言:javascript
复制
$(( 5 - ($1 / 8) ))

对于网络掩码,CIDR前缀的最大和最小可能值为32

代码语言:javascript
复制
11111111.11111111.11111111.11111111

网络掩码为0

代码语言:javascript
复制
00000000.00000000.00000000.00000000

以上公式使用整数除法,因此可能的结果范围为1到5:

代码语言:javascript
复制
5 - (32 / 8) = 1
5 - ( 0 / 8) = 5

$6设置为:

代码语言:javascript
复制
$(( (255 << (8 - ($1 % 8))) & 255 ))

让我们以CIDR前缀18为例来分析这一点。首先,我们取模数并做一些减法:

代码语言:javascript
复制
8 - (18 % 8) = 6

接下来,我们将按以下值按位移位255:

代码语言:javascript
复制
255 << 6

这与将6个0位推入二进制255的末尾相同:

代码语言:javascript
复制
11111111000000

最后,我们将此值与255进行逐位AND:

代码语言:javascript
复制
11111111000000 &
00000011111111  # 255

这给了我们

代码语言:javascript
复制
00000011000000

或者简单地说

代码语言:javascript
复制
11000000

看起来眼熟吗?这是我们的网络掩码中的第三个二进制八位数:

代码语言:javascript
复制
11111111.11111111.11000000.00000000
                  ^------^

以十进制表示,该值为192。

接下来,我们根据$1的值移动位置参数

代码语言:javascript
复制
[ $1 -gt 1 ] && shift $1 || shift

在我们的示例中,$1的值为3,因此我们将位置参数3向左移动。先前的$4值变为$1的新值,先前的$5值变为$2的值,依此类推:

代码语言:javascript
复制
$1: 255
$2: 255
$3: 192
$4: 0
$5: 0
$6: 0

这些值看起来应该很熟悉:它们是网络掩码中的十进制八位数(末尾附加了几个额外的零)。要获得网络掩码,我们只需打印出前四个中间带点的内容:

代码语言:javascript
复制
echo ${1-0}.${2-0}.${3-0}.${4-0}

每个参数后面的-0表示,如果未设置该参数,则使用0作为默认值。

输出:

代码语言:javascript
复制
255.255.192.0
票数 36
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20762575

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档