예제 #1
0
        /// <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);
        }
예제 #2
0
        /// <summary>
        /// Decode message flags from the BER encoded buffer starting at specified offset.
        /// </summary>
        /// <param name="buffer">BER encoded buffer</param>
        /// <param name="offset">Offset within the buffer to start decoding process</param>
        /// <returns>Buffer position after the decoded value</returns>
        public override int Decode(byte[] buffer, int offset)
        {
            // reset class values
            _authenticationFlag = false;
            _privacyFlag        = false;
            _reportableFlag     = false;
            OctetString flagObject = new OctetString();

            offset = flagObject.Decode(buffer, offset);
            if (flagObject.Length > 0)
            {
                if ((flagObject[0] & FLAG_AUTH) != 0)
                {
                    _authenticationFlag = true;
                }

                if ((flagObject[0] & FLAG_PRIV) != 0)
                {
                    _privacyFlag = true;
                }

                if ((flagObject[0] & FLAG_REPORTABLE) != 0)
                {
                    _reportableFlag = true;
                }
            }
            else
            {
                throw new SnmpDecodingException("Invalid SNMPv3 flag field.");
            }
            return(offset);
        }
예제 #3
0
        /// <summary>
        /// Decode BER encoded <see cref="ScopedPdu"/> values. This method does not perform SNMP v3 privacy operations
        /// and is not aware of privacy requirements.
        ///
        /// To decode a privacy protected SNMP v3 packet, you will need to a) extract <see cref="OctetString"/> value
        /// holding encrypted <see cref="ScopedPdu"/> data, b) decrypt the encrypted ScopedPdu data into an unecrypted
        /// byte array, c) pass unencrypted <see cref="ScopedPdu"/> and BER encoded byte array to this method for
        /// final data conversion from BER into individual sequences and variables.
        /// </summary>
        /// <param name="buffer">Buffer holding BER encoded <see cref="ScopedPdu"/> data</param>
        /// <param name="offset">Offset within the buffer BER encoded <see cref="ScopedPdu"/> data begins.</param>
        /// <returns>Offset position after parsed ScopedPdu</returns>
        /// <exception cref="SnmpDecodingException">Error was encountered when decoding the PDU</exception>
        /// <exception cref="OverflowException">Thrown when buffer is too short to contain the PDU</exception>
        public override int Decode(byte[] buffer, int offset)
        {
            byte sequenceType = ParseHeader(buffer, ref offset, out int length);

            if (sequenceType != SnmpConstants.SMI_SEQUENCE)
            {
                throw new SnmpDecodingException("Invalid ScopedPdu sequence detected. Invalid ScopedPdu encoding.");
            }
            // verify packet can match parsed length
            if (length > (buffer.Length - offset))
            {
                throw new OverflowException("SNMP packet too short.");
            }

            // Reset scoped pdu specific variables
            _contextEngineId.Reset();
            _contextName.Reset();
            // parse scoped pdu specific variables
            offset = _contextEngineId.Decode(buffer, offset);
            offset = _contextName.Decode(buffer, offset);
            // decode base pdu
            offset = base.Decode(buffer, offset);

            return(offset);
        }
예제 #4
0
        /// <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);
        }
예제 #5
0
        /// <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 int headerLen);

            if (tmpAsnType != (byte)EPduType.Trap)
            {
                throw new SnmpException(string.Format("Invalid SNMP ASN.1 type. Received: {0:x2}", tmpAsnType));
            }

            // decode protocol data unit
            offset = Pdu.Decode(buf, offset);

            return(offset);
        }
예제 #6
0
        /// <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);
        }