Порт источника TCP не является случайным

Когда мы пытаемся получить файл с веб-сервера, иногда доступ невозможен. После проверки связи с tcpdump мы увидели, что исходная машина случайным образом выбирает исходный порт для связи. Это должно быть хорошо, но «случайный выбор» не такой случайный, как предполагалось. Таким образом, исходные порты очень часто повторно используются через короткое время (иногда всего за 2 секунды). В системе назначения сокет находится в состоянии TIME_WAIT, поэтому связь прервана адресатом. Возникает вопрос, почему сервер выбирает порт источника недостаточно случайно (например, 3388, 3345,2345,3388).

Мы можем воссоздать точно такое же поведение при использовании wget со следующими параметрами:

wget -t 1 "xxx/test.html" -O /dev/null -o /dev/null -d --bind-address=yyy.yyy.yyy.yyy

Тогда система выбирает порт случайным образом, но не случайным образом, и если порт используется повторно слишком быстро, то обмен данными невозможен (повторная отправка SYN-пакетов)

Небольшая модификация оператора wget:

wget -t 1 "xxx/test.html" -O /dev/null -o /dev/null -d

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

Итак, наша исходная система работает точно так же, как и первый оператор wget, но нам нужно, чтобы она работала как вторая или выбирала порты более случайным образом. Как изменить поведение выбора портов-источников для TCP-коммуникаций?

0
задан 14 July 2016 в 14:06
1 ответ

Я проверил это локально и не могу воспроизвести поведение. Даже если я настрою машину linux на использование только двух локальных портов, я смогу без проблем инициировать несколько (20+) соединений к одному и тому же домену (внутреннему или внешнему). Я также гарантирую, что удаленный сервер находится в состоянии TIME-WAIT, установив no-http-keep-alive заголовок (и подтвердив это через netstat).

Я обнаружил, что при использовании флага --bind-address для WGET, он использует Bind() для создания сокета, где IP источника - это то, что указано в командной строке, а порт источника выбирается из /proc/sys/net/ipv4/ip_local_port_range. Всякий раз, когда необходимо выбрать новый порт источника, это будет предыдущий порт + 2. После достижения конца диапазона портов источника, он вернется к началу и снова начнет отсчет через два.

Когда вы опускаете флаг --bind-address, функция Connect() используется для установки сокета, где IP-адрес источника берется из интерфейса по умолчанию, а порт источника - это случайный порт в диапазоне /proc/sys/net/ipv4/ip_local_port_range. Новые порты источника также будут выбраны случайным образом из этого диапазона.

В любом случае, при повторном использовании сокета, начальный номер последовательности был увеличен внутренними TCP-часами, что позволяет серверам принять новое воплощение соединения. Это согласуется с моим тестированием 20 запросов на соединение с использованием одного и того же порта источника и увеличением значений ISN - все они принимаются сервером в состоянии TIME-WAIT.

Если исключить любые странности, вводимые tcp_tw_recycle, так как я не верю, что на Windows-сервере присутствует такая возможность, то единственное, что я могу придумать - это комбинация:

  • небольшого эфемерного диапазона портов, настроенного на вашем Linux-сервере, что приводит к регулярному повторному использованию локальных портов при использовании --bind-интерфейса .
  • Брандмауэр или какое-либо другое сетевое устройство между клиентом и сервером, которое выполняет рандомизацию номеров последовательностей TCP. В результате, нельзя полагаться на то, что начальные номера последовательности, попадающие на сервер, будут больше, чем предыдущее соединение и могут привести к обрыву соединения.
0
ответ дан 5 December 2019 в 09:53

Теги

Похожие вопросы