1 /* 2 * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 27 package com.sun.jmx.snmp.daemon; 28 29 30 31 // java import 32 // 33 import java.util.Vector; 34 import java.util.Enumeration; 35 import java.util.Hashtable; 36 import java.util.logging.Level; 37 import java.io.InterruptedIOException; 38 import java.net.DatagramSocket; 39 import java.net.DatagramPacket; 40 import java.net.SocketException; 41 42 // jmx imports 43 // 44 import javax.management.MBeanServer; 45 import javax.management.ObjectName; 46 import com.sun.jmx.snmp.SnmpMessage; 47 import com.sun.jmx.snmp.SnmpPduFactory; 48 import com.sun.jmx.snmp.SnmpPduBulk; 49 import com.sun.jmx.snmp.SnmpPduPacket; 50 import com.sun.jmx.snmp.SnmpPduRequest; 51 import com.sun.jmx.snmp.SnmpPduTrap; 52 import com.sun.jmx.snmp.SnmpValue; 53 import com.sun.jmx.snmp.SnmpVarBind; 54 import com.sun.jmx.snmp.SnmpVarBindList; 55 import com.sun.jmx.snmp.SnmpDefinitions; 56 import com.sun.jmx.snmp.SnmpStatusException; 57 import com.sun.jmx.snmp.SnmpTooBigException; 58 import com.sun.jmx.snmp.SnmpDataTypeEnums; 59 60 // RI imports 61 // 62 import static com.sun.jmx.defaults.JmxProperties.SNMP_ADAPTOR_LOGGER; 63 64 // SNMP runtime import 65 // 66 import com.sun.jmx.snmp.agent.SnmpMibAgent; 67 import com.sun.jmx.snmp.agent.SnmpUserDataFactory; 68 //import com.sun.jmx.snmp.IPAcl.IPAcl; 69 import com.sun.jmx.snmp.InetAddressAcl; 70 71 72 class SnmpRequestHandler extends ClientHandler implements SnmpDefinitions { 73 74 private transient DatagramSocket socket = null ; 75 private transient DatagramPacket packet = null ; 76 private transient Vector<SnmpMibAgent> mibs = null ; 77 78 /** 79 * Contains the list of sub-requests associated to the current request. 80 */ 81 private transient Hashtable<SnmpMibAgent, SnmpSubRequestHandler> subs = null; 82 83 /** 84 * Reference on the MIBS 85 */ 86 private transient SnmpMibTree root; 87 88 private transient InetAddressAcl ipacl = null ; 89 private transient SnmpPduFactory pduFactory = null ; 90 private transient SnmpUserDataFactory userDataFactory = null ; 91 private transient SnmpAdaptorServer adaptor = null; 92 /** 93 * Full constructor 94 */ 95 public SnmpRequestHandler(SnmpAdaptorServer server, int id, 96 DatagramSocket s, DatagramPacket p, 97 SnmpMibTree tree, Vector<SnmpMibAgent> m, 98 InetAddressAcl a, 99 SnmpPduFactory factory, 100 SnmpUserDataFactory dataFactory, 101 MBeanServer f, ObjectName n) 102 { 103 super(server, id, f, n); 104 105 // Need a reference on SnmpAdaptorServer for getNext & getBulk, 106 // in case of oid equality (mib overlapping). 107 // 108 adaptor = server; 109 socket = s; 110 packet = p; 111 root= tree; 112 mibs = new Vector<>(m); 113 subs= new Hashtable<>(mibs.size()); 114 ipacl = a; 115 pduFactory = factory ; 116 userDataFactory = dataFactory ; 117 //thread.start(); 118 } 119 120 /** 121 * Treat the request available in 'packet' and send the result 122 * back to the client. 123 * Note: we overwrite 'packet' with the response bytes. 124 */ 125 @Override 126 public void doRun() { 127 128 // Trace the input packet 129 // 130 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { 131 SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, 132 "doRun","Packet received:\n" + 133 SnmpMessage.dumpHexBuffer(packet.getData(), 0, packet.getLength())); 134 } 135 136 // Let's build the response packet 137 // 138 DatagramPacket respPacket = makeResponsePacket(packet) ; 139 140 // Trace the output packet 141 // 142 if ((SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) && (respPacket != null)) { 143 SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, 144 "doRun","Packet to be sent:\n" + 145 SnmpMessage.dumpHexBuffer(respPacket.getData(), 0, respPacket.getLength())); 146 } 147 148 // Send the response packet if any 149 // 150 if (respPacket != null) { 151 try { 152 socket.send(respPacket) ; 153 } catch (SocketException e) { 154 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { 155 if (e.getMessage().equals(InterruptSysCallMsg)) { 156 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, 157 "doRun", "interrupted"); 158 } else { 159 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, 160 "doRun", "I/O exception", e); 161 } 162 } 163 } catch(InterruptedIOException e) { 164 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { 165 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, 166 "doRun", "interrupted"); 167 } 168 } catch(Exception e) { 169 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { 170 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, 171 "doRun", "failure when sending response", e); 172 } 173 } 174 } 175 } 176 177 /** 178 * Here we make a response packet from a request packet. 179 * We return null if there no response packet to sent. 180 */ 181 private DatagramPacket makeResponsePacket(DatagramPacket reqPacket) { 182 DatagramPacket respPacket = null ; 183 184 // Transform the request packet into a request SnmpMessage 185 // 186 SnmpMessage reqMsg = new SnmpMessage() ; 187 try { 188 reqMsg.decodeMessage(reqPacket.getData(), reqPacket.getLength()) ; 189 reqMsg.address = reqPacket.getAddress() ; 190 reqMsg.port = reqPacket.getPort() ; 191 } 192 catch(SnmpStatusException x) { 193 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { 194 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, 195 "makeResponsePacket", "packet decoding failed", x); 196 } 197 reqMsg = null ; 198 ((SnmpAdaptorServer)adaptorServer).incSnmpInASNParseErrs(1) ; 199 } 200 201 // Make the response SnmpMessage if any 202 // 203 SnmpMessage respMsg = null ; 204 if (reqMsg != null) { 205 respMsg = makeResponseMessage(reqMsg) ; 206 } 207 208 // Try to transform the response SnmpMessage into response packet. 209 // NOTE: we overwrite the request packet. 210 // 211 if (respMsg != null) { 212 try { 213 reqPacket.setLength(respMsg.encodeMessage(reqPacket.getData())) ; 214 respPacket = reqPacket ; 215 } 216 catch(SnmpTooBigException x) { 217 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { 218 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, 219 "makeResponsePacket", "response message is too big"); 220 } 221 try { 222 respMsg = newTooBigMessage(reqMsg) ; 223 reqPacket.setLength(respMsg.encodeMessage(reqPacket.getData())) ; 224 respPacket = reqPacket ; 225 } 226 catch(SnmpTooBigException xx) { 227 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { 228 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, 229 "makeResponsePacket", "'too big' is 'too big' !!!"); 230 } 231 adaptor.incSnmpSilentDrops(1); 232 } 233 } 234 } 235 236 return respPacket ; 237 } 238 239 /** 240 * Here we make a response message from a request message. 241 * We return null if there is no message to reply. 242 */ 243 private SnmpMessage makeResponseMessage(SnmpMessage reqMsg) { 244 SnmpMessage respMsg = null ; 245 246 // Transform the request message into a request pdu 247 // 248 SnmpPduPacket reqPdu; 249 Object userData = null; 250 try { 251 reqPdu = (SnmpPduPacket)pduFactory.decodeSnmpPdu(reqMsg) ; 252 if (reqPdu != null && userDataFactory != null) 253 userData = userDataFactory.allocateUserData(reqPdu); 254 } 255 catch(SnmpStatusException x) { 256 reqPdu = null ; 257 SnmpAdaptorServer snmpServer = (SnmpAdaptorServer)adaptorServer ; 258 snmpServer.incSnmpInASNParseErrs(1) ; 259 if (x.getStatus()== SnmpDefinitions.snmpWrongSnmpVersion) 260 snmpServer.incSnmpInBadVersions(1) ; 261 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { 262 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, 263 "makeResponseMessage", "message decoding failed", x); 264 } 265 } 266 267 // Make the response pdu if any 268 // 269 SnmpPduPacket respPdu = null ; 270 if (reqPdu != null) { 271 respPdu = makeResponsePdu(reqPdu,userData) ; 272 try { 273 if (userDataFactory != null) 274 userDataFactory.releaseUserData(userData,respPdu); 275 } catch (SnmpStatusException x) { 276 respPdu = null; 277 } 278 } 279 280 // Try to transform the response pdu into a response message if any 281 // 282 if (respPdu != null) { 283 try { 284 respMsg = (SnmpMessage)pduFactory. 285 encodeSnmpPdu(respPdu, packet.getData().length) ; 286 } 287 catch(SnmpStatusException x) { 288 respMsg = null ; 289 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { 290 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, 291 "makeResponseMessage", "failure when encoding the response message", x); 292 } 293 } 294 catch(SnmpTooBigException x) { 295 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { 296 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, 297 "makeResponseMessage", "response message is too big"); 298 } 299 300 try { 301 // if the PDU is too small, why should we try to do 302 // recovery ? 303 // 304 if (packet.getData().length <=32) 305 throw x; 306 int pos= x.getVarBindCount(); 307 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { 308 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, 309 "makeResponseMessage", "fail on element" + pos); 310 } 311 int old; 312 while (true) { 313 try { 314 respPdu = reduceResponsePdu(reqPdu, respPdu, pos) ; 315 respMsg = (SnmpMessage)pduFactory. 316 encodeSnmpPdu(respPdu, 317 packet.getData().length -32) ; 318 break; 319 } catch (SnmpTooBigException xx) { 320 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { 321 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, 322 "makeResponseMessage", "response message is still too big"); 323 } 324 old= pos; 325 pos= xx.getVarBindCount(); 326 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { 327 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, 328 "makeResponseMessage","fail on element" + pos); 329 } 330 if (pos == old) { 331 // we can not go any further in trying to 332 // reduce the message ! 333 // 334 throw xx; 335 } 336 } 337 }// end of loop 338 } catch(SnmpStatusException xx) { 339 respMsg = null ; 340 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { 341 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, 342 "makeResponseMessage", "failure when encoding the response message", xx); 343 } 344 } 345 catch(SnmpTooBigException xx) { 346 try { 347 respPdu = newTooBigPdu(reqPdu) ; 348 respMsg = (SnmpMessage)pduFactory. 349 encodeSnmpPdu(respPdu, packet.getData().length) ; 350 } 351 catch(SnmpTooBigException xxx) { 352 respMsg = null ; 353 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { 354 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, 355 "makeResponseMessage", "'too big' is 'too big' !!!"); 356 } 357 adaptor.incSnmpSilentDrops(1); 358 } 359 catch(Exception xxx) { 360 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { 361 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, 362 "makeResponseMessage", "Got unexpected exception", xxx); 363 } 364 respMsg = null ; 365 } 366 } 367 catch(Exception xx) { 368 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { 369 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, 370 "makeResponseMessage", "Got unexpected exception", xx); 371 } 372 respMsg = null ; 373 } 374 } 375 } 376 return respMsg ; 377 } 378 379 /** 380 * Here we make a response pdu from a request pdu. 381 * We return null if there is no pdu to reply. 382 */ 383 private SnmpPduPacket makeResponsePdu(SnmpPduPacket reqPdu, 384 Object userData) { 385 386 SnmpAdaptorServer snmpServer = (SnmpAdaptorServer)adaptorServer ; 387 SnmpPduPacket respPdu = null ; 388 389 snmpServer.updateRequestCounters(reqPdu.type) ; 390 if (reqPdu.varBindList != null) 391 snmpServer.updateVarCounters(reqPdu.type, 392 reqPdu.varBindList.length) ; 393 394 if (checkPduType(reqPdu)) { 395 respPdu = checkAcl(reqPdu) ; 396 if (respPdu == null) { // reqPdu is accepted by ACLs 397 if (mibs.size() < 1) { 398 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { 399 SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, 400 "makeResponsePdu", "Request " + reqPdu.requestId + 401 " received but no MIB registered."); 402 } 403 return makeNoMibErrorPdu((SnmpPduRequest)reqPdu, userData); 404 } 405 switch(reqPdu.type) { 406 case SnmpPduPacket.pduGetRequestPdu: 407 case SnmpPduPacket.pduGetNextRequestPdu: 408 case SnmpPduPacket.pduSetRequestPdu: 409 respPdu = makeGetSetResponsePdu((SnmpPduRequest)reqPdu, 410 userData) ; 411 break ; 412 413 case SnmpPduPacket.pduGetBulkRequestPdu: 414 respPdu = makeGetBulkResponsePdu((SnmpPduBulk)reqPdu, 415 userData) ; 416 break ; 417 } 418 } 419 else { // reqPdu is rejected by ACLs 420 // respPdu contains the error response to be sent. 421 // We send this response only if authResEnabled is true. 422 if (!snmpServer.getAuthRespEnabled()) { // No response should be sent 423 respPdu = null ; 424 } 425 if (snmpServer.getAuthTrapEnabled()) { // A trap must be sent 426 try { 427 snmpServer.snmpV1Trap(SnmpPduTrap. 428 trapAuthenticationFailure, 0, 429 new SnmpVarBindList()) ; 430 } 431 catch(Exception x) { 432 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { 433 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, 434 "makeResponsePdu", "Failure when sending authentication trap", x); 435 } 436 } 437 } 438 } 439 } 440 return respPdu ; 441 } 442 443 // 444 // Generates a response packet, filling the values in the 445 // varbindlist with one of endOfMibView, noSuchObject, noSuchInstance 446 // according to the value of <code>status</code> 447 // 448 // @param statusTag should be one of: 449 // <li>SnmpDataTypeEnums.errEndOfMibViewTag</li> 450 // <li>SnmpDataTypeEnums.errNoSuchObjectTag</li> 451 // <li>SnmpDataTypeEnums.errNoSuchInstanceTag</li> 452 // 453 SnmpPduPacket makeErrorVarbindPdu(SnmpPduPacket req, int statusTag) { 454 455 final SnmpVarBind[] vblist = req.varBindList; 456 final int length = vblist.length; 457 458 switch (statusTag) { 459 case SnmpDataTypeEnums.errEndOfMibViewTag: 460 for (int i=0 ; i<length ; i++) 461 vblist[i].value = SnmpVarBind.endOfMibView; 462 break; 463 case SnmpDataTypeEnums.errNoSuchObjectTag: 464 for (int i=0 ; i<length ; i++) 465 vblist[i].value = SnmpVarBind.noSuchObject; 466 break; 467 case SnmpDataTypeEnums.errNoSuchInstanceTag: 468 for (int i=0 ; i<length ; i++) 469 vblist[i].value = SnmpVarBind.noSuchInstance; 470 break; 471 default: 472 return newErrorResponsePdu(req,snmpRspGenErr,1); 473 } 474 return newValidResponsePdu(req,vblist); 475 } 476 477 // Generates an appropriate response when no mib is registered in 478 // the adaptor. 479 // 480 // <li>If the version is V1:</li> 481 // <ul><li>Generates a NoSuchName error V1 response PDU</li></ul> 482 // <li>If the version is V2:</li> 483 // <ul><li>If the request is a GET, fills the varbind list with 484 // NoSuchObject's</li> 485 // <li>If the request is a GET-NEXT/GET-BULK, fills the varbind 486 // list with EndOfMibView's</li> 487 // <li>If the request is a SET, generates a NoAccess error V2 488 // response PDU</li> 489 // </ul> 490 // 491 // 492 SnmpPduPacket makeNoMibErrorPdu(SnmpPduRequest req, Object userData) { 493 // There is no agent registered 494 // 495 if (req.version == SnmpDefinitions.snmpVersionOne) { 496 // Version 1: => NoSuchName 497 return 498 newErrorResponsePdu(req,snmpRspNoSuchName,1); 499 } else if (req.version == SnmpDefinitions.snmpVersionTwo) { 500 // Version 2: => depends on PDU type 501 switch (req.type) { 502 case pduSetRequestPdu : 503 case pduWalkRequest : 504 // SET request => NoAccess 505 return 506 newErrorResponsePdu(req,snmpRspNoAccess,1); 507 case pduGetRequestPdu : 508 // GET request => NoSuchObject 509 return 510 makeErrorVarbindPdu(req,SnmpDataTypeEnums. 511 errNoSuchObjectTag); 512 case pduGetNextRequestPdu : 513 case pduGetBulkRequestPdu : 514 // GET-NEXT or GET-BULK => EndOfMibView 515 return 516 makeErrorVarbindPdu(req,SnmpDataTypeEnums. 517 errEndOfMibViewTag); 518 default: 519 } 520 } 521 // Something wrong here: => snmpRspGenErr 522 return newErrorResponsePdu(req,snmpRspGenErr,1); 523 } 524 525 /** 526 * Here we make the response pdu from a get/set request pdu. 527 * At this level, the result is never null. 528 */ 529 private SnmpPduPacket makeGetSetResponsePdu(SnmpPduRequest req, 530 Object userData) { 531 532 // Create the trhead group specific for handling sub-requests 533 // associated to the current request. Use the invoke id 534 // 535 // Nice idea to use a thread group on a request basis. 536 // However the impact on performance is terrible ! 537 // theGroup= new ThreadGroup(thread.getThreadGroup(), 538 // "request " + String.valueOf(req.requestId)); 539 540 // Let's build the varBindList for the response pdu 541 // 542 543 if (req.varBindList == null) { 544 // Good ! Let's make a full response pdu. 545 // 546 return newValidResponsePdu(req, null) ; 547 } 548 549 // First we need to split the request into subrequests 550 // 551 splitRequest(req); 552 int nbSubRequest= subs.size(); 553 if (nbSubRequest == 1) 554 return turboProcessingGetSet(req,userData); 555 556 557 // Execute all the subrequests resulting from the split of the 558 // varbind list. 559 // 560 SnmpPduPacket result= executeSubRequest(req,userData); 561 if (result != null) 562 // It means that an error occurred. The error is already 563 // formatted by the executeSubRequest 564 // method. 565 return result; 566 567 // So far so good. So we need to concatenate all the answers. 568 // 569 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { 570 SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, 571 "makeGetSetResponsePdu", 572 "Build the unified response for request " + req.requestId); 573 } 574 return mergeResponses(req); 575 } 576 577 /** 578 * The method runs all the sub-requests associated to the current 579 * instance of SnmpRequestHandler. 580 */ 581 private SnmpPduPacket executeSubRequest(SnmpPduPacket req, 582 Object userData) { 583 584 int errorStatus = SnmpDefinitions.snmpRspNoError ; 585 586 int i; 587 // If it's a set request, we must first check any varBind 588 // 589 if (req.type == pduSetRequestPdu) { 590 591 i=0; 592 for(Enumeration<SnmpSubRequestHandler> e= subs.elements(); e.hasMoreElements() ; i++) { 593 // Indicate to the sub request that a check must be invoked ... 594 // OK we should have defined out own tag for that ! 595 // 596 SnmpSubRequestHandler sub= e.nextElement(); 597 sub.setUserData(userData); 598 sub.type= pduWalkRequest; 599 600 sub.run(); 601 602 sub.type= pduSetRequestPdu; 603 604 if (sub.getErrorStatus() != SnmpDefinitions.snmpRspNoError) { 605 // No point to go any further. 606 // 607 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { 608 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, 609 "executeSubRequest", "an error occurs"); 610 } 611 612 return newErrorResponsePdu(req, errorStatus, 613 sub.getErrorIndex() + 1) ; 614 } 615 } 616 }// end processing check operation for a set PDU. 617 618 // Let's start the sub-requests. 619 // 620 i=0; 621 for(Enumeration<SnmpSubRequestHandler> e= subs.elements(); e.hasMoreElements() ;i++) { 622 SnmpSubRequestHandler sub= e.nextElement(); 623 /* NPCTE fix for bugId 4492741, esc 0, 16-August 2001 */ 624 sub.setUserData(userData); 625 /* end of NPCTE fix for bugId 4492741 */ 626 627 sub.run(); 628 629 if (sub.getErrorStatus() != SnmpDefinitions.snmpRspNoError) { 630 // No point to go any further. 631 // 632 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { 633 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, 634 "executeSubRequest", "an error occurs"); 635 } 636 637 return newErrorResponsePdu(req, errorStatus, 638 sub.getErrorIndex() + 1) ; 639 } 640 } 641 642 // everything is ok 643 // 644 return null; 645 } 646 647 /** 648 * Optimize when there is only one sub request 649 */ 650 private SnmpPduPacket turboProcessingGetSet(SnmpPduRequest req, 651 Object userData) { 652 653 int errorStatus; 654 SnmpSubRequestHandler sub = subs.elements().nextElement(); 655 sub.setUserData(userData); 656 657 // Indicate to the sub request that a check must be invoked ... 658 // OK we should have defined out own tag for that ! 659 // 660 if (req.type == SnmpDefinitions.pduSetRequestPdu) { 661 sub.type= pduWalkRequest; 662 sub.run(); 663 sub.type= pduSetRequestPdu; 664 665 // Check the error status. 666 // 667 errorStatus= sub.getErrorStatus(); 668 if (errorStatus != SnmpDefinitions.snmpRspNoError) { 669 // No point to go any further. 670 // 671 return newErrorResponsePdu(req, errorStatus, 672 sub.getErrorIndex() + 1) ; 673 } 674 } 675 676 // process the operation 677 // 678 679 sub.run(); 680 errorStatus= sub.getErrorStatus(); 681 if (errorStatus != SnmpDefinitions.snmpRspNoError) { 682 // No point to go any further. 683 // 684 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { 685 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, 686 "turboProcessingGetSet", "an error occurs"); 687 } 688 int realIndex= sub.getErrorIndex() + 1; 689 return newErrorResponsePdu(req, errorStatus, realIndex) ; 690 } 691 692 // So far so good. So we need to concatenate all the answers. 693 // 694 695 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { 696 SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, 697 "turboProcessingGetSet", "build the unified response for request " 698 + req.requestId); 699 } 700 return mergeResponses(req); 701 } 702 703 /** 704 * Here we make the response pdu for a bulk request. 705 * At this level, the result is never null. 706 */ 707 private SnmpPduPacket makeGetBulkResponsePdu(SnmpPduBulk req, 708 Object userData) { 709 710 SnmpVarBind[] respVarBindList; 711 712 // RFC 1905, Section 4.2.3, p14 713 int L = req.varBindList.length ; 714 int N = Math.max(Math.min(req.nonRepeaters, L), 0) ; 715 int M = Math.max(req.maxRepetitions, 0) ; 716 int R = L - N ; 717 718 if (req.varBindList == null) { 719 // Good ! Let's make a full response pdu. 720 // 721 return newValidResponsePdu(req, null) ; 722 } 723 724 // Split the request into subrequests. 725 // 726 splitBulkRequest(req, N, M, R); 727 SnmpPduPacket result= executeSubRequest(req,userData); 728 if (result != null) 729 return result; 730 731 respVarBindList= mergeBulkResponses(N + (M * R)); 732 733 // Now we remove useless trailing endOfMibView. 734 // 735 int m2 ; // respVarBindList[m2] item and next are going to be removed 736 int t = respVarBindList.length ; 737 while ((t > N) && (respVarBindList[t-1]. 738 value.equals(SnmpVarBind.endOfMibView))) { 739 t-- ; 740 } 741 if (t == N) 742 m2 = N + R ; 743 else 744 m2 = N + ((t -1 -N) / R + 2) * R ; // Trivial, of course... 745 if (m2 < respVarBindList.length) { 746 SnmpVarBind[] truncatedList = new SnmpVarBind[m2] ; 747 for (int i = 0 ; i < m2 ; i++) { 748 truncatedList[i] = respVarBindList[i] ; 749 } 750 respVarBindList = truncatedList ; 751 } 752 753 // Good ! Let's make a full response pdu. 754 // 755 return newValidResponsePdu(req, respVarBindList) ; 756 } 757 758 /** 759 * Check the type of the pdu: only the get/set/bulk request 760 * are accepted. 761 */ 762 private boolean checkPduType(SnmpPduPacket pdu) { 763 764 boolean result; 765 766 switch(pdu.type) { 767 768 case SnmpDefinitions.pduGetRequestPdu: 769 case SnmpDefinitions.pduGetNextRequestPdu: 770 case SnmpDefinitions.pduSetRequestPdu: 771 case SnmpDefinitions.pduGetBulkRequestPdu: 772 result = true ; 773 break; 774 775 default: 776 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { 777 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, 778 "checkPduType", "cannot respond to this kind of PDU"); 779 } 780 result = false ; 781 break; 782 } 783 784 return result ; 785 } 786 787 /** 788 * Check if the specified pdu is conform to the ACL. 789 * This method returns null if the pdu is ok. If not, it returns 790 * the response pdu to be replied. 791 */ 792 private SnmpPduPacket checkAcl(SnmpPduPacket pdu) { 793 SnmpPduPacket response = null ; 794 String community = new String(pdu.community) ; 795 796 // We check the pdu type and create an error response if 797 // the check failed. 798 // 799 if (ipacl != null) { 800 if (pdu.type == SnmpDefinitions.pduSetRequestPdu) { 801 if (!ipacl.checkWritePermission(pdu.address, community)) { 802 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { 803 SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, 804 "checkAcl", "sender is " + pdu.address + 805 " with " + community +". Sender has no write permission"); 806 } 807 int err = SnmpSubRequestHandler. 808 mapErrorStatus(SnmpDefinitions. 809 snmpRspAuthorizationError, 810 pdu.version, pdu.type); 811 response = newErrorResponsePdu(pdu, err, 0) ; 812 } 813 else { 814 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { 815 SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, 816 "checkAcl", "sender is " + pdu.address + 817 " with " + community +". Sender has write permission"); 818 } 819 } 820 } 821 else { 822 if (!ipacl.checkReadPermission(pdu.address, community)) { 823 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { 824 SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, 825 "checkAcl", "sender is " + pdu.address + 826 " with " + community +". Sender has no read permission"); 827 } 828 int err = SnmpSubRequestHandler. 829 mapErrorStatus(SnmpDefinitions. 830 snmpRspAuthorizationError, 831 pdu.version, pdu.type); 832 response = newErrorResponsePdu(pdu, 833 err, 834 0); 835 SnmpAdaptorServer snmpServer = 836 (SnmpAdaptorServer)adaptorServer; 837 snmpServer.updateErrorCounters(SnmpDefinitions. 838 snmpRspNoSuchName); 839 } 840 else { 841 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { 842 SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, 843 "checkAcl", "sender is " + pdu.address + 844 " with " + community +". Sender has read permission"); 845 } 846 } 847 } 848 } 849 850 // If the response is not null, this means the pdu is rejected. 851 // So let's update the statistics. 852 // 853 if (response != null) { 854 SnmpAdaptorServer snmpServer = (SnmpAdaptorServer)adaptorServer ; 855 snmpServer.incSnmpInBadCommunityUses(1) ; 856 if (ipacl.checkCommunity(community) == false) 857 snmpServer.incSnmpInBadCommunityNames(1) ; 858 } 859 860 return response ; 861 } 862 863 /** 864 * Make a response pdu with the specified error status and index. 865 * NOTE: the response pdu share its varBindList with the request pdu. 866 */ 867 private SnmpPduRequest newValidResponsePdu(SnmpPduPacket reqPdu, 868 SnmpVarBind[] varBindList) { 869 SnmpPduRequest result = new SnmpPduRequest() ; 870 871 result.address = reqPdu.address ; 872 result.port = reqPdu.port ; 873 result.version = reqPdu.version ; 874 result.community = reqPdu.community ; 875 result.type = SnmpPduRequest.pduGetResponsePdu ; 876 result.requestId = reqPdu.requestId ; 877 result.errorStatus = SnmpDefinitions.snmpRspNoError ; 878 result.errorIndex = 0 ; 879 result.varBindList = varBindList ; 880 881 ((SnmpAdaptorServer)adaptorServer). 882 updateErrorCounters(result.errorStatus) ; 883 884 return result ; 885 } 886 887 /** 888 * Make a response pdu with the specified error status and index. 889 * NOTE: the response pdu share its varBindList with the request pdu. 890 */ 891 private SnmpPduRequest newErrorResponsePdu(SnmpPduPacket req,int s,int i) { 892 SnmpPduRequest result = newValidResponsePdu(req, null) ; 893 result.errorStatus = s ; 894 result.errorIndex = i ; 895 result.varBindList = req.varBindList ; 896 897 ((SnmpAdaptorServer)adaptorServer). 898 updateErrorCounters(result.errorStatus) ; 899 900 return result ; 901 } 902 903 private SnmpMessage newTooBigMessage(SnmpMessage reqMsg) 904 throws SnmpTooBigException { 905 SnmpMessage result = null ; 906 SnmpPduPacket reqPdu; 907 908 try { 909 reqPdu = (SnmpPduPacket)pduFactory.decodeSnmpPdu(reqMsg) ; 910 if (reqPdu != null) { 911 SnmpPduPacket respPdu = newTooBigPdu(reqPdu) ; 912 result = (SnmpMessage)pduFactory. 913 encodeSnmpPdu(respPdu, packet.getData().length) ; 914 } 915 } 916 catch(SnmpStatusException x) { 917 // This should not occur because decodeIncomingRequest has normally 918 // been successfully called before. 919 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { 920 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, 921 "newTooBigMessage", "Internal error", x); 922 } 923 throw new InternalError(x) ; 924 } 925 926 return result ; 927 } 928 929 private SnmpPduPacket newTooBigPdu(SnmpPduPacket req) { 930 SnmpPduRequest result = 931 newErrorResponsePdu(req, SnmpDefinitions.snmpRspTooBig, 0) ; 932 result.varBindList = null ; 933 return result ; 934 } 935 936 private SnmpPduPacket reduceResponsePdu(SnmpPduPacket req, 937 SnmpPduPacket resp, 938 int acceptedVbCount) 939 throws SnmpTooBigException { 940 941 // Reduction can be attempted only on bulk response 942 // 943 if (req.type != SnmpPduPacket.pduGetBulkRequestPdu) { 944 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { 945 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, 946 "reduceResponsePdu", "cannot remove anything"); 947 } 948 throw new SnmpTooBigException(acceptedVbCount) ; 949 } 950 951 // We're going to reduce the varbind list. 952 // First determine which items should be removed. 953 // Next duplicate and replace the existing list by the reduced one. 954 // 955 // acceptedVbCount is the number of varbind which have been 956 // successfully encoded before reaching bufferSize: 957 // * when it is >= 2, we split the varbindlist at this 958 // position (-1 to be safe), 959 // * when it is 1, we only put one (big?) item in the varbindlist 960 // * when it is 0 (in fact, acceptedVbCount is not available), 961 // we split the varbindlist by 2. 962 // 963 int vbCount; 964 if (acceptedVbCount >= 3) 965 vbCount = Math.min(acceptedVbCount - 1, resp.varBindList.length) ; 966 else if (acceptedVbCount == 1) 967 vbCount = 1 ; 968 else // acceptedCount == 0 ie it is unknown 969 vbCount = resp.varBindList.length / 2 ; 970 971 if (vbCount < 1) { 972 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { 973 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, 974 "reduceResponsePdu", "cannot remove anything"); 975 } 976 throw new SnmpTooBigException(acceptedVbCount) ; 977 } 978 else { 979 SnmpVarBind[] newVbList = new SnmpVarBind[vbCount] ; 980 for (int i = 0 ; i < vbCount ; i++) { 981 newVbList[i] = resp.varBindList[i] ; 982 } 983 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { 984 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, 985 "reduceResponsePdu", (resp.varBindList.length - newVbList.length) + 986 " items have been removed"); 987 } 988 resp.varBindList = newVbList ; 989 } 990 991 return resp ; 992 } 993 994 /** 995 * The method takes the incoming requests and split it into subrequests. 996 */ 997 private void splitRequest(SnmpPduRequest req) { 998 999 int nbAgents= mibs.size(); 1000 SnmpMibAgent agent = mibs.firstElement(); 1001 if (nbAgents == 1) { 1002 // Take all the oids contained in the request and 1003 // 1004 subs.put(agent, new SnmpSubRequestHandler(agent, req, true)); 1005 return; 1006 } 1007 1008 // For the get next operation we are going to send the varbind list 1009 // to all agents 1010 // 1011 if (req.type == pduGetNextRequestPdu) { 1012 for(Enumeration<SnmpMibAgent> e= mibs.elements(); e.hasMoreElements(); ) { 1013 final SnmpMibAgent ag= e.nextElement(); 1014 subs.put(ag, new SnmpSubNextRequestHandler(adaptor, ag, req)); 1015 } 1016 return; 1017 } 1018 1019 int nbReqs= req.varBindList.length; 1020 SnmpVarBind[] vars= req.varBindList; 1021 SnmpSubRequestHandler sub; 1022 for(int i=0; i < nbReqs; i++) { 1023 agent= root.getAgentMib(vars[i].oid); 1024 sub= subs.get(agent); 1025 if (sub == null) { 1026 // We need to create the sub request handler and update 1027 // the hashtable 1028 // 1029 sub= new SnmpSubRequestHandler(agent, req); 1030 subs.put(agent, sub); 1031 } 1032 1033 // Update the translation table within the subrequest 1034 // 1035 sub.updateRequest(vars[i], i); 1036 } 1037 } 1038 1039 /** 1040 * The method takes the incoming get bulk requests and split it into 1041 * subrequests. 1042 */ 1043 private void splitBulkRequest(SnmpPduBulk req, 1044 int nonRepeaters, 1045 int maxRepetitions, 1046 int R) { 1047 // Send the getBulk to all agents 1048 // 1049 for(Enumeration<SnmpMibAgent> e= mibs.elements(); e.hasMoreElements(); ) { 1050 final SnmpMibAgent agent = e.nextElement(); 1051 1052 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { 1053 SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, 1054 "splitBulkRequest", "Create a sub with : " + agent + " " + nonRepeaters 1055 + " " + maxRepetitions + " " + R); 1056 } 1057 1058 subs.put(agent, 1059 new SnmpSubBulkRequestHandler(adaptor, 1060 agent, 1061 req, 1062 nonRepeaters, 1063 maxRepetitions, 1064 R)); 1065 } 1066 } 1067 1068 private SnmpPduPacket mergeResponses(SnmpPduRequest req) { 1069 1070 if (req.type == pduGetNextRequestPdu) { 1071 return mergeNextResponses(req); 1072 } 1073 1074 SnmpVarBind[] result= req.varBindList; 1075 1076 // Go through the list of subrequests and concatenate. 1077 // Hopefully, by now all the sub-requests should be finished 1078 // 1079 for(Enumeration<SnmpSubRequestHandler> e= subs.elements(); e.hasMoreElements();) { 1080 SnmpSubRequestHandler sub= e.nextElement(); 1081 sub.updateResult(result); 1082 } 1083 return newValidResponsePdu(req,result); 1084 } 1085 1086 private SnmpPduPacket mergeNextResponses(SnmpPduRequest req) { 1087 int max= req.varBindList.length; 1088 SnmpVarBind[] result= new SnmpVarBind[max]; 1089 1090 // Go through the list of subrequests and concatenate. 1091 // Hopefully, by now all the sub-requests should be finished 1092 // 1093 for(Enumeration<SnmpSubRequestHandler> e= subs.elements(); e.hasMoreElements();) { 1094 SnmpSubRequestHandler sub= e.nextElement(); 1095 sub.updateResult(result); 1096 } 1097 1098 if (req.version == snmpVersionTwo) { 1099 return newValidResponsePdu(req,result); 1100 } 1101 1102 // In v1 make sure there is no endOfMibView ... 1103 // 1104 for(int i=0; i < max; i++) { 1105 SnmpValue val= result[i].value; 1106 if (val == SnmpVarBind.endOfMibView) 1107 return newErrorResponsePdu(req, 1108 SnmpDefinitions.snmpRspNoSuchName, i+1); 1109 } 1110 1111 // So far so good ... 1112 // 1113 return newValidResponsePdu(req,result); 1114 } 1115 1116 private SnmpVarBind[] mergeBulkResponses(int size) { 1117 // Let's allocate the array for storing the result 1118 // 1119 SnmpVarBind[] result= new SnmpVarBind[size]; 1120 for(int i= size-1; i >=0; --i) { 1121 result[i]= new SnmpVarBind(); 1122 result[i].value= SnmpVarBind.endOfMibView; 1123 } 1124 1125 // Go through the list of subrequests and concatenate. 1126 // Hopefully, by now all the sub-requests should be finished 1127 // 1128 for(Enumeration<SnmpSubRequestHandler> e= subs.elements(); e.hasMoreElements();) { 1129 SnmpSubRequestHandler sub= e.nextElement(); 1130 sub.updateResult(result); 1131 } 1132 1133 return result; 1134 } 1135 1136 @Override 1137 protected String makeDebugTag() { 1138 return "SnmpRequestHandler[" + adaptorServer.getProtocol() + ":" + 1139 adaptorServer.getPort() + "]"; 1140 } 1141 1142 @Override 1143 Thread createThread(Runnable r) { 1144 return null; 1145 } 1146 1147 static final private String InterruptSysCallMsg = 1148 "Interrupted system call"; 1149 }