Simple SNMP Query Tool - Open Source - C# (C-sharp)
SNMP packet structure
// Author: Toomas Kaljus
// http://www.digigrupp.com
namespace DG
{
public enum SnmpType
{
Boolean = 0x01,
Integer = 0x02,
BitString = 0x03,
OctetString = 0x04,
Null = 0x05,
ObjectIdentifier = 0x06,
Sequence = 0x30,
IPAddress = 0x40,
Counter32 = 0x41,
Gauge = 0x42,
TimeTicks = 0x43,
Opaque = 0x44,
NetAddress = 0x45,
Counter64 = 0x46,
UInt32 = 0x47,
GetRequestPDU = 0xa0,
GetNextRequestPDU = 0xa1,
GetResponsePDU = 0xa2,
SetRequestPDU = 0xa3,
TrapPDUv1 = 0xa4,
GetBulkRequest = 0xa5,
InformRequest = 0xa6,
TrapPDUv2 = 0xa7
}
public class SNMPPacket
{
public long Version;
public string Community;
public SnmpType PacketType;
public long RequestID;
public long Error;
public long Index;
public string ObjectID;
public SnmpType ValueType;
public object Value;
public SNMPPacket() : base() { }
// commonly used snmp type constants
public SNMPPacket(ref byte[] Packet)
: base()
{
try
{
int Pos = 0;
GetSNMPSequence(ref Packet, ref Pos, (byte)SnmpType.Sequence);
Version = GetSNMPInteger(ref Packet, ref Pos);
Community = GetSNMPString(ref Packet, ref Pos);
GetSNMPSequence(ref Packet, ref Pos, (byte)SnmpType.GetResponsePDU);
RequestID = GetSNMPInteger(ref Packet, ref Pos);
Error = GetSNMPInteger(ref Packet, ref Pos);
Index = GetSNMPInteger(ref Packet, ref Pos);
GetSNMPSequence(ref Packet, ref Pos, (byte)SnmpType.Sequence);
GetSNMPSequence(ref Packet, ref Pos, (byte)SnmpType.Sequence);
ObjectID = GetSNMPObjectID(ref Packet, ref Pos);
ValueType = 0;
Value = null;
if (Error == 0)
{
// extract first data component (usually there only is one)
ValueType = (SnmpType)Packet[Pos];
switch (ValueType)
{
case SnmpType.Boolean:
Value = GetSNMPInteger(ref Packet, ref Pos, (byte)ValueType); break;
case SnmpType.Integer:
Value = GetSNMPInteger(ref Packet, ref Pos); break;
case SnmpType.OctetString:
Value = GetSNMPString(ref Packet, ref Pos); break;
case SnmpType.Null:
Value = GetSNMPNull(ref Packet, ref Pos); break;
case SnmpType.ObjectIdentifier:
Value = GetSNMPObjectID(ref Packet, ref Pos); break;
case SnmpType.IPAddress:
Value = GetSNMPIPAddress(ref Packet, ref Pos); break;
case SnmpType.Counter32:
Value = GetSNMPInteger(ref Packet, ref Pos, (byte)ValueType); break;
case SnmpType.Gauge:
Value = GetSNMPInteger(ref Packet, ref Pos, (byte)ValueType); break;
case SnmpType.TimeTicks:
Value = new System.TimeSpan((long)GetSNMPInteger(ref Packet, ref Pos, (byte)ValueType) * 100000); break;
case SnmpType.Opaque:
Value = GetSNMPInteger(ref Packet, ref Pos, (byte)ValueType); break;
case SnmpType.NetAddress:
Value = GetSNMPInteger(ref Packet, ref Pos, (byte)ValueType); break;
case SnmpType.Counter64:
Value = GetSNMPInteger(ref Packet, ref Pos, (byte)ValueType); break;
case SnmpType.UInt32:
Value = GetSNMPInteger(ref Packet, ref Pos, (byte)ValueType); break;
default:
Value = GetSNMPBinary(ref Packet, ref Pos); break;
}
//GetSNMPNull(ref Packet, ref Pos);
}
}
catch { }
}
public byte[] GetBytes()
{
if (RequestID == 0) RequestID = 1;
// create components for request Packet
byte[] _Version = SNMPInteger(Version);
byte[] _Community = SNMPString(Community);
byte[] _RequestID = SNMPInteger(RequestID);
byte[] _Error = SNMPInteger(Error);
byte[] _Index = SNMPInteger(Index);
byte[] _ObjectID = SNMPObjectID(ObjectID);
byte[] _EndMarker = SNMPNull();
byte[] Packet = new byte[8 + _Version.Length + _Community.Length + _RequestID.Length + _Error.Length + _Index.Length + _ObjectID.Length + _EndMarker.Length];
byte[] _ASN1Header = SNMPSequence(0x30, Packet.Length - 2);
int RequestLength = 6 + _RequestID.Length + _Error.Length + _Index.Length + _ObjectID.Length;
byte[] _RequestHeader = SNMPSequence((int)PacketType, RequestLength);
int VarBindListLength = 4 + _ObjectID.Length;
byte[] _VarBindList = SNMPSequence(0x30, VarBindListLength);
int VarBindLength = 2 + _ObjectID.Length;
byte[] _VarBind = SNMPSequence(0x30, VarBindLength);
// combine components to request Packet
int Pos = 0;
System.Buffer.BlockCopy(_ASN1Header, 0, Packet, Pos, _ASN1Header.Length);
Pos += _ASN1Header.Length;
System.Buffer.BlockCopy(_Version, 0, Packet, Pos, _Version.Length);
Pos += _Version.Length;
System.Buffer.BlockCopy(_Community, 0, Packet, Pos, _Community.Length);
Pos += _Community.Length;
System.Buffer.BlockCopy(_RequestHeader, 0, Packet, Pos, _RequestHeader.Length);
Pos += _RequestHeader.Length;
System.Buffer.BlockCopy(_RequestID, 0, Packet, Pos, _RequestID.Length);
Pos += _RequestID.Length;
System.Buffer.BlockCopy(_Error, 0, Packet, Pos, _Error.Length);
Pos += _Error.Length;
System.Buffer.BlockCopy(_Index, 0, Packet, Pos, _Index.Length);
Pos += _Index.Length;
System.Buffer.BlockCopy(_VarBindList, 0, Packet, Pos, _VarBindList.Length);
Pos += _VarBindList.Length;
System.Buffer.BlockCopy(_VarBind, 0, Packet, Pos, _VarBind.Length);
Pos += _VarBind.Length;
System.Buffer.BlockCopy(_ObjectID, 0, Packet, Pos, _ObjectID.Length);
Pos += _ObjectID.Length;
System.Buffer.BlockCopy(_EndMarker, 0, Packet, Pos, _EndMarker.Length);
Pos += _EndMarker.Length;
return Packet;
}
// add variable length in front of byte list
private void AddSNMPLength(ref System.Collections.ArrayList B, int Len)
{
int Pos = 0;
B.Insert(Pos++, (byte)(Len & 0xFF));
Len >>= 8;
while (Len != 0)
{
B.Insert(Pos++, (byte)(Len & 0xFF));
Len >>= 8;
}
if (Pos > 1) B.Insert(0, (byte)(B.Count | 0x80));
}
// create snmp integer
private byte[] SNMPInteger(long Val)
{
System.Collections.ArrayList B = new System.Collections.ArrayList();
do
{
B.Insert(0, (byte)(Val & 0xFF));
Val >>= 8;
} while (Val != 0);
AddSNMPLength(ref B, B.Count);
byte[] Result = new byte[1 + B.Count];
int Pos = 0;
Result[Pos++] = (byte)SnmpType.Integer;
for (int i = 0; i < B.Count; i++) Result[Pos++] = (byte)B[i];
return Result;
}
// create snmp octet string
private byte[] SNMPString(string Val)
{
System.Collections.ArrayList B = new System.Collections.ArrayList();
AddSNMPLength(ref B, Val.Length);
byte[] Result = new byte[1 + B.Count + Val.Length];
int Pos = 0;
Result[Pos++] = (byte)SnmpType.OctetString;
for (int i = 0; i < B.Count; i++) Result[Pos++] = (byte)B[i];
System.Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Val), 0, Result, Pos, Val.Length);
return Result;
}
// create snmp null
private byte[] SNMPNull()
{
byte[] Result = new byte[2];
Result[0] = (byte)SnmpType.Null;
Result[1] = 0x00; // length is zero
return Result;
}
// create snmp OID
private byte[] SNMPObjectID(string Val)
{
if (Val.StartsWith("1.3")) Val = "43" + Val.Substring(3);
System.Collections.ArrayList B = new System.Collections.ArrayList();
string[] A = Val.Split('.');
int Len = 0;
for (int i = 0; i < A.Length; i++)
{
int V = System.Convert.ToInt32(A[i]);
B.Insert(Len, (byte)(V & 0x7F));
V >>= 7;
while (V != 0)
{
B.Insert(Len, (byte)(V & 0x7F | 0x80));
V >>= 7;
}
Len = B.Count;
}
AddSNMPLength(ref B, B.Count);
byte[] Result = new byte[1 + B.Count];
int Pos = 0;
Result[Pos++] = (byte)SnmpType.ObjectIdentifier;
for (int i = 0; i < B.Count; i++) Result[Pos++] = (byte)B[i];
return Result;
}
// create snmp sequence header
private byte[] SNMPSequence(long Tag, int Len)
{
System.Collections.ArrayList B = new System.Collections.ArrayList();
AddSNMPLength(ref B, Len);
byte[] Result = new byte[1 + B.Count];
int Pos = 0;
Result[Pos++] = (byte)Tag;
for (int i = 0; i < B.Count; i++) Result[Pos++] = (byte)B[i];
return Result;
}
// get snmp variable length
private int GetSNMPLength(ref byte[] Packet, ref int Pos)
{
int Len = Packet[Pos++];
if (Len > 128)
{
int L = Len & 0x7F;
Len = 0;
for (int i = 0; i < L; i++) Len = (Len << 8) + Packet[Pos++];
}
return Len;
}
// get snmp integer
private long GetSNMPInteger(ref byte[] Packet, ref int Pos)
{
if (Packet[Pos++] != (byte)SnmpType.Integer) throw new System.Exception("ASN.1 Integer expected.");
int Len = GetSNMPLength(ref Packet, ref Pos);
long Val = 0;
for (int i = 0; i < Len; i++) Val = (Val << 8) + Packet[Pos++];
return Val;
}
// get snmp variable as integer (used for booleans, integers of all sizes, counters, etc.)
private long GetSNMPInteger(ref byte[] Packet, ref int Pos, int Tag)
{
if (Packet[Pos++] != Tag) throw new System.Exception("ASN.1 Integer " + System.String.Format("0x{0:x}", Tag) + " expected.");
int Len = GetSNMPLength(ref Packet, ref Pos);
long Val = 0;
for (int i = 0; i < Len; i++) Val = (Val << 8) + Packet[Pos++];
return Val;
}
// get snmp octet string (detect dates and numeric mac addresses)
private string GetSNMPString(ref byte[] Packet, ref int Pos)
{
if (Packet[Pos++] != (byte)SnmpType.OctetString) throw new System.Exception("ASN.1 String expected.");
int Len = GetSNMPLength(ref Packet, ref Pos);
// detect date/time
try
{
int y = (Packet[Pos] * 256) + Packet[Pos + 1];
int m = Packet[Pos + 2];
int d = Packet[Pos + 3];
if ((y < 2020) && (y > 1990) && (m < 13) && (d < 32))
{
int h = Packet[Pos + 4];
int n = Packet[Pos + 5];
int s = Packet[Pos + 6];
int t = Packet[Pos + 7];
string DateResult = y + "-" + ((m < 10) ? "0" : "") + m + "-" + ((d < 10) ? "0" : "") + d + " "
+ ((h < 10) ? "0" : "") + h + ":" + ((n < 10) ? "0" : "") + n + ":" + ((s < 10) ? "0" : "") + s
+ "." + t;
Pos += Len;
return DateResult;
}
}
catch { }
// detect numbers
string Result = "";
if (Len <= 8) for (int l = Pos; l < Pos + Len - 1; l++) if (Packet[l] < 32)
{
Result = System.BitConverter.ToString(Packet, Pos, Len);
break;
}
if (Result == "") Result = System.Text.Encoding.ASCII.GetString(Packet, Pos, Len);
Pos += Len;
return Result;
}
// get snmp null
private string GetSNMPNull(ref byte[] Packet, ref int Pos)
{
if (Packet[Pos++] != (byte)SnmpType.Null) throw new System.Exception("ASN.1 Null expected.");
Pos++;
return "";
}
// get snmp OID
private string GetSNMPObjectID(ref byte[] Packet, ref int Pos)
{
if (Packet[Pos++] != (byte)SnmpType.ObjectIdentifier) throw new System.Exception("ASN.1 ObjectID expected.");
int Len = GetSNMPLength(ref Packet, ref Pos);
string Result = "";
for (int i = Pos; i < Pos + Len; i++)
{
int Val = 0;
int V;
do
{
V = Packet[i];
Val = (Val << 7) + (V & 0x7F);
if (V > 127) i++; else break;
} while (true);
if (Result != "") Result += ".";
Result += Val;
}
if (Result.StartsWith("43")) Result = "1.3" + Result.Substring(2);
Pos += Len;
return Result;
}
// get snmp sequence length (used for Sequence, GetResponsePDU, etc)
private int GetSNMPSequence(ref byte[] Packet, ref int Pos, int Tag)
{
if (Packet[Pos++] != (byte)Tag) throw new System.Exception("ASN.1 " + System.String.Format("0x{0:x}", Tag) + " expected.");
return GetSNMPLength(ref Packet, ref Pos);
}
// get snmp ipaddress
private string GetSNMPIPAddress(ref byte[] Packet, ref int Pos)
{
if (Packet[Pos++] != (byte)SnmpType.IPAddress) throw new System.Exception("ASN.1 IPAddress expected.");
int Len = GetSNMPLength(ref Packet, ref Pos);
string Result = "";
for (int i = 0; i < Len; i++)
{
if (Result != "") Result += ".";
Result += Packet[Pos++];
}
return Result;
}
// get binary snmp data (used for unknown data types)
private string GetSNMPBinary(ref byte[] Packet, ref int Pos)
{
Pos++;
int Len = GetSNMPLength(ref Packet, ref Pos);
string Result = System.BitConverter.ToString(Packet, Pos, Len);
Pos += Len;
return Result;
}
}
}