諸事情でアプリやサーバからいろいろな通知を SNMP トラップで送ることがよくあるのですが、データバインディングの中身に日本語(UTF-8)を含めなければならないことがあります。
送るのは snmptrap コマンドで普通に送れますが・・snmptrapd でそれを受信するためには少し工夫が必要でした。
snmptrapd で日本語を受ける
普通に受けるとマルチバイト部分が "E3 81 82 E3 81 84 E3 81 86 E3 81 88 E3 81 8A"
のように16進の文字列に置き換えられて traphandle には渡されます。
これをどうにかするために、まずトラップの MIB で次のように型を定義します。
HogeString ::= TEXTUAL-CONVENTION DISPLAY-HINT "255t" STATUS current SYNTAX OCTET STRING
トラップのデータバインディングのオブジェクトの定義で↑の型を使います。
hogeMessage OBJECT-TYPE SYNTAX HogeString MAX-ACCESS read-only STATUS current ::= { hogeAlarmObjs 1 }
この MIB を snmptrapd に食わせて snmptrap で日本語(UTF-8)を含むトラップを送ると UTF-8 のバイナリそのままで traphandle に渡されます。
CentOS 7 で問題発生
CentOS 5 の snmptrapd なら↑の方法で大丈夫でした。
がしかし、CentOS 7 の snmptrapd だとマルチバイト部分が .
で置換されてしまいました。
原因
これ↓です。
そのままバッファにコピーされていたものが sprint_realloc_asciistring
を通るようになっています。
sprint_realloc_asciistring
では isprint
でも isspace
でもない文字はすべて .
に置換されます。
簡単な解決方法
たぶんない。
強いて言えばトラップで日本語などのマルチバイト文字を使わないようにすることですけど。
面倒な解決方法
16進の文字列を traphandle に指定するスクリプトでデコードします。
実はもっと昔は、日本語(UTF-8)ではなく日本語(Shift_JIS)を使っていました。その頃は16進になった文字列を自前でデコードしていました。
ので、そんなに面倒なことでは無いはずですが・・・
MIB を食わさずに -Oa
を付けて snmptrapd を起動すると同じ動き(.
に置換)になり、-Ox
なら16進表記になります。
-Oa
は文字列をそのまま表示するオプションで、-Ox
は文字列を16進で表示するオプションです。どちらのオプションも指定しないときは文字列がそのままで表示可能かを自動で判断されます。
がしかし、MIB で DISPLAY-HINT
が指定されているときは -Oa
や -Ox
は無視して DISPLAY-HINT
に従います。
なので、↑の MIB を食わすと -Ox
を指定したとしてもマルチバイト文字は .
に置換されてしまい、16進文字列にはなりません。
つまり、↑の MIB を食わせる限りマルチバイト文字が .
に置換されてしまい、デコードも不可能です。
MIB を食わせなければ良いのですが・・・下記のような列挙型のオブジェクトは値そのものではなく名前に置き換わって欲しいので、MIB は食わせたいです。
HogePriority ::= INTEGER { EMERG (0), ALERT (1), CRIT (2), ERR (3), WARN (4), NOTICE (5), INFO (6), DEBUG (7) }
もちろん MIB を書き換えて DISPLAY-HINT
を削除してしまえば良いんですけど・・・
MIB をそのままで解決する
/etc/snmp/snmp.conf
に下記を追記します。
noDisplayHint yes
すると DISPLAY-HINT
が無視されて16進文字列になるので、自前でデコードできます。
ただ、この方法だと↑の列挙型のオブジェクトの名前への解決が行われないっぽい気が・・・やっぱり MIB 書き換えるしか無いか。
なお、この設定(noDisplayHint
)はオプションの -Ih
と同じ意味ですが、snmptrapd は -I
が別の意味に割り当てられているので設定ファイルで指定する必要があります。