AS-Stats — инструмент для создания графиков трафика для каждой AS из записей NetFlow / sFlow

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

Скрипты анализируют sFlow / NetFlow потоки, по результатам строят графики и выбирают топ. Вот как это выглядит:

В нашем случае имеем парк оборудования от Extreme Networks, а потому графики будем строить на базе sFlow потоков. Особенность нашего случая, это отсутствие в составе sFlow пакета данных о src/dst AS.

Все дальнейшие действия будем производить на 18 ubuntu-server (да, под root’ом). Из дополнительных требований: размер дискового пространства, не менее 100ГБ.

Статью пишу по прошествию месяца после установки, поэтому может статся что где-то могу пропустить какой-то пакет зависимостей

Предварительно разберемся что же там летит в sFlow пакете. Тут нам пригодится sflowtool Установка не должна вызвать сложностей и описана на гитхабе.

# по умолчанию в убунту нет компилятора, потому предварительно установим
apt install autoconf make
mkdir /opt && cd /opt
# а дальше все как обычно, качаем и устанавливаем
git clone https://github.com/sflow/sflowtool.git
cd sflowtool/
./boot.sh
./configure
make
sudo make install

Форвардим поток на наш сервер с AS-Stats, я использую samplicator, и запускаем sflowtool

sflowtool -p 65000 -l
# где
# -p 65000 - порт на который летит sFlow поток
# -l - построчный вывод пакетов

Получаем содержимое пакета:

FLOW,10.81.200.81,1008,0,00d861be6878,0004966d523d,0x0800,1917,0,109.88.212.238,81.170.142.157,6,0x00,128,51310,4430,0x10,68,46,16384
# где
# sFlowAgent - 10.81.200.81
# inputPort - 1008 - номер порта свитча из SNMP
# outputPort - 0 - в настройках свитча стоит ловить только вход на порт, 
# т.к. слушаем все порты на свитче
# src_MAC
# dst_MAC
# ethernet_type
# in_vlan
# out_vlan
# src_IP
# dst_IP
# IP_protocol
# ip_tos
# ip_ttl
# udp_src_port OR tcp_src_port OR icmp_type
# udp_dst_port OR tcp_dst_port OR icmp_code
# tcp_flags
# packet_size
# IP_size
# sampling_rate - сэмплинг рэйт (пригодится в будующем в конфиге)

Как видно из пакета, в sFlow нет ничего про src / dst AS, что вносит некоторые сложности в генерацию статистики по AS. К счастью, не только мы такие неудачники и в требованиях к AS-Stats указано: ip2as.pm, for additional lookup (https://github.com/JackSlateur/perl-ip2as)

Подготавим систему и установим требуемые пакеты:

apt update 
apt upgrade
apt install perl librrds-perl librrd-dev rrdtool apache2 php php-sqlite3 libmailtools-perl libio-socket-ssl-perl gcc libnet-patricia-perl libjson-xs-perl sqlite3 whois
# проверим что за версию php мы установили
php -v
PHP 7.2.24-0ubuntu0.18.04.7 (cli) (built: Oct  7 2020 15:24:25) ( NTS )
# установим под нужную версию php модуль apache и включим php
apt install libapache2-mod-php7.2
a2enmod php7.2
service apache2 restart
apt autoremove
# немножко модулей perl
cpan install CPAN
cpan install File::Find::Rule
cpan install Net::sFlow
cpan install Log::Log4perl
cpan install IO::Select
cpan install IO::Socket
cpan install Scalar::Util
cpan install TryCatch
# клонируем AS-Stats и ip2as.pm
cd /opt/
git clone https://github.com/manuelkasper/AS-Stats.git
mv AS-Stats as-stats
cd as-stats/
git clone https://github.com/JackSlateur/perl-ip2as
# положим ip2as.pm к perl модулям
cd perl-ip2as
cp ip2as.pm /usr/share/perl5/

Основное установили, но нам надо актуализировать айпишники к реалиям сегодняшнего дня. Тут на помощь прийдут базы maxmind. Регистрируемся по ссылке https://www.maxmind.com/en/geolite2/signup
и скачиваем эти базы https://dev.maxmind.com/geoip/geoip2/geolite2-asn-csv-database/

Устанавливаем jq и генерим новый json

apt install jq
mkdir /opt/as-stats/maxmind 
cd /opt/as-stats/maxmind
# в папочку нужно положить распакованные базы maxmind 
# думаю с этим трудностей не возникнет (можно через scp или sftp)
tail -q -n +2 GeoLite2-ASN-Blocks-IPv4.csv GeoLite2-ASN-Blocks-IPv6.csv | jq -n -R '
inputs |
split(",") |
{ (.[0]):  .[1] } '  | jq -s add >> ip2as
# скрипт взят отсюда https://github.com/JackSlateur/perl-ip2as/issues/4
# и копируем сгенерированный файлик
cp ip2as /opt/as-stats/perl-ip2as/tools/ip2asn.json

Теперь о конфигурационном файле. Пример лежит по пути conf/knownlinks. В шапке файла все понятно расписано. Основное что стоит запомнить, никаких пробелов, только табы. Во второй столбик пишем номера портов из SNMP. Что там за порты можно посмотреть по SNMP, например snmpwalk -v2c -c public 10.10.10.10 .1.3.6.1.2.1.2.2.1.2 Правьте файлик под свои потребности.

У меня же железок много, поэтому чуть-чуть автоматизируем. Создадим файлик AS куда внесем данные в формате «название источника» «ip источника» Каждый источник с новой строки. Например: 65010 10.10.0.10. И сгенерим конфиг ./conf-gen.sh Содержимое скрипта:

cat conf-gen.sh 
#!/usr/bin/env bash
>asstats.conf
echo "# Router IP		SNMP ifindex[/VLAN]	tag			description		color	samplingrate
# note: tabs must be used to separate fields (not spaces)
# max. length for tag is 12 characters; allowed characters: a-z A-Z 0-9 _
# sampling rate can be separate for in/out by specifying <in>/<out> rates." >> asstats.conf

oldIFS=$IFS
IFS=$'\n'

for ASN in $(cat AS);do
ASN1=$(echo $ASN | awk '{print $1}')
ASN2=$(echo $ASN | awk '{print $2}')
echo "# $ASN1" >> asstats.conf
#10.11.0.11		1001				65011_1			65011 1			A6CEE3	16384
echo -e "$ASN2\t\t1025\t\t\t$ASN1\t\t\t$ASN1\t\tA6CEE3\t16384" >> asstats.conf
echo -e "$ASN2\t\t1026\t\t\t$ASN1\t\t\t$ASN1\t\tA6CEE3\t16384" >> asstats.conf
echo -e "$ASN2\t\t1027\t\t\t$ASN1\t\t\t$ASN1\t\tA6CEE3\t16384" >> asstats.conf
echo -e "$ASN2\t\t1028\t\t\t$ASN1\t\t\t$ASN1\t\tA6CEE3\t16384" >> asstats.conf
echo -e "$ASN2\t\t1029\t\t\t$ASN1\t\t\t$ASN1\t\tA6CEE3\t16384" >> asstats.conf
echo -e "$ASN2\t\t1030\t\t\t$ASN1\t\t\t$ASN1\t\tA6CEE3\t16384" >> asstats.conf
IFS=$oldIFS

done

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

Конфиг есть, осталось создать папку для rrd-файлов. Я её называю по номеру AS, вы называйте как удобно

mkdir /opt/as-stats/15169
# даем всем права на чтение/запись ибо сюда и скрипты и апач ходит
chmod 0777 /opt/as-stats/15169

Пришло впемя запускать as-stats. Моя команда запуска выглядит так:

/usr/bin/perl -w /opt/as-stats/bin/asstatd.pl -r /opt/as-stats/15169 -p 0 -P 65000 -k /opt/as-stats/asstats.conf -a 15169 -n -m /opt/as-stats/perl-ip2as/tools/ip2asn.json &
# описание параметров запуска можно подсмотреть в самом скрипте asstatd
# -r <path to RRD files>
# -p <NetFlow UDP listen port> - default $server_port, use 0 to disable NetFlow
# -P <sFlow UDP listen port> - default $sflow_server_port, use 0 to disable sFlow
# -k <path to known links file>
# -a <your own AS number> - only required for sFlow
# -n enable peer-as statistics
# -m IP<->ASN mapping

Ждем пару минут и проверяем папку с rrd-файлами. Если папка не пустая, значит все идет как задумано. Команду запуска положим в файлик run_asstats.sh и добавим в крон, вместе с командами подсчета объема трафика для веб-странички. Я подсчитываю за сутки и за неделю. Cодержимое крона для as-stats у меня такое:

# run asstats
@reboot /opt/as-stats/run_asstats.sh

*/30 * * * * /opt/as-stats/bin/rrd-extractstats.pl /opt/as-stats/15169 /opt/as-stats/asstats.conf /opt/as-stats/13188/asstats_day.txt
15 */1 * * * /opt/as-stats/bin/rrd-extractstats.pl /opt/as-stats/15169 /opt/as-stats/asstats.conf /opt/as-stats/13188/asstats_week.txt 168

Графики генерируются, трафик считается. Осталось сделать веб. Копируем содержимое папки www в рабочую директорию Apache и правим пути в файле config.inc

cp -R /opt/as-stats/www /var/www/html
cat /var/www/html/config.inc
<?php

/* changes these values to suit your local configuration */

$rrdpath = "/opt/as-stats/15169";
$daystatsfile = "/opt/as-stats/15169/asstats_day.txt";
$rrdtool = "/usr/bin/rrdtool";

$daypeerstatsfile = "/opt/as-stats/15169/peerasstats_day.txt";
$showpeeras = false;

$asinfofile = "asinfo.txt";
$knownlinksfile = "/opt/as-stats/asstats.conf";
$outispositive = false;
$show95th = true;

$ntop = 20;
$showv6 = true;
$showtitledetail = true;
$vertical_label = true;			# vertical IN/OUT label in graph
$brighten_negative = true;		# brighten the "negative" part of graphs

$whois = "/usr/bin/whois";
$assetpath = "asset";
$asset_cache_life = "604800";	# 604800 seconds = 7 days

$compat_rrdtool12 = false;		# compatibility with RRDtool 1.2 (show95th will not work if this is set)

/* Custom links to be shown for each AS. You can use %as% as a
   placeholder for the ASN. */
$customlinks = array(
	'PeeringDB' => 'https://www.peeringdb.com/asn/%as%',
	'robtex' => 'https://www.robtex.com/as/as%as%.html',
	'HE' => 'http://bgp.he.net/AS%as%',
	'RIPEstat' => 'https://stat.ripe.net/AS%as%#tabId=at-a-glance',
	'CIDR v4' => 'http://www.cidr-report.org/cgi-bin/as-report?as=AS%as%&view=2.0',
	'CIDR v6' => 'http://www.cidr-report.org/cgi-bin/as-report?as=AS%as%&view=2.0&v=6',
	'Radar Qrator' => 'https://radar.qrator.net/as%as%/'
);

/* Custom time intervals for top N AS */

$top_intervals[] = array(
	'hours' => 7*24,
	'statsfile' => '/opt/as-stats/15169/asstats_week.txt',
	'label' => '1 week'
);
/*$top_intervals[] = array(
	'hours' => 30*24,
	'statsfile' => '/opt/as-stats/15169/asstats_month.txt',
	'label' => '30 days'
);
*/


/* END - no closing php tag needed here (prevents problems with stray whitespace) */

Также можно установить альтернативный вариант веб-интерфейса. Ссылочка на него есть на страничке AS-Stats в гитхаб, но я остановился на дефолтном представлении. Тут на ваш вкус.

Еще хотелось бы добавить два замечания:
— файл /var/www/html/asinfo.txt содержит не полную информацию об AS, можно либо внести требующиеся вам AS в ручную или грепнуть базы maxmind и добавить все не достающее
— если в вашей сети есть кеши от гугла, фейсбука или других апстримов и вы хотели бы видеть трафик на эти кеши в статистике — добавьте айпишники этих нод с привязкой к нужной AS в файл /opt/as-stats/perl-ip2as/tools/ip2asn.json