/// <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> /// 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); }
/// <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); }
/// <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 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); }
/// <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); }