Ниже приведен дамп программы wirehark, в котором IP-адреса заменены на «клиент» и «сервер»:
4414.229553 client -> server TCP 62464 > http [SYN] Seq=0 Win=65535 Len=0 MSS=1452 WS=3 TSV=116730231 TSER=0
4414.229633 server -> client TCP http > 62464 [SYN, ACK] Seq=0 Ack=1 Win=5792 Len=0 MSS=1460 TSV=2406364374 TSER=116730231 WS=6
4414.263330 client -> server TCP 62464 > http [ACK] Seq=1 Ack=1 Win=524280 Len=0 TSV=116730231 TSER=2406364374
4418.812859 server -> client TCP http > 62464 [SYN, ACK] Seq=0 Ack=1 Win=5792 Len=0 MSS=1460 TSV=2406365520 TSER=116730231 WS=6
4418.892176 client -> server TCP [TCP Dup ACK 778#1] 62464 > http [ACK] Seq=1 Ack=1 Win=524280 Len=0 TSV=116730278 TSER=2406365520
4424.812864 server -> client TCP http > 62464 [SYN, ACK] Seq=0 Ack=1 Win=5792 Len=0 MSS=1460 TSV=2406367020 TSER=116730278 WS=6
4424.891240 client -> server TCP [TCP Dup ACK 778#2] 62464 > http [ACK] Seq=1 Ack=1 Win=524280 Len=0 TSV=116730337 TSER=2406367020
Таким образом, обычная последовательность SYN, SYN + ACK, ACK, кажется, имеет место, за исключением того, что сервер, похоже, не интерпретирует ACK. Вместо этого он продолжает повторно отправлять SYN + ACK, на который клиент постоянно отвечает дубликатом предыдущего ACK. Я не понимаю, как это могло случиться.
Я заметил проблему, потому что отслеживание соединений iptables считает эти соединения установленными и сохраняет их в памяти на полный 120-часовой тайм-аут. У меня есть некоторые правила брандмауэра, чтобы предотвратить большое количество одновременных подключений, пределы которых были достигнуты людьми, без фактического наличия такого количества активных подключений. В netstat
команда не показывает эти фантомные соединения.
Другая информация:
Сервер представляет собой стандартную систему debian lenny со стандартным ядром:
Linux tb 2.6.26-2-686 #1 SMP Wed Aug 19 06:06:52 UTC 2009 i686 GNU/Linux
Бег:
Apache/2.2.9 (Debian) mod_ssl/2.2.9 OpenSSL/0.9.8g
У меня нет всей информации о клиенте (я не могу воспроизвести локально), но это Mac с браузером Chrome.
У меня нет правил брандмауэра, влияющих на ACK-пакеты. В основном я фильтрую только SYN-пакеты, все остальные TCP-пакеты пропускаются. Поэтому я на самом деле не использую отслеживание соединений для брандмауэра, кроме подсчета одновременных соединений и некоторого графического отображения установленных TCP-пакетов по сравнению с другими типами пакетов.
Изменить: мои правила iptables, относящиеся к TCP-порту 80:
iptables -P INPUT ACCEPT
iptables -A INPUT -p tcp --syn --dport 80 -m connlimit --connlimit-above 50 -j LOGDROP-CONN
iptables -A INPUT -p tcp --syn -m multiport --dports 80,443 -j ACCEPT
iptables -A INPUT -p tcp --syn -j REJECT --reject-with tcp-reset
iptables -A LOGDROP-CONN -m limit --limit 1/minute --limit-burst 1 -j LOG --log-prefix "ConConn "
iptables -A LOGDROP-CONN -j DROP
Изменить 2: еще один дамп, на этот раз с использованием tcpdump -vv:
16:05:52.999525 IP (tos 0x0, ttl 55, id 46466, offset 0, flags [DF], proto TCP (6), length 64) client.50538 > server.www: S, cksum 0x4429 (correct), 38417001:38417001(0) win 65535 <mss 1452,nop,wscale 3,nop,nop,timestamp 117224762 0,sackOK,eol>
16:05:52.999580 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 60) server.www > client.50538: S, cksum 0xa2ab (correct), 3062713115:3062713115(0) ack 38417002 win 5792 <mss 1460,sackOK,timestamp 2418739698 117224762,nop,wscale 6>
16:05:53.321788 IP (tos 0x0, ttl 55, id 24299, offset 0, flags [DF], proto TCP (6), length 52) client.50538 > server.www: ., cksum 0xe813 (correct), 1:1(0) ack 1 win 65535 <nop,nop,timestamp 117224765 2418739698>
16:05:56.252697 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 60) server.www > client.50538: S, cksum 0x9f7a (correct), 3062713115:3062713115(0) ack 38417002 win 5792 <mss 1460,sackOK,timestamp 2418740512 117224765,nop,wscale 6>
16:05:56.277250 IP (tos 0x0, ttl 55, id 15533, offset 0, flags [DF], proto TCP (6), length 52) client.50538 > server.www: ., cksum 0xe4c4 (correct), 1:1(0) ack 1 win 65535 <nop,nop,timestamp 117224798 2418740512>
Я бы использовал грубую силу. Сначала я бы попробовал, работает ли он с остановленным iptables. Если да, то это что-то в iptables.
Затем я добавлял правила одно за другим и смотрел, какое из них вызывает сбой соединения. Затем я играл с этим правилом до тех пор, пока он не делал то, что я хотел, не нарушая полностью трафик.
Если бы он не работал с остановленным iptables, это было бы действительно странно.
Хорошо, у меня нет полного ответа, но я многому научился с тех пор, как впервые возникла эта проблема. Я поделюсь своими мыслями здесь.
telnet www.website.com 80
и не отправлять никаких данных. Это все еще может быть особенностью Linux, поскольку все серверы, которые я тестировал, вполне могут работать под управлением Linux. Такое поведение также происходило без загруженных iptables-rules, так что это действительно связано с ядром.iptables
отслеживание соединений, похоже, не разделяет эту логику, поэтому соединение останется в ESTABLISHED
состояние до истечения времени ожидания. По умолчанию время ожидания составляет 5 дней (!). Я планирую сократить это до чего-то более разумного, например, до нескольких часов.nc -l ###
и связан с этим. Так что это может быть определенный параметр TCP, который Apache устанавливает для своего прослушивающего сокета. Или это может быть что-то совершенно уникальное для Apache. Большинство других демонов объявляют о себе сразу после подключения, поэтому они не подходят для этого. Соединение должно выполнить трехстороннее рукопожатие, а затем немедленно перейти в режим ожидания.Тем не менее, спасибо за идеи, данные выше, они помогли разобраться в этом.