netgraph нода: ng_patch

ToS DSCP

Автор новости: Vadim Goncharov (nuclight)
netgraph — модульная сетевая подсистема ядра FreeBSD, основанная на принципе графов. В Netgraph строится граф из узлов различных типов, узел каждого типа имеет некоторое количество входов/выходов (далее хуков (hooks)). Узел netgraph позволяет производить определенные действия над пакетом, проходящим через него.

netgraph нода: ng_patch

С помощью ng_patch появилась возможность редактирования произвольных полей в заголовках IP-пакетов.
Эта нода позволяет производить последовательность операций над произвольными байтами пакета, не только ToS или TTL — как в данных, так и в заголовке, причем, все это в ядре.
Вместе с модулем ng_bpf это дает возможность выловить и изменить любой пакет.
Возможности открываются огромные.
Например, в icq пакете можно изменять текст «перейдите по ссылке» на «Перейдя по ссылке можна сфватить вирусню » =)

Maxim Ignatenko написал ноду ng_patch(4) — и её, наконец, закоммиттили, а недавно смержили в 8-STABLE (r209843) и вчера — в 7-STABLE (r210019). Работает также на 6.4, если убрать в коде CSUM_SCTP.

В настоящее время ng_patch — единственный штатный способ менять в проходящем пакете что-то. Зато, в отличие от других решений (в том числе на других ОС), эта нода позволяет производить последовательность операций над произвольными байтами пакета, не только ToS или TTL.
Пример для iptables:

1
2
 iptables -t mangle -A POSTROUTING -j TOS --set-tos 0x10
 iptables -t mangle -A POSTROUTING -j TTL --ttl-set 128

В мане рассмотрены примеры изменения ToS и TTL.

Тут будет описано изменение DSCP.

DSCP(Differenciated Services Code Point)— поле в IP-пакете, позволяющее назначить сетевому трафику различные уровни обслуживания. Для достижения этого каждый пакет в сети помечается кодом DSCP и соответствующим ему уровнем обслуживания.

Аббревиатуры ToS и DSCP родственны — используются для обозначения специального байта данных стандартного заголовка IP-пакета. Этот байт несет информацию о приоритете трафика, который в бизнес-трафике обычно назначается для пакетов IP-телефонии (третий сетевой уровень L3). Поскольку этот один и тот же байт иногда интерпретируется по-разному (либо как ToS байт, либо как DS/DSCP байт), получается некоторая путаница, хотя смысл и принцип технологии приоритезации не меняется — пакеты, помеченные высоким более приоритетом, передаются быстрее (менее приоритетные становятся в очередь). На рисунке показано расположение бит указанного байта (красным помечена наиболее важная, серым — неиспользующаяся часть).

ToS DSCP

ToS DSCP

Когда используют терминологию ToS, то в контексте приоретизации имеют в виду 3 старшие бита P2..P0, кодирующие уровень приоритета от 0 (минимальный приоритет) до 7 (максимальный приоритет). Для IP-телефонии применяется уровень приоритета 5 (critical, ToS-байт равен 0xA0 или 10100000b), а для обычного трафика уровень 0 (routine, ToS-байт равен 0x00 или 00000000b). У Cisco есть для каждого уровня приоритета специальное имя (precedence critical, precedence flash и т. д., см. таблицу).

IP Precedence Value

Уровень

Имя

0   routine
1   priority
2   immediate
3   flash
4   flash-override
5   critical
6  
internet
7  
network

Когда используют терминологию DSCP, имеются в виду 6 старших бит DS5..DS0, где DS5..DS3 кодируют уровень класса обслуживания от 0 (минимальный приоритет) до 7 (максимальный приоритет) и приоритет удаления (от 0, когда приоритет удаления максимальный, до 7, когда приоритет удаления минимальный — кодирование приоритета удаления «обратное»). В итоге получается число от 0 до 63, кодирующее приоритет (чем больше число, тем трафик важнее). Такое многоуровневое кодирование приоритета часто оказывается избыточным, и поэтому используются только биты DS5..DS3. При IP-телефонии применяется класс сервиса 5 (DS-байт равен 0xA0 или 10100000b), а для обычного трафика класс сервиса 0 (DS-байт равен 0x00 или 00000000b). Сравните с ToS — изменилась только терминология, а значение байта передается то же самое.

Для ng_patch:
Байты пакета для операций рассматриваются как без знаковые целые длиной 1, 2, 4 или 8 байт, применять можно такие операции из языка Си: присвоение нового значения (=), добавление (+=), вычитание (-=), умножение (*=), деление (/=), отрицание (= -), побитовое AND (&=), побитовое OR (|=), побитовое XOR (^=), сдвиг влево (<<=), сдвиг вправо (>>=). Исключением является отрицание, здесь данные рассмтариваются как знаковые, а аргумент не используется.
Конфигурируется нода следующими структурами, ниже рассмотрим на примере:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
struct ng_patch_op {
        uint64_t        value;
        uint32_t        offset;
        uint16_t        length; /* 1,2,4 or 8 bytes */
        uint16_t        mode;
};
/* Patching modes */
#define NG_PATCH_MODE_SET       1
#define NG_PATCH_MODE_ADD       2
#define NG_PATCH_MODE_SUB       3
#define NG_PATCH_MODE_MUL       4
#define NG_PATCH_MODE_DIV       5
#define NG_PATCH_MODE_NEG       6
#define NG_PATCH_MODE_AND       7
#define NG_PATCH_MODE_OR        8
#define NG_PATCH_MODE_XOR       9
#define NG_PATCH_MODE_SHL       10
#define NG_PATCH_MODE_SHR       11
 
struct ng_patch_config {
        uint32_t        count;
        uint32_t        csum_flags;
        struct ng_patch_op ops[];
};

Для примера в проходящих пакетах выставляем DSCP в AF33. В RFC 791 начало заголовка IP:

1
2
3
4
5
    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 
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |Version|  IHL  |Type of Service|          Total Length         |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Нужный нам 1 байт — ToS — второй, то есть, имеет смещение 1 от начала заголовка. Мы уже знаем, что байт ToS был переопределен под использование DSCP, в RFC 3168 он определяется так:

1
2
3
4
5
6
7
    0     1     2     3     4     5     6     7   
 +-----+-----+-----+-----+-----+-----+-----+-----+
 |          DS FIELD, DSCP           | ECN FIELD |
 +-----+-----+-----+-----+-----+-----+-----+-----+
 
   DSCP: differentiated services codepoint        
   ECN:  Explicit Congestion Notification

Нужный нам AF33 описан в RFC 2597 (и в справочнике по цискам — тоже): AF33 = ‘011110’.
Что теперь? А вот 2 бита ECN нам трогать не надо, надо их оставить как есть. Минимальный же размер для операции — 1 байт. Сначала надо обнулить искомые биты, а потом — сделать из них нужное нам значение. Два шага, сначала:

1
2
3
4
5
6
7
8
9
10
11
 +-+-+-+-+-+-+-+-+
 |s t u v w x y z|   исходный байт
 +-+-+-+-+-+-+-+-+
                AND 
 +-+-+-+-+-+-+-+-+
 |0 0 0 0 0 0 1 1|   значение 0x03
 +-+-+-+-+-+-+-+-+
                  =
 +-+-+-+-+-+-+-+-+
 |0 0 0 0 0 0 y z|
 +-+-+-+-+-+-+-+-+

потом:

1
2
3
4
5
6
7
8
9
10
11
 +-+-+-+-+-+-+-+-+
 |0 0 0 0 0 0 y z|  промежуточный байт
 +-+-+-+-+-+-+-+-+
                 OR
 +-+-+-+-+-+-+-+-+
 |0 1 1 1 1 0 0 0|  значение AF33, сдвинутое на 2 влево: 0x78 (7=0111, 8=1000)
 +-+-+-+-+-+-+-+-+
                  =
 +-+-+-+-+-+-+-+-+
 |0 1 1 1 1 0 y z|  то, что надо!
 +-+-+-+-+-+-+-+-+

Итак, составляем структурки для конфигурации узла и получаем итоговые команды (это уже полная конфигурация):

1
2
3
4
5
6
7
8
/usr/sbin/ngctl -f- <<-SEQ
        mkpeer ipfw: patch 600 in
        name ipfw:600 dscp_af33
        msg dscp_af33: setconfig { count=2 csum_flags=1 ops=[   \
                { mode=7 value=0x03 length=1 offset=1 }         \
                { mode=8 value=0x78 length=1 offset=1 } ] }
SEQ
/sbin/ipfw add 160 netgraph 600 ip from any to any not dst-port 80

Операций у нас две, и поэтому count сообщает, что в массиве ops=[ … ] будет две структуры ng_patch_op. Отдельно осталось рассмотреть поле csum_flags — оно может принимать такие значения (см. ), которые можно OR-ить:

1
2
3
4
#define CSUM_IP      0x0001        /* will csum IP */
#define CSUM_TCP     0x0002        /* will csum TCP */
#define CSUM_UDP     0x0004        /* will csum UDP */
#define CSUM_SCTP    0x0040        /* will csum SCTP */

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

Только учтите, что это средство — в стиле Unix, и позволяет админу прострелить себе ногу. Хитро поигравшись значениями, можно так изменить пакет, что на выходном пути IP-стека ядро свалится в панику или будут какие-нибудь еще непредсказуемые результаты.


Leave a Comment

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Загрузка...
Menu Title