1152 lines · 43.3 KB · Java
RawDownload
/* * 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 :

Lines 1–500 of 1152.