Объяснение преобразователя cidr в сетевую маску в оболочке linux netmask2cdir и cdir2netmask [закрыто]

Я нашел следующие функции оболочки из этого темы

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%%*}
   echo $((  + (${#x}/4) ))
}


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

не могли бы вы подробно объяснить, как эти функции преобразуют cidr в сетевую маску и сетевую маску в cidr? В частности, вызовы set расширение параметр ${#…}, и арифметическое разложение $((…)) довольно подавляющим.

1 ответов


mask2cdr()

чтобы получить префикс CIDR из точечно-десятичной маски сети, как эта:

255.255.192.0

сначала вам нужно преобразовать четыре октета в двоичный, а затем подсчитать наиболее значимые биты (т. е. количество ведущих):

11111111.11111111.11000000.00000000  # 18 ones = /18 in CIDR

эта функция делает это довольно изобретательно. Во-первых, мы снимаем все ведущие 255 октеты (т. е. октеты, которые все в двоичном формате) и хранить результаты в переменной x:

local x=${1##*255.}

этот шаг использует расширения параметр, на который в значительной степени опирается весь сценарий. Если мы продолжим наш пример netmask 255.255.192.0, теперь у нас есть следующие значения:

: 255.255.192.0
$x: 192.0

Далее мы устанавливаем три переменные: , и . Они называются позиционные параметры; они очень похожи на обычные именованные переменные, но обычно устанавливаются при передаче аргументов скрипту или функция. Мы можем установить значения напрямую, используя set --, например:

set -- foo bar  #  = foo,  = bar

я предпочитаю использовать именованные переменные над позиционными параметрами, так как это упрощает чтение и отладку скриптов, но конечный результат тот же. Мы установили в:

0^^^128^192^224^240^248^252^254^

это действительно просто таблица для преобразования определенных десятичных значений в двоичные и подсчета числа 1 бит. Мы вернемся к этому позже.

мы к

$(( (${#1} - ${#x})*2 ))

это называется Арифметические Расширения. Это выглядит сложным, но на самом деле это просто подсчет количества 1 биты мы сняли в первой команде. Он распадается на это:

(number of chars in  - number of chars in $x) * 2

, который в нашем случае составляет

(13 - 5) * 2 = 16

мы сняли два октета, так что мы получаем 16. Обретать смысл.

мы в:

${x%%.*}

значение $x все после первый . снял. В нашем случае это 192.

нам нужно преобразовать это число в двоичный код и подсчитать количество 1 бит в нем, поэтому давайте вернемся к нашей "таблице преобразования."Мы можем разделить таблицу на равные куски по четыре символа:

0^^^  128^  192^  224^  240^  248^  252^  254^

в двоичном формате вышеуказанные числа:

00000000 10000000 11000000 11100000 11110000 11111000 11111100 11111110
# 0 ones 1 one    2 ones   3 ones   ...

если считать с левой, в каждом из четырех блок символа в таблице соответствует дополнительному 1 бит в двоичном. Мы попытка преобразовать 192, поэтому давайте сначала отрежем самую правую часть стола, от 192 on, и хранить его в x:

x=${1%%*}

значение $x теперь

0^^^128^

который содержит два четырехсимвольных блока или два 1 биты в двоичном формате.

теперь нам просто нужно сложить 1 биты от нашего ведущего 255 октеты (всего 16, хранятся в переменной ) и 1 биты с предыдущего шага (2 итого):

echo $((  + (${#x}/4) ))

здесь

${#x}/4

- количество символов в $x делится на четыре, т. е. количество четырехсимвольных блоков в $x.

выход:

18

cdr2mask()

давайте продолжим работать с нашим предыдущим примером, который имел префикс CIDR 18.

мы используем:set -- для установки позиционных параметров $1 - $9:

: $(( 5 - ( / 8) ))  # 5 - (18 / 8) = 3 [integer math]
: 255
: 255
: 255
: 255
: $(( (255 << (8 - ( % 8))) & 255 ))  # (255 << (8 - (18 % 8))) & 255 = 192
: 0
: 0
: 0

рассмотрим формулы используется для установки и немного ближе. установлено:

$(( 5 - ( / 8) ))

максимальное и минимальное возможные значения для префикса CIDR-32 для netmask

11111111.11111111.11111111.11111111

и 0 для маски

00000000.00000000.00000000.00000000

в приведенной выше формуле используется целочисленное деление, поэтому возможные результаты варьируются от 1 до 5:

5 - (32 / 8) = 1
5 - ( 0 / 8) = 5

установлено:

$(( (255 << (8 - ( % 8))) & 255 ))

давайте разберем это для нашего примера префикса CIDR 18. Сначала мы возьмите модуль и сделайте некоторое вычитание:

8 - (18 % 8) = 6

Далее мы побитовый сдвиг 255 на это значение:

255 << 6

это то же самое, что нажать шесть 0 бит на конец 255 в двоичном формате:

11111111000000

наконец, мы побитовые и это значение с 255:

11111111000000 &
00000011111111  # 255

что дает

00000011000000

или просто

11000000

знакомо? Это третий октет в нашем Маска в binary:

11111111.11111111.11000000.00000000
                  ^------^

в десятичном формате значение равно 192.

Далее мы сдвигаем позиционные параметры на основе значения :

[  -gt 1 ] && shift  || shift

в нашем случае значение равно 3, поэтому мы смещаем позиционные параметры 3 влево. Предыдущее значение становится новым значением , Предыдущее значение становится значением и так:

: 255
: 255
: 192
: 0
: 0
: 0

эти значения должны выглядеть знакомыми: они являются десятичными октетами из нашей сетевой маски (с парой дополнительных нулей, прикрепленных в конце). Чтобы получить сетевую маску, мы просто распечатываем первые четыре с точками между ними:

echo ${1-0}.${2-0}.${3-0}.${4-0}

на -0 после каждого параметра, что надо использовать 0 как значение по умолчанию, если параметр не задан.

выход:

255.255.192.0