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

порт источника 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-коммуникаций?

Я тестировал это локально и не могу воспроизвести поведение. Даже когда я настраиваю свой 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-interface.
  • Межсетевой экран или другое сетевое устройство между клиентом и сервером, которое выполняет рандомизацию порядкового номера TCP. В результате нельзя полагаться на то, что начальные порядковые номера, попадающие на сервер, будут больше, чем у предыдущего соединения, и могут привести к разрыву соединений.