Exemplo n.º 1
0
        /// <summary>
        /// Parses the SHUTDOWN chunk fields.
        /// </summary>
        /// <param name="buffer">The buffer holding the serialised chunk.</param>
        /// <param name="posn">The position to start parsing at.</param>
        public static SctpShutdownChunk ParseChunk(byte[] buffer, int posn)
        {
            var shutdownChunk = new SctpShutdownChunk();

            shutdownChunk.CumulativeTsnAck = NetConvert.ParseUInt32(buffer, posn + SCTP_CHUNK_HEADER_LENGTH);
            return(shutdownChunk);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Parses the an DCEP open message from a buffer.
        /// </summary>
        /// <param name="buffer">The buffer to parse the message from.</param>
        /// <param name="posn">The position in the buffer to start parsing from.</param>
        /// <returns>A new DCEP open message instance.</returns>
        public static DataChannelOpenMessage Parse(byte[] buffer, int posn)
        {
            if (buffer.Length < DCEP_OPEN_FIXED_PARAMETERS_LENGTH)
            {
                throw new ApplicationException("The buffer did not contain the minimum number of bytes for a DCEP open message.");
            }

            var dcepOpen = new DataChannelOpenMessage();

            dcepOpen.MessageType = buffer[posn];
            dcepOpen.ChannelType = buffer[posn + 1];
            dcepOpen.Priority    = NetConvert.ParseUInt16(buffer, posn + 2);
            dcepOpen.Reliability = NetConvert.ParseUInt32(buffer, posn + 4);

            ushort labelLength    = NetConvert.ParseUInt16(buffer, posn + 8);
            ushort protocolLength = NetConvert.ParseUInt16(buffer, posn + 10);

            if (labelLength > 0)
            {
                dcepOpen.Label = Encoding.UTF8.GetString(buffer, 12, labelLength);
            }

            if (protocolLength > 0)
            {
                dcepOpen.Protocol = Encoding.UTF8.GetString(buffer, 12 + labelLength, protocolLength);
            }

            return(dcepOpen);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Parses the SACK chunk fields.
        /// </summary>
        /// <param name="buffer">The buffer holding the serialised chunk.</param>
        /// <param name="posn">The position to start parsing at.</param>
        public static SctpSackChunk ParseChunk(byte[] buffer, int posn)
        {
            var    sackChunk = new SctpSackChunk();
            ushort chunkLen  = sackChunk.ParseFirstWord(buffer, posn);

            ushort startPosn = (ushort)(posn + SCTP_CHUNK_HEADER_LENGTH);

            sackChunk.CumulativeTsnAck = NetConvert.ParseUInt32(buffer, startPosn);
            sackChunk.ARwnd            = NetConvert.ParseUInt32(buffer, startPosn + 4);
            ushort numGapAckBlocks  = NetConvert.ParseUInt16(buffer, startPosn + 8);
            ushort numDuplicateTSNs = NetConvert.ParseUInt16(buffer, startPosn + 10);

            int reportPosn = startPosn + FIXED_PARAMETERS_LENGTH;

            for (int i = 0; i < numGapAckBlocks; i++)
            {
                ushort start = NetConvert.ParseUInt16(buffer, reportPosn);
                ushort end   = NetConvert.ParseUInt16(buffer, reportPosn + 2);
                sackChunk.GapAckBlocks.Add(new SctpTsnGapBlock {
                    Start = start, End = end
                });
                reportPosn += GAP_REPORT_LENGTH;
            }

            for (int j = 0; j < numDuplicateTSNs; j++)
            {
                sackChunk.DuplicateTSN.Add(NetConvert.ParseUInt32(buffer, reportPosn));
                reportPosn += DUPLICATE_TSN_LENGTH;
            }

            return(sackChunk);
        }
Exemplo n.º 4
0
        /// <summary>
        /// Parses the DATA chunk fields
        /// </summary>
        /// <param name="buffer">The buffer holding the serialised chunk.</param>
        /// <param name="posn">The position to start parsing at.</param>
        public static SctpDataChunk ParseChunk(byte[] buffer, int posn)
        {
            var    dataChunk = new SctpDataChunk();
            ushort chunkLen  = dataChunk.ParseFirstWord(buffer, posn);

            if (chunkLen < FIXED_PARAMETERS_LENGTH)
            {
                throw new ApplicationException($"SCTP data chunk cannot be parsed as buffer too short for fixed parameter fields.");
            }

            dataChunk.Unordered = (dataChunk.ChunkFlags & 0x04) > 0;
            dataChunk.Begining  = (dataChunk.ChunkFlags & 0x02) > 0;
            dataChunk.Ending    = (dataChunk.ChunkFlags & 0x01) > 0;

            int startPosn = posn + SCTP_CHUNK_HEADER_LENGTH;

            dataChunk.TSN          = NetConvert.ParseUInt32(buffer, startPosn);
            dataChunk.StreamID     = NetConvert.ParseUInt16(buffer, startPosn + 4);
            dataChunk.StreamSeqNum = NetConvert.ParseUInt16(buffer, startPosn + 6);
            dataChunk.PPID         = NetConvert.ParseUInt32(buffer, startPosn + 8);

            int userDataPosn = startPosn + FIXED_PARAMETERS_LENGTH;
            int userDataLen  = chunkLen - SCTP_CHUNK_HEADER_LENGTH - FIXED_PARAMETERS_LENGTH;

            if (userDataLen > 0)
            {
                dataChunk.UserData = new byte[userDataLen];
                Buffer.BlockCopy(buffer, userDataPosn, dataChunk.UserData, 0, dataChunk.UserData.Length);
            }

            return(dataChunk);
        }
Exemplo n.º 5
0
        /// <summary>
        /// Verifies whether the checksum for a serialised SCTP packet is valid.
        /// </summary>
        /// <param name="buffer">The buffer holding the serialised packet.</param>
        /// <param name="posn">The start position in the buffer.</param>
        /// <param name="length">The length of the packet in the buffer.</param>
        /// <returns>True if the checksum was valid, false if not.</returns>
        public static bool VerifyChecksum(byte[] buffer, int posn, int length)
        {
            uint origChecksum = NetConvert.ParseUInt32(buffer, posn + CHECKSUM_BUFFER_POSITION);

            NetConvert.ToBuffer(0U, buffer, posn + CHECKSUM_BUFFER_POSITION);
            uint calcChecksum = CRC32C.Calculate(buffer, posn, length);

            // Put the original checksum back.
            NetConvert.ToBuffer(origChecksum, buffer, posn + CHECKSUM_BUFFER_POSITION);

            return(origChecksum == NetConvert.EndianFlip(calcChecksum));
        }
Exemplo n.º 6
0
        /// <summary>
        /// Parses the an SCTP header from a buffer.
        /// </summary>
        /// <param name="buffer">The buffer to parse the SCTP header from.</param>
        /// <param name="posn">The position in the buffer to start parsing the header from.</param>
        /// <returns>A new SCTPHeaer instance.</returns>
        public static SctpHeader Parse(byte[] buffer, int posn)
        {
            if (buffer.Length < SCTP_HEADER_LENGTH)
            {
                throw new ApplicationException("The buffer did not contain the minimum number of bytes for an SCTP header.");
            }

            SctpHeader header = new SctpHeader();

            header.SourcePort      = NetConvert.ParseUInt16(buffer, posn);
            header.DestinationPort = NetConvert.ParseUInt16(buffer, posn + 2);
            header.VerificationTag = NetConvert.ParseUInt32(buffer, posn + 4);
            header.Checksum        = NetConvert.ParseUInt32(buffer, posn + 8);

            return(header);
        }
Exemplo n.º 7
0
        public void ParseBindingRequestWithIceControlledAttribute()
        {
            var buffer = new byte[]
            {
                0x00, 0x01, 0x00, 0x50, 0x21, 0x12, 0xa4, 0x42, 0x0c, 0x66, 0x64, 0x5a, 0xf7, 0xe9, 0xe6, 0x57,
                0x3f, 0x53, 0x2b, 0x33, 0x00, 0x24, 0x00, 0x04, 0x6e, 0x7f, 0xff, 0xff, 0x80, 0x29, 0x00, 0x08,
                0x27, 0xff, 0x2a, 0x17, 0x1b, 0x88, 0x8f, 0xfe, 0x80, 0x22, 0x00, 0x08, 0x6c, 0x69, 0x62, 0x6a,
                0x75, 0x69, 0x63, 0x65, 0x00, 0x06, 0x00, 0x09, 0x4e, 0x4f, 0x43, 0x47, 0x3a, 0x6b, 0x57, 0x55,
                0x48, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x14, 0x23, 0x7e, 0x24, 0x6c, 0x44, 0x12, 0xbc, 0x43,
                0xfc, 0x63, 0x01, 0xf4, 0xda, 0x36, 0x73, 0xdf, 0x84, 0xb8, 0x23, 0xd6, 0x80, 0x28, 0x00, 0x04,
                0x07, 0x8a, 0x49, 0x2e
            };

            var stunReq = STUNMessage.ParseSTUNMessage(buffer, buffer.Length);

            Assert.NotNull(stunReq);
            Assert.Equal(1853882367U,
                         NetConvert.ParseUInt32(stunReq.Attributes.Single(x => x.AttributeType == STUNAttributeTypesEnum.Priority).Value, 0));
            Assert.Equal(8, stunReq.Attributes.Single(x => x.AttributeType == STUNAttributeTypesEnum.IceControlled).PaddedLength);
            Assert.Equal(0x27ff2a171b888ffeU,
                         NetConvert.ParseUInt64(stunReq.Attributes.Single(x => x.AttributeType == STUNAttributeTypesEnum.IceControlled).Value, 0));
        }
Exemplo n.º 8
0
        /// <summary>
        /// Parses the INIT or INIT ACK chunk fields
        /// </summary>
        /// <param name="buffer">The buffer holding the serialised chunk.</param>
        /// <param name="posn">The position to start parsing at.</param>
        public static SctpInitChunk ParseChunk(byte[] buffer, int posn)
        {
            var    initChunk = new SctpInitChunk();
            ushort chunkLen  = initChunk.ParseFirstWord(buffer, posn);

            int startPosn = posn + SCTP_CHUNK_HEADER_LENGTH;

            initChunk.InitiateTag           = NetConvert.ParseUInt32(buffer, startPosn);
            initChunk.ARwnd                 = NetConvert.ParseUInt32(buffer, startPosn + 4);
            initChunk.NumberOutboundStreams = NetConvert.ParseUInt16(buffer, startPosn + 8);
            initChunk.NumberInboundStreams  = NetConvert.ParseUInt16(buffer, startPosn + 10);
            initChunk.InitialTSN            = NetConvert.ParseUInt32(buffer, startPosn + 12);

            int paramPosn          = startPosn + FIXED_PARAMETERS_LENGTH;
            int paramsBufferLength = chunkLen - SCTP_CHUNK_HEADER_LENGTH - FIXED_PARAMETERS_LENGTH;

            if (paramPosn < paramsBufferLength)
            {
                bool stopProcessing = false;

                foreach (var varParam in GetParameters(buffer, paramPosn, paramsBufferLength))
                {
                    switch (varParam.ParameterType)
                    {
                    case (ushort)SctpInitChunkParameterType.IPv4Address:
                    case (ushort)SctpInitChunkParameterType.IPv6Address:
                        var address = new IPAddress(varParam.ParameterValue);
                        initChunk.Addresses.Add(address);
                        break;

                    case (ushort)SctpInitChunkParameterType.CookiePreservative:
                        initChunk.CookiePreservative = NetConvert.ParseUInt32(varParam.ParameterValue, 0);
                        break;

                    case (ushort)SctpInitChunkParameterType.HostNameAddress:
                        initChunk.HostnameAddress = Encoding.UTF8.GetString(varParam.ParameterValue);
                        break;

                    case (ushort)SctpInitChunkParameterType.SupportedAddressTypes:
                        for (int valPosn = 0; valPosn < varParam.ParameterValue.Length; valPosn += 2)
                        {
                            switch (NetConvert.ParseUInt16(varParam.ParameterValue, valPosn))
                            {
                            case (ushort)SctpInitChunkParameterType.IPv4Address:
                                initChunk.SupportedAddressTypes.Add(SctpInitChunkParameterType.IPv4Address);
                                break;

                            case (ushort)SctpInitChunkParameterType.IPv6Address:
                                initChunk.SupportedAddressTypes.Add(SctpInitChunkParameterType.IPv6Address);
                                break;

                            case (ushort)SctpInitChunkParameterType.HostNameAddress:
                                initChunk.SupportedAddressTypes.Add(SctpInitChunkParameterType.HostNameAddress);
                                break;
                            }
                        }
                        break;

                    case (ushort)SctpInitChunkParameterType.EcnCapable:
                        break;

                    case (ushort)SctpInitChunkParameterType.StateCookie:
                        // Used with INIT ACK chunks only.
                        initChunk.StateCookie = varParam.ParameterValue;
                        break;

                    case (ushort)SctpInitChunkParameterType.UnrecognizedParameter:
                        // Used with INIT ACK chunks only. This parameter is the remote peer returning
                        // a list of parameters it did not understand in the INIT chunk.
                        initChunk.UnrecognizedParameters.Add(varParam.ParameterValue);
                        break;

                    default:
                        // Parameters are not recognised in an INIT or INIT ACK.
                        initChunk.GotUnrecognisedParameter(varParam);
                        break;
                    }

                    if (stopProcessing)
                    {
                        logger.LogWarning($"SCTP unrecognised parameter {varParam.ParameterType} for chunk type {initChunk.KnownType} "
                                          + "indicated no further chunks should be processed.");
                        break;
                    }
                }
            }

            return(initChunk);
        }
Exemplo n.º 9
0
        /// <summary>
        /// Parses the ERROR chunk fields.
        /// </summary>
        /// <param name="buffer">The buffer holding the serialised chunk.</param>
        /// <param name="posn">The position to start parsing at.</param>
        public static SctpErrorChunk ParseChunk(byte[] buffer, int posn, bool isAbort)
        {
            var    errorChunk = (isAbort) ? new SctpAbortChunk(false) : new SctpErrorChunk();
            ushort chunkLen   = errorChunk.ParseFirstWord(buffer, posn);

            int paramPosn          = posn + SCTP_CHUNK_HEADER_LENGTH;
            int paramsBufferLength = chunkLen - SCTP_CHUNK_HEADER_LENGTH;

            if (paramPosn < paramsBufferLength)
            {
                bool stopProcessing = false;

                foreach (var varParam in GetParameters(buffer, paramPosn, paramsBufferLength))
                {
                    switch (varParam.ParameterType)
                    {
                    case (ushort)SctpErrorCauseCode.InvalidStreamIdentifier:
                        ushort streamID = (ushort)((varParam.ParameterValue != null) ?
                                                   NetConvert.ParseUInt16(varParam.ParameterValue, 0) : 0);
                        var invalidStreamID = new SctpErrorInvalidStreamIdentifier {
                            StreamID = streamID
                        };
                        errorChunk.AddErrorCause(invalidStreamID);
                        break;

                    case (ushort)SctpErrorCauseCode.MissingMandatoryParameter:
                        List <ushort> missingIDs = new List <ushort>();
                        if (varParam.ParameterValue != null)
                        {
                            for (int i = 0; i < varParam.ParameterValue.Length; i += 2)
                            {
                                missingIDs.Add(NetConvert.ParseUInt16(varParam.ParameterValue, i));
                            }
                        }
                        var missingMandatory = new SctpErrorMissingMandatoryParameter {
                            MissingParameters = missingIDs
                        };
                        errorChunk.AddErrorCause(missingMandatory);
                        break;

                    case (ushort)SctpErrorCauseCode.StaleCookieError:
                        uint staleness = (uint)((varParam.ParameterValue != null) ?
                                                NetConvert.ParseUInt32(varParam.ParameterValue, 0) : 0);
                        var staleCookie = new SctpErrorStaleCookieError {
                            MeasureOfStaleness = staleness
                        };
                        errorChunk.AddErrorCause(staleCookie);
                        break;

                    case (ushort)SctpErrorCauseCode.OutOfResource:
                        errorChunk.AddErrorCause(new SctpCauseOnlyError(SctpErrorCauseCode.OutOfResource));
                        break;

                    case (ushort)SctpErrorCauseCode.UnresolvableAddress:
                        var unresolvable = new SctpErrorUnresolvableAddress {
                            UnresolvableAddress = varParam.ParameterValue
                        };
                        errorChunk.AddErrorCause(unresolvable);
                        break;

                    case (ushort)SctpErrorCauseCode.UnrecognizedChunkType:
                        var unrecognised = new SctpErrorUnrecognizedChunkType {
                            UnrecognizedChunk = varParam.ParameterValue
                        };
                        errorChunk.AddErrorCause(unrecognised);
                        break;

                    case (ushort)SctpErrorCauseCode.InvalidMandatoryParameter:
                        errorChunk.AddErrorCause(new SctpCauseOnlyError(SctpErrorCauseCode.InvalidMandatoryParameter));
                        break;

                    case (ushort)SctpErrorCauseCode.UnrecognizedParameters:
                        var unrecognisedParams = new SctpErrorUnrecognizedParameters {
                            UnrecognizedParameters = varParam.ParameterValue
                        };
                        errorChunk.AddErrorCause(unrecognisedParams);
                        break;

                    case (ushort)SctpErrorCauseCode.NoUserData:
                        uint tsn = (uint)((varParam.ParameterValue != null) ?
                                          NetConvert.ParseUInt32(varParam.ParameterValue, 0) : 0);
                        var noData = new SctpErrorNoUserData {
                            TSN = tsn
                        };
                        errorChunk.AddErrorCause(noData);
                        break;

                    case (ushort)SctpErrorCauseCode.CookieReceivedWhileShuttingDown:
                        errorChunk.AddErrorCause(new SctpCauseOnlyError(SctpErrorCauseCode.CookieReceivedWhileShuttingDown));
                        break;

                    case (ushort)SctpErrorCauseCode.RestartAssociationWithNewAddress:
                        var restartAddress = new SctpErrorRestartAssociationWithNewAddress
                        {
                            NewAddressTLVs = varParam.ParameterValue
                        };
                        errorChunk.AddErrorCause(restartAddress);
                        break;

                    case (ushort)SctpErrorCauseCode.UserInitiatedAbort:
                        string reason = (varParam.ParameterValue != null) ?
                                        Encoding.UTF8.GetString(varParam.ParameterValue) : null;
                        var userAbort = new SctpErrorUserInitiatedAbort {
                            AbortReason = reason
                        };
                        errorChunk.AddErrorCause(userAbort);
                        break;

                    case (ushort)SctpErrorCauseCode.ProtocolViolation:
                        string info = (varParam.ParameterValue != null) ?
                                      Encoding.UTF8.GetString(varParam.ParameterValue) : null;
                        var protocolViolation = new SctpErrorProtocolViolation {
                            AdditionalInformation = info
                        };
                        errorChunk.AddErrorCause(protocolViolation);
                        break;

                    default:
                        // Parameter was not recognised.
                        errorChunk.GotUnrecognisedParameter(varParam);
                        break;
                    }

                    if (stopProcessing)
                    {
                        logger.LogWarning($"SCTP unrecognised parameter {varParam.ParameterType} for chunk type {SctpChunkType.ERROR} "
                                          + "indicated no further chunks should be processed.");
                        break;
                    }
                }
            }

            return(errorChunk);
        }
Exemplo n.º 10
0
 /// <summary>
 /// Gets the verification tag from a serialised SCTP packet. This allows
 /// a pre-flight check to be carried out before de-serialising the whole buffer.
 /// </summary>
 /// <param name="buffer">The buffer holding the serialised packet.</param>
 /// <param name="posn">The start position in the buffer.</param>
 /// <param name="length">The length of the packet in the buffer.</param>
 /// <returns>The verification tag for the serialised SCTP packet.</returns>
 public static uint GetVerificationTag(byte[] buffer, int posn, int length)
 {
     return(NetConvert.ParseUInt32(buffer, posn + VERIFICATIONTAG_BUFFER_POSITION));
 }