github.com/igoogolx/clash@v1.19.8/transport/ssr/obfs/random_head.go (about)

     1  package obfs
     2  
     3  import (
     4  	"crypto/rand"
     5  	"encoding/binary"
     6  	"hash/crc32"
     7  	mathRand "math/rand"
     8  	"net"
     9  
    10  	"github.com/igoogolx/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  	buf := pool.Get(pool.RelayBufferSize)
    43  	defer pool.Put(buf)
    44  	c.Conn.Read(buf)
    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 := mathRand.Intn(96) + 4
    58  		buf := pool.Get(dataLength + 4)
    59  		defer pool.Put(buf)
    60  		rand.Read(buf[:dataLength])
    61  		binary.LittleEndian.PutUint32(buf[dataLength:], 0xffffffff-crc32.ChecksumIEEE(buf[:dataLength]))
    62  		_, err := c.Conn.Write(buf)
    63  		return len(b), err
    64  	}
    65  	if c.rawTransRecv {
    66  		_, err := c.Conn.Write(c.buf)
    67  		c.buf = nil
    68  		c.rawTransSent = true
    69  		return len(b), err
    70  	}
    71  	return len(b), nil
    72  }