
Навигация по странице
О задании
Задание 13 ЕГЭ по информатике посвящено работе с IP-адресами и масками сети. Оно направлено на проверку умений определять параметры по заданному IP-адресу и маске подсети, рассчитывать количество возможных адресов в сети, а также на применение побитовых операций для работы с IP-адресами и масками.
Работать в данном задании предстоит всего с тремя значениями: адрес сети, адрес узла и маска подсети. Два из них даются в условии, а одно требуется найти. Задания 13 можно разделить на 7 типов, в зависимости от данных значений.
Для успешного решения 13 заданий требуется уверенно понимать работу IP-адресации, а именно знать следующие термины: адрес сети, широковещательный адрес, маска подсети и префикс сети.
Часть рассматриваемых заданий можно решать вручную, но эффективнее и быстрее будет использовать специализированный модуль для работы с IP-адресами в Python – ipaddress.
В данной статье мы рассмотрим все перечисленные выше термины и основные функции модуля ipaddress. После теоретического блока разберем пару примеров на каждый тип данного задания.
Основные термины
В прошлой статье мы уже знакомились с работой сетей передачи данных и с некоторыми базовыми терминами, так что настоятельно рекомендуем сначала изучить материал, представленный в ней, а затем уже перейти к решению заданий ЕГЭ.
Сейчас мы уже не будем погружаться в работу IP-адресации, а просто дадим определения всем нужным нам терминам.
IP-адрес (Internet Protocol address) — это уникальный числовой идентификатор, присваиваемый каждому устройству в компьютерной сети, использующей протокол IP.
В версии протокола IPv4, которая используется в заданиях ЕГЭ, IP-адрес представляет собой 32-битное число, обычно записываемое в виде четырех десятичных чисел (от 0 до 255), разделенных точками. Например: 192.168.0.1. Каждое число между точками называется октетом.
IP-адрес выполняет две основные функции:
- Идентификация узла (компьютера, маршрутизатора или другого устройства) в сети
- Определение местоположения этого узла в сетевой иерархии
Весь IP-адрес состоит из двух основных логических частей: номер сети (адрес сети) и номер хоста (адрес узла). Первая часть указывает на саму сеть и является общей для всех устройств в данной сети, вторая же часть указывает на конкретное устройство в этой сети.
Разделение между этими частями зависит от маски подсети. Маска подсети — это 32-битное число, которое используется для разделения IP-адреса на две части: адрес сети и адрес узла. Маска записывается так же, как и IP-адрес — в виде четырех десятичных чисел, разделенных точками.
Принцип работы маски подсети:
- Биты в маске, равные 1, указывают на ту часть IP-адреса, которая относится к адресу сети
- Биты в маске, равные 0, указывают на часть IP-адреса, которая относится к адресу узла. Эта часть IP-адреса является изменяемой
Маска подсети может принимать только определенные значения, так как единицы должны быть непрерывными и располагаться в начале маски.
Вот примеры допустимых масок:
- 255.0.0.0 (11111111 00000000 00000000 00000000)
- 255.255.0.0 (11111111 11111111 00000000 00000000)
- 255.255.255.0 (11111111 11111111 11111111 00000000)
- 255.255.255.128 (11111111 11111111 11111111 10000000)
При этом такие маски, как 255.255.0.255 или 255.0.255.0, недопустимы, поскольку в них нарушается требование непрерывности единиц.
Из-за того, что единицы должны следовать строго в непрерывной последовательности, байт маски подсети не может принимать абсолютно любые значения. Например, значения, меньшие 128 (кроме нуля) недопустимы. А также маска не может принимать значения, где в двоичной записи ноль стоит между единицами: 131(10000011) или 220 (11011100).
Все допустимые значения каждого байта (октета) маски подсети перечислены на изображении ниже:

Для записи IP-адреса может применяться CIDR нотация. CIDR (Classless Inter-Domain Routing) — это метод записи IP-адресов и масок подсети в компактной форме «IP-адрес/префикс», где префикс указывает количество бит, отведённых под сетевую часть.
То есть префикс в такой записи означает количество единиц в маске подсети. Он может принимать значения от 0 до 32.
Например:
- 192.168.0.0/24 означает, что маска подсети содержит 24 единицы, то есть равна 255.255.255.0
- 10.0.0.0/8 означает маску 255.0.0.0
- 172.16.0.0/16 означает маску 255.255.0.0
- 192.168.0.0/28 означает маску 255.255.255.240
В таблице ниже приведено соответствие длины префикса, маски подсети, количества адресов в сети и количества хостов в сети.

Количество адресов в сети можно вычислить по формуле:
N = 2(32-Х), где N – количество адресов, X – префикс.
Так, в сети 192.168.1.0/16 будет 216 = 65 536 доступных адресов в сети.
Но не все эти адреса можно использовать. В любой сети (кроме тех, что с префиксом 31 и 32) два адреса всегда зарезервированы для специальных целей и не могут назначаться устройствам. Первый адрес – это адрес сети.
Адрес сети — это IP-адрес, у которого в части, отведенной для адреса узла (определяемой маской подсети), все биты равны 0. Адрес сети идентифицирует саму сеть, а не какое-либо конкретное устройство в ней.
Для определения адреса сети выполняется операция поразрядной конъюнкции между IP-адресом и маской подсети.
Например, устройство в сети имеет адрес 192.168.1.3, а маска подсети здесь 255.255.255.0. Выполним побитовую конъюнкцию и найдем адрес сети:
Адрес узла: 11000000 10101000 00000001 00000011
И
Маска: 11111111 11111111 11111111 00000000
=
Адрес сети: 11000000 10101000 00000001 00000000
Получим значение 11000000 10101000 00000001 00000000 или 192.168.1.0 в десятичной системе, которое и будет являться адресом сети.
Для получения номера узла нужно сначала применить инверсию к маске подсети, а затем побитовую конъюнкцию к адресу узла.
Адрес узла: 11000000 10101000 00000001 00000011
И
Инвертированная маска: 00000000 00000000 00000000 11111111
=
Номер узла: 00000000 00000000 00000000 00000011
В таком случае получим 0.0.0.3 или же просто 3, что и будет номером узла.
С первым «недоступным» адресом разобрались. Второй адрес, который не может быть назначен устройству в сети – это широковещательный адрес.
Широковещательный адрес — это специальный IP-адрес, который используется для отправки данных всем устройствам в конкретной сети. У широковещательного адреса в части, отведенной для адреса узла, все биты равны 1.
Для определения широковещательного адреса выполняется поразрядная дизъюнкция между адресом сети и инвертированной маской подсети.
Адрес сети: 11000000 10101000 00000001 00000000
ИЛИ
Инвертированная маска: 00000000 00000000 00000000 11111111
=
Широковещательный адрес: 11000000 10101000 00000001 11111111
В нашей сети широковещательным будет адрес 192.168.1.255.
Но необязательно вычислять все эти значения вручную, ведь есть встроенный в Python модуль ipaddress, который содержит множество полезных функций для работы с сетями. Давайте познакомимся с этими функциями поближе.
Модуль ipaddress
Модуль ipaddress включает в себя классы для работы с IP-адресами и сетями. Внутри этого модуля содержатся три основных класса, каждый из которых мы разберём далее.
Работа с IP-адресом
Создать объект IP-адреса можно с помощью фабричной функции ip_address(). Её вызов с верными параметрами приведёт к созданию объекта класса IPv4Address (или IPv6Address при работе с 6 версией IP). Эта функция может принимать корректный IP-адрес в виде строки или в виде десятичного числа.
Для примера создадим объекты IP-адреса из строки «192.168.0.0» и из числа 3232235779 (число должно быть меньше 232):
from ipaddress import ip_address
ip_1 = ip_address("192.168.0.0")
ip_2 = ip_address(3232235779)
print(f'Из строки: {ip_1}')
print(f'Из числа: {ip_2}')
>>>Из строки: 192.168.0.0
>>>Из числа: 192.168.1.3
Перевести из стандартного точечного десятичного формата в целое десятичное число можно, применив стандартную функцию int() к объекту IP-адреса (для обратного перевода можно использовать функцию str()):
from ipaddress import ip_address
ip_1 = ip_address("192.168.0.0")
ip_2 = ip_address(3232235779)
print(f'В виде числа: {int(ip_1)}')
print(f'В виде строки: {str(ip_2)}')
>>>В виде числа: 3232235520
>>>В виде строки: 192.168.1.3
Объект IP-адреса имеет следующие атрибуты и методы:
- exploded – полный (развёрнутый) вид адреса
- compressed – сокращённая форма адреса (актуально для IPv6)
- version – версия IP (4 или 6)
- is_private – находится ли адрес в частном диапазоне
- is_global – является ли адрес глобальным
- is_reserved – зарезервирован ли адрес
- is_multicast – является ли адрес мультикастом
- is_loopback – является ли адрес адресом обратной связи
- is_link_local – является ли адрес локальным (Link-Local)
При решении 13 заданий ЕГЭ вам часто придётся работать с двоичным представлением IP-адреса. Для получения такой записи из объекта IP-адреса можно использовать такую запись через f-строки:
from ipaddress import ip_address
ip = ip_address("192.168.0.0")
bin_ip = f'{int(ip):032b}'
print(bin_ip)
>>>11000000101010000000000000000000
Получить первые или последние два байта IP-адреса можно через срезы:
from ipaddress import ip_address
ip = ip_address("129.129.0.255")
bin_ip = f'{int(ip):032b}'
two_left = bin_ip[:16]
two_right = bin_ip[16:]
print(f'Весь адрес: {bin_ip}')
print(f'По частям: {two_left} | {two_right}')
>>>Весь адрес: 10000001100000010000000011111111
>>>По частям: 1000000110000001 | 0000000011111111
Работа с IP-сетью
Более обширный функционал доступен для объектов IP-сети. Создаются они с помощью фабричной функции ip_network() и принимают адрес сети с маской сети или её префиксом.
from ipaddress import ip_network
net = ip_network('192.168.1.0/255.255.255.0')
print(net)
>>>192.168.1.0/24
Помните, что адрес сети не может иметь никаких битов узла, то есть последнее значение в записи адреса сети должно быть 0. При попытке создать объект сети с установленными битами узла будет вызвана ошибка ValueError.
Запросить приведение дополнительных битов к нулю можно с помощью параметра strict со значением False (можно просто вторым аргументом функции передать логическое значение False).
Например, создадим сеть по адресу её узла «192.168.1.3» и маске подсети «255.255.255.0»:
from ipaddress import ip_network
net = ip_network('192.168.1.3/255.255.255.0', strict=False)
print(net)
>>>192.168.1.0/24
Основные методы и атрибуты, которыми мы будем пользоваться чаще всего, у объекта IP-сети такие:
- network_address – сетевой адрес
- broadcast_address – широковещательный адрес
- prefixlen – длина префикса (количество единиц в маске)
- num_addresses – количество адресов в сети
- netmask – маска подсети
- hosts() – генератор, перебирающий все доступные хосты (без network и broadcast)
Результат применения перечисленных выше атрибутов показан ниже:
from ipaddress import ip_network
net = ip_network('192.168.1.3/255.255.255.248', strict=False)
print(f'Адрес сети: {net.network_address}')
print(f'Широковещ-ный:{net.broadcast_address}')
print(f'Длина префикса: {net.prefixlen}')
print(f'Адресов в сети: {net.num_addresses}')
print(f'Маска: {net.netmask}')
>>>Адрес сети: 192.168.1.0
>>>Широковещ-ный:192.168.1.7
>>>Длина префикса: 29
>>>Адресов в сети: 8
>>>Маска: 255.255.255.248
Вернуть генератор всех адресов в сети можно с помощью метода hosts().
from ipaddress import ip_network
net = ip_network('192.168.1.3/255.255.255.248', strict=False)
for ip in net.hosts():
print(ip, end=" ")
>>>192.168.1.1 192.168.1.2 192.168.1.3 192.168.1.4 192.168.1.5 192.168.1.6
Объект IP-сети поддерживает протокол итерации, следовательно, можно как перебирать все адреса в сети в цикле, так и обращаться к ним через квадратные скобки (метод __getitem__()).
Переберём все адреса в сети с узлом «192.168.1.3» и префиксом «/30»:
from ipaddress import ip_network
net = ip_network('192.168.1.2/30', strict=False)
for ip in net:
print(ip, end=" ")
>>>192.168.1.0 192.168.1.1 192.168.1.2 192.168.1.3
Давайте создадим объект IP-адреса «192.168.1.5» и проверим, принадлежат ли он сети «192.168.1.0/28»:
from ipaddress import ip_address, ip_network
ip = ip_address('192.168.1.5')
net = ip_network('192.168.1.0/28')
if ip in net.hosts():
print(f'Узел {ip} принадлежит сети')
>>>Узел 192.168.1.5 принадлежит сети
Но такие проверки лучше делать с использованием объекта IP-интерфейса.
Работа с IP-интерфейсом
IP-интерфейс – это комбинация IP-адреса и маски сети, которая определяет сетевой интерфейс устройства. В отличие от простого IP-адреса, интерфейс всегда содержит информацию о сети, к которой он принадлежит.
Класс IPv4Interface объединяет характеристики как отдельного IP-адреса, так и всей сети в целом. То есть объекты этого класса совмещают в себе методы классов IP-адреса и IP-сети.
Допустим, у нас сеть задана адресом входящего в неё узла «192.168.1.5» и маской сети «255.255.255.0». Создадим IP-интерфейс этой сети:
from ipaddress import ip_interface
interface = ip_interface('192.168.1.10/255.255.255.0')
print(interface)
>>>192.168.1.10/24
Теперь можем вывести адрес сети (объект сети), её префикс, и получить адрес узла в виде объекта:
from ipaddress import ip_interface
interface = ip_interface('192.168.1.10/255.255.255.0')
print(f'Адрес сети: {interface.network.network_address}')
print(f'Префикс: {interface.network.prefixlen}')
print(f'Адрес узла: {interface.ip}')
>>>Адрес сети: 192.168.1.0
>>>Префикс: 24
>>>Адрес узла: 192.168.1.10
Давайте проверим, принадлежит ли адрес «192.168.1.5» нашей сети:
from ipaddress import ip_interface, ip_address
interface = ip_interface('192.168.1.10/255.255.255.0')
ip = ip_address('192.168.1.5')
if ip in interface.network:
print(f'Адрес {ip} принадлежит сети')
>>>Адрес 192.168.1.5 принадлежит сети
Мы рассмотрели все необходимые методы, которыми будем пользоваться при решении заданий 13 ЕГЭ по информатике. Теперь можем смело переходить к разбору алгоритма решения этих заданий.
Алгоритм решения
Как уже было сказано, задания 13 ЕГЭ по информатике можно поделить на 7 типов в зависимости от значений, которые даны в условии. Ниже перечислены эти типы с кратким описанием каждого:
- Тип 1. Даны адрес сети и маска. Требуется найти количество адресов в сети, удовлетворяющих условию
- Тип 2. Даны адрес узла и адрес сети. Требуется найти маску подсети (наибольшее/наименьшее количество единиц/нулей)
- Тип 3. Даны адрес сети и маска с неизвестным байтом. Требуется найти значение отсутствующего байта маски, при котором будет выполняться условие (количество единиц/нулей в левых двух байтах меньше/больше количества в правых двух байтах)
- Тип 4. Даны маска подсети и адрес сети с неизвестным байтом. Требуется найти значение отсутствующего байта адреса сети, при котором будет выполняться условие (количество единиц/нулей в левых двух байтах меньше/больше количества в правых двух байтах)
- Тип 5. Даны два адреса узлов, находящихся в одной сети. Требуется найти маску подсети (наибольшее/наименьшее количество единиц/нулей в маске)
- Тип 6. Даны адрес узла сети и маска. Требуется найти наибольший/наименьший адрес хоста.
- Тип 7. Даны маска подсети и адрес узла с неизвестным байтом. Требуется найти значение отсутствующего байта адреса узла, при котором будет выполняться условие (количество единиц/нулей в левых двух байтах меньше/больше количества в правых двух байтах)
Все представленные в статье типы отсортированы по количеству заданий, представленных в официальных сборниках, и по вероятности попадания этих типов на реальном ЕГЭ по информатике.
Задания первого типа представлены в ЕГЭ прошлого года (2024) и в демоверсии 2025 года. Рекомендуем сделать акцент на этом типе, ведь есть довольно большая вероятность, что именно задания этого типа и попадутся вам на экзамене.
Задания же седьмого типа встречаются крайне редко и только в авторских вариантах заданий. Также вы можете наткнуться и на некоторые другие, необычные авторские формулировки заданий. Но не стоит их бояться, по рассмотренным далее алгоритмам они также будут решаться без особых проблем.
Сейчас же мы последовательно разберём все типы 13 заданий и решим пару примеров на каждый из них.
Тип 1
Рассмотрим такую формулировку задания первого типа:
Задание 1303
«Сеть задана IP-адресом 172.16.168.0 и маской сети 255.255.248.0.
Сколько в этой сети IP-адресов, для которых количество единиц в двоичной записи IP-адреса не кратно 5?
В ответе укажите только число»
В этом задании нам предстоит создать объект сети и перебрать все IP-адреса в этой сети. Среди них нужно определить, в каких адресах количество единиц кратно 5 и вывести на экран количество таких адресов.
Для начала импортируем функцию ip_network() из модуля ipaddress и создаём объект сети со значениями из условия:
from ipaddress import ip_network
net = ip_network('172.16.192.0/255.255.192.0')
Далее перебираем все адреса из этой сети, считаем количество единиц в каждом адресе, если оно делится на 5 без остатка, то условие кратности выполняется. В переменную cnt будем записывать количество всех адресов сети, для которых выполняется условие кратности 5.
cnt = 0
for i in net:
ip = f'{int(i):032b}'
if ip.count('1') % 5 != 0:
cnt += 1
print(cnt)
На этом все. Полный код решения этого задания будет такой:
from ipaddress import ip_network
net = ip_network('172.16.192.0/255.255.192.0')
cnt = 0
for i in net:
ip = f'{int(i):032b}'
if ip.count('1') % 5 != 0:
cnt += 1
print(cnt)
В ответе получаем количество подходящих под условие IP-адресов – 1663.
Пример 1
Рассмотрим еще одну задачу с похожей формулировкой:
Задание 1310
«Сеть задана IP-адресом 142.108.56.118 и сетевой маской 255.255.255.240.
Сколько в этой сети IP-адресов, для которых в двоичной записи IP-адреса суммарное количество единиц в левых двух байтах меньше суммарного количества единиц в правых двух байтах?
В ответе укажите только число»
Здесь адрес сети имеет установленные последние биты, то есть последний байт IP-адреса сети не равен нулю. Это означает, что функции ip_network() необходимо передать в качестве второго аргумента логическое значение False.
from ipaddress import ip_network
net = ip_network('142.108.56.118/255.255.255.240', False)
Далее мы все также в цикле перебираем все IP-адреса данной сети. Только теперь будем подсчитывать количество единиц отдельно в левых и правых двух байтах каждого IP-адреса.
Если количество единиц в левых двух байтах меньше количества единиц в правых двух байтах, то будем увеличивать значение переменной cnt на 1.
cnt = 0
for i in net:
ip = f'{int(i):032b}'
two_left = ip[:16]
two_right = ip[16:]
if two_left.count('1') < two_right.count('1'):
cnt += 1
print(cnt)
В итоге получаем такой код:
from ipaddress import ip_network
net = ip_network('142.108.56.118/255.255.255.240', False)
cnt = 0
for i in net:
ip = f'{int(i):032b}'
two_left = ip[:16]
two_right = ip[16:]
if two_left.count('1') < two_right.count('1'):
cnt += 1
print(cnt)
По итогу его работы получаем количество нужных нам IP-адресов – 5.
Тип 2
Начнём с такой формулировки:
Задание 1307
«Для узла с IP-адресом 192.168.24.72 адрес сети равен 192.168.24.64. Определите наименьшее возможное количество единиц в последних двух байтах маски.
В ответе укажите только число»
Такие задания на поиск маски очень легко решаются вручную. Для этого необходимо перевести все данные в условии значения в двоичный вид и вспомнить, в чем суть маски подсети.
Маска подсети при применении поразрядной конъюнкции позволяет получить из адреса узла адрес сети. Следовательно, можем заполнять маску единицами слева направо до тех пор, пока, применяя побитовую конъюнкцию, из адреса узла будет получаться адрес сети.
Адрес узла в двоичном виде записывается так: 11000000 10101000 00011000 01001000. То есть каждый октет мы переводим из десятичного в двоичный вид. Так, число 192 в двоичной системе счисления записывается как 11000000.
Аналогично получаем адрес сети в двоичном представлении: 11000000 10101000 00011000 01000000. Напишем их друг под другом, оставив пустую строку под маску.

Теперь начнём записывать единицы в маску до последней единицы в адресе сети.

Таким образом, мы получили минимальную допустимую маску нашей сети. Можно и продолжить заполнение единицами маски. Но строго до тех пор, пока на соответствующей позиции в адресе узла не встретится единица.

В данном случае мы дописали еще две единицы (отмечены зелёным), а уже на пятом бите последнего байта мы должны поставить ноль, иначе маска будет некорректной. Такой записью мы получим максимальную допустимую маску сети.
Но нам нужна минимальная, так что уберём две лишние единицы и рассмотрим два последних байта маски. В них содержится ровно 10 единиц, что и будет ответом на данное задание.

Теперь решим это задание кодом. Использовать будем функции ip_network() и ip_address(). Импортируем их и создаём объекты IP-адреса сети и IP-адреса узла.
from ipaddress import ip_network, ip_address
ip_net = ip_address('192.168.24.64')
ip_host = ip_address('192.168.24.72')
Добавим переменную bit_mask, в которой будем хранить последние два байта каждой подходящей маски в двоичном виде.
В цикле будем перебирать возможные длины префикса сети. Мы рассматриваем последние два байта, так что нас интересуют значения префикса от 17 до 30.
В цикле будем создавать объект сети с помощью ip_network(), используя адрес узла (можно и адрес сети) и длину префикса, значения которого и перебираем в цикле.
bit_mask = []
for mask in range(17, 31):
net = ip_network(f'{ip_host}/{mask}', False)
Теперь будем проверять, что адрес узла содержится в списке всех хостов сети, а адрес сети соответствует тому, что задан в условии.
if ip_host in net.hosts() and net.network_address == ip_net:
Если условие истинно, то текущая маска сети нам подходит. Значит, переводим её значение в двоичный вид и добавляем в список bit_mask последние два байта (16 символов):
bit_mask.append(f'{int(net.netmask):032b}'[16:])
Для получения ответа мы выбираем наименьшую маску и вычисляем в ней количество единиц:
print(min(bit_mask).count("1"))
Весь код для решения этой задачи выглядит так:
from ipaddress import ip_network, ip_address
ip_net = ip_address('192.168.24.64')
ip_host = ip_address('192.168.24.72')
bit_mask = []
for mask in range(17, 31):
net = ip_network(f'{ip_host}/{mask}', False)
if ip_host in net.hosts() and net.network_address == ip_net:
bit_mask.append(f'{int(net.netmask):032b}'[16:])
print(min(bit_mask).count("1"))
Её же можно решить и через IP-интерфейс. Код будет по большей части аналогичным, но придётся лишний раз обращаться к объекту сети из IP-интерфейса:
from ipaddress import ip_interface, ip_address
ip_net = ip_address('192.168.24.64')
ip_host = ip_address('192.168.24.72')
bit_mask = []
for mask in range(17, 31):
# Можно использовать и адрес сети, и адрес узла
net = ip_interface(f'{ip_net}/{mask}')
if ip_host in net.network.hosts() and net.network.network_address == ip_net:
bit_mask.append(f'{int(net.netmask):032b}'[16:])
print(min(bit_mask).count("1"))
Пример 2
Формулировка будет следующая:
Задание 1311
«Для узла с IP-адресом 44.44.229.28 адрес сети равен 44.44.224.0.
Каково наибольшее значение единиц в разрядах маски?»
В данном задании от нас требуется найти значение единиц в разрядах маски. Вместо перевода целочисленного значения маски в двоичный вид можем воспользоваться префиксом – его длина как раз и означает количество единиц в маске подсети. Для получения префикса сети будем вызывать атрибут prefixlen у объекта сети.
Начало решения будет аналогичное прошлому:
from ipaddress import ip_network, ip_address
ip_net = ip_address('44.44.224.0')
ip_host = ip_address('44.44.229.28')
prefixlen = []
Далее мы также будем перебирать возможные значения длины префикса в цикле for и создавать объект сети с каждым значением.
for mask in range(17, 32):
net = ip_network(f'{ip_host}/{mask}', False)
Составляем условие, в котором будем проверять, что адрес узла содержится в списке всех хостов сети, а адрес сети соответствует тому, что задан в условии. Если условие будет истинно, то в список prefixlen добавляем текущее значение длины префикса сети.
if ip_host in net.hosts() and net.network_address == ip_net:
prefixlen.append(net.prefixlen)
После того как цикл закончит работу, выводим максимальное значение из списка prefixlen.
print(max(prefixlen))
Весь код у нас будет такой:
from ipaddress import ip_network, ip_address
ip_net = ip_address('44.44.224.0')
ip_host = ip_address('44.44.229.28')
prefixlen = []
for mask in range(17, 32):
net = ip_network(f'{ip_host}/{mask}', False)
if ip_host in net.hosts() and net.network_address == ip_net:
prefixlen.append(net.prefixlen)
print(max(prefixlen))
А в результате работы программы получим число 21.
Тип 3
Разберём задание с такой формулировкой:
Задание 1313
«Сеть задана IP-адресом 191.239.130.3 и маской сети 255.255.А.0, где А – некоторое допустимое для записи маски число. Определите минимальное значение А, для которого для всех IP-адресов этой сети в двоичной записи IP-адреса суммарное количество единиц в левых двух байтах не менее суммарного количества единиц в правых двух байтах.
В ответе укажите только число»
Как и во всех заданиях раньше, начинаем с импорта функций и создания объекта IP-адреса.
from ipaddress import ip_network, ip_address
ip_net = ip_address('191.239.130.3')
В цикле for перебираем допустимые значения длины префикса сети. Поскольку в маске из условия отсутствует именно третий байт, то будем перебирать значения от 16 до 24.
for mask in range(16, 24):
net = ip_network(f'{ip_net}/{mask}', False)
Далее распишем условие, в котором будет проверка на то, что для каждого IP-адреса в сети количество единиц в левых двух байтах больше или равно количеству единиц в правых двух байтах.
if all(f'{int(ip):032b}'[:16].count('1') >= f'{int(ip):032b}'[16:].count('1') for ip in net):
При первом же выполнении этого условия возвращаем маску нашей сети атрибутом netmask, переводим её в строчный формат и разделяем по точкам. Это мы делаем только для того, чтобы в ответе увидеть именно третий байт маски. Вы можете этого не делать, а просто вывести всю маску и определить значение третьего байта самостоятельно.
res_mask = str(net.netmask).split('.')
print(res_mask[2])
break
Полный код будет выглядеть так:
from ipaddress import ip_network, ip_address
ip_net = ip_address('191.239.130.3')
for mask in range(16, 24):
net = ip_network(f'{ip_net}/{mask}', False)
if all(f'{int(ip):032b}'[:16].count('1') >= f'{int(ip):032b}'[16:].count('1') for ip in net):
res_mask = str(net.netmask).split('.')
print(res_mask[2])
break
Запускаем его и видим на экране число 224, которое и запишем в ответ.
Пример 3
Формулировка здесь будет такой:
Задание 1314
«Сеть задана IP-адресом 255.215.88.80 и маской сети 255.255.А.0, где А – некоторое допустимое для записи маски число. Определите минимальное значение А, для которого для всех IP-адресов этой сети в двоичной записи IP-адреса суммарное количество нулей в левых двух байтах не более суммарного количества нулей в правых двух байтах.
В ответе укажите только число»
Решение здесь будет идентичным предыдущему. Все изменения коснутся только строки с условием: будем считать количество нулей, а не единиц, а также поменяется знак между частями выражения – теперь количество нулей слева должно быть меньше или равно количеству нулей справа.
if all(f'{int(ip):032b}'[:16].count('0') <= f'{int(ip):032b}'[16:].count('0') for ip in net):
В остальном код без изменений, и выглядит он так:
from ipaddress import ip_network, ip_address
ip_net = ip_address('255.215.88.80')
for mask in range(16, 24):
net = ip_network(f'{ip_net}/{mask}', False)
if all(f'{int(ip):032b}'[:16].count('0') <= f'{int(ip):032b}'[16:].count('0') for ip in net):
res_mask = str(net.netmask).split('.')
print(res_mask[2])
break
После запуска получаем ответ на данное задание – число 224.
Тип 4
Продолжаем разбирать типы с пропущенными числами в данных. Теперь байт отсутствует не в маске, а в IP-адресе сети. Подход здесь похож на тот, что мы использовали ранее. Но в этом типе заданий перебирать будем не значения длины префикса, а конкретное значение байта в IP-адресе от 0 до 255.
Начнём разбор этого типа с такой формулировки:
Задание 1315
«Сеть задана IP-адресом 32.0.А.5, где А – некоторое допустимое для записи IP-адреса число, и масок сети 255.255.240.0. Определите минимальное значение А, для которого для всех IP-адресов этой сети в двоичной записи IP-адреса суммарное количество единиц в левых двух байтах не более суммарного количества единиц в правых двух байтах.
В ответе укажите только число»
Здесь нам нужно определить третий байт в адресе «32.0.А.5». Логичней всего будет представить этот адрес в виде f-строки с переменной А, значения которой и будем перебирать в цикле for.
for A in range(256):
net = ip_network(f'32.0.{A}.5/255.255.240.0', False)
Затем идёт уже знакомое нам условие сравнения единиц в левых двух байтах и в правых двух байтах.
if all(f'{int(ip):032b}'[:16].count('1') <= f'{int(ip):032b}'[16:].count('1') for ip in net):
print(A)
break
Весь код к этому заданию выглядит так:
from ipaddress import ip_network
for A in range(256):
net = ip_network(f'32.0.{A}.5/255.255.240.0', False)
if all(f'{int(ip):032b}'[:16].count('1') <= f'{int(ip):032b}'[16:].count('1') for ip in net):
print(A)
break
В итоге получаем, что на месте А должно быть число 16, которое и записываем в ответ.
Пример 4
Задание 1316
«Сеть задана IP-адресом 127.254.А.10, где А – некоторое допустимое для записи IP-адреса число, и масок сети 255.255.224.0. Определите максимальное значение А, для которого для всех IP-адресов этой сети в двоичной записи IP-адреса суммарное количество единиц в левых двух байтах не менее суммарного количества единиц в правых двух байтах.
В ответе укажите только число»
Подробно разбирать решение этого задания не будем. Код здесь мало чем отличается от предыдущего.
from ipaddress import ip_network
mask = '255.255.224.0'
for A in range(256)[::-1]:
net = ip_network(f'127.254.{A}.10/{mask}', False)
if all(f'{int(ip):032b}'[:16].count('1') >= f'{int(ip):032b}'[16:].count('1') for ip in net):
print(A)
break
В результате работы нашей программы получим искомое значение числа А – 159.
Тип 5
В заданиях этого типа нам даются только адреса двух узлов, находящихся в одной (или разных) сети. Обычно требуется найти какое-либо значение, связанное с маской подсети: количество нулей или единиц в ней или количество адресов в сети.
Для примера рассмотрим такую формулировку:
Задание 1306
«Два узла, находящиеся в одной сети, имеют IP-адреса 192.168.190.12 и 192.168.184.0.
Укажите наибольшее возможное количество единиц в маске этой сети»
Подход к решению здесь будет таким же, как и во всех заданиях, в которых отсутствует маска подсети. Будем перебирать все возможные значения длины префикса сети, строить сеть с каждым адресом и проверять, что обе сети действительно совпадают, а оба адреса из условия являются хостами любой сети.
Сначала создаём два объекта IP-адреса на основе данных из условия.
from ipaddress import ip_network, ip_address
ip_1 = ip_address('192.168.190.12')
ip_2 = ip_address('192.168.184.0')
Далее перебираем все возможные значения длины префикса в цикле for. Поскольку нам необходимо найти наибольшее количество единиц в маске, то начнём со значения длины префикса в 30 и будем уменьшать его, пока не дойдём до подходящего.
Внутри цикла создаём два объекта сети с каждым из данных IP-адресов и текущим значением длины префикса сети.
for mask in range(31)[::-1]:
net_1 = ip_network(f'{ip_1}/{mask}', False)
net_2 = ip_network(f'{ip_2}/{mask}', False)
И формируем условие: если обе сети совпадают, проверяем, что адреса ip_1 и ip_2 являются хостами одной из сети. Как только все условия выполнятся, выводим текущее значение длины префикса на экран и завершаем цикл.
if net_1 == net_2 and ip_1 in net_1.hosts() and ip_2 in net_1.hosts():
print(mask)
break
Полный код к этому заданию будет такой:
from ipaddress import ip_network, ip_address
ip_1 = ip_address('192.168.190.12')
ip_2 = ip_address('192.168.184.0')
for mask in range(31)[::-1]:
net_1 = ip_network(f'{ip_1}/{mask}', False)
net_2 = ip_network(f'{ip_2}/{mask}', False)
if net_1 == net_2 and ip_1 in net_1.hosts() and ip_2 in net_1.hosts():
print(mask)
break
В результате работы программы получаем длину префикса сети, равную 20, что и означает требуемое по условию наибольшее возможное количество единиц в маске сети.
Пример 5
Рассмотрим задание с похожей формулировкой:
Задание 1319
«Два узла, находящиеся в одной сети, имеют IP-адреса 127.0.1.65 и 127.0.1.101.
Укажите наименьшее возможное количество адресов в этой сети»
Решение здесь будет таким же, как и в прошлом примере. Только в ответ будем давать количество адресов в сети, которое вернёт нам атрибут num_addresses объекта IP-сети. Выглядит это решение следующим образом:
from ipaddress import ip_network, ip_address
ip_1 = ip_address('127.0.1.65')
ip_2 = ip_address('127.0.1.101')
for mask in range(31)[::-1]:
net_1 = ip_network(f'{ip_1}/{mask}', False)
net_2 = ip_network(f'{ip_2}/{mask}', False)
if net_1 == net_2 and ip_1 in net_1.hosts() and ip_2 in net_1.hosts():
print(net_1.num_addresses)
break
По окончании работы программы видим на экране число 64, которое и записываем в ответ.
Тип 6
Задания данного типа являются самыми простыми среди всех 13 заданий. Решения здесь, обычно, занимают всего одну строку, без учёта импорта функций и вывода результата.
Начнём с такой формулировки:
Задание 1302
«Сеть задана IP-адресом одного из входящих в неё узлов 218.194.82.148 и сетевой маской 255.255.255.192.
Найдите наибольший IP-адрес в данной сети, который может быть назначен компьютеру.
В ответе укажите найденный IP-адрес без разделителей»
Импортируем нужные функции из модуля ipaddress и создаём объект сети по данным из условия.
from ipaddress import ip_network
net = ip_network('218.194.82.148/255.255.255.192', False)
Нам нужно найти наибольший IP-адрес, который может быть назначен хосту. Вспоминаем, что последний адрес в сети – это широковещательный. Следовательно, нужно взять предпоследний – он и будет наибольшим в этой сети, который можно присвоить любому устройству.
В Python предпоследний элемент списка можно получить с помощью индекса «-2». Добавим в уже написанный код вывод на экран предпоследнего элемента объекта net. Получим такую программу:
from ipaddress import ip_network
net = ip_network('218.194.82.148/255.255.255.192', False)
print(net[-2])
Она выведет на экран IP-адрес 218.194.82.190. Переписываем его в ответ без десятичных точек между числами и радуемся проделанной работе.
Пример 6
Формулировка будет такая:
Задание 1305
«Сеть задана IP-адресом одного из входящих в неё узлов 192.168.128.30 и сетевой маской 255.255.255.240.
Найдите наименьший IP-адрес в данной сети, который может быть назначен компьютеру.
В ответе укажите найденный IP-адрес без разделителей»
В этом случае от нас требуется дать в ответ наименьший IP-адрес в сети. Снова вспоминаем, какие адреса не могут быть назначены устройствам сети: это широковещательный и адрес сети.
Самым первым адресом в нашей сети будет как раз адрес сети. Следовательно, наименьший адрес, который можно назначить любому устройству – это второй.
Строим сеть по данным из условия и выводим на экран элемент сети с индексом 1.
from ipaddress import ip_network
net = ip_network('192.168.128.30/255.255.255.240', False)
print(net[1])
В результате получаем адрес 192.168.128.17, который записываем без разделителей в ответ.
Тип 7
И снова задания с отсутствующим байтом. На этот раз неизвестный байт скрывается в адресе узла.
Задания этого типа встречаются куда реже всех остальных. Но решение здесь будет таким же, как в заданиях четвёртого типа с неизвестным байтом в IP-адресе сети.
Рассмотрим такую формулировку задания:
Задание 1317
«Сеть, в которой содержится узел с IP-адресом 240.224.A.60, задана маской сети 255.255.255.128, где A – некоторое допустимое для записи IP-адреса число. Определите минимальное значение A, для которого для всех IP-адресов этой сети в двоичной записи IP-адреса суммарное количество единиц будет больше 13.
В ответе укажите только число»
Действуем по рассмотренному ранее алгоритму: в цикле перебираем значение числа А от 0 до 255, строим сеть и в условии проверяем, что для каждого адреса этой сети суммарное количество единиц больше 13. Как только условие станет истинным, выводим текущее значение А на экран.
Код для решения этого задания будет таким:
from ipaddress import ip_network
mask = '255.255.255.128'
for A in range(256):
net = ip_network(f'240.224.{A}.60/{mask}', False)
if all(f'{int(ip):032b}'.count('1') > 13 for ip in net):
print(A)
break
В результате получаем число 127.
Пример 7
Задание 1318
«Сеть, в которой содержится узел с IP-адресом 127.215.A.32, задана маской сети 255.255.254.0, где A – некоторое допустимое для записи IP-адреса число. Определите максимальное значение A, для которого для всех IP-адресов этой сети в двоичной записи IP-адреса суммарное количество нулей в левых двух байтах не больше суммарного количества нулей в правых двух байтах.
В ответе укажите только число»
Решение здесь будет аналогичным тому, что привели ранее для задания 1317. Условие проверки количества нулей в левых двух байтах и правых двух байтах мы также рассматривали ранее, например, в задании 1314.
Поскольку здесь требуется дать в ответ максимальное значение А, то перебираем числа от 255 до 0. Это можно записать в виде диапазона range(255, -1, -1) или через срез: range(256)[::-1].
В итоге можем написать такой код:
from ipaddress import ip_network
mask = '255.255.254.0'
for A in range(256)[::-1]:
net = ip_network(f'127.215.{A}.32/{mask}', False)
if all(f'{int(ip):032b}'[:16].count('0') <= f'{int(ip):032b}'[16:].count('0') for ip in net):
print(A)
break
После завершения работы программы на экран выводится число 241, которое и будет ответом на это задание.