github.com/igoogolx/clash@v1.19.8/transport/ssr/obfs/tls1.2_ticket_auth.go (about) 1 package obfs 2 3 import ( 4 "bytes" 5 "crypto/hmac" 6 "crypto/rand" 7 "encoding/binary" 8 mathRand "math/rand" 9 "net" 10 "strings" 11 "time" 12 13 "github.com/igoogolx/clash/common/pool" 14 "github.com/igoogolx/clash/transport/ssr/tools" 15 ) 16 17 func init() { 18 register("tls1.2_ticket_auth", newTLS12Ticket, 5) 19 register("tls1.2_ticket_fastauth", newTLS12Ticket, 5) 20 } 21 22 type tls12Ticket struct { 23 *Base 24 *authData 25 } 26 27 func newTLS12Ticket(b *Base) Obfs { 28 r := &tls12Ticket{Base: b, authData: &authData{}} 29 rand.Read(r.clientID[:]) 30 return r 31 } 32 33 type tls12TicketConn struct { 34 net.Conn 35 *tls12Ticket 36 handshakeStatus int 37 decoded bytes.Buffer 38 underDecoded bytes.Buffer 39 sendBuf bytes.Buffer 40 } 41 42 func (t *tls12Ticket) StreamConn(c net.Conn) net.Conn { 43 return &tls12TicketConn{Conn: c, tls12Ticket: t} 44 } 45 46 func (c *tls12TicketConn) Read(b []byte) (int, error) { 47 if c.decoded.Len() > 0 { 48 return c.decoded.Read(b) 49 } 50 51 buf := pool.Get(pool.RelayBufferSize) 52 defer pool.Put(buf) 53 n, err := c.Conn.Read(buf) 54 if err != nil { 55 return 0, err 56 } 57 58 if c.handshakeStatus == 8 { 59 c.underDecoded.Write(buf[:n]) 60 for c.underDecoded.Len() > 5 { 61 if !bytes.Equal(c.underDecoded.Bytes()[:3], []byte{0x17, 3, 3}) { 62 c.underDecoded.Reset() 63 return 0, errTLS12TicketAuthIncorrectMagicNumber 64 } 65 size := int(binary.BigEndian.Uint16(c.underDecoded.Bytes()[3:5])) 66 if c.underDecoded.Len() < 5+size { 67 break 68 } 69 c.underDecoded.Next(5) 70 c.decoded.Write(c.underDecoded.Next(size)) 71 } 72 n, _ = c.decoded.Read(b) 73 return n, nil 74 } 75 76 if n < 11+32+1+32 { 77 return 0, errTLS12TicketAuthTooShortData 78 } 79 80 if !hmac.Equal(buf[33:43], c.hmacSHA1(buf[11:33])[:10]) || !hmac.Equal(buf[n-10:n], c.hmacSHA1(buf[:n-10])[:10]) { 81 return 0, errTLS12TicketAuthHMACError 82 } 83 84 c.Write(nil) 85 return 0, nil 86 } 87 88 func (c *tls12TicketConn) Write(b []byte) (int, error) { 89 length := len(b) 90 if c.handshakeStatus == 8 { 91 buf := pool.GetBuffer() 92 defer pool.PutBuffer(buf) 93 for len(b) > 2048 { 94 size := mathRand.Intn(4096) + 100 95 if len(b) < size { 96 size = len(b) 97 } 98 packData(buf, b[:size]) 99 b = b[size:] 100 } 101 if len(b) > 0 { 102 packData(buf, b) 103 } 104 _, err := c.Conn.Write(buf.Bytes()) 105 if err != nil { 106 return 0, err 107 } 108 return length, nil 109 } 110 111 if len(b) > 0 { 112 packData(&c.sendBuf, b) 113 } 114 115 if c.handshakeStatus == 0 { 116 c.handshakeStatus = 1 117 118 data := pool.GetBuffer() 119 defer pool.PutBuffer(data) 120 121 data.Write([]byte{3, 3}) 122 c.packAuthData(data) 123 data.WriteByte(0x20) 124 data.Write(c.clientID[:]) 125 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}) 126 data.Write([]byte{0x1, 0x0}) 127 128 ext := pool.GetBuffer() 129 defer pool.PutBuffer(ext) 130 131 host := c.getHost() 132 ext.Write([]byte{0xff, 0x01, 0x00, 0x01, 0x00}) 133 packSNIData(ext, host) 134 ext.Write([]byte{0, 0x17, 0, 0}) 135 c.packTicketBuf(ext, host) 136 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}) 137 ext.Write([]byte{0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00}) 138 ext.Write([]byte{0x00, 0x12, 0x00, 0x00}) 139 ext.Write([]byte{0x75, 0x50, 0x00, 0x00}) 140 ext.Write([]byte{0x00, 0x0b, 0x00, 0x02, 0x01, 0x00}) 141 ext.Write([]byte{0x00, 0x0a, 0x00, 0x06, 0x00, 0x04, 0x00, 0x17, 0x00, 0x18}) 142 143 binary.Write(data, binary.BigEndian, uint16(ext.Len())) 144 data.ReadFrom(ext) 145 146 ret := pool.GetBuffer() 147 defer pool.PutBuffer(ret) 148 149 ret.Write([]byte{0x16, 3, 1}) 150 binary.Write(ret, binary.BigEndian, uint16(data.Len()+4)) 151 ret.Write([]byte{1, 0}) 152 binary.Write(ret, binary.BigEndian, uint16(data.Len())) 153 ret.ReadFrom(data) 154 155 _, err := c.Conn.Write(ret.Bytes()) 156 if err != nil { 157 return 0, err 158 } 159 return length, nil 160 } else if c.handshakeStatus == 1 && len(b) == 0 { 161 buf := pool.GetBuffer() 162 defer pool.PutBuffer(buf) 163 164 buf.Write([]byte{0x14, 3, 3, 0, 1, 1, 0x16, 3, 3, 0, 0x20}) 165 tools.AppendRandBytes(buf, 22) 166 buf.Write(c.hmacSHA1(buf.Bytes())[:10]) 167 buf.ReadFrom(&c.sendBuf) 168 169 c.handshakeStatus = 8 170 171 _, err := c.Conn.Write(buf.Bytes()) 172 return 0, err 173 } 174 return length, nil 175 } 176 177 func packData(buf *bytes.Buffer, data []byte) { 178 buf.Write([]byte{0x17, 3, 3}) 179 binary.Write(buf, binary.BigEndian, uint16(len(data))) 180 buf.Write(data) 181 } 182 183 func (t *tls12Ticket) packAuthData(buf *bytes.Buffer) { 184 binary.Write(buf, binary.BigEndian, uint32(time.Now().Unix())) 185 tools.AppendRandBytes(buf, 18) 186 buf.Write(t.hmacSHA1(buf.Bytes()[buf.Len()-22:])[:10]) 187 } 188 189 func packSNIData(buf *bytes.Buffer, u string) { 190 len := uint16(len(u)) 191 buf.Write([]byte{0, 0}) 192 binary.Write(buf, binary.BigEndian, len+5) 193 binary.Write(buf, binary.BigEndian, len+3) 194 buf.WriteByte(0) 195 binary.Write(buf, binary.BigEndian, len) 196 buf.WriteString(u) 197 } 198 199 func (c *tls12TicketConn) packTicketBuf(buf *bytes.Buffer, u string) { 200 length := 16 * (mathRand.Intn(17) + 8) 201 buf.Write([]byte{0, 0x23}) 202 binary.Write(buf, binary.BigEndian, uint16(length)) 203 tools.AppendRandBytes(buf, length) 204 } 205 206 func (t *tls12Ticket) hmacSHA1(data []byte) []byte { 207 key := pool.Get(len(t.Key) + 32) 208 defer pool.Put(key) 209 copy(key, t.Key) 210 copy(key[len(t.Key):], t.clientID[:]) 211 212 sha1Data := tools.HmacSHA1(key, data) 213 return sha1Data[:10] 214 } 215 216 func (t *tls12Ticket) getHost() string { 217 host := t.Param 218 if len(host) == 0 { 219 host = t.Host 220 } 221 if len(host) > 0 && host[len(host)-1] >= '0' && host[len(host)-1] <= '9' { 222 host = "" 223 } 224 hosts := strings.Split(host, ",") 225 host = hosts[mathRand.Intn(len(hosts))] 226 return host 227 }