Ответ 1
mask2cdr()
Чтобы получить префикс CIDR из десятичной сетевой маски, такой как этот:
255.255.192.0
вам сначала нужно преобразовать четыре октета в двоичный, а затем подсчитать наиболее значимые биты (например, количество ведущих):
11111111.11111111.11000000.00000000 # 18 ones = /18 in CIDR
Эта функция делает это довольно творчески. Во-первых, мы снимаем все ведущие октеты 255
(т.е. Октеты, все из которых находятся в двоичном виде) и сохраняем результаты в переменной x
:
local x=${1##*255.}
Этот шаг использует расширение параметра, которое весь script опирается довольно сильно. Если мы продолжим с нашей примерной сетевой маской 255.255.192.0
, теперь мы имеем следующие значения:
$1: 255.255.192.0
$x: 192.0
Затем мы устанавливаем три переменные: $1
, $2
и $3
. Они называются позиционные параметры; они очень похожи на обычные именованные переменные, но обычно устанавливаются, когда вы передаете аргументы функции script или. Мы можем установить значения непосредственно с помощью set --
, например:
set -- foo bar # $1 = foo, $2 = bar
Я предпочитаю использовать именованные переменные по позиционным параметрам, поскольку упрощает чтение и отладку скриптов, но конечный результат тот же. Положим $1
на:
0^^^128^192^224^240^248^252^254^
Это действительно просто таблица для преобразования определенных десятичных значений в двоичный код и подсчета количества бит 1
. Мы вернемся к этому позже.
Положим $2
на
$(( (${#1} - ${#x})*2 ))
Это выглядит сложным, но на самом деле это просто подсчет количества бит 1
, который мы разделили в первой команде. Это ломается до этого:
(number of chars in $1 - number of chars in $x) * 2
который в нашем случае работает
(13 - 5) * 2 = 16
Мы разделили два октета, чтобы мы получили 16. Имеет смысл.
Положим $3
в:
${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
и сохраните ее в x
:
x=${1%%$3*}
Значение $x
теперь
0^^^128^
который содержит два четырехсимвольных блока или два бита 1
в двоичном формате.
Теперь нам просто нужно добавить биты 1
из наших ведущих октетов 255
(всего 16, сохраненных в переменной $2
) и бит 1
с предыдущего шага (всего 2):
echo $(( $2 + (${#x}/4) ))
где
${#x}/4
- количество символов в $x
, деленное на четыре, т.е. количество четырехсимвольных блоков в $x
.
Вывод:
18
cdr2mask()
Продолжайте работать с нашим предыдущим примером, у которого был префикс CIDR 18
.
Мы используем 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 ))
Позвольте сломать это для нашего примера префикса CIDR 18
. Сначала мы берем модуль и делаем некоторое вычитание:
8 - (18 % 8) = 6
Затем мы побитно сдвигаем 255 на это значение:
255 << 6
Это то же самое, что нажать шесть бит 0
на конец 255 в двоичном формате:
11111111000000
Наконец, мы побитовое И это значение с 255:
11111111000000 &
00000011111111 # 255
который дает
00000011000000
или просто
11000000
Посмотрите знакомый? Это третий октет в нашей сетевой маске в двоичном формате:
11111111.11111111.11000000.00000000
^------^
В десятичном значении значение равно 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
Эти значения должны выглядеть знакомыми: это десятичные октеты из нашей сетевой маски (с добавлением пары дополнительных нулей в конце). Чтобы получить сетевую маску, мы просто распечатываем первые четыре с точками между ними:
echo ${1-0}.${2-0}.${3-0}.${4-0}
-0
после каждого параметра говорит использовать 0
как значение по умолчанию, если параметр не установлен.
Вывод:
255.255.192.0