TCP одновременное открытие и предотвращение самостоятельного подключения - PullRequest
12 голосов
/ 28 февраля 2011

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

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

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

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

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

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

Что ты думаешь? Как вы решаете проблему?

P.S. 1

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

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

Ответы [ 9 ]

14 голосов
/ 29 июля 2011

Когда я наткнулся на это, я был ошеломлен.Я мог бы выяснить, что номер исходящего порта случайно совпадает с номером входящего порта, но не потому, что квитирование 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 голосов
/ 10 марта 2011

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

2 голосов
/ 28 февраля 2011

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

Нет проблем, нет проблем.

1 голос
/ 11 марта 2011

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

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

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

В приведенном ниже сообщении кратко описывается, что такое пакет 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 и IP-адрес B - localhost

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

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

0 голосов
/ 11 марта 2011

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

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

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

0 голосов
/ 10 марта 2011

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

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

0 голосов
/ 09 марта 2011

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

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

0 голосов
/ 28 февраля 2011

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

0 голосов
/ 28 февраля 2011

Хм, это странная проблема.Если у вас есть клиент / сервер на одной и той же машине, и он всегда будет на одной и той же машине, возможно, лучше использовать общую память или сокет домена Unix или какую-либо другую форму IPC.запустить сервер на фиксированном порту и клиент на фиксированном исходном порту.Скажем, сервер работает на 5000, а клиент работает на 5001. У вас действительно есть проблема привязки к любому из них, если к ним привязано что-то еще.заставить клиента к нечетному номеру порта.Выберите случайное число в эфемерном диапазоне, ИЛИ это с 1, и затем вызовите bind () с этим.Если bind () завершается неудачно с EADDRINUSE, выберите другой нечетный номер порта и повторите попытку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...