Назад | Перейти на главную страницу

Сервер не отправляет пакет SYN / ACK в ответ на пакет SYN

Используя iptraf, tcpdump и wirehark, я вижу приходящий 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

Я приложил изображение вывода wirehark.

http://imgur.com/pECG0.png

Вывод в 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-запрос примерно раз в секунду.

ФАЙЛ PCAP

После того, как возникла та же проблема, я наконец уловил основную причину.

В Linux, когда сокет находится в режиме TIME_WAIT и добавлен новый SYN (для той же пары ip / port src, ip / port dest), ядро ​​проверяет, является ли номер SEQ SYN <или>, чем последний полученный SEQ для этот сокет.

(PS: на изображении вывода wirehark, прикрепленного к этой проблеме, порядковые номера показаны как относительные, если вы не установите их как абсолютные, вы не увидите проблему. Захват должен также показать старый сеанс, чтобы иметь возможность сравнивать номера SEQ)

  • если номер SEQ SYN больше, чем номер SEQ предыдущего пакета, создается новое соединение, и все работает
  • если SEQ-номер SYN <, чем SEQ-номер предыдущего пакета, ядро ​​отправит ACK, относящееся к предыдущему сокету, потому что ядро ​​считает, что полученный SYN является задержанным пакетом предыдущего сокета.

Такое поведение происходит потому, что в начале TCP номер SEQ, сгенерированный компьютерами, был инкрементным, было почти невозможно получить номер SEQ <, чем номер SEQ предыдущего сокета, все еще находящегося в TIME_WAIT.

Увеличение пропускной способности компьютеров делает это практически невозможным. Но самое важное здесь то, что теперь большинство систем используют случайный ISN (начальный номер SEQ) для повышения безопасности. Так что ничто не мешает, чтобы номер SEQ a нового сокета был больше номера 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 указывает на это в пакете № 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 (или другой брандмауэр). service iptables stop отключит его до следующей перезагрузки - если это решит проблему, вам необходимо изменить настройки iptables.

Кроме того, если у вас включен IPv6 на вашем интерфейсе, иногда есть маршрут через ipv4, но не через ipv6. Когда это происходит, и маршрут ipv6 является «по умолчанию», ваши пакеты могут проходить по неправильному адресу (даже на правильном интерфейсе). Попробуйте отключить ipv6, чтобы узнать, не в этом ли проблема.