аукцион / donate / услуги / RSS / распечатать / вход 
Мой мир
Вконтакте
Одноклассники

[12 февраля 2021 | 16 февраля 2021 | 17 февраля 2021]

NetFlow v5 Python (часть 1)

NetFlow является замечательным инструментом для контроля трафика в сети. Для него существует масса коммерческих и бесплатных продуктов, но иногда системным администраторам хочется чего-то странного. Например, мне захотелось написать свой собственный коллектор и анализатор. Будто бы я смогу смогу сделать лёгкий, переносимый и оптимальный вариант который меня полностью удовлетворит. Естественно, что мне захотелось его написать на Python с использованием стандартных библиотек. Но поискав на просторах сети информацию по этому поводу я нашел, что масса примеров и попыток реализаций уходит корнями в пример господина Брайна Рэка. При этом его никто не упоминает, но регулярно выдают его код за свой. В большинстве случаев добавляется вывод в файл, вместо терминала. Опять же я тоже продублирую код из блога этого замечательного человека. Если вы знаете автора более начального уровня, то пишите в комментарии.

Сегодня только продублирую этот код и покажу результат его вывода и опишу своё видение идеального коллектора для NetFlow.

import socket, struct

from socket import inet_ntoa

SIZE_OF_HEADER = 24
SIZE_OF_RECORD = 48

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('0.0.0.0', 9996))

while True:
	buf, addr = sock.recvfrom(1500)

	(version, count) = struct.unpack('!HH',buf[0:4])
	if version != 5:
		print ("Not NetFlow v5!")
		continue

	# It's pretty unlikely you'll ever see more then 1000 records in a 1500 byte UDP packet
	if count <= 0 or count >= 1000:
		print ("Invalid count %s" % count)
		continue

	uptime = socket.ntohl(struct.unpack('I',buf[4:8])[0])
	epochseconds = socket.ntohl(struct.unpack('I',buf[8:12])[0])

	for i in range(0, count):
		try:
			base = SIZE_OF_HEADER+(i*SIZE_OF_RECORD)

			data = struct.unpack('!IIIIHH',buf[base+16:base+36])

			nfdata = {}
			nfdata['saddr'] = inet_ntoa(buf[base+0:base+4])
			nfdata['daddr'] = inet_ntoa(buf[base+4:base+8])
			nfdata['pcount'] = data[0]
			nfdata['bcount'] = data[1]
			nfdata['stime'] = data[2]
			nfdata['etime'] = data[3]
			nfdata['sport'] = data[4]
			nfdata['dport'] = data[5]
			nfdata['protocol'] = ord(buf[base+38])
		except:
			continue

	# Do something with the netflow record..
	print ("%s:%s -> %s:%s" % (nfdata['saddr'],nfdata['sport'],nfdata['daddr'],nfdata['dport']))

Этот код выводит на экран информацию о передаче пакетов с какого IP:PORT на какой IP:PORT передаются пакеты. Очень хорошая демонстрация получается на небольших каналах, таких как домашний роутер. Результат вывода приблизительно вот такой.

Cisco NetFlow Python.

Пакет NetFlow состоит из двух частей, заголовка и группы записей. В заголовке хранится следующая информация:

Bytes Contents Описание
0-1 version Версия NetFlow протокола. Может быть 1, 5 или 9.
2-3 count Количество пакетов с данными. Не может быть больше 30 пакетов.
4-7 sys_uptime Время в миллисекундах с момента запуска сетевого оборудования. Можно использовать для контроля за перезапуском оборудования. Можно использовать как временной идентификатор.
8-11 unix_secs UNIX-время (в секундах) на момент начала передачи пакетов. Количество секунд прошедшее с 0000 UTC 1970. Можно использовать как временной идентификатор.
12-15 unix_nsecs UNIX-время (в наносекундах) на момент начала передачи пакетов. Количество наносекунд прошедшее с 0000 UTC 1970. Можно использовать как временной идентификатор.
16-19 flow_sequence Номер записи. Позволяет контролировать потерю пакетов.
20 engine_type Тип движка.
21 engine_id Идентификатор движка.
22-23 sampling_interval Количество выборок. Первые два бита содержат режим выборок. Остальное является интервалом выборок. Этим полем сенсор оповещает о том, что отправляется 1:N пакетов. Например, при высокой нагрузке на канал сенсор может отправлять один из 10000 пакетов.

Пакеты с данными о трафике выглядят вот так:

Bytes Contents Описание
0-3 srcaddr IP-адрес источника трафика.
4-7 dstaddr IP-адрес получателя трафика.
8-11 nexthop IP-адрес следующего роутера.
12-13 input Индекс входящего интерфейса. Они заново нумеруются при каждом запуске устройства, номера можно запросить через SNMP.
14-15 output Индекс исходящего интерфейса. Они заново нумеруются при каждом запуске устройства, номера можно запросить через SNMP.
16-19 dPkts Количество переданых пакетов.
20-23 dOctets Количество переданых байтов.
24-27 first SysUptime время генерации первого пакета. Вычислить абсолютное время генерации пакета можно используя информацию из заголовка.
28-31 last SysUptime время генерации последнего пакета. Вычислить абсолютное время генерации пакета можно используя информацию из заголовка.
32-33 srcport Порт источника.
34-35 dstport Порт получателя.
36 pad1 Не используется
37 tcp_flags Все TCP-флаги наблюдаемые во время замера.
38 prot IP протокол (1=ICMP, 6=TCP, 17=UDP, 47=GRE и т.д.).
39 tos Тип сервиса ToS. Тип обслуживания позволяет приоритизировать IP-трафик на сетевых маршрутизаторах.
40-41 src_as Номер автономной системы источника.
42-43 dst_as Номер автономной системы приёмника.
44 src_mask Префикс сети источника
45 dst_mask Префикс сети приёмника.
46-47 pad2 Не используется.

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

Какие подводные камни тут могут скрываться? Например, номера интерфейсов (физических портов) перегенерируются при каждой перезагрузке сетевого оборудования, по этому необходимо зафиксировать эти номера. Либо при каждой перезагрузке создавать новую табличку с номерами интерфейсов. Запрашивать имена интерфейсов можно используя SNMP. Но эту часть я вынесу из области коллектора, коллектор должен собирать информацию и возможно отправлять в БД.

Где хранить информацию о собранных данных? Первое, что приходит в голову — это кидать в БД. Но тут кроется небольшой подвох, мне не нравится иметь несколько точек отказа. Я бы хотел хранить данные на диске, но хранить их на диске крайне неудобно. Так, что я пока думаю. Вероятно сделаю некий гибрид, буду складировать из коллектора информацию в файлы и потом с определённой периодичностью проходить по ним, нормализовать и записывать в БД. Некий UNIX-подход, иметь массу узкозаточенных инструментов.

Номер протокола. Я остановился на реализации пятой версии протокола. Но разница между первым и пятым минимальная. В пятой версии добавлена следующая информация: Sampling interval, общий счетчик переданых NetFlow пакетов, номера входящей/исходящей автономной системы и префикс сети источника и приёмника.

Изначально я хотел реализовать первую версию, так как она простая как три копейки, но впоследствии эта система будет интегрирована с Центром мониторинга и управления сетью связи общего пользования от Роскомнадзора. А для них есть необходимость передавать в Netflow трафике информацию о sampling interval и автономных системах. Возможно совсем в открытую я буду реализовывать первую версию или сразу два обработчика в одном скрипте. Так как первая версия меньше всего нагружает оборудование в случае если передавать все данные. Пока я не знаю, что делать в случае если будут приходить пакеты с использованием sampling interval, по идее нужно будет просто умножать полученные данные на этот показатель, но реальная точность получаемых данных уменьшится.

На текущий момент я занимаюсь теоретизированием и подотовкой к экспериментам. Надо подумать как хранить данные, взвесить все за и против. Так же надо принять решение о пробросе пакетов до следующего приёмника. Как минимум надо понять кто этим будет заниматься. Либо сам коллектор и тогда всё будет происходить on-line, либо написать дополнительную программу, которая будет читать полученные данные и по цепочке передавать информацию. Ещё я думаю о том, что при передаче информации в ЦМУССОП можно будет понизить sampling interval, чтобы не забивать исходящий канал на наших маршрутизаторах.

Надеюсь, что у меня получится реализовать все свои задумки. Хотя я понимаю, что Python не совсем подходящий инструмент для подобных целей.

Тэги: ИТ, Cisco, программирование, Питон

Отредактировано:2021-02-24 15:19:35


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

Сообщайте мне о замеченных ошибках на: web@orcinus.ru. Все пожелания и советы будут учтены при дальнейшем проектировании сайта. Я готов сотрудничать со всеми желающими. В некоторых случаях, мнение автора может не совпадать с мнением автора! Phone: +7-902-924-70-49.

Top.Mail.Ru
Top.Mail.Ru LiveInternet Rambler's Top100 Яндекс.Метрика