Дело о загадочном сбросе BGP-сессий из-за неправильного атрибута OTC
Недавно мы столкнулись с интересной проблемой: необъяснимым сбросом BGP-сессий после получения роутерами маршрутов. Мы решили исследовать причины такого поведения — для этого мы проанализировали те сообщения BGP UPDATE, которые вызывали ошибку.
Довольно быстро выяснилось, что у всех этих маршрутов была одна общая деталь: они содержали некорректный атрибут OTC. При этом корень проблемы со сбросом сессий заключался в том, как именно роутеры обрабатывали неправильные маршруты. Поговорим об этом чуть ниже, а сперва обсудим матчасть.
Что такое OTC и как работает этот атрибут
OTC (BGP Only to Customer) — один из двух ключевых элементов системы BGP-ролей, описанной в стандарте RFC9234. Данная система была разработана при участии сотрудников Qrator и предназначена для обнаружения и предотвращения утечек маршрутов.
OTC — это опциональный атрибут сообщения BGP UPDATE, с установленной стандартом длиной 32 бита (4 октета). Его значением является номер автономной системы (ASN), которая выступает в качестве источника для нисходящей части маршрута.
Атрибут OTC работает в связке с BGP Role — механизмом, который задает роли и взаимоотношения автономных систем при установке между ними BGP-сессии (Provider–Customer, Peer–Peer, Customer–Provider).
Вот как это работает в случае входящих маршрутов: при получении маршрута автономная система сравнивает значение атрибута OTC с номером AS, от которой получен маршрут, принимая во внимание свои отношения с этой AS, заданные механизмом BGP Roles. Маршруты, полученные от клиентов или пиров, — за исключением случаев, когда OTC совпадает с ASN этого пира, — отклоняются, таким образом предотвращается утечка маршрута.
Аналогично в случае исходящих маршрутов: если в маршруте, который AS собирается отправить своим пирам или провайдерам (то есть не клиентам), есть установленный атрибут OTC, не совпадающий с номером данной AS, то этот маршрут отклоняется, чтобы предотвратить утечку маршрута.
Проще говоря, механизм BGP Roles и атрибут OTC позволяют поддерживающим их автономным системам удостоверяться в том, что маршруты распространяются только в правильном направлении и обнаруживать те случаи, когда это не так — то есть утечки маршрутов.
Также стандартом RFC9234 предусмотрено добавление атрибута OTC к легитимным маршрутам, в которых он не установлен — это может делать как отправляющая маршрут транзитная AS (при этом она записывает в качестве значения атрибута свой ASN), так и принимающая маршрут AS (в этом случае она записывает в атрибут ASN той системы, от которой маршрут получен).
Таким образом, данный механизм позволяет предотвращать утечки маршрутов даже в тех случаях, когда оригинальные отправители маршрутов не поддерживают стандарт RFC9234 — благодаря этому обеспечивается своего рода коллективный иммунитет.
Как выглядели сообщения об ошибках при сбросе BGP-сессий
Возвращаясь к исследуемому случаю, проблема заключалась в том, что некоторые AS рассылали сообщения BGP UPDATE с неверно заполненным полем Extended Length внутри атрибута OTC.
Попробуем разобраться глубже и посмотрим в HEX-дамп одного из сообщений, которые вызвали сброс BGP-сессии. Определим часть дампа, в которой хранится информация об атрибуте с типом 35 (атрибут OTC). В данном случае это "f0fa 0423 0000 4cfe".
Скорее всего, OTC будет неизвестен большинству маршрутизаторов, так как это относительно новый атрибут, но роутеру в любом случае нужно его каким-то образом распарсить.
Распарсим и мы (не забывая про правило чтения байт в двубайтных словах — сначала правый, потом левый). Для парсинга нужно понять сколько места занимает атрибут в памяти и после этого извлечь содержимое атрибута.
- 0xfa — часть предыдущего атрибута (Community), ее пропускаем.
- 0xf0 (0b11110000) — флаги атрибута: Optional=1, Transitive=1, Partial=1, Extended Length=1.
- 0x23 — 35 тип атрибута, соответствует OTC.
Размер атрибута описывается двумя полями:
- Флагом атрибута Extended Length (EL). Если значение EL=0, то размер атрибута занимает в памяти 1 байт, а если EL=1, то 2 байта.
- Самим значением размера атрибута.
Таким образом, если EL=1, то идущие следом два байта будут интерпретированы как размер.
- 0x04 — 4, предполагаемая длина атрибута. Однако из-за неверного флага Extended Length к ней был добавлен соседний байт 0x00. Поэтому она была прочитана как 0x0400, то есть 1024 байта, что и вызвало проблему.
- 0x00004cfe — 0xfe4c или 65100, значение атрибута (в данном случае это приватный ASN).
Похоже, в реализации относительно свежей функциональности была допущена ошибка.
Почему неправильный атрибут OTC вызывал сброс BGP-сессии
Эти сообщения начали передаваться между роутерами и автономными системами. При этом разные роутеры обрабатывали такие проблемные маршруты по-разному:
- Вероятно, часть роутеров просто отбрасывала некорректный маршрут и продолжала работать как ни в чем ни бывало (почему «вероятно»: такие кейсы априори невозможно обнаружить, поскольку маршрут не передавался дальше).
- Некоторые роутеры исправляли проблему, выставляя ожидаемый для данного атрибута флаг вместо оригинального значения.
- Другие роутеры игнорировали ошибку и просто пересылали дальше маршрут с неправильным атрибутом.
- В четвертом же случае роутеры при получении маршрута с поломанным атрибутом сбрасывали BGP-сессию.
Собственно, этот четвертый случай и был той проблемой, с которой мы столкнулись. Почему так происходило? На самом деле в стандарте RFC9234 в явном виде прописано, что следует делать при получении поломанного атрибута OTC:
«Атрибут OTC считается некорректно сформированным, если его значение длины не равно 4. Сообщение UPDATE с некорректно сформированным атрибутом OTC ДОЛЖНО обрабатываться согласно подходу "treat-as-withdraw" [RFC7606]».
Проще говоря, согласно стандарту при получении маршрутов с некорректным OTC такие маршруты следует отклонять. К сожалению, как мы видим, далеко не все роутеры следовали этому стандарту, вместо отклонения маршрута пересылая некорректное сообщение дальше или даже сбрасывая BGP-сессию.
Последняя ошибка, очевидно, была связана с тем, что роутеры действовали не по процедуре «treat-as-withdraw», прописанной в RFC7606, а по более старой, прописанной в базовой спецификации BGP:
«Согласно базовой спецификации BGP [RFC4271], BGP-узел, получивший сообщение UPDATE с некорректно сформированным атрибутом, обязан сбросить сессию, по которой был получен проблемный атрибут».
Выводы
При внедрении новых технологий и стандартов неизбежно возникают ошибки — конечно же, важно их обнаруживать и устранять в существующем ПО. Кейс с неправильным OTC-атрибутом показал, что даже при наличии четких требований в RFC поведение разных его реализаций может значительно отличаться. Это привело к непредсказуемым сетевым последствиям: от тихого распространения некорректных маршрутов до «необъяснимого» сброса BGP-сессий.
Правильный путь в таких ситуациях — единообразное следование стандартам, в данном случае явно указанному в RFC9234 механизму «treat-as-withdraw» из RFC7606. Чем быстрее вендоры и операторы внедрят корректную поддержку спецификации, тем выше будет устойчивость глобальной маршрутизируемой инфраструктуры.
Напомним, что поддержка BGP-ролей и атрибута OTC уже достаточно давно внедрена разработчиками в демоны маршрутизации FRR (FRRouting) и BIRD. А в сентябре 2025 поддержка RFC9234 появилась в роутерах Juniper, начиная с Junos OS Release 25.2R1.