суббота, 11 июля 2015 г.

Небольшие обновления Briseis и Dracon

Немного отвлекся от монстров в Diablo и обновил свои проекты Briseis и Dracon.

Dracon теперь умеет выгружать последний бекап из базы MongoDB. Если с коммутатора запросить у сервиса файл с именем backup, то будет выгружена последняя конфигурация для данного устройства (если она, конечно, ранее выгружалась в базу).

Еще удобно использовать переменную {$target}, которая будет заменена на IP-адрес коммутатора. Я добавил этот шаблон в конфиг:
config snmp system_name {$target}
И теперь по LLDP вижу не только MAC соседнего коммутатора, но и его IP (т.к. по LLDP передается system name)

Briseis теперь удобнее использовать для управления командами выгрузки и загрузки конфигурации, благодаря возможности сделать паузу между отправкой set-команд.

Я сделал такую последовательность SNMP-команд:
  1. Сохраняем конфигурацию в памяти коммутатора.
  2. Выгружаем конфигурацию на сервис Dracon.
  3. Получаем новую конфигурацию с сервиса Dracon.
Между каждой командой проходит 5 секунд, чтобы дать коммутатору время сделать свои дела и не получить ошибку с сообщением, что файловая система занята. Затем пишем в статистику, завершаем цикл и 2-3 секунды ждем до начала нового. Итого общее время на проход я выставил в 20 секунд. За раз из базы выбирается 10 коммутаторов. Получается в минуту сохраняются, бекапятся и обновляются 30 коммутаторов.

Как буду уверен, что новый конфиг применяется корректно, то обновлю все устройства по всей сети. Сейчас же обновил около трех сотен, для проверки самого механизма обновления через Briseis и Dracon.

пятница, 3 июля 2015 г.

Show log? No entry!

Случайно заметили проблему на коммутаторе DGS-3120-24SC - при попытке посмотреть лог командой show log устройство весело рапортовало No entry! Обновление ПО и перезагрузка не помогли. Решение, впрочем, нашлось довольно быстро при помощи Яндекса. Описано оно тут. Все, что нужно сделать, это выполнить команду clear log. Теме 6 лет, между прочим!

Очередной раз налицо подтверждение тому, что все новое - хорошо забытое старое. Век живи - век учись! :)

пятница, 19 июня 2015 г.

Разработка ACL для DES-3200-28/C1

Недавно наконец-то закончил разбираться с ACL-ками для ревизии C1. Коммутаторы DES-3200-28 этой ревизии являются самыми распространенными в моей сети - их число приближается к 900. Долгое время они не имели вообще никаких ACL - ситуацию спасали сегментация трафика и влан-на-коммутатор - но хотелось дополнительной защиты от потенциального спуфинга.

Итак, задачи, которые должны решать ACL:

  • Блокировка трафика от абонентов к сетям управления.
  • Блокировка определенных портов для предотвращения доступа к общим сетевым ресурсам.
  • Блокировка неправильных ARP-пакетов от абонентов (в целях предотвращения ARP-spoofing'а).
  • Блокировка IP-пакетов с поддельными SRC IP-адресами (IP-Spoofing) в целях предотвращения DDoS-атак и исчерпания пула NAT.
  • Отправка приоритетного трафика (телевидение) в определенную очередь (резервирование полосы пропускания).
  • Блокировка мультикаста от абонентов.
  • Разрешение любого трафика с порта (включается вручную).
На коммутаторах ревизии C1 логика работы ACL менялась в процессе разработки ПО. В результате этого не вся информация, приведенная на форумах и в официальных презентациях, является актуальной.

Сейчас все выглядит так:
  • На коммутаторе может быть всего 4 ACL профиля, причем 2 из них уже созданы - это Ethernet и IP.
  • Можно создать еще два профиля на выбор из набора Ethernet, IP, IPv6 и PCF, причем PCF профиль может быть всего один.
  • Кадр сопоставляется с правилами последовательно, так, как идут правила в профилях. Профили тоже проверяются последовательно. То есть все точно также, как и на других моделях.
  • В PCF правила можно добавлять до 4-х chunk по 4 байта каждый.
Ограничения по количеству профилей накладывают ограничения и на общую структуру правил. То есть, если один чанк уже был использован с одной маской, то именно в эту маску именно в этом профиле и придется уложить все правила, где проверяются соответствующие чанку байты.

Примечание: Соответствие chunk и байт смотри тут.

Короче говоря, написать любые нужные правила не сложно, но вот собрать их все вместе это еще то кунг-фу. В результате некоторые правила приходится делать не так, как хочется, а так, чтобы они могли ужиться с другими правилами.

Конкретно замедитировав, я остановился на следующей логике:
  1. Профиль #1 (vip): Безусловно разрешается трафик для нужных портов. Настраивается исключительно вручную и при необходимости.
  2. Профиль #2 (vlandscp): Разрешается трафик для управляющих и служебных сетей (коммутаторы, камеры, wi-fi). Меняется приоритет правильным мультикаст-группам.
  3. Профиль #3 (security): Запрещается мультикаст от абонентов и некоторые не очень хорошие TCP порты
  4. Профиль #4 (pcf): Запрещается трафик к служебным сетям от абонентов. Разрешаются только корректные ARP и source IP. Остальные ARP и IP для абонентов блокируются.

После разбирательств с QoS и идеи вообще не фильтровать трафик на служебных портах профиль №2 потерял свою актуальность. Здесь я оставлю его просто в качестве примера правил.

Профиль vip:
create access_profile profile_id 1 profile_name vip ethernet source_mac 00-00-00-00-00-00
#to manually allow any traffic for port X add following rule:
#config access_profile profile_name vip add access_id auto_assign ethernet source_mac 00-00-00-00-00-00 port X permit


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

create access_profile profile_id 2 profile_name vlandscp ip destination_ip_mask 255.255.248.0 vlan 0xFF0
#allow vlans with tag 0-15, 16-31 (management) 448-463, 464-479 (wi-fi), 576-591 (cams 586)
config access_profile profile_name vlandscp add access_id auto_assign ip vlan_id 1 port all permit
config access_profile profile_name vlandscp add access_id auto_assign ip vlan_id 16 port all permit
config access_profile profile_name vlandscp add access_id auto_assign ip vlan_id 448 port all permit
config access_profile profile_name vlandscp add access_id auto_assign ip vlan_id 464 port all permit
config access_profile profile_name vlandscp add access_id auto_assign ip vlan_id 576 port all permit
 

#replace priority on multicast groups in range 239.1.8.0/21
config access_profile profile_name vlandscp add access_id 64 ip destination_ip 239.1.8.0 port [up] permit priority 6 replace_dscp_with 48
config access_profile profile_name vlandscp add access_id 64 ip destination_ip 239.1.8.0 port [pu] permit priority 6 replace_dscp_with 48


Если профиль vip имел тип ethernet, то vlandscp имеет тип ip (оба эти профиля зарезервированы и уже созданы системой). В последнем случае профиль создан с destination_ip_mask для сетей /21 и диапазона из 16 vlan. Последнее достигается из-за использования бинарной/неполной маски 0xFF0.

Первые 5 правил разрешают трафик в 5 диапазонах из 16 служебных vlan. Следующие два правила отправляют телевидение в 6-ю очередь и переписывают метку dscp.

Повторюсь, от профиля vlandscp я отказался, в данном случае это всего лишь демонстрация правил.

Фактически весь трафик попадает под обработку только двух оставшихся профилей - security и pcf.

Профиль security:

create access_profile profile_id 3 profile_name security ip destination_ip_mask 240.0.0.0 tcp dst_port_mask 0xFFFF
#deny multicast from subscribers
config access_profile profile_name security add access_id auto_assign ip destination_ip 224.0.0.0 port [ss] deny
#deny TCP 135,139,445,2869,3587,5357,5358
config access_profile profile_name security add access_id auto_assign ip tcp dst_port  135 port [ss] deny
config access_profile profile_name security add access_id auto_assign ip tcp dst_port  139 port [ss] deny
config access_profile profile_name security add access_id auto_assign ip tcp dst_port  445 port [ss] deny
config access_profile profile_name security add access_id auto_assign ip tcp dst_port 2869 port [ss] deny
config access_profile profile_name security add access_id auto_assign ip tcp dst_port 3587 port [ss] deny
config access_profile profile_name security add access_id auto_assign ip tcp dst_port 5357 port [ss] deny
config access_profile profile_name security add access_id auto_assign ip tcp dst_port 5358 port [ss] deny


Сначала блокируется multicast с абонентских портов, после чего блокируются некоторые не очень нужные абоненту TCP-порты. В моем случае блокировка TCP-портов несколько избыточна, но я решил оставить ее на всякий случай. Остальной трафик для обнаружения сетевых ресурсов будет заблокирован из-за сегментации трафика, ACL на маршрутизаторе и vlan, ограничивающегося коммутатором.

Ну и самый интересный профиль - pcf:
create access_profile profile_id 4 profile_name pcf packet_content_mask offset_chunk_1 3 0xFFFF offset_chunk_2 7 0xFFFFFEF8 offset_chunk_3 8 0xFFF80000
#deny networks 172.16.0.0/13 and 10.99.0.0/13 for subscribers
config access_profile profile_name pcf add access_id 8 packet_content offset_chunk_1 0x0800 offset_chunk_3 0xAC100000 port [ss] deny
config access_profile profile_name pcf add access_id 9 packet_content offset_chunk_1 0x0800 offset_chunk_3 0x0A600000 port [ss] deny
#allow specific source network (10.XX.YY.port_N*8 0.0.1.7) for a customer
config access_profile profile_name pcf add access_id
auto_assign packet_content offset_chunk_1 0x0800 offset_chunk_2 0x0A(fn_2oct#custom1)(fn_3oct#custom1)08 port  [ss#1] permit
config access_profile profile_name pcf add access_id
auto_assign packet_content offset_chunk_1 0x0800 offset_chunk_2 0x0A(fn_2oct#custom1)(fn_3oct#custom1)10 port  [ss#2] permit
...
#permit ARP with correct 4th octet (between port_N*8 and port_N*8+7)
config access_profile profile_name pcf add access_id
auto_assign packet_content offset_chunk_1 0x0806 offset_chunk_3 0x(fn_3oct#custom1)080000 port  [ss#1] permit
config access_profile profile_name pcf add access_id auto_assign packet_content offset_chunk_1 0x0806 offset_chunk_3 0x(fn_3oct_p1#custom1)080000 port  [ss#1] permit
config access_profile profile_name pcf add access_id auto_assign packet_content offset_chunk_1 0x0806 offset_chunk_3 0x(fn_3oct#custom1)100000 port  [ss#2] permit
config access_profile profile_name pcf add access_id auto_assign packet_content offset_chunk_1 0x0806 offset_chunk_3 0x(fn_3oct_p1#custom1)100000 port  [ss#2] permit

...
#deny IP
config access_profile profile_name pcf add access_id 254 packet_content offset_chunk_1 0x0800 port [ss] deny
#deny ARP
config access_profile profile_name pcf add access_id 255 packet_content offset_chunk_1 0x0806 port [ss] deny


Обратите внимание на используемые чанки и их маски: offset_chunk_1 3 0xFFFF, offset_chunk_2 7 0xFFFFFEF8 и offset_chunk_3 8 0xFFF80000.

В этом профиле мы фильтруем ethertype, ip src, ip dst, arp src. Посмотрим на расположение этих данных в структуре кадра:
ethertype - байты 12  и 13
arp src ip - байты 28, 29, 30 и 31
ip src - байты 26, 27, 28  и 29
ip dst - байты 30, 31, 32 и 33

Поэтому согласно приведенной выше таблице нас интересуют чанки №3, №7 и №8, которые включают в себя все нужные нам байты. Самое забавное в нашей ситуации то, что arp src ip находится "между" чанками 7 и 8, т.е. захватывает вторую половину 7 чанка и первую половину 8-го чанка. При этом, как я уже упоминал выше, мы можем использовать каждый чанк только 1 раз. Поэтому придется строить правила с учетом этого нюанса.

Разберем что именно нам надо описать в правилах:
В сети каждому абоненту выдается диапазон адресов /29, основанный на номере порта. При этом первый бит третьего октета IP-адреса может меняться на единичку. Исторически это использовалось для блокирования должников. При этом сама сеть, в которую попадают абоненты одного коммутатора, имеет маску /23.

Это будет лучше понятно на примере:
Если абонент подключен в порт №1 и для абонентов этого коммутатора выделена сеть 10.128.4.0/23, то правильными адресами для абонента будут 10.128.4.8/29  и 10.128.5.8/29.
Аналогично для 10-го порта и сети 10.133.56.0/23 - соответственно 10.133.56.80/29 и 10.133.57.80/29.

Как нетрудно догадаться, такая схема описывается маской 0xFFFFFEF8. В бинарном представлении последние два байта здесь будут выглядеть как 0b11111110 и 0b11111000. Если кто забыл, это, фактически, инверсия cisco wildcard mask, где биты, соответствующие нулевым битам маски, игнорирутся.

Таким образом мы разобрались с одной маской для IP SRC (чанк 7) - это 0xFFFFFEF8. Теперь аналогичным образом нужно описать ARP. Но ARP SRC IP смещен на 2 байта по отношение к IP SRC и самые интересный нам байты попадают уже в чанк 8. Это байты с номерами 30 и 31. А вот остальные 2 байта нам уже не нужны. Отсюда наша маска для чанка 8 должна была бы быть 0xFEF80000. Однако, согласно техзаданию нам надо блокировать еще доступ и к сетям управления, которые в нашем случае описываются как 172.16.0.0/15 и 10.99.0.0/16. Как видно, 172 и 10 - это байт №30, а 16 и 99 - байт №31, т.е. те же самые байты, которые мы пытаемся описать для ARP SRC IP. И если для байта №31 мы еще можем позволить себе забрать дополнительные 8 адресов (т.к. это локальные адреса), то забирать по 1 дополнительному адресу для байта №30 было бы слишком роскошно. Отсюда вывод: использовать маску 0xFFFFFFF8 и описывать ARP двумя правилами - с жестко заданными третьим октетом X и X+1.*

Ну и чтобы отделять мух от котлет ARP от IP нам потребуется знать ethertype. Его задаем жестко, поэтому используем маску 0xFFFF (0x0000FFFF).

* Эту "мелочь" я обнаружил уже в процессе написания заметки. Изначально я забыл про "нечетный" третий октет для ARP. Все-таки полезно иногда писать такие статьи и заново все разбирать. :)

Итак, первые два правила запрещают доступ к 172.16.0.0/13 и 10.99.0.0/13. Такая избыточная маска получается из-за упомянутых выше ограничений. С этим придется мириться, ага.

Потом одним правилом разрешаем абонентский блок 10.XX.YY.port_N*8 0.0.1.7 (и YY+1).

Далее двумя правилами разрешаем валидные ARP-пакеты.

И последними двумя правилами запрещаем остальные IP и ARP от абонентов.

Ну и в конце классика жанра:
enable cpu_interface_filtering

create cpu access_profile profile_id 1 ip destination_ip_mask 255.255.255.255
config cpu access_profile profile_id 1 add access_id 1 ip destination_ip 224.0.0.2 port all permit

create cpu access_profile profile_id 2 ip destination_ip_mask 255.255.248.0
config cpu access_profile profile_id 2 add access_id 1 ip destination_ip 239.1.8.0 port all permit

#deny multicast-query for subscribers
create cpu access_profile profile_id 3 ip destination_ip_mask 240.0.0.0
config cpu access_profile profile_id 3 add access_id 1 ip destination_ip 224.0.0.0 port [ss] deny


И еще:
config cpu_filter l3_control_pkt [all] all state disable
config cpu_filter l3_control_pkt  [ss] all state  enable


Этим мы запрещаем всякие служебные пакетики от абонентов, не попадающие под обычные ACL, но разрешаем возможность отписываться от мультикаст-групп.

P.S. Правила в процессе обкатки, пока ни один пользователь не пострадал, но, возможно, я что-то еще поменяю.

P.P.S. О конструкциях типа [ss], [all] и (fn_3oct#custom1) можно прочитать на странице сервиса генерации конфигов Dracon.

среда, 17 июня 2015 г.

Dracon - сервис генерации конфигурационных файлов 'на лету'

Выложил на гитхаб Dracon. Это виртуальный TFTP-сервер, который хранит в своей памяти информацию о коммутаторах и портах и по запросу выдает конфигурацию на основе этих данных и предварительно сгенерированного шаблона.

В самом шаблоне при этом можно писать что-то вроде:
config ports [ss] state enable

Где [ss] при выгрузке заменяется на нужный диапазон портов.

Можно использовать собственные функции, например для подстановки в ACL нужных IP или MAC адресов.

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

Проще говоря, если вдруг поменялся uplink, добавилась новая магистраль или подключился VIP-клиент со специфичными настройками порта - просто правим нужные свойства в биллинге и запрашиваем с коммутатора новый конфиг у Dracon.

пятница, 29 мая 2015 г.

Обновлены примеры ACL правил для ревизии C1

Обновил примеры правил на этой странице.

Хочу сказать что ревизия C1 нравится мне все больше и больше. Просто новые модели коммутаторов D-Link надо использовать через пару лет после их появления, когда все устаканится, а баги будут выпилены.

Неудобно, правда, что в этой ревизии можно использовать только 1 PCF профиль. Ладно бы, если бы можно было использовать большое число чанков, но нет! Текущее ограничение в 4 чанка по 4 байта не позволяет реализовать мои хотелки. Так что придется выкручиваться.

На следующей неделе планирую закончить разработку правил и составить разбор на тему "что как и почему".

понедельник, 25 мая 2015 г.

Конференция в jabber

От скуки зарегистрировал конференцию в джаббере - ccna@conference.jabber.ru.

Собираюсь присутствовать там в рабочее время и, иногда, по вечерам. Заходите, пообщаемся, обсудим нюансы сетестроения. :)

p.s. Из новостей - плотно взялся за PCF ACL на коммутаторах DES-3200-xx/C1. Через пару недель поделюсь результатами.

пятница, 3 апреля 2015 г.

Перезагрузка коммутаторов при помощи Briseis

Продолжим использовать Briseis не по назначению. :) В прошлой заметке мы научились массово обновлять прошивку на коммутаторах, а теперь отправим все перепрошитые коммутаторы в перезагрузку. Будем считать, что мы продолжаем работы, описанные в прошлый раз, так что остановлюсь на самом главном.

В любом месте файла userdict.py определяем списки OID для формирования varbind:

reboot3028 = [
    ['.1.3.6.1.4.1.171.11.63.6.2.1.2.1','0','3','INTEGER']
]

reboot3200 = [
    ['.1.3.6.1.4.1.171.11.113.1.3.2.1.2.1','0','3','INTEGER']
]

reboot3200_c1 = [
    ['.1.3.6.1.4.1.171.12.1.2.19','0','2','INTEGER']
]


reboot_01_04 = [
    ['1.3.6.1.4.1.171.12.1.2.32.1.3','1','\x05\x05','OCTETSTR'],
    ['1.3.6.1.4.1.171.12.1.2.32.1.4','1','\x01\x04\x07\xdf','OCTETSTR'],
    ['1.3.6.1.4.1.171.12.1.2.32.1.5','1','1','INTEGER']
]


Первые 3 списка нужны для мгновенной перезагрузки коммутатора, а 4-й позволяет выполнить отложенную перезагрузку коммутаторов DES-3200-28 ревизии C1.

Теперь в файле bconfig.py исправляем 'PassSetSet' на:
PassSetSet  = {1:['reboot']}

А 'oids_set' на:
oids_set={
    'DES-3200-28':{
       'reboot':reboot3200
    },
    'DES-3200-28/C1':{
        'reboot':reboot3200_c1
    },
    'DES-3028':{
       'reboot':reboot3028
    }
}


Для модели DES-3200-28/C1 при желании можем использовать отложенную перезагрузку, заменив значение 'reboot3200_c1' на 'reboot_01_04'. Поскольку 1-е апреля уже прошло, то есть смысл заменить '\x01\x04' на желаемую дату. Кстати, дата в команде дана скорее для примера оформления hex-значений для net-snmp в Python. На самом деле достаточно указывать только время:
delayed reboot = [
    ['1.3.6.1.4.1.171.12.1.2.32.1.3','1','\x05\x05','OCTETSTR'],
    ['1.3.6.1.4.1.171.12.1.2.32.1.5','1','1','INTEGER']
]

Такой набор позволит планировать перезагрузку в любой день без правки словаря. Перезагрузка произойдет когда часы в следующий раз покажут 5:05.

Закончим это небольшое, но весьма полезное отступление и запустим программу:
./briseis.py start

Не забудем и остановить ее через несколько секунд:
./briseis.py stop

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