Когда ddos начался, с непривычки было непонятно, что происходит: в access_log веб-сервера понемногу добавлялись новые запросы, но при попытке открыть сайт браузером я получал отказ. Поскольку с ddos раньше не сталкивался, то первые несколько часов думал, что какие-то сетевые проблемы (провайдер, где стоит проксирующий http-сервер, иногда имеет проблемы со связностью до провайдера, где стоит главный http-сервер). Когда стало ясно, что проблема более серьезная, запустил tcpdump и увидел большую сетевую активность.
Как выяснилось позже, наличие DDoS проще всего определить, установив скорость поступающих по внешнему интерфейсу пакетов, в linux это проще всего сделать чтением из /proc/net/dev:root@laylah ~ #cat /proc/net/dev Inter-| Receive | Transmit face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed lo:59286813 278952 0 0 0 0 0 0 59286813 278952 0 0 0 0 0 0 eth0:38433436 575324 0 0 0 0 0 0 64005875 101279 0 0 0 0 0 0 eth1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 eth2: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 eth3: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 eth4:160842629303 1968355293 0 9282641 689519 0 0 0 175815679927 464227952 0 0 0 0 0 0
На основании поля "Receive packets" можно рассчитать скорость поступающих на интерфейсов пакетов, для моего сервера в нормальных условиях эта цифра колеблется от 100 до 1000 пакетов в секунду. Во время же DDoS цифра за несколько десятков секунд достигает значений в десятки тысяч пакетов в секунду и продолжает держаться, пока продолжается атака.
Sat Dec 12 13:31:58 2009: 202 Sat Dec 12 13:31:59 2009: 261 Sat Dec 12 13:32:00 2009: 206 Sat Dec 12 13:32:01 2009: 180 Sat Dec 12 13:32:02 2009: 188 Sat Dec 12 13:32:03 2009: 184 Sat Dec 12 13:32:04 2009: 190 Sat Dec 12 13:32:05 2009: 112 Sat Dec 12 13:32:06 2009: 284 Sat Dec 12 13:32:07 2009: 284 Sat Dec 12 13:32:08 2009: 250 Sat Dec 12 13:32:09 2009: 264 Sat Dec 12 13:32:10 2009: 246 Sat Dec 12 13:32:11 2009: 192 Sat Dec 12 13:32:13 2009: 118 Sat Dec 12 13:32:14 2009: 464 Sat Dec 12 13:32:15 2009: 1173 Sat Dec 12 13:32:16 2009: 1252 Sat Dec 12 13:32:17 2009: 3446 Sat Dec 12 13:32:18 2009: 2466 Sat Dec 12 13:32:19 2009: 3693 Sat Dec 12 13:32:20 2009: 5035 Sat Dec 12 13:32:21 2009: 3761 Sat Dec 12 13:32:22 2009: 2685 Sat Dec 12 13:32:23 2009: 3439 Sat Dec 12 13:32:24 2009: 6848 Sat Dec 12 13:32:25 2009: 12287 Sat Dec 12 13:32:26 2009: 12611 Sat Dec 12 13:32:27 2009: 13721 Sat Dec 12 13:32:28 2009: 12845 Sat Dec 12 13:32:29 2009: 12156 Sat Dec 12 13:32:30 2009: 11656 Sat Dec 12 13:32:31 2009: 12708 Sat Dec 12 13:32:32 2009: 13890 Sat Dec 12 13:32:33 2009: 16133 Sat Dec 12 13:32:34 2009: 19523 Sat Dec 12 13:32:35 2009: 19457 Sat Dec 12 13:32:36 2009: 12814 Sat Dec 12 13:32:37 2009: 12699 Sat Dec 12 13:32:38 2009: 11544 Sat Dec 12 13:32:39 2009: 11999 Sat Dec 12 13:32:40 2009: 11553 Sat Dec 12 13:32:41 2009: 12775 Sat Dec 12 13:32:42 2009: 12510 Sat Dec 12 13:32:43 2009: 13831 Sat Dec 12 13:32:44 2009: 15287 Sat Dec 12 13:32:45 2009: 14523 Sat Dec 12 13:32:46 2009: 14575 Sat Dec 12 13:32:47 2009: 13435 Sat Dec 12 13:32:48 2009: 13682 Sat Dec 12 13:32:49 2009: 14495 Sat Dec 12 13:32:50 2009: 17310 Sat Dec 12 13:32:51 2009: 18253 Sat Dec 12 13:32:52 2009: 16196 Sat Dec 12 13:32:53 2009: 15136 Sat Dec 12 13:32:54 2009: 15249 Sat Dec 12 13:32:55 2009: 15542 Sat Dec 12 13:32:56 2009: 15279 Sat Dec 12 13:32:57 2009: 14835 Sat Dec 12 13:32:58 2009: 14478 Sat Dec 12 13:32:59 2009: 15961 Sat Dec 12 13:33:00 2009: 16179 Sat Dec 12 13:33:01 2009: 18295 Sat Dec 12 13:33:02 2009: 21040 Sat Dec 12 13:33:03 2009: 19100 Sat Dec 12 13:33:04 2009: 17054 Sat Dec 12 13:33:05 2009: 19715
Сетевые настройки по умолчанию не очень хорошо подходят для работы при больших нагрузках, их нужно поправить (ниже не окончательный вариант, как минимум не решена проблема Out of socket memory, возможно, поможет установка параметра /proc/sys/net/ipv4/tcp_tw_recycle, но это еще не проверено)
# увеличение буферов (ring buffer) интерфейса, # включение tcp checksum offloading, # по совету Влада Селиверстова: ethtool -G eth4 rx 4096 tx 4096 ethtool -K eth4 tso on sysctl -w net.ipv4.tcp_max_syn_backlog=65536 # Увеличение памяти, доступной tcp стеку, по мотивам # http://wwwx.cs.unc.edu/~sparkst/howto/network_tuning.php # !!! memory pages; page size: getconf PAGESIZE #sysctl -w net.ipv4.tcp_mem="32768 32768 32768" # 128MB sysctl -w net.ipv4.tcp_mem="131072 131072 131072" # 512MB # http://www.susegeek.com/networking/network-performance-fine-tuning-in-opensuse-suse/ sysctl -w net.ipv4.tcp_no_metrics_save=1 # чтобы установленные выше параметры # вступили в силу как можно скорее sysctl -w net.ipv4.route.flush=1 # включение tcp syn cookies (против syn flood) echo 1 > /proc/sys/net/ipv4/tcp_syncookies # увеличение таблицы conntrack echo 224000 > /proc/sys/net/ipv4/netfilter/ip_conntrack_max # уменьшение timeout-ов echo 1 > /proc/sys/net/ipv4/tcp_synack_retries echo 1 > /proc/sys/net/ipv4/tcp_syn_retries echo 1 > /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_last_ack echo 1 > /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_syn_recv echo 1 > /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_fin_wait
Обнаружение атакующих ip адресов я делал на основании access_log проксируюющего веб-сервера, получая в режиме реального информацию об обращающихся к серверу ip адресах. С момента начала атаки (резкого роста скорости входящего трафика) до момента стабилизации ситуации (когда пользователи могли в половине случаев получить доступ к контенту веб-сервера) обычно проходило от 1 до 2 часов. Выявление атакующих ip адресов я делал на основании следующих алгоритмов.Обнаружение атакуемого URL
URL считается атакуемым, если на протяжении последних 30 секунд к нему обращались хотя бы раз в 26 или более секунд (при этом абсолютное число обращений на этом этапе не учиывается). Понятно, что для разных серверов этот параметр будет плавающим -- ключевым является проведение черты между нормальной нагрузкой и нагрузкой в условиях атаки. После обнаружения атакуемого URL полезно "закрывать" его на веб-сервере так, чтобы он отдавался максимально быстро, я делал это путем возврата HTTP 503. Можно также делать статическую копию атакуемого URL (если она будет небольшой по размеру) или "переименовывать" на время оригинальную страницу, а по атакуемом адресу возвращать объяснение ситуации и ссылку на переименованную страницу. URL перестает считаться атакуемым, если вышеописанное условие не выполнялось для него ни разу за последние 30 минут -- после этого его можно "открывать" для всех.Обнаружение вяло атакующих ip адресов
Для каждого ip адреса включается счетчик обращений к атакуемым URL; если ip адрес обратится более 15 раз к атакуемым url, то я считал его атакующим. При этом если до достижения порогового значения ip адрес обращался к неатакуемому url, то он вносился на 300 секунд в whitelist, по истечении 300 секунд алгоритм подсчета обращений к атакуемому URL запускался заново (счетчик обнулялся). При большом количестве атакующих машин этот процесс, растягивается на продолжительное время (чем больше атакующих машин, тем больше времени понадобится, чтобы их выявить).Обнаружение агрессивно атакующих ip адресов
Критерием агрессивной атаки я выбрал X > 4 * Y, где X -- количество обращений от ip адреса к серверу за предыдущую секунду, а Y -- количество разных url, запрошенных этим же ip адресом с сервера за ту же секунду. То есть, если ip адрес запросил за последнюю секунду один URL пять или более раз, то он атакует, если меньше пяти раз, то не атакует. Если ip адрес запросил за последнюю секунду два разных URL суммарно девять или более раз, то он атакует, если меньше девяти раз, то не атакует. И так далее. Таким образом учитывается обычный режим работы пользователя с сайтом: чаще всего пользователь в одну секунду запрашивает html файл и используемые в нем картинки, css, javascript -- это может быть до 15 запросов в секунду, но все 15 url будут разными (а атакующий ip адрес в моем случае 15 раз запрашивал один и тот же url).Обнаружение умеренно атакующих ip адресов
Возможен также некий средний по отношению к двум предыдущим способ поведения атакующего, когда он не считается вяло атакующим, потому что иногда запрашивает "неатакуемые" url, и не считается агрессивно атакующим, потому что не делает более 2-3 запросов в секунду. Для обнаружения таких ip адресов я использовал формулу X > 2 * Y, где X -- суммарное количество обращений ip адреса к серверу за последние 30 секунд, а Y -- количество секунд за последние 30 секунд, в которые данный ip адрес обращался к серверу хотя бы раз. При этом формула применялась только для тех ip адресов, для которых Y был больше 26. Важным моментом в этом алгоритме является то, что под него попадает поведение большинства поисковых роботов, поэтому для дополнительной надежности я делал проверку PTR записи и не считал атакующими ip адреса, принадлежащие большим поисковым компаниями (типа yandex, google, yahoo, mail.ru).
ip адреса, определенные как атакующие, по любому из вышеперечисленных алгоритмов, заносились в iptables как адреса, от которых не принимается никакой трафик.Линейный перебор
Сначала я заносил все атакующие адреса в таблицу INPUT, что приводило к такого вида таблице:-A INPUT -s 70.45.85.229/32 -j DROP -A INPUT -s 200.138.47.57/32 -j DROP -A INPUT -s 189.4.53.142/32 -j DROP -A INPUT -s 201.66.199.79/32 -j DROP -A INPUT -s 62.139.191.250/32 -j DROP -A INPUT -s 187.2.255.74/32 -j DROP -A INPUT -s 190.166.157.186/32 -j DROP -A INPUT -s 69.79.164.210/32 -j DROP -A INPUT -s 59.94.250.211/32 -j DROP -A INPUT -s 189.220.189.73/32 -j DROP -A INPUT -s 200.163.52.146/32 -j DROP -A INPUT -s 190.48.174.83/32 -j DROP -A INPUT -s 41.210.9.67/32 -j DROP -A INPUT -s 117.18.229.8/32 -j DROP -A INPUT -s 41.214.205.171/32 -j DROP -A INPUT -s 41.189.39.240/32 -j DROP -A INPUT -s 41.239.22.225/32 -j DROP -A INPUT -s 190.59.53.242/32 -j DROP -A INPUT -s 122.161.58.106/32 -j DROP -A INPUT -s 85.9.119.10/32 -j DROP -A INPUT -s 189.74.118.168/32 -j DROP -A INPUT -s 122.173.219.232/32 -j DROP -A INPUT -s 41.202.76.107/32 -j DROP -A INPUT -s 95.84.101.89/32 -j DROP -A INPUT -s 222.252.120.15/32 -j DROP -A INPUT -s 187.22.95.128/32 -j DROP -A INPUT -s 189.195.73.181/32 -j DROP -A INPUT -s 201.153.129.252/32 -j DROP -A INPUT -s 122.162.80.113/32 -j DROP -A INPUT -s 200.141.94.236/32 -j DROP -A INPUT -s 188.54.122.155/32 -j DROP
С ростом базы блокируемых ip адресов таблица увеличивалась, из-за чего увеличивалось время проверки каждого поступающего пакета. При превышении определенного количества блокируемых ip адресов и превышении определенной скорости поступающих пакетов машина переставала справляться с нагрузкой. Это выглядело, как очень длинные задержки при работе по ssh вплоть до невозможности подключения, а также очень сильные задержки при работе с консолью, кроме того в top висел процесс ksoftirqd/0 (или ksoftirqd/1, ksoftirqd/2, ksoftirqd/3). По совету Владимира Неверова я установил irqbalance, но это ситуацию не исправило. Озвучивалась также версия, что данное поведение проявляется, когда сетевая карта перестает справляться с входящим потоком, однако версия не оправдалась, потому что внесение первым пунктом в таблицу INPUT iptables правила-A INPUT -p tcp -m tcp --dport 80 -j DROP
моментально исправляло положение.Линейный перебор по октетам
Дмитрий Тейблюм посоветовал изменить порядок блокировки атакующих ip адресов следующим образом. Для блокировки ip адреса A.B.C.D в iptables создаются: 1) в таблице INPUT правило -s A.0.0.0/8 -j A 2) таблица A с правилом -s A.B.0.0/16 -j A_B 3) таблица A_B с правилом -s A.B.C.0/24 -j A_B_C 4) таблица A_B_C с правилом -s A.B.C.D/32 -j DROP При таком способе блокировки ip адресов при любом размере базы скорость проверки ip адреса не превышает 4 выборов из таблицы размером 255 элементов. Это оказывается заметно эффективней, чем линейный перебор таблицы в 10,000 ip адресов.
Для работы с DDoS использовался сервер на базе Intel Xeon E5310 quad-core с 8 гигабайтами оперативной памяти, встроенной сетевой картой на чипсете Intel 80003ES2LAN (linux pci id 8086:1096), PCI Express сетевой картой на чипсете Intel 82576 (linux pci id 8086:10e8), linux 2.6.31-gentoo-r5. Сервер адекватно работал на скоростях до 60,000 входящих пакетов в секунду и базой блокируемых ip адресов порядка 10,000 (на больших цифрах не удалось проверить, но есть предположение, что при использовании схемы Тейблюма потолок заметно выше). Описанная схема линейно масштабируется путем установки нескольких проксирующих серверов и разделения входящего потока на них. При создании общих баз (атакуемых url, счетчиков, блокируемых ip адресов) эффективность защиты дополнительно возрастает. Например, для подавления атаки со 100,000 ip адресов скоростью в 600,000 пакетов в секунду потребуется 10 серверов описанного типа и один высокопроизводительный балансер, поддерживающий скорость 600,000 пакетов в секунду на одном интерфейсе.
При DDoS атаках описанного вида есть возможность сохранять в целом работоспособной большую часть атакуемого сервиса. До некоторой степени неработоспособными могут оказаться непосредственно атакуемые адреса, но при использовании определенных техник и их работоспособность можно в основном сохранить. При ограниченности доступных на подавление атаки ресурсов (ширина канала подключения, стоимость входящего трафика, количество отражающих атаку серверов) крайне полезным оказывается ограничение на скорость входящих TCP SYN пакетов, впрочем это ограничение пропорционально уменьшает как количество паразитного трафика, так и количество полезного трафика.
-- petya@kohts.ru, 2009