/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2011 The OpenNMS Group, Inc.
* OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc.
*
* OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
*
* OpenNMS(R) 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 3 of the License,
* or (at your option) any later version.
*
* OpenNMS(R) 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 OpenNMS(R). If not, see:
* http://www.gnu.org/licenses/
*
* For more information contact:
* OpenNMS(R) Licensing <license@opennms.org>
* http://www.opennms.org/
* http://www.opennms.com/
*******************************************************************************/
package org.opennms.netmgt.snmp.snmp4j;
import java.io.IOException;
import java.net.InetAddress;
import org.opennms.netmgt.snmp.SnmpAgentConfig;
import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.ScopedPDU;
import org.snmp4j.Snmp;
import org.snmp4j.Target;
import org.snmp4j.TransportMapping;
import org.snmp4j.UserTarget;
import org.snmp4j.mp.MPv3;
import org.snmp4j.mp.MessageProcessingModel;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.security.AuthMD5;
import org.snmp4j.security.AuthSHA;
import org.snmp4j.security.PrivAES128;
import org.snmp4j.security.PrivAES192;
import org.snmp4j.security.PrivAES256;
import org.snmp4j.security.PrivDES;
import org.snmp4j.security.SecurityLevel;
import org.snmp4j.security.SecurityProtocols;
import org.snmp4j.security.USM;
import org.snmp4j.security.UsmUser;
import org.snmp4j.smi.Address;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.UdpAddress;
import org.snmp4j.transport.DefaultUdpTransportMapping;
public class Snmp4JAgentConfig {
private SnmpAgentConfig m_config;
public Snmp4JAgentConfig(SnmpAgentConfig config) {
m_config = config;
}
public InetAddress getInetAddress() {
return m_config.getAddress();
}
public OctetString getAuthPassPhrase() {
return createOctetString(m_config.getAuthPassPhrase());
}
public OID getAuthProtocol() {
return convertAuthProtocol(m_config.getAuthProtocol());
}
public int getMaxRequestSize() {
return m_config.getMaxRequestSize();
}
public int getMaxVarsPerPdu() {
return m_config.getMaxVarsPerPdu();
}
public int getMaxRepetitions() {
return m_config.getMaxRepetitions();
}
public int getPort() {
return m_config.getPort();
}
public int getRetries() {
return m_config.getRetries();
}
public int getSecurityLevel() {
return convertSecurityLevel(m_config.getSecurityLevel());
}
public OctetString getSecurityName() {
return convertSecurityName(m_config.getSecurityName());
}
public int getTimeout() {
return m_config.getTimeout();
}
public int getVersion() {
return convertVersion(m_config.getVersion());
}
/**
* Returns a string representation of the SNMP4J version constant
* @param version
* @return
*/
public String getVersionString() {
switch (getVersion()) {
case SnmpConstants.version1:
return "SNMPv1";
case SnmpConstants.version2c:
return "SNMPv2c";
case SnmpConstants.version3:
return "SNMPv3";
default:
return "unknown: " + getVersion();
}
}
public String getWriteCommunity() {
return m_config.getWriteCommunity();
}
public String toString() {
return m_config.toString();
}
/**
* This method converts an InetAddress to an implementation of an SNMP4J Address
* (UdpAddress or TcpAddress)
*
* TODO: This needs to be updated when the protocol flag is added to the SNMP Config
* so that UDP or TCP can be used in v3 operations.
*/
private Address convertAddress(InetAddress address, int port) {
String transportAddress = address.getHostAddress();
transportAddress += "/" + port;
Address targetAddress = new UdpAddress(transportAddress);
return targetAddress;
}
/**
* This method adapts the OpenNMS SNMP version constants
* to SNMP4J defined constants.
*
* @param version
* @return
*/
private int convertVersion(int version) {
switch (version) {
case SnmpAgentConfig.VERSION3:
return SnmpConstants.version3;
case SnmpAgentConfig.VERSION2C:
return SnmpConstants.version2c;
default:
return SnmpConstants.version1;
}
}
private OctetString createOctetString(String s) {
if (s == null) {
return null;
}
OctetString octetString;
if (s.startsWith("0x")) {
octetString = OctetString.fromHexString(s.substring(2), ':');
} else {
octetString = new OctetString(s);
}
return octetString;
}
/**
* Adapts the OpenNMS SNMPv3 security name to an SNMP4J compatible
* security name (String -> OctetString)
*
* @param securityName
* @return
*/
private OctetString convertSecurityName(String securityName) {
return new OctetString(securityName);
}
private OID convertPrivProtocol(String privProtocol) {
/*
* Returning null here is okay because the SNMP4J library supports
* this value as null when creating the SNMP session.
*/
if (privProtocol == null) {
return null;
}
if (privProtocol.equals("DES")) {
return PrivDES.ID;
} else if ((privProtocol.equals("AES128")) || (privProtocol.equals("AES"))) {
return PrivAES128.ID;
} else if (privProtocol.equals("AES192")) {
return PrivAES192.ID;
} else if (privProtocol.equals("AES256")) {
return PrivAES256.ID;
} else {
throw new IllegalArgumentException("Privacy protocol " + privProtocol + " not supported");
}
}
/**
* Adapts the OpenNMS SNMPv3 community name to an SNMP4J compatible
* community name (String -> OctetString)
*
* @param agentConfig
* @return
*/
private OctetString convertCommunity(String community) {
return new OctetString(community);
}
private OID convertAuthProtocol(String authProtocol) {
/*
* Returning null here is okay because the SNMP4J library supports
* this value as null when creating the SNMP session.
*/
if (authProtocol == null) {
return null;
}
if (authProtocol.equals("MD5")) {
return AuthMD5.ID;
} else if (authProtocol.equals("SHA")) {
return AuthSHA.ID;
} else {
throw new IllegalArgumentException("Authentication protocol unsupported: " + authProtocol);
}
}
protected Target getTarget() {
Target target = createTarget();
target.setVersion(getVersion());
target.setRetries(getRetries());
target.setTimeout(getTimeout());
target.setAddress(getAddress());
target.setMaxSizeRequestPDU(getMaxRequestSize());
return target;
}
private Target createTarget() {
return (isSnmpV3() ? createUserTarget() : createCommunityTarget());
}
boolean isSnmpV3() {
return m_config.getVersion() == SnmpConstants.version3;
}
private Target createCommunityTarget() {
CommunityTarget target = new CommunityTarget();
target.setCommunity(getReadCommunity());
return target;
}
private Target createUserTarget() {
UserTarget target = new UserTarget();
target.setSecurityLevel(getSecurityLevel());
target.setSecurityName(getSecurityName());
return target;
}
private OctetString getReadCommunity() {
return convertCommunity(m_config.getReadCommunity());
}
private Address getAddress() {
return convertAddress(getInetAddress(), getPort());
}
public OID getPrivProtocol() {
return convertPrivProtocol(m_config.getPrivProtocol());
}
public OctetString getPrivPassPhrase() {
return createOctetString(m_config.getPrivPassPhrase());
}
/**
* This method adapts the OpenNMS SNMPv3 security level constants
* to SNMP4J defined constants.
*
* @param securityLevel
* @return
*/
private int convertSecurityLevel(int securityLevel) {
switch (securityLevel) {
case SnmpAgentConfig.AUTH_NOPRIV :
securityLevel = SecurityLevel.AUTH_NOPRIV;
break;
case SnmpAgentConfig.AUTH_PRIV :
securityLevel = SecurityLevel.AUTH_PRIV;
break;
case SnmpAgentConfig.NOAUTH_NOPRIV :
securityLevel = SecurityLevel.NOAUTH_NOPRIV;
break;
default :
securityLevel = SecurityLevel.NOAUTH_NOPRIV;
}
return securityLevel;
}
public Snmp createSnmpSession() throws IOException {
TransportMapping transport = new DefaultUdpTransportMapping();
Snmp session = new Snmp(transport);
if (isSnmpV3()) {
// Make a new USM
USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0);
// Add the specified user to the USM
usm.addUser(
getSecurityName(),
new UsmUser(
getSecurityName(),
getAuthProtocol(),
getAuthPassPhrase(),
getPrivProtocol(),
getPrivPassPhrase()
)
);
// Remove the old SNMPv3 MessageProcessingModel. If you don't do this, you'll end up with
// two SNMPv3 MessageProcessingModel instances in the dispatcher and connections will fail.
MessageProcessingModel oldModel = session.getMessageDispatcher().getMessageProcessingModel(MessageProcessingModel.MPv3);
if (oldModel != null) {
session.getMessageDispatcher().removeMessageProcessingModel(oldModel);
}
// Add a new SNMPv3 MessageProcessingModel with the newly-created USM
session.getMessageDispatcher().addMessageProcessingModel(new MPv3(usm));
}
return session;
}
/**
* Creates an SNMP4J PDU based on the SNMP4J version constants.
* A v3 request requires a ScopedPDU.
*
* @param type
* @return
*/
public PDU createPdu(int type) {
PDU pdu = getVersion() == SnmpConstants.version3 ? new ScopedPDU() : new PDU();
pdu.setType(type);
return pdu;
}
}