web-dev-qa-db-ja.com

Linuxシェルのnetmask2cdirおよびcdir2netmaskでのcidrからnetmaskへのコンバーターの説明

これから次のシェル関数が見つかりました 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、パラメーター展開_${#…}_、および算術展開$((…))の呼び出しは非常に圧倒的です。

19
MOHAMED

mask2cdr()

このようなドット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

cdr2mask()

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
28