/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.synapse.commons.snmp; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.snmp4j.TransportMapping; import org.snmp4j.agent.BaseAgent; import org.snmp4j.agent.CommandProcessor; import org.snmp4j.agent.DuplicateRegistrationException; import org.snmp4j.agent.ManagedObject; import org.snmp4j.agent.io.ImportModes; import org.snmp4j.agent.mo.MOTableRow; import org.snmp4j.agent.mo.snmp.*; import org.snmp4j.agent.security.MutableVACM; import org.snmp4j.log.Log4jLogFactory; import org.snmp4j.mp.MPv3; import org.snmp4j.mp.SnmpConstants; import org.snmp4j.security.*; import org.snmp4j.smi.*; import org.snmp4j.transport.TransportMappings; import javax.management.*; import java.io.File; import java.io.IOException; import java.lang.management.ManagementFactory; import java.net.BindException; import java.util.*; /** * SNMP agent which is capable of listening for incoming SNMP GET/GETNEXT requests * and responding to them accordingly. This agent implementation exposed all the * standard Synapse MBeans over SNMP. The view exposed by the agent is read-only as of * now (this may be changed in a future version). The relevant OID mappings are * defined in the SynapseMIBUtils class. Each MBean attribute becomes a leaf in the MIB * exposed by the agent. For each MBean, attributes are arranged in the alphabetical * order for OID assignment. MBean APIs rarely change. Therefore this scheme will * guarantee a fairly consistent OID scheme. */ class SNMPAgent extends BaseAgent { private static final Log log = LogFactory.getLog(SNMPAgent.class); private static final String FULL_READ_VIEW = "fullReadView"; private static final String GROUP_NAME = "synapseSNMPGroup"; private static final String COMMUNITY_RECORD = "public2public"; private Properties properties; private Set<OID> registeredOIDs = new HashSet<OID>(); private int snmpVersion; // initialize Log4J logging static { org.snmp4j.log.LogFactory.setLogFactory(new Log4jLogFactory()); } public SNMPAgent(Properties properties) { super(new File(SNMPConstants.BC_FILE), new File(SNMPConstants.CONFIG_FILE), new CommandProcessor(new OctetString(MPv3.createLocalEngineID()))); this.properties = properties; String version = getProperty(SNMPConstants.SNMP_VERSION, SNMPConstants.SNMP_DEFAULT_VERSION); if (SNMPConstants.SNMP_VERSION_1.equals(version)) { this.snmpVersion = SnmpConstants.version1; } else if (SNMPConstants.SNMP_VERSION_2_C.equals(version)) { this.snmpVersion = SnmpConstants.version2c; } else { log.warn("Unsupported SNMP version: " + version + " - Using defaults"); this.snmpVersion = SnmpConstants.version1; } // Override the default sysOID and set the WSO2 OID... this.sysOID = new OID(SNMPConstants.SYNAPSE_OID_BRANCH); setSysDescr(new OctetString(getProperty(SNMPConstants.SNMP_DESCRIPTION, SNMPConstants.SNMP_DEFAULT_DESCRIPTION))); } @Override protected void registerSnmpMIBs() { this.snmpv2MIB.setContact(new OctetString(getProperty(SNMPConstants.SNMP_CONTACT_NAME, SNMPConstants.SNMP_DEFAULT_CONTACT_NAME))); this.snmpv2MIB.setLocation(new OctetString(getProperty(SNMPConstants.SNMP_LOCATION, SNMPConstants.SNMP_DEFAULT_LOCATION))); this.snmpv2MIB.setName(new OctetString(getProperty(SNMPConstants.SNMP_HOST, SNMPConstants.SNMP_DEFAULT_HOST))); super.registerSnmpMIBs(); } /** * Initialize and start this SNMP agent * * @throws IOException If an error occurs while initializing the agent */ public void start() throws IOException { String context = getProperty(SNMPConstants.SNMP_CONTEXT_NAME, SNMPConstants.SNMP_DEFAULT_CONTEXT_NAME); try{ init(); } catch (Exception e) { if (e.getCause() != null && e.getCause() instanceof BindException) { log.info("SNMP agent is already running, not initializing again"); } else { log.error("Unable to initialize SNMP agent", e); } } loadConfig(ImportModes.REPLACE_CREATE); addShutdownHook(); getServer().addContext(new OctetString(context)); finishInit(); run(); sendColdStartNotification(); } @Override protected void initTransportMappings() throws IOException { String host = getProperty(SNMPConstants.SNMP_HOST, SNMPConstants.SNMP_DEFAULT_HOST); int port = Integer.parseInt(getProperty(SNMPConstants.SNMP_PORT, String.valueOf(SNMPConstants.SNMP_DEFAULT_PORT))); String address = host + "/" + port; Address adr = GenericAddress.parse(address); TransportMapping tm = TransportMappings.getInstance().createTransportMapping(adr); transportMappings = new TransportMapping[] { tm }; log.info("SNMP transport adapter initialized on udp:" + address); } @Override protected void registerManagedObjects() { log.info("Initializing Synapse SNMP MIB"); MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); Set<ObjectInstance> instances = mbs.queryMBeans(null, null); try { for (ObjectInstance instance : instances) { ObjectName objectName = instance.getObjectName(); if (objectName.getDomain().equals("org.apache.synapse")) { String oidString = SynapseMIBUtils.getOID(objectName); if (oidString == null) { continue; } MBeanInfo info = mbs.getMBeanInfo(objectName); MBeanAttributeInfo[] attributes = info.getAttributes(); List<String> attributeNames = new ArrayList<String>(); List<String> mapAttributes = new ArrayList<String>(); for (MBeanAttributeInfo attributeInfo : attributes) { attributeNames.add(attributeInfo.getName()); if (Map.class.getName().equals(attributeInfo.getType())) { mapAttributes.add(attributeInfo.getName()); } } Collections.sort(attributeNames); doRegister(attributeNames, mapAttributes, oidString, objectName); } } } catch (Exception e) { log.error("Error while initializing the SNMP MIB", e); } } private void doRegister(List<String> attributeNames, List<String> mapAttributes, String oidString, ObjectName objectName) { for (int i = 0; i < attributeNames.size(); i++) { String attributeName = attributeNames.get(i); if (mapAttributes.contains(attributeName)) { continue; } OID oid = new OID(oidString + "." + (i + 1) + ".0"); if (log.isDebugEnabled()) { log.debug("Registering " + objectName + "@" + attributeName + " as OID: " + oid); } try { server.register(new SynapseMOScalar( oid, objectName, attributeName, snmpVersion), null); registeredOIDs.add(oid); } catch (DuplicateRegistrationException e) { log.error("Error while registering the OID: " + oid + " for object: " + objectName + " and attribute: " + attributeName, e); } } } @Override protected void unregisterManagedObjects() { if (log.isDebugEnabled()) { log.debug("Cleaning up registered OIDs"); } for (OID oid : registeredOIDs) { ManagedObject mo = server.getManagedObject(oid, null); if (mo != null) { server.unregister(mo, null); } } registeredOIDs.clear(); } @Override protected void addUsmUser(USM usm) { } @Override protected void addNotificationTargets(SnmpTargetMIB snmpTargetMIB, SnmpNotificationMIB snmpNotificationMIB) { } @Override protected void addViews(VacmMIB vacm) { String communityString = getProperty(SNMPConstants.SNMP_COMMUNITY_NAME, SNMPConstants.SNMP_DEFAULT_COMMUNITY_NAME); String securityName = getProperty(SNMPConstants.SNMP_SECURITY_NAME, SNMPConstants.SNMP_DEFAULT_SECURITY_NAME); int securityModel = SecurityModel.SECURITY_MODEL_SNMPv1; if (snmpVersion == SnmpConstants.version2c) { securityModel = SecurityModel.SECURITY_MODEL_SNMPv2c; } vacm.addGroup(securityModel, new OctetString(securityName), new OctetString(GROUP_NAME), StorageType.nonVolatile); vacm.addAccess(new OctetString(GROUP_NAME), new OctetString(communityString), securityModel, SecurityLevel.NOAUTH_NOPRIV, MutableVACM.VACM_MATCH_EXACT, new OctetString(FULL_READ_VIEW), // read permission granted new OctetString(), // no write permissions new OctetString(), // no notify permissions StorageType.nonVolatile); vacm.addViewTreeFamily(new OctetString(FULL_READ_VIEW), new OID(SNMPConstants.SYNAPSE_OID_BRANCH), new OctetString(), VacmMIB.vacmViewIncluded, StorageType.nonVolatile); vacm.addViewTreeFamily(new OctetString(FULL_READ_VIEW), new OID("1.3.6"), new OctetString(), VacmMIB.vacmViewIncluded, StorageType.nonVolatile); vacm.addViewTreeFamily(new OctetString(FULL_READ_VIEW), new OID("1.3.6.1.2.1.1"), new OctetString(), VacmMIB.vacmViewIncluded, StorageType.nonVolatile); } @Override protected void addCommunities(SnmpCommunityMIB communityMIB) { String community = getProperty(SNMPConstants.SNMP_COMMUNITY_NAME, SNMPConstants.SNMP_DEFAULT_COMMUNITY_NAME); String securityName = getProperty(SNMPConstants.SNMP_SECURITY_NAME, SNMPConstants.SNMP_DEFAULT_SECURITY_NAME); String context = getProperty(SNMPConstants.SNMP_CONTEXT_NAME, SNMPConstants.SNMP_DEFAULT_CONTEXT_NAME); if (log.isDebugEnabled()) { log.debug("Registering SNMP community string: " + community + " under the " + "context: " + context); } Variable[] com2sec = new Variable[] { new OctetString(community), // community name new OctetString(securityName), // security name getAgent().getContextEngineID(), // local engine ID new OctetString(context), // default context name new OctetString(), // transport tag new Integer32(StorageType.nonVolatile), // storage type new Integer32(RowStatus.active) // row status }; MOTableRow row = communityMIB.getSnmpCommunityEntry().createRow( new OctetString(COMMUNITY_RECORD).toSubIndex(true), com2sec); communityMIB.getSnmpCommunityEntry().addRow(row); } private String getProperty(String name, String def) { String value = properties.getProperty(name); if (value == null) { value = def; } return value; } }