LINUX.ORG.RU
решено ФорумAdmin

iptables неправильно считает кол-во DROP'нутых UDP-пакетов

 8200, ,


1

1

Добрый вечер.

iptables почему-то некорректно считает кол-во UDP-пакетов, к которым было применено действие DROP (1 пакет считает как 8200). Если вместо DROP делать ACCEPT или LOG, все считается правильно. Если DROP'ать TCP-пакеты, считает тоже правильно.

Таблицы чисты:

# iptables-save
# Generated by iptables-save v1.4.17 on Tue Jan 29 18:23:15 2013
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [8:480]
:POSTROUTING ACCEPT [8:480]
COMMIT
# Completed on Tue Jan 29 18:23:15 2013
# Generated by iptables-save v1.4.17 on Tue Jan 29 18:23:15 2013
*mangle
:PREROUTING ACCEPT [62:16051]
:INPUT ACCEPT [62:16051]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [91:6063]
:POSTROUTING ACCEPT [91:6063]
COMMIT
# Completed on Tue Jan 29 18:23:15 2013
# Generated by iptables-save v1.4.17 on Tue Jan 29 18:23:15 2013
*filter
:INPUT ACCEPT [67:16487]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [99:6539]
COMMIT
# Completed on Tue Jan 29 18:23:15 2013
Добавляем правило и смотрим на счетчик:
# iptables -A OUTPUT -p udp --dport 5555 -j DROP
# iptables -nvL
Chain INPUT (policy ACCEPT 1 packets, 40 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 1 packets, 52 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:5555
Теперь пробуем отправить один(1) UDP пакет на порт 5555 и снова смотрим на счетчик:
# echo -n 'test' | nc -u 8.8.8.8 5555
# iptables -nvL
Chain INPUT (policy ACCEPT 129 packets, 39767 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 146 packets, 14802 bytes)
 pkts bytes target     prot opt in     out     source               destination         
 8200  262K DROP       udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:5555
Что это? Похоже на какую-то петлю внутри iptables. Если ничего больше не отправлять, значение счетчика не изменится. Если отправить еще один UDP пакет на порт 5555, к значению счетчика вместо 1 прибавится 8200.

iptables v1.4.17

Проверил на другой системе с iptables 1.4.12, там вместо 8200 к счетчику прибавляется 32.

★★★★★

Последнее исправление: edigaryev (всего исправлений: 2)
Ответ на: комментарий от zgen

-x, --exact

Увы, не помогло:

# iptables --exact -nvL
Chain INPUT (policy ACCEPT 33 packets, 1920 bytes)
    pkts      bytes target     prot opt in     out     source               destination         

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
    pkts      bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 35 packets, 2238 bytes)
    pkts      bytes target     prot opt in     out     source               destination         
    8200   270600 DROP       udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:5555
Судя по всему тут никто с такой проблемой не сталкивался, буду писать в багзиллу netfilter.

edigaryev ★★★★★
() автор топика
Ответ на: комментарий от edigaryev

Судя по всему тут никто с такой проблемой не сталкивался, буду писать в багзиллу netfilter.

Судя по всему вообще никто не сталкивался, а это в первую очередь повод задуматься о том, что бы делаете не так.

1. Вы пишите, что «1 пакет считает как 8200»

Приводите картинку, где:
---
pkts bytes target prot opt in out source destination
8200 262K DROP udp  — * * 0.0.0.0/0 0.0.0.0/0
----

Вы что, правда считаете, что в 1 output udp пакет может влезть
«262K» данных (по счетчику же)?
И какой вывод вы должны сделать из этого?

2. Надо быть совсем нездоровым, чтобы без прочих данных считать, что

# echo -n 'test' | nc -u 8.8.8.8 5555

Сгенерирует один пакет.

В общем, даже разбираться неохота с вами, подумайте еще раз пожалуйста, прежде чем

писать в багзиллу netfilter.


А то подозреваю, писателей там хватает. С читателями беда.
И посидите пожалуйста с tcpdump'ом на интерфейсе, авось мысль умная в голову придет.

zgen ★★★★★
()
Последнее исправление: zgen (всего исправлений: 7)
Ответ на: комментарий от edigaryev

Ну не знаю, у меня все нормально считается

Chain OUTPUT (policy ACCEPT 952 packets, 1443217 bytes)
    pkts      bytes target     prot opt in     out  source               destination

    1227  1466317            all  --  *      *       0.0.0.0/0            0.0.0.0/0

     275    23100 DROP       icmp --  *      *       0.0.0.0/0            1.1.1.1             

linux-3.7.3

iptables v1.4.17

IMHO tcpdump или -j LOG быстро помогут найти источник проблемы.

vel ★★★★★
()
Ответ на: комментарий от zgen

Вы что, правда считаете, что в 1 output udp пакет может влезть «262K» данных (по счетчику же)?

Насколько мне известно, счетчик bytes суммирует размеры пакетов, попавших под это правило.

Пакет, который я отправляю, имеет размер (20 + 8 + 4) = 32 байта без Ethernet заголовка. В этом можно убедиться запустив tcpdump:

# tcpdump -v -n -i eth0 host 8.8.8.8
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
00:29:55.885716 IP (tos 0x0, ttl 64, id 35419, offset 0, flags [DF], proto UDP (17), length 32)
    192.168.0.2.51746 > 8.8.8.8.5555: UDP, length 4

По показателям iptables все сходится: 262400 / 8200 = 32

Кстати заметил еще одну особенность: если вместо DROP поставить REJECT, значения счетчиков будут в два раза меньше (4100 вместо 8200 и 131K вместо 262K) — становится все теплее.

И какой вывод вы должны сделать из этого?

В netfilter/iptables баг или я чего-то не знаю.

Надо быть совсем нездоровым, чтобы без прочих данных считать, что
Сгенерирует один пакет.

«Прочие данные» у меня имеются, так что будем считать что я здоров :)

В общем, даже разбираться неохота с вами, подумайте еще раз пожалуйста, прежде чем
И посидите пожалуйста с tcpdump'ом на интерфейсе, авось мысль умная в голову придет.

Если верить tcpdump'у/Wireshark'у — пакет вылетает один (см. вывод tcpdump'а выше), кроме меня во время эксперимента на 5555 порт никто ничего отправлять больше не должен. Возможно я ошибаюсь, но на мой взгляд такое поведение iptables уж слишком неочевидно и заслуживает тикета в багзилле.

edigaryev ★★★★★
() автор топика
Ответ на: комментарий от vel

Ну не знаю, у меня все нормально считается

С icmp match у меня тоже все нормально считается, попробуй udp :)

edigaryev ★★★★★
() автор топика
Ответ на: комментарий от vel

IMHO tcpdump или -j LOG быстро помогут найти источник проблемы.

Забавно. Если оставить в OUTPUT одно правило с -j LOG — все нормально работает, но стоит только сделать так:

Chain OUTPUT (policy ACCEPT 1 packets, 52 bytes)
    pkts      bytes target     prot opt in     out     source               destination         
       0        0 LOG        udp  --  *      *       0.0.0.0/0            8.8.8.8              LOG flags 0 level 4
       0        0 DROP       udp  --  *      *       0.0.0.0/0            8.8.8.8             
...и netfilter засирает /var/log/messages на отличненько!

edigaryev ★★★★★
() автор топика
Ответ на: комментарий от edigaryev

http://nmap.org/nping/ + определите правила максимально точно, а не только dst port, включая source address & iface, покажите route'ы и таблицы postrouting.

Я бы начал с упрощения картины -

удалил бы ВСЕ цепочки из всех таблиц (mange/nat/etc), действие по-умолчанию оставил бы ACCEPT, единственное правило бы оставил в output. И проверял бы вменяемым инструментом.

zgen ★★★★★
()
Последнее исправление: zgen (всего исправлений: 4)
Ответ на: комментарий от edigaryev

У меня все линуксы в production, поэтому сам проверить пока не могу.

zgen ★★★★★
()
Ответ на: комментарий от zgen

Там точно написано то, что нужно?

А то:

[ 6271.916258] IN= OUT=eth0 SRC=192.168.0.2 DST=8.8.8.8 LEN=32 TOS=0x00 PREC=0x00 TTL=64 ID=30782 DF PROTO=UDP SPT=45945 DPT=5555 LEN=12 
[ 6271.916262] IN= OUT=eth0 SRC=192.168.0.2 DST=8.8.8.8 LEN=32 TOS=0x00 PREC=0x00 TTL=64 ID=30783 DF PROTO=UDP SPT=45945 DPT=5555 LEN=12 
[ 6271.916267] IN= OUT=eth0 SRC=192.168.0.2 DST=8.8.8.8 LEN=32 TOS=0x00 PREC=0x00 TTL=64 ID=30784 DF PROTO=UDP SPT=45945 DPT=5555 LEN=12 
[ 6271.916272] IN= OUT=eth0 SRC=192.168.0.2 DST=8.8.8.8 LEN=32 TOS=0x00 PREC=0x00 TTL=64 ID=30785 DF PROTO=UDP SPT=45945 DPT=5555 LEN=12 
[ 6271.916277] IN= OUT=eth0 SRC=192.168.0.2 DST=8.8.8.8 LEN=32 TOS=0x00 PREC=0x00 TTL=64 ID=30786 DF PROTO=UDP SPT=45945 DPT=5555 LEN=12 
[ 6271.916281] IN= OUT=eth0 SRC=192.168.0.2 DST=8.8.8.8 LEN=32 TOS=0x00 PREC=0x00 TTL=64 ID=30787 DF PROTO=UDP SPT=45945 DPT=5555 LEN=12 
[ 6271.916289] IN= OUT=eth0 SRC=192.168.0.2 DST=8.8.8.8 LEN=32 TOS=0x00 PREC=0x00 TTL=64 ID=30788 DF PROTO=UDP SPT=45945 DPT=5555 LEN=12 
[ 6271.916294] IN= OUT=eth0 SRC=192.168.0.2 DST=8.8.8.8 LEN=32 TOS=0x00 PREC=0x00 TTL=64 ID=30789 DF PROTO=UDP SPT=45945 DPT=5555 LEN=12 

edigaryev ★★★★★
() автор топика
Ответ на: комментарий от zgen

удалил бы ВСЕ цепочки из всех таблиц (mange/nat/etc), действие по-умолчанию оставил бы ACCEPT, единственное правило бы оставил в output.

Ну, я впринципе так с самого начала и сделал, для чистоты эксперимента, см. нулевой пост — картина проста до предела. Только вот боюсь дефолтные цепочки из таблиц netfilter'а удалить не получится :)

И проверял бы вменяемым инструментом.

Про nping не знал, спасибо за наводку, но я все-таки считаю что для этой задачи подойдут оба инструмента (netcat и nping). Единственное, что удобнее делать с помощью nping рамках данной задачи — это отправлять данные в цикле.

edigaryev ★★★★★
() автор топика
Ответ на: комментарий от edigaryev

Если вместо DROP делать ... REJECT, все считается правильно (с) первое сообщение
если вместо DROP поставить REJECT, значения счетчиков будут в два раза меньше (с) последующее

Где-то тут взаимоисключающие параграфы, что-то изменилось в условиях теста между ними?

zgen ★★★★★
()
Последнее исправление: zgen (всего исправлений: 1)
Ответ на: комментарий от zgen

Сначала удалил DROP правило, чтобы посмотреть в Wireshark'е разницу между тем, что отправляет nc и nping. Единственное отличие — nc устанавливает DF-bit. Сначала подумал что дело в нём, но попробовав отправить пакет с помощью nping --df счетчик все равно считал все правильно.

В итоге решил запустить nc под strace'ом — вот тут-то все встало на свои места:

write(3, "test123", 7)                  = -1 EPERM (Operation not permitted)
write(3, "test123", 7)                  = -1 EPERM (Operation not permitted)
write(3, "test123", 7)                  = -1 EPERM (Operation not permitted)
write(3, "test123", 7)                  = -1 EPERM (Operation not permitted)
write(3, "test123", 7)                  = -1 EPERM (Operation not permitted)
write(3, "test123", 7)                  = -1 EPERM (Operation not permitted)
write(3, "test123", 7)                  = -1 EPERM (Operation not permitted)
write(3, "test123", 7)                  = -1 EPERM (Operation not permitted)
write(3, "test123", 7)                  = -1 EPERM (Operation not permitted)
write(3, "test123", 7)                  = -1 EPERM (Operation not permitted)
write(3, "test123", 7)                  = -1 EPERM (Operation not permitted)
write(3, "test123", 7)                  = -1 EPERM (Operation not permitted)

Когда в OUTPUT есть правило, блокирующее UDP-пакеты идущие туда, куда пытается отправить свои пакеты netcat, на попытку write() ему возвращается -1 и значение errno устанавливается в EPERM.

netcat почему-то вообще не проверяет значение errno при возникновении ошибки (т.е. когда write() возвращает -1), и не особо задумываясь делает еще 8200 попыток:

    wretry = 8200;			/* more than we'll ever hafta write */

...т.к. данные еще не отправлены в сеть, а попытки делать еще можно (wretry не равен нулю):

    if ((rzleft) || (rnleft)) {		/* shovel that shit till they ain't */
	wretry--;			/* none left, and get another load */
	goto shovel;
    }

С TCP такое не прокатывало, потому-что все застревало еще на connect().

Хитрый баг, потому-что он проявляется только тогда, когда мы _не_ можем использовать Wireshark и следовательно посмотреть, что же все-таки уходит в сеть. Да, -j LOG и счетчики какбэ намекают, но уж очень это подозрительно выглядит когда без DROP'а все нормально считается, а с ним — нет. Надо было конечно сразу strace запускать :)

edigaryev ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.