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  }