Pull to refresh

Ловля необычных SNMP-trap сообщений необычным способом

Reading time 4 min
Views 14K


У нас в сети, на доступе, используется большое количество коммутаторов D-Link.

Назрела необходимость принимать SNMP-трапы. Но оказалось не всё так просто, потому что огромное количество коммутаторов были из серий DES-1228/1210-28/1210-52. Эти коммутаторы вроде и умеют отправлять трапы, но вот сервер никак не хотел их ловить. Оказалось что трапы умеет ловить исключительно приложение под Windows, и название ему — Smart Console Utility.

Т.е. автоматизировать процесс сбора трапов, по задумке вендора, никак не получится.
Однако, пакеты с SNMP-трапами, все-таки на трап-сервер идут и с этим надо что-то делать.

Недолго думая, подняли на трап-сервере xinetd и начали принимать пакеты с сообщениями. Приходили они на UDP-порт 64514. И что было удивительно и интересно — сообщения шли в конце пакета, прямым текстом, нужно лишь было обрезать бинарные не читаемые заголовки.

Кстати, inetd/xinetd еще называют «супер-сервером Интернет», это такой сетевой сервис, который слушает сокеты и приходящие сетевые пакеты отправляет твоему приложению для анализа/сохранения/ и вообще для чего угодно. Т.е. в *nix системе можно «голыми руками» написать свой сетевой сервис. Это поистине круто!

Конфигурация xinetd (/etc/xinetd.d/trap-handler-scu):

service smart-console-utility
{
        disable         = no
        id              = trap-handler-scu
        type            = UNLISTED
        flags           = IPv4
        protocol        = udp
        socket_type     = dgram
        user            = root
        wait            = yes
        server          = /services/snmp/trap-handler-scu.php
        port            = 64514
#       log_type        = FILE /var/log/xinetd-trap-handler-scu.log
#       log_on_success  = PID HOST
#       log_on_failure  = HOST
}


Код, которому будет передаваться каждый пришедший UDP-пакет (/services/snmp/trap-handler-scu.php):
Написан на PHP, т.к. выполняется быстро, и после ему можно придать возможность складывать трап-сообщения в БД.

#!/usr/bin/php5
<?php

set_time_limit(5);
error_reporting(0);


$logging		= true;		// Global logging
$debug_logging		= false;	// Logging debug messages
$dump_requests		= false;	// Save requests
$request_buffer_size	= 1024;		// 1024 Bytes - Maximum request size

$log_file		= '/var/log/smart-console-utility/smart-console-utility.log';
$req_id			= preg_replace(array('/\./', '/(\-)([0-9]{1}$)/', '/(\-)([0-9]{2}$)/', '/(\-)([0-9]{3}$)/'), array('-', '$1---$2', '$1--$2', '$1-$2'), array_sum(explode(' ', microtime())));

$dump_dir		= '/tmp/smart-console-utility';
$dump_request_file	= $dump_dir.'/'.$req_id.'.request';

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function write_log($message)
{
	global $log_file, $logging, $req_id;
	if ($logging)
	{$logging = (file_put_contents($log_file, date('Y-m-d H:i:s  ').'['.$req_id.' '.sprintf('%-14s', $_SERVER['REMOTE_HOST']).'] '.$message."\n", FILE_APPEND) !== false);}
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
if ($debug_logging) {write_log('Start');}
if ($read_handle = fopen('php://stdin', 'r'))
{
	if (($dump_requests) && (!is_dir($dump_dir))) 
	{
		mkdir($dump_dir, 644, true);
		$dump_requests = is_dir($dump_dir);
	}
	// Read client request
	if ($request = fread($read_handle, $request_buffer_size))
	{
		// Get trap message
		preg_match('/[\w\d\s\-\(\)\.]+$/', $request, $matches);
		if ($matches)
		{
			$trap_message =
				preg_replace(array('/\([\d]+\)/', '/[\.]+$/'), '', 
					preg_replace('/[ ]{2,}/', ' ',
						preg_replace('/^.DES/', 'DES',
							trim(end($matches))
						)
					)
				);
		} else {$trap_message = '';}
		if ($logging) {write_log($trap_message);}
		if ($debug_logging) {write_log('Handle request, size('.strlen($request).")\t-> ".$trap_message);}
		if ($dump_requests) {file_put_contents($dump_request_file, $request, FILE_APPEND);}
		// Parse trap message
	}
	else
	{write_log('Null request');}
	fclose($read_handle);
}
else
{write_log('Unable to open STDIN!');}
if ($debug_logging) {write_log('End');}

?>


В результате получатся приблизительно такие записи в журнале:

2014-09-12 06:25:50 SCU--1410485150-0287 10.X.0.26     DES-1210-28 Port 2 copper link up
2014-09-12 06:25:50 SCU--1410485150-3536 10.X.0.18      DES-1210-52 Port 9 copper link up
2014-09-12 06:25:50 SCU--1410485150-7605 10.X.0.31      DES-1210-52 Port 48 copper link up
2014-09-12 06:25:52 SCU--1410485152-9745 10.X.0.104    DES-1210-28 Port 10 copper link up
2014-09-12 06:25:55 SCU--1410485155-5064 10.X.0.11      DES-1210-52 Port 28 copper link up
2014-09-12 06:25:55 SCU--1410485155-7615 10.X.0.31      DES-1210-52 Port 48 copper link up
2014-09-12 06:25:58 SCU--1410485158-7782 10.X.0.31      DES-1210-52 Port 48 copper link up
2014-09-12 06:26:01 SCU--1410485161-4395 10.X.0.31      DES-1210-52 Port 48 copper link up
2014-09-12 06:26:04 SCU--1410485164-0377 10.X.0.31      DES-1210-52 Port 48 copper link up
2014-09-12 06:26:04 SCU--1410485164-3473 10.X.0.18      DES-1210-52 Port 9 copper link up
2014-09-12 06:26:06 SCU--1410485166-0395 10.X.0.31      DES-1210-52 Port 48 copper link up
2014-09-12 06:26:07 SCU--1410485167-1539 10.X.0.31      DES-1210-52 Port 47 copper link up
2014-09-12 06:26:07 SCU--1410485167-2226 10.X.0.128     DES-1210-28 Port 2 copper link up


Кстати, в данном выводе видно «схлопывание» порта (port-flapping), строчка «DES-1210-52 Port 48 copper link up» повторяется много раз. Она показывает что с портом или кабелем что-то не так.

Дефект на порту найден — задача выполнена.
Tags:
Hubs:
+3
Comments 15
Comments Comments 15

Articles