ITエンジニアの技術メモ

神奈川在住のITエンジニアの備忘録です。おもにプログラミングやネットワーク技術について、学んだことを自分の中で整理するためにゆるゆると書いています。ちゃんと検証できていない部分もあるのでご参考程度となりますが、誰かのお役に立てれば幸いです。

SNMP Trap を受信するスクリプト

SNMP Trapを受信し、受信した内容を標準出力に出すperlスクリプト receiveTrap.pl を作成した。
perl receiveTrap.pl」と実行すると、終了するまでSNMP Trapを受信して表示し続ける。終了するには、実行したターミナル上で ctrl + c を実行する。

use strict;
use warnings;
use Socket;

my $TRAP_PORT = 162;
my $BUF_SIZE  = 65535;

my $socket;
socket($socket, PF_INET, SOCK_DGRAM, 0) or die "Failed to create socket. $!\n";
bind($socket, pack_sockaddr_in($TRAP_PORT, INADDR_ANY)) or die "Failed to bind socket. $!\n";

$|=1; # if not, you can't redirect the output to a file.
while (1) {
    my $trapData;
    my $clientInfo = recv($socket, $trapData, $BUF_SIZE, 0) or die "Failed to receive trap data. $!\n";

    my $clientAddr = (unpack_sockaddr_in($clientInfo))[1];
    my $clientAddrStr = inet_ntoa($clientAddr);
    my $trapDataHexDump = unpack("H*", $trapData);
    
    my $snmpVersion = getSnmpVersion($trapDataHexDump);
    
    # Split by space. Ex. "01020304" -> "01 02 03 04"
    my @hexDumpArray = $trapDataHexDump =~ /.{2}/g;
    my $trapDataHexDumpSplit;
    foreach my $hexDump (@hexDumpArray) {
        $trapDataHexDumpSplit .= $hexDump . " ";
    }

    my ($sec, $min, $hour, $day, $mon, $year) = (localtime)[0..5];
    $year += 1900;
    $mon += 1;
    print "$year/$mon/$day $hour:$min:$sec\n";
    print "$snmpVersion trap data: \n$trapDataHexDumpSplit\n";
    print "from $clientAddrStr\n\n";
}

sub getSnmpVersion {
    my $trapDataHexDump = shift; 
    $trapDataHexDump =~ m/^30.+0201(.{2})/;
    my $snmpVersionHex = $1;
    
    my $snmpVersion;
    if ($snmpVersionHex eq '00') {
        $snmpVersion = 'v1'
    }
    elsif ($snmpVersionHex eq '01') {
        $snmpVersion = 'v2c'
    }
    elsif ($snmpVersionHex eq '03') {
        $snmpVersion = 'v3'
    }
    else {
        $snmpVersion = 'Unknown version'
    }
    return $snmpVersion;
}

受信したSNMP Trapの情報は以下のように出力される。

2018/4/10 1:12:8
v2c trap data:
xx xx xx xx ...
from 127.0.0.1

「trap data:」配下の xx は、受信データを16進ダンプしたもの。

なお、

$|=1;

は、perlが出力をバッファしないようにするために指定している。これがないと、標準出力をリダイレクトしてファイルに出力できない。