Подтвердить что ты не робот

Одновременное открытое и самоподключение TCP

Стандарт TCP имеет функцию "одновременного открытия".

Признак функции, клиент пытается подключиться к локальному порту, когда порт находится из эфемерный диапазон, может иногда подключаться к себе (см. здесь).

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

Я использую RHEL 5.3, и мои клиенты постоянно пытаются подключиться к локальному серверу. В конце концов клиент подключается к себе.

Я хочу предотвратить ситуацию. Я вижу два возможных решения проблемы:

  • Не используйте эфемерные порты для портов сервера. Согласитесь с эфемерным диапазоном портов и настройте его на своих машинах (см. эфемерный диапазон)
  • Проверьте connect(), поскольку кто-то предлагает здесь.

Как вы думаете? Как вы справляетесь с проблемой?

P.S. 1

За исключением решения, которое я, очевидно, ищу, Я хочу, чтобы вы поделились своим жизненным опытом с этой проблемой.

Когда я нашел причину проблемы, я был "изумлен" на своем рабочем месте, люди не знакомы с ним. Сервер опроса, подключая его периодически, является обычной практикой ИМХО, так как это, что проблема не является общеизвестной.

4b9b3361

Ответ 1

Для сервера вам необходимо связать() сокет с портом. После того как адрр: пара портов имеет сокет, он больше не будет использоваться для неявного привязки в connect().

Нет проблем, никаких проблем.

Ответ 2

Когда я наткнулся на это, я был ошеломлен. Я мог бы понять, что исходящие номер порта случайно совпадает с номером входящего порта, но не почему TCP рукопожатие (SYN SYN-ACK ACK) будет успешным (спросите себя: кто отправляет ACK, если никто не делает listen() и accept()???)

Как Linux, так и FreeBSD показывают это поведение.

В любом случае, одно из решений заключается в том, чтобы не допускать большого количества номеров портов для серверов.

Я заметил, что Дарвин делает эту проблему, не допуская выходного порта чтобы быть таким же, как порт назначения. Они, должно быть, тоже были укушены этим...

Легкий способ показать этот эффект выглядит следующим образом:

while true
do
    telnet 127.0.0.1 50000 
done

И подождите минуту или около того, и вы будете общаться с самим собой...

Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refused
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refused
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refused
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
hello?
hello?

Во всяком случае, он делает хороший материал для собеседования.

Ответ 3

Привяжите клиентский сокет к порту 0 (системные назначения), проверьте назначенный порт, если он соответствует порту локального сервера, который уже знает, что сервер выключен и может пропустить connect().

Ответ 4

Обратите внимание, что это решение является теоретическим, и я не тестировал его самостоятельно. Я не испытывал этого раньше (или не понимал), и, надеюсь, я больше не переживу этого.

Я предполагаю, что вы не можете редактировать ни исходный код клиента, ни источник сервера. Кроме того, я предполагаю, что реальной проблемой является сервер, который не может запускаться.

Запустите сервер с помощью стартового приложения. Если целевой порт, который будет связываться с сервером, используется любым процессом, создайте пакет RST (reset) с помощью сырых сокетов.

В приведенном ниже сообщении кратко описывается, что такое пакет RST (взятый из http://forum.soft32.com/linux/killing-socket-connection-cmdline-ftopict473059.html)

Вам нужно посмотреть на генератор пакетов "raw socket".
И вы должны быть суперпользователем.
Вам, вероятно, нужен сетевой сниффер.

http://en.wikipedia.org/wiki/Raw_socket
http://kerneltrap.org/node/3072 - Атаки TCP RST
http://search.cpan.org/dist/Net-RawIP/lib/Net/RawIP.pm - модуль Perl
http://mixter.void.ru/rawip.html - исходный IP-адрес в C

В версии C вам нужен пакет TH_RST.

RST предназначен для обработки следующего случая.

A и B установить соединение.
B перезагружается и забывает об этом.
A отправляет пакет B в порт X из порта Y.

B отправляет RST-пакет обратно, говоря "о чем вы говорите? иметь с вами связь. Пожалуйста, закройте это соединение."

Итак, вы должны знать/подделывать IP-адрес B и знать оба порта X
и Y. Одним из портов будет известный номер порта. Другой вы должны это выяснить. Я также хочу знать последовательность номер.

Обычно люди делают это с помощью сниффера. Вы можете использовать переключатель с помощью функцию зеркального отображения пакетов или запустить снифер на любом из хостов A или B.

В качестве примечания, Comcast сделал это, чтобы отключить трафик P2P.
http://www.eff.org/wp/packet-forgery-isps-report-comcast-affair

В нашем случае нам не нужно использовать сниффера, так как мы знаем следующую информацию:

Итак, вы должны знать/подделывать IP-адрес B и знать оба порта X и Y

X = Y и B IP-адрес - localhost

Учебник по http://mixter.void.ru/rawip.html описывает, как использовать Raw Sockets.

ПРИМЕЧАНИЕ, что любой другой процесс в системе может также украсть наш целевой порт из эфемерного пула. (например, Mozilla Firefox). Это решение не будет работать для такого типа подключений, поскольку X!= Y B IP-адрес не является локальным, а что-то вроде 192.168.1.43 на eth0. В этом случае вы можете использовать netstat для получения IP-адреса X, Y и B, а затем создать RST-пакет соответственно.

Ответ 5

Хмм, это странная проблема. Если у вас есть клиент/сервер на одном компьютере, и он всегда будет на одном компьютере, возможно, разделяемая память или сокет домена Unix или какая-либо другая форма IPC - лучший выбор.

Другими параметрами могут быть запуск сервера на фиксированном порту и клиент на фиксированном исходном порту. Скажем, сервер работает на 5000, а клиент работает на 5001. У вас есть проблема привязки к любому из них, если к ним привязано что-то еще.

Вы можете запустить сервер на четном номере порта и заставить клиента указать номер нечетного порта. Выберите случайное число в эфемерном диапазоне, ИЛИ оно с 1, а затем вызовите bind() с этим. Если bind() не работает с EADDRINUSE, выберите другой номер нечетного порта и повторите попытку.

Ответ 6

Этот параметр фактически не реализован в большинстве TCP. У вас есть реальная проблема?

Ответ 7

Это интересная проблема! Если вы в основном обеспокоены тем, что ваш сервер работает, вы всегда можете реализовать механизм heartbeat на самом сервере, чтобы сообщить о статусе другому процессу. Или вы можете написать script, чтобы проверить, работает ли ваш серверный процесс.

Если вы обеспокоены фактическим подключением к имеющемуся серверу, я предлагаю переместить вашего клиента на другую машину. Таким образом, вы можете убедиться, что на вашем сервере, по крайней мере, есть сетевое подключение.

Ответ 8

По-моему, это ошибка в спецификации TCP; прослушивающие сокеты не должны отправлять нежелательные SYN, а получение SYN (а не SYN + ACK) после того, как вы отправили сообщение, должно быть незаконным и привести к reset, который быстро позволит клиенту закрыть несчастливо -изменить локальный порт. Но никто не просил моего мнения;)

Как вы говорите, очевидным ответом является не прослушивание в эфемерном диапазоне портов. Другое решение, если вы знаете, вы будете подключаться к локальной машине, заключается в разработке вашего протокола, чтобы сервер отправил первое сообщение и имел короткий тайм-аут на стороне клиента для получения этого сообщения.

Ответ 9

Фактическая проблема, с которой вы сталкиваетесь, заключается в том, что пока сервер не работает, что-то еще может использовать эфемерный порт, который вы ожидаете от своего сервера в качестве исходного порта для исходящего соединения. Детальная информация о том, как это происходит, является отдельной для реальной проблемы, и это может происходить способами, отличными от того, как вы описываете.

Решение этой проблемы - установить SO_REUSEADDR в сокет. Это позволит вам создать сервер на порту, имеющем текущее исходящее соединение.

Если вы действительно заботитесь об этом номере порта, вы можете использовать специальные методы работы, чтобы остановить его выделение как эфемерный порт.