FastNetMon

Monday 29 December 2014

Профайлинг Perl приложений

Всем привет! Сегодня мы будем профайлить Perl приложения и искать в них узкие места!

Итак, я веду эксперименты над своей новой утилиткой - linux_network_activity_tracker.pl, которая на машинах с десятками тысяч процессов работает довольно медленно.

Итак, запускаем профайлинг:
perl -d:DProf linux_network_activity_tracker.pl
После того, как он отработал нам нужно запустить обработчик полученных данных:
dprofpp
В итоге нам будет сгенерирована удобная и доступная для понимания табличка:
Total Elapsed Time = 78.18037 Seconds
  User+System Time = 57.55037 Seconds
Exclusive Times
%Time ExclSec CumulS #Calls sec/call Csec/c  Name
 57.1   32.89 32.893  26894   0.0012 0.0012  Antidoto::get_process_connections
 30.0   17.30 17.620    342   0.0506 0.0515  Antidoto::parse_tcp_connections
 6.52   3.750  3.750    342   0.0110 0.0110  Antidoto::parse_unix_connections
 1.00   0.576  1.019   6986   0.0001 0.0001  Antidoto::get_proc_status
 0.98   0.563  0.563   7328   0.0001 0.0001  Antidoto::read_file_contents_to_li
                                             st
 0.56   0.323  0.323 136504   0.0000 0.0000  Antidoto::_hex2ip
 0.28   0.160  0.160    342   0.0005 0.0005  Antidoto::build_inode_to_socket_lo
                                             okup_table
 0.13   0.073  1.092    342   0.0002 0.0032  Antidoto::get_init_pid_for_contain
                                             er
 0.05   0.028  0.037    342   0.0001 0.0001  Antidoto::parse_udp_connections
 0.02   0.010  0.010      4   0.0025 0.0025  main::BEGIN
 0.00       - -0.000      1        -      -  DynaLoader::dl_load_file
 0.00       - -0.000      1        -      -  DynaLoader::dl_undef_symbols
 0.00       - -0.000      1        -      -  DynaLoader::dl_find_symbol
 0.00       - -0.000      1        -      -  DynaLoader::dl_install_xsub
 0.00       - -0.000      1        -      -  Digest::MD5::bootstrap
По которой отлично видно, кто пожрал время CPU :)

Wednesday 24 December 2014

Как работает механизм SYN Cookie в ядре Linux?

Всем привет! 

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

Именно это и делает SYN cookie. В ответ на клиентский SYN пакет мы НЕ сохраняем никакой информации о соединении, а пакуем ее в ответный SYN+ACK пакет и отправляем клиенту. И лишь в случае, когда клиент ответит нам своим ACK передав эту информацию - мы ее проверим, распакуем информацию содержащуюся в нем и создадим запись о таком соединении и откроем обмен данными.

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

Как известно, эта фича включается так:
sysctl -w net.ipv4.tcp_syncookies = 1
Но когда именно они включаются? Как работают? Всегда ли это панацея? На эти вопросы я постараюсь ответить ниже.

Вся обработка входящего tcp соединения начинается в файле net/ipv4/tcp_input.c в функции tcp_conn_request. Там сразу после приема пакета осуществляется следующая проверка:
if ((sysctl_tcp_syncookies == 2 || inet_csk_reqsk_queue_is_full(sk)) && !isn) {      want_cookie = tcp_syn_flood_action(sk, skb, rsk_ops->slab_name); }
Дословно она означает, что syn cookie включаются (не посылаются! А просто включаются!) если параметр sysctl -w net.ipv4.tcp_syncookies = 2 либо когда переполнится syn очередь для сокета (а она в свою очередь задается через параметр net.ipv4.tcp_max_syn_backlog = 2048).

Уже сейчас можно понять, что 2048 - это очень много и почти любое приложение после получения такого числа запросов на подключение погибнет. При этом syn cookie включенные в режиме "1" еще даже не включатся!

Чуточку дальше в том же файле tcp_input.c осуществляется проверка - а не переполнена ли очередь ожидания на слушающем (listen) сокете, она в свою очередь задается на уровне приложения, через второй аргумент системного вызова listen. И если она полна - то соединение просто отбрасывается, безотносительно режиму syn cookie вообще! Система предполагает, что приложение не может больше отработать и в принципе не принимает трафик. На этом обработка кончается. Если же очередь не забита - мы движемся дальше.

Обращаю внимание! Что syn cookie еще НЕ был отправлен! Даже если он был включен на какой-то из предыдущих проверок.

Теперь мы вызываем функцию cookie_init_sequence, которая в свою очередь дергает cookie_v4_init_sequence, которая объявлена в net/ipv4/syncookies.c. И там параметры входящего соединения хэшируются с помощью хэш функции sha1 (secure_tcp_syn_cookie). В свою очередь, стоит обратить внимание, что sha1 - это довольно тяжелая функция для процессора и довольно серьезный Intel E5 2620 может хэшировать не более 400 мегабайт/секунду в расчете на 1 ядро. Постойте пугаться! Не съедят syn cookie Ваш процессор, даже довольно слабый 2620 может обработать до 32Gb/s чисто на хэшировании, это огромные цифры, так что нагрузки на процессор пугаться не стоит - я просто привел информацию о том, что это не бесплатная операция.

И после того как эта cookie сформирована, мы посылаем ее клиенту. Как можно заметить - режим "2" работы syn cookie на сервере, где ожидаются атаки - предпочтительнее. Но стоит понимать, что syn cookie - это хак, который не особо согласуется с протоколом tcp и бывает, что он приводит к неработоспособности ряда фич, поэтому использовать его нужно лишь после тщательных тестов. Но при этом такой подход все равно  не защищает приложения должным образом.

Как хорошее и надежное решение данной проблемы стоит использовать iptables/netfilter цель SYN PROXY, которая блокирует  syn флуд раньше, чем они пойдет в обработку ядром (на этапе фильтрации через netfilter). Но тут стоит отметить, что данный функционал был добавлен в 3.12 ядре и присутствует только в RHEL/CentOS 7, в более младших версиях дистрибутивов такой возможности нету и вряд ли появится.

Но я бы хотел добавить, что syn cookie должны быть ВКЛЮЧЕНЫ в обязательном порядке. Вообще без них Linux упадет от самой слабой атаки syn флудом.

В чем же отличия 1 и 2го режимов syn cookie? В первом режиме они подключаются, когда переполняется очередь syn соединений на 1 порт, а во втором режиме они включаются безусловно даже очередь пуста. То есть для ВСЕХ соединений.

Подробнее читайте в документации ядра Linux - тут :) Все рассуждения основаны на анализе ядра ядра 3.18, в Вашей версии ядра все может быть ИНАЧЕ!

Tuesday 23 December 2014

Сборка конструктора сетевых пакетов для C++ Crafter

Ставим зависимости:
sudo apt-get install libpcap0.8 libpcap0.8-dev

Берем здесь файлик crafter-0.3.tar.gz https://drive.google.com/folderview?id=0B4PDTNA2TABgVWRSaW5yLW5UbFk&usp=sharing

Кладем его на сервер в папку /usr/src
cd /usr/src
tar -xf crafter-0.3.tar.gz
cd crafter-0.3/
./configure --prefix=/opt/crafter
make
make install
Добавляем библиотеку в систему:
echo "/opt/crafter/lib/" > /etc/ld.so.conf.d/crafter.conf
ldconfig
А теперь идем изучать документацию! Штука очень занятная и аналогичная Scapy во многом. 

Monday 22 December 2014

Демонизация процессов на CentOS и Debian

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

Для Debian есть пакет daemon.

Вот с таким набором параметров:
daemon
Invalid arguments: no command supplied
usage: daemon [options] [--] [cmd arg...]
options:

      -h, --help              - Print a help message then exit
      -V, --version           - Print a version message then exit
      -v, --verbose[=level]   - Set the verbosity level
      -d, --debug[=level]     - Set the debugging level

      -C, --config=path       - Specify the configuration file
      -N, --noconfig          - Bypass the system configuration file
      -n, --name=name         - Guarantee a single named instance
      -X, --command=cmd       - Specify the client command as an option
      -P, --pidfiles=/dir     - Override standard pidfile location
      -F, --pidfile=/path     - Override standard pidfile name and location

      -u, --user=user[:group] - Run the client as user[:group]
      -R, --chroot=path       - Run the client with path as root
      -D, --chdir=path        - Run the client in directory path
      -m, --umask=umask       - Run the client with the given umask
      -e, --env="var=val"     - Set a client environment variable
      -i, --inherit           - Inherit environment variables
      -U, --unsafe            - Allow execution of unsafe executable
      -S, --safe              - Deny execution of unsafe executable
      -c, --core              - Allow core file generation

      -r, --respawn           - Respawn the client when it terminates
      -a, --acceptable=#      - Minimum acceptable client duration (seconds)
      -A, --attempts=#        - Respawn # times on error before delay
      -L, --delay=#           - Delay between spawn attempt bursts (seconds)
      -M, --limit=#           - Maximum number of spawn attempt bursts
          --idiot             - Idiot mode (trust root with the above)

      -f, --foreground        - Run the client in the foreground
      -p, --pty[=noecho]      - Allocate a pseudo terminal for the client

      -l, --errlog=spec       - Send daemon's error output to syslog or file
      -b, --dbglog=spec       - Send daemon's debug output to syslog or file
      -o, --output=spec       - Send client's output to syslog or file
      -O, --stdout=spec       - Send client's stdout to syslog or file
      -E, --stderr=spec       - Send client's stderr to syslog or file

          --running           - Check if a named daemon is running
          --restart           - Restart a named daemon client
          --stop              - Terminate a named daemon process


Для  CentOS есть пакет daemonize.

Вот с таким набором параметров:
 daemonize
daemonize, version 1.7.3
Usage: daemonize [OPTIONS] path [arg] ...

OPTIONS

-a             Append to, instead of overwriting, output files. Ignored
               unless -e and/or -o are specified.
-c <dir>       Set daemon's working directory to <dir>.
-e <stderr>    Send daemon's stderr to file <stderr>, instead of /dev/null.
-E var=value   Pass environment setting to daemon. May appear multiple times.
-o <stdout>    Send daemon's stdout to file <stdout>, instead of /dev/null.
-p <pidfile>   Save PID to <pidfile>.
-u <user>      Run daemon as user <user>. Requires invocation as root.
-l <lockfile>  Single-instance checking using lockfile <lockfile>.
-v             Issue verbose messages to stdout while daemonizing.
Такое ощущение, что лучше демонизироваться самому.

Saturday 20 December 2014

Сборка ZeroMQ на Debian 7 Wheezy

Довольно много приложений последнее время переходят к использованию ZeroMQ и не зря! Очень крутая библиотека :)

Итак, соберем же ее:
cd /usr/src
wget http://download.zeromq.org/zeromq-4.0.5.tar.gz
tar -xf zeromq-4.0.5.tar.gz
cd zeromq-4.0.5
./configure --prefix=/opt/zeromq_405
make install
ln -s /opt/zeromq_405/ /opt/zeromq

Добавляем библиотеку в систему:
echo "/opt/zeromq/lib" > /etc/ld.so.conf.d/zeromq.conf
ldconfig
Все, теперь можно собирать любые приложения с данный библиотекой:

g++ server.c -I /opt/zeromq/include -l/opt/zeromq/lib/libzmq.so -oserver

Wednesday 17 December 2014

Настройка OpenVPN сервера на CentOS 7 и активация клиентам на Mac OS

Подключаем  Epel репозиторий:
yum install -y epel-release
Устанавливаем OpenVPN пакет:
yum install -y openvpn
Копируем пример конфига OpenVPN в боевой путь:
cp /usr/share/doc/openvpn-2.3.2/sample/sample-config-files/server.conf /etc/openvpn/server.conf
Корректируем конфиг:
vim /etc/openvpn/server.conf
Добавляем в самый низ (подключаем DNS серверы Google):
push "dhcp-option DNS 8.8.8.8"
push "dhcp-option DNS 8.8.4.4"

И следом активируем перенаправление всего трафка в туннель:
push "redirect-gateway def1 bypass-dhcp"
Включаем форвардинг трафика в ядре:
echo "net.ipv4.ip_forward=1" > /etc/sysctl.d/forwarding.conf
sysctl --system 
Активируем фаерволл:
systemctl enable firewalld
systemctl start firewalld
systemctl status firewalld
Применяем изменения:

firewall-cmd --reload
И разрешаем OpenVPN и ssh трафик:
firewall-cmd --add-service=ssh --permanent
firewall-cmd --add-service=openvpn --permanent
firewall-cmd --add-masquerade --permanent

Теперь нам нужно сгенерировать сертификаты для сервера;
mkdir /root/openvpn_keys
yum install -y unzip zip
mkdir /root/openvpn_keys
cd /root/openvpn_keys
wget https://github.com/OpenVPN/easy-rsa/archive/master.zip
unzip master.zip
cd easy-rsa-master/easyrsa3
Создаем собственный PKI (не забудьте пароль от CA, иначе в будущем придется создавать его заново):
mv vars.example  vars
./easyrsa init-pki
./easyrsa build-ca
./easyrsa gen-dh
Создаем сертификаты для сервера:
./easyrsa gen-req myservername
./easyrsa sign-req server myservername
Снимаем пароль с приватного ключа:
openssl rsa -in /root/openvpn_keys/easy-rsa-master/easyrsa3/pki/private/myservername.key -out /root/openvpn_keys/easy-rsa-master/easyrsa3/pki/private/mmyservername.key.without_password

Заменяем ключ на безпарольный:
mv /root/openvpn_keys/easy-rsa-master/easyrsa3/pki/private/myservername.key.without_password /root/openvpn_keys/easy-rsa-master/easyrsa3/pki/private/myservername.key
Переносим сертификаты и ключи в папку OpenVPN:
cp pki/ca.crt   /etc/openvpn/ca.crt
cp pki/dh.pem /etc/openvpn/dh1024.pem
cp pki/issued/myservername.crt /etc/openvpn/server.crt
cp pki/private/myservername.key  /etc/openvpn/server.key
Создаем конфиг клиенту (уже с флажком nopass, так как нам тут пароль не нужен):
./easyrsa gen-req clientmac nopass
./easyrsa sign-req client clientmac

Запускаем OpenVPN:
systemctl enable openvpn@server
systemctl start openvpn@server
systemctl status -l openvpn@server

При настройке клиента стоит учесть, что ему нужно передать каким-либо безопасным способом следующие файлы:
/root/openvpn_keys/easy-rsa-master/easyrsa3/pki/issued/clientmac.crt
/root/openvpn_keys/easy-rsa-master/easyrsa3/pki/private/clientmac.key
/root/openvpn_keys/easy-rsa-master/easyrsa3/pki/private/ca.crt
Продолжаем настройку - настроим клиента OpenVPN на MacOS.



Настройка OpenVPN клиента на Mac OS - Tunnelblick

Все проще некуда :) Сначала стягиваем Tunnelblick и устанавливаем.

После этого стягиваем с OpenVPN сервера файлы:
client.crt
client.key
ca.crt
Создаем конфиг для Tunnelblick:
mkdir ~/Desktop/openvpn_secure.tblk
cd ~/Desktop/openvpn_secure.tblk
Создаем конфиг OpenVPN (не забываем менять a.b.c.d на адрес сервера):
vim config.ovpn
Содержимое:
client
proto udp
verb 3
dev tun
remote a.b.c.d
port 1194
ca ca.crt
cert clientmac.crt
key clientmac.key
nobind
persist-key
persist-tun
comp-lzo
После этого открываем рабочий стол и дважды щелкаем по openvpn_secure.tblk и соглашаемся на добавление туннеля. После этого в углу экрана тыкаем по значку  Tunnelblick и подключаемся. Ура!

Источник: тыц

Sunday 14 December 2014

trafgen и ошибка Flushing TX_RING failed

Боюсь, что оно чинится лишь обновлением ядра на что-то в районе  3.16. Соответствующий багрепорт: https://github.com/netsniff-ng/netsniff-ng/issues/136

Самый удобный и правильный способ обновить ядро на Debian 7 Wheezy

Открываем конфиг репозиториев:
vim /etc/apt/sources.list

Добавляем там:
deb http://http.debian.net/debian wheezy-backports main

Ставим новое ядро:
apt-get update
apt-get -t wheezy-backports install linux-image-3.16.0-0.bpo.4-amd64linux-headers-3.16.0-0.bpo.4-amd64

После этого в ребут:
shutdown -r now
Но обращаю внимание - что ядра из бэкпортов намного менее объезжены и оттестированы. И очень легко налететь на какой-либо чудесный баг.

Установка packETH на Debian 7 Wheezy

Вот так:
apt-get install -y make gcc pkg-config libgtk-3-dev libgtk2.0-dev
cd /usr/src
wget http://sourceforge.net/projects/packeth/files/latest/download?source=files -OpackETH-1.8.tar.bz
tar -xf packETH-1.8.tar.bz
cd packETH-1.8/
./configure --prefix=/opt/packeth
make
make install
Сама тулза очень странная, требует иксы. А консольная версия очень урезанная, ибо умеет посылать лишь подготовленный ранее кусок данных в формате pcap.

Так что задача высокоскоростного генератора трафика остается открытой.

Thursday 11 December 2014

Tuesday 9 December 2014

OpenVZ: TCP: time wait bucket table overflow (CT1001)

 Да, очень странный стандартный конфиг:
sysctl -a|grep tcp_max_tw_buckets
net.ipv4.tcp_max_tw_buckets = 262144
net.ipv4.tcp_max_tw_buckets_ub = 16536
Особо заметно будет при нескольких контейнерах на машину. Детально: http://kb.sp.parallels.com/en/118693

Как просмотреть содержимое L2TP пакетов не шифрованного туннеля?

Итак, имеется L2TP трафик, внутри которого по IP транспорту идет трафик.

Как его распаковать? Ни tcpdump, ни tshark его стандартно не видят.

Итак, нам нужен Wireshark 1.99. Входим в его настройки, идем в Protocols, выбираем там L2TP. L2TPv3 cookie size: Detect, L2TPv3 L2-Specific sublayer: Default L2-Specific. Decode L2TPv3 packet contents as: Ethernet. И все! Оно распакуется и будет видно содержимое пакетов :)

Monday 8 December 2014

Детектирование DDoS атак на отраженном и ответном трафике

Рекомендую к прочтению очень полезную информацию о том, как косвенно фиксировать атаки: http://labs.spritelink.net/clever-ddos-detection

Чтобы не потерялось привожу здесь:

The detection of DDoS attacks is typically based on some form of threshold value and typically on traffic that is going to a potential target, ie to the host that we want to protect from attacks.
It can be a threshold value for total traffic or for a certain traffic class, like UDP packets, and the actual threshold value can either be configured statically or it can be more dynamic and based on previously collected data, ie baselining and from that finding anomalous traffic patterns.
Using traffic classes can help us differentiate between a large file transfer and a large DNS reflection & amplification attack but not all attacks are that easy to filter out.
One approach is simply to let the end hosts tell us when they are under attack. A server knows what traffic it wants and anything else would be counted in an "unwanted" bucket and once we see enough unwanted traffic it could notify the DDoS mitigation system via an API. This approach requires integration with the end hosts though and while it might be possible in a homogeneous environment it can be very difficulty in a mixed environment.
How do we know when a host is receiving unwanted packets?
A normal TCP stack sends TCP RST packets for incoming TCP packets it doesn't want and similarly a firewall will send ICMP administratively prohibited messages.
By analysing TCP RST & ICMP messages we should be able to get a hint on when an attack is occurring and we could hone in classic threshold based methods for an end result which should be a highly accurate DDoS detection system.
So how can we collect the information? NetFlow collects flows on the router which it then exports to the collector and while this is great for traffic statistics it doesn't lend itself very well for this type of DDoS detection. We will not be able to see inside that ICMP message to see what packet caused the sending of the ICMP packet. sFlow on the other hand provides just this possibility as it merely send the N first bytes of a sampled packet.
Further, Netflow is inherently slow. Most router implementations allow a minimum timer of 60 and 15 seconds for active and inactive flows respectively. Packets are put in a flow table and subsequent packets in the same flow will increase the bits and number of packets seen for that flow. Once the expiration timer is hit the flow is exported. That means you will have to wait up to a minute before you receive data at your collector.
sFlow on the other hand works completely differently. It takes the first N bytes of a packet and sends it off directly to the collector allowing you to do analysis on just seconds old data.
When it comes to DDoS detection the difference between minutes and a few seconds means the world.
By analysing TCP RST and ICMP via sFlow one should be able to build a DDoS detection system without match... or has anyone already done this?

Набор данных о различных протоколах в формате PCAP

Как запустить tshark, tcpdump или iftop из под высокопроизводительного PF_RING?

Для этого нужно собрать pcap с поддержкой pf_ring. Сначала собираем модуль ядра - PF_RING. Потом собираем похаченую библиотеку pcap, в которой опрос данных переделан на PF_RING.
cd /usr/src
wget http://sourceforge.net/projects/ntop/files/PF_RING/PF_RING-6.0.2.tar.gz/download -OPF_RING.6.0.2.tar.gz
tar -xf PF_RING.6.0.2.tar.gz
cd PF_RING-6.0.2
Собираем либу (но не ставим):
cd lib
make
Собираем патченный pcap:
cd userland/libpcap-1.1.1-ring
./configure --prefix=/opt/pcap_pfring_602
make install
Врубаем tshark или любой другой софт с поддержкой pcap:

LD_PRELOAD=/opt/pcap_pfring_602/lib/libpcap.so tshark -i eth3
Можно iftop:
LD_PRELOAD=/opt/pcap_pfring_602/lib/libpcap.so iftop -i eth3
И даже tcpdump:

LD_PRELOAD=/opt/pcap_pfring_602/lib/libpcap.so tcpdump -i eth4 'proto l2tp'
И ура - скорость будет дикая! :)

Monday 1 December 2014

CMake Error at /usr/lib64/boost/Boost.cmake:536 (message) - ошибка при работе cmake на CentOS 6 при сборке проекта с Boost

Вот поймал такую ошибку:



cmake ..
-- The C compiler identification is GNU 4.4.7
-- The CXX compiler identification is GNU 4.4.7
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
CMake Error at /usr/lib64/boost/Boost.cmake:536 (message):
The imported target "boost_date_time-static" references the file

"/usr/lib64/lib64/libboost_date_time.a"

but this file does not exist. Possible reasons include:

* The file was deleted, renamed, or moved to another location.

* An install or uninstall procedure did not complete successfully.

* The installation package was faulty and contained

"/usr/lib64/boost/Boost.cmake"

but not all the files it references.

Call Stack (most recent call first):
/usr/lib64/boost/BoostConfig.cmake:28 (include)
/usr/share/cmake/Modules/FindBoost.cmake:177 (find_package)
CMakeLists.txt:30 (find_package)


-- Configuring incomplete, errors occurred!
See also "/usr/src/fastnetmon/build/CMakeFiles/CMakeOutput.log".
Фиксится вот так - перед функцией find_package добавляем следующее:
set(Boost_NO_BOOST_CMAKE ON)

Вот запись в трекере cmake: http://public.kitware.com/Bug/view.php?id=15270