LINUX.ORG.RU

Как получилось connect() к самому себе по TCP/IP, если я не слушал порт? И при этом совпали SRC и DST порты. Странный ESTABLISHED. Что это?

 


3

1

Короче, софтина «server» слушала 127.0.0.1:44112. На неё был коннект от софтины «client». По этому коннекту гонялось много данных. Потом софтину «server» убили, а на клиент пришёл дисконнект. На этот случай у «client» есть адский цикл, в котором он очень часто пытается коннектиться к «server» (connect()). Потом решили запустить «server» обратно. Но при попытке запустить «server» обнаружилось, что «server» не может забиндить себе свой порт 44112.

ERROR -1 == bind(), errno 98, "Address already in use"

И тут выяснилось, что существует странный коннект:

> netstat -natp | grep 44112
tcp        0      0 127.0.0.1:44112         127.0.0.1:44112         ESTABLISHED 10038/client    
К самому себе? «client» не слушал 44112. Или куда? Что это вообще такое? Этот коннект пропадает при убийстве «client».

Жесть какая-то: http://stackoverflow.com/questions/4021271/socket-getting-created-with-same-i...



Последнее исправление: hlamotron (всего исправлений: 2)

Что жесть, то да.

А не надо слушать порты, которые находятся в диапазоне для исходящих соединений.

Harald ★★★★★
()
Ответ на: комментарий от Harald

Видимо вы об этом?

https://en.wikipedia.org/wiki/Ephemeral_port

Получилось воспроизвести: вот этот код рано или поздно приводит к коннекту на самого себя,даже если я ничего не слушал, причём по этому порту гоняются какие-то данные. Жесть ваще!

while(1) {
    connect("127.0.0.1:44112");
}
hlamotron
() автор топика
Ответ на: комментарий от hlamotron

После многократных попыток порты совпали и телнет подключился сам к себе. Нормально работает, ввод дублируется выводом

telnet 127.0.0.1 44112

urquan
()

Здесь подробнее: http://sgros.blogspot.ru/2013/08/tcp-client-self-connect.html

И для проверки это фигни не обязатльно многократные проверки, достаточно прибиндить порт, на который устанавливаешь соединение:

nc -p 54321 127.0.0.1 54321

А для защиты можно только прописать правило в iptables для определённого порта, что REJECT пакетов, у которых src port = dst port. А универсального правила в iptables или tc, ИМХО, нет.

mky ★★★★★
()
Ответ на: комментарий от hizel

Шта!?

Да ладно, ты что не в курсе про то, что порты выше 32768(по крайней мере в Linux, официально там с другого более высокого номера диапазон начинается, гуглить лень) - динамические, и не предназначены для слушающих сокетов серверного ПО?

Правда факт того что вот так можно зациклить клиента лично для меня - новость. Но не то чтобы я сильно удивился - не зря ж диапазоны портов так разбиты. Видать при нецелевом использовании возможны грабли. В чём мы здесь и убедились :-)

Pinkbyte ★★★★★
()
Последнее исправление: Pinkbyte (всего исправлений: 1)
Ответ на: комментарий от Pinkbyte

ты что не в курсе про то, что порты выше 32768 - динамические, и не предназначены для слушающих сокетов серверного ПО

Я тоже не в курсе был... Что еще я не знаю о этой Вселенной? :)

I-Love-Microsoft ★★★★★
()
Ответ на: комментарий от hlamotron

Ну извини. Не могу придумать объяснения почему лучше следовать стандартам, чтобы избежать граблей, чем не следовать им - просто потому что можно это делать.

Pinkbyte ★★★★★
()
Ответ на: комментарий от hlamotron

Да всё логично. При коннекте исходящий порт выбирается рандомно незанятый из диапазона номеров больше 32768. Если часто делать коннекты, то чисто по теории вероятности исходящий порт может совпасть со входящим. А дальше уже UB. Теоретически ОС может делать дополнительную проверку, но это всё равно не исключит все возможные плохие ситуации. Например, наш порт может захватить другой клиент, который вполне легетимно приконнектился к иному ресурсу. В общем, как костыли не вставляй, а использование портов с номерами больше 32768 - потенциальный отстрел ноги.

Решение: не использовать эти порты для серверов. Тебе действительно так сложно это делать, с учётом того, что этот факт явно прописан в куче литературы? Ты бы ещё возмутился, что по UDP пакеты могут не доходить.

KivApple ★★★★★
()
Ответ на: комментарий от KivApple

А я чёт тоже это пропустил. Теперь хоть знаю

false ★★★★★
()
Ответ на: комментарий от KivApple

Хотя в принципе я понимаю, что если я буду слушать порт старше 32768, то в один момент я не смогу его слушать, т.к. ОС его заюзает как исходящий. Но всё равно неясно, почему описываемый в треде коннект реально осуществим.

Стандарт говорит, что эти порты могут использоваться для исходящих соединений. Ну хорошо, максимум чем это грозит - что я не смогу открыть порт для прослушивания в один прекрасный момент. Но почему из этого должно следовать, что я могу законнектиться сам на себя? Неужели TCP-стек, инициируя куда-то соединение не понимает, что он сейчас клиент, а не сервер? Почему он с радостью отзывается на прилетевший к нему SYN, не посылая такой SYN нахрен? Он ведь понимает, что он ничего не слушал, а сам начал коннект, хотя и на том же порту. Например я коннектился локально на порт 44111, который никто не слушал, и случайно выбрал его же как исходящий порт. Но я ведь понимаю, что я на этом порту клиент и что его никто не слушает. И, соответственно, все серверные поползновения в отношении этого порта могу легко рубить. Непонятно, почему TCP-стек не может отличить эти состояния.

Хотя, если подумать, наверное машина состояний TCP особо и не должна думать кто чего там начал, она просто умеет переходить из SYN в SYN+ACK а из него ещё там куда-то и без разницы кто что начал...

hlamotron
() автор топика
Ответ на: комментарий от hlamotron

Почему он с радостью отзывается на прилетевший к нему SYN, не посылая такой SYN нахрен?

Хотя, если подумать, наверное машина состояний TCP особо и не должна думать кто чего там начал, она просто умеет переходить из SYN в SYN+ACK а из него ещё там куда-то и без разницы кто что начал...

Судя по описанию, выглядящему разумно, при получении SYN в состоянии SYN-SENT предполагается TCP Simultaneous Open. Обратно отсылается ACK, и когда с того конца дойдёт SYN+ACK (или просто ACK), соединение считается установленным. Впрочем, действительно, ОС могла бы учитывать, что никакой нормальный процесс с одного порта самому себе на тот же самый порт пакеты не посылает.

proud_anon ★★★★★
()
Последнее исправление: proud_anon (всего исправлений: 1)
Ответ на: комментарий от PunkoIvan

любой(почти) клиент может быть сервером, а сервер - клиентом.

Разговор не про функцию, а про порядок инициации клиента. Кто инициатор, кто ответчик. Когда инициатор вдруг становится ответчиком - это жопа.

hlamotron
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.