技術メモ

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

16進のSNMP OIDを通常の文字列の形式に変換する

主題の処理を行うperlスクリプト convertOidHexToStr.pl を作成した。使い方は、例えば、「perl convertOidHexToStr.pl 2b06010401CE0F」 や 「perl convertOidHexToStr.pl "2b 06 01 04 01 CE 0F"」 のように指定すると、結果として、人に優しい形式でOID文字列を「.1.3.6.1.4.1.9999」と出力する。

use strict;
use warnings;

# -----------------------
# Check args.
# -----------------------
my $oidHex = $ARGV[0];
$oidHex =~ s/\s//g;
if (length($oidHex)%2 != 0 or $oidHex =~ /[^0-9a-fA-F]/) {
    die "Input is not hex string\n";
}

my @hexUnits = $oidHex =~ /.{2}/g;
my $length = @hexUnits;

# -----------------------
# Main.
# -----------------------
my $oidStr;
my @tmpsubIds;
my $isInMultiBytes = 0;
my $subIdCnt = 0;
for(my $i=0; $i<$length; $i++) {
    my $subId = hex($hexUnits[$i]);
    if ($i == 0) {
        my $firstSubId = int($subId / 40);
        my $secondSubId = $subId % 40;
        if ($firstSubId > 2) {
            die "The first sub id is 0 or 1 or 2.\n";
        }
        $oidStr .= "\." . $firstSubId . "\." . $secondSubId;
        $subIdCnt += 2;
        next;
    }
    
    if ($subId >= 128) {
        $subId -= 128;
        push(@tmpsubIds, $subId);
        $isInMultiBytes = 1;
    }
    elsif ($isInMultiBytes == 1) {
        push(@tmpsubIds, $subId);
        my $subIdForMultiBytes = computeSubIdForMultiBytes(@tmpsubIds);
        $subIdCnt++;
        if (isSubIdCntOverMax($subIdCnt)) {
            die "Sub id count is over the max value(128).\n";
        }
        $oidStr .= "\." . $subIdForMultiBytes;
        @tmpsubIds = ();
        $isInMultiBytes = 0;
    }
    else {
        if (isSubIdOverMax($subId)) {
            die "Sub id is over the max value(4294967295).\n";
        }
        $subIdCnt++;
        if (isSubIdCntOverMax($subIdCnt)) {
            die "Sub id count is over the max value(128).\n";
        }
        $oidStr .= "\." . $subId;
    }
}

print $oidStr;

# -----------------------
# Sub functions.
# -----------------------
sub isSubIdCntOverMax {
    my $subIdCnt = shift;
    if ($subIdCnt > 128) { # According to rfc2578.
        return 1;
    }
    return 0;
}

sub isSubIdOverMax {
    my $subId = shift;
    if ($subId > 4294967295) { # over 2^32-1. According to rfc2578.
        return 1;
    }
    return 0;
}

sub computeSubIdForMultiBytes {
    my @subIds = @_;
    my $length = @subIds;
    my $computedSubId;
    for(my $i=0; $i<$length; $i++) {
        $computedSubId += (128**($length-$i-1)) * $subIds[$i];
    }
    return $computedSubId;
}


パケットダンプを読むとき、
akrad.hatenablog.com
で書いたようにちょっと面倒なところがあるので、このスクリプトを作成した。