001: /*
002: * SNMP Package
003: *
004: * Copyright (C) 2004, Jonathan Sevy <jsevy@mcs.drexel.edu>
005: *
006: * This is free software. Redistribution and use in source and binary forms, with
007: * or without modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright notice, this
011: * list of conditions and the following disclaimer.
012: * 2. Redistributions in binary form must reproduce the above copyright notice,
013: * this list of conditions and the following disclaimer in the documentation
014: * and/or other materials provided with the distribution.
015: * 3. The name of the author may not be used to endorse or promote products
016: * derived from this software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
019: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
020: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
021: * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
022: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
023: * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
024: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
025: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
026: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: *
028: */
029:
030: package snmp;
031:
032: import java.io.*;
033:
034: /**
035: * SNMPBERCodec defines methods for converting from ASN.1 BER encoding to SNMPObject subclasses. The extraction
036: * process usually produces a tree structure of objects with an SNMPSequence object at the root; this
037: * is the usual behavior when a received encoded message is received from an SNMP device.
038: */
039:
040: public class SNMPBERCodec {
041:
042: public static final byte SNMPINTEGER = 0x02;
043: public static final byte SNMPBITSTRING = 0x03;
044: public static final byte SNMPOCTETSTRING = 0x04;
045: public static final byte SNMPNULL = 0x05;
046: public static final byte SNMPOBJECTIDENTIFIER = 0x06;
047: public static final byte SNMPSEQUENCE = 0x30;
048:
049: public static final byte SNMPIPADDRESS = (byte) 0x40;
050: public static final byte SNMPCOUNTER32 = (byte) 0x41;
051: public static final byte SNMPGAUGE32 = (byte) 0x42;
052: public static final byte SNMPTIMETICKS = (byte) 0x43;
053: public static final byte SNMPOPAQUE = (byte) 0x44;
054: public static final byte SNMPNSAPADDRESS = (byte) 0x45;
055: public static final byte SNMPCOUNTER64 = (byte) 0x46;
056: public static final byte SNMPUINTEGER32 = (byte) 0x47;
057:
058: public static final byte SNMPGETREQUEST = (byte) 0xA0;
059: public static final byte SNMPGETNEXTREQUEST = (byte) 0xA1;
060: public static final byte SNMPGETRESPONSE = (byte) 0xA2;
061: public static final byte SNMPSETREQUEST = (byte) 0xA3;
062: public static final byte SNMPTRAP = (byte) 0xA4;
063:
064: // SNMPv2 constants
065: public static final byte SNMPv2pCOMMUNICATION = (byte) 0xA2;
066: public static final byte SNMPv2pAUTHORIZEDMESSAGE = (byte) 0xA1;
067: public static final byte SNMPv2pENCRYPTEDMESSAGE = (byte) 0xA1;
068: public static final byte SNMPv2BULKREQUEST = (byte) 0xA5;
069: public static final byte SNMPv2INFORMREQUEST = (byte) 0xA6;
070: public static final byte SNMPv2TRAP = (byte) 0xA7;
071:
072: public static final byte SNMPv2pENCRYPTEDDATA = (byte) 0xA1;
073:
074: public static final byte SNMPUNKNOWNOBJECT = 0x00;
075:
076: /**
077: * Extracts an SNMP object given its type, length, value triple as an SNMPTLV object.
078: * Called by SNMPObject subclass constructors.
079: * @throws SNMPBadValueException Indicates byte array in value field is uninterprettable for
080: * specified SNMP object type.
081: */
082: public static SNMPObject extractEncoding(SNMPTLV theTLV)
083: throws SNMPBadValueException {
084:
085: switch (theTLV.tag) {
086: case SNMPINTEGER: {
087: return new SNMPInteger(theTLV.value);
088: }
089:
090: case SNMPSEQUENCE: {
091: return new SNMPSequence(theTLV.value);
092: }
093:
094: case SNMPOBJECTIDENTIFIER: {
095: return new SNMPObjectIdentifier(theTLV.value);
096: }
097:
098: case SNMPOCTETSTRING: {
099: return new SNMPOctetString(theTLV.value);
100: }
101:
102: case SNMPBITSTRING: {
103: return new SNMPBitString(theTLV.value);
104: }
105:
106: case SNMPIPADDRESS: {
107: return new SNMPIPAddress(theTLV.value);
108: }
109:
110: case SNMPCOUNTER32: {
111: return new SNMPCounter32(theTLV.value);
112: }
113:
114: case SNMPGAUGE32: {
115: return new SNMPGauge32(theTLV.value);
116: }
117:
118: case SNMPTIMETICKS: {
119: return new SNMPTimeTicks(theTLV.value);
120: }
121:
122: case SNMPNSAPADDRESS: {
123: return new SNMPNSAPAddress(theTLV.value);
124: }
125:
126: case SNMPCOUNTER64: {
127: return new SNMPCounter64(theTLV.value);
128: }
129:
130: case SNMPUINTEGER32: {
131: return new SNMPUInteger32(theTLV.value);
132: }
133:
134: case SNMPGETREQUEST:
135: case SNMPGETNEXTREQUEST:
136: case SNMPGETRESPONSE:
137: case SNMPSETREQUEST: {
138: return new SNMPPDU(theTLV.value, theTLV.tag);
139: }
140:
141: case SNMPTRAP: {
142: return new SNMPv1TrapPDU(theTLV.value);
143: }
144:
145: case SNMPv2TRAP: {
146: return new SNMPv2TrapPDU(theTLV.value);
147: }
148:
149: case SNMPv2INFORMREQUEST: {
150: return new SNMPv2InformRequestPDU(theTLV.value);
151: }
152:
153: case SNMPNULL:
154: case SNMPOPAQUE: {
155: return new SNMPNull();
156: }
157:
158: default: {
159: //System.out.println("Unrecognized tag");
160: //return new SNMPOctetString(theTLV.value);
161: return new SNMPUnknownObject(theTLV.value);
162: }
163: }
164:
165: }
166:
167: /**
168: * Extracts the type, length and value of the SNMP object whose BER encoding begins at the
169: * specified position in the given byte array. Throws an SNMPBadValueException if there's
170: * any problem with the extraction.
171: */
172:
173: public static SNMPTLV extractNextTLV(byte[] enc, int position)
174: throws SNMPBadValueException {
175: SNMPTLV nextTLV = new SNMPTLV();
176: int currentPos = position;
177:
178: try {
179:
180: // get tag
181:
182: /*
183: if ((enc[currentPos] % 32) < 31)
184: {
185: // single byte tag; extract value
186: nextTLV.tag = (int)(enc[currentPos]);
187: }
188: else
189: {
190: // multiple byte tag; for now, just return value in subsequent bytes ...
191: // but need to think about universal / application fields, etc...
192: nextTLV.tag = 0;
193:
194: do
195: {
196: currentPos++;
197: nextTLV.tag = nextTLV.tag * 128 + (int)(enc[currentPos] % 128);
198: }
199: while ((enc[currentPos]/128) >= 1);
200: }
201: */
202:
203: // single byte tag; extract value
204: nextTLV.tag = enc[currentPos];
205: currentPos++; // now at start of length info
206:
207: // get length of data
208:
209: int dataLength;
210:
211: int unsignedValue = enc[currentPos];
212: if (unsignedValue < 0)
213: unsignedValue += 256;
214:
215: if ((unsignedValue / 128) < 1) {
216: // single byte length; extract value
217: dataLength = unsignedValue;
218: } else {
219: // multiple byte length; first byte's value (minus first bit) is # of length bytes
220: int numBytes = (unsignedValue % 128);
221:
222: dataLength = 0;
223:
224: for (int i = 0; i < numBytes; i++) {
225: currentPos++;
226: unsignedValue = enc[currentPos];
227: if (unsignedValue < 0)
228: unsignedValue += 256;
229: dataLength = dataLength * 256 + unsignedValue;
230: }
231: }
232:
233: currentPos++; // now at start of data
234:
235: // set total length
236: nextTLV.totalLength = currentPos - position + dataLength;
237:
238: // extract data portion
239:
240: ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
241: outBytes.write(enc, currentPos, dataLength);
242: nextTLV.value = outBytes.toByteArray();
243:
244: return nextTLV;
245:
246: } catch (IndexOutOfBoundsException e) {
247: // whatever the exception, throw an SNMPBadValueException
248: throw new SNMPBadValueException(
249: "Problem while decoding SNMP: packet truncated or corrupt");
250: } catch (Exception e) {
251: // whatever the exception, throw an SNMPBadValueException
252: throw new SNMPBadValueException(
253: "Problem while decoding SNMP");
254: }
255:
256: }
257:
258: /**
259: * Utility function for encoding a length as a BER byte sequence
260: */
261:
262: public static byte[] encodeLength(int length) {
263: ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
264:
265: // see if can be represented in single byte
266: // don't forget the first bit is the "long field test" bit!!
267: if (length < 128) {
268: byte[] len = { (byte) length };
269: outBytes.write(len, 0, 1);
270: } else {
271: // too big for one byte
272: // see how many are needed:
273: int numBytes = 0;
274: int temp = length;
275: while (temp > 0) {
276: ++numBytes;
277: temp = (int) Math.floor(temp / 256);
278: }
279:
280: byte num = (byte) numBytes;
281: num += 128; // set the "long format" bit
282: outBytes.write(num);
283:
284: byte[] len = new byte[numBytes];
285: for (int i = numBytes - 1; i >= 0; --i) {
286: len[i] = (byte) (length % 256);
287: length = (int) Math.floor(length / 256);
288: }
289: outBytes.write(len, 0, numBytes);
290:
291: }
292:
293: return outBytes.toByteArray();
294: }
295:
296: }
|