/// <summary>Decode BER encoded variable binding. /// </summary> /// <param name="buffer">BER encoded buffer /// </param> /// <param name="offset">Offset in the data buffer from where to start decoding. Offset is /// passed by reference and will contain the offset of the byte immediately after the parsed /// variable binding. /// </param> /// <returns>Buffer position after the decoded value</returns> public override int decode(byte[] buffer, int offset) { int headerLength; byte asnType = ParseHeader(buffer, ref offset, out headerLength); if (asnType != Type) throw new SnmpException(string.Format("Invalid ASN.1 type. Expected 0x{0:x2} received 0x{1:x2}", Type, asnType)); // verify the length if ((buffer.Length - offset) < headerLength) throw new OverflowException("Buffer underflow error"); _oid = new Oid(); offset = _oid.decode(buffer, offset); int saveOffset = offset; // Look ahead in the header to see the data type we need to parse asnType = ParseHeader(buffer, ref saveOffset, out headerLength); _value = SnmpConstants.GetSyntaxObject(asnType); if (_value == null) throw new SnmpDecodingException(String.Format("Invalid ASN.1 type encountered 0x{0:x2}. Unable to continue decoding.", asnType)); offset = _value.decode(buffer, offset); return offset; }
/// <summary> /// Construct Vb with the OID and value /// </summary> /// <param name="oid">OID</param> /// <param name="value">Value</param> public Vb(Oid oid, AsnType value) : this(oid) { _value = (AsnType)value.Clone(); }
/// <summary> /// Decode received SNMP packet. /// </summary> /// <param name="buffer">BER encoded packet buffer</param> /// <param name="length">BER encoded packet buffer length</param> /// <exception cref="SnmpException">Thrown when invalid encoding has been found in the packet</exception> /// <exception cref="OverflowException">Thrown when parsed header points to more data then is available in the packet</exception> /// <exception cref="SnmpInvalidVersionException">Thrown when parsed packet is not SNMP version 1</exception> /// <exception cref="SnmpInvalidPduTypeException">Thrown when received PDU is of a type not supported by SNMP version 1</exception> public override int Decode(byte[] buffer, int length) { MutableByte buf = new MutableByte(buffer, length); int offset = 0; offset = base.Decode(buffer, buffer.Length); if (Version != SnmpVersion.Ver2) { throw new SnmpInvalidVersionException("Invalid protocol version"); } offset = _snmpCommunity.Decode(buf, offset); int tmpOffset = offset; byte asnType = AsnType.ParseHeader(buf, ref tmpOffset, out int headerLength); // Check packet length if (headerLength + offset > buf.Length) { throw new OverflowException("Insufficient data in packet"); } if (asnType != (byte)PduType.Get && asnType != (byte)PduType.GetNext && asnType != (byte)PduType.Set && asnType != (byte)PduType.GetBulk && asnType != (byte)PduType.Response && asnType != (byte)PduType.V2Trap && asnType != (byte)PduType.Inform) { throw new SnmpInvalidPduTypeException("Invalid SNMP operation received: " + string.Format("0x{0:x2}", asnType)); } // Now process the Protocol Data Unit offset = Pdu.Decode(buf, offset); return(length); }
/// <summary> /// Encode SNMP packet for sending. /// </summary> /// <returns>BER encoded SNMP packet.</returns> public override byte[] Encode() { MutableByte buf = new MutableByte(); if (Pdu.Type != PduType.Get && Pdu.Type != PduType.GetNext && Pdu.Type != PduType.Set && Pdu.Type != PduType.V2Trap && Pdu.Type != PduType.Response && Pdu.Type != PduType.GetBulk && Pdu.Type != PduType.Inform) { throw new SnmpInvalidPduTypeException("Invalid SNMP PDU type while attempting to encode PDU: " + string.Format("0x{0:x2}", Pdu.Type)); } // snmp version _protocolVersion.Encode(buf); // community string _snmpCommunity.Encode(buf); // pdu _pdu.Encode(buf); // wrap the packet into a sequence MutableByte tmpBuf = new MutableByte(); AsnType.BuildHeader(tmpBuf, SnmpConstants.SMI_SEQUENCE, buf.Length); buf.Prepend(tmpBuf); return(buf); }
/// <summary> /// Copy values from another Pdu class. /// </summary> /// <param name="value"><see cref="Pdu"/> cast as AsnType</param> /// <exception cref="ArgumentNullException">Thrown when received argument is null</exception> public void Set(AsnType value) { if (value == null) { throw new ArgumentNullException("value"); } Pdu pdu = value as Pdu; if (pdu != null) { this.Type = pdu.Type; this._requestId.Value = pdu.RequestId; if (this.Type == PduType.GetBulk) { this.NonRepeaters = pdu.NonRepeaters; this.MaxRepetitions = pdu.MaxRepetitions; } else { this.ErrorStatus = pdu.ErrorStatus; this.ErrorIndex = pdu.ErrorIndex; } this._vbs.Clear(); foreach (Vb v in pdu.VbList) { this._vbs.Add((Vb)v.Clone()); } } else { throw new ArgumentNullException("value", "Argument is not an Oid class"); } }
/// <summary>Copy values from another Pdu class.</summary> /// <param name="value"><see cref="Pdu"/> cast as AsnType</param> /// <exception cref="ArgumentNullException">Thrown when received argument is null</exception> public void Set(AsnType value) { if (value == null) { throw new ArgumentNullException(nameof(value)); } if (value is Pdu pdu) { Type = pdu.Type; requestId.Value = pdu.RequestId; if (Type == EPduType.GetBulk) { NonRepeaters = pdu.NonRepeaters; MaxRepetitions = pdu.MaxRepetitions; } else { ErrorStatus = pdu.ErrorStatus; ErrorIndex = pdu.ErrorIndex; } VbList.Clear(); foreach (Vb v in pdu.VbList) { VbList.Add((Vb)v.Clone()); } } else { throw new ArgumentNullException(nameof(value), "Argument is not an Oid class"); } }
/// <summary> /// Encode SNMP packet for sending. /// </summary> /// <returns>BER encoded SNMP packet.</returns> /// <exception cref="SnmpInvalidPduTypeException">Thrown when PDU being encoded is not a valid SNMP version 1 PDU. Acceptable /// protocol version 1 operations are GET, GET-NEXT, SET and RESPONSE.</exception> public override byte[] encode() { if (this.Pdu.Type != PduType.Get && this.Pdu.Type != PduType.GetNext && this.Pdu.Type != PduType.Set && this.Pdu.Type != PduType.Response) { throw new SnmpInvalidVersionException("Invalid SNMP PDU type while attempting to encode PDU: " + string.Format("0x{0:x2}", this.Pdu.Type)); } if (this.Pdu.RequestId == 0) { System.Random rand = new System.Random((System.Int32)DateTime.Now.Ticks); this.Pdu.RequestId = rand.Next(); } MutableByte tmpBuffer = new MutableByte(); // snmp version _protocolVersion.encode(tmpBuffer); // community string _snmpCommunity.encode(tmpBuffer); // pdu this.Pdu.encode(tmpBuffer); MutableByte buf = new MutableByte(); // wrap the packet into a sequence AsnType.BuildHeader(buf, SnmpConstants.SMI_SEQUENCE, tmpBuffer.Length); buf.Append(tmpBuffer); return(buf); }
/// <summary>Decode BER encoded variable binding. /// </summary> /// <param name="buffer">BER encoded buffer /// </param> /// <param name="offset">Offset in the data buffer from where to start decoding. Offset is /// passed by reference and will contain the offset of the byte immediately after the parsed /// variable binding. /// </param> /// <returns>Buffer position after the decoded value</returns> public override int decode(byte[] buffer, int offset) { int headerLength; byte asnType = ParseHeader(buffer, ref offset, out headerLength); if (asnType != Type) { throw new SnmpException(string.Format("Invalid ASN.1 type. Expected 0x{0:x2} received 0x{1:x2}", Type, asnType)); } // verify the length if ((buffer.Length - offset) < headerLength) { throw new OverflowException("Buffer underflow error"); } _oid = new Oid(); offset = _oid.decode(buffer, offset); int saveOffset = offset; // Look ahead in the header to see the data type we need to parse asnType = ParseHeader(buffer, ref saveOffset, out headerLength); _value = SnmpConstants.GetSyntaxObject(asnType); if (_value == null) { throw new SnmpDecodingException(String.Format("Invalid ASN.1 type encountered 0x{0:x2}. Unable to continue decoding.", asnType)); } offset = _value.decode(buffer, offset); return(offset); }
/// <summary> /// "Look-ahead" decode of SNMP packet header including USM information /// </summary> /// <remarks> /// Decode first component of the SNMP version 3 packet allowing the caller to retrieve USM SecureName needed to retrieve /// client security parameters that will allow authentication and privacy decryption to take place. /// /// This method is used to support Agent like behavior or to handle unsolicited packets like TRAP and INFORMs. In all of /// these cases, sender of packets will forward a packet without a request being sent by you. In turn, you will need /// to parse enough of the packet to retrieve SecureName which you can use to retrieve security parameters associated with /// that user and attempt to authorize and privacy decrypt the received packet. /// /// Only use this method when your application is acting as an Agent or if you need to process TRAP and INFORM packets. /// </remarks> /// <param name="berBuffer">Raw SNMP version 3 packet</param> /// <param name="length">SNMP version 3 packet length</param> /// <returns>UserSecurityModel class parsed from the parameter SNMP version 3 packet</returns> /// <exception cref="SnmpInvalidVersionException">Thrown when attempting to parse an SNMP packet that is not version 3</exception> /// <exception cref="OverflowException">Thrown when header specifies packet length that is longer then the amount of data received.</exception> /// <exception cref="SnmpDecodingException">Thrown when invalid sequence is enountered while decoding global message data sequence</exception> /// <exception cref="SnmpException">Thrown with SnmpException.UnsupportedNoAuthPriv when packet is using privacy without authentication (not allowed)</exception> /// <exception cref="SnmpException">Thrown with SnmpException.UnsupportedSecurityModel when packet is sent with security model other then USM (only USM is defined in SNMPv3 standard)</exception> public UserSecurityModel GetUSM(byte[] berBuffer, int length) { MutableByte buffer = new MutableByte(berBuffer, length); int offset = 0; // let base class parse first sequence and SNMP version number offset = base.Decode(buffer, length); // check for correct SNMP protocol version if (_protocolVersion != (int)SnmpVersion.Ver3) { throw new SnmpInvalidVersionException("Expecting SNMP version 3."); } // now grab the global message data sequence header information byte asnType = AsnType.ParseHeader(buffer, ref offset, out int len); if (asnType != SnmpConstants.SMI_SEQUENCE) { throw new SnmpDecodingException("Invalid sequence type when decoding global message data sequence."); } // check that packet size can accommodate the length specified in the header if (len > (buffer.Length - offset)) { throw new OverflowException("Packet is too small to contain the data described in the header."); } // retrieve message id offset = _messageId.Decode(buffer, offset); // max message size offset = _maxMessageSize.Decode(buffer, offset); // message flags offset = MsgFlags.Decode(buffer, offset); // verify that a valid authentication/privacy configuration is present in the packet if (MsgFlags.Authentication == false && MsgFlags.Privacy == true) { throw new SnmpException(SnmpException.UnsupportedNoAuthPriv, "SNMP version 3 noAuthPriv security combination is not supported."); } // security model code offset = _securityModel.Decode(buffer, offset); // we only support USM. code = 0x03 if (_securityModel.Value != USM.Type) { throw new SnmpException(SnmpException.UnsupportedSecurityModel, "Class only support SNMP Version 3 User Security Model."); } // parse user security model offset = USM.Decode(buffer, offset); return(USM); }
/// <summary> /// Wrap BER encoded SNMP information contained in the parameter <see cref="MutableByte"/> class. /// /// Information in the parameter is prepended by the SNMP version field and wrapped in a sequence header. /// /// Derived classes call this method to finalize SNMP packet encoding. /// </summary> /// <param name="buffer">Buffer containing BER encoded SNMP information</param> public virtual void Encode(MutableByte buffer) { // Encode SNMP protocol version MutableByte temp = new MutableByte(); _protocolVersion.Encode(temp); buffer.Prepend(temp); temp.Reset(); AsnType.BuildHeader(temp, SnmpConstants.SMI_SEQUENCE, buffer.Length); buffer.Prepend(temp); }
/// <summary> /// SET class value from another Counter64 class cast as <seealso cref="AsnType"/>. /// </summary> /// <param name="value">Counter64 class cast as <seealso cref="AsnType"/></param> /// <exception cref="ArgumentException">Argument is not Counter64 type.</exception> public void Set(AsnType value) { Counter64 val = value as Counter64; if (val != null) { _value = val.Value; } else { throw new ArgumentException("Invalid argument type."); } }
/// <summary> /// SET class value from another Integer32 class cast as <see cref="AsnType"/>. /// </summary> /// <param name="value">Integer32 class cast as <see cref="AsnType"/></param> /// <exception cref="ArgumentException">Argument is not Integer32 type.</exception> public void Set(AsnType value) { Integer32 val = value as Integer32; if (val != null) { _value = val.Value; } else { throw new ArgumentException("Invalid argument type."); } }
/// <summary> /// SET class value from another UInteger32 or Integer32 class cast as <seealso cref="AsnType"/>. /// </summary> /// <param name="value">UInteger32 class cast as <seealso cref="AsnType"/></param> /// <exception cref="ArgumentNullException">Parameter is null.</exception> public void Set(AsnType value) { if (value == null) { throw new ArgumentNullException("value", "Parameter is null"); } if (value is UInteger32) { _value = ((UInteger32)value).Value; } else if (value is Integer32) { _value = (UInt32)((Integer32)value).Value; } }
/// <summary> /// Get SNMP protocol version from the packet. This routine does not verify if version number is valid. Caller /// should verify that returned value represents a valid SNMP protocol version number. /// /// <code> /// int protocolVersion = Packet.GetProtocolVersion(inPacket, inLength); /// if( protocolVersion != -1 ) /// { /// if( protocolVersion == SnmpConstants.SNMPV1 || protocolVersion == SnmpConstants.SNMPV2 || protocolVersion == SnmpConstants.SNMPV3 ) /// { /// // do something /// } /// else /// { /// Console.WriteLine("Invalid SNMP protocol version."); /// } /// } /// else /// { /// Console.WriteLine("Invalid SNMP packet."); /// } /// </code> /// </summary> /// <param name="buffer">BER encoded SNMP packet</param> /// <param name="bufferLength">Length of the BER encoded packet</param> /// <returns>Returns SNMP protocol version, if packet is not valid returned value is -1.</returns> public static int GetProtocolVersion(byte[] buffer, int bufferLength) { int offset = 0; int length = 0; byte asnType = AsnType.ParseHeader(buffer, ref offset, out length); if ((offset + length) > bufferLength) { return(-1); // This is not a valid packet } Integer32 version = new Integer32(); offset = version.decode(buffer, offset); return(version.Value); }
/// <summary> /// Return SNMP type object of the type specified by name. Supported variable types are: /// <see cref="Integer32"/>, <see cref="Counter32"/>, <see cref="Gauge32"/>, <see cref="Counter64"/>, /// <see cref="TimeTicks"/>, <see cref="OctetString"/>, <see cref="IpAddress"/>, <see cref="Oid"/>, and /// <see cref="Null"/>. /// /// Type names are the same as support class names compared without case sensitivity (e.g. Integer == INTEGER). /// </summary> /// <param name="name">Name of the object type (not case sensitive)</param> /// <returns>New <see cref="AsnType"/> object.</returns> public static AsnType GetSyntaxObject(string name) { AsnType obj = null; if (name.ToUpper().Equals("INTEGER32") || name.ToUpper().Equals("INTEGER")) { obj = new Integer32(); } else if (name.ToUpper().Equals("COUNTER32")) { obj = new Counter32(); } else if (name.ToUpper().Equals("GAUGE32")) { obj = new Gauge32(); } else if (name.ToUpper().Equals("COUNTER64")) { obj = new Counter64(); } else if (name.ToUpper().Equals("TIMETICKS")) { obj = new TimeTicks(); } else if (name.ToUpper().Equals("OCTETSTRING")) { obj = new OctetString(); } else if (name.ToUpper().Equals("IPADDRESS")) { obj = new IpAddress(); } else if (name.ToUpper().Equals("OID")) { obj = new Oid(); } else if (name.ToUpper().Equals("NULL")) { obj = new Null(); } else { throw new ArgumentException("Invalid value type name"); } return(obj); }
/// <summary> /// Return SNMP type object of the type specified by name. Supported variable types are: /// * <see cref="Integer32"/> /// * <see cref="Counter32"/> /// * <see cref="Gauge32"/> /// * <see cref="Counter64"/> /// * <see cref="TimeTicks"/> /// * <see cref="OctetString"/> /// * <see cref="IpAddress"/> /// * <see cref="Oid"/> /// * <see cref="Null"/> /// </summary> /// <param name="name">Name of the object type</param> /// <returns>New <see cref="AsnType"/> object.</returns> public static AsnType GetSyntaxObject(string name) { AsnType obj = null; if (name == "Integer32") { obj = new Integer32(); } else if (name == "Counter32") { obj = new Counter32(); } else if (name == "Gauge32") { obj = new Gauge32(); } else if (name == "Counter64") { obj = new Counter64(); } else if (name == "TimeTicks") { obj = new TimeTicks(); } else if (name == "OctetString") { obj = new OctetString(); } else if (name == "IpAddress") { obj = new IpAddress(); } else if (name == "Oid") { obj = new Oid(); } else if (name == "Null") { obj = new Null(); } else { throw new ArgumentException("Invalid value type name"); } return(obj); }
/// <summary> /// Get SNMP protocol version from the packet. This routine does not verify if version number is valid. Caller /// should verify that returned value represents a valid SNMP protocol version number. /// /// <code> /// int protocolVersion = Packet.GetProtocolVersion(inPacket, inLength); /// if( protocolVersion != -1 ) /// { /// if( protocolVersion == SnmpConstants.SNMPV1 || protocolVersion == SnmpConstants.SNMPV2 || protocolVersion == SnmpConstants.SNMPV3 ) /// { /// // do something /// } /// else /// { /// Console.WriteLine("Invalid SNMP protocol version."); /// } /// } /// else /// { /// Console.WriteLine("Invalid SNMP packet."); /// } /// </code> /// </summary> /// <param name="buffer">BER encoded SNMP packet</param> /// <param name="bufferLength">Length of the BER encoded packet</param> /// <returns>Returns SNMP protocol version, if packet is not valid returned value is -1.</returns> /// <exception cref="SnmpDecodingException">Thrown when invalid sequence type is found at the start of the SNMP packet being decoded</exception> public static int GetProtocolVersion(byte[] buffer, int bufferLength) { int offset = 0; byte asnType = AsnType.ParseHeader(buffer, ref offset, out int length); if ((offset + length) > bufferLength) { return(-1); // This is not a valid packet } if (asnType != SnmpConstants.SMI_SEQUENCE) { throw new SnmpDecodingException("Invalid sequence type at the start of the SNMP packet."); } Integer32 version = new Integer32(); _ = version.decode(buffer, offset); return(version.Value); }
/// <summary> /// Get SNMP protocol version from the packet. This routine does not verify if version number is valid. Caller /// should verify that returned value represents a valid SNMP protocol version number. /// /// <code> /// int protocolVersion = Packet.GetProtocolVersion(inPacket, inLength); /// if( protocolVersion != -1 ) /// { /// if( protocolVersion == SnmpConstants.SNMPV1 || protocolVersion == SnmpConstants.SNMPV2 || protocolVersion == SnmpConstants.SNMPV3 ) /// // do something /// else /// Console.WriteLine("Invalid SNMP protocol version."); /// } /// else /// Console.WriteLine("Invalid SNMP packet."); /// </code> /// </summary> /// <param name="buffer">BER encoded SNMP packet</param> /// <param name="bufferLength">Length of the BER encoded packet</param> /// <returns>Returns SNMP protocol version, if packet is not valid returned value is -1.</returns> /// <exception cref="SnmpDecodingException">Thrown when invalid sequence type is found at the start of the SNMP packet being decoded</exception> public static ESnmpVersion GetProtocolVersion(byte[] buffer, int bufferLength) { int offset = 0; byte asnType = AsnType.ParseHeader(buffer, ref offset, out int length); if ((offset + length) > bufferLength) { throw new SnmpDecodingException("Cannot parse SNMP version from packet, input past end"); } if (asnType != SnmpConstants.SmiSequence) { throw new SnmpDecodingException("Invalid sequence type at the start of the SNMP packet."); } Integer32 version = new Integer32(); offset = version.Decode(buffer, offset); return((ESnmpVersion)version.Value); }
/// <summary> /// Decode received packet. This method overrides the base implementation that cannot be used with this type of the packet. /// </summary> /// <param name="buffer">Packet buffer</param> /// <param name="length">Buffer length</param> public override int decode(byte[] buffer, int length) { int offset = 0; MutableByte buf = new MutableByte(buffer, length); offset = base.decode(buffer, length); // parse community offset = _snmpCommunity.decode(buf, offset); // look ahead to make sure this is a TRAP packet int tmpOffset = offset; byte tmpAsnType = AsnType.ParseHeader(buffer, ref tmpOffset, out _); if (tmpAsnType != (byte)PduType.Trap) { throw new SnmpException(string.Format("Invalid SNMP ASN.1 type. Received: {0:x2}", tmpAsnType)); } // decode protocol data unit offset = this.Pdu.decode(buf, offset); return(offset); }
/// <summary>Encode SNMP packet for sending.</summary> /// <returns>BER encoded SNMP packet.</returns> /// <exception cref="SnmpInvalidPduTypeException"> /// Thrown when PDU being encoded is not a valid SNMP version 1 PDU. Acceptable /// protocol version 1 operations are GET, GET-NEXT, SET and RESPONSE. /// </exception> public override byte[] Encode() { if ( Pdu.Type != EPduType.Get && Pdu.Type != EPduType.GetNext && Pdu.Type != EPduType.Set && Pdu.Type != EPduType.Response) { throw new SnmpInvalidVersionException("Invalid SNMP PDU type while attempting to encode PDU: " + string.Format("0x{0:x2}", Pdu.Type)); } if (Pdu.RequestId == 0) { Random rand = new Random((int)DateTime.Now.Ticks); Pdu.RequestId = rand.Next(); } MutableByte tmpBuffer = new MutableByte(); // snmp version protocolVersion.Encode(tmpBuffer); // community string Community.Encode(tmpBuffer); // pdu Pdu.Encode(tmpBuffer); MutableByte buf = new MutableByte(); // wrap the packet into a sequence AsnType.BuildHeader(buf, SnmpConstants.SmiSequence, tmpBuffer.Length); buf.Append(tmpBuffer); return(buf); }
public static AsnType Get(IPAddress agent, string community, string oid) { // Define agent parameters class AgentParameters agentParameters = new AgentParameters(SnmpVersion.Ver2, new OctetString(community)); // Construct target UdpTarget target = new UdpTarget(agent, 161, 2000, 1); // Pdu class used for all requests Pdu pdu = new Pdu(PduType.Get); pdu.VbList.Add(oid); //sysDescr // Make SNMP request var snmpResponse = target.Request(pdu, agentParameters) as SnmpV2Packet; AsnType result = null; // If result is null then agent didn't reply or we couldn't parse the reply. if (snmpResponse != null) { // ErrorStatus other then 0 is an error returned by // the Agent - see SnmpConstants for error definitions if (snmpResponse.Pdu.ErrorStatus != 0) { // agent reported an error with the request throw new Exception($"Error in SNMP reply. Error {snmpResponse.Pdu.ErrorStatus} index {snmpResponse.Pdu.ErrorIndex}"); } else { result = snmpResponse.Pdu.VbList[0].Value; } } target.Close(); return(result); }
/// <summary>Used to create correct variable type object for the specified encoded type</summary> /// <param name="asnType">ASN.1 type code</param> /// <returns>A new object matching type supplied or null if type was not recognized.</returns> public static AsnType GetSyntaxObject(byte asnType) { AsnType obj = null; if (asnType == SnmpConstants.SMI_INTEGER) { obj = new Integer32(); } else if (asnType == SnmpConstants.SMI_COUNTER32) { obj = new Counter32(); } else if (asnType == SnmpConstants.SMI_GAUGE32) { obj = new Gauge32(); } else if (asnType == SnmpConstants.SMI_COUNTER64) { obj = new Counter64(); } else if (asnType == SnmpConstants.SMI_TIMETICKS) { obj = new TimeTicks(); } else if (asnType == SnmpConstants.SMI_STRING) { obj = new OctetString(); } else if (asnType == SnmpConstants.SMI_OPAQUE) { obj = new Opaque(); } else if (asnType == SnmpConstants.SMI_IPADDRESS) { obj = new IpAddress(); } else if (asnType == SnmpConstants.SMI_OBJECTID) { obj = new Oid(); } else if (asnType == SnmpConstants.SMI_PARTY_CLOCK) { obj = new V2PartyClock(); } else if (asnType == SnmpConstants.SMI_NOSUCHINSTANCE) { obj = new NoSuchInstance(); } else if (asnType == SnmpConstants.SMI_NOSUCHOBJECT) { obj = new NoSuchObject(); } else if (asnType == SnmpConstants.SMI_ENDOFMIBVIEW) { obj = new EndOfMibView(); } else if (asnType == SnmpConstants.SMI_NULL) { obj = new Null(); } return(obj); }
/// <summary>Encode SNMP version 3 packet</summary> /// <param name="authKey">Authentication key (not password)</param> /// <param name="privKey">Privacy key (not password)</param> /// <remarks> /// Before encoding the packet into a byte array you need to ensure all required information is /// set. Examples of required information is request type, Vbs (Oid + values pairs), USM settings including /// SecretName, authentication method and secret (if needed), privacy method and secret (if needed), etc. /// </remarks> /// <returns>Byte array BER encoded SNMP packet.</returns> public byte[] Encode(byte[] authKey, byte[] privKey) { MutableByte buffer = new MutableByte(); // encode the global message data sequence header information MutableByte globalMessageData = new MutableByte(); // if message id is 0 then generate a new, random message id if (messageId.Value == 0) { Random rand = new Random(); messageId.Value = rand.Next(1, int.MaxValue); } // encode message id messageId.Encode(globalMessageData); // encode max message size maxMessageSize.Encode(globalMessageData); // message flags messageFlags.Encode(globalMessageData); // security model code securityModel.Value = userSecurityModel.Type; securityModel.Encode(globalMessageData); // add global message data to the main buffer // encode sequence header and add data AsnType.BuildHeader(buffer, SnmpConstants.SmiSequence, globalMessageData.Length); buffer.Append(globalMessageData); MutableByte packetHeader = new MutableByte(buffer); // before going down this road, check if this is a discovery packet OctetString savedUserName = new OctetString(); bool privacy = messageFlags.Privacy; bool authentication = messageFlags.Authentication; bool reportable = messageFlags.Reportable; if (userSecurityModel.EngineId.Length <= 0) { // save USM settings prior to encoding a Discovery packet savedUserName.Set(userSecurityModel.SecurityName); userSecurityModel.SecurityName.Reset(); // delete security name for discovery packets messageFlags.Authentication = false; messageFlags.Privacy = false; messageFlags.Reportable = true; } userSecurityModel.Encode(buffer); if (userSecurityModel.EngineId.Length <= 0) { // restore saved USM values userSecurityModel.SecurityName.Set(savedUserName); messageFlags.Authentication = authentication; messageFlags.Privacy = privacy; messageFlags.Reportable = reportable; } // Check if privacy encryption is required MutableByte encodedPdu = new MutableByte(); if (messageFlags.Privacy && userSecurityModel.EngineId.Length > 0) { IPrivacyProtocol privacyProtocol = PrivacyProtocol.GetInstance(userSecurityModel.Privacy); if (privacyProtocol == null) { throw new SnmpException(SnmpException.EErrorCode.UnsupportedPrivacyProtocol, "Specified privacy protocol is not supported."); } // Get BER encoded ScopedPdu MutableByte unencryptedPdu = new MutableByte(); scopedPdu.Encode(unencryptedPdu); // we have to expand the key IAuthenticationDigest auth = Authentication.GetInstance(userSecurityModel.Authentication); if (auth == null) { throw new SnmpException(SnmpException.EErrorCode.UnsupportedNoAuthPriv, "Invalid authentication protocol. noAuthPriv mode not supported."); } byte[] encryptedBuffer = privacyProtocol.Encrypt(unencryptedPdu, 0, unencryptedPdu.Length, privKey, userSecurityModel.EngineBoots, userSecurityModel.EngineTime, out byte[] privacyParameters, auth); userSecurityModel.PrivacyParameters.Set(privacyParameters); OctetString encryptedOctetString = new OctetString(encryptedBuffer); encryptedOctetString.Encode(encodedPdu); // now redo packet encoding buffer.Reset(); buffer.Set(packetHeader); userSecurityModel.Encode(buffer); int preEncodedLength = encodedPdu.Length; buffer.Append(encodedPdu); if (maxMessageSize.Value != 0) { // verify compliance with maximum message size if ((encodedPdu.Length - preEncodedLength) > maxMessageSize) { throw new SnmpException(SnmpException.EErrorCode.MaximumMessageSizeExceeded, "ScopedPdu exceeds maximum message size."); } } } else { scopedPdu.Encode(encodedPdu); buffer.Append(encodedPdu); } Encode(buffer); if (messageFlags.Authentication && userSecurityModel.EngineId.Length > 0) { userSecurityModel.Authenticate(authKey, ref buffer); // Now re-encode the packet with the authentication information userSecurityModel.Encode(packetHeader); packetHeader.Append(encodedPdu); Encode(packetHeader); buffer = packetHeader; } return(buffer); }
/// <summary> /// Decode SNMP version 3 packet. This method will perform authentication check and decode privacy protected <see cref="ScopedPdu"/>. This method will /// not check for the timeliness of the packet, correct engine boot value or engine id because it does not have a reference to the engine time prior to this call. /// </summary> /// <param name="berBuffer">BER encoded SNMP version 3 packet buffer</param> /// <param name="length">Buffer length</param> /// <param name="authKey">Authentication key (not password)</param> /// <param name="privKey">Privacy key (not password)</param> /// <returns>The length of the decoded segment</returns> public int Decode(byte[] berBuffer, int length, byte[] authKey, byte[] privKey) { MutableByte buffer = new MutableByte(berBuffer, length); int offset = 0; // let base class parse first sequence and SNMP version number offset = base.Decode(buffer, length); // check for correct SNMP protocol version if (protocolVersion != (int)ESnmpVersion.Ver3) { throw new SnmpInvalidVersionException("Expecting SNMP version 3."); } // now grab the global message data sequence header information byte asnType = AsnType.ParseHeader(buffer, ref offset, out int len); if (asnType != SnmpConstants.SmiSequence) { throw new SnmpDecodingException("Invalid sequence type in global message data sequence."); } // check that packet size can accommodate the length specified in the header if (len > (buffer.Length - offset)) { throw new OverflowException("Packet is too small to contain the data described in the header."); } // retrieve message id offset = messageId.Decode(buffer, offset); // max message size offset = maxMessageSize.Decode(buffer, offset); // message flags offset = messageFlags.Decode(buffer, offset); // verify that a valid authentication/privacy configuration is present in the packet if (messageFlags.Authentication == false && messageFlags.Privacy == true) { throw new SnmpException(SnmpException.EErrorCode.UnsupportedNoAuthPriv, "SNMP version 3 noAuthPriv security combination is not supported."); } // security model code offset = securityModel.Decode(buffer, offset); // we only support USM. code = 0x03 if (securityModel.Value != userSecurityModel.Type) { throw new SnmpException(SnmpException.EErrorCode.UnsupportedSecurityModel, "Class only support SNMP Version 3 User Security Model."); } // parse user security model offset = userSecurityModel.Decode(buffer, offset); // Authenticate message if authentication flag is set and packet is not a discovery packet if (messageFlags.Authentication && userSecurityModel.EngineId.Length > 0) { // Authenticate packet if (userSecurityModel.AuthenticationParameters.Length != 12) { throw new SnmpAuthenticationException("Invalid authentication parameter field length."); } if (!userSecurityModel.IsAuthentic(authKey, buffer)) { throw new SnmpAuthenticationException("Authentication of the incoming packet failed."); } } // Decode ScopedPdu if it is privacy protected and packet is not a discovery packet if (messageFlags.Privacy && userSecurityModel.EngineId.Length > 0) { IPrivacyProtocol privacyProtocol = PrivacyProtocol.GetInstance(userSecurityModel.Privacy); if (privacyProtocol == null) { throw new SnmpException(SnmpException.EErrorCode.UnsupportedPrivacyProtocol, "Privacy protocol requested is not supported."); } if (userSecurityModel.PrivacyParameters.Length != privacyProtocol.PrivacyParametersLength) { throw new SnmpException(SnmpException.EErrorCode.InvalidPrivacyParameterLength, "Invalid privacy parameters field length."); } // Initialize a temporary OctetString class to hold encrypted ScopedPdu OctetString encryptedScopedPdu = new OctetString(); offset = encryptedScopedPdu.Decode(buffer, offset); // decode encrypted packet byte[] decryptedScopedPdu = privacyProtocol.Decrypt(encryptedScopedPdu, 0, encryptedScopedPdu.Length, privKey, userSecurityModel.EngineBoots, userSecurityModel.EngineTime, userSecurityModel.PrivacyParameters); int tempOffset = 0; offset = scopedPdu.Decode(decryptedScopedPdu, tempOffset); } else { offset = scopedPdu.Decode(buffer, offset); } return(offset); }
/// <summary> /// SET class value from supplied Vb class /// </summary> /// <param name="value">Vb class to clone data from</param> public void Set(Vb value) { _oid = (Oid)value.Oid.Clone(); _value = (Oid)value.Value.Clone(); }
/// <summary>Construct Vb with the supplied OID and Null value</summary> /// <param name="oid">OID</param> public Vb(Oid oid) : this() { this.oid = (Oid)oid.Clone(); value = new Null(); }
/// <summary>Construct Vb with the oid value and <seealso cref="Null"/> value.</summary> /// <param name="oid">String representing OID value to set</param> public Vb(string oid) : this() { this.oid = new Oid(oid); value = new Null(); }
/// <summary> /// SET class value from supplied Vb class /// </summary> /// <param name="value">Vb class to clone data from</param> public void Set(Vb value) { this._oid = (Oid)value.Oid.Clone(); this._value = (Oid)value.Value.Clone(); }
/// <summary> /// Construct Vb with the oid value and <seealso cref="Null"/> value. /// </summary> /// <param name="oid">String representing OID value to set</param> public Vb(string oid) : this() { _oid = new Oid(oid); _value = new Null(); }
/// <summary> /// Construct Vb with the supplied OID and Null value /// </summary> /// <param name="oid">OID</param> public Vb(Oid oid) : this() { _oid = (Oid)oid.Clone(); _value = new Null(); }
/// <summary> /// Reset Vb value to Null /// </summary> public void ResetValue() { _value = new Null(); }
/// <summary> /// Executa uma requisição do tipo Set /// </summary> /// <param name="setValue">Valor a set definido</param> public void Send(AsnType setValue) { using (var target = new UdpTarget(Host.IP, Host.Port, TimeOut, Retries)) { var agentp = new AgentParameters(SnmpVersion.Ver2, new OctetString(Host.Community)); // Caso necessario, appenda o .0 na requisição var oid = new Oid(Object.OID); if (oid[oid.Length - 1] != 0) oid.Add(0); // Cria pacote de dados RequestData = new Pdu(setValue == null ? PduType.Get : PduType.Set); // Adiciona dados da requisição switch (RequestData.Type) { case PduType.Get: RequestData.VbList.Add(oid); break; case PduType.Set: RequestData.VbList.Add(oid, setValue); break; default: throw new InvalidOperationException("unsupported"); } try { if (LogRequests) Logger.Self.Log(this); Timestamp = DateTime.Now; // Envia requisição ResponsePacket = target.Request(RequestData, agentp) as SnmpV2Packet; // Trata resposta if (ResponsePacket != null && ResponsePacket.Pdu.ErrorStatus == (int)PduErrorStatus.noError) { // TODO: suportar mais de um retorno var item = ResponsePacket.Pdu.VbList[0]; ResponseValue = item.Value; if (LogRequests) Logger.Self.Log(item); } } catch (Exception ex) { if (LogRequests) Logger.Self.Log(ex); throw new SnmpException("Não foi possível realizar a operação"); } } }