/// <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>Decode BER encoded SNMP version 1 trap packet</summary> /// <param name="buffer">BER encoded buffer</param> /// <param name="offset">Offset in the packet to start decoding from</param> /// <returns>Buffer position after the decoded value.</returns> /// <exception cref="SnmpException">Invalid SNMP Pdu type received. Not an SNMP version 1 Trap PDU.</exception> /// <exception cref="SnmpException">Invalid Variable Binding list encoding.</exception> public override int Decode(byte[] buffer, int offset) { byte asnType = ParseHeader(buffer, ref offset, out int headerLength); if (asnType != (byte)PduType.Trap) { throw new SnmpException("Invalid PDU type."); } if (headerLength > buffer.Length - offset) { throw new OverflowException("Packet is too short."); } offset = _enterprise.Decode(buffer, offset); offset = _agentAddr.Decode(buffer, offset); offset = _generic.Decode(buffer, offset); offset = _specific.Decode(buffer, offset); offset = _timeStamp.Decode(buffer, offset); // clean out the current variables VbList.Clear(); offset = VbList.Decode(buffer, offset); return(offset); }
/// <summary> /// Decode SNMP packet header. This class decodes the initial sequence and SNMP protocol version /// number. /// </summary> /// <param name="buffer">BER encoded SNMP packet</param> /// <param name="length">Packet length</param> /// <returns>Offset position after the initial sequence header and protocol version value</returns> /// <exception cref="SnmpDecodingException">Thrown when invalid sequence type is found at the start of the SNMP packet being decoded</exception> public virtual int Decode(byte[] buffer, int length) { int offset = 0; if (length < 2) { // we need at least 2 bytes throw new OverflowException("Packet too small."); } // make sure you get the right length buffer to be able to check for over/under flow errors MutableByte buf = new MutableByte(buffer, length); Sequence seq = new Sequence(); offset = seq.Decode(buf, offset); if (seq.Type != SnmpConstants.SmiSequence) { throw new SnmpDecodingException("Invalid sequence type at the start of the SNMP packet."); } offset = protocolVersion.Decode(buf, offset); return(offset); }
/// <summary> /// Decode USM portion of the SNMP version 3 packet. /// </summary> /// <param name="buffer">Received SNMP packet BER encoded</param> /// <param name="offset">Offset within the buffer to start decoding USM information</param> /// <returns>Buffer position after the decoded value</returns> /// <exception cref="SnmpDecodingException">Thrown when decoding enountered invalid data type in USM information</exception> /// <exception cref="OverflowException">Thrown when packet is too small to contain information length specified in header</exception> public override int Decode(byte[] buffer, int offset) { // Grab the octet string header byte type = ParseHeader(buffer, ref offset, out int len); if (type != OCTETSTRING) { throw new SnmpDecodingException("Invalid value type found while looking for USM header."); } if (len > (buffer.Length - offset)) { throw new OverflowException("Packet too small"); } // Now grab the sequence header type = ParseHeader(buffer, ref offset, out len); if (type != SnmpConstants.SMI_SEQUENCE) { throw new SnmpDecodingException("Sequence missing from USM header."); } if (len > (buffer.Length - offset)) { throw new OverflowException("Packet too small"); } // now grab values one at the time offset = _engineId.Decode(buffer, offset); offset = _engineBoots.Decode(buffer, offset); offset = _engineTime.Decode(buffer, offset); offset = _securityName.Decode(buffer, offset); int saveOffset = offset; offset = AuthenticationParameters.Decode(buffer, offset); if (AuthenticationParameters.Length > 0) { // walk through and set the authentication parameters to 0x00 in the packet saveOffset += 2; // Skip BER encoded variable type and length for (int i = 0; i < AuthenticationParameters.Length; i++) { buffer[saveOffset + i] = 0x00; } } offset = _privacyParameters.Decode(buffer, offset); return(offset); }
/// <summary>Decode BER encoded Pdu</summary> /// <remarks> /// Decodes the protocol data unit from the passed buffer. If an error /// occurs during the decoding sequence then an AsnDecodingException is /// thrown by the method. The value is decoded using the AsnEncoder /// passed to the object. /// </remarks> /// <param name="buffer">BER encoded buffer</param> /// <param name="offset">The offset byte to begin decoding</param> /// <returns>Buffer position after the decoded value</returns> /// <exception cref="OverflowException">Thrown when header points to more data then is available.</exception> public override int Decode(byte[] buffer, int offset) { byte asnType = ParseHeader(buffer, ref offset, out int headerLength); if (offset + headerLength > buffer.Length) { throw new OverflowException("Insufficient data in packet"); } base.Type = asnType; // request id offset = requestId.Decode(buffer, offset); // error status offset = errorStatus.Decode(buffer, offset); // error index offset = errorIndex.Decode(buffer, offset); // clean out the current variables VbList.Clear(); // decode the Variable binding collection offset = VbList.Decode(buffer, offset); // if Pdu is an SNMP version 2 TRAP, remove sysUpTime and trapObjectID from the VarBinds array if (Type == EPduType.V2Trap || Type == EPduType.Inform) { if (VbList.Count > 0) { if (VbList[0].Oid.Equals(SnmpConstants.SysUpTime)) { TrapSysUpTime.Set(VbList[0].Value); VbList.RemoveAt(0); // remove sysUpTime } } if (VbList.Count > 0) { if (VbList[0].Oid.Equals(SnmpConstants.TrapObjectId)) { trapObjectID.Set((Oid)VbList[0].Value); VbList.RemoveAt(0); // remove sysUpTime } } } return(offset); }
/// <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(); offset = 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); }