LINUX.ORG.RU

Но ведь это дыра для DDoS!

 , , ,


0

3

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

Ниже ссылки на этот стрим на обоих ресурсах:

Этот стрим посвящён проблеме закрытия сокета до того, как все посланные данные на самом деле ушли к получателю. Суть проблемы в том, что функция write (как и неупомянутая в стриме send) пишет данные в ядро, а дошли ли эти данные до получателя уже полностью она не знает, хотя сокеты в Linux блокирующие по-умолчанию. Если сразу после write() или send() вызвать close(sock), у принимающей стороны случится ECONNRESET (Connection reset by peer). Случиться это может в случае, если и принимающая сторона решила что-то нам послать в самом начале, а мы это не прочитали. Это важное условие, потому что в противном случае всё работает верно и без ухищрений.

Первую половину ролика сибиряк разбирает одну старую статью на эту тему, пробует повторить и исправить по статье данную проблему в своём тестовом коде. Вторая половина ролика посвящена исправлению кода в его старых проектах и в контексте этой темы она не так интересна.

В статье предлагаются следующие шаги для решения данной проблемы:

Во-первых предлагается вызывать shutdown(sock, SHUT_WR) на отправляющей стороне сразу после последнего write. Но этого недостаточно, поэтому так же предлагается выставить опцию сокета SO_LINGER которая уже сама по себе должна решить проблему, но почему-то её не решает и это выглядит так, как будто она просто не работает. Есть и Linux-only вещи, такие как SIOCOUTQ ioctl(). Но универсальным решением предлагается просто бесконечный цикл, в котором вычитываются все данные и лишь затем можно закрывать сокет.

Я проверил на своём компьютере большинство из выше перечисленного и этот бесконечный цикл действительно работает, а SO_LINGER с и без shutdown(sock, SHUT_WR) и даже с shutdown(sock, SHUT_RDWR) действительно не работает. Но ведь решение с бесконечным чтением в цикле - это дыра уровня DDoS, ведь если ко мне будет идти бесконечный поток данных, сокет я никогда не закрою.

Ещё одно наблюдение. Если перед закрытием сокета вызвать shutdown(sock, SHUT_WR) и короткий sleep, это так же решает проблему. Неужели в UNIX/Linux/POSIX нет нормального решения данной проблемы?



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

Не смотри никакие «программистские» видео. Нормальные программисты, адресующие свои послания (на тему программирования) другим нормальным людям, используют для этого текст. Видео вместо текста используется в двух случаях: 1) автор вовсе не программист, а на самом деле домохозяйка, замаскировавшая/идентифицирующая себя как программист, 2) послание адресовано вовсе не норм. людям, а умственно отсталым (у которых проблемы с чтением). Поскольку видео от домохозяек про программирование тебе явно не нужны, и видео для слабоумных, я надеюсь, тебе тоже не требуются, итог такой: забудь про видеохостинги и ютуб в частности, когда хочешь что-то узнать на тему программирования.

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

Что касается проблемы, то в большинстве случаев её нет и решать соответственно тоже нечего. То, что ты дальше описываешь - специально сломанный синтетический пример.

Ещё одно наблюдение. Если перед закрытием сокета вызвать shutdown(sock, SHUT_WR) и короткий sleep, это так же решает проблему.

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

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

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

Вообще, если ты не занимаешься проектированием сетевых сервисов - забей на это всё, оно тебя не коснётся. Если занимаешься - может быть когда-то допустишь баг (не в кодинге, в архитектуре), выглядящий похоже на это описание, ну и придётся его исправлять, поптуно разобравшись наконец в том о чем там пытались поведать.

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

Не смотри никакие «программистские» видео. Нормальные программисты, адресующие свои послания (на тему программирования) другим нормальным людям, используют для этого текст. Видео вместо текста используется в двух случаях: 1) автор вовсе не программист, а на самом деле домохозяйка, замаскировавшая/идентифицирующая себя как программист, 2) послание адресовано вовсе не норм. людям, а умственно отсталым (у которых проблемы с чтением). Поскольку видео от домохозяек про программирование тебе явно не нужны, и видео для слабоумных, я надеюсь, тебе тоже не требуются, итог такой: забудь про видеохостинги и ютуб в частности, когда хочешь что-то узнать на тему программирования.

Ты слишком категоричен. Например автор SerenityOS делает такие же виде с лайв кодингом и ещё немалое число программистов этим увлекается.

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

Этот сигнал от shutdown(sock, SHUT_WR) влияет на что-то ещё и поэтому без него sleep не работает. Можешь сам поиграться, вот tar.gz в base64.

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
/gaOuQyLACgAAA==
zg
() автор топика
Ответ на: комментарий от sergej

да, это страшная уязвимость уровня setenv в glibc! :)

Представь себе сервер, который закрывает сокеты именно таким способом. На сервер зашла куча народу и постоянно пишут на сервак рандомный мусор, не давая ему закрыть сокет. Сокеты закончились и вот он DDoS.

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

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

почему неправильному? выше процитировали коммент о том, что tcp - это не протокол прикладного уровня.

и я подробно не ковырял, но мне кажется оно должно отвалиться через net.ipv4.tcp_fin_timeout секунд в любом случае.

а можно ещё просто понаоткрывать соединений и ничего не делать - тож сокеты кончатся, дефолтный таймаут у tcp обычно довольно конский.

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

и я подробно не ковырял, но мне кажется оно должно отвалиться через net.ipv4.tcp_fin_timeout секунд в любом случае.

С чего бы ему отваливаться, если с другой стороны FIN ещё не посылали?

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

Представь себе сервер, который закрывает сокеты именно таким способом

Никто таким способом сокеты не закрывает, очевидно же. А то, что твой видеоблоггер его предложил в качестве «решения» - только подтверждает мои слова о том, что видео смотреть нельзя.

Но иногда нужен и голый TCP

Что значит «голый tcp» и кому нужен? Давай обвиним тогда «unix/linux/poxix» (c) идеологию работы с хранилищами, что они не позволяют прогам выполнять dd if=/dev/urandom of=/dev/sda (когда они хотят работать с «голым диском»). А когда ты эту проблему исправляешь (надо переключиться на рута) - начинают портиться файлы на диска, что есть «дос-атака».

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

shutdown() посылает fin и соединение попадает в fin-wait-1

если другая сторона fin не шлёт, то оно или оторвется по tcp_fin_timeout или когда-нибудь оторвется из-за превышения tcp_max_orphans

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

shutdown() посылает fin и соединение попадает в fin-wait-1

Верно

если другая сторона fin не шлёт, то оно или оторвется по tcp_fin_timeout или когда-нибудь оторвется из-за превышения tcp_max_orphans

Неверно. Вот давай прочтём вмести: https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt

tcp_fin_timeout - INTEGER
	The length of time an orphaned (no longer referenced by any
	application) connection will remain in the FIN_WAIT_2 state
	before it is aborted at the local end.  While a perfectly
	valid "receive only" state for an un-orphaned connection, an
	orphaned connection in FIN_WAIT_2 state could otherwise wait
	forever for the remote to close its end of the connection.
	Cf. tcp_max_orphans
	Default: 60 seconds

Видишь, этот таймаут относится к состоянию FIN_WAIT_2, а не FIN_WAIT_1 и «orphaned connection» в нашем случае вообще нет, что означает, что и tcp_max_orphans не поможет.

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

Укажите на проблему автору. Скорее всего обычные комментарии он игнорирует, поэтому отправьте через донат.

Возможно ему уже рассказали, потому что видео на Твиче пропало.

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

в интернетах пишут, что tcp_max_orphans закрывает FIN_WAIT_1, лично не проверял

советуют временно ставить tcp_max_orphans=0, а потом возвращать на место, чтобы позакрывать всё висящее в FIN_WAIT_1

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

И снова читаем в официальной документации ядра

tcp_max_orphans - INTEGER
	Maximal number of TCP sockets not attached to any user file handle,
	held by system.	If this number is exceeded orphaned connections are
	reset immediately and warning is printed. This limit exists
	only to prevent simple DoS attacks, you _must_ not rely on this
	or lower the limit artificially, but rather increase it
	(probably, after increasing installed memory),
	if network conditions require more than default value,
	and tune network services to linger and kill such states
	more aggressively. Let me to remind again: each orphan eats
	up to ~64K of unswappable memory.

То есть советующие уменьшать этот параметр советуют явно плохое.

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

Односторонний shutdown SHUT_WR не закрывает соединение, и не должен закрывать, ни через какой таймаут. Это соединение не закрыто, в нём только одна сторона закончила слать данные, а вторая при этом может их слать сколько угодно, и вовсе не в целях завершения сеанса, а в качестве обычной работы. Как пример - скачивание файла по http без keep-alive: клиент может послать запрос и FIN после него, а сервер будет отдавать ему файл, хоть час, хоть день, хоть неделю (если он большой). И только когда сервер закончит всё отдавать, он тоже сделает FIN и вот после этого соединение начнёт закрываться.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)

Зачем ты сначала смотришь какую-то херню, а потом несёшь её на ЛОР, при том, что сам же понимаешь, что херня?

Возьми да автору этого видео всё и выскажи.

P.S. В суть проблемы даже не вникал.

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

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

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

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

Зачем ты сначала смотришь какую-то херню, а потом несёшь её на ЛОР, при том, что сам же понимаешь, что херня?

Почему ты решил, что это херня? Например как работает SO_LINGER никто так и не объяснил. А ведь похоже, что это просто сломано и не работает ибо баг.

P.S. В суть проблемы даже не вникал.

Зачем тогда сообщение написал?

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

дежурить около сервака вахтовым методом

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

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

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

Автор злоупотребляет методом привлечением внимания, известным как ragebait: запостить твит вида «линукс какашка, линуксоиды фанатики» (точную цитату искать не буду) и фармить внимание разъярённой (и поддвакивающей с другой стороны) публики. Вопрос «правда его слова или неправда» оставлю за скобками, просто, ну, сложно теперь воспринимать человека не как клоуна-вниманиеняшу.

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

Автор злоупотребляет методом привлечением внимания, известным как ragebait: запостить твит вида «линукс какашка, линуксоиды фанатики» (точную цитату искать не буду) и фармить внимание разъярённой (и поддвакивающей с другой стороны) публики.

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

https://www.youtube.com/watch?v=81MdyDYqB-A

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

присматривать или полагаться на сторонние сервисы

хотя есть ещё 3й вариант - расчитывать, что ты нахрен никому не нужен чтоб тебя ддосить, я так обычно и делаю :)

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

в доке же написано

When enabled, a close(2) or shutdown(2) will not return until all queued messages for the socket have been successfully sent or the linger timeout has been reached.

А в реальном коде это так не работает. Скачай код выше, из base64 представления tar.gz архива и поиграйся с ним сам.

zg
() автор топика

Есть и Linux-only вещи, такие как SIOCOUTQ ioctl(). Но универсальным решением предлагается просто бесконечный цикл, в котором вычитываются все данные и лишь затем можно закрывать сокет.

Точно ли есть проблемы с асинхронными select/poll/epoll? Там ведь вроде как информируется когда данные были переданы или буфер пустой. Вот после этого события и закрывать сокет.

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

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

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

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

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

зы. вы чего боитесь-то? что close заблокируется каким-то внешними нехорошими людьми?

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 2)
  1. Смотреть видосики про программирование - это зашквар.
  2. А прикинь, принимающая сторона TCP пакет примет, а пакет с ACK обратно не пошлёт. Во какой ужос может быть.
Stanson ★★★★★
()