| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- package obfs
- import (
- "bytes"
- "crypto/hmac"
- "encoding/binary"
- "math/rand"
- "net"
- "strings"
- "time"
- "github.com/Dreamacro/clash/common/pool"
- "github.com/Dreamacro/clash/transport/ssr/tools"
- )
- func init() {
- register("tls1.2_ticket_auth", newTLS12Ticket, 5)
- register("tls1.2_ticket_fastauth", newTLS12Ticket, 5)
- }
- type tls12Ticket struct {
- *Base
- *authData
- }
- func newTLS12Ticket(b *Base) Obfs {
- r := &tls12Ticket{Base: b, authData: &authData{}}
- rand.Read(r.clientID[:])
- return r
- }
- type tls12TicketConn struct {
- net.Conn
- *tls12Ticket
- handshakeStatus int
- decoded bytes.Buffer
- underDecoded bytes.Buffer
- sendBuf bytes.Buffer
- }
- func (t *tls12Ticket) StreamConn(c net.Conn) net.Conn {
- return &tls12TicketConn{Conn: c, tls12Ticket: t}
- }
- func (c *tls12TicketConn) Read(b []byte) (int, error) {
- if c.decoded.Len() > 0 {
- return c.decoded.Read(b)
- }
- buf := pool.Get(pool.RelayBufferSize)
- defer pool.Put(buf)
- n, err := c.Conn.Read(buf)
- if err != nil {
- return 0, err
- }
- if c.handshakeStatus == 8 {
- c.underDecoded.Write(buf[:n])
- for c.underDecoded.Len() > 5 {
- if !bytes.Equal(c.underDecoded.Bytes()[:3], []byte{0x17, 3, 3}) {
- c.underDecoded.Reset()
- return 0, errTLS12TicketAuthIncorrectMagicNumber
- }
- size := int(binary.BigEndian.Uint16(c.underDecoded.Bytes()[3:5]))
- if c.underDecoded.Len() < 5+size {
- break
- }
- c.underDecoded.Next(5)
- c.decoded.Write(c.underDecoded.Next(size))
- }
- n, _ = c.decoded.Read(b)
- return n, nil
- }
- if n < 11+32+1+32 {
- return 0, errTLS12TicketAuthTooShortData
- }
- if !hmac.Equal(buf[33:43], c.hmacSHA1(buf[11:33])[:10]) || !hmac.Equal(buf[n-10:n], c.hmacSHA1(buf[:n-10])[:10]) {
- return 0, errTLS12TicketAuthHMACError
- }
- c.Write(nil)
- return 0, nil
- }
- func (c *tls12TicketConn) Write(b []byte) (int, error) {
- length := len(b)
- if c.handshakeStatus == 8 {
- buf := pool.GetBuffer()
- defer pool.PutBuffer(buf)
- for len(b) > 2048 {
- size := rand.Intn(4096) + 100
- if len(b) < size {
- size = len(b)
- }
- packData(buf, b[:size])
- b = b[size:]
- }
- if len(b) > 0 {
- packData(buf, b)
- }
- _, err := c.Conn.Write(buf.Bytes())
- if err != nil {
- return 0, err
- }
- return length, nil
- }
- if len(b) > 0 {
- packData(&c.sendBuf, b)
- }
- if c.handshakeStatus == 0 {
- c.handshakeStatus = 1
- data := pool.GetBuffer()
- defer pool.PutBuffer(data)
- data.Write([]byte{3, 3})
- c.packAuthData(data)
- data.WriteByte(0x20)
- data.Write(c.clientID[:])
- data.Write([]byte{0x00, 0x1c, 0xc0, 0x2b, 0xc0, 0x2f, 0xcc, 0xa9, 0xcc, 0xa8, 0xcc, 0x14, 0xcc, 0x13, 0xc0, 0x0a, 0xc0, 0x14, 0xc0, 0x09, 0xc0, 0x13, 0x00, 0x9c, 0x00, 0x35, 0x00, 0x2f, 0x00, 0x0a})
- data.Write([]byte{0x1, 0x0})
- ext := pool.GetBuffer()
- defer pool.PutBuffer(ext)
- host := c.getHost()
- ext.Write([]byte{0xff, 0x01, 0x00, 0x01, 0x00})
- packSNIData(ext, host)
- ext.Write([]byte{0, 0x17, 0, 0})
- c.packTicketBuf(ext, host)
- ext.Write([]byte{0x00, 0x0d, 0x00, 0x16, 0x00, 0x14, 0x06, 0x01, 0x06, 0x03, 0x05, 0x01, 0x05, 0x03, 0x04, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x03, 0x02, 0x01, 0x02, 0x03})
- ext.Write([]byte{0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00})
- ext.Write([]byte{0x00, 0x12, 0x00, 0x00})
- ext.Write([]byte{0x75, 0x50, 0x00, 0x00})
- ext.Write([]byte{0x00, 0x0b, 0x00, 0x02, 0x01, 0x00})
- ext.Write([]byte{0x00, 0x0a, 0x00, 0x06, 0x00, 0x04, 0x00, 0x17, 0x00, 0x18})
- binary.Write(data, binary.BigEndian, uint16(ext.Len()))
- data.ReadFrom(ext)
- ret := pool.GetBuffer()
- defer pool.PutBuffer(ret)
- ret.Write([]byte{0x16, 3, 1})
- binary.Write(ret, binary.BigEndian, uint16(data.Len()+4))
- ret.Write([]byte{1, 0})
- binary.Write(ret, binary.BigEndian, uint16(data.Len()))
- ret.ReadFrom(data)
- _, err := c.Conn.Write(ret.Bytes())
- if err != nil {
- return 0, err
- }
- return length, nil
- } else if c.handshakeStatus == 1 && len(b) == 0 {
- buf := pool.GetBuffer()
- defer pool.PutBuffer(buf)
- buf.Write([]byte{0x14, 3, 3, 0, 1, 1, 0x16, 3, 3, 0, 0x20})
- tools.AppendRandBytes(buf, 22)
- buf.Write(c.hmacSHA1(buf.Bytes())[:10])
- buf.ReadFrom(&c.sendBuf)
- c.handshakeStatus = 8
- _, err := c.Conn.Write(buf.Bytes())
- return 0, err
- }
- return length, nil
- }
- func packData(buf *bytes.Buffer, data []byte) {
- buf.Write([]byte{0x17, 3, 3})
- binary.Write(buf, binary.BigEndian, uint16(len(data)))
- buf.Write(data)
- }
- func (t *tls12Ticket) packAuthData(buf *bytes.Buffer) {
- binary.Write(buf, binary.BigEndian, uint32(time.Now().Unix()))
- tools.AppendRandBytes(buf, 18)
- buf.Write(t.hmacSHA1(buf.Bytes()[buf.Len()-22:])[:10])
- }
- func packSNIData(buf *bytes.Buffer, u string) {
- len := uint16(len(u))
- buf.Write([]byte{0, 0})
- binary.Write(buf, binary.BigEndian, len+5)
- binary.Write(buf, binary.BigEndian, len+3)
- buf.WriteByte(0)
- binary.Write(buf, binary.BigEndian, len)
- buf.WriteString(u)
- }
- func (c *tls12TicketConn) packTicketBuf(buf *bytes.Buffer, u string) {
- length := 16 * (rand.Intn(17) + 8)
- buf.Write([]byte{0, 0x23})
- binary.Write(buf, binary.BigEndian, uint16(length))
- tools.AppendRandBytes(buf, length)
- }
- func (t *tls12Ticket) hmacSHA1(data []byte) []byte {
- key := pool.Get(len(t.Key) + 32)
- defer pool.Put(key)
- copy(key, t.Key)
- copy(key[len(t.Key):], t.clientID[:])
- sha1Data := tools.HmacSHA1(key, data)
- return sha1Data[:10]
- }
- func (t *tls12Ticket) getHost() string {
- host := t.Param
- if len(host) == 0 {
- host = t.Host
- }
- if len(host) > 0 && host[len(host)-1] >= '0' && host[len(host)-1] <= '9' {
- host = ""
- }
- hosts := strings.Split(host, ",")
- host = hosts[rand.Intn(len(hosts))]
- return host
- }
|