个人瞎搞之 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; } } } }
浙公网安备 33010602011771号