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のやり取りをせずに、そのままリクエストを受け取れるため、
実装もシンプルになるだろう。