JavaでSNMPトラップを送信するコードを作成した。snmp4j (https://www.snmp4j.org/) を使用しているので、コンパイル&実行には snmp4j-x.x.x.jar が必要。(実機検証は Java1.8 + snmp4j-2.6.2.jar で実施した)
実行方法
java TrapSender [-v {1|2c|2}] [-a agent-addr] [-o trapOid] [-e enterpriseID] destHost
実行例 (SNMPv1 トラップ送信)
java TrapSender -v 1 -a 192.168.0.1 -e .1.2.3.4.5.6 192.168.0.2
実行例 (SNMPv2c トラップ送信)
java TrapSender -v 2c -o .1.2.3.4.5.6 192.168.0.2
import org.snmp4j.*; import org.snmp4j.mp.SnmpConstants; import org.snmp4j.smi.*; import org.snmp4j.transport.DefaultUdpTransportMapping; import java.io.IOException; public class TrapSender { // Set default value. private String destAddr = "127.0.0.1"; private String agentAddr = "127.0.0.1"; private int destPort = 162; private String trapOid = ".1.2.3.4.5"; private String enterpriseId = ".1.2.3.4.5"; private String commName = "public"; private int snmpVersion = SnmpConstants.version2c; private int varBindNum = 3; void sendTrap () throws IOException { if (snmpVersion == SnmpConstants.version1) { sendV1Trap(); } else { if (snmpVersion == SnmpConstants.version2c) { sendV2cTrap(); } } } void sendV1Trap () throws IOException { // Construct a trap pdu. PDUv1 trapPdu = new PDUv1(); trapPdu.setType(PDU.V1TRAP); trapPdu.setEnterprise(new OID(enterpriseId)); trapPdu.setGenericTrap(PDUv1.ENTERPRISE_SPECIFIC); trapPdu.setSpecificTrap(1); trapPdu.setAgentAddress(new IpAddress(agentAddr)); addVarBindsTo(trapPdu, varBindNum); // Specify a target(dest info). CommunityTarget target = createTarget(commName, SnmpConstants.version1, destAddr, destPort); // Send a snmp trap. System.out.println("Sending an SNMPv1 trap to " + destAddr + " ..."); sendPdu(trapPdu, target); } void sendV2cTrap () throws IOException { // Construct a trap pdu. PDU trapPdu = new PDU(); trapPdu.setType(PDU.NOTIFICATION); trapPdu.add(new VariableBinding(SnmpConstants.sysUpTime, new TimeTicks(1000))); trapPdu.add(new VariableBinding(SnmpConstants.snmpTrapOID, new OID(trapOid))); addVarBindsTo(trapPdu, varBindNum); // Specify a target(dest info). CommunityTarget target = createTarget(commName, SnmpConstants.version2c, destAddr, destPort); // Send a snmp trap. System.out.println("Sending an SNMPv2c trap to " + destAddr + " ..."); sendPdu(trapPdu, target); } private CommunityTarget createTarget(String commName, int snmpVersion, String destIpAddr, int destPort) throws IOException { CommunityTarget target = new CommunityTarget(); target.setCommunity(new OctetString(commName)); target.setVersion(SnmpConstants.version2c); target.setAddress(new UdpAddress(destIpAddr + "/" + destPort)); return target; } private void sendPdu (PDU trapPdu, CommunityTarget target) throws IOException { TransportMapping transport = new DefaultUdpTransportMapping(); Snmp snmp = null; try { transport.listen(); snmp = new Snmp(transport); snmp.send(trapPdu, target); snmp.close(); } catch (IOException ex) { throw ex; } finally { snmp.close(); } } private void addVarBindsTo (PDU trapPdu, int varBindNum) { if (trapPdu == null || varBindNum == 0) { return; } for (int i=1; i<=varBindNum; i++) { String oid = ".1.2.3.4.5." + i; String val = "val" + i; trapPdu.add(new VariableBinding(new OID(oid), new OctetString(val))); } } void setParams(String[] args) throws IllegalArgumentException { for (int i=0; i<args.length; i++) { if ("-v".equals(args[i])) { i++; if ("1".equals(args[i])) { snmpVersion = SnmpConstants.version1; } else if ("2".equals(args[i]) || "2c".equals(args[i])) { snmpVersion = SnmpConstants.version2c; } else { throw new IllegalArgumentException("Specified SNMP version is invalid..."); } } if ("-a".equals(args[i])) { i++; if (!isValidIpv4Addr(args[i])) { throw new IllegalArgumentException("Specified agent address is invalid..."); } agentAddr = args[i]; } if ("-o".equals(args[i])) { i++; if (!isValidOid(args[i])) { throw new IllegalArgumentException("Specified trap oid is invalid..."); } trapOid = args[i]; } if ("-e".equals(args[i])) { i++; if (!isValidOid(args[i])) { throw new IllegalArgumentException("Specified enterprise id is invalid..."); } enterpriseId = args[i]; } else{ destAddr = args[i]; } } if(destAddr == null) { throw new IllegalArgumentException("Trap dest is not specified..."); } } private boolean isValidIpv4Addr(String addrStr) { String[] octets = addrStr.split("\\."); if (octets.length != 4) { return false; } for (String octet : octets) { int octetNum; try { octetNum = Integer.parseInt(octet); } catch (NumberFormatException ex) { return false; } if (octetNum < 0 || 255 < octetNum) { return false; } } return true; } private boolean isValidOid(String oidStr) { final int SUB_ID_CNT_MAX = 128; final double SUB_ID_MAX = Math.pow(2,32)-1; if (oidStr.startsWith(".")) { oidStr = oidStr.substring(1); } String[] subIds = oidStr.split("\\."); if (SUB_ID_CNT_MAX < subIds.length) { return false; } for (int i=0; i<subIds.length; i++) { int subIdNum; try { subIdNum = Integer.parseInt(subIds[i]); } catch (NumberFormatException ex) { return false; } if (i == 0) { if (subIdNum != 0 && subIdNum != 1 && subIdNum != 2) { return false; } } if (subIdNum < 0 || SUB_ID_MAX < subIdNum) { return false; } } return true; } public static void main(String[] args) { TrapSender trapsender = new TrapSender(); try { trapsender.setParams(args); trapsender.sendTrap(); } catch (IOException ex) { System.err.println("Exception happened while sending an snmp trap..."); System.err.println(ex.getMessage()); ex.printStackTrace(); System.exit(1); } catch (Exception ex) { System.err.println(ex.getMessage()); ex.printStackTrace(); System.exit(1); } } }
上記で送信したSNMPトラップをwiresharkで見て、意図した内容になっていたので問題ないはず。
現時点では、トラップに含まれるvarbindなど、ハードコードしている部分もあるので、今後はそれらも引数で変更できるようエンハンスしたい。