1. Введение
В задании №13 нужно работать с IPv4-адресами и масками сети. В условии могут попросить определить адрес сети, перебрать адреса внутри сети, найти допустимую маску или посчитать адреса, двоичная запись которых обладает нужным свойством.
Задание проверяет умение:
- понимать строение IPv4-адреса и маски сети;
- переводить байты адреса в восьмибитную двоичную запись;
- находить адрес сети с помощью поразрядной конъюнкции;
- работать с библиотекой
ipaddress; - перебирать адреса и маски и проверять двоичную запись адреса.
Основной способ решения на экзамене — короткая программа на Python с библиотекой ipaddress.
Но код становится понятным только после того, как разобраны адрес, маска и адрес сети.
2. Теория
IPv4-адрес
IPv4-адрес состоит из четырёх десятичных чисел от 0 до 255, разделённых точками. Каждая часть называется байтом и занимает 8 бит. Поэтому весь адрес содержит 32 бита.
Например, число 10 в одном байте записывается как 00001010, а число 8 — как 00001000.
Ведущие нули обязательны: без них невозможно правильно разделить 32-битную запись на четыре байта.
Маска сети
Маска — тоже 32-битное число. Единицы маски показывают, какая часть IP-адреса относится к адресу сети, а нули — какая часть относится к адресу узла внутри этой сети.
В корректной маске сначала идут все единицы, а затем все нули. Количество начальных единиц называют длиной префикса.
Например, маске 255.255.224.0 соответствует префикс /19.
Как получить адрес сети
Адрес сети получают, применяя операцию И к каждой паре соответствующих битов IP-адреса и маски.
В условии это может называться поразрядной конъюнкцией или поразрядным умножением.
Для адреса 10.8.248.131 и маски 255.255.224.0 получается адрес сети 10.8.224.0.
Биты узла, стоящие под нулями маски, обнуляются.
Библиотека ipaddress: основа кода
Модуль ipaddress входит в стандартную библиотеку Python и умеет создавать отдельные адреса и целые сети.
from ipaddress import *— подключает функции и классы модуля.ad = ip_address('10.8.248.131')— создаёт отдельный IP-адрес.net = ip_network('10.8.224.0/255.255.224.0')— создаёт сеть по адресу сети и маске.net = ip_network('10.8.248.131/255.255.224.0', 0)— создаёт сеть по адресу узла;0означаетstrict=False.net.network_address— возвращает адрес сети.net.netmask— возвращает маску сети.net.num_addresses— возвращает общее количество адресов сети.for ip in net:— перебирает все IP-адреса сети.f'{ip:b}'— получает 32-битную двоичную запись IP-адреса.bin(int(ip))[2:].zfill(32)— другой способ получить ту же 32-битную запись.
Без второго аргумента ip_network ожидает именно адрес сети.
Если в условии дан адрес узла, пишем 0 или strict=False: тогда Python сам обнулит узловую часть и найдёт сеть.
Перебор адресов и масок
У IPv4-адреса 32 бита, поэтому длина маски может принимать 33 значения: от /0 до /32.
Если в маске mask единиц, то нулей в ней:
32 - mask
а число адресов сети равно:
2 в степени (32 - mask)
Для проверки количества единиц или нулей адрес переводят в двоичную строку и используют count.
Срезы [:16] и [16:] отделяют левые два байта от правых двух байтов.
bits = f'{ip:b}'
ones = bits.count('1')
zeros = bits.count('0')
left = bits[:16]
right = bits[16:]
Адреса компьютеров в сети
Если условие спрашивает все IP-адреса сети, перебираем:
for ip in net:
Адрес сети и широковещательный адрес тоже войдут в перебор.
Если нужен адрес компьютера, крайние адреса не подходят:
- первый адрес компьютера —
net[1]; - последний адрес компьютера —
net[-2].
Если условие спрашивает все IP-адреса сети, перебираем for ip in net — адрес сети и широковещательный адрес тоже войдут в перебор.
Если нужен адрес компьютера, крайние адреса не подходят: первый адрес компьютера — net[1], последний — net[-2].
net = ip_network('45.172.106.203/255.255.252.0', 0)
print(net[1]) # наименьший адрес компьютера
print(net[-2]) # наибольший адрес компьютера
3. Пошаговое решение задачи кодом
Разбор задачи
В терминологии сетей TCP/IP маской сети называют двоичное число, которое показывает, какая часть IP-адреса узла сети относится к адресу сети, а какая — к адресу узла в этой сети.
Адрес сети получается в результате применения поразрядной конъюнкции к заданному адресу узла и маске сети.
Сеть задана IP-адресом 87.226.26.72 и маской сети 255.255.255.252.
Сколько в этой сети IP-адресов, у которых количество нулей в двоичной записи IP-адреса чётно?
В ответе укажите только число.
Код
from ipaddress import * # подключаем библиотеку
k = 0 # количество подходящих адресов
# перебираем все адреса сети
for ip in ip_network('87.226.26.72/255.255.255.252', 0):
ip2 = f'{ip:b}' # переводим адрес в 32-битную строку
# проверяем, что количество нулей чётно
if ip2.count('0') % 2 == 0:
k += 1 # учитываем подходящий адрес
print(k) # выводим ответ
Ответ: 2
Проверка результата
Маска 255.255.255.252 соответствует префиксу /30, поэтому сеть содержит 2 в степени (32 - 30), то есть 4 адреса.
Из них условию отвечают два адреса.
| IP-адрес | Количество нулей в 32-битной записи |
|---|---|
| 87.226.26.72 | 18 — чётное, адрес подходит |
| 87.226.26.73 | 17 — нечётное |
| 87.226.26.74 | 17 — нечётное |
| 87.226.26.75 | 16 — чётное, адрес подходит |
4. Практика
Задача 1. Досрочная волна 2024
Сеть задана IP-адресом 105.224.200.224 и сетевой маской 255.255.255.224.
Сколько в этой сети IP-адресов, для которых количество единиц в двоичной записи IP-адреса кратно 4?
В ответе укажите только число.
Решение на Python
from ipaddress import *
k = 0
for ip in ip_network('105.224.200.224/255.255.255.224', 0):
ip2 = f'{ip:b}'
if ip2.count('1') % 4 == 0:
k += 1
print(k)
Ответ: 10
Задача 2
Сеть, в которой содержится узел c IP-адресом 116.242.A.26, задана маской сети 255.255.255.224, где A — некоторое допустимое для записи IP-адреса число.
Определите максимальное значение A, для которого для всех IP-адресов этой сети в двоичной записи IP-адреса суммарное количество единиц в левых двух байтах не меньше суммарного количества единиц в правых двух байтах.
Решение на Python
from ipaddress import *
answer = 0
for A in range(256):
net = ip_network(f'116.242.{A}.26/255.255.255.224', 0)
good = True
for ip in net:
ip2 = f'{ip:b}'
if ip2[:16].count('1') < ip2[16:].count('1'):
good = False
break
if good:
answer = A
print(answer)
Переменная good остаётся равной True только тогда, когда условие выполнено для каждого адреса сети.
Значения A перебираются по возрастанию, поэтому последнее сохранённое значение является максимальным.
Ответ: 240
Задача 3
Для узла с IP-адресом 218.48.192.64 адрес сети равен 218.48.192.0.
Сколько существует различных возможных значений третьего слева байта маски, если известно, что в этой сети не менее 500 узлов?
Ответ запишите в виде десятичного числа.
Решение на Python
from ipaddress import *
third_bytes = set()
for mask in range(33):
net = ip_network(f'218.48.192.64/{mask}', 0)
if (str(net.network_address) == '218.48.192.0'
and net.num_addresses >= 500):
third = int(str(net.netmask).split('.')[2])
third_bytes.add(third)
print(len(third_bytes))
Перебираются все 33 длины маски.
set сохраняет только различные значения третьего байта маски, поэтому в конце достаточно вывести длину множества.
Ответ: 6
Задача 4. Минимальное количество нулей маски
Для узла с IP-адресом 111.91.200.28 адрес сети равен 111.91.192.0.
Найдите наименьшее возможное количество нулей в двоичной записи маски подсети.
Решение на Python
from ipaddress import *
answers = []
for mask in range(33):
net = ip_network(f'111.91.200.28/{mask}', 0)
if str(net.network_address) == '111.91.192.0':
answers.append(32 - mask)
print(min(answers))
mask — количество единиц маски. Следовательно, количество нулей равно 32 - mask.
Сохраняем результат для каждой подходящей маски и выбираем минимальный.
Ответ: 12
Задача 5. Адрес оканчивается на две единицы
Сеть задана IP-адресом 235.86.56.0 и маской сети 255.255.248.0.
Сколько в этой сети IP-адресов, двоичная запись которых оканчивается на две единицы?
Решение на Python
from ipaddress import *
k = 0
net = ip_network('235.86.56.0/255.255.248.0', 0)
for ip in net:
ip2 = f'{ip:b}'
if ip2[-2:] == '11':
k += 1
print(k)
Срез ip2[-2:] берёт два последних символа двоичной строки.
Подходят адреса, у которых этот срез равен строке '11'.
Ответ: 512
Видео разбор
Так-же все основные прототипы представлены в видео разборе задания