はじめに
この連載では監視用プロトコルとして広く知られているSNMPについて設定方法などを交えて説明していきます。今回は前半で作成したMIBファイルを基に生成したソースファイルの編集ポイント、およびエージェントの作成方法を述べます。
構築環境はFedora7(2.6.23.17-88.fc7)、32bit、glibc-2.6-4、gcc-4.1.2を使用しています。
これまでの記事
- 第1回:net-snmpについて(基礎知識)
- 第2回:net-snmpについて(環境構築)
- 第3回:net-snmpについて(機器管理)
- 第4回:net-snmpについて(Trap設定)
- 第5回:net-snmpについて(独自監視項目の追加・前編)
7. 拡張MIBと独自エージェントの実装
今まで取得してきた情報は、既にnet-snmpが用意したものです。
しかし自分たちが作成したソフトの挙動を監視する際、その監視項目は当然ですがnet-snmpにはありませんし、他のsnmpソフトにもありません。
ではどうするか、自分たちで監視したい項目をnet-snmpに追加することで対応します。
具体的な方法は下記の通りです。
- 企業拡張番号の払い出し
- MIBファイルの作成
- MIBファイルの登録
- mib2cによるソースファイルの生成
- ソースファイルの修正・改良
- ソースファイルから拡張MIB対応エージェントの構築
今回は、前回作成したMIBファイルから自動生成されたソースファイルの編集ポイント、および実際にエージェントを作成する手順について述べて行きます。
7.5 ソースコードの説明
mib2c
によって生成されたソースファイルは、それだけでは使用はおろか、make
も通りません。get-requestに対してどんな情報を出力するか、set-requestに対して、どんなチェックをして、どんな値の時に何をするか、仕様を決めてプログラムに落とし込む必要があります。
今回はmib2c
によって生成されたファイルに対して編集したファイルをダウンロードできるようにUpしましたので、そちらを参考にしながら説明をします(と言っても大したことはしておりませんが)。
7.5.1 init_matsutest
いわゆる初期化処理です。編集しなくともコンパイルは通ります。
一回しか呼ばれないので、大域変数や、他のアプリケーションの情報が格納されたファイルなどを開いて、そのディスクリプタを保存しておくなどの初期化処理を追加します。
7.5.2 handle_mtuObject1
文字列を作成後、snmp_set_var_typed_value
に渡しています。
sprintf( buf, "matsutest1, pid:[%d] timer:%s:[%d] call_count:[%d]", getpid( ), status, timered_count, func_call_cnt ); snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR, (u_char *)buf, strlen( buf ));
7.5.3 handle_mtuObject2
自身が呼ばれた回数をカウントし、その数値をsnmp_set_var_typed_value
に渡しています。
int func_call_cnt; snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *)&func_call_cnt, sizeof( func_call_cnt ));
7.5.4 handle_mtuTrap
set-request/get-request両方に対応しなくてはいけないため、やや複雑です。get-requestで呼ばれたときは、reqinfo->mode == MODE_GET
が実行されるだけなので、数値(trap_status)を返して終了しています。
snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *)&trap_status, sizeof( trap_status ));
set-request
で呼ばれた時、reqinfo->mode
は下記の順で呼ばれます(つまり最低4回、handle_mtuTrapが呼ばれます)。
MODE_SET_RESERVE1 → NG → MODE_SET_FREE ↓OK MODE_SET_RESERVE2 → NG → MODE_SET_FREE ↓OK MODE_SET_ACTION → NG → MODE_SET_UNDO ↓OK MODE_SET_COMMIT
今回はMODE_SET_ACTION
の時に値を判定し、条件を満たす場合、Trap
関数(send_mtuStatusTrap_trap)を発行しています。それ以外の場所では何もしてません(OKを返しているだけです)。
今回は生成されたプログラムを極力編集しないようにしたので、MODE_SET_ACTION
以外の所では、本当は消すところを、"if( 0 )
"とか、ありえない記述をしていますが、ご容赦ください。
入力された値は、requests->requestvb->val.*
に入っています。さらにこの領域はポインタなので、実際に変数に確保するには下記の通り行ってください。
int p = *( requests->requestvb->val.integer );
float p = *( requests->requestvb->val.floatVal );
double p = *( requests->requestvb->val.doubleVal );
char * p = strdup( requests->requestvb->val.string );
int strlen = request->requestvb->val_len;
実はつい最近まで、上記が原因となるバッファオーバーフローバグなどがnet-snmpに存在してました。デーモンとして動作するnet-snmpにとって脆弱性を突かれると管理者権限が奪われます。
安全を期すために、「動的に」取得した配列で処理するか、コピー先の配列の大きさ分しかコピーしない等とした対策をとった方が良いでしょう。
7.5.5 handle_mtuTimer
これも set-request/get-request 両方で呼ばれます。
get-requestで呼ばれたときは、reqinfo->mode == MODE_GET
の時なので、数値(timer_status)を返して終了しています。
set-requestで呼ばれたときは、MODE_SET_ACTION
の時、入力された値によってタイマーの登録・解除を行っています。
- タイマー登録:
snmp_alarm_register
- タイマー解除:
snmp_alarm_unregister
今回は自作の関数timer_matsutest
を設定し、そこで30秒経過するとTrap
関数(send_mtuTimerTrap_trap)を発行、タイマーを解除しています。
snmp_alarm_register/snmp_alarm_unregister
は、net-snmpにおける組み込み関数です。詳細は7.6章で説明します。
7.5.6 send_mtuStatusTrap_trap
実はTrap用のソースファイルは、編集しなくてもMakeは通ります。このままでも行けるんですが、イベント内容(独自に送信したい情報)は空になるので、トラップ送信回数とTrapのステータス情報を送信するようにしました。送信したい内容は引数を通して取得しています。
7.5.7 send_mtuTimerTrap_trap
上記同様、イベント内容を送信するために編集しています。タイマーによるトラップのカウント値とhandle_mtuObject1
で作成した文字列を返すように編集しました。具体的にはこれらの値をsend_mtuTimerTrap_trap
の引数として渡し、使用するようにしました。