Привет коллегам!

Продолжаю разбираться с ng_netflow. Собственно, цель этих разбирательств в том, чтобы как можно большую часть трафика (в идеале -- весь), идущего "на", "с" или "через" данный хост можно было пропустить через ng_netflow и увидеть максимально корректное его отображение в виде проэкспортированной netflow-статистики (в том смысле, что если в netflow статистике указано, что для данного flow пакеты пришли через интерфейс A и ушли через интерфейс B в сторону gteway'я G, то значит в реальности так и было).

На данный момент ng_netflow, в силу его внутреннего устройства, до этого идеала далеко. У него проблемы с broadcast- и multicast-трафиком, с пакетами, отсеяными firewall'ом, с ipfw fwd, с локальным трафиком и, возможно, еще с чем-то, до чего я пока не добрался. Справедливости ради следует сказать, что все вышеперечисленное обычно не является определяющим в общем объеме трафика, так что ng_netflow для основного трафика на машине без особых изысков в конфигурации -- вполне рабочий инструмент. Но мне хочется перевести его из фазы "make it work" в фазу "make it right", (ну а затем и в "make it fast", если понадобится).

Пока план действий предполагается примерно следующий. Пакет попадает в ng_netflow и на in- и на out- стадии его обработки сетевым стеком. На in- стадии, если нужно, создается новая flow entry, поля которой заполняются неким одним образом, а потом на out-стадии некоторые поля этой entry (например, out ifindex, next hop) подправляются/дозаполняются в соответствии с появившейся новой информацией. (Вообще-то там все чуть сложнее, поскольку, например, для локально сгенерированного, но исходящего за пределы хоста трафика, in-стадии нет вообще, но общую идею отражает.)

Пытаясь реализовать это план наткнулся на странную ситуацию с локальным трафиком. Сейчас проиллюстрирую. "Обвязка" вокруг ng_netflow создается так:

/usr/sbin/ngctl -f- <<-ENDCS
        mkpeer ipfw: netflow 1 iface0
        name ipfw:1 netflow
        connect ipfw: netflow: 101 out0
        connect ipfw: netflow: 2 iface1
        msg netflow: setconfig { iface=0 conf=7 }
        msg netflow: setconfig { iface=1 conf=7 }
        msg netflow: setdlt { iface=0 dlt=12 }
        msg netflow: setdlt { iface=1 dlt=12 }
        msg netflow: settimeouts { inactive=15 active=60 }
        mkpeer netflow: ksocket export inet/dgram/udp
        name netflow:export flowexp
        msg flowexp: connect inet/${ngnetflow_dst}
ENDCS

Откуда видно, что пакеты попадают в ng_netflow только из ipfw.
Сам firewall выглядит так:

>ipfw list
00010 netgraph 1 ip from any to any in
00020 netgraph 1 ip from any to not 224.0.0.0/4 out
00021 ngtee 2 ip from any to 224.0.0.0/4 out
00100 allow ip from any to any via lo0
00200 deny ip from any to 127.0.0.0/8
00300 deny ip from 127.0.0.0/8 to any
00400 deny ip from any to ::1
00500 deny ip from ::1 to any
00600 allow ipv6-icmp from :: to ff02::/16
00700 allow ipv6-icmp from fe80::/10 to fe80::/10
00800 allow ipv6-icmp from fe80::/10 to ff02::/16
00900 allow ipv6-icmp from any to any ip6 icmp6types 1
01000 allow ipv6-icmp from any to any ip6 icmp6types 2,135,136
65000 allow ip from any to any
65535 deny ip from any to any

Посылаем 1 UDP пакет на 127.0.0.1:8192 (этот UDP-порт никто не слушает):

>traceroute -e -q1 -M5 -m5 -p8192 127.0.0.1
traceroute to 127.0.0.1 (127.0.0.1), 5 hops max, 40 byte packets
 5  localhost (127.0.0.1)  0.062 ms

Смотрим, что появилось в netflow:

>flowctl netflow show | fgrep -e Src -e 127.0.0.1
SrcIf         SrcIPaddress    DstIf         DstIPaddress    Pr SrcP DstP  Pkts
(null)        127.0.0.1       lo0           127.0.0.1       17 b171 2000      1
lo0           127.0.0.1       lo0           127.0.0.1       17 b171 2000      1
(null)        127.0.0.1       lo0           127.0.0.1        1 0000 0000      1
lo0           127.0.0.1       lo0           127.0.0.1        1 0000 0000      1

Видим ушедший пакет и icmp port unreachable ему навстречу, но и то и другое -- в виде 2-х flow, отличающихся source interface'ом.

Для сравнения, если проделать то же самое, но отправить пакет за пределы машины, на другую машину, где порт тоже никто не слушает, такого эффекта не будет:

>traceroute -e -q1 -M5 -m5 -p8192 10.1.0.7
traceroute to 10.1.0.7 (10.1.0.7), 5 hops max, 40 byte packets
 5  10.1.0.7 (10.1.0.7)  0.182 ms
>flowctl netflow show | fgrep -e Src -e 10.1.0.7
SrcIf         SrcIPaddress    DstIf         DstIPaddress    Pr SrcP DstP  Pkts
(null)        10.1.0.14       vlan3         10.1.0.7        17 b17e 2000      1
vlan3         10.1.0.7        lo0           10.1.0.14        1 0000 0000      1

Для разнообразия отправим еще пакет по адресу, на котором нет никакой машины:

>traceroute -e -q1 -M5 -m5 -p8192 10.1.0.15
traceroute to 10.1.0.15 (10.1.0.15), 5 hops max, 40 byte packets
 5  *
>flowctl netflow show | fgrep -e Src -e 10.1.0.15
SrcIf         SrcIPaddress    DstIf         DstIPaddress    Pr SrcP DstP  Pkts
(null)        10.1.0.14       vlan3         10.1.0.15       17 b194 2000      1


Мда. Изначально я было хотел попросить прокомментировать эти мои наблюдения, но так долго писал весь этот длинный текст, что аж сам понял, почему оно так себя ведет. :) Сначала в ng_netflow попадает out-пакет идущий на 127.0.0.1, у него SrcIf=(null), как и положено out-пакетам, потом он уходит в lo0 и тут же снова принимается из lo0, но SrcIf уже, понятное дело, lo0, а поскольку SrcIf входит в определение того, что такое flow, то вот и образуется второй flow для того же пакета, что формально правильно, но по сути неправильно, ибо в результате такой трафик учитывается дважды. Теперь вопрос, что можно с этим сделать? Ну, кроме как просто не отправлять в ng_netflow out-пакеты, идущие на lo0? Может у кого есть какие идеи?

--
Olwi

Ответить