技術メモ

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

SNMP trap (coldStart) 送信スクリプト

以前作成した以下の perl スクリプトをエンハンスした。
akrad.hatenablog.com

具体的には、SNMPv1 のcoldStartトラップも SNMPv2cのcoldStartトラップも送信できるようにし、トラップ送信先やSNMPv1トラップの agent-addrフィールドも指定できるようにした。
使い方の例は以下。


1.1.1.1 に、SNMPv2cのcoldStartトラップを送信する。

perl sendTrap.pl -v 2 -d 1.1.1.1


1.1.1.1 に、agent-addrフィールドを 2.2.2.2 として、SNMPv1のcoldStartトラップを送信する。

perl sendTrap.pl -v 1 -d 1.1.1.1 -a 2.2.2.2


作成したperlスクリプトは以下の通り。
sendTrap.pl

use strict;
use warnings;
use Socket;
use Getopt::Long 'GetOptions';

#---------------
# Constant value
#---------------
my $V1_TRAP   = 'a4';
my $V2c_TRAP  = 'a7';
my $SNMP_V1   = 0;
my $SNMP_V2C  = 1;

my $INTEGER      = '02';
my $OCTET_STRING = '04';
my $OBJECT_ID    = '06';
my $SEQUENCE     = '30';
my $IP_ADDRESS   = '40';
my $TIME_TICKS   = '43';

#-------------------
# Set default value
#-------------------
my $destAddr      = 'localhost';
my $destPort      = 162;
my $snmpVersion   = '2';
my $enterpriseOid = '1.2.3.4.5';
my $agentAddr     = '127.0.0.1';

GetOptions(
    'dest=s'      => \$destAddr,
    'version=s'   => \$snmpVersion,
    'agentaddr=s' => \$agentAddr
);

#-------------------
# Check user's input
#-------------------
if ($destAddr =~ /^\d/) { # This is an ip address. Because hostname doesn't start from a digit.
    if (!isIpAddress($agentAddr)) {
        die("$destAddr is not an ip address.");
    }
}

if (($snmpVersion ne '1') and ($snmpVersion ne '2') and ($snmpVersion ne '2c')) {
    die("$snmpVersion must be 1 or 2(2c)");
}

if (!isIpAddress($agentAddr)) {
    die("$agentAddr is not an ip address.");
}


#---------------
# MAIN
#---------------
my $socket;
socket($socket, PF_INET, SOCK_DGRAM, 0) or die "Failed to create socket. $!";

my $addrBin = inet_aton($destAddr);
my $sockAddr = pack_sockaddr_in($destPort, $addrBin);

my $trapData;
if ($snmpVersion eq '1') {
    $trapData = constractV1TrapData();
}
elsif (($snmpVersion eq '2') or ($snmpVersion eq '2c')) {
    $trapData = constractV2cTrapData();
}
else {
    die("Need to specify 1 or 2(2c) for version.");
}

my $trapDataBin = pack("H*", $trapData);
send($socket, $trapDataBin, 0, $sockAddr) or die "Failed to send. $!";


#---------------
# Sub functions
#---------------
sub constractV1TrapData {
    my $snmpVersion  = $SNMP_V1;
    my $commName     = 'public';
    my $pduType      = $V1_TRAP;
    my $requestID    = 10;
    my $errorStatus  = 0;
    my $errorIndex   = 0;
    my $genericTrap  = 0;
    my $specificTrap = 0;
    my $timeStamp    = 0;

    my $snmpVersionBerUnit   = constractBerData($INTEGER, convertDecNumToHexStr($snmpVersion));
    my $commNameBerUnit      = constractBerData($OCTET_STRING, unpack("H*", $commName));
    my $enterpriseOidBerUnit = constractBerData($OBJECT_ID, convertOidStrToHexStr($enterpriseOid));
    my $agentAddrBerUnit     = constractBerData($IP_ADDRESS, convertIpAddrStrToHexStr($agentAddr));
    my $genericTrapBerUnit   = constractBerData($INTEGER, convertDecNumToHexStr($genericTrap));
    my $specificTrapBerUnit  = constractBerData($INTEGER, convertDecNumToHexStr($specificTrap));
    my $timeStampBerUnit     = constractBerData($TIME_TICKS, convertDecNumToHexStr($timeStamp));
    my $emptyVarbindBerUnit  = constractBerData($SEQUENCE, "");
    
    my $trapPduLength = getBinLengthFromHexStr(
                            $enterpriseOidBerUnit,
                            $agentAddrBerUnit,
                            $genericTrapBerUnit,
                            $specificTrapBerUnit,
                            $timeStampBerUnit,
                            $emptyVarbindBerUnit);
    
    my $totalength = getBinLengthFromHexStr(
                        $snmpVersionBerUnit, 
                        $commNameBerUnit, 
                        $pduType,
                        convertDecNumToHexStr($trapPduLength))
                     + $trapPduLength;

    my $trapData = $SEQUENCE . 
                   convertDecNumToHexStr($totalength) .
                   $snmpVersionBerUnit . 
                   $commNameBerUnit . 
                   $pduType .
                   convertDecNumToHexStr($trapPduLength) .
                   $enterpriseOidBerUnit .
                   $agentAddrBerUnit .
                   $genericTrapBerUnit .
                   $specificTrapBerUnit .
                   $timeStampBerUnit .
                   $emptyVarbindBerUnit;
    return $trapData;
}

sub constractV2cTrapData {
    my $snmpVersion = $SNMP_V2C;
    my $commName    = 'public';
    my $pduType     = $V2c_TRAP;
    my $requestID   = 10;
    my $errorStatus = 0;
    my $errorIndex  = 0;

    my $snmpVersionBerUnit = constractBerData($INTEGER, convertDecNumToHexStr($snmpVersion));
    my $commNameBerUnit    = constractBerData($OCTET_STRING, unpack("H*", $commName));
    my $requestIDBerUnit   = constractBerData($INTEGER, convertDecNumToHexStr($requestID));
    my $errorStatusBerUnit = constractBerData($INTEGER, convertDecNumToHexStr($errorStatus));
    my $errorIndexBerUnit  = constractBerData($INTEGER, convertDecNumToHexStr($errorIndex));
    my $varbindData        = constractVarbindData();
    
    my $trapPduLength = getBinLengthFromHexStr(
                            $requestIDBerUnit,
                            $errorStatusBerUnit,
                            $errorIndexBerUnit,
                            $SEQUENCE,
                            convertDecNumToHexStr(getBinLengthFromHexStr($varbindData)),
                            $varbindData);
    
    my $totalength = getBinLengthFromHexStr(
                        $snmpVersionBerUnit, 
                        $commNameBerUnit, 
                        $pduType,
                        convertDecNumToHexStr($trapPduLength))
                     + $trapPduLength;

    my $trapData = $SEQUENCE . 
                   convertDecNumToHexStr($totalength) .
                   $snmpVersionBerUnit . 
                   $commNameBerUnit . 
                   $pduType .
                   convertDecNumToHexStr($trapPduLength) .
                   $requestIDBerUnit .
                   $errorStatusBerUnit .
                   $errorIndexBerUnit .
                   $SEQUENCE .
                   convertDecNumToHexStr(getBinLengthFromHexStr($varbindData)) .
                   $varbindData;
    return $trapData;
}

sub constractVarbindData {
    # ------------------------
    # sysUpTime
    # ------------------------
    my $sysUpTimeOid = '1.3.6.1.2.1.1.3.0';
    my $sysUpTimeOidBerData = constractBerData($OBJECT_ID, convertOidStrToHexStr($sysUpTimeOid));
    my $sysUpTime = 10;
    my $sysUpTimeBerData = constractBerData($TIME_TICKS, convertDecNumToHexStr($sysUpTime));
    my $sysUpTimeVarbindLength = getBinLengthFromHexStr($sysUpTimeOidBerData, $sysUpTimeBerData);
    my $sysUpTimeVarbind = $SEQUENCE . 
                           convertDecNumToHexStr($sysUpTimeVarbindLength) . 
                           $sysUpTimeOidBerData .
                           $sysUpTimeBerData;

    # ------------------------
    # sysTrapOID
    # ------------------------
    my $sysTrapOid = '1.3.6.1.6.3.1.1.4.1.0';
    my $sysTrapOidBerData = constractBerData($OBJECT_ID, convertOidStrToHexStr($sysTrapOid));
    my $sysTrapOidData = '1.3.6.1.6.3.1.1.5.1';
    my $sysTrapBerData = constractBerData($OBJECT_ID, convertOidStrToHexStr($sysTrapOidData));
    my $sysTrapVarbindLength = getBinLengthFromHexStr($sysTrapOidBerData, $sysTrapBerData);
    my $sysTrapVarbind = $SEQUENCE . 
                         convertDecNumToHexStr($sysTrapVarbindLength) . 
                         $sysTrapOidBerData .
                         $sysTrapBerData;
    
    return $sysUpTimeVarbind . $sysTrapVarbind;
}

sub isIpAddress {
    my $ipAddr = shift;
    my @octets = split(/\./, $ipAddr);
    return 0 if (@octets != 4);
    foreach my $octet (@octets) {
        if (!($octet =~ /^\d+$/) or !(0 <= $octet and $octet <= 255)) {
            return 0;
        }
    }
    return 1;
}

sub convertIpAddrStrToHexStr {
    my $ipAddrStr = shift;
    my @octets = split(/\./, $ipAddrStr);
    my $ipAddrHexStr;
    foreach my $octet (@octets) {
        $ipAddrHexStr .= convertDecNumToHexStr($octet);
    }
    return $ipAddrHexStr;
}

sub convertOidStrToHexStr {
    my $oidStr = shift;
    my @oids = split(/\./, $oidStr);
    my $hexStr = convertDecNumToHexStr(40*$oids[0] + $oids[1]);
    for (my $i = 2; $i <= $#oids; $i++) {
        if ($oids[$i] < 128) {
            $hexStr .= convertDecNumToHexStr($oids[$i]);
        }
        else {
            $hexStr .= convertOidNumToHexStrForMultiBytes($oids[$i]);
        }
    }
    return $hexStr;
}

sub convertOidNumToHexStrForMultiBytes {
    my $oidNum = shift;
    my $hexStr = "";
    my $counter = 0;

    my $workVal = $oidNum;
    while (1) {
        my $quotient  = int($workVal / 128);
        my $remainder = $workVal % 128;

        if ($counter != 0) {
            $remainder += 128;
        }
        $hexStr = convertDecNumToHexStr($remainder) . $hexStr;

        if ($quotient == 0) {
            last;
        }
        $workVal = $quotient;
        $counter++;
    }
    return $hexStr;
}

sub getBinLengthFromHexStr {
    my @hexStrs = @_;
    my $binLength = 0;
    foreach my $hexStr (@hexStrs) {
       $binLength += length($hexStr)/2;
    }
    return $binLength;
}

sub constractBerData {
    my ($tag, $data) = @_;
    $data =~ s/\s//g;
    my $binLength = (length($data))/2;
    my $berData = $tag . convertDecNumToHexStr($binLength) . $data;
    return $berData;
}

sub convertDecNumToHexStr {
    my $decNum = shift;
    my $hexStr = sprintf("%02x", $decNum);
    if (length($hexStr)%2 != 0) {
        $hexStr = '0' . $hexStr;
    }
    return $hexStr;
}


上記のスクリプト作成に当たっては、OID を BER(Basic Encoding Rules) 形式でエンコーディングするのがちょっと面倒だった。(convertOidStrToHexStr関数やconvertOidNumToHexStrForMultiBytes関数の辺り・・)
この辺の話については、別途、記事を書きたいと思っている。

AOSSを使って、プリンタと無線LANルータを接続

自宅で、無線LANルータ(buffalo)経由で PCとプリンタを接続するために、プリンタと無線LANルータを無線で接続することになった。簡単に、構成は以下。

 

無線LANルータ

          |

          +---------(ここは接続済)--------- PC

          |

          + ------(接続したのはここ)------ プリンタ

 

PCやスマホから無線LANルータへの接続は何度もやったことがあるので慣れているが、プリンタから無線LANルータはやったことがなかったので、どうやってやるのかな・・と思って調べたところ、AOSS (AirStation One-Touch Secure System) という便利な技術があることが分かった。この技術を使うと、無線LANルータのSSIDやPWを手入力せずに接続設定を行うことができる。

幸い、プリンタも無線LANルータもAOSSに対応していたので、以下の手順により接続を行うことができた。

  1. プリンタのAOSSを起動する。(プリンタによって手順は異なる)
  2. 無線LANルータのAOSSを起動する。(無線LANルータ側のAOSSボタンを押す)

これだけで、プリンタと無線LANルータの接続設定が完了し、PCから無線LANルータ経由でプリンタを操作できるようになった。

SNMPのパケットダンプを解析する時のコツ

先ほど、

SNMP v2c trap (coldStart) 送信スクリプト - Akira's Blog

の記事を書くために SNMPトラップのパケットダンプを解析した。この際に SEQUENCE型を示す 0x30 に着目すると、各データの区切り位置が分かって解析しやすかった。

 パケットダンプ内に 0x30 があったとして、それが SEQUENCE型を示すとは限らないが、目安として 0x30 をデータの区切り位置と見なすと、パケット解析が捗りそうな気がする。

ちなみに、解析したパケットダンプは以下。

30 40 02 01 01 04 06 70 75 62 6c 69 63 a7 33 02 
01 0a 02 01 00 02 01 00 30 28 30 0d 06 08 2b 06 
01 02 01 01 03 00 43 01 0a 30 17 06 0a 2b 06 01 
06 03 01 01 04 01 00 06 09 2b 06 01 06 03 01 01 
05 01

 ここに登場する 0x30 は全てSEQUENCE型を示すもので、以下の通り、データの区切りと見なせる。

30 : SEQUENCE     # トラップデータの開始
40 : Total length
02 01 01 : SNMP version
04 06 70 75 62 6c 69 63 : community name
a7 : V2-TRAP-PDU
33 : PDU length
02 01 0a : request id (10)
02 01 00 : error status
02 01 00 : error index

30 : SEQUENCE     # varbindリストの開始
28 : varbind list length

30 : SEQUENCE     # varbind(1つ目)の開始
0d : varbind length
06 08 2b 06 01 02 01 01 03 00 : .1.3.6.1.2.1.1.3.0
43 01 0a : sysUpTime value (10)

30 : SEQUENCE
17 : varbind length     # varbind(2つ目)の開始
06 0a 2b 06 01 06 03 01 01 04 01 00 : .1.3.6.1.6.3.1.1.4.1.0
06 09 2b 06 01 06 03 01 01 05 01 : .1.3.6.1.6.3.1.1.5.1

 

今後、SNMPデータのパケットダンプを解析する時は、0x30 を区切りの目安として考えたい。

まあ、wiresharkとか使える環境だったら、使った方が断然楽で速いのだが、そうでない環境で作業することもあると思うので、今回纏めてみた。

SNMP v2c trap (coldStart) 送信スクリプト

SNMP v2c の trap (coldStart) を送信するperlスクリプト sendTrap.pl を作成した。perl sendTrap.pl として実行すると、localhost の 162/udp に対して、coldStartトラップを送信する。例えば、SNMPマネージャのtrap受信テストを簡単に行うのに使用できると思う。

use strict;
use warnings;
use Socket;

#---------------
# SNMP type
#---------------
my $V1_TRAP = 'a4';
my $V2_TRAP = 'a7';

#---------------
# Data type
#---------------
my $INTEGER      = '02';
my $OCTET_STRING = '04';
my $OBJECT_ID    = '06';
my $SEQUENCE     = '30';
my $IP_ADDRESS   = '40';
my $TIME_TICKS   = '43';

#---------------
# Dest info
#---------------
my $DEST_ADDR = 'localhost';
my $DEST_PORT = 162;

#---------------
# MAIN
#---------------
my $socket;
socket($socket, PF_INET, SOCK_DGRAM, 0) or die "Failed to create socket. $!";

my $addrBin = inet_aton($DEST_ADDR);
my $sockAddr = pack_sockaddr_in($DEST_PORT, $addrBin);

my $trapData = constractTrapData();
my $trapDataBin = pack("H*", $trapData);
send($socket, $trapDataBin, 0, $sockAddr) or die "Failed to send. $!";

#---------------
# Sub functions
#---------------
sub constractTrapData {
    my $snmpVersion = 1; # v2c
    my $commName    = 'public';
    my $pduType     = 'a7'; # SNMPv2 trap
    my $requestID   = 10;
    my $errorStatus = 0;
    my $errorIndex  = 0;

    my $snmpVersionBerUnit = constractBerData($INTEGER, changeDecNumToHexStr($snmpVersion));
    my $commNameBerUnit    = constractBerData($OCTET_STRING, unpack("H*", $commName));
    my $requestIDBerUnit   = constractBerData($INTEGER, changeDecNumToHexStr($requestID));
    my $errorStatusBerUnit = constractBerData($INTEGER, changeDecNumToHexStr($errorStatus));
    my $errorIndexBerUnit  = constractBerData($INTEGER, changeDecNumToHexStr($errorIndex));
    my $varbindData        = constractVarbindData();
    
    my $trapPduLength = getBinLengthFromHexStr(
                            $requestIDBerUnit,
                            $errorStatusBerUnit,
                            $errorIndexBerUnit,
                            $SEQUENCE,
                            changeDecNumToHexStr(getBinLengthFromHexStr($varbindData)),
                            $varbindData);
    
    my $totalength = getBinLengthFromHexStr(
                        $snmpVersionBerUnit, 
                        $commNameBerUnit, 
                        $pduType,
                        changeDecNumToHexStr($trapPduLength))
                     + $trapPduLength;

    my $trapData = $SEQUENCE . 
                   changeDecNumToHexStr($totalength) .
                   $snmpVersionBerUnit . 
                   $commNameBerUnit . 
                   $pduType .
                   changeDecNumToHexStr($trapPduLength) .
                   $requestIDBerUnit .
                   $errorStatusBerUnit .
                   $errorIndexBerUnit .
                   $SEQUENCE .
                   changeDecNumToHexStr(getBinLengthFromHexStr($varbindData)) .
                   $varbindData;
    return $trapData;
}

sub constractVarbindData {
    # ------------------------
    # sysUpTime
    # ------------------------
    my $sysUpTimeOid = '1.3.6.1.2.1.1.3.0';
    my $sysUpTimeOidBerData = constractBerData($OBJECT_ID, convertOidStrToHexStr($sysUpTimeOid));
    my $sysUpTime = 10;
    my $sysUpTimeBerData = constractBerData($TIME_TICKS, changeDecNumToHexStr($sysUpTime));
    my $sysUpTimeVarbindLength = getBinLengthFromHexStr($sysUpTimeOidBerData, $sysUpTimeBerData);
    my $sysUpTimeVarbind = $SEQUENCE . 
                           changeDecNumToHexStr($sysUpTimeVarbindLength) . 
                           $sysUpTimeOidBerData .
                           $sysUpTimeBerData;

    # ------------------------
    # sysTrapOID
    # ------------------------
    my $sysTrapOid = '1.3.6.1.6.3.1.1.4.1.0';
    my $sysTrapOidBerData = constractBerData($OBJECT_ID, convertOidStrToHexStr($sysTrapOid));
    my $sysTrapOidData = '1.3.6.1.6.3.1.1.5.1';
    my $sysTrapBerData = constractBerData($OBJECT_ID, convertOidStrToHexStr($sysTrapOidData));
    my $sysTrapVarbindLength = getBinLengthFromHexStr($sysTrapOidBerData, $sysTrapBerData);
    my $sysTrapVarbind = $SEQUENCE . 
                         changeDecNumToHexStr($sysTrapVarbindLength) . 
                         $sysTrapOidBerData .
                         $sysTrapBerData;
    
    return $sysUpTimeVarbind . $sysTrapVarbind;
}

sub convertOidStrToHexStr {
    my $oidStr = shift;
    my @oids = split(/\./, $oidStr);
    my $hexStr = changeDecNumToHexStr(40*$oids[0] + $oids[1]);
    for (my $i = 2; $i <= $#oids; $i++) {
        $hexStr .= changeDecNumToHexStr($oids[$i]);
    }
    return $hexStr;
}

sub getBinLengthFromHexStr {
    my @hexStrs = @_;
    my $binLength = 0;
    foreach my $hexStr (@hexStrs) {
       $binLength += length($hexStr)/2;
    }
    return $binLength;
}

sub constractBerData {
    my ($tag, $data) = @_;
    $data =~ s/\s//g;
    my $binLength = (length($data))/2;
    my $berData = $tag . changeDecNumToHexStr($binLength) . $data;
    return $berData;
}

sub changeDecNumToHexStr {
    my $decNum = shift;
    my $hexStr = sprintf("%02x", $decNum);
    if (length($hexStr)%2 != 0) {
        $hexStr = '0' . $hexStr;
    }
    return $hexStr;
}


上記のスクリプトが送信するtrapデータのパケットダンプは以下の通り。

30 40 02 01 01 04 06 70 75 62 6c 69 63 a7 33 02
01 0a 02 01 00 02 01 00 30 28 30 0d 06 08 2b 06
01 02 01 01 03 00 43 01 0a 30 17 06 0a 2b 06 01
06 03 01 01 04 01 00 06 09 2b 06 01 06 03 01 01
05 01


上記を簡単に解説すると以下の通り。

30 : SEQUENCE
40 : Total length
02 01 01 : SNMP version
04 06 70 75 62 6c 69 63 : community name
a7 : V2-TRAP-PDU
33 : PDU length
02 01 0a : request id (10)
02 01 00 : error status
02 01 00 : error index

30 : SEQUENCE
28 : varbind list length

30 : SEQUENCE
0d : varbind length
06 08 2b 06 01 02 01 01 03 00 : .1.3.6.1.2.1.1.3.0
43 01 0a : sysUpTime value (10)

30 : SEQUENCE
17 : varbind length
06 0a 2b 06 01 06 03 01 01 04 01 00 : .1.3.6.1.6.3.1.1.4.1.0
06 09 2b 06 01 06 03 01 01 05 01 : .1.3.6.1.6.3.1.1.5.1


perl の Net::SNMP パッケージを使用すればもっと簡単に書けるが、SNMP trap のパケットの中身の勉強も兼ねて、一から作成してみた。
なお、今回作成したスクリプトについては、V1 trap にも対応したり、送信先などを引数で与えたりする等、今後いろいろエンハンスする予定。

C:\Users\All Users と C:\ProgramData

C:\Users\All Users は C:\ProgramData へのシンボリックリンクになっている。つまり、C:\Users\All Users の実体は C:\ProgramData にある。これを知らないで、「C:\Users\All Users に C:\ProgramData と同じデータが重複して存在しまっている」とか思って、C:\Users\All Users 配下を削除すると、実体の方(C:\ProgramData配下)も消えてしまうので、要注意。

 

ちなみに、何でこのようになっているかについて調べたところ、Windows上で動くアプリの互換性を保つため、という説明が見つかった。

C:\ProgramData と C:\Users\All Users は同じものだった - pudding - diary(2016-12-20)

おそらく C:\Users\All Users 配下にデータを配備するようにアプリが作られていた時代があったのだろう。

メモ帳でUTF-8で保存すると、ファイルの先頭にBOMが入る。

メモ帳でUTF-8で保存すると、ファイルの先頭に BOM(Byte Order Mark)が入る。通常テキストエディタではBOMが付いているか分からないが、バイナリエディタで見ると BOM(0xEF 0xBB 0xBF) が付いているのが分かる。ちなみに、メモ帳のこの挙動は、私の調べた限り、変更する方法はない。

 

このBOMが付いている状態のファイルをプログラムに読み込ませると、エラーが発生することがある。これに嵌ると、テキストエディタで見る限り、プログラムに読み込ませたファイルは問題なさそうに見えるため、原因が分かるまで時間がかかることがある。

 

なので、正しい内容のファイルをプログラムに読み込ませているはずなのに、プログラム側でエラーが発生する時は、ファイルにBOMが付いているかを疑うのが良いと思う。

sprintf関数とunpack関数

sprintf関数とunpack関数は、ともに引数の数値を16進表記に変換できるが、以下の挙動の違いがある。

use strict;
use warnings;

my $num = 12;

my $hexdumpBySprintf = sprintf("%x", $num);
my $hexdumpByUnpack = unpack("H*", $num);

print "hexdump by sprintf: $hexdumpBySprintf\n"; # c
print "hexdump by unpack: $hexdumpByUnpack\n";   # 3121

上記を実行すると、結果は以下になる。

hexdump by sprintf: c
hexdump by unpack: 3132


つまり、sprintf関数の方は、引数の 12 を数値として扱い、対応する16進文字に変換する。一方、unpack関数の方は、引数の 12 を文字として扱い、対応する16進文字列に変換する。