Source/Tx.Network/Snmp/SnmpEncodeDecoder.cs (145 lines of code) (raw):

 namespace Tx.Network.Snmp { using Asn1Types; using System; using System.IO; using System.Net; /// <summary> /// Class to Encode\Decode SNMP data /// </summary> internal static class SnmpEncodeDecoder { /// <summary> /// The header length offset /// </summary> private const int SnmpV2MessageHeaderLength = 32; /// <summary> /// To Asn.1/Snmp Encoded byte array. /// </summary> /// <param name="snmpPacket">The SNMP packet.</param> /// <returns>Asn.1 encoded byte array</returns> /// <exception cref="System.ArgumentNullException">snmpPacket</exception> public static byte[] ToSnmpEncodedByteArray(this SnmpDatagramV2C snmpPacket) { byte[] dataBytes = new byte[8194]; int length = dataBytes.EncodeVarBinds(0, snmpPacket.VarBinds); Array.Resize(ref dataBytes, length); int headerLength = SnmpV2MessageHeaderLength + snmpPacket.Header.Community.Length; byte[] headerBytes = new byte[headerLength]; int offset = 0; //Encode version offset = headerBytes.EncodeInteger(offset, (int)snmpPacket.Header.Version); //Encode Community String offset = headerBytes.EncodeOctetString(offset, snmpPacket.Header.Community); //Encode PDU Type offset = headerBytes.EncodeClassConstructType(offset, Asn1Class.ContextSpecific, ConstructType.Constructed, (byte)snmpPacket.PduType); int commonPduControlFieldLength = 1 //pduType + snmpPacket.RequestId.GetIntegerLength() + ((int)snmpPacket.ErrorStatus).GetIntegerLength() + snmpPacket.ErrorIndex.GetIntegerLength() + length; //length of varbind values //Encode PDU length offset = headerBytes.EncodeLength(offset, commonPduControlFieldLength); //Encode RequestId offset = headerBytes.EncodeInteger(offset, snmpPacket.RequestId); //Encode ErrorStatus offset = headerBytes.EncodeInteger(offset, (int)snmpPacket.ErrorStatus); //Encode ErrorIndex offset = headerBytes.EncodeInteger(offset, snmpPacket.ErrorIndex); //Encode VarBinds Length offset = headerBytes.EncodeClassConstructType(offset, Asn1Class.Universal, ConstructType.Constructed, (byte)Asn1Tag.Sequence); offset = headerBytes.EncodeLength(offset, length); byte[] allBytes = new byte[6]; int newOffset = 0; newOffset = allBytes.EncodeClassConstructType(newOffset, Asn1Class.Universal, ConstructType.Constructed, (byte)Asn1Tag.Sequence); newOffset = allBytes.EncodeLength(newOffset, offset + length); //Resize and append varbinds to header Array.Resize(ref allBytes, newOffset + offset + length); Array.Copy(headerBytes, 0, allBytes, newOffset, offset); Array.Copy(dataBytes, 0, allBytes, newOffset + offset, length); return allBytes; } /// <summary> /// Converts the Asn.1 encoded byte array to SNMP Datagram. /// </summary> /// <param name="byteSegment">The asn.1 encoded bytes.</param> /// <param name="timestamp">The timestamp when the packet has been received.</param> /// <param name="sourceIpAddress">The source IP address of the packet.</param> /// <returns> /// SnmpPacket /// </returns> /// <exception cref="System.ArgumentNullException">bytes</exception> /// <exception cref="System.IO.InvalidDataException">Snmp Version V3 not supported</exception> public static SnmpDatagram ToSnmpDatagram( this ArraySegment<byte> byteSegment, DateTimeOffset timestamp, string sourceIpAddress) { var bytes = byteSegment.Array; if(bytes == null || bytes.Length == 0) { throw new ArgumentNullException("byteSegment"); } int offset = byteSegment.Offset; int length; offset = bytes.NextValueLength(offset, -1, -1, -1, out length); offset = bytes.NextValueLength(offset, -1, -1, (int)Asn1Tag.Integer, out length); SnmpVersion snmpVersion = (SnmpVersion)bytes.ReadInteger(offset, length); offset += length; if (snmpVersion == SnmpVersion.V3) { throw new InvalidDataException("Snmp Version V3 not supported"); } offset = bytes.NextValueLength(offset, -1, -1, (int)Asn1Tag.OctetString, out length); string community = bytes.ReadOctetString(offset, length); offset += length; PduType pduType = (PduType)(bytes[offset++] & 0x1F); offset = bytes.ReadLength(offset, out length); if (snmpVersion == SnmpVersion.V1 && pduType== PduType.Trap) { offset = bytes.NextValueLength(offset, -1, -1, (int)Asn1Tag.ObjectIdentifier, out length); ObjectIdentifier oid = new ObjectIdentifier(bytes.ReadOids(offset, length)); offset += length; offset = bytes.NextValueLength(offset, -1, -1, (int)Asn1SnmpTag.IpAddress, out length); IPAddress ipAddress = bytes.ReadIpAddress(offset); offset += length; offset = bytes.NextValueLength(offset, -1, -1, (int)Asn1Tag.Integer, out length); GenericTrap genericTrap = (GenericTrap)bytes.ReadInteger(offset, length); offset += length; offset = bytes.NextValueLength(offset, -1, -1, (int)Asn1Tag.Integer, out length); int specificTrap = bytes.ReadInteger(offset, length); offset += length; offset = bytes.NextValueLength(offset, -1, -1, (int)Asn1SnmpTag.TimeTicks, out length); uint timeStamp = bytes.ReadUnsignedInteger(offset, length); offset += length; offset = bytes.NextValueLength(offset, (int)Asn1Class.Universal, (int)ConstructType.Constructed, (int)Asn1Tag.Sequence, out length); VarBind[] varBinds = bytes.ReadVarBinds(offset, length); return new SnmpDatagramV1( timestamp, sourceIpAddress, new SnmpHeader(snmpVersion, community), varBinds); } else { offset = bytes.NextValueLength(offset, -1, -1, (int)Asn1Tag.Integer, out length); int requestId = bytes.ReadInteger(offset, length); offset += length; offset = bytes.NextValueLength(offset, -1, -1, (int)Asn1Tag.Integer, out length); SnmpErrorStatus errorStatus = (SnmpErrorStatus)bytes.ReadInteger(offset, length); offset += length; offset = bytes.NextValueLength(offset, -1, -1, (int)Asn1Tag.Integer, out length); int errorIndex = bytes.ReadInteger(offset, length); offset += length; offset = bytes.NextValueLength(offset, (int)Asn1Class.Universal, (int)ConstructType.Constructed, (int)Asn1Tag.Sequence, out length); VarBind[] varBinds = bytes.ReadVarBinds(offset, length); return new SnmpDatagramV2C( timestamp, sourceIpAddress, new SnmpHeader(snmpVersion, community), varBinds, pduType, requestId, errorStatus, errorIndex); } } /// <summary> /// Nexts the length of the value. /// </summary> /// <param name="bytes">The bytes.</param> /// <param name="offset">The offset.</param> /// <param name="classValidations">The class validations.</param> /// <param name="constructValidations">The construct validations.</param> /// <param name="typeValidations">The type validations.</param> /// <param name="length">The length.</param> /// <returns>int [value to next offset]</returns> /// <exception cref="DataMisalignedException"> /// Data Malformated/Expected Asn1 Class tag is: + ((Asn1Class)classValidations).ToString() /// or /// Data Malformated/Expected ConstructType tag is: + ((ConstructType)constructValidations).ToString() /// or /// Data Malformated/Expected Asn1 tag is: + ((Asn1Tag)typeValidations).ToString() /// or /// Data Malformated/Expected Asn1Snmp tag is: + ((Asn1SnmpTag)typeValidations).ToString() /// </exception> private static int NextValueLength(this byte[] bytes, int offset, int classValidations, int constructValidations, int typeValidations, out int length) { var type = bytes[offset++].DecodeToClassConstructType(); if (classValidations != -1 && type.Asn1ClassType != (Asn1Class)classValidations) { throw new DataMisalignedException("Data Malformated/Expected Asn1 Class tag is: " + ((Asn1Class)classValidations).ToString()); } if (constructValidations != -1 && type.Asn1ConstructType != (ConstructType)constructValidations) { throw new DataMisalignedException("Data Malformated/Expected ConstructType tag is: " + ((ConstructType)constructValidations).ToString()); } if (type.Asn1TagType != Asn1Tag.NotAsn1Data) { if (typeValidations != -1 && type.Asn1TagType != (Asn1Tag)typeValidations) { throw new DataMisalignedException("Data Malformated/Expected Asn1 tag is: " + ((Asn1Tag)typeValidations).ToString()); } } else { if (typeValidations != -1 && type.Asn1SnmpTagType != (Asn1SnmpTag)typeValidations) { throw new DataMisalignedException("Data Malformated/Expected Asn1Snmp tag is: " + ((Asn1SnmpTag)typeValidations).ToString()); } } return bytes.ReadLength(offset, out length); } } }