これから次のシェル関数が見つかりました topic
_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
、パラメーター展開_${#…}
_、および算術展開$((…))
の呼び出しは非常に圧倒的です。
このようなドット10進ネットマスクからCIDRプレフィックスを取得するには、次のようにします。
255.255.192.0
最初に4つのオクテットをバイナリに変換してから、最上位ビット(つまり、先頭のビットの数)をカウントする必要があります。
11111111.11111111.11000000.00000000 # 18 ones = /18 in CIDR
この関数はそれをかなり創造的に行います。まず、先頭の255
オクテット(つまり、すべてバイナリのオクテット)をすべて取り除き、結果を変数x
に格納します。
local x=${1##*255.}
このステップでは、 パラメーター展開 を使用します。これは、スクリプト全体がかなり大きく依存しています。 255.255.192.0
のネットマスクの例を続けると、次の値になります。
$1: 255.255.192.0
$x: 192.0
次に、$1
、$2
、および$3
の3つの変数を設定します。これらは 位置パラメータ と呼ばれます。これらは通常の名前付き変数によく似ていますが、通常、スクリプトまたは関数に引数を渡すときに設定されます。 set --
を使用して、値を直接設定できます。次に例を示します。
set -- foo bar # $1 = foo, $2 = bar
スクリプトの読み取りとデバッグが容易になるため、位置パラメーターよりも名前付き変数を使用する方が好きですが、最終的な結果は同じです。 $1
を次のように設定します。
0^^^128^192^224^240^248^252^254^
これは実際には、特定の10進値を2進数に変換し、1
ビットの数をカウントするための単なるテーブルです。後でこれに戻ります。
$2
をに設定します
$(( (${#1} - ${#x})*2 ))
これは 算術展開 と呼ばれます。複雑に見えますが、実際には、最初のコマンドで削除した1
ビットの数を数えているだけです。それはこれに分解されます:
(number of chars in $1 - number of chars in $x) * 2
私たちの場合、これは
(13 - 5) * 2 = 16
2つのオクテットを取り除いたので、16になります。理にかなっています。
$3
を次のように設定します。
${x%%.*}
これは、最初の$x
以降のすべてが削除された.
の値です。私たちの場合、これは192
です。
この数値を2進数に変換し、その中の1
ビットの数を数える必要があるので、「変換テーブル」に戻りましょう。テーブルをそれぞれ4文字の等しいチャンクに分割できます。
0^^^ 128^ 192^ 224^ 240^ 248^ 252^ 254^
バイナリでは、上記の数値は次のとおりです。
00000000 10000000 11000000 11100000 11110000 11111000 11111100 11111110
# 0 ones 1 one 2 ones 3 ones ...
左から数えると、テーブル内の4文字の各ブロックは、バイナリの追加の1
ビットに対応します。 192
を変換しようとしているので、最初に192
からテーブルの右端の部分を切り取り、x
に格納します。
x=${1%%$3*}
$x
の値は現在
0^^^128^
これには、2つの4文字ブロック、またはバイナリの2つの1
ビットが含まれます。
ここで、先頭の1
オクテットの255
ビット(合計16、変数$2
に格納)と前のステップの1
ビットを合計する必要があります(2合計):
echo $(( $2 + (${#x}/4) ))
どこ
${#x}/4
は、$x
の文字数を4で割った数、つまり$x
の4文字のブロック数です。
18
18
のCIDRプレフィックスを持つ前の例で実行を続けましょう。
set --
を使用して、位置パラメータ$ 1から$ 9を設定します。
$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
は次のように設定されます。
$(( 5 - ($1 / 8) ))
CIDRプレフィックスの可能な最大値と最小値は、ネットマスクの場合32です。
11111111.11111111.11111111.11111111
ネットマスクの場合は0
00000000.00000000.00000000.00000000
上記の式は整数除算を使用しているため、可能な結果は1から5の範囲です。
5 - (32 / 8) = 1
5 - ( 0 / 8) = 5
$6
は次のように設定されます。
$(( (255 << (8 - ($1 % 8))) & 255 ))
18
のCIDRプレフィックスの例でこれを分解してみましょう。まず、モジュラスを取り、いくつかの減算を行います。
8 - (18 % 8) = 6
次に、255をこの値だけビット単位でシフトします。
255 << 6
これは、6つの0
ビットをバイナリの255の終わりにプッシュするのと同じです。
11111111000000
最後に、この値を255とビット単位でANDします。
11111111000000 &
00000011111111 # 255
これは
00000011000000
または単に
11000000
見覚えがあります?これは、バイナリのネットマスクの3番目のオクテットです。
11111111.11111111.11000000.00000000
^------^
10進数では、値は192です。
次に、$1
の値に基づいて位置パラメータをシフトします。
[ $1 -gt 1 ] && shift $1 || shift
この場合、$1
の値は3なので、位置パラメーター3を左にシフトします。 $4
の以前の値は$1
の新しい値になり、$5
の以前の値は$2
の値になります。
$1: 255
$2: 255
$3: 192
$4: 0
$5: 0
$6: 0
これらの値は見覚えがあるはずです。これらはネットマスクの10進オクテットです(最後にいくつかの余分なゼロが追加されています)。ネットマスクを取得するには、最初の4つをドットを挟んで印刷します。
echo ${1-0}.${2-0}.${3-0}.${4-0}
各パラメーターの後の-0
は、パラメーターが設定されていない場合、デフォルト値として0
を使用するように指示します。
255.255.192.0