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 {
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 {
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);
CommunityTarget target = createTarget(commName, SnmpConstants.version1, destAddr, destPort);
System.out.println("Sending an SNMPv1 trap to " + destAddr + " ...");
sendPdu(trapPdu, target);
}
void sendV2cTrap () throws IOException {
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);
CommunityTarget target = createTarget(commName, SnmpConstants.version2c, destAddr, destPort);
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など、ハードコードしている部分もあるので、今後はそれらも引数で変更できるようエンハンスしたい。