Привет коллегам!
Продолжаю разбираться с 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