Nginx-ru mailing list archive (nginx-ru@sysoev.ru)
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: ошибка в nginx ?
On Friday, July 11, 2008 at 23:50:36, Andrei Nigmatulin wrote:
>> IS> Единственное, что можно делать:
>> IS> ждать секунду и повторять попытку до истечения ..._connect_timeout.
>> backlog обычно бывает переполнен при (очень) большой нагрузке,
>> это сделает веб-сервера под управлением nginx на операционной
>> системе с ядром Linux гораздо более уязвимыми к DDOS-атакам.
[ ... ]
AN> А в "не-linux" по-другому ?
Да.
в других системах (например, FreeBSD) при попытке выполнить connect
в неблокирующем режиме к unix domain socket в ситуации переполнения
backlog`а этого socket`а возвращается ECONNREFUSED, в Linux - EAGAIN.
а например, там где все остальные POSIX-совместимые системы
возвращают EINPROGRESS - Windows возвращает WSAEWOULDBLOCK
и поскольку код WSAEWOULDBLOCK ~= EAGAIN, то для nginx везде
реакция на EAGAIN оказывается такой же, как и на EINPROGRESS.
src\event\ngx_event_connect.c
===========================================================
if (rc == -1) {
err = ngx_socket_errno;
/* Winsock returns WSAEWOULDBLOCK (NGX_EAGAIN) */
if (err != NGX_EINPROGRESS && err != NGX_EAGAIN) {
===========================================================
для FreeBSD - проблем нет, потому что функция connect никогда
не возвращает EAGAIN, из-за этого проблемы есть только в Linux.
POSIX connect:
http://www.opengroup.org/onlinepubs/000095399/functions/connect.html
WINSOCK connect:
http://msdn.microsoft.com/en-us/library/ms737625(VS.85).aspx
>> nginx будет ..._connect_timeout секунд держать tcp соединение
>> с клиентом, и будет раз в секунду пытаться установить соединение
>> с сервером при переполненном backlog`е - впустую растрачивая
>> системные ресурсы. и workaround к этой уязвимости неизвестен.
AN> Если бэкенд (на одной машине с nginx, ведь мы до сих пор говорим
AN> про локальные сокеты) настолько загружен, что не успевает разгребать
AN> очередь новых запросов, то у nginx должна быть четкая стратегия -
AN> держаться до последнего и делать все возможное.
попытками выполнить connect с интервалом в 1 секунду в течение 60 секунд
nginx будет только мешать backend`у обрабатывать другие клиентские запросы.
в случае подключения к backend`у на FreeBSD и при переполнении backlog`а
nginx сразу получает ответ ECONNREFUSED и сразу возвращает клиенту 502.
стратегия должна быть, прежде всего в виде одинаковой реакции
на одинаковые внешние события. "делать все возможное" в случае
перегрузки backend`а клиентскими запросами - это прежде всего,
не мешать ему работать и не создавать лишнюю нагрузку на сервер.
AN> Если он будет выдавать 502, то это значит атака удалась.
атака еще больше удалась, когда вместо 1 запроса к backend`у
nginx будет делать 60 запросов, на каждый из них затрачивая
системные ресурсы и без того уже перегруженного сервера.
например, если backlog для unix domain socket выставлен в 1024
и этот backlog уже полностью заполнен - нет смысла даже пытаться
создавать еще один "програмный backlog" на уровне nginx frontend`а
тем более - "програмный backlog" с неограниченным размером, который
администратору никак нельзя будет уменьшить или выключить.
потому что пока backend обработает 512 первых запросов из backlog`а,
часть клиентов просто отвалится по своему собственному connect_timeout
не дождавшись ответа от сервера, или пользователь закроет окно браузера.
AN> А продолжать попытки обработать запрос - это правильно, ведь в конце
AN> концов на это есть fastcgi_connect_timeout секунд, а вдруг получится.
fastcgi_connect_timeout - это не то, это connect timeout.
в данном случае нет timeout`а, а есть код ошибки EAGAIN.
и причина этой проблемы в nginx с EAGAIN на Linux - это Windows.
===================================================================
реакция на EAGAIN в Linux должна быть такой же как на ECONNREFUSED
в случае попытки connect к unix domain socket в non-bloking режиме
===================================================================
реакция на EAGAIN в Windows должна быть такой же как на EINPROGRESS
в случае попытки connect к anything domain socket в non-bloking режиме
===================================================================
если больше никакие системы кроме Linux и Windows
не возвращают EAGAIN из connect, то патч к функции
src\event\ngx_event_connect.c можно сделать в виде
блока условной компиляции, что позволит даже
несколько ускорить работу nginx на FreeBSD.
--
Best regards,
Gena
|