Разбираем BGP NOTIFICATION по RFC

Habrahabr

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

Не могу сказать, что я это помню, ещё не могу сказать что это мне мешает в работе. Я даже не могу сказать, что мне приходится часто видеть заголовки в каком-то необработанном виде, потому что, как правило, сообщения в syslog или на консоли уже переформатированы в связные английские предложения. Но, иногда, приходиться смотреть глубже, например, этот год был урожайный на подобные сообщения:

Ericsson SmartEdge

notification msg sent (nbr 192.0.2.1, context 0x40030044 32 bytes, repeated 89 times, code 3/4 (update: attribute flags error) - 
0000 0000 ffff ffff ffff ffff ffff ffff ffff ffff 0020 0303 04e0 0708 0003 02ed 5bdc 3f01

Cisco, то же с другой стороны

NOTIFICATION received from 192.0.2.2 (External AS 64496):
code 3 (Update Message Error) subcode 4 (attribute flags error),
Data: e0 07 08 00 03 02 ed 5b dc 3f 01

Попробуем разобрать это руками как написано в RFC4721. Не будем искать причину — просто разбор заголовков. Будет много цитат и, скорее всего, ничего нового для тех кто уже это умеет делать. Для остальных читаем дальше.

Чтобы внести разнообразие не ограничимся одним сообщением и разберём ещё вот это issue с GitHub FRRouting:

%NOTIFICATION: received from neighbor 192.168.0.1
3/5 (UPDATE Message Error/Attribute Length Error) 3298 bytes
50 02 0c de 02 ff 00 00 0c b9 00 00 00 ae 00 04 00 3e 00 04 00 3e 00 04 00 35 00 04 00 35 ... очень много раз 00 04 00 35

Что мы можем прочитать? Видим тип сообщения, его значение и подзначение, IP адрес соседства (который нам и так известен) и шестнадцатеричная строка, которую мы не понимаем.

Начнём с главного с сайта IANA где есть все нужные коды с отсылкой к RFC4721. Если набраться сил и прочитать RFC от корки до корки, то всё должно стать понятно, но мы попытаемся разобраться только в формате наших двух сообщений не затрагивая поведенческие аспекты.

Разбираем NOTIFICATION

Из содержания, по названию, нам подходит пункт 4.5 NOTIFICATION Message Format. Открыв который действительно находим формат нужного нам заголовка и список всех кодов с ссылкой на соответствующие разделы (дальше всё цитирование спрячем под спойлеры):

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      | Error code    | Error subcode |   Data (variable)             |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      Error Code:

         This 1-octet unsigned integer indicates the type of
         NOTIFICATION.  The following Error Codes have been defined:

            Error Code       Symbolic Name               Reference
              1         Message Header Error             Section 6.1
              2         OPEN Message Error               Section 6.2
              3         UPDATE Message Error             Section 6.3
              4         Hold Timer Expired               Section 6.5
              5         Finite State Machine Error       Section 6.6
              6         Cease                            Section 6.7

Наш раздел 6.3 UPDATE Message Error с кодом ошибки 3. Видим его во всех сообщениях, вместе с уточняющим кодом:

code 3/4 (update: attribute flags error) - 0000 0000 ffff ffff ffff ffff ffff ffff ffff ffff 0020 0303 04e0 0708 0003 02ed 5bdc 3f01

code 3 (Update Message Error) subcode 4 (attribute flags error), Data: e0 07 08 00 03 02 ed 5b dc 3f 01

3/5 (UPDATE Message Error/Attribute Length Error) 3298 bytes 50 02 0c de 02 ff 00 00 0c b9 00 00 00 ae 00 04 00 3e 00 04 00 3e 00 04 00 35 00 04 00 35 ... очень много раз 00 04 00 35

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

В нашем случае — используемые флаги не могут быть использованы c данным атрибутом:

4 Attribute Flags Error
If any recognized attribute has Attribute Flags that conflict with
the Attribute Type Code, then the Error Subcode MUST be set to
Attribute Flags Error.  The Data field MUST contain the erroneous
attribute (type, length, and value).

и — фактическая длина атрибута не совпадает с ожидаемой:

5 Attribute Length Error
If any recognized attribute has an Attribute Length that conflicts
with the expected length (based on the attribute type code), then the
Error Subcode MUST be set to Attribute Length Error.  The Data field
MUST contain the erroneous attribute (type, length, and value).

Самое важное, что тут написано и что нам поможет в дальнейшем это то, что помимо кодов ошибок в сообщении ДОЛЖЕН присутствовать ошибочный атрибут из UPDATE сообщения в поле data в формате TLV (тип, длина, значение). Та самая шестнадцатеричная строка которую мы пока не можем интерпретировать. Однако, у нас по прежнему есть проблема в идентификации этого поля, связанная теперь с различными соглашениями принятыми производителями устройств для отображения журнала логов.

В примере с Cisco, явно указывается начало словом "Data": code 3 (Update Message Error) subcode 4 (attribute flags error), Data: e0 07 08 00 03 02 ed 5b dc 3f 01

В остальных случаях, такой привязки нет. При этом строка с Ericsson, содержит гораздо больше данных чем у Cisco, хотя мы знаем что эти сообщения идентичны. Поэтому возвращаемся на шаг назад к описанию NOTIFICATION и видим что мы разобрали его полностью, поле data переменной длины является последним в сообщении.

Поднимемся выше по иерархии и начнём читать с начала раздела 4.1:

Message Header Format
      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      +                                                               +
      |                                                               |
      +                                                               +
      |                           Marker                              |
      +                                                               +
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |          Length               |      Type     |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Каждое сообщение начинается с поля:

Marker
This 16-octet field is included for compatibility; it MUST be
set to all ones.

длиной в 16 байт и состоящее из всех единиц ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff. Такой же паттерн мы видим в логе Ericsson: code 3/4 (update: attribute flags error) - 0000 0000 (ffff ffff ffff ffff ffff ffff ffff ffff) 0020 0303 04e0 0708 0003 02ed 5bdc 3f01

Далее поле длины в два байта: code 3/4 (update: attribute flags error) - 0000 0000 ffff ffff ffff ffff ffff ffff ffff ffff (0020) 0303 04e0 0708 0003 02ed 5bdc 3f01, со значением 32 десятичные, что совпадает с расшифровкой из журнала notification msg sent (nbr 192.0.2.1, context 0x40030044 32 bytes, а ещё дальше :

Тип сообщения
This 1-octet unsigned integer indicates the type code of the
message.  This document defines the following type codes:

                     1 - OPEN
                     2 - UPDATE
                     3 - NOTIFICATION
                     4 - KEEPALIVE

и мы знаем что оно номер 3 — NOTIFICATION: code 3/4 (update: attribute flags error) - 0000 0000 ffff ffff ffff ffff ffff ffff ffff ffff 0020 (03)03 04e0 0708 0003 02ed 5bdc 3f01

А следом уже само сообщение и то что мы распознали (раздел 4.5) 03 04 — тип и подтип ошибки: code 3/4 (update: attribute flags error) - 0000 0000 ffff ffff ffff ffff ffff ffff ffff ffff 0020 03(03 04)e0 0708 0003 02ed 5bdc 3f01

Ericsson повторил нам не только поле data которое начинается с e0, а всё сформированное сообщение. В логе Cisco именно с него начинается байтовая последовательность. Лог FRRouting, также содержит полностью расшифрованный заголовок BGP сообщения NOTIFICATION за которым следует уже поле data, к декодированию которого мы возвращаемся.

Направляемся к описанию формата UPDATE, так как рассчитываем там найти описание форматов атрибутов, чтобы понять что именно мы всё же получаем. UPDATE содержит много полей, атрибуты задаются в поле переменной длины Path Attributes:

каждый из которых представлен в формате TLV
A variable-length sequence of path attributes is present in
every UPDATE message, except for an UPDATE message that carries
only the withdrawn routes.  Each path attribute is a triple
<attribute type, attribute length, attribute value> of variable
length.

Начнём со значения поля Тип, которое состоит из двух однобайтных частей:

Флаги и значения атрибута
         Attribute Type is a two-octet field that consists of the
         Attribute Flags octet, followed by the Attribute Type Code
         octet.

               0                   1
               0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
               |  Attr. Flags  |Attr. Type Code|
               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Здесь опять надо читать всё подряд, так как всё оформлено сплошным текстом. Из него следует, что поле флагов использует 4 первых бита с 0 по 3, а второй байт определяет сам атрибут. Сведём всё это в таблицу:

Бит Attr. Flags Значение Связанный атрибут
0 0 – well-known 1 — ORIGIN 2 — AS_PATH 3 — NEXT-HOP 5 — LOCAL_PREF 6 — ATOMIC_AGGREGATE
1 — optional 4 — MULTI_EXIT_DISC 7 — AGGREGATOR
1 0 – optional non-transitive MULTI_EXIT_DISC
1 – optional transitive или для всех well-known ORIGIN AS-PATH NEXT-HOP ATOMIC_AGGREGATE AGGREGATOR
2 0 — optional complete или для всех well-known и non-transitive ORIGIN AS-PATH NEXT-HOP MULTI_EXIT_DISC LOCAL_PREF ATOMIC_AGGREGATE
1 – optional partial

Биты 4-7 должны быть 0 при передаче и игнорироваться при приёме, на них внимание не обращаем. Бит 3 определяет размер поля length в TLV:

0 – один байт, 1 — два байта
The fourth high-order bit (bit 3) of the Attribute Flags octet
is the Extended Length bit.  It defines whether the Attribute
Length is one octet (if set to 0) or two octets (if set to 1).

Отдельный интерес представляет флаг partial, который может быть установлен для транзитивных опциональных атрибутов. Описание флага разбросано в нескольких местах по всему тексту RFC. Встречаются следующие ситуации его использования:

  1. В случае, если атрибут не распознаётся этот флаг устанавливается, а сам атрибут передаётся дальше — 9 раздел:
    Update Message handling
    If an optional transitive attribute is unrecognized, the Partial 
    bit (the third high-order bit) in the attribute flags octet is 
    set to 1, and the attribute is retained for propagation to other 
    BGP speakers.
    
  2. Если атрибут распознаётся следующим спикером, то флаг всё равно не сбрасывается — 5 раздел:
    Path Attributes
    Paths with unrecognized transitive optional attributes SHOULD be 
    accepted.  If a path with an unrecognized transitive optional 
    attribute is accepted and passed to other BGP peers, then the 
    unrecognized transitive optional attribute of that path MUST be 
    passed, along with the path, to other BGP peers with the Partial bit 
    in the Attribute Flags octet set to 1.  If a path with a recognized,
    transitive optional attribute is accepted and passed along to other 
    BGP peers and the Partial bit in the Attribute Flags octet is set 
    to 1 by some previous AS, it MUST NOT be set back to 0 by the 
    current AS.
    
  3. И если не исходный спикер хочет добавить транзитивный атрибут, то флаг так же устанавливается:
    (там же)
    New, transitive optional attributes MAY be attached to the path by
    the originator or by any other BGP speaker in the path.  If they are
    not attached by the originator, the Partial bit in the Attribute
    Flags octet is set to 1.
    

Приступим к разбору UPDATE

Поле флагов в первом случае e0: code 3/4 (update: attribute flags error) - 0000 0000 ffff ffff ffff ffff ffff ffff ffff ffff 0020 0303 04(e0) 0708 0003 02ed 5bdc 3f01 — в двоичном 1110 0000 — опциональный, транзитивный с установленным флагом partial, поле длины задаётся одним байтом.

code 3/4 (update: attribute flags error) - 0000 0000 ffff ffff ffff ffff ffff ffff ffff ffff 0020 0303 04e0 (07)08 0003 02ed 5bdc 3f01 — код атрибута 7 — AGGREGATOR

Размер данных 8 байт: code 3/4 (update: attribute flags error) - 0000 0000 ffff ffff ffff ffff ffff ffff ffff ffff 0020 0303 04e0 07(08) 0003 02ed 5bdc 3f01

Во втором случае — общеизвестный атрибут (50 — 0101 0000), размер поля длины в два байта, AS_PATH (02), длина 3294 байта (0c de): 3/5 (UPDATE Message Error/Attribute Length Error) 3298 bytes (50 02 0c de) 02 ff 00 00 0c b9 00 00 00 ae 00 04 00 3e 00 04 00 3e 00 04 00 35 00 04 00 35 ... очень много раз 00 04 00 35

Оставшаяся часть строки это поле данных самого атрибута. Для этого продвигаемся дальше по разделу 4.3:

AGGREGATOR
AGGREGATOR is an optional transitive attribute of length 6.
The attribute contains the last AS number that formed the
aggregate route (encoded as 2 octets), followed by the IP
address of the BGP speaker that formed the aggregate route
(encoded as 4 octets).  This SHOULD be the same address as
the one used for the BGP Identifier of the speaker.

Следует учесть работу с 32-битными ASn RFC6793, чтобы получить следующий результат:

4 байта это AS197357: code 3/4 (update: attribute flags error) - 0000 0000 ffff ffff ffff ffff ffff ffff ffff ffff 0020 0303 04e0 0708 (0003 02ed) 5bdc 3f01,

и 4 байта IP адрес 91.220.63.1: code 3/4 (update: attribute flags error) - 0000 0000 ffff ffff ffff ffff ffff ffff ffff ffff 0020 0303 04e0 0708 0003 02ed (5bdc 3f01) — в сумме 8 байт, как и указано в поле длины.

Во втором случае AS_PATH, сам по себе TLV:

3-й вглубь, от начала NOTIFICATION
The path segment type is a 1-octet length field with the
following values defined:

   Value      Segment Type

    1         AS_SET: unordered set of ASes a route in the
                 UPDATE message has traversed

    2         AS_SEQUENCE: ordered set of ASes a route in
                 the UPDATE message has traversed

The path segment length is a 1-octet length field,
containing the number of ASes (not the number of octets) in
the path segment value field.

Поля типа и длины размером по 1 байту.

Тип 2, размер данных (ff — 255 ASn): 3/5 (UPDATE Message Error/Attribute Length Error) 3298 bytes 50 02 0c de (02 ff) 00 00 0c b9 00 00 00 ae 00 04 00 3e 00 04 00 3e 00 04 00 35 00 04 00 35 ... очень много раз 00 04 00 35

Сами данные — номера AS по 4 байта каждая: 3/5 (UPDATE Message Error/Attribute Length Error) 3298 bytes 50 02 0c de 02 ff (00 00 0c b9) (00 00 00 ae ) (00 04 00 3e ) (00 04 00 3e ) (00 04 00 35 ) (00 04 00 35 )... очень много раз 00 04 00 35 — AS3257, AS174, AS262206 AS262206, AS262197, AS262197, AS262197, AS262197 ...

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

К сожалению, а может и нет — RFC не является лёгкой прогулкой для чтения, в некоторых местах данные сведены в таблицы, в других ровно в тех же случаях они расписаны непосредственно в тексте и приходится много вычитывать для понимания структуры. Но радует, что они есть и производители смогли их прочитать и довести до реализации.

P.S. В случае FRRouting есть патч, намекающий, что проблема не в формате.

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