Пример #1
0
        private static Smb2Packet CompressForNonChained(Smb2CompressiblePacket packet, Smb2CompressionInfo compressionInfo, Smb2Role role)
        {
            var compressionAlgorithm = GetCompressionAlgorithm(packet, compressionInfo, role);

            if (compressionAlgorithm == CompressionAlgorithm.NONE)
            {
                return(packet);
            }

            var packetBytes = packet.ToBytes();

            var compressor = GetCompressor(compressionAlgorithm);

            uint offset = 0;

            if (compressionInfo.CompressBufferOnly)
            {
                offset = (packet as IPacketBuffer).BufferOffset;
            }

            var compressedPacket = new Smb2NonChainedCompressedPacket();

            compressedPacket.Header.ProtocolId = Smb2Consts.ProtocolIdInCompressionTransformHeader;
            compressedPacket.Header.OriginalCompressedSegmentSize = (uint)packetBytes.Length;
            compressedPacket.Header.CompressionAlgorithm          = compressionAlgorithm;
            compressedPacket.Header.Flags     = Compression_Transform_Header_Flags.SMB2_COMPRESSION_FLAG_NONE;
            compressedPacket.Header.Offset    = offset;
            compressedPacket.UncompressedData = packetBytes.Take((int)offset).ToArray();
            compressedPacket.CompressedData   = compressor.Compress(packetBytes.Skip((int)offset).ToArray());

            compressedPacket.OriginalPacket = packet;

            return(compressedPacket);
        }
Пример #2
0
        /// <summary>
        /// Compress SMB2 packet.
        /// </summary>
        /// <param name="packet">The SMB2 packet.</param>
        /// <param name="compressionInfo">Compression info.</param>
        /// <param name="role">SMB2 role.</param>
        /// <returns>The compressed packet, or original packet if compression is not applicable.</returns>
        public static Smb2Packet Compress(Smb2CompressiblePacket packet, Smb2CompressionInfo compressionInfo, Smb2Role role)
        {
            Smb2Packet compressed;

            if (compressionInfo.SupportChainedCompression)
            {
                compressed = CompressForChained(packet, compressionInfo, role);
            }
            else
            {
                compressed = CompressForNonChained(packet, compressionInfo, role);
            }

            if (compressed == packet)
            {
                // Compression is not applicable.
                return(packet);
            }

            var originalBytes = packet.ToBytes();

            var compressedBytes = compressed.ToBytes();

            // Check whether compression shrinks the on-wire packet size
            if (compressedBytes.Length < originalBytes.Length)
            {
                return(compressed);
            }
            else
            {
                return(packet);
            }
        }
        private static Smb2Packet CompressForChained(Smb2CompressiblePacket packet, Smb2CompressionInfo compressionInfo, Smb2Role role)
        {
            bool needCompression = IsCompressionNeeded(packet, compressionInfo, role);

            if (!needCompression)
            {
                return(packet);
            }

            bool isPatternV1Supported = compressionInfo.CompressionIds.Contains(CompressionAlgorithm.Pattern_V1);

            Smb2Packet compressed;

            if (isPatternV1Supported)
            {
                compressed = CompressWithPatternV1(packet, compressionInfo, role);
            }
            else
            {
                // Regress to non-chained since pattern scanning algorithm is not supported.
                compressed = CompressForNonChained(packet, compressionInfo, role);
            }

            return(compressed);
        }
Пример #4
0
        /// <summary>
        /// Compress SMB2 packet.
        /// </summary>
        /// <param name="packet">The SMB2 packet.</param>
        /// <param name="compressionInfo">Compression info.</param>
        /// <param name="role">SMB2 role.</param>
        /// <param name="offset">The offset where compression start, default zero.</param>
        /// <returns></returns>
        public static Smb2Packet Compress(Smb2CompressiblePacket packet, Smb2CompressionInfo compressionInfo, Smb2Role role, uint offset = 0)
        {
            var compressionAlgorithm = GetCompressionAlgorithm(packet, compressionInfo, role);

            if (compressionAlgorithm == CompressionAlgorithm.NONE)
            {
                return packet;
            }

            var packetBytes = packet.ToBytes();

            var compressor = GetCompressor(compressionAlgorithm);

            var compressedPacket = new Smb2CompressedPacket();
            compressedPacket.Header.ProtocolId = Smb2Consts.ProtocolIdInCompressionTransformHeader;
            compressedPacket.Header.OriginalCompressedSegmentSize = (uint)packetBytes.Length;
            compressedPacket.Header.CompressionAlgorithm = compressionAlgorithm;
            compressedPacket.Header.Reserved = 0;
            compressedPacket.Header.Offset = offset;
            compressedPacket.UncompressedData = packetBytes.Take((int)offset).ToArray();
            compressedPacket.CompressedData = compressor.Compress(packetBytes.Skip((int)offset).ToArray());

            var compressedPackectBytes = compressedPacket.ToBytes();

            // Check whether compression shrinks the on-wire packet size
            if (compressedPackectBytes.Length < packetBytes.Length)
            {
                compressedPacket.OriginalPacket = packet;
                return compressedPacket;
            }
            else
            {
                return packet;
            }
        }
Пример #5
0
        private static bool IsCompressionNeeded(Smb2CompressiblePacket packet, Smb2CompressionInfo compressionInfo, Smb2Role role)
        {
            bool supportCompression = compressionInfo.CompressionIds.Any(compressionAlgorithm => compressionAlgorithm != CompressionAlgorithm.NONE);

            if (!supportCompression)
            {
                return(false);
            }

            bool needCompression = false;

            switch (role)
            {
            case Smb2Role.Client:
            {
                // Client will compress outgoing packets when:
                // 1. EligibleForCompression is set for write request. (when user hopes write request to be compressed)
                // 2. CompressAllPackets is set. (when user hopes all request to be compressed)
                if (compressionInfo.CompressAllPackets)
                {
                    needCompression = true;
                }
                else if (packet is Smb2WriteRequestPacket)
                {
                    needCompression = packet.EligibleForCompression;
                }
            }
            break;

            case Smb2Role.Server:
            {
                // Server will compress outgoing packets when:
                // 1. CompressAllPackets is set and EligibleForCompression. (when server hopes all responses to be compressed, and request is compressed)
                // 2. EligibleForCompression is set for read response.  (when compress read is specified in read request)
                if (compressionInfo.CompressAllPackets || packet is Smb2ReadResponsePacket)
                {
                    needCompression = packet.EligibleForCompression;
                }
            }
            break;

            default:
            {
                throw new InvalidOperationException("Unknown SMB2 role!");
            }
            }

            if (needCompression && compressionInfo.CompressBufferOnly)
            {
                // Not compress packet if it does not contain buffer.
                if (!(packet is IPacketBuffer) || (packet as IPacketBuffer).BufferLength == 0)
                {
                    needCompression = false;
                }
            }

            return(needCompression);
        }
Пример #6
0
        private static CompressionAlgorithm GetCompressionAlgorithm(Smb2CompressiblePacket packet, Smb2CompressionInfo compressionInfo, Smb2Role role)
        {
            bool needCompression = IsCompressionNeeded(packet, compressionInfo, role);

            if (!needCompression)
            {
                return(CompressionAlgorithm.NONE);
            }

            var result = GetPreferredCompressionAlgorithm(compressionInfo);

            return(result);
        }
Пример #7
0
        /// <summary>
        /// Compress SMB2 packet.
        /// </summary>
        /// <param name="packet">The SMB2 packet.</param>
        /// <param name="compressionInfo">Compression info.</param>
        /// <param name="role">SMB2 role.</param>
        /// <param name="offset">The offset where compression start, default zero.</param>
        /// <returns></returns>
        public static Smb2Packet Compress(Smb2CompressiblePacket packet, Smb2CompressionInfo compressionInfo, Smb2Role role, uint offset = 0)
        {
            var compressionAlgorithm = GetCompressionAlgorithm(packet, compressionInfo, role);

            if (compressionAlgorithm == CompressionAlgorithm.NONE)
            {
                return(packet);
            }

            var packetBytes = packet.ToBytes();

            var compressor = GetCompressor(compressionAlgorithm);

            var compressedPacket = new Smb2CompressedPacket();

            compressedPacket.Header.ProtocolId = Smb2Consts.ProtocolIdInCompressionTransformHeader;
            compressedPacket.Header.OriginalCompressedSegmentSize = (uint)packetBytes.Length;
            compressedPacket.Header.CompressionAlgorithm          = compressionAlgorithm;
            compressedPacket.Header.Reserved  = 0;
            compressedPacket.Header.Offset    = offset;
            compressedPacket.UncompressedData = packetBytes.Take((int)offset).ToArray();
            compressedPacket.CompressedData   = compressor.Compress(packetBytes.Skip((int)offset).ToArray());

            // HACK: fake size
            if (((Smb2SinglePacket)packet).Header.Command == Smb2Command.WRITE)
            {
                ((Smb2WriteRequestPacket)packet).PayLoad.Length       += 0x1000;
                compressedPacket.Header.OriginalCompressedSegmentSize += 0x1000;
            }

            // HACK: force compressed packet to be sent
            return(compressedPacket);

            // var compressedPackectBytes = compressedPacket.ToBytes();

            // Check whether compression shrinks the on-wire packet size
            // if (compressedPackectBytes.Length < packetBytes.Length)
            // {
            //     compressedPacket.OriginalPacket = packet;
            //     return compressedPacket;
            // }
            // else
            // {
            //     return packet;
            // }
        }
Пример #8
0
        private static CompressionAlgorithm GetCompressionAlgorithm(Smb2CompressiblePacket packet, Smb2CompressionInfo compressionInfo, Smb2Role role)
        {
            bool supportCompression = compressionInfo.CompressionIds.Any(compressionAlgorithm => compressionAlgorithm != CompressionAlgorithm.NONE);

            if (!supportCompression)
            {
                return(CompressionAlgorithm.NONE);
            }

            bool needCompression = false;

            switch (role)
            {
            case Smb2Role.Client:
            {
                // Client will compress outgoing packets when:
                // 1. EligibleForCompression is set for write request. (when user hopes write request to be compressed)
                // 2. CompressAllPackets is set. (when user hopes all request to be compressed)
                if (compressionInfo.CompressAllPackets)
                {
                    needCompression = true;
                }
                else if (packet is Smb2WriteRequestPacket)
                {
                    needCompression = packet.EligibleForCompression;
                }
            }
            break;

            case Smb2Role.Server:
            {
                // Server will compress outgoing packets when:
                // 1. CompressAllPackets is set and EligibleForCompression. (when server hopes all responses to be compressed, and request is compressed)
                // 2. EligibleForCompression is set for read response.  (when compress read is specified in read request)
                if (compressionInfo.CompressAllPackets || packet is Smb2ReadResponsePacket)
                {
                    needCompression = packet.EligibleForCompression;
                }
            }
            break;

            default:
            {
                throw new InvalidOperationException("Unknown SMB2 role!");
            }
            }

            if (!needCompression)
            {
                return(CompressionAlgorithm.NONE);
            }

            if (compressionInfo.PreferredCompressionAlgorithm == CompressionAlgorithm.NONE)
            {
                return(compressionInfo.CompressionIds.First(compressionAlgorithm => compressionAlgorithm != CompressionAlgorithm.NONE));
            }
            else
            {
                if (!compressionInfo.CompressionIds.Contains(compressionInfo.PreferredCompressionAlgorithm))
                {
                    throw new InvalidOperationException("Specified preferred compression algorithm is not supported by SUT!");
                }
                return(compressionInfo.PreferredCompressionAlgorithm);
            }
        }
        private static Smb2Packet CompressWithPatternV1(Smb2CompressiblePacket packet, Smb2CompressionInfo compressionInfo, Smb2Role role)
        {
            var data = packet.ToBytes();

            var dataToCompress = data;

            if (compressionInfo.CompressBufferOnly)
            {
                dataToCompress = data.Skip((packet as IPacketBuffer).BufferOffset).ToArray();
            }

            SMB2_COMPRESSION_PATTERN_PAYLOAD_V1?forwardDataPattern;

            SMB2_COMPRESSION_PATTERN_PAYLOAD_V1?backwardDataPattern;

            ScanForPatternV1(dataToCompress, out forwardDataPattern, out backwardDataPattern);

            if (forwardDataPattern == null && backwardDataPattern == null)
            {
                // Regress to non-chained since no pattern is found at front or end.
                return(CompressForNonChained(packet, compressionInfo, role));
            }

            var result = new Smb2ChainedCompressedPacket();

            result.OriginalPacket = packet;

            result.Header = new Compression_Transform_Header();

            result.Header.ProtocolId = Smb2Consts.ProtocolIdInCompressionTransformHeader;

            result.Header.OriginalCompressedSegmentSize = (UInt32)data.Length;

            result.Header.Flags = Compression_Transform_Header_Flags.SMB2_COMPRESSION_FLAG_CHAINED;

            var payloads = new List <Tuple <SMB2_COMPRESSION_PAYLOAD_HEADER, object> >();

            bool isFirst = true;

            if (compressionInfo.CompressBufferOnly)
            {
                var header = data.Take((packet as IPacketBuffer).BufferOffset).ToArray();

                var payloadHeader = SMB2_COMPRESSION_PAYLOAD_HEADER.Create(CompressionAlgorithm.NONE, (UInt32)header.Length, 0, ref isFirst);

                payloads.Add(new Tuple <SMB2_COMPRESSION_PAYLOAD_HEADER, object>(payloadHeader, header));
            }

            if (forwardDataPattern != null)
            {
                var payloadHeader = SMB2_COMPRESSION_PAYLOAD_HEADER.Create(CompressionAlgorithm.Pattern_V1, (UInt32)PatternPayloadLength, 0, ref isFirst);

                payloads.Add(new Tuple <SMB2_COMPRESSION_PAYLOAD_HEADER, object>(payloadHeader, forwardDataPattern));
            }

            int forwardDataPatternLength = (int)(forwardDataPattern?.Repetitions ?? 0);

            int backwardDataPatternLength = (int)(backwardDataPattern?.Repetitions ?? 0);

            var innerData = dataToCompress.Skip(forwardDataPatternLength).Take(dataToCompress.Length - forwardDataPatternLength - backwardDataPatternLength).ToArray();

            if (innerData.Length > 0)
            {
                var innerPayload = ChainedCompressWithCompressionAlgorithm(innerData, compressionInfo, ref isFirst);

                payloads.Add(innerPayload);
            }

            if (backwardDataPattern != null)
            {
                var payloadHeader = SMB2_COMPRESSION_PAYLOAD_HEADER.Create(CompressionAlgorithm.Pattern_V1, (UInt32)PatternPayloadLength, 0, ref isFirst);

                payloads.Add(new Tuple <SMB2_COMPRESSION_PAYLOAD_HEADER, object>(payloadHeader, backwardDataPattern));
            }

            result.Payloads = payloads.ToArray();

            return(result);
        }