/* * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.jmx.snmp.daemon; // java import // import java.util.Vector; import java.util.Enumeration; import java.util.Hashtable; import java.util.logging.Level; import java.io.InterruptedIOException; import java.net.DatagramSocket; import java.net.DatagramPacket; import java.net.SocketException; // jmx imports // import javax.management.MBeanServer; import javax.management.ObjectName; import com.sun.jmx.snmp.SnmpMessage; import com.sun.jmx.snmp.SnmpPduFactory; import com.sun.jmx.snmp.SnmpPduBulk; import com.sun.jmx.snmp.SnmpPduPacket; import com.sun.jmx.snmp.SnmpPduRequest; import com.sun.jmx.snmp.SnmpPduTrap; import com.sun.jmx.snmp.SnmpValue; import com.sun.jmx.snmp.SnmpVarBind; import com.sun.jmx.snmp.SnmpVarBindList; import com.sun.jmx.snmp.SnmpDefinitions; import com.sun.jmx.snmp.SnmpStatusException; import com.sun.jmx.snmp.SnmpTooBigException; import com.sun.jmx.snmp.SnmpDataTypeEnums; // RI imports // import static com.sun.jmx.defaults.JmxProperties.SNMP_ADAPTOR_LOGGER; // SNMP runtime import // import com.sun.jmx.snmp.agent.SnmpMibAgent; import com.sun.jmx.snmp.agent.SnmpUserDataFactory; //import com.sun.jmx.snmp.IPAcl.IPAcl; import com.sun.jmx.snmp.InetAddressAcl; class SnmpRequestHandler extends ClientHandler implements SnmpDefinitions { private transient DatagramSocket socket = null ; private transient DatagramPacket packet = null ; private transient Vector mibs = null ; /** * Contains the list of sub-requests associated to the current request. */ private transient Hashtable<SnmpMibAgent, SnmpSubRequestHandler> subs = null; /** * Reference on the MIBS */ private transient SnmpMibTree root; private transient Object ipacl = null ; private transient SnmpPduFactory pduFactory = null ; private transient SnmpUserDataFactory userDataFactory = null ; private transient SnmpAdaptorServer adaptor = null; /** * Full constructor */ public SnmpRequestHandler(SnmpAdaptorServer server, int id, DatagramSocket s, DatagramPacket p, SnmpMibTree tree, Vector m, Object a, SnmpPduFactory factory, SnmpUserDataFactory dataFactory, MBeanServer f, ObjectName n) { super(server, id, f, n); // Need a reference on SnmpAdaptorServer for getNext & getBulk, // in case of oid equality (mib overlapping). // adaptor = server; socket = s; packet = p; root= tree; mibs = (Vector) m.clone(); subs= new Hashtable<SnmpMibAgent, SnmpSubRequestHandler>(mibs.size()); ipacl = a; pduFactory = factory ; userDataFactory = dataFactory ; //thread.start(); } /** * Treat the request available in 'packet' and send the result * back to the client. * Note: we overwrite 'packet' with the response bytes. */ public void doRun() { // Trace the input packet // if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, "doRun","Packet received:\n" + SnmpMessage.dumpHexBuffer(packet.getData(), 0, packet.getLength())); } // Let's build the response packet // DatagramPacket respPacket = makeResponsePacket(packet) ; // Trace the output packet // if ((SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) && (respPacket != null)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, "doRun","Packet to be sent:\n" + SnmpMessage.dumpHexBuffer(respPacket.getData(), 0, respPacket.getLength())); } // Send the response packet if any // if (respPacket != null) { try { socket.send(respPacket) ; } catch (SocketException e) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { if (e.getMessage().equals(InterruptSysCallMsg)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "doRun", "interrupted"); } else { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "doRun", "I/O exception", e); } } } catch(InterruptedIOException e) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "doRun", "interrupted"); } } catch(Exception e) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "doRun", "failure when sending response", e); } } } } /** * Here we make a response packet from a request packet. * We return null if there no response packet to sent. */ private DatagramPacket makeResponsePacket(DatagramPacket reqPacket) { DatagramPacket respPacket = null ; // Transform the request packet into a request SnmpMessage // SnmpMessage reqMsg = new SnmpMessage() ; try { reqMsg.decodeMessage(reqPacket.getData(), reqPacket.getLength()) ; reqMsg.address = reqPacket.getAddress() ; reqMsg.port = reqPacket.getPort() ; } catch(SnmpStatusException x) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "makeResponsePacket", "packet decoding failed", x); } reqMsg = null ; ((SnmpAdaptorServer)adaptorServer).incSnmpInASNParseErrs(1) ; } // Make the response SnmpMessage if any // SnmpMessage respMsg = null ; if (reqMsg != null) { respMsg = makeResponseMessage(reqMsg) ; } // Try to transform the response SnmpMessage into response packet. // NOTE: we overwrite the request packet. // if (respMsg != null) { try { reqPacket.setLength(respMsg.encodeMessage(reqPacket.getData())) ; respPacket = reqPacket ; } catch(SnmpTooBigException x) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "makeResponsePacket", "response message is too big"); } try { respMsg = newTooBigMessage(reqMsg) ; reqPacket.setLength(respMsg.encodeMessage(reqPacket.getData())) ; respPacket = reqPacket ; } catch(SnmpTooBigException xx) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "makeResponsePacket", "'too big' is 'too big' !!!"); } adaptor.incSnmpSilentDrops(1); } } } return respPacket ; } /** * Here we make a response message from a request message. * We return null if there is no message to reply. */ private SnmpMessage makeResponseMessage(SnmpMessage reqMsg) { SnmpMessage respMsg = null ; // Transform the request message into a request pdu // SnmpPduPacket reqPdu = null ; Object userData = null; try { reqPdu = (SnmpPduPacket)pduFactory.decodeSnmpPdu(reqMsg) ; if (reqPdu != null && userDataFactory != null) userData = userDataFactory.allocateUserData(reqPdu); } catch(SnmpStatusException x) { reqPdu = null ; SnmpAdaptorServer snmpServer = (SnmpAdaptorServer)adaptorServer ; snmpServer.incSnmpInASNParseErrs(1) ; if (x.getStatus()== SnmpDefinitions.snmpWrongSnmpVersion) snmpServer.incSnmpInBadVersions(1) ; if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "makeResponseMessage", "message decoding failed", x); } } // Make the response pdu if any // SnmpPduPacket respPdu = null ; if (reqPdu != null) { respPdu = makeResponsePdu(reqPdu,userData) ; try { if (userDataFactory != null) userDataFactory.releaseUserData(userData,respPdu); } catch (SnmpStatusException x) { respPdu = null; } } // Try to transform the response pdu into a response message if any // if (respPdu != null) { try { respMsg = (SnmpMessage)pduFactory. encodeSnmpPdu(respPdu, packet.getData().length) ; } catch(SnmpStatusException x) { respMsg = null ; if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "makeResponseMessage", "failure when encoding the response message", x); } } catch(SnmpTooBigException x) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "makeResponseMessage", "response message is too big"); } try { // if the PDU is too small, why should we try to do // recovery ? // if (packet.getData().length <=32) throw x; int pos= x.getVarBindCount(); if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "makeResponseMessage", "fail on element" + pos); } int old= 0; while (true) { try { respPdu = reduceResponsePdu(reqPdu, respPdu, pos) ; respMsg = (SnmpMessage)pduFactory. encodeSnmpPdu(respPdu, packet.getData().length -32) ; break; } catch (SnmpTooBigException xx) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "makeResponseMessage", "response message is still too big"); } old= pos; pos= xx.getVarBindCount(); if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "makeResponseMessage","fail on element" + pos); } if (pos == old) { // we can not go any further in trying to // reduce the message ! // throw xx; } } }// end of loop } catch(SnmpStatusException xx) { respMsg = null ; if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "makeResponseMessage", "failure when encoding the response message", xx); } } catch(SnmpTooBigException xx) { try { respPdu = newTooBigPdu(reqPdu) ; respMsg = (SnmpMessage)pduFactory. encodeSnmpPdu(respPdu, packet.getData().length) ; } catch(SnmpTooBigException xxx) { respMsg = null ; if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "makeResponseMessage", "'too big' is 'too big' !!!"); } adaptor.incSnmpSilentDrops(1); } catch(Exception xxx) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "makeResponseMessage", "Got unexpected exception", xxx); } respMsg = null ; } } catch(Exception xx) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "makeResponseMessage", "Got unexpected exception", xx); } respMsg = null ; } } } return respMsg ; } /** * Here we make a response pdu from a request pdu. * We return null if there is no pdu to reply. */ private SnmpPduPacket makeResponsePdu(SnmpPduPacket reqPdu, Object userData) { SnmpAdaptorServer snmpServer = (SnmpAdaptorServer)adaptorServer ; SnmpPduPacket respPdu = null ; snmpServer.updateRequestCounters(reqPdu.type) ; if (reqPdu.varBindList != null) snmpServer.updateVarCounters(reqPdu.type, reqPdu.varBindList.length) ; if (checkPduType(reqPdu)) { respPdu = checkAcl(reqPdu) ; if (respPdu == null) { // reqPdu is accepted by ACLs if (mibs.size() < 1) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, "makeResponsePdu", "Request " + reqPdu.requestId + " received but no MIB registered."); } return makeNoMibErrorPdu((SnmpPduRequest)reqPdu, userData); } switch(reqPdu.type) { case SnmpPduPacket.pduGetRequestPdu: case SnmpPduPacket.pduGetNextRequestPdu: case SnmpPduPacket.pduSetRequestPdu: respPdu = makeGetSetResponsePdu((SnmpPduRequest)reqPdu, userData) ; break ; case SnmpPduPacket.pduGetBulkRequestPdu: respPdu = makeGetBulkResponsePdu((SnmpPduBulk)reqPdu, userData) ; break ; } } else { // reqPdu is rejected by ACLs // respPdu contains the error response to be sent. // We send this response only if authResEnabled is true. if (!snmpServer.getAuthRespEnabled()) { // No response should be sent respPdu = null ; } if (snmpServer.getAuthTrapEnabled()) { // A trap must be sent try { snmpServer.snmpV1Trap(SnmpPduTrap. trapAuthenticationFailure, 0, new SnmpVarBindList()) ; } catch(Exception x) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "makeResponsePdu", "Failure when sending authentication trap", x); } } } } } return respPdu ; } // // Generates a response packet, filling the values in the // varbindlist with one of endOfMibView, noSuchObject, noSuchInstance // according to the value of <code>status</code> // // @param statusTag should be one of: // <li>SnmpDataTypeEnums.errEndOfMibViewTag</li> // <li>SnmpDataTypeEnums.errNoSuchObjectTag</li> // <li>SnmpDataTypeEnums.errNoSuchInstanceTag</li> // SnmpPduPacket makeErrorVarbindPdu(SnmpPduPacket req, int statusTag) { final SnmpVarBind[] vblist = req.varBindList; final int length = vblist.length; switch (statusTag) { case SnmpDataTypeEnums.errEndOfMibViewTag: for (int i=0 ; i<length ; i++) vblist[i].value = SnmpVarBind.endOfMibView; break; case SnmpDataTypeEnums.errNoSuchObjectTag: for (int i=0 ; i<length ; i++) vblist[i].value = SnmpVarBind.noSuchObject; break; case SnmpDataTypeEnums.errNoSuchInstanceTag: for (int i=0 ; i<length ; i++) vblist[i].value = SnmpVarBind.noSuchInstance; break; default: return newErrorResponsePdu(req,snmpRspGenErr,1); } return newValidResponsePdu(req,vblist); } // Generates an appropriate response when no mib is registered in // the adaptor. // // <li>If the version is V1:</li> // <ul><li>Generates a NoSuchName error V1 response PDU</li></ul> // <li>If the version is V2:</li> // <ul><li>If the request is a GET, fills the varbind list with // NoSuchObject's</li> // <li>If the request is a GET-NEXT/GET-BULK, fills the varbind // list with EndOfMibView's</li> // <li>If the request is a SET, generates a NoAccess error V2 // response PDU</li> // </ul> // // SnmpPduPacket makeNoMibErrorPdu(SnmpPduRequest req, Object userData) { // There is no agent registered // if (req.version == SnmpDefinitions.snmpVersionOne) { // Version 1: => NoSuchName return newErrorResponsePdu(req,snmpRspNoSuchName,1); } else if (req.version == SnmpDefinitions.snmpVersionTwo) { // Version 2: => depends on PDU type switch (req.type) { case pduSetRequestPdu : case pduWalkRequest : // SET request => NoAccess return newErrorResponsePdu(req,snmpRspNoAccess,1); case pduGetRequestPdu : // GET request => NoSuchObject return makeErrorVarbindPdu(req,SnmpDataTypeEnums. errNoSuchObjectTag); case pduGetNextRequestPdu : case pduGetBulkRequestPdu : // GET-NEXT or GET-BULK => EndOfMibView return makeErrorVarbindPdu(req,SnmpDataTypeEnums. errEndOfMibViewTag); default: } } // Something wrong here: => snmpRspGenErr return newErrorResponsePdu(req,snmpRspGenErr,1); } /** * Here we make the response pdu from a get/set request pdu. * At this level, the result is never null. */ private SnmpPduPacket makeGetSetResponsePdu(SnmpPduRequest req, Object userData) { // Create the trhead group specific for handling sub-requests // associated to the current request. Use the invoke id // // Nice idea to use a thread group on a request basis. // However the impact on performance is terrible ! // theGroup= new ThreadGroup(thread.getThreadGroup(), // "request " + String.valueOf(req.requestId)); // Let's build the varBindList for the response pdu // if (req.varBindList == null) { // Good ! Let's make a full response pdu. // return newValidResponsePdu(req, null) ; } // First we need to split the request into subrequests // splitRequest(req); int nbSubRequest= subs.size(); if (nbSubRequest == 1) return turboProcessingGetSet(req,userData); // Execute all the subrequests resulting from the split of the // varbind list. // SnmpPduPacket result= executeSubRequest(req,userData); if (result != null) // It means that an error occured. The error is already // formatted by the executeSubRequest // method. return result; // So far so good. So we need to concatenate all the answers. // if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, "makeGetSetResponsePdu", "Build the unified response for request " + req.requestId); } return mergeResponses(req); } /** * The method runs all the sub-requests associated to the current * instance of SnmpRequestHandler. */ private SnmpPduPacket executeSubRequest(SnmpPduPacket req, Object userData) { int errorStatus = SnmpDefinitions.snmpRspNoError ; int nbSubRequest= subs.size(); int i=0; // If it's a set request, we must first check any varBind // if (req.type == pduSetRequestPdu) { i=0; for(Enumeration e= subs.elements(); e.hasMoreElements() ; i++) { // Indicate to the sub request that a check must be invoked ... // OK we should have defined out own tag for that ! // SnmpSubRequestHandler sub= (SnmpSubRequestHandler) e.nextElement(); sub.setUserData(userData); sub.type= pduWalkRequest; sub.run(); sub.type= pduSetRequestPdu; if (sub.getErrorStatus() != SnmpDefinitions.snmpRspNoError) { // No point to go any further. // if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "executeSubRequest", "an error occurs"); } return newErrorResponsePdu(req, errorStatus, sub.getErrorIndex() + 1) ; } } }// end processing check operation for a set PDU. // Let's start the sub-requests. // i=0; for(Enumeration e= subs.elements(); e.hasMoreElements() ;i++) { SnmpSubRequestHandler sub= (SnmpSubRequestHandler) e.nextElement(); /* NPCTE fix for bugId 4492741, esc 0, 16-August 2001 */ sub.setUserData(userData); /* end of NPCTE fix for bugId 4492741 */ sub.run(); if (sub.getErrorStatus() != SnmpDefinitions.snmpRspNoError) { // No point to go any further. // if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "executeSubRequest", "an error occurs"); } return newErrorResponsePdu(req, errorStatus, sub.getErrorIndex() + 1) ; } } // everything is ok // return null; } /** * Optimize when there is only one sub request */ private SnmpPduPacket turboProcessingGetSet(SnmpPduRequest req, Object userData) { int errorStatus = SnmpDefinitions.snmpRspNoError ; SnmpSubRequestHandler sub = subs.elements().nextElement(); sub.setUserData(userData); // Indicate to the sub request that a check must be invoked ... // OK we should have defined out own tag for that ! // if (req.type == SnmpDefinitions.pduSetRequestPdu) { sub.type= pduWalkRequest; sub.run(); sub.type= pduSetRequestPdu; // Check the error status. // errorStatus= sub.getErrorStatus(); if (errorStatus != SnmpDefinitions.snmpRspNoError) { // No point to go any further. // return newErrorResponsePdu(req, errorStatus, sub.getErrorIndex() + 1) ; } } // process the operation // sub.run(); errorStatus= sub.getErrorStatus(); if (errorStatus != SnmpDefinitions.snmpRspNoError) { // No point to go any further. // if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "turboProcessingGetSet", "an error occurs"); } int realIndex= sub.getErrorIndex() + 1; return newErrorResponsePdu(req, errorStatus, realIndex) ; } // So far so good. So we need to concatenate all the answers. // if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, "turboProcessingGetSet", "build the unified response for request " + req.requestId); } return mergeResponses(req); } /** * Here we make the response pdu for a bulk request. * At this level, the result is never null. */ private SnmpPduPacket makeGetBulkResponsePdu(SnmpPduBulk req, Object userData) { SnmpVarBind[] respVarBindList = null ; // RFC 1905, Section 4.2.3, p14 int L = req.varBindList.length ; int N = Math.max(Math.min(req.nonRepeaters, L), 0) ; int M = Math.max(req.maxRepetitions, 0) ; int R = L - N ; if (req.varBindList == null) { // Good ! Let's make a full response pdu. // return newValidResponsePdu(req, null) ; } // Split the request into subrequests. // splitBulkRequest(req, N, M, R); SnmpPduPacket result= executeSubRequest(req,userData); if (result != null) return result; respVarBindList= mergeBulkResponses(N + (M * R)); // Now we remove useless trailing endOfMibView. // int m2 ; // respVarBindList[m2] item and next are going to be removed int t = respVarBindList.length ; while ((t > N) && (respVarBindList[t-1]. value.equals(SnmpVarBind.endOfMibView))) { t-- ; } if (t == N) m2 = N + R ; else m2 = N + ((t -1 -N) / R + 2) * R ; // Trivial, of course... if (m2 < respVarBindList.length) { SnmpVarBind[] truncatedList = new SnmpVarBind[m2] ; for (int i = 0 ; i < m2 ; i++) { truncatedList[i] = respVarBindList[i] ; } respVarBindList = truncatedList ; } // Good ! Let's make a full response pdu. // return newValidResponsePdu(req, respVarBindList) ; } /** * Check the type of the pdu: only the get/set/bulk request * are accepted. */ private boolean checkPduType(SnmpPduPacket pdu) { boolean result = true ; switch(pdu.type) { case SnmpDefinitions.pduGetRequestPdu: case SnmpDefinitions.pduGetNextRequestPdu: case SnmpDefinitions.pduSetRequestPdu: case SnmpDefinitions.pduGetBulkRequestPdu: result = true ; break; default: if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "checkPduType", "cannot respond to this kind of PDU"); } result = false ; break; } return result ; } /** * Check if the specified pdu is conform to the ACL. * This method returns null if the pdu is ok. If not, it returns * the response pdu to be replied. */ private SnmpPduPacket checkAcl(SnmpPduPacket pdu) { SnmpPduPacket response = null ; String community = new String(pdu.community) ; // We check the pdu type and create an error response if // the check failed. // if (ipacl != null) { if (pdu.type == SnmpDefinitions.pduSetRequestPdu) { if (!((InetAddressAcl)ipacl). checkWritePermission(pdu.address, community)) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, "checkAcl", "sender is " + pdu.address + " with " + community +". Sender has no write permission"); } int err = SnmpSubRequestHandler. mapErrorStatus(SnmpDefinitions. snmpRspAuthorizationError, pdu.version, pdu.type); response = newErrorResponsePdu(pdu, err, 0) ; } else { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, "checkAcl", "sender is " + pdu.address + " with " + community +". Sender has write permission"); } } } else { if (!((InetAddressAcl)ipacl).checkReadPermission(pdu.address, community)) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, "checkAcl", "sender is " + pdu.address + " with " + community +". Sender has no read permission"); } int err = SnmpSubRequestHandler. mapErrorStatus(SnmpDefinitions. snmpRspAuthorizationError, pdu.version, pdu.type); response = newErrorResponsePdu(pdu, err, 0); SnmpAdaptorServer snmpServer = (SnmpAdaptorServer)adaptorServer; snmpServer.updateErrorCounters(SnmpDefinitions. snmpRspNoSuchName); } else { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, "checkAcl", "sender is " + pdu.address + " with " + community +". Sender has read permission"); } } } } // If the response is not null, this means the pdu is rejected. // So let's update the statistics. // if (response != null) { SnmpAdaptorServer snmpServer = (SnmpAdaptorServer)adaptorServer ; snmpServer.incSnmpInBadCommunityUses(1) ; if (((InetAddressAcl)ipacl).checkCommunity(community) == false) snmpServer.incSnmpInBadCommunityNames(1) ; } return response ; } /** * Make a response pdu with the specified error status and index. * NOTE: the response pdu share its varBindList with the request pdu. */ private SnmpPduRequest newValidResponsePdu(SnmpPduPacket reqPdu, SnmpVarBind[] varBindList) { SnmpPduRequest result = new SnmpPduRequest() ; result.address = reqPdu.address ; result.port = reqPdu.port ; result.version = reqPdu.version ; result.community = reqPdu.community ; result.type = result.pduGetResponsePdu ; result.requestId = reqPdu.requestId ; result.errorStatus = SnmpDefinitions.snmpRspNoError ; result.errorIndex = 0 ; result.varBindList = varBindList ; ((SnmpAdaptorServer)adaptorServer). updateErrorCounters(result.errorStatus) ; return result ; } /** * Make a response pdu with the specified error status and index. * NOTE: the response pdu share its varBindList with the request pdu. */ private SnmpPduRequest newErrorResponsePdu(SnmpPduPacket req,int s,int i) { SnmpPduRequest result = newValidResponsePdu(req, null) ; result.errorStatus = s ; result.errorIndex = i ; result.varBindList = req.varBindList ; ((SnmpAdaptorServer)adaptorServer). updateErrorCounters(result.errorStatus) ; return result ; } private SnmpMessage newTooBigMessage(SnmpMessage reqMsg) throws SnmpTooBigException { SnmpMessage result = null ; SnmpPduPacket reqPdu = null ; try { reqPdu = (SnmpPduPacket)pduFactory.decodeSnmpPdu(reqMsg) ; if (reqPdu != null) { SnmpPduPacket respPdu = newTooBigPdu(reqPdu) ; result = (SnmpMessage)pduFactory. encodeSnmpPdu(respPdu, packet.getData().length) ; } } catch(SnmpStatusException x) { // This should not occur because decodeIncomingRequest has normally // been successfully called before. if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "newTooBigMessage", "Internal error", x); } throw new InternalError() ; } return result ; } private SnmpPduPacket newTooBigPdu(SnmpPduPacket req) { SnmpPduRequest result = newErrorResponsePdu(req, SnmpDefinitions.snmpRspTooBig, 0) ; result.varBindList = null ; return result ; } private SnmpPduPacket reduceResponsePdu(SnmpPduPacket req, SnmpPduPacket resp, int acceptedVbCount) throws SnmpTooBigException { // Reduction can be attempted only on bulk response // if (req.type != req.pduGetBulkRequestPdu) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "reduceResponsePdu", "cannot remove anything"); } throw new SnmpTooBigException(acceptedVbCount) ; } // We're going to reduce the varbind list. // First determine which items should be removed. // Next duplicate and replace the existing list by the reduced one. // // acceptedVbCount is the number of varbind which have been // successfully encoded before reaching bufferSize: // * when it is >= 2, we split the varbindlist at this // position (-1 to be safe), // * when it is 1, we only put one (big?) item in the varbindlist // * when it is 0 (in fact, acceptedVbCount is not available), // we split the varbindlist by 2. // int vbCount = resp.varBindList.length ; if (acceptedVbCount >= 3) vbCount = Math.min(acceptedVbCount - 1, resp.varBindList.length) ; else if (acceptedVbCount == 1) vbCount = 1 ; else // acceptedCount == 0 ie it is unknown vbCount = resp.varBindList.length / 2 ; if (vbCount < 1) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "reduceResponsePdu", "cannot remove anything"); } throw new SnmpTooBigException(acceptedVbCount) ; } else { SnmpVarBind[] newVbList = new SnmpVarBind[vbCount] ; for (int i = 0 ; i < vbCount ; i++) { newVbList[i] = resp.varBindList[i] ; } if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "reduceResponsePdu", (resp.varBindList.length - newVbList.length) + " items have been removed"); } resp.varBindList = newVbList ; } return resp ; } /** * The method takes the incoming requests and split it into subrequests. */ private void splitRequest(SnmpPduRequest req) { int nbAgents= mibs.size(); SnmpMibAgent agent= (SnmpMibAgent) mibs.firstElement(); if (nbAgents == 1) { // Take all the oids contained in the request and // subs.put(agent, new SnmpSubRequestHandler(agent, req, true)); return; } // For the get next operation we are going to send the varbind list // to all agents // if (req.type == pduGetNextRequestPdu) { for(Enumeration e= mibs.elements(); e.hasMoreElements(); ) { SnmpMibAgent ag= (SnmpMibAgent) e.nextElement(); subs.put(ag, new SnmpSubNextRequestHandler(adaptor, ag, req)); } return; } int nbReqs= req.varBindList.length; SnmpVarBind[] vars= req.varBindList; SnmpSubRequestHandler sub; for(int i=0; i < nbReqs; i++) { agent= root.getAgentMib(vars[i].oid); sub= subs.get(agent); if (sub == null) { // We need to create the sub request handler and update // the hashtable // sub= new SnmpSubRequestHandler(agent, req); subs.put(agent, sub); } // Update the translation table within the subrequest // sub.updateRequest(vars[i], i); } } /** * The method takes the incoming get bulk requests and split it into * subrequests. */ private void splitBulkRequest(SnmpPduBulk req, int nonRepeaters, int maxRepetitions, int R) { // Send the getBulk to all agents // for(Enumeration e= mibs.elements(); e.hasMoreElements(); ) { SnmpMibAgent agent = (SnmpMibAgent) e.nextElement(); if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, "splitBulkRequest", "Create a sub with : " + agent + " " + nonRepeaters + " " + maxRepetitions + " " + R); } subs.put(agent, new SnmpSubBulkRequestHandler(adaptor, agent, req, nonRepeaters, maxRepetitions, R)); } return; } private SnmpPduPacket mergeResponses(SnmpPduRequest req) { if (req.type == pduGetNextRequestPdu) { return mergeNextResponses(req); } SnmpVarBind[] result= req.varBindList; // Go through the list of subrequests and concatenate. // Hopefully, by now all the sub-requests should be finished // for(Enumeration e= subs.elements(); e.hasMoreElements();) { SnmpSubRequestHandler sub= (SnmpSubRequestHandler) e.nextElement(); sub.updateResult(result); } return newValidResponsePdu(req,result); } private SnmpPduPacket mergeNextResponses(SnmpPduRequest req) { int max= req.varBindList.length; SnmpVarBind[] result= new SnmpVarBind[max]; // Go through the list of subrequests and concatenate. // Hopefully, by now all the sub-requests should be finished // for(Enumeration e= subs.elements(); e.hasMoreElements();) { SnmpSubRequestHandler sub= (SnmpSubRequestHandler) e.nextElement(); sub.updateResult(result); } if (req.version == snmpVersionTwo) { return newValidResponsePdu(req,result); } // In v1 make sure there is no endOfMibView ... // for(int i=0; i < max; i++) { SnmpValue val= result[i].value; if (val == SnmpVarBind.endOfMibView) return newErrorResponsePdu(req, SnmpDefinitions.snmpRspNoSuchName, i+1); } // So far so good ... // return newValidResponsePdu(req,result); } private SnmpVarBind[] mergeBulkResponses(int size) { // Let's allocate the array for storing the result // SnmpVarBind[] result= new SnmpVarBind[size]; for(int i= size-1; i >=0; --i) { result[i]= new SnmpVarBind(); result[i].value= SnmpVarBind.endOfMibView; } // Go through the list of subrequests and concatenate. // Hopefully, by now all the sub-requests should be finished // for(Enumeration e= subs.elements(); e.hasMoreElements();) { SnmpSubRequestHandler sub= (SnmpSubRequestHandler) e.nextElement(); sub.updateResult(result); } return result; } protected String makeDebugTag() { return "SnmpRequestHandler[" + adaptorServer.getProtocol() + ":" + adaptorServer.getPort() + "]"; } Thread createThread(Runnable r) { return null; } static final private String InterruptSysCallMsg = "Interrupted system call"; static final private SnmpStatusException noSuchNameException = new SnmpStatusException(SnmpDefinitions.snmpRspNoSuchName) ; }