2010年07月28日

実践SNMP+Java - Trap/Inform Receiver

SNMP4Jを利用したSNMP Trap/Informの受信について説明します。

そろそろ気がつかれている方もいるかもしれませんが、SNMPv3については説明してきませんでした。

僕自身、実践で利用する機会・ニーズが少ないのが理由です。

SNMP Trap/Inform受信についてもSNMPv3は、多分動くだろう、という程度です。
時間が出来たらv3についてもまとめるつもりです。

早速Javaコードから見ていきましょう。
 
<Javaコード>
  1. public class SnmpReceiver implements CommandResponder {
  2.   private Snmp snmp = null;
  3.   public static void main(String[] args) {
  4.     SnmpReceiver receiver = new SnmpReceiver();
  5.     receiver.start();
  6.   }
  7.   public void start() {
  8.     System.out.println("starting snmp trap/inform receiver...");
  9.     MultiThreadedMessageDispatcher dispatcher;
  10.     Address listenAddr;
  11.     ThreadPool pool;
  12.     try {
  13.       // message dispatcher
  14.       int numWorkers = 5;
  15.       pool = ThreadPool.create("workers", numWorkers);
  16.       dispatcher = new MultiThreadedMessageDispatcher(pool, new MessageDispatcherImpl());
  17.       // listen UDP address
  18.       String udpAddr = "udp:0.0.0.0/162"; // choose receiver interface and port.
  19.       listenAddr = GenericAddress.parse( System.getProperty("snmp4j.listenAddress", udpAddr) );
  20.       TransportMapping tm;
  21.       if ( listenAddr instanceof UdpAddress ) {
  22.         tm = new DefaultUdpTransportMapping( (UdpAddress) listenAddr );
  23.       } else {
  24.         tm = new DefaultTcpTransportMapping( (TcpAddress) listenAddr );
  25.       }
  26.       // SNMP operation base object
  27.       snmp = new Snmp(dispatcher, tm);
  28.       // message processing model for SNMPv1
  29.       snmp.getMessageDispatcher().addMessageProcessingModel( new MPv1() );
  30.       // message processing model for SNMPv2c (community based SNMPv2).
  31.       snmp.getMessageDispatcher().addMessageProcessingModel( new MPv2c() );
  32.       // message processing model for SNMPv3
  33.       snmp.getMessageDispatcher().addMessageProcessingModel( new MPv3() );
  34.       USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0);
  35.       SecurityModels.getInstance().addSecurityModel(usm);
  36.       // open port
  37.       snmp.listen();
  38.       // register this listener to observer.
  39.       snmp.addCommandResponder(this);
  40.       System.out.println("succeed: start snmp trap/inform receiver.");
  41.     } catch (UnknownHostException e) {
  42.       e.printStackTrace();
  43.     } catch (IOException e) {
  44.       e.printStackTrace();
  45.     }
  46.   }
  47.   public void processPdu(CommandResponderEvent snmpEvent) {
  48.     System.out.println("* * * * * * * * * * SNMP TRAP/INFORM EVENT * * * * * * * * * *");
  49.     try {
  50.       // get security name.
  51.       String communityInPDU = null;
  52.       byte[] securityName = snmpEvent.getSecurityName();
  53.       if ( securityName != null ) {
  54.         communityInPDU = OctetString.fromByteArray( snmpEvent.getSecurityName() ).toString();
  55.       }
  56.       // get source UDP address.
  57.       Address address = snmpEvent.getPeerAddress();
  58.       System.out.println("snmp agent addr      -> " + address);
  59.       System.out.println("snmp agent community -> " + communityInPDU);
  60.       // get security model
  61.       switch ( snmpEvent.getSecurityModel() ) {
  62.       case SecurityModel.SECURITY_MODEL_SNMPv1:
  63.         System.out.println("security model       -> SNMPv1");
  64.         break;
  65.       case SecurityModel.SECURITY_MODEL_SNMPv2c:
  66.         System.out.println("security model       -> SNMPv2c");
  67.         break;
  68.       case SecurityModel.SECURITY_MODEL_USM:
  69.         System.out.println("security model       -> SNMPv3");
  70.         break;
  71.       }
  72.       // get PDU type.
  73.       PDU receivePDU = snmpEvent.getPDU();
  74.       if ( receivePDU != null ) {
  75.         switch ( receivePDU.getType() ) {
  76.         case PDU.V1TRAP: //v1
  77.           System.out.println("PDU Type             -> SNMPv1 Trap PDU");
  78.           PDUv1 v1TrapPDU = (PDUv1) receivePDU;
  79.           System.out.println(" Timestamp    -> " + v1TrapPDU.getTimestamp());
  80.           System.out.println(" Enterprise   -> " + v1TrapPDU.getEnterprise().toString());
  81.           System.out.println(" GenericType  -> " + v1TrapPDU.getGenericTrap());
  82.           System.out.println(" SpecificType -> " + v1TrapPDU.getSpecificTrap());
  83.           break;
  84.         case PDU.TRAP: // v2c|v3
  85.           System.out.println("PDU Type             -> SNMP Trap PDU");
  86.           break;
  87.         case PDU.INFORM: // inform
  88.           System.out.println("PDU Type             -> SNMP Inform PDU");
  89.           // send inform response.
  90.           PDU responsePDU = snmpEvent.getPDU();
  91.           responsePDU.setErrorIndex(0);
  92.           responsePDU.setErrorStatus(0);
  93.           responsePDU.setType(PDU.RESPONSE);
  94.           /*
  95.            * StatusInformation represents status information of a SNMPv3 message
  96.            * that is needed to return a report message.
  97.            */
  98.           StatusInformation statusInfo = new StatusInformation();
  99.           /*
  100.            *  StateReference represents state information associated with SNMP messages.
  101.            *  The state reference is used to send response or report (SNMPv3 only).
  102.            *  Depending on the security model not all fields may be filled.
  103.            */
  104.           StateReference stateRef = snmpEvent.getStateReference();
  105.           // return response PDU
  106.           snmpEvent.getMessageDispatcher().returnResponsePdu(
  107.               snmpEvent.getMessageProcessingModel(),
  108.               snmpEvent.getSecurityModel(),
  109.               snmpEvent.getSecurityName(),
  110.               snmpEvent.getSecurityLevel(),
  111.               responsePDU,
  112.               snmpEvent.getMaxSizeResponsePDU(),
  113.               stateRef,
  114.               statusInfo
  115.               );
  116.           break;
  117.         default:
  118.           System.out.println("PDU Type             -> any other PDU: " + receivePDU.getType());
  119.           break;
  120.         }
  121.         // get variable bindings.
  122.         System.out.println(" - - - - - - - - - - - Variable Bindings - - - - - - - - - - -");
  123.         for (int i=0; i<receivePDU.size(); i++) {
  124.           VariableBinding varbind = receivePDU.get(i);
  125.           System.out.println(i + ": " + varbind.getOid().toString() +" -> "+ varbind.getVariable().toString());
  126.         }
  127.         System.out.println();
  128.       }
  129.     } catch (Exception e) {
  130.       e.printStackTrace();
  131.     }
  132.   }
  133.   public void shutdown() {
  134.     try {
  135.       snmp.close();
  136.     } catch (IOException e) {
  137.       e.printStackTrace();
  138.     }
  139.   }
  140. }


<実行結果>

まず、この受信Javaプログラムを起動します。 
 
  starting snmp trap/inform receiver...
  succeed: start snmp trap/inform receiver.
 
次にSNMPv1 Trap/SNMPv2 Trap/SNMP Informで作成したプログラムを使って、
受信サーバにSNMPメッセージを送信すると次のような結果が表示されます。
 
1)SNMPv1 Trap
 
  * * * * * * * * * * SNMP TRAP/INFORM EVENT * * * * * * * * * *
  snmp agent addr      -> 192.168.0.11/50579
  snmp agent community -> public
  security model       -> SNMPv1
  PDU Type             -> SNMPv1 Trap PDU
   Timestamp    -> 8640000
   Enterprise   -> 1.3.6.1.4.1.99999.1.1.100
   AgentAddress -> 127.0.0.1
   GenericType  -> 6
   SpecificType -> 3
   - - - - - - - - - - - Variable Bindings - - - - - - - - - - -
  0: 1.3.6.1.4.1.99999.1.2.1.0 -> NETBUFFALO SNMPv1 trap
  1: 1.3.6.1.4.1.99999.1.2.2.0 -> sample v1 trap
 
2)SNMPv2 Trap
 
  * * * * * * * * * * SNMP TRAP/INFORM EVENT * * * * * * * * * *
  snmp agent addr      -> 192.168.0.11/50588
  snmp agent community -> public
  security model       -> SNMPv2c
  PDU Type             -> SNMP Trap PDU
   - - - - - - - - - - - Variable Bindings - - - - - - - - - - -
  0: 1.3.6.1.2.1.1.3.0 -> 1 day, 0:00:00.00
  1: 1.3.6.1.6.3.1.1.4.1.0 -> 1.3.6.1.4.1.99999.1.1.100.0.1
  2: 1.3.6.1.4.1.99999.1.2.1.0 -> NETBUFFALO SNMPv2 trap - varbind 1
  3: 1.3.6.1.4.1.99999.1.2.2.0 -> NETBUFFALO SNMPv2 trap - varbind 2
 
3)SNMPv2 Inform
 
  * * * * * * * * * * SNMP TRAP/INFORM EVENT * * * * * * * * * *
  snmp agent addr      -> 192.168.0.11/50601
  snmp agent community -> public
  security model       -> SNMPv2c
  PDU Type             -> SNMP Inform PDU
   - - - - - - - - - - - Variable Bindings - - - - - - - - - - -
  0: 1.3.6.1.2.1.1.3.0 -> 1 day, 0:00:00.00
  1: 1.3.6.1.6.3.1.1.4.1.0 -> 1.3.6.1.4.1.99999.1.1.100.0.1
  2: 1.3.6.1.4.1.99999.1.2.1.0 -> NETBUFFALO SNMPv2 Inform - my varbind 1
  3: 1.3.6.1.4.1.99999.1.2.2.0 -> NETBUFFALO SNMPv2 Inform - my varbind 2
 

<説明>

1)オブザーバー・パターン
  サンプル・コードでは、CommandResponderインタフェースを実装し、42行目の
  snmp.addCommandResponder(this);でSnmpオブジェクトに自身のオブジェクトを
  リスナー登録しています。
  こうしておくとSnmpオブジェクトがSNMPメッセージを受信した際に、
  自身のprocessPdu(CommandResponderEvent snmpEvent)メソッドが呼び出されます。
 
2)受信サーバの起動
  10~49行目でサービスの起動処理を行っています。
  17~19行目ではトラップを受信した際にディスパッチする為のワーカー・スレッドの数
 (numWorkers)を指定してスレッド・プール及びディスパッチャーを生成しています。
  このスレッド数が受信性能に関わってくる訳ですが、数と性能の関係については
  別の機会で説明します。
  21~30行目ではSNMPマネージャ側の受信アドレスを指定し、Snmpオブジェクトを
  生成しています。今回のコードでは、'0.0.0.0'を指定していますが、これは全ての
  ネットワーク・インタフェースから受信することを意味しています。
  もし、SNMPマネージャの動作するサーバ上に複数のネットワーク・インタフェース
  (IPアドレス)が存在し、特定のIPアドレス宛のメッセージのみ受信する場合には、
  受信IPアドレスを指定します。
  最後に32~40行目でSNMPv1~v3に対応するメッセージ処理モデルを生成・追加後、
  メッセージの受信を開始(snmp.listen())しています。
  #snmp.addCommandResponder(this)も忘れずに!
 
3)受信処理
  51~142行目がトラップの受信処理です。
  まず、CommandResponderEventオブジェクトからエージェント(送信)側の
  UDPアドレス情報、コミュニティ名を取り出しています。
  もし、コミュニティ名で認証する場合には、この時点で行ないます。
  67~77行目のセキュリティ・モデルは参考情報として出力しています。
  80~127行目でPDUの情報を出力しています。
  まず、PDUタイプを判定し、SNMPv1であればv1 Trap PDU特有の情報を出力しています。
  SNMPv2 Informの場合ですが、エージェント(送信)側に受信を表すメッセージを
  送信する必要があるので、その処理を113~122行目で行っています。
  その送信PDUの中身ですが、簡単に言うと、受信したPDUをそのまま投げ返しています。
  もし、データ(バーバインズ)の中身を確認してから送信するなら、コード上、
  少し後ろの方で実装すべきかもしれません。
  最後に130~134行目で各バーバインドの中身を取り出し、出力しています。
 
4)停止処理
  停止処理を144~150行目で実装していますが、このコードでは呼出される
  ことはありません。参考として記載しておきました。
 
入門SNMP
入門SNMP
posted with amazlet at 13.01.12
ダグラス・R. マウロ ケビン・J. シュミット
オライリー・ジャパン
売り上げランキング: 257,278

Java ネットワーク プログラミング 基礎からわかる 完全入門
永嶋 浩
技術評論社
売り上げランキング: 228,941

Posted by netbuffalo at 19:09│TrackBack(0) 実践SNMP+Java 


この記事へのトラックバックURL