Сервер не отправляет пакет SYN/ACK в ответ на пакет SYN
Используя iptraf, tcpdump и wireshark, я вижу входящий пакет SYN, но в ответном пакете установлена только ACK FLAG.
Я использую Debian 5 с ядром 2.6.36
Я отключил window_scaling и tcp_timestamps, tcp_tw_recycle и tcp_tw_reuse:
cat /etc/sysctl.conf
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_tw_reuse = 0
net.ipv4.tcp_window_scaling = 0
net.ipv4.tcp_timestamps = 0
Я приложил изображение вывода Wireshark.
Вывод в netstat
netstat -natu | grep '72.23.130.104'
tcp 0 0 97.107.134.212:18000 72.23.130.104:42905 SYN_RECV
Я делаю все возможное, чтобы найти решение, и мне еще предстоит выяснить проблему, поэтому любая помощь / предложения очень ценятся.
ОБНОВЛЕНИЕ 1: я установил tcp_syncookies = 0 и заметил, что теперь я отвечаю с 1 SYN+ACK для каждых 50 запросов SYN. Хост, пытающийся подключиться, отправляет запрос SYN примерно раз в секунду.
5 ответов
После той же проблемы я, наконец, уловил причину
В Linux, когда сокет находится на TIME_WAIT и добавляется новый SYN (для той же пары ip/port src, ip/port dest), ядро проверяет, является ли SEQ-номер SYN <или>, чем последний SEQ, полученный для эта розетка.
(PS: на изображении вывода wireshark, приложенного к этой проблеме, seq номер показан как относительный, если вы не установите их как абсолютные, вы не увидите проблему. При захвате должен был бы показать старый сеанс также уметь сравнивать номера SEQ)
- если SEQ-номер SYN> чем SEQ-номер предыдущего пакета, создается новое соединение, и все работает
- если номер SEQ SYN <номера SEQ предыдущего пакета, ядро отправит ACK, связанный с предыдущим сокетом, потому что ядро считает, что полученный SYN является задержанным пакетом предыдущего сокета.
Такое поведение происходит, потому что в начале TCP номер SEQ, генерируемый компьютерами, где он был инкрементным, было почти невозможно получить номер SEQ <, чем номер SEQ предыдущего сокета, все еще находящегося в TIME_WAIT.
Увеличение пропускной способности компьютеров делает это от почти невозможного до редкого. Но самое важное здесь заключается в том, что сейчас большинство систем используют случайный ISN (начальный номер SEQ) для повышения безопасности. Так что ничто не мешает номеру SEQ нового сокета быть> номера SEQ предыдущего.
Каждая ОС использует различные алгоритмы, которые более или менее безопасны, чтобы избежать этой конкретной проблемы. http://www.bsdcan.org/2006/papers/ImprovingTCPIP.pdf дает хорошее представление об этой проблеме.
Есть последние хитрости... так что ядро отправит ACK, связанный со старым сеансом, тогда? Клиентская ОС должна получить ACK (предыдущего сеанса), не понимать его, потому что для клиента сеанс закрыт, отправьте RST. Когда сервер получит этот RST, он немедленно очистит сокет (поэтому он больше не будет в TIME_WAIT). Со своей стороны, клиент ожидает SYN/ACK, так как он не получает его, он отправит новый SYN . Тем временем RST был отправлен и сеанс очищен на сервере, поэтому этот вторичный SYN будет работать, а сервер ответит SYN / ACK и так далее.
Таким образом, нормальное поведение состоит в том, что соединение должно работать, но задерживаться на секунду (пока не будет отправлен вторичный SYN). В случае Джеффа, он сказал в комментарии, что использует брандмауэр Fortinet, эти брандмауэры (по умолчанию) сбрасывают ACK, связанный со старым сеансом (поскольку брандмауэр не видит открытого сеанса, связанного с ACK), поэтому клиент не отправить любой RST, и сервер не может очистить сеанс из состояния TIME_WAIT (кроме, конечно, в конце таймера TIME_WAIT). Команда "set anti-replay free " на fortinet может позволить перенаправлять этот ACK-пакет, а не отбрасывать.
Похоже, что 97.107.134.212 уже считает, что есть связь (72.23.130.104:42905, 97.107.134.212:18000)
,
Когда 72.23.130.104:42905 отправляет свой пакет SYN, его порядковый номер равен 246811966. Далее должен быть пакет SYN/ACK с собственным номером SEQ и значением ACK 246811967.
Но он отправляет ACK с SEQ=1736793629 и ACK=172352206. Это, вероятно, значения из более ранней связи.
Любые новые попытки подключения должны приходить с другого номера порта... это происходит? Wireshark указывает на это в pkt#11: "Номера портов TCP используются повторно".
Похоже, проблема в отправителе.
FWIW, я могу подключиться просто отлично:
1 0.000000 192.168.0.135 97.107.134.212 TCP 45883 > biimenu [SYN] Seq=809402803 Win=14600 Len=0 MSS=1460 SACK_PERM=1 TSV=2319725 TSER=0 WS=7
2 0.022525 97.107.134.212 192.168.0.135 TCP biimenu > 45883 [SYN, ACK] Seq=4293896301 Ack=809402804 Win=14600 Len=0 MSS=1360 SACK_PERM=1
3 0.022553 192.168.0.135 97.107.134.212 TCP 45883 > biimenu [ACK] Seq=809402804 Ack=4293896302 Win=14600 Len=0
Однажды я видел это раньше, потому что исходящие и входящие пакеты проходили по разным маршрутам в сети, и на входящем участке было устройство отслеживания подключений с отслеживанием состояния. Так как это устройство (в моем случае балансировщик нагрузки, но он мог бы быть просто брандмауэром) никогда не видел первоначальный SYN, SYN-ACK был сброшен на пол как ложный.
Это должно быть больше, чем просто асимметрия, потому что мы также пропускаем исходящий пакет:
SYN отключается, но мы не видим входящего SYN-ACK или исходящего ACK с локального сервера. Итак, что-то еще должно было проксировать оба этих пакета, и тогда мы видим входящий ACK - который действительно является четвертым пакетом в последовательности.
Я думаю, что WAN-ускоритель неправильно настроен между ними.
Я бы проверил несколько вещей:
Ваш хост является многодомным (например, у вас есть более одного интерфейса Ethernet?) - если это так, ваши маршруты могут быть испорчены. Самый простой способ проверить это - отключить вторичный интерфейс (ы) и посмотреть, исчезнет ли проблема.
Другая вещь, чтобы проверить, включен ли iptables (или некоторый другой брандмауэр). Служба iptables stop отключит ее до следующей перезагрузки - если это решит проблему, вам необходимо настроить параметры iptables.
Кроме того, если на вашем интерфейсе включен IPv6, иногда существует маршрут через ipv4, но не через ipv6. Когда это происходит, и маршрут ipv6 является "значением по умолчанию", ваши пакеты могут проходить по неправильному адресу (даже на правильном интерфейсе). Попробуйте отключить ipv6, чтобы увидеть, если это проблема.