github.com/yaling888/clash@v1.53.0/transport/ssr/obfs/random_head.go (about) 1 package obfs 2 3 import ( 4 R "crypto/rand" 5 "encoding/binary" 6 "hash/crc32" 7 "math/rand/v2" 8 "net" 9 10 "github.com/yaling888/clash/common/pool" 11 ) 12 13 func init() { 14 register("random_head", newRandomHead, 0) 15 } 16 17 type randomHead struct { 18 *Base 19 } 20 21 func newRandomHead(b *Base) Obfs { 22 return &randomHead{Base: b} 23 } 24 25 type randomHeadConn struct { 26 net.Conn 27 *randomHead 28 hasSentHeader bool 29 rawTransSent bool 30 rawTransRecv bool 31 buf []byte 32 } 33 34 func (r *randomHead) StreamConn(c net.Conn) net.Conn { 35 return &randomHeadConn{Conn: c, randomHead: r} 36 } 37 38 func (c *randomHeadConn) Read(b []byte) (int, error) { 39 if c.rawTransRecv { 40 return c.Conn.Read(b) 41 } 42 bufP := pool.GetNetBuf() 43 defer pool.PutNetBuf(bufP) 44 _, _ = c.Conn.Read(*bufP) 45 c.rawTransRecv = true 46 _, _ = c.Write(nil) 47 return 0, nil 48 } 49 50 func (c *randomHeadConn) Write(b []byte) (int, error) { 51 if c.rawTransSent { 52 return c.Conn.Write(b) 53 } 54 c.buf = append(c.buf, b...) 55 if !c.hasSentHeader { 56 c.hasSentHeader = true 57 dataLength := rand.IntN(96) + 4 58 bufP := pool.GetBufferWriter() 59 bufP.Grow(dataLength + 4) 60 defer pool.PutBufferWriter(bufP) 61 _, _ = R.Read((*bufP)[:dataLength]) 62 binary.LittleEndian.PutUint32((*bufP)[dataLength:], 0xffffffff-crc32.ChecksumIEEE((*bufP)[:dataLength])) 63 _, err := c.Conn.Write(bufP.Bytes()) 64 return len(b), err 65 } 66 if c.rawTransRecv { 67 _, err := c.Conn.Write(c.buf) 68 c.buf = nil 69 c.rawTransSent = true 70 return len(b), err 71 } 72 return len(b), nil 73 }