net-snmpのpass_persistを使って、
自作したsnmp agentで応答を返す。
以下自作agent。
# include <iostream>
# include <string>
void getnext_request( std::string &oid ) {
if(
oid == ".1.3.6.1.4.1.99999" ||
oid == ".1.3.6.1.4.1.99999.1"
) {
std::cout
<< ".1.3.6.1.4.1.99999.1.0" << std::endl
<< "integer" << std::endl
<< 42 << std::endl
;
} else {
// 該当する内容が無い場合、NONE\nを返す
std::cout << "NONE" << std::endl;
}
}
void get_request( std::string &oid ) {
if( oid == ".1.3.6.1.4.1.99999.1.0" ) {
std::cout
<< oid << std::endl
<< "integer" << std::endl
<< 42 << std::endl
;
} else {
// 該当する内容が無い場合、NONE\nを返す
std::cout << "NONE" << std::endl;
}
}
int main( int argc, char **argv ) {
while( 1 ) {
std::string line;
std::cin >> line;
if( line.empty() ) {
break;
} else if( line == "PING" ) {
std::cout << "PONG" << std::endl;
} else if( line == "get" ) {
std::string oid;
std::cin >> oid;
get_request( oid );
} else if( line == "getnext" ) {
std::string oid;
std::cin >> oid;
getnext_request( oid );
} else {
// unk.
break;
}
}
}
このサンプルでは、getで.1.3.6.1.4.1.99999.1.0しか応答しない。
もしこれを元にagentを作成する場合は、
getnext_requestとget_requestの部分を、相当作りこむ必要がある。
上記ソースをコンパイルする。
実行ファイルは/root/a.outとする。
snmpd.confを以下のようにする。
#
syslocation あなたの心の中
syscontact todanano
# sec.name source community
com2sec Net-Local 0.0.0.0 public
# groupName securityModel securityName
group Net-Group v1 Net-Local
group Net-Group v2c Net-Local
# name incl/excl subtree mask(optional)
view all included .1
# group context sec.model sec.level prefix read write notif
access Net-Group "" any noauth exact all none none
access Net-Group "" any priv exact all none none
pass_persist .1.3.6.1.4.1.99999 /root/a.out
pass_persist .1.3.6.1.4.1.99999 /root/a.outの部分が、
作成した自作エージェントを設定している箇所。
.1.3.6.1.4.1.99999以下のリクエストが来た場合、
/root/a.outに渡すようになる。
それ以外は、色々書いてあるが、最低限、応答が返せる内容であれば
何でも良い。
snmpd.confを書き換えたら、snmpdを再起動する。
[root@localhost ~]# /etc/init.d/snmpd restart
Stopping snmpd: [ OK ]
Starting snmpd: [ OK ]
[root@localhost ~]#
snmpgetかsnmpwalkを使って、.1.3.6.1.4.1.99999.1.0が応答することを確認する。
※snmpgetの場合、oidを間違えないこと。間違えた場合、エラーとなる。
[root@localhost ~]# snmpget -v 1 -c public localhost .1.3.6.1.4.1.99999.1.0
SNMPv2-SMI::enterprises.99999.1.0 = INTEGER: 42
[root@localhost ~]#
[root@localhost ~]#
[root@localhost ~]# snmpwalk -v 1 -c public localhost .1.3.6.1.4.1.99999
SNMPv2-SMI::enterprises.99999.1.0 = INTEGER: 42
[root@localhost ~]#
[root@localhost ~]# snmpwalk -v 1 -c public localhost .1.3.6.1.4.1.99999.1
SNMPv2-SMI::enterprises.99999.1.0 = INTEGER: 42
[root@localhost ~]#
[root@localhost ~]# snmpwalk -v 1 -c public localhost .1.3.6.1.4.1.99999.1.0
SNMPv2-SMI::enterprises.99999.1.0 = INTEGER: 42
[root@localhost ~]#
[root@localhost ~]#
先にも書いたが、上記サンプルでは、.1.3.6.1.4.1.99999.1.0しか応答を返せないので、
もしこれ以外の内容を返したい場合は、作りこむ必要がある。
(特にgetnextの内容は、相当考える必要がある。矛盾無く、次のoidを返せる仕組みが必要)
また、pass_persistによって呼び出されるプロセスは、
一度実行された後は、起動し続ける。
これは、snmpwalkなど、連続で問い合わせを受ける場合、
応答速度の面で恩恵がある。
また、前回値と今回値の差分値を返す場合、
プロセスが起動し続けているため、
シンプルな実装が可能となる(一時ファイル等を使う必要が無い)。
該当するoidにリクエストが来たタイミングで、対象のプロセスが動作していない場合、
snmpdはプロセスの実行を試みる。
すでに動作している場合は、そのままやり取りをする。
一度起動したプロセスは、snmpdの停止(再起動)によって、停止する。
[root@localhost ~]# /etc/init.d/snmpd restart
Stopping snmpd: [ OK ]
Starting snmpd: [ OK ]
[root@localhost ~]#
[root@localhost ~]#
[root@localhost ~]# ps aux | grep a.out
root 15833 0.0 0.0 61176 748 pts/0 S+ 10:09 0:00 grep a.out
[root@localhost ~]#
[root@localhost ~]#
[root@localhost ~]# snmpwalk -v 1 -c public localhost .1.3.6.1.4.1.99999.1.0
SNMPv2-SMI::enterprises.99999.1.0 = INTEGER: 42
[root@localhost ~]#
[root@localhost ~]#
[root@localhost ~]# ps aux | grep a.out
root 15839 0.0 0.0 11564 1008 ? S 10:09 0:00 /root/a.out
root 15843 0.0 0.0 61176 748 pts/0 S+ 10:09 0:00 grep a.out
[root@localhost ~]#
[root@localhost ~]#
[root@localhost ~]# /etc/init.d/snmpd restart
Stopping snmpd: [ OK ]
Starting snmpd: [ OK ]
[root@localhost ~]#
[root@localhost ~]# ps aux | grep a.out
root 15865 0.0 0.0 61176 748 pts/0 S+ 10:09 0:00 grep a.out
[root@localhost ~]#
[root@localhost ~]#
仮に指定したプロセスが、起動し続けるような実装になっていない場合でも、
単にいなければ実行してからやり取りをするだけなので、とりあえず動作する。
ただ、起動し続けるプログラムよりも、オーバーヘッドが大きくなるため、
pass_persistで設定する意味は無い。
実行したら終了したい場合は、pass_persistではなく、passを使ったほうが良い。
passであれば、PING、PONGのやり取りをせずに、そのままリクエストを受け取れるため、
実装もシンプルになるだろう。