Подсети и маски: расчёт на Python

Учимся считать подсети: маску, адрес сети, broadcast, диапазон и число хостов — с живыми примерами на Python.

Маска подсети — это набор бит, который отделяет в адресе часть «сеть» от части «хост». В CIDR её задаёт префикс /N.

Из чего состоит подсеть

В любой подсети есть несколько особых адресов:

  • Адрес сети — первый адрес (все биты хоста = 0). Идентифицирует саму подсеть.
  • Broadcast — последний адрес (все биты хоста = 1). Пакет на него уходит всем в подсети.
  • Адреса хостов — всё между ними. Именно их можно назначать устройствам.

Поэтому полезных адресов всегда на два меньше, чем всего: первый и последний зарезервированы. Для /26 всего 64 адреса, но хостов — 62.

Считаем подсеть на Python

Вместо ручного перевода в двоичную систему используем стандартный модуль ipaddress — он есть в Python из коробки и работает в браузере. Возьмём сеть 192.168.10.0/26:

import ipaddress

net = ipaddress.ip_network('192.168.10.0/26')
print('Сеть:           ', net)
print('Маска:          ', net.netmask)
print('Префикс:        ', '/' + str(net.prefixlen))
print('Адрес сети:     ', net.network_address)
print('Broadcast:      ', net.broadcast_address)
print('Всего адресов:  ', net.num_addresses)
print('Доступно хостов:', net.num_addresses - 2)
hosts = list(net.hosts())
print('Первый хост:    ', hosts[0])
print('Последний хост: ', hosts[-1])

Вывод:

Сеть:            192.168.10.0/26
Маска:           255.255.255.192
Префикс:         /26
Адрес сети:      192.168.10.0
Broadcast:       192.168.10.63
Всего адресов:   64
Доступно хостов: 62
Первый хост:     192.168.10.1
Последний хост:  192.168.10.62

Маска /26 в десятичной форме — 255.255.255.192: 26 единиц, потом 6 нулей. Диапазон хостов 192.168.10.1192.168.10.62.

Шпаргалка по префиксам

ПрефиксМаскаВсего адресовХостов
/24255.255.255.0256254
/25255.255.255.128128126
/26255.255.255.1926462
/27255.255.255.2243230
/30255.255.255.25242

Правило: при каждом увеличении префикса на 1 число адресов делится пополам.

Деление сети на подсети

Частая задача: разбить сеть на несколько равных подсетей. Делим 10.0.0.0/24 на четыре /26:

import ipaddress

base = ipaddress.ip_network('10.0.0.0/24')
print('Делим', base, 'на подсети /26:')
for sub in base.subnets(new_prefix=26):
    h = list(sub.hosts())
    print(f'  {sub}  хосты {h[0]} - {h[-1]}')

Вывод:

Делим 10.0.0.0/24 на подсети /26:
  10.0.0.0/26  хосты 10.0.0.1 - 10.0.0.62
  10.0.0.64/26  хосты 10.0.0.65 - 10.0.0.126
  10.0.0.128/26  хосты 10.0.0.129 - 10.0.0.190
  10.0.0.192/26  хосты 10.0.0.193 - 10.0.0.254

Проверка: входит ли адрес в сеть

Ещё одна типовая задача — понять, принадлежит ли IP заданной сети (так работают firewall-правила):

import ipaddress

net = ipaddress.ip_network('172.16.0.0/16')
print('Проверяем адреса в сети', net)
for ip in ['172.16.5.9', '172.17.0.1', '192.168.0.1']:
    addr = ipaddress.ip_address(ip)
    print(f'  {ip:14} -> {"да" if addr in net else "нет"}')

Вывод:

Проверяем адреса в сети 172.16.0.0/16
  172.16.5.9     -> да
  172.17.0.1     -> нет
  192.168.0.1    -> нет

Итог

  • В подсети первый адрес — сеть, последний — broadcast; хостов на 2 меньше.
  • Модуль ipaddress считает маску, диапазон и число хостов за вас.
  • .subnets(new_prefix=N) делит сеть на равные подсети.
  • Оператор in проверяет принадлежность адреса сети.
Проверьте себя
1. Сколько хостов можно адресовать в подсети /26?
A64
B62
C26
D32
2. Что такое broadcast-адрес подсети?
AПервый адрес сети
BПоследний адрес (все биты хоста = 1), пакет на него идёт всем в подсети
CАдрес шлюза по умолчанию
DАдрес DNS-сервера
3. Какова маска для префикса /26?
A255.255.255.0
B255.255.255.128
C255.255.255.192
D255.255.255.224
4. Что вернёт выражение ip_address('172.16.5.9') in ip_network('172.16.0.0/16')?
ATrue
BFalse
CОшибку
DNone
Поддержать проект