📄 snmpbercodec.java
字号:
/*
* SNMP Package
*
* Copyright (C) 2004, Jonathan Sevy <jsevy@mcs.drexel.edu>
*
* This is free software. Redistribution and use in source and binary forms, with
* or without modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
package snmp;
import java.io.*;
/**
* SNMPBERCodec defines methods for converting from ASN.1 BER encoding to SNMPObject subclasses. The extraction
* process usually produces a tree structure of objects with an SNMPSequence object at the root; this
* is the usual behavior when a received encoded message is received from an SNMP device.
*/
public class SNMPBERCodec
{
public static final byte SNMPINTEGER = 0x02;
public static final byte SNMPBITSTRING = 0x03;
public static final byte SNMPOCTETSTRING = 0x04;
public static final byte SNMPNULL = 0x05;
public static final byte SNMPOBJECTIDENTIFIER = 0x06;
public static final byte SNMPSEQUENCE = 0x30;
public static final byte SNMPIPADDRESS = (byte)0x40;
public static final byte SNMPCOUNTER32 = (byte)0x41;
public static final byte SNMPGAUGE32 = (byte)0x42;
public static final byte SNMPTIMETICKS = (byte)0x43;
public static final byte SNMPOPAQUE = (byte)0x44;
public static final byte SNMPNSAPADDRESS = (byte)0x45;
public static final byte SNMPCOUNTER64 = (byte)0x46;
public static final byte SNMPUINTEGER32 = (byte)0x47;
public static final byte SNMPGETREQUEST = (byte)0xA0;
public static final byte SNMPGETNEXTREQUEST = (byte)0xA1;
public static final byte SNMPGETRESPONSE = (byte)0xA2;
public static final byte SNMPSETREQUEST = (byte)0xA3;
public static final byte SNMPTRAP = (byte)0xA4;
// SNMPv2 constants
public static final byte SNMPv2pCOMMUNICATION = (byte)0xA2;
public static final byte SNMPv2pAUTHORIZEDMESSAGE = (byte)0xA1;
public static final byte SNMPv2pENCRYPTEDMESSAGE = (byte)0xA1;
public static final byte SNMPv2BULKREQUEST = (byte)0xA5;
public static final byte SNMPv2INFORMREQUEST = (byte)0xA6;
public static final byte SNMPv2TRAP = (byte)0xA7;
public static final byte SNMPv2pENCRYPTEDDATA = (byte)0xA1;
public static final byte SNMPUNKNOWNOBJECT = 0x00;
/**
* Extracts an SNMP object given its type, length, value triple as an SNMPTLV object.
* Called by SNMPObject subclass constructors.
* @throws SNMPBadValueException Indicates byte array in value field is uninterprettable for
* specified SNMP object type.
*/
public static SNMPObject extractEncoding(SNMPTLV theTLV)
throws SNMPBadValueException
{
switch (theTLV.tag)
{
case SNMPINTEGER:
{
return new SNMPInteger(theTLV.value);
}
case SNMPSEQUENCE:
{
return new SNMPSequence(theTLV.value);
}
case SNMPOBJECTIDENTIFIER:
{
return new SNMPObjectIdentifier(theTLV.value);
}
case SNMPOCTETSTRING:
{
return new SNMPOctetString(theTLV.value);
}
case SNMPBITSTRING:
{
return new SNMPBitString(theTLV.value);
}
case SNMPIPADDRESS:
{
return new SNMPIPAddress(theTLV.value);
}
case SNMPCOUNTER32:
{
return new SNMPCounter32(theTLV.value);
}
case SNMPGAUGE32:
{
return new SNMPGauge32(theTLV.value);
}
case SNMPTIMETICKS:
{
return new SNMPTimeTicks(theTLV.value);
}
case SNMPNSAPADDRESS:
{
return new SNMPNSAPAddress(theTLV.value);
}
case SNMPCOUNTER64:
{
return new SNMPCounter64(theTLV.value);
}
case SNMPUINTEGER32:
{
return new SNMPUInteger32(theTLV.value);
}
case SNMPGETREQUEST:
case SNMPGETNEXTREQUEST:
case SNMPGETRESPONSE:
case SNMPSETREQUEST:
{
return new SNMPPDU(theTLV.value, theTLV.tag);
}
case SNMPTRAP:
{
return new SNMPv1TrapPDU(theTLV.value);
}
case SNMPv2TRAP:
{
return new SNMPv2TrapPDU(theTLV.value);
}
case SNMPv2INFORMREQUEST:
{
return new SNMPv2InformRequestPDU(theTLV.value);
}
case SNMPNULL:
case SNMPOPAQUE:
{
return new SNMPNull();
}
default:
{
//System.out.println("Unrecognized tag");
//return new SNMPOctetString(theTLV.value);
return new SNMPUnknownObject(theTLV.value);
}
}
}
/**
* Extracts the type, length and value of the SNMP object whose BER encoding begins at the
* specified position in the given byte array. Throws an SNMPBadValueException if there's
* any problem with the extraction.
*/
public static SNMPTLV extractNextTLV(byte[] enc, int position)
throws SNMPBadValueException
{
SNMPTLV nextTLV = new SNMPTLV();
int currentPos = position;
try
{
// get tag
/*
if ((enc[currentPos] % 32) < 31)
{
// single byte tag; extract value
nextTLV.tag = (int)(enc[currentPos]);
}
else
{
// multiple byte tag; for now, just return value in subsequent bytes ...
// but need to think about universal / application fields, etc...
nextTLV.tag = 0;
do
{
currentPos++;
nextTLV.tag = nextTLV.tag * 128 + (int)(enc[currentPos] % 128);
}
while ((enc[currentPos]/128) >= 1);
}
*/
// single byte tag; extract value
nextTLV.tag = enc[currentPos];
currentPos++; // now at start of length info
// get length of data
int dataLength;
int unsignedValue = enc[currentPos];
if (unsignedValue < 0)
unsignedValue += 256;
if ((unsignedValue / 128) < 1)
{
// single byte length; extract value
dataLength = unsignedValue;
}
else
{
// multiple byte length; first byte's value (minus first bit) is # of length bytes
int numBytes = (unsignedValue % 128);
dataLength = 0;
for (int i = 0; i < numBytes; i++)
{
currentPos++;
unsignedValue = enc[currentPos];
if (unsignedValue < 0)
unsignedValue += 256;
dataLength = dataLength * 256 + unsignedValue;
}
}
currentPos++; // now at start of data
// set total length
nextTLV.totalLength = currentPos - position + dataLength;
// extract data portion
ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
outBytes.write(enc, currentPos, dataLength);
nextTLV.value = outBytes.toByteArray();
return nextTLV;
}
catch (IndexOutOfBoundsException e)
{
// whatever the exception, throw an SNMPBadValueException
throw new SNMPBadValueException("Problem while decoding SNMP: packet truncated or corrupt");
}
catch (Exception e)
{
// whatever the exception, throw an SNMPBadValueException
throw new SNMPBadValueException("Problem while decoding SNMP");
}
}
/**
* Utility function for encoding a length as a BER byte sequence
*/
public static byte[] encodeLength(int length)
{
ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
// see if can be represented in single byte
// don't forget the first bit is the "long field test" bit!!
if (length < 128)
{
byte[] len = {(byte)length};
outBytes.write(len, 0, 1);
}
else
{
// too big for one byte
// see how many are needed:
int numBytes = 0;
int temp = length;
while (temp > 0)
{
++numBytes;
temp = (int)Math.floor(temp / 256);
}
byte num = (byte)numBytes;
num += 128; // set the "long format" bit
outBytes.write(num);
byte[] len = new byte[numBytes];
for (int i = numBytes-1; i >= 0; --i)
{
len[i] = (byte)(length % 256);
length = (int)Math.floor(length / 256);
}
outBytes.write(len, 0, numBytes);
}
return outBytes.toByteArray();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -