个人瞎搞之 C#不建立TLS获取SNI的值(用到了Span<T>)

使用示例

static void SNI()
        {
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);


            socket.Bind(new IPEndPoint(IPAddress.Loopback, 443));

            socket.Listen(6);

            while (true)
            {
                using var stream = new NetworkStream(socket.Accept());

                byte[] buffer = new byte[4096];

                int n = stream.Read(buffer);

                //因为这个地方假设一次性就把Client Hello全读取出来了
                //否则出错
                //其他情况行为都未定义,比如根本没有SNI
                //浏览器访问https://localhost
                //前提是解析出的IP是127.0.0.1
                var v = TLSClientHelloMethod.GetServerName(buffer.AsSpan(0, n));


                Console.WriteLine(Encoding.UTF8.GetString(v));
            }





        }

 

 

完整代码

 

    public static class TLSClientHelloMethod
    {
        enum TLS_Client_Hello_ExtensionsType
        {
            ServerName = 0,
        }


        [StructLayout(LayoutKind.Explicit, Size = 32)]
        struct TLS_Client_Hello_Random
        {

        }

        [StructLayout(LayoutKind.Explicit, Size = 3)]
        struct TLS_Client_Hello_HandshakeLength
        {

        }

        [StructLayout(LayoutKind.Explicit, Size = 5)]
        struct TLS_Client_Hello_Extensions_ServerName
        {
            [FieldOffset(0)]
            ushort _ListLength;

            [FieldOffset(2)]
            byte _Type;

            [FieldOffset(3)]
            ushort _Length;
        }

        [StructLayout(LayoutKind.Explicit, Size = 4)]
        struct TLS_Client_Hello_ExtensionsItem
        {
            [FieldOffset(0)]
            ushort _Type;

            [FieldOffset(2)]
            ushort _Length;



            public TLS_Client_Hello_ExtensionsType Type => (TLS_Client_Hello_ExtensionsType)ReverseBig(_Type);

            public ushort Length => ReverseBig(_Length);
        }

        [StructLayout(LayoutKind.Explicit, Size = 4)]
        struct TLS_Client_Hello_Betun
        {
            [FieldOffset(0)]
            public ushort CompMethods;

            [FieldOffset(2)]
            public ushort ExtensionsLength;
        }

        [StructLayout(LayoutKind.Explicit, Size = 43)]
        struct TLS_Client_Hello_First
        {
            [FieldOffset(0)]
            public byte ContentType;

            [FieldOffset(1)]
            public ushort ContentVerison;

            [FieldOffset(3)]
            public ushort ContentLength;

            [FieldOffset(5)]
            public byte HandshakeType;

            //这个占用三个字节
            [FieldOffset(6)]
            public TLS_Client_Hello_HandshakeLength HandshakeLength;

            [FieldOffset(9)]
            public ushort HandshakeVerison;

            [FieldOffset(11)]
            public TLS_Client_Hello_Random TLSRandom;
        }




        static T ReverseBig<T>(T value) where T : unmanaged
        {
            if (BitConverter.IsLittleEndian)
            {

                MemoryMarshal.Cast<T, byte>(MemoryMarshal.CreateSpan(ref value, 1)).Reverse();

                return value;
            }
            else
            {
                return value;
            }

        }


        static ref T AsAndSlice<T>(ref Span<byte> buffer) where T : unmanaged
        {
            ref T p = ref MemoryMarshal.AsRef<T>(buffer);


            buffer = buffer.Slice(Unsafe.SizeOf<T>());

            return ref p;
        }

        static Span<byte> Spik(ref Span<byte> buffer, int spik)
        {
            var v = buffer.Slice(0, spik);

            buffer = buffer.Slice(spik);

            return v;
        }


        static Span<byte> SessionID(ref Span<byte> buffer)
        {
            int n = AsAndSlice<byte>(ref buffer);

            return Spik(ref buffer, n);
        }


        static Span<byte> CipherSuites(ref Span<byte> buffer)
        {
            int n = ReverseBig(AsAndSlice<ushort>(ref buffer));

            return Spik(ref buffer, n);




        }

        static TLS_Client_Hello_ExtensionsType GetExItem(ref Span<byte> buffer, out Span<byte> item)
        {
            var ex = AsAndSlice<TLS_Client_Hello_ExtensionsItem>(ref buffer);

            item = Spik(ref buffer, ex.Length);


            return ex.Type;

        }

        public static Span<byte> GetServerName(Span<byte> buffer)
        {


            AsAndSlice<TLS_Client_Hello_First>(ref buffer);

            SessionID(ref buffer);

            CipherSuites(ref buffer);

            AsAndSlice<TLS_Client_Hello_Betun>(ref buffer);

            while (true)
            {

                if (GetExItem(ref buffer, out var messge) == TLS_Client_Hello_ExtensionsType.ServerName)
                {
                    AsAndSlice<TLS_Client_Hello_Extensions_ServerName>(ref messge);

                    return messge;
                }
            }
        }
    }

 

posted @ 2021-04-08 19:51  FfD4edyo  阅读(179)  评论(0)    收藏  举报