Thank you for reading this post, don't forget to subscribe!
Маска подсети — это набор битов, определяющий, какое количество битов используется для указания адреса подсети, а какое для указания адреса компьютера в этой подсети. Более привычно маску подсети видеть в десятичном виде, но на самом деле она представляется в бинарном виде. Если вы понимаете, как представляется адрес подсети и адрес компьютера в этой подсети, то можете легко определить по адресу компьютера и маске подсети адрес этой самой подсети и маску подсети в таком виде:
<адрес-подсети>/<количество-бит>.
Пример маски подсети
Предположим, у вас есть некоторая сеть 192.168.1.0 (сеть класса C), а маска подсети (netmask) представлена как 255.255.255.0 (в бинарном виде это 11111111 11111111 11111111 00000000). Это говорит о том, что для адреса подсети выделены первые 24 бита, а под адрес компьютера в подсети 8 бит, то есть, интервал значений последнего октета (последних 8 бит) будет принимать 256 различных значений (значения от 0 до 255 включительно), где 0 — это адрес подсети, а 255 — броадкаст. Соответственно, под адреса компьютеров вы сможете выделить 254 адреса (от 1 до 254). И, находясь на каком-либо компьютере под управлением операционной системы на базе ядра Linux, вы можете посмотреть адрес компьютера и сетевую маску при помощи команд «ifconfig» и «ip addr».
Иногда требуется имея адрес компьютера и маску подсети определить адрес подсети и битность сетевой маски, чтобы представить адрес подсети в виде
1 |
<адрес-подсети>/<количество-бит-в-маске> |
Например:
1 |
192.168.1.0/24 |
Давайте попробуем решить задачу по такому преобразования на bash.
Перевод из десятичной системы в двоичную в bash
Для решения задачи нам необходимо будет перевести маску подсети в бинарный вид, поскольку маска подсети (netmask) — это последовательность бит, определяющая, какие из бит в указанном адресе выделены под адрес подсети (бит установлен в единицу), а какие — под адрес компьютера в подсети. Это очень важный момент в понимании IP адресов.
Функции, которая позволяет преобразовать десятичные числа в двоичные, в bash нет, поэтому необходимо будет использовать небольшую хитрость. Она заключается в том, что мы можем сгенерировать массив из последовательностей единиц и ноликов, каждый элемент которого будет являться двоичным представлением десятичного значения индекса этого элемента.
1 |
BINARRAY=({0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}) |
Эта строчка будет развернута в массив, содержащий 8-разрядные значения, что равносильно следующим операциям:
1 2 3 4 5 6 |
BINARRAY[0]="00000000" BINARRAY[1]="00000001" BINARRAY[2]="00000010" ... BINARRAY[254]="11111110" BINARRAY[255]="11111111" |
Перевод из двоичной системы в десятичную в bash
Обратное преобразование нам потребуется, чтобы преобразовать последовательность бит обратно в десятичное число. Тут всё проще. В bash есть возможность преобразовывать число из N-ричного в десятичное, где N — это число до 64 включительно. Вот как это выглядит для системы счисления с основанием 2 (двоичной):
1 2 3 4 5 6 |
> A=$((2#00000010)) > echo $A 2 > B=$((2#11111110)) > echo $B 254 |
Как видите, в данном случае всё очень просто.
Пишем скрипт
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
#!/bin/bash # Массив с двоичными значениями 00000000, 00000001, … 11111111 BARRAY=({0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}) # Переменная PARAMS содержит "192.168.1.10 255.255.255.0" PARAMS=$(ifconfig wlan0 | grep netmask | awk '{print $2" "$4}') # IP_ADDRESS содержит "192.168.1.10" IP_ADDRESS=${PARAMS%% *} # Заменяем точки на пробелы IP_ADDRESS=${IP_ADDRESS//./ } # Преобразуем октеты IP-адреса в бинарный вид BINARY_IP_ADDRESS=$(for octet in $IP_ADDRESS; do echo -n ${BARRAY[octet]}" "; done) # Разделяем побитово и помещаем в массив BIN_IP_SEP1=${BINARY_IP_ADDRESS//1/1 } BINARY_IP_ARRAY=( ${BIN_IP_SEP1//0/0 } ) # Маска подсети (255.255.255.0) NETMASK=${PARAMS#* } # Заменяем точки на пробелы NETMASK=${NETMASK//./ } # Преобразуем маску подсети в бинарный вид BINARY_NETMASK=$(for octet in $NETMASK; do echo -n ${BARRAY[octet]}" "; done) # Разделяем маску подсети побитово и помещаем в массив BIN_MASK_SEP1=${BINARY_NETMASK//1/1 } BINARY_MASK_ARRAY=( ${BIN_MASK_SEP1//0/0 } ) # Считаем количество битов, установленных в 1 BITS_COUNT=0 for i in ${BINARY_MASK_ARRAY[@]} do [ "$i" == "1" ] && BITS_COUNT=$((BITS_COUNT + 1)) done # Считаем адрес подсети NEW_ADDRESS="" for i in {0..31} do # После каждых 8 бит ставим пробел [ $(($i % 8)) -ne 0 ] || NEW_ADDRESS+=" " if [ "${BINARY_MASK_ARRAY[$i]}" == "1" ] then # Если бит в маске подсети равен 1, добавляем бит из адреса NEW_ADDRESS+="${BINARY_IP_ARRAY[$i]}" else # Если бит в маске подсети равен 0, добавляем его NEW_ADDRESS+="${BINARY_MASK_ARRAY[$i]}" fi done # Ковертируем значения октетов в десятичные значения DECIMAL_ADDRESS=`echo $(for octet in $NEW_ADDRESS; do echo $((2#$octet)); done)` # Заменяем пробелы на точки DECIMAL_ADDRESS=${DECIMAL_ADDRESS// /.} # Выводим итоговый результат echo $DECIMAL_ADDRESS/$BITS_COUNT |
Если вы хотите использовать команду ip для получения адреса и маски подсети, а не ifconfig, который считается устаревшим, вам нужно только поменять вычисление переменной PARAMS, так, чтобы ее значение содержало адрес компьютера и маску подсети в виде «192.168.1.10 255.255.255.0».