From 5eeac447fec190d8684d10385364f83d85d8bd89 Mon Sep 17 00:00:00 2001 From: yuhan6665 <1588741+yuhan6665@users.noreply.github.com> Date: Sun, 13 Jul 2025 21:13:17 -0400 Subject: [PATCH] Delay and detect H2 settings frame Do not send fake H2 settings packet if the upper level (xhttp) will send the real packet --- conn.go | 42 ++++++++++++++++++++++++++++++++++++++++++ record_detect.go | 3 ++- tls.go | 39 +++++++++++++++++++++++++-------------- 3 files changed, 69 insertions(+), 15 deletions(-) diff --git a/conn.go b/conn.go index a408e76..231ad5f 100644 --- a/conn.go +++ b/conn.go @@ -29,6 +29,8 @@ type Conn struct { ClientVer [3]byte ClientTime time.Time ClientShortId [8]byte + PostHandshakeRecord []TrafficPacket + PosthandshakeMutex sync.Mutex // constant conn net.Conn @@ -1314,10 +1316,50 @@ func (c *Conn) Write(b []byte) (int, error) { } } + c.PosthandshakeMutex.Lock() + if c.PostHandshakeRecord != nil { + for _, packet := range c.PostHandshakeRecord { + for i, length := range packet.Lens { + if length <= 100 && i == len(packet.Lens) - 1 && isH2Settings(b) { + fmt.Printf("REALITY skip fake H2 Settings frame len(postHandshakeRecord): %v\n", length) + } else { + plainText := make([]byte, length-16) + plainText[0] = 23 + plainText[1] = 3 + plainText[2] = 3 + plainText[3] = byte((length - 5) >> 8) + plainText[4] = byte((length - 5)) + plainText[5] = 23 + postHandshakeRecord := c.out.cipher.(aead).Seal(plainText[:5], c.out.seq[:], plainText[5:], plainText[:5]) + c.out.incSeq() + c.write(postHandshakeRecord) + fmt.Printf("REALITY Send with data, len(postHandshakeRecord): %v\tlen(buffer):%v\n", length, len(b)) + } + } + } + c.PostHandshakeRecord = nil + } + c.PosthandshakeMutex.Unlock() + n, err := c.writeRecordLocked(recordTypeApplicationData, b) return n + m, c.out.setErrorLocked(err) } +func isH2Settings(b []byte) bool { + if len(b) < 9 { + return false + } + if b[3] == 0x04 && b[5] == 0x00 && b[6] == 0x00 && b[7] == 0x00 && b[8] == 0x00 { + // H2 settings with stream identifier of zero (0x0) is used for connection control messages + return true + } + if b[3] == 0x08 && b[5] == 0x00 && b[6] == 0x00 && b[7] == 0x00 && b[8] == 0x00 { + // H2 window update, unlikely but put here anyways + return true + } + return false +} + // handleRenegotiation processes a HelloRequest handshake message. func (c *Conn) handleRenegotiation() error { if c.vers == VersionTLS13 { diff --git a/record_detect.go b/record_detect.go index c7962ed..6f2b933 100644 --- a/record_detect.go +++ b/record_detect.go @@ -90,13 +90,13 @@ func (c *DetectConn) Read(b []byte) (n int, err error) { for { data := make([]byte, 0, 2048) n, err = c.Conn.Read(data[len(data):cap(data)]) + data = data[:len(data)+n] if err != nil { return 0, err } newPacket := TrafficPacket { SinceHandshake: time.Since(c.HandshakeDone), } - c.PostHandshakeRecordsLens[c.Sni] = append(c.PostHandshakeRecordsLens[c.Sni], newPacket) for len(data) > 0 { if len(data) >= 5 && bytes.Equal(data[:3], []byte{23, 3, 3}) { length := int(binary.BigEndian.Uint16(data[3:5])) + 5 @@ -106,5 +106,6 @@ func (c *DetectConn) Read(b []byte) (n int, err error) { break } } + c.PostHandshakeRecordsLens[c.Sni] = append(c.PostHandshakeRecordsLens[c.Sni], newPacket) } } diff --git a/tls.go b/tls.go index ac86734..eea90be 100644 --- a/tls.go +++ b/tls.go @@ -374,21 +374,32 @@ func Server(ctx context.Context, conn net.Conn, config *Config) (*Conn, error) { if err != nil { break } - for _, packet := range postHandshakeRecordsLens[hs.clientHello.serverName] { - for _, length := range packet.Lens { - plainText := make([]byte, length-16) - plainText[0] = 23 - plainText[1] = 3 - plainText[2] = 3 - plainText[3] = byte((length - 5) >> 8) - plainText[4] = byte((length - 5)) - plainText[5] = 23 - postHandshakeRecord := hs.c.out.cipher.(aead).Seal(plainText[:5], hs.c.out.seq[:], plainText[5:], plainText[:5]) - hs.c.out.incSeq() - hs.c.write(postHandshakeRecord) - fmt.Printf("REALITY remoteAddr: %v\tlen(postHandshakeRecord): %v\n", remoteAddr, len(postHandshakeRecord)) + hs.c.PostHandshakeRecord = postHandshakeRecordsLens[hs.clientHello.serverName] + go func(){ + if hs.c.PostHandshakeRecord != nil { + time.Sleep(hs.c.PostHandshakeRecord[0].SinceHandshake) } - } + hs.c.PosthandshakeMutex.Lock() + defer hs.c.PosthandshakeMutex.Unlock() + if hs.c.PostHandshakeRecord != nil { + for _, packet := range hs.c.PostHandshakeRecord { + for _, length := range packet.Lens { + plainText := make([]byte, length-16) + plainText[0] = 23 + plainText[1] = 3 + plainText[2] = 3 + plainText[3] = byte((length - 5) >> 8) + plainText[4] = byte((length - 5)) + plainText[5] = 23 + postHandshakeRecord := hs.c.out.cipher.(aead).Seal(plainText[:5], hs.c.out.seq[:], plainText[5:], plainText[:5]) + hs.c.out.incSeq() + hs.c.write(postHandshakeRecord) + fmt.Printf("REALITY remoteAddr: %v\tSend after sleep%s\tlen(postHandshakeRecord): %v\n", remoteAddr, packet.SinceHandshake, len(postHandshakeRecord)) + } + } + hs.c.PostHandshakeRecord = nil + } + }() hs.c.isHandshakeComplete.Store(true) break }