1 /* 2 * Copyright (c) 2001, 2006, 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 package com.sun.jmx.snmp; 27 28 import com.sun.jmx.snmp.SnmpSecurityParameters; 29 // java imports 30 // 31 import java.util.Vector; 32 import java.net.InetAddress; 33 34 35 import com.sun.jmx.snmp.SnmpStatusException; 36 /** 37 * A partially decoded representation of an SNMP packet. It contains 38 * the information contained in any SNMP message (SNMPv1, SNMPv2 or 39 * SNMPv3). 40 * <p><b>This API is a Sun Microsystems internal API and is subject 41 * to change without notice.</b></p> 42 * @since 1.5 43 */ 44 public abstract class SnmpMsg implements SnmpDefinitions { 45 /** 46 * The protocol version. 47 * <P><CODE>decodeMessage</CODE> and <CODE>encodeMessage</CODE> do not 48 * perform any check on this value. 49 * <BR><CODE>decodeSnmpPdu</CODE> and <CODE>encodeSnmpPdu</CODE> only 50 * accept the values 0 (for SNMPv1), 1 (for SNMPv2) and 3 (for SNMPv3). 51 */ 52 public int version = 0; 53 54 /** 55 * Encoding of the PDU. 56 * <P>This is usually the BER encoding of the PDU's syntax 57 * defined in RFC1157 and RFC1902. However, this can be authenticated 58 * or encrypted data (but you need to implemented your own 59 * <CODE>SnmpPduFactory</CODE> class). 60 */ 61 public byte[] data = null; 62 63 /** 64 * Number of useful bytes in the <CODE>data</CODE> field. 65 */ 66 public int dataLength = 0; 67 68 /** 69 * Source or destination address. 70 * <BR>For an incoming message it's the source. 71 * For an outgoing message it's the destination. 72 */ 73 public InetAddress address = null; 74 75 /** 76 * Source or destination port. 77 * <BR>For an incoming message it's the source. 78 * For an outgoing message it's the destination. 79 */ 80 public int port = 0; 81 /** 82 * Security parameters. Contain informations according to Security Model (Usm, community string based, ...). 83 */ 84 public SnmpSecurityParameters securityParameters = null; 85 /** 86 * Returns the encoded SNMP version present in the passed byte array. 87 * @param data The unmarshalled SNMP message. 88 * @return The SNMP version (0, 1 or 3). 89 */ getProtocolVersion(byte[] data)90 public static int getProtocolVersion(byte[] data) 91 throws SnmpStatusException { 92 int version = 0; 93 BerDecoder bdec = null; 94 try { 95 bdec = new BerDecoder(data); 96 bdec.openSequence(); 97 version = bdec.fetchInteger(); 98 } 99 catch(BerException x) { 100 throw new SnmpStatusException("Invalid encoding") ; 101 } 102 try { 103 bdec.closeSequence(); 104 } 105 catch(BerException x) { 106 } 107 return version; 108 } 109 110 /** 111 * Returns the associated request ID. 112 * @param data The flat message. 113 * @return The request ID. 114 */ getRequestId(byte[] data)115 public abstract int getRequestId(byte[] data) throws SnmpStatusException; 116 117 /** 118 * Encodes this message and puts the result in the specified byte array. 119 * For internal use only. 120 * 121 * @param outputBytes An array to receive the resulting encoding. 122 * 123 * @exception ArrayIndexOutOfBoundsException If the result does not fit 124 * into the specified array. 125 */ encodeMessage(byte[] outputBytes)126 public abstract int encodeMessage(byte[] outputBytes) 127 throws SnmpTooBigException; 128 129 /** 130 * Decodes the specified bytes and initializes this message. 131 * For internal use only. 132 * 133 * @param inputBytes The bytes to be decoded. 134 * 135 * @exception SnmpStatusException If the specified bytes are not a valid encoding. 136 */ decodeMessage(byte[] inputBytes, int byteCount)137 public abstract void decodeMessage(byte[] inputBytes, int byteCount) 138 throws SnmpStatusException; 139 140 /** 141 * Initializes this message with the specified <CODE>pdu</CODE>. 142 * <P> 143 * This method initializes the data field with an array of 144 * <CODE>maxDataLength</CODE> bytes. It encodes the <CODE>pdu</CODE>. 145 * The resulting encoding is stored in the data field 146 * and the length of the encoding is stored in <CODE>dataLength</CODE>. 147 * <p> 148 * If the encoding length exceeds <CODE>maxDataLength</CODE>, 149 * the method throws an exception. 150 * 151 * @param pdu The PDU to be encoded. 152 * @param maxDataLength The maximum length permitted for the data field. 153 * 154 * @exception SnmpStatusException If the specified <CODE>pdu</CODE> is not valid. 155 * @exception SnmpTooBigException If the resulting encoding does not fit 156 * into <CODE>maxDataLength</CODE> bytes. 157 * @exception ArrayIndexOutOfBoundsException If the encoding exceeds <CODE>maxDataLength</CODE>. 158 */ encodeSnmpPdu(SnmpPdu pdu, int maxDataLength)159 public abstract void encodeSnmpPdu(SnmpPdu pdu, int maxDataLength) 160 throws SnmpStatusException, SnmpTooBigException; 161 162 163 /** 164 * Gets the PDU encoded in this message. 165 * <P> 166 * This method decodes the data field and returns the resulting PDU. 167 * 168 * @return The resulting PDU. 169 * @exception SnmpStatusException If the encoding is not valid. 170 */ decodeSnmpPdu()171 public abstract SnmpPdu decodeSnmpPdu() 172 throws SnmpStatusException; 173 174 /** 175 * Dumps the content of a byte buffer using hexadecimal form. 176 * 177 * @param b The buffer to dump. 178 * @param offset The position of the first byte to be dumped. 179 * @param len The number of bytes to be dumped starting from offset. 180 * 181 * @return The string containing the dump. 182 */ dumpHexBuffer(byte [] b, int offset, int len)183 public static String dumpHexBuffer(byte [] b, int offset, int len) { 184 StringBuffer buf = new StringBuffer(len << 1) ; 185 int k = 1 ; 186 int flen = offset + len ; 187 188 for (int i = offset; i < flen ; i++) { 189 int j = b[i] & 0xFF ; 190 buf.append(Character.forDigit((j >>> 4) , 16)) ; 191 buf.append(Character.forDigit((j & 0x0F), 16)) ; 192 k++ ; 193 if (k%16 == 0) { 194 buf.append('\n') ; 195 k = 1 ; 196 } else 197 buf.append(' ') ; 198 } 199 return buf.toString() ; 200 } 201 202 /** 203 * Dumps this message in a string. 204 * 205 * @return The string containing the dump. 206 */ printMessage()207 public String printMessage() { 208 StringBuffer sb = new StringBuffer() ; 209 sb.append("Version: ") ; 210 sb.append(version) ; 211 sb.append("\n") ; 212 if (data == null) { 213 sb.append("Data: null") ; 214 } 215 else { 216 sb.append("Data: {\n") ; 217 sb.append(dumpHexBuffer(data, 0, dataLength)) ; 218 sb.append("\n}\n") ; 219 } 220 221 return sb.toString() ; 222 } 223 224 /** 225 * For SNMP Runtime private use only. 226 */ encodeVarBindList(BerEncoder benc, SnmpVarBind[] varBindList)227 public void encodeVarBindList(BerEncoder benc, 228 SnmpVarBind[] varBindList) 229 throws SnmpStatusException, SnmpTooBigException { 230 // 231 // Remember: the encoder does backward encoding 232 // 233 int encodedVarBindCount = 0 ; 234 try { 235 benc.openSequence() ; 236 if (varBindList != null) { 237 for (int i = varBindList.length - 1 ; i >= 0 ; i--) { 238 SnmpVarBind bind = varBindList[i] ; 239 if (bind != null) { 240 benc.openSequence() ; 241 encodeVarBindValue(benc, bind.value) ; 242 benc.putOid(bind.oid.longValue()) ; 243 benc.closeSequence() ; 244 encodedVarBindCount++ ; 245 } 246 } 247 } 248 benc.closeSequence() ; 249 } 250 catch(ArrayIndexOutOfBoundsException x) { 251 throw new SnmpTooBigException(encodedVarBindCount) ; 252 } 253 } 254 255 /** 256 * For SNMP Runtime private use only. 257 */ encodeVarBindValue(BerEncoder benc, SnmpValue v)258 void encodeVarBindValue(BerEncoder benc, 259 SnmpValue v)throws SnmpStatusException { 260 if (v == null) { 261 benc.putNull() ; 262 } 263 else if (v instanceof SnmpIpAddress) { 264 benc.putOctetString(((SnmpIpAddress)v).byteValue(), SnmpValue.IpAddressTag) ; 265 } 266 else if (v instanceof SnmpCounter) { 267 benc.putInteger(((SnmpCounter)v).longValue(), SnmpValue.CounterTag) ; 268 } 269 else if (v instanceof SnmpGauge) { 270 benc.putInteger(((SnmpGauge)v).longValue(), SnmpValue.GaugeTag) ; 271 } 272 else if (v instanceof SnmpTimeticks) { 273 benc.putInteger(((SnmpTimeticks)v).longValue(), SnmpValue.TimeticksTag) ; 274 } 275 else if (v instanceof SnmpOpaque) { 276 benc.putOctetString(((SnmpOpaque)v).byteValue(), SnmpValue.OpaqueTag) ; 277 } 278 else if (v instanceof SnmpInt) { 279 benc.putInteger(((SnmpInt)v).intValue()) ; 280 } 281 else if (v instanceof SnmpString) { 282 benc.putOctetString(((SnmpString)v).byteValue()) ; 283 } 284 else if (v instanceof SnmpOid) { 285 benc.putOid(((SnmpOid)v).longValue()) ; 286 } 287 else if (v instanceof SnmpCounter64) { 288 if (version == snmpVersionOne) { 289 throw new SnmpStatusException("Invalid value for SNMP v1 : " + v) ; 290 } 291 benc.putInteger(((SnmpCounter64)v).longValue(), SnmpValue.Counter64Tag) ; 292 } 293 else if (v instanceof SnmpNull) { 294 int tag = ((SnmpNull)v).getTag() ; 295 if ((version == snmpVersionOne) && (tag != SnmpValue.NullTag)) { 296 throw new SnmpStatusException("Invalid value for SNMP v1 : " + v) ; 297 } 298 if ((version == snmpVersionTwo) && 299 (tag != SnmpValue.NullTag) && 300 (tag != SnmpVarBind.errNoSuchObjectTag) && 301 (tag != SnmpVarBind.errNoSuchInstanceTag) && 302 (tag != SnmpVarBind.errEndOfMibViewTag)) { 303 throw new SnmpStatusException("Invalid value " + v) ; 304 } 305 benc.putNull(tag) ; 306 } 307 else { 308 throw new SnmpStatusException("Invalid value " + v) ; 309 } 310 311 } 312 313 314 /** 315 * For SNMP Runtime private use only. 316 */ decodeVarBindList(BerDecoder bdec)317 public SnmpVarBind[] decodeVarBindList(BerDecoder bdec) 318 throws BerException { 319 bdec.openSequence() ; 320 Vector<SnmpVarBind> tmp = new Vector<SnmpVarBind>() ; 321 while (bdec.cannotCloseSequence()) { 322 SnmpVarBind bind = new SnmpVarBind() ; 323 bdec.openSequence() ; 324 bind.oid = new SnmpOid(bdec.fetchOid()) ; 325 bind.setSnmpValue(decodeVarBindValue(bdec)) ; 326 bdec.closeSequence() ; 327 tmp.addElement(bind) ; 328 } 329 bdec.closeSequence() ; 330 SnmpVarBind[] varBindList= new SnmpVarBind[tmp.size()] ; 331 tmp.copyInto(varBindList); 332 return varBindList ; 333 } 334 335 336 /** 337 * For SNMP Runtime private use only. 338 */ decodeVarBindValue(BerDecoder bdec)339 SnmpValue decodeVarBindValue(BerDecoder bdec) 340 throws BerException { 341 SnmpValue result = null ; 342 int tag = bdec.getTag() ; 343 344 // bugId 4641696 : RuntimeExceptions must be transformed in 345 // BerException. 346 switch(tag) { 347 348 // 349 // Simple syntax 350 // 351 case BerDecoder.IntegerTag : 352 try { 353 result = new SnmpInt(bdec.fetchInteger()) ; 354 } catch(RuntimeException r) { 355 throw new BerException(); 356 // BerException("Can't build SnmpInt from decoded value."); 357 } 358 break ; 359 case BerDecoder.OctetStringTag : 360 try { 361 result = new SnmpString(bdec.fetchOctetString()) ; 362 } catch(RuntimeException r) { 363 throw new BerException(); 364 // BerException("Can't build SnmpString from decoded value."); 365 } 366 break ; 367 case BerDecoder.OidTag : 368 try { 369 result = new SnmpOid(bdec.fetchOid()) ; 370 } catch(RuntimeException r) { 371 throw new BerException(); 372 // BerException("Can't build SnmpOid from decoded value."); 373 } 374 break ; 375 case BerDecoder.NullTag : 376 bdec.fetchNull() ; 377 try { 378 result = new SnmpNull() ; 379 } catch(RuntimeException r) { 380 throw new BerException(); 381 // BerException("Can't build SnmpNull from decoded value."); 382 } 383 break ; 384 385 // 386 // Application syntax 387 // 388 case SnmpValue.IpAddressTag : 389 try { 390 result = new SnmpIpAddress(bdec.fetchOctetString(tag)) ; 391 } catch (RuntimeException r) { 392 throw new BerException(); 393 // BerException("Can't build SnmpIpAddress from decoded value."); 394 } 395 break ; 396 case SnmpValue.CounterTag : 397 try { 398 result = new SnmpCounter(bdec.fetchIntegerAsLong(tag)) ; 399 } catch(RuntimeException r) { 400 throw new BerException(); 401 // BerException("Can't build SnmpCounter from decoded value."); 402 } 403 break ; 404 case SnmpValue.GaugeTag : 405 try { 406 result = new SnmpGauge(bdec.fetchIntegerAsLong(tag)) ; 407 } catch(RuntimeException r) { 408 throw new BerException(); 409 // BerException("Can't build SnmpGauge from decoded value."); 410 } 411 break ; 412 case SnmpValue.TimeticksTag : 413 try { 414 result = new SnmpTimeticks(bdec.fetchIntegerAsLong(tag)) ; 415 } catch(RuntimeException r) { 416 throw new BerException(); 417 // BerException("Can't build SnmpTimeticks from decoded value."); 418 } 419 break ; 420 case SnmpValue.OpaqueTag : 421 try { 422 result = new SnmpOpaque(bdec.fetchOctetString(tag)) ; 423 } catch(RuntimeException r) { 424 throw new BerException(); 425 // BerException("Can't build SnmpOpaque from decoded value."); 426 } 427 break ; 428 429 // 430 // V2 syntaxes 431 // 432 case SnmpValue.Counter64Tag : 433 if (version == snmpVersionOne) { 434 throw new BerException(BerException.BAD_VERSION) ; 435 } 436 try { 437 result = new SnmpCounter64(bdec.fetchIntegerAsLong(tag)) ; 438 } catch(RuntimeException r) { 439 throw new BerException(); 440 // BerException("Can't build SnmpCounter64 from decoded value."); 441 } 442 break ; 443 444 case SnmpVarBind.errNoSuchObjectTag : 445 if (version == snmpVersionOne) { 446 throw new BerException(BerException.BAD_VERSION) ; 447 } 448 bdec.fetchNull(tag) ; 449 result = SnmpVarBind.noSuchObject ; 450 break ; 451 452 case SnmpVarBind.errNoSuchInstanceTag : 453 if (version == snmpVersionOne) { 454 throw new BerException(BerException.BAD_VERSION) ; 455 } 456 bdec.fetchNull(tag) ; 457 result = SnmpVarBind.noSuchInstance ; 458 break ; 459 460 case SnmpVarBind.errEndOfMibViewTag : 461 if (version == snmpVersionOne) { 462 throw new BerException(BerException.BAD_VERSION) ; 463 } 464 bdec.fetchNull(tag) ; 465 result = SnmpVarBind.endOfMibView ; 466 break ; 467 468 default: 469 throw new BerException() ; 470 471 } 472 473 return result ; 474 } 475 476 } 477