Prefix hijacking. Используем RPKI для борьбы с потерей трафика

Admin

Original poster
Administrator
Сообщения
916
Реакции
753
Посетить сайт
images.jpg
Инциденты с prefix hijacking случаются регулярно, когда трафик массово отправляется не тем путем, которым должен. Некоторые из них, может, и связаны со злым умыслом, но большинство случайны и происходят по вине невнимательных админов. Сегодня я расскажу, как провайдеры могут предотвратить их или свести к минимуму, а заодно и как самому не стать их виновником.​
Суть проблемы
Протокол маршрутизации BGP сам по себе не содержит никакой информации о том, кому принадлежит та или иная сеть. Анонсировать чужие префиксы при этом вполне обычная практика — небольшие сети анонсируют свои сети транзитным провайдерам с развитой сетью, а те уже анонсируют их всем остальным. Кроме того, на точках обмена трафиком активно используются так называемые сервера маршрутов (route servers), которые позволяют получать маршруты ко всем сетям участников точки сразу, без настройки отдельной сессии с каждым из них.

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

Авторизируйтесь или Зарегистрируйтесь что бы просматривать ссылки.

, к примеру, принципиально не позволяет даже фильтровать входящие маршруты: поскольку каждый маршрутизатор OSPF строит и поддерживает полную карту соединений в сети, отказ одного маршрутизатора запоминать часть сети может нарушить ее связь со всеми остальными. Протоколы с отслеживанием состояния каналов (link-state) вроде OSPF прекрасно подходят для внутренней маршрутизации, где на выбор пути влияют только технические соображения: длина пути и его пропускная способность.

Поскольку интернет — объединение независимых сетей, в силу вступают экономические и политические факторы. Самый короткий путь не всегда самый выгодный. Из-за этого реализации BGP вынужденно позволяют такие виды фильтрации и модификации анонсов, которые неприемлемы в других протоколах.

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


Фильтрация исходящих анонсов
Прежде чем рассматривать механизмы защиты от чужих ошибок, давай рассмотрим, как не стать виновником инцидента самому.

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

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

Предположим, есть вот такой конфиг:
Код:
router bgp 64496
  network 192.0.2.0/24

  neighbor 203.0.113.10 remote-as 64500
  neighbor 203.0.113.10 description AwfulTransit
Диапазон номеров автономных систем 64496–64511 зарезервирован для примеров и документации в

Авторизируйтесь или Зарегистрируйтесь что бы просматривать ссылки.

. Он не совпадает с диапазоном для частного использования (64512–65534). Разница такая же, как между диапазоном адресов IPv4 для частного использования из

Авторизируйтесь или Зарегистрируйтесь что бы просматривать ссылки.

и сетями 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24 (TEST-NET-[123]).

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

Мы анонсируем провайдеру сеть 192.0.2.0/24. Провайдер анонсирует нам все маршруты интернета. В этой ситуации никакие фильтры не нужны, потому что ни один протокол маршрутизации не анонсирует полученные от соседа маршруты обратно ему же. Это базовый механизм предотвращения петель маршрутизации.

В то же время все протоколы, включая BGP, анонсируют все маршруты всем остальным соседям, если не указано обратное. Чем больше связность сети и число альтернативных маршрутов к каждой сети, тем она надежнее. Если, конечно, все участники могут и согласны пропускать через себя этот трафик — а клиенты провайдеров не готовы и не согласны.

Предположим, что ты добавил подключение ко второму провайдеру:
Код:
router bgp 64496
  neighbor 203.0.113.20 remote-as 64510

С такими настройками твой маршрутизатор начнет анонсировать маршруты одного провайдера другому.
Чтобы этого не произошло, нужно явно указать, что анонсировать.
Если у тебя всего один маршрутизатор BGP и все маршруты приходят из какого-то внутреннего протокола или опций network, проще всего отфильтровать по пустому AS path. Номер автономной системы добавляется в путь маршрута не в момент его зарождения, а в момент анонса, поэтому у локально порожденных маршрутов он пустой. Пустой строке соответствует регулярное выражение ^$.
Код:
bgp as-path access-list LocalOnly permit ^$
!
route-map LocalOnly permit 10
 match as-path LocalOnly
!
Если у тебя есть свои клиенты или маршруты по иной причине приходят опять же из BGP, то придется фильтровать явно, с помощью prefix-list.

На практике в случае с клиентом и провайдером при утечке таблицы провайдер автоматически отключит сессию клиента или проигнорирует лишние маршруты. Успешный захват префиксов обычно происходит между равноправными сетями: транзитными провайдерами или участниками точки обмена трафиков.

Как провайдеры это предотвращают? Самая простая и неспецифичная мера защиты — опция maximum-prefix.


Опция maximum-prefix
Эта опция делает ровно то, о чем говорит ее название. Если количество сетей в анонсе соседа превышает указанное значение, сессия автоматически обрывается и соседу отправляется BGP notification.

В FRR это делается вот так:
Код:
router bgp 64500
  address-family ipv4 unicast
    neighbor 192.0.2.10 maximum-prefix 1
Очевидный недостаток: нарушение политики со стороны клиента обрывает всю связь с провайдером. Добавление новой сети или разделение существующей на части становится для клиента весьма рискованной операцией, для которой нужно уведомить провайдера и дождаться его подтверждения перед тем, как менять настройки.


Альтернативы
Увы, все альтернативы в рамках самого BGP — либо немасштабируемые, либо чисто эвристические.

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

Например, разрешим принимать от клиента сети 192.0.2.0/24 и 203.0.113.0/24 вместе со всеми их подсетями вплоть до /32:
Код:
!
ip prefix-list MyPrefixes seq 10 permit 192.0.2.0/24 le 32
ip prefix-list MyPrefixes seq 20 permit 203.0.113.0/24 le 32
!
route-map Transit-Out permit 10
 match ip address prefix-list MyPrefixes
!
router bgp 64500
 neighbor 198.51.100.1 remote-as 64501
 !
 address-family ipv4 unicast
  neighbor 198.51.100.1 route-map Transit-Out out
 exit-address-family
!
Другой вариант — фильтрация по максимальной длине AS path. По аналогии с пустым путем локальных маршрутов из фильтра для исходящего направления мы можем разрешить на стороне провайдера все маршруты, у которых путь состоит из ровно одной AS, — с помощью регулярного выражения ^([0-9]+)(_\1)*$. Это автоматически исключит маршруты, которые пришли к нашему соседу извне, а не были порождены им самим. Очевидно, это защитит только от случайных ошибок, а не намеренных попыток анонсировать чужую сеть.

Почему не [0-9]+? Многие люди для контроля за тем, через какого провайдера к ним пойдет входящий трафик, используют опцию AS path prepend, которая искусственно делает путь длиннее, чем он есть, поскольку добавляет в него локальную автономную систему несколько раз. Выражение, которое соответствует пути из ровно одного номера AS, запретило бы такие анонсы.

Ни один из этих вариантов не подходит для пиринга между провайдерами или участниками точек обмена трафиком. Знать содержимое анонсов наперед в этих случаях невозможно, нужно проверять именно аутентичность анонсов.

Сам BGP используется еще с девяностых, но механизм для проверки аутентичности анонсов появился недавно и называется

Авторизируйтесь или Зарегистрируйтесь что бы просматривать ссылки.

(RPKI).
RPKI
RPKI — сравнительно новый механизм, который позволяет автоматически проверять принадлежность префиксов к автономным системам.

RPKI не является частью BGP и не ограничивается им. По сути, это эквивалент whois с цифровыми подписями и набором протоколов для их автоматической проверки. Подписывать сами анонсы было бы бессмысленно, поскольку их модификация при передаче неизбежна — каждый маршрутизатор должен добавить в AS path свой номер автономной системы. Вместо этого BGP origin validation проверяет соответствие адреса сети и автономной системы источника — крайнего правого номера в AS path.

К сожалению, RPKI — не настоящее, а будущее. Еще далеко не все операторы автономных систем участвуют в ней, несмотря на очевидные преимущества, поэтому просто отфильтровать все анонсы, для которых нет данных валидации, не выйдет. Можно только отфильтровать явно не соответствующие автономной системе источника. Тем не менее ознакомиться с ней и увидеть ее в работе сейчас может каждый.

Хранение базы данных соответствия сетей и автономных систем и проверка подписей производятся не на самом маршрутизаторе, а на отдельном сервере — для экономии ресурсов.


Запускаем сервер RPKI
Для демонстрации потребуется хост для сервера RPKI с любой UNIX-подобной системой, программы rsync и JDK8+ и два хоста с установленным FRR.

Прежде чем настраивать что-то в FRR, нужно запустить сам сервер RPKI. Мы будем использовать реализацию RIPE, которая состоит из двух компонентов: rpki-validator-3 и rpki-rtr-server.

Запускаем rpki-validator
Сначала нужно запустить

Авторизируйтесь или Зарегистрируйтесь что бы просматривать ссылки.

. Он доступен в виде образа для Docker и пакетов RPM для CentOS 7, а также в виде обычного tgz-архива с исполняемым файлом, который запускается на любой системе.
Код:
$ wget https://ftp.ripe.net/tools/rpki/validator3/prod/generic/rpki-validator-3-latest-dist.tar.gz
$ tar xfz ./rpki-validator-3-latest-dist.tar.gz
$ cd rpki-validator-<номер версии>
$ ./rpki-validator-3.sh
Настройки для баз данных всех RIR (RIPE, ARIN и других) уже включены в комплект, он автоматически загрузит их базы данных. Для его работы требуются только JDK8 или новее и rsync. Объем скачиваемых данных пока в пределах гигабайта.

Если ты планируешь запускать оба сервиса на одной машине, дополнительная настройка не требуется. Если нет, нужно поправить опцию server.address в conf/application.properties: по умолчанию он слушает только на localhost.

Запускаем rpki-rtr-server
Сам протокол RTR реализует другой проект:

Авторизируйтесь или Зарегистрируйтесь что бы просматривать ссылки.

. Для своей работы он требует запущенного rpki-validator, поэтому предыдущий шаг пропустить нельзя. Если он не сможет подключиться к валидатору, он сообщит об этом исключением вида I/O error on GET request for "

Авторизируйтесь или Зарегистрируйтесь что бы просматривать ссылки.

": Connection refused (Connection refused).

Процедура его запуска столь же проста:
Код:
$ wget https://ftp.ripe.net/tools/rpki/validator3/prod/generic/rpki-rtr-server-latest-dist.tar.gz
$ tar xfz ./rpki-rtr-server-latest-dist.tar.gz
$ cd rpki-rtr-server-<номер версии>
$ ./rpki-rtr-server.sh
Он тоже по умолчанию слушает только на localhost. Если настраивать FRR с проверкой аутентичности анонсов ты будешь на другой машине, нужно поправить опцию rtr.server.address в conf/application.properties.

После того как оба сервиса успешно запустятся, можно настроить сам FRR.


Настраиваем FRR
Клиент RPKI реализован в библиотеке

Авторизируйтесь или Зарегистрируйтесь что бы просматривать ссылки.

. RTR здесь — RPKI to Router protocol, протокол обмена данными между сервером RPKI и маршрутизатором. Большинство свободных реализаций BGP, включая FRR, используют именно ее.

По умолчанию RPKI в BGPd выключен, и чтобы его включить, нужно поправить /etc/frr/daemons:
Код:
bgpd_options="   --daemon -A 127.0.0.1 -M rpki"
Сначала настроим маршрутизатор условного провайдера. Предположим, что rtr-server запущен на 192.168.56.1. Зайдем в vtysh и добавим следующие настройки:
Код:
rpki
  rpki polling_period 1000
  rpki timeout 10
  rpki initial-synchronisation-timeout 30
  rpki cache 192.168.56.1 8323 preference 1
Проверить статус соединения можно командой show rpki cache-connection. Если все прошло нормально, ее вывод будет выглядеть так:
Код:
Connected to group 1
rpki tcp cache 192.168.56.1 8323 pref 1
Теперь настроим сам BGP. В route-map для не соответствующих автономной системе префиксов мы понизим local preference до 5 (ее значение по умолчанию — 100), чтобы эффект можно было увидеть в show ip bgp:
Код:
router bgp 64496
 neighbor 192.0.2.10 remote-as 64501
 !
 address-family ipv4 unicast
  neighbor 10.46.1.100 route-map RPKI-Test in
 exit-address-family
!
route-map RPKI-Test permit 10
 match rpki invalid
 set local-preference 5
Теперь настроим маршрутизатор условного злоумышленника, который будет анонсировать сеть сервера DNS Cloudflare (1.1.1.0/24, AS13335) из явно несоответствующей автономной системы 64501:
Код:
ip route 1.1.1.0/24 blackhole

router bgp 64501
 neighbor 192.0.2.1 remote-as 64496
 !
 address-family ipv4 unicast
  network 1.1.1.0/24
 exit-address-family
Теперь на первом маршрутизаторе в show ip bgp мы увидим следующую картину:
Код:
Network Next Hop Metric LocPrf Weight Path
*> 1.1.1.0/24 192.0.2.10 0 5 0 64501 i
Надеюсь, эта статья поможет тебе дожить до массового внедрения RPKI без инцидентов.


Авторизируйтесь или Зарегистрируйтесь что бы просматривать ссылки.