// // This file is part of the OpenNMS(R) Application. // // OpenNMS(R) is Copyright (C) 2005 The OpenNMS Group, Inc. All rights reserved. // OpenNMS(R) is a derivative work, containing both original code, included code and modified // code that was published under the GNU General Public License. Copyrights for modified // and included code are below. // // OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. // // Modifications: // // 2008 Dec 29: Code and comment formatting, remove some obvious comments, // and make the logic in processVarBindAt a little more clear. // - dj@opennms.org // // Original code base Copyright (C) 1999-2001 Oculan Corp. All rights reserved. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // For more information contact: // OpenNMS Licensing <license@opennms.org> // http://www.opennms.org/ // http://www.opennms.com/ // package org.infosec.ismp.snmp.snmp4j; import java.net.InetAddress; import org.infosec.ismp.snmp.SnmpObjId; import org.infosec.ismp.snmp.SnmpValue; import org.infosec.ismp.snmp.TrapIdentity; import org.infosec.ismp.snmp.TrapInformation; import org.infosec.ismp.snmp.TrapNotificationListener; import org.infosec.ismp.snmp.TrapProcessor; import org.infosec.ismp.snmp.TrapProcessorFactory; import org.infosec.ismp.util.ThreadCategory; import org.snmp4j.CommandResponder; import org.snmp4j.CommandResponderEvent; import org.snmp4j.MessageException; import org.snmp4j.PDU; import org.snmp4j.PDUv1; import org.snmp4j.mp.StateReference; import org.snmp4j.mp.StatusInformation; import org.snmp4j.smi.Integer32; import org.snmp4j.smi.IpAddress; import org.snmp4j.smi.OID; import org.snmp4j.smi.SMIConstants; import org.snmp4j.smi.TimeTicks; import org.snmp4j.smi.Variable; import org.snmp4j.smi.VariableBinding; public class Snmp4JTrapNotifier implements CommandResponder { private final TrapProcessorFactory m_trapProcessorFactory; private final TrapNotificationListener m_listener; public Snmp4JTrapNotifier(TrapNotificationListener listener, TrapProcessorFactory processorFactory) { m_listener = listener; m_trapProcessorFactory = processorFactory; } public static class Snmp4JV1TrapInformation extends TrapInformation { private final PDUv1 m_pdu; protected Snmp4JV1TrapInformation(InetAddress agent, String community, PDUv1 pdu, TrapProcessor trapProcessor) { super(agent, community, trapProcessor); m_pdu = pdu; } @Override protected InetAddress getTrapAddress() { return m_pdu.getAgentAddress().getInetAddress(); } @Override protected String getVersion() { return "v1"; } @Override protected int getPduLength() { return m_pdu.getVariableBindings().size(); } @Override protected long getTimeStamp() { return m_pdu.getTimestamp(); } @Override protected TrapIdentity getTrapIdentity() { return new TrapIdentity(SnmpObjId.get(m_pdu.getEnterprise() .getValue()), m_pdu.getGenericTrap(), m_pdu.getSpecificTrap()); } protected VariableBinding getVarBindAt(int i) { return m_pdu.get(i); } @Override protected void processVarBindAt(int i) { SnmpObjId name = SnmpObjId.get(getVarBindAt(i).getOid().getValue()); SnmpValue value = new Snmp4JValue(getVarBindAt(i).getVariable()); processVarBind(name, value); } } public static class Snmp4JV2TrapInformation extends TrapInformation { /** * The received PDU */ private final PDU m_pdu; /** * The name of the PDU's type */ private final String m_pduTypeString; /** * The snmp sysUpTime OID is the first varbind */ static final int SNMP_SYSUPTIME_OID_INDEX = 0; /** * The snmp trap OID is the second varbind */ static final int SNMP_TRAP_OID_INDEX = 1; /** * The sysUpTimeOID, which should be the first varbind in a V2 trap */ static final OID SNMP_SYSUPTIME_OID = new OID(".1.3.6.1.2.1.1.3.0"); /** * The sysUpTimeOID, which should be the first varbind in a V2 trap, but in * the case of Extreme Networks only mostly */ static final OID EXTREME_SNMP_SYSUPTIME_OID = new OID( ".1.3.6.1.2.1.1.3"); /** * The snmpTrapOID, which should be the second varbind in a V2 trap */ static final OID SNMP_TRAP_OID = new OID(".1.3.6.1.6.3.1.1.4.1.0"); /** * Constructs a new trap information instance that contains the sending * agent, the community string, and the Protocol Data Unit. * * @param agent * The sending agent's address * @param community * The community string from the SNMP packet. * @param pdu * The encapsulated Protocol Data Unit. * @param trapProcessor The trap processor used to process the trap data * */ public Snmp4JV2TrapInformation(InetAddress agent, String community, PDU pdu, TrapProcessor trapProcessor) { super(agent, community, trapProcessor); m_pdu = pdu; m_pduTypeString = PDU.getTypeString(m_pdu.getType()); } /** * Returns the Protocol Data Unit that was encapsulated within the SNMP * Trap message */ private PDU getPdu() { return m_pdu; } @Override protected int getPduLength() { return getPdu().size(); } @Override protected long getTimeStamp() { if (log().isDebugEnabled()) { log().debug( "V2 " + m_pduTypeString + " first varbind value: " + getVarBindAt(0).getVariable().toString()); } switch (getVarBindAt(SNMP_SYSUPTIME_OID_INDEX).getVariable() .getSyntax()) { case SMIConstants.SYNTAX_TIMETICKS: log().debug( "V2 " + m_pduTypeString + " first varbind value is of type TIMETICKS (correct)"); return ((TimeTicks) getVarBindAt(SNMP_SYSUPTIME_OID_INDEX) .getVariable()).getValue(); case SMIConstants.SYNTAX_INTEGER32: log().debug( "V2 " + m_pduTypeString + " first varbind value is of type INTEGER, casting to TIMETICKS"); return ((Integer32) getVarBindAt(SNMP_SYSUPTIME_OID_INDEX) .getVariable()).getValue(); default: throw new IllegalArgumentException( "V2 " + m_pduTypeString + " does not have the required first varbind as TIMETICKS - cannot process " + m_pduTypeString); } } @Override protected TrapIdentity getTrapIdentity() { OID snmpTrapOid = (OID) getVarBindAt(SNMP_TRAP_OID_INDEX) .getVariable(); OID lastVarBindOid = getVarBindAt(getPduLength() - 1).getOid(); Variable lastVarBindValue = getVarBindAt(getPduLength() - 1) .getVariable(); return new TrapIdentity(SnmpObjId.get(snmpTrapOid.getValue()), SnmpObjId.get(lastVarBindOid.getValue()), new Snmp4JValue( lastVarBindValue)); } @Override public InetAddress getTrapAddress() { return getAgentAddress(); } protected VariableBinding getVarBindAt(int index) { return getPdu().get(index); } @Override protected String getVersion() { return "v2"; } @Override protected void validate() { int pduType = getPdu().getType(); if (pduType != PDU.TRAP && pduType != PDU.INFORM) { throw new IllegalArgumentException( "Received not SNMPv2 Trap|Inform from host " + getTrapAddress() + " PDU Type = " + PDU.getTypeString(getPdu().getType())); } if (log().isDebugEnabled()) { log().debug( "V2 " + m_pduTypeString + " numVars or pdu length: " + getPduLength()); } if (getPduLength() < 2) { throw new IllegalArgumentException( "V2 " + m_pduTypeString + " from " + getTrapAddress() + " IGNORED due to not having the required varbinds. Have " + getPduLength() + ", needed at least 2"); } OID varBindName0 = getVarBindAt(0).getOid(); OID varBindName1 = getVarBindAt(1).getOid(); /* * Modify the sysUpTime varbind OID to add the trailing 0 if it is * missing, which is seen with some Extreme equipment. */ if (varBindName0.equals(EXTREME_SNMP_SYSUPTIME_OID)) { log().info( "V2 " + m_pduTypeString + " from " + getTrapAddress() + " has been corrected due to the sysUptime.0 varbind not having been sent with a trailing 0.\n\tVarbinds received are : " + varBindName0 + " and " + varBindName1); varBindName0 = SNMP_SYSUPTIME_OID; } /* * Confirm that the two required varbinds (sysUpTime and * snmpTrapOID) are present and in that order. */ if ((!(varBindName0.equals(SNMP_SYSUPTIME_OID))) || (!(varBindName1.equals(SNMP_TRAP_OID)))) { throw new IllegalArgumentException( "V2 " + m_pduTypeString + " from " + getTrapAddress() + " IGNORED due to not having the required varbinds.\n\tThe first varbind must be sysUpTime.0 and the second snmpTrapOID.0\n\tVarbinds received are : " + varBindName0 + " and " + varBindName1); } } @Override protected void processVarBindAt(int i) { if (i == 0) { log().debug( "Skipping processing of varbind " + i + ": it is sysuptime and the first varbind, and is not processed as a parm per RFC2089"); } else if (i == 1) { log().debug( "Skipping processing of varbind " + i + ": it is the trap OID and the second varbind, and is not processed as a parm per RFC2089"); } else { SnmpObjId name = SnmpObjId.get(getVarBindAt(i).getOid() .getValue()); SnmpValue value = new Snmp4JValue(getVarBindAt(i).getVariable()); processVarBind(name, value); } } } @Override public void processPdu(CommandResponderEvent e) { PDU command = new PDU(e.getPDU()); IpAddress addr = ((IpAddress) e.getPeerAddress()); if (command != null) { if (command.getType() == PDU.INFORM) { PDU response = new PDU(command); response.setErrorIndex(0); response.setErrorStatus(0); response.setType(PDU.RESPONSE); StatusInformation statusInformation = new StatusInformation(); StateReference ref = e.getStateReference(); try { e.getMessageDispatcher().returnResponsePdu( e.getMessageProcessingModel(), e.getSecurityModel(), e.getSecurityName(), e.getSecurityLevel(), response, e.getMaxSizeResponsePDU(), ref, statusInformation); if (log().isDebugEnabled()) { log().debug( "Sent RESPONSE PDU to peer " + addr + " acknowledging receipt of INFORM (reqId=" + command.getRequestID() + ")"); } } catch (MessageException ex) { log().error( "Error while sending RESPONSE PDU to peer " + addr + ": " + ex.getMessage() + "acknowledging receipt of INFORM (reqId=" + command.getRequestID() + ")"); } } } if (e.getPDU() instanceof PDUv1) { m_listener.trapReceived(new Snmp4JV1TrapInformation(addr .getInetAddress(), new String(e.getSecurityName()), (PDUv1) e.getPDU(), m_trapProcessorFactory .createTrapProcessor())); } else { m_listener.trapReceived(new Snmp4JV2TrapInformation(addr .getInetAddress(), new String(e.getSecurityName()), e .getPDU(), m_trapProcessorFactory.createTrapProcessor())); } } private ThreadCategory log() { return ThreadCategory.getInstance(getClass()); } }