github.com/chwjbn/xclash@v0.2.0/transport/simple-obfs/tls.go (about)

     1  package obfs
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"io"
     7  	"math/rand"
     8  	"net"
     9  	"time"
    10  
    11  	"github.com/chwjbn/xclash/common/pool"
    12  )
    13  
    14  func init() {
    15  	rand.Seed(time.Now().Unix())
    16  }
    17  
    18  const (
    19  	chunkSize = 1 << 14 // 2 ** 14 == 16 * 1024
    20  )
    21  
    22  // TLSObfs is shadowsocks tls simple-obfs implementation
    23  type TLSObfs struct {
    24  	net.Conn
    25  	server        string
    26  	remain        int
    27  	firstRequest  bool
    28  	firstResponse bool
    29  }
    30  
    31  func (to *TLSObfs) read(b []byte, discardN int) (int, error) {
    32  	buf := pool.Get(discardN)
    33  	_, err := io.ReadFull(to.Conn, buf)
    34  	if err != nil {
    35  		return 0, err
    36  	}
    37  	pool.Put(buf)
    38  
    39  	sizeBuf := make([]byte, 2)
    40  	_, err = io.ReadFull(to.Conn, sizeBuf)
    41  	if err != nil {
    42  		return 0, nil
    43  	}
    44  
    45  	length := int(binary.BigEndian.Uint16(sizeBuf))
    46  	if length > len(b) {
    47  		n, err := to.Conn.Read(b)
    48  		if err != nil {
    49  			return n, err
    50  		}
    51  		to.remain = length - n
    52  		return n, nil
    53  	}
    54  
    55  	return io.ReadFull(to.Conn, b[:length])
    56  }
    57  
    58  func (to *TLSObfs) Read(b []byte) (int, error) {
    59  	if to.remain > 0 {
    60  		length := to.remain
    61  		if length > len(b) {
    62  			length = len(b)
    63  		}
    64  
    65  		n, err := io.ReadFull(to.Conn, b[:length])
    66  		to.remain -= n
    67  		return n, err
    68  	}
    69  
    70  	if to.firstResponse {
    71  		// type + ver + lensize + 91 = 96
    72  		// type + ver + lensize + 1 = 6
    73  		// type + ver = 3
    74  		to.firstResponse = false
    75  		return to.read(b, 105)
    76  	}
    77  
    78  	// type + ver = 3
    79  	return to.read(b, 3)
    80  }
    81  
    82  func (to *TLSObfs) Write(b []byte) (int, error) {
    83  	length := len(b)
    84  	for i := 0; i < length; i += chunkSize {
    85  		end := i + chunkSize
    86  		if end > length {
    87  			end = length
    88  		}
    89  
    90  		n, err := to.write(b[i:end])
    91  		if err != nil {
    92  			return n, err
    93  		}
    94  	}
    95  	return length, nil
    96  }
    97  
    98  func (to *TLSObfs) write(b []byte) (int, error) {
    99  	if to.firstRequest {
   100  		helloMsg := makeClientHelloMsg(b, to.server)
   101  		_, err := to.Conn.Write(helloMsg)
   102  		to.firstRequest = false
   103  		return len(b), err
   104  	}
   105  
   106  	buf := pool.GetBuffer()
   107  	defer pool.PutBuffer(buf)
   108  	buf.Write([]byte{0x17, 0x03, 0x03})
   109  	binary.Write(buf, binary.BigEndian, uint16(len(b)))
   110  	buf.Write(b)
   111  	_, err := to.Conn.Write(buf.Bytes())
   112  	return len(b), err
   113  }
   114  
   115  // NewTLSObfs return a SimpleObfs
   116  func NewTLSObfs(conn net.Conn, server string) net.Conn {
   117  	return &TLSObfs{
   118  		Conn:          conn,
   119  		server:        server,
   120  		firstRequest:  true,
   121  		firstResponse: true,
   122  	}
   123  }
   124  
   125  func makeClientHelloMsg(data []byte, server string) []byte {
   126  	random := make([]byte, 28)
   127  	sessionID := make([]byte, 32)
   128  	rand.Read(random)
   129  	rand.Read(sessionID)
   130  
   131  	buf := &bytes.Buffer{}
   132  
   133  	// handshake, TLS 1.0 version, length
   134  	buf.WriteByte(22)
   135  	buf.Write([]byte{0x03, 0x01})
   136  	length := uint16(212 + len(data) + len(server))
   137  	buf.WriteByte(byte(length >> 8))
   138  	buf.WriteByte(byte(length & 0xff))
   139  
   140  	// clientHello, length, TLS 1.2 version
   141  	buf.WriteByte(1)
   142  	buf.WriteByte(0)
   143  	binary.Write(buf, binary.BigEndian, uint16(208+len(data)+len(server)))
   144  	buf.Write([]byte{0x03, 0x03})
   145  
   146  	// random with timestamp, sid len, sid
   147  	binary.Write(buf, binary.BigEndian, uint32(time.Now().Unix()))
   148  	buf.Write(random)
   149  	buf.WriteByte(32)
   150  	buf.Write(sessionID)
   151  
   152  	// cipher suites
   153  	buf.Write([]byte{0x00, 0x38})
   154  	buf.Write([]byte{
   155  		0xc0, 0x2c, 0xc0, 0x30, 0x00, 0x9f, 0xcc, 0xa9, 0xcc, 0xa8, 0xcc, 0xaa, 0xc0, 0x2b, 0xc0, 0x2f,
   156  		0x00, 0x9e, 0xc0, 0x24, 0xc0, 0x28, 0x00, 0x6b, 0xc0, 0x23, 0xc0, 0x27, 0x00, 0x67, 0xc0, 0x0a,
   157  		0xc0, 0x14, 0x00, 0x39, 0xc0, 0x09, 0xc0, 0x13, 0x00, 0x33, 0x00, 0x9d, 0x00, 0x9c, 0x00, 0x3d,
   158  		0x00, 0x3c, 0x00, 0x35, 0x00, 0x2f, 0x00, 0xff,
   159  	})
   160  
   161  	// compression
   162  	buf.Write([]byte{0x01, 0x00})
   163  
   164  	// extension length
   165  	binary.Write(buf, binary.BigEndian, uint16(79+len(data)+len(server)))
   166  
   167  	// session ticket
   168  	buf.Write([]byte{0x00, 0x23})
   169  	binary.Write(buf, binary.BigEndian, uint16(len(data)))
   170  	buf.Write(data)
   171  
   172  	// server name
   173  	buf.Write([]byte{0x00, 0x00})
   174  	binary.Write(buf, binary.BigEndian, uint16(len(server)+5))
   175  	binary.Write(buf, binary.BigEndian, uint16(len(server)+3))
   176  	buf.WriteByte(0)
   177  	binary.Write(buf, binary.BigEndian, uint16(len(server)))
   178  	buf.Write([]byte(server))
   179  
   180  	// ec_point
   181  	buf.Write([]byte{0x00, 0x0b, 0x00, 0x04, 0x03, 0x01, 0x00, 0x02})
   182  
   183  	// groups
   184  	buf.Write([]byte{0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x19, 0x00, 0x18})
   185  
   186  	// signature
   187  	buf.Write([]byte{
   188  		0x00, 0x0d, 0x00, 0x20, 0x00, 0x1e, 0x06, 0x01, 0x06, 0x02, 0x06, 0x03, 0x05,
   189  		0x01, 0x05, 0x02, 0x05, 0x03, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x03, 0x01,
   190  		0x03, 0x02, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x03,
   191  	})
   192  
   193  	// encrypt then mac
   194  	buf.Write([]byte{0x00, 0x16, 0x00, 0x00})
   195  
   196  	// extended master secret
   197  	buf.Write([]byte{0x00, 0x17, 0x00, 0x00})
   198  
   199  	return buf.Bytes()
   200  }