Пользователь
5,6
рейтинг
1 ноября 2011 в 19:21

Администрирование → Обратная маска из песочницы

Существующая маска для IP адреса выросла из классового деления адресов, на заре эпохи IP:
Класс A: 8 бит для номера сети 24 бита для номера хоста
Класс B: 16 бит на сеть и 16 бит на хост
Класс C: 24 бита на сеть 8 бит на хост

Когда стало слишком расточительным делить адреса подобным образом появилась маска, представляющая собой 32-х битное (из стольких же бит состоит и IP адрес) поле из подряд идущих единиц с начала поля, и после подряд идущих нулей. Единицы определяют те биты в IP адресе которые формируют номер сети, нули те биты в адресе которые формируют номер хоста.
IP адрес, десятичное:     10.      10.       0.       1
IP адрес, двоичное: 00001010.00001010.00000000.00000001
Маска, двоичное:    11111111.11111111.11111100.00000000
Маска, десятичное:       255.     255.     252.       0

Представление маски подобным образом, вполне, соотносится с термином битовой маски, т.е. единицы и нули определяют действия над конкретными битами в исходном числе, но плохо соотносится с форматом IP адреса – номер сети всегда определяется битами вначале, номер хоста битами в конце. Поэтому представление маски в виде 32-х битного поля является избыточным. Для однозначного определения маски можно определить только количество подряд идущих единиц с начала IP адреса от 0 до 32 – префиксное обозначение, обычно записывается через дробь после IP адреса: для примера выше 10.10.0.1/22 – 22 бита номер сети и 32-22=10 бит номер хоста. Если говорит про IPv6 адрес, то там определяется только префиксная запись маски/адреса – 2001:d8:a15e::1/48

Теперь представим маску таким образом, чтобы единицы определяли те биты в IP адресе которые формируют номер хоста, а нули те биты которые формируют номер сети, в результате получаем инверсную маску:
IP адрес, десятичное:            10.      10.       0.       1/22
IP адрес, двоичное:        00001010.00001010.00000000.00000001
Маска, двоичное:           11111111.11111111.11111100.00000000
Инверсная маска, двоичное: 00000000.00000000.00000011.11111111
Маска, десятичное:              255.     255.     252.       0
Инверсная маска, десятичное:      0.       0.       3.     255

Это то что умеет делать любой, или почти любой, сетевой калькулятор, здесь не двоичная арифметика, точнее не арифметика, а базовые манипуляции по переводу чисел между системами счисления.

Получение инверсной маски из прямой, и обратное действие осуществляется инвертированием битового поля – замена 0 на 1, а 1 на 0. Если использовать десятичное представление то получение инверсной маски вычисляется следующим образом: от 255 отнимается число соответствующее значению октета в прямой маске, для примера выше:
  255.255.255.255
- 255.255.252.  0
=   0.  0.  3.255

Перевод из инверсной в прямую, также производится вычитанием из 255 значение октета соответствующего инверсной маске:
  255.255.255.255
-   0.  0.  3.255
= 255.255.252.  0

Используя термин инверсная маска, я умышленно исказил общепринятое название русскоязычного термина – обратная маска (invers mask, wildcard mask) – потому что обратная маска это гораздо более мощный механизм чем просто другое обозначение битов для нумерации сети и хоста в IP адресе. Обратная маска не обязана содержать подряд идущие единицы или нули, и единицы это не просто обозначение области хоста в IP адресе. Единицы это обозначение битов в IP адресе, которые могут меняться при проверке условий, а нули фиксируют неизменные биты. То есть русскоязычный термин обратная маска больше соответствует «wildcard mask», нежели «invers mask», хотя в технической документации употребляется оба в одинаковых смыслах.

Область применения обратной маски это условные операции с IP адресами в cisco like интерфейсе и идеологии (не только cisco устройства). К этим областям относятся в частности списки доступа (ACL) – позволяет создавать не просто условия хост из этой сети, а гораздо более гибкие правила и определение сетей, а также в конфигурировании протоколов маршрутизации, OSPF например – позволяет создавать компактные правила для анонса не подряд идущих сетей.

Решим задачу запрета доступа с нечётных хостов из сети 192.168.0.0/24 куда либо. Если в нашем распоряжении есть только прямая маска, то нам надо составить правило на каждое из нечётных чисел в этой сети. От 192.168.0.1 до 192.168.0.253. IP 192.168.0.255 является широковещательным адресом и нам его обрабатывать не надо. Получаем (в нотации cisco):
access-list 101 deny ip 192.168.0.1 255.255.255.255 any
(255.255.255.255 можно заменить на специально слово host, сделаем это)
access-list 101 deny ip host 192.168.0.1 any
access-list 101 deny ip host 192.168.0.3 any
access-list 101 deny ip host 192.168.0.5 any
access-list 101 deny ip host 192.168.0.7 any
…
access-list 101 deny ip host 192.168.0.93 any
…
access-list 101 deny ip host 192.168.0.253 any
access-list 101 permit ip any any

Итого: 128 строчек.

В конце мы разрешили доступ всему что мы не запретили. Теперь надо ассоциировать этот ACL с нужным интерфейсом, Fa0/1 например:
int fa0/1
ip access-group 101 in

Попробуем сократить полученный ACL, используя то свойство, что нечётное число в двоичном представлении всегда имеет значение 1 в нулевом разряде.
192.168.0.0 =  11000000.10101000.00000000.0000000|0 - чёт.
192.168.0.1 =  11000000.10101000.00000000.0000000|1 - не чёт.
192.168.0.2 =  11000000.10101000.00000000.0000001|0 - чёт
192.168.0.3 =  11000000.10101000.00000000.0000001|1 - не чёт
192.168.0.4 =  11000000.10101000.00000000.0000010|0 - чёт
192.168.0.5 =  11000000.10101000.00000000.0000010|1 - не чёт
192.168.0.6 =  11000000.10101000.00000000.0000011|0 - чёт
192.168.0.93 = 11000000.10101000.00000000.0101110|1 - не чёт

Используем обратную маску, напомню, что 1 – биты которые могут меняться, 0 которые не могут. Маска /24 = 255.255.255.0 в инверсной маске имеет 0.0.0.255 или 00000000.00000000.00000000.11111111. То есть последний октет может меняться во всех битах, но мы знаем что 0 бит надо оставить неизменным, поэтому изменим обратную маску следующим образом: 00000000.00000000.00000000.11111110 или 0.0.0.254. Заметим что если мы преобразуем эту запись в прямую маску, по правилам для инверсной маски то получится 255.255.255.1, что является неверной записью для маски, и с этим сетевой калькулятор уже не справится (или я их не видел).

Значит наша сеть 192.168.0.0/24 должна в последнем октете нулевом бите всегда иметь 1, то есть 192.168.0.1 с обратной маской 0.0.0.254.
Сеть 192.168.0.1, двоичное:         11000000.10101000.00000000.00000001
Обратная маска 0.0.0.254, двоичное: 00000000.00000000.00000000.11111110

Единицы в обратной маске это изменяемые биты в адресе — это биты в последнем октете со 1 по 7, с их использованием и нулевым битом всегда равным единице, мы можем составить любое нечётное число от 1 до 255.

Теперь напишем ACL, т.к. значение IP 192.168.0.255, имеет специальный смысл, разрешим его в первой строчке, иначе оно тоже будет запрещено:
access-list 101 permit ip host 192.168.0.255 any
access-list 101 deny ip 192.168.0.1 0.0.0.254 any
access-list 101 permit ip any any

Итого: 3 строчки вместо 128, можно сказать «Ого!».

Усложним задачу, нечётным должен быть предпоследний октет в подсетях 192.168.0.0/16. То есть для сетей 192.168.1.0/24, 192.168.3.0/24 и т.д. доступ надо закрыть. Изменим нашу обратную маску – инверсная маска для /16 = 0.0.255.255, предпоследний октет, мы по аналогии с первым примером сделаем 254, итого получим 0.0.254.255. И наши сети должны иметь нечётный предпослений октет 192.168.1.0 с обратной маской 0.0.254.255.
Сеть 192.168.1.0, двоичное:           11000000.10101000.00000001.00000000
Обратная маска 0.0.254.255, двоичное: 00000000.00000000.11111110.11111111

И наш ACL, предварительно разрешим IP 192.168.255.255 имеющий специальный смысл:
access-list 101 permit ip host 192.168.255.255 any
access-list 101 deny ip 192.168.1.0 0.0.254.255 any
access-list 101 permit ip any any

А теперь сделаем так чтобы в нечётных подсетях 192.168.0.0/16 в предпоследнем октете должны быть запрещены хосты (числа в последнем октете) с 1 по 63. Задачу с запрещением нечётных предпоследних октетов мы решили в примере выше, теперь посчитаем хосты с 1 по 63. 63 в двоичном представлении равно 111111, следовательно нам надо выбрать числа от 00000001 до 00111111. Предыдущая обратная маска 0.0.254.255 выбирала все числа в последнем октете, то есть могли меняться все 8 бит, нам надо менять всего лишь 6 бит, т.е числа от 0 до 63, итого для последнего октета мы имеем запись 00111111 и вся маска 0.0.254.63.
Сеть 192.168.1.0, двоичное:          11000000.10101000.00000001.00000000
Обратная маска 0.0.254.63, двоичное: 00000000.00000000.11111110.00111111

Значение хоста 0, для нечётных предпоследних октетов, мы разрешим отдельным правилом ACL, т.к они по условию задачи не должны быть запрещены. Для этого случая обратная маска в последнем октете должна жёстко задать одно число, то есть ни один из битов не должен меняться, значит этот октет в обратной маске будет 0.
Сеть 192.168.1.0, двоичное:         11000000.10101000.00000001.00000000
Обратная маска 0.0.254.0, двоичное: 00000000.00000000.11111110.00000000

И наш ACL, правила permit со значением 255 в последнем октете у нас нет, т.к. в запрещающее правило это значение не попадает:
access-list 101 permit ip 192.168.1.0 0.0.254.0 any
access-list 101 deny ip 192.168.1.0 0.0.254.255 any
access-list 101 permit ip any any

В качестве закрепления материала, можно попробовать составить последний ACL с использованием только инверсной маски (т.е. где 0 и 1 идут строго подряд, в начале и соответственно в конце записи), и посчитать выгоду в количестве строчек.

Возможный вопрос, что делать если надо запретить чётные сети: в чётных числах нулевой бит всегда равен 0, соответственно вместо единички ставим 0. Для первого примера, всё тоже, но чётные хосты:
Сеть 192.168.0.0, двоичное:         11000000.10101000.00000000.00000000
Обратная маска 0.0.0.254, двоичное: 00000000.00000000.00000000.11111110

ACL короче, потому что IP 192.168.0.255, не попадает в запрещёные:
access-list 101 deny ip 192.168.0.1 0.0.0.254 any
access-list 101 permit ip any any

Очень много споров слышал по поводу: насколько часто данный механизм применяется на практике. За 4 года работы в отрасли применял только один раз, но этот раз позволил сократить ACL с несколько тысяч записей, если бы использовались стандартные маски (или просто инверсия к стандартной маске) до одной, собственно пример этого есть выше.

Данный пост навеян habrahabr.ru/blogs/sysadm/129664 в котором не нашёл для себя раскрытия описанной темы, спасибо его автору за вдохновение. Про ACL и маски для маршрутизаторов cisco можно почитать на сайте cisco (на английском): www.cisco.com/en/US/products/sw/secursw/ps1018/products_tech_note09186a00800a5b9a.shtml
Михаил Васильев @Loiqig
карма
30,0
рейтинг 5,6
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Администрирование

Комментарии (21)

  • 0
    На Linux не работает(
    ip route add 10.0.0.0/0.0.0.254 via gretunnel

    Error: an inet prefix is expected rather than "10.0.0.0/0.0.0.254".
    route реагирует примерно также.
    • +2
      Это потому что автор не слишком разъясняет тот момент, что маска подсети (то есть, определение того, какая часть адреса — это номер сети, а какая — номер хоста) всегда бывает только обычной, в которой сначала идёт непрерывная последовательность единиц, а потом — нулей, а то, про что рассказывается в статье — это не маски подсетей, а способ выделения нужных нам адресов из какого-то их множества.
      • 0
        В RFC1519 про непрерывность нигде явно не говорится, просто он устарел, поэтому поддерживается частично.
        • 0
          Вот именно, что он устарел и заменён на RFC4632, в котором вообще понятие маски подсети выводится из употребления и заменяется на длину префикса.
    • 0
      Описанные маски точно работают на маршрутизаторах и L3 коммутаторах Cisco и Brocade(Foundry), конкретно про soft-router не могу сказать потому что ни разу не работал с ними в продакшн.
  • +5
    Честно говоря, не могу себе представить РЕАЛЬНОГО сценария применения рваных масок. Если вы до этого докатились, значит допустили ошибку еще раньше на стадии проектирования сети =)
    • 0
      а если рассмотреть вариант — так уже было и осталось по наследству? :)
      • 0
        В свое время вопрос наследия решился плавной миграцией с выпиливанием того, что было)
    • 0
      Обслуживать приходится сети реального, а не идеального мира.

      Я использовал рваные маски для рандомизации NATа вручную — нескольких тысяч внутренних адресов транслировал на 64 внешних адреса. Внутренние адреса распределялись неравномерно:
      в 172.17.0.0/16 использовалось ~200 начальных,
      в 172.18.0.0/16 ~1000,
      в 172.19.0.0/16 ~2000,
      в 172.20.0.0/16 ~500,
      и тд без какой-то закономерности.

      NAT делал так:
      0.0.0.0/0.0.0.252 -> IP0
      0.0.0.4/0.0.0.252 -> IP1
      0.0.0.8/0.0.0.252 -> IP2

      0.0.0.252/0.0.0.252 -> IP63
      Вроде не напутал…

      Вся конструкция помещалась в цепочку-контейнер для выделения транслируемого диапазона 172.16.0.0/12. Исполнялось на iptables без малейших сложностей.
      • 0
        Мощно) подозреваю, что есть способ автоматической рандомизации ;)
        • 0
          вот его и чинил ломал
    • 0
      Реально я так распределяю юзеров на 2 НАТ-сервера: на один всех четных, на второй — не четных.
    • 0
      Например, реальный используемый сценарий: абоненту выделяется сеть на 8 адресов (чтобы он мог использовать дома не роутер, а простой коммутатор и подключать несколько устройств, соответственно). Если баланс в плюсе, то выделяется сеть с 1 по 7, если не в плюсе то 9 до 15. То есть подсети с 3 битом равным 1, должны иметь доступ только к сайту статистике, и возможно каким-то внутренним ресурсам.
      Сеть 192.168.0.0/16 бьём на 2-е части следующим образом: 192.168.0.8/0.0.255.247 — 11110111 в последнем октете.
      • 0
        Почему в случае неуплаты не выделить ему совсем другую подсеть? (я так понимаю, настройки он получает по DHCP?)
        • 0
          Если выделяем другую сеть, мы теряем возможность привязки к пользователю его личной, неизменной, сети в одну строчку с более короткой маской /28, где половинки /29 характеризуют его как безденежного и денежного. На одном L3 интерфейсе находится множество пользователей и применение способа комментарием выше позволяет определить сразу всех разрешённых или запрещённых пользователей, сохраняя при этом свойство описанное в первом предложении.
          Но вообще конечно вы правы, насчёт прямоты архитектуры, вот только чтобы мигрировать плавно и безболезненно иногда приходится придумывать странные решения.
  • +1
    Зачем было инвертировать маску, когда можно было изначально вместо упакованной /n нотации для маски применять развёрную a.b.c.d нотацию с её исходной интерпретацией 0/1 бит? (1 — сеть, 0 — хост) Т.е. не раскрыт смысл инверсии, все эти танцы с пропусканием чётных хостов реализуемы и без XOR'ов
    • 0
      имеется в виду без XOR'ов по битам неинверсной маски
    • 0
      Инверсная маска это всего лишь способ записи реализованный в реальных и конкретных устройствах, с помощью которого были составлены примеры. Про другой способ очень хочется узнать, возможно мой действительно громоздкий и мозголомный.
  • 0
    Речь не про ваш способ, а про способ реализованный в этих самых устройствах. Непонятно, зачем было в них городить огород с заменой 0 и 1 битов. А ваше повествование просто очень наглядно демонстрирует странность этой замены — сначала мы делаем вывод, что a.b.c.d запись избыточна по отношению к /n записи, т.к. в маске вначале только биты1, а в конце только биты0. Потом рассматривается инверсия, у которой биты ведут себя наоборот, и в классической /n форме она непредставима (правда представима в гибридной /-n форме). А потом вместо того чтобы забить болт и на ненужную инверсию вместе с неуниверсальной /n нотацией, мы зачем-то юзаем a.b.c.d на инверсной форме, а не на прямой.
    • 0
      Очень много поправили и сделали лучше в IPv6, там более последовательное определение, на ошибках учатся. Такая непоследовательность ведь во многих отраслях присутствует…
      … про обратную маску для IPv6, пока ничего не знаю — не приходилось.
  • 0
    «ненормальное системное администрирование»

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.