conn_raw.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. package tapdance
  2. import (
  3. "bytes"
  4. "context"
  5. "crypto/rand"
  6. "encoding/base64"
  7. "encoding/binary"
  8. "encoding/hex"
  9. "errors"
  10. "fmt"
  11. "io"
  12. "net"
  13. "strconv"
  14. "strings"
  15. "sync"
  16. "time"
  17. "github.com/golang/protobuf/proto"
  18. pb "github.com/refraction-networking/gotapdance/protobuf"
  19. tls "github.com/refraction-networking/utls"
  20. )
  21. // Simply establishes TLS and TapDance connection.
  22. // Both reader and writer flows shall have this underlying raw connection.
  23. // Knows about but doesn't keep track of timeout and upload limit
  24. type tdRawConn struct {
  25. tcpConn closeWriterConn // underlying TCP connection with CloseWrite() function that sends FIN
  26. tlsConn *tls.UConn // TLS connection to decoy (and station)
  27. covert string // hostname that tapdance station will connect client to
  28. TcpDialer func(context.Context, string, string) (net.Conn, error)
  29. decoySpec *pb.TLSDecoySpec
  30. pinDecoySpec bool // don't ever change decoy (still changeable from outside)
  31. initialMsg *pb.StationToClient
  32. stationPubkey []byte
  33. tagType tdTagType
  34. remoteConnId []byte // 32 byte ID of the connection to station, used for reconnection
  35. establishedAt time.Time // right after TLS connection to decoy is established, but not to station
  36. UploadLimit int // used only in POST-based tags
  37. closed chan struct{}
  38. closeOnce sync.Once
  39. useProxyHeader bool // request the station to prepend the connection with PROXY header
  40. // dark decoy variables
  41. darkDecoyUsed bool
  42. darkDecoySNI string
  43. darkDecoyV6Support bool // *bool so that it is a nullable type. that can be overridden by the dialer
  44. // stats to report
  45. sessionStats pb.SessionStats
  46. failedDecoys []string
  47. // purely for logging and stats reporting purposes:
  48. flowId uint64 // id of the flow within the session (=how many times reconnected)
  49. sessionId uint64 // id of the local session
  50. strIdSuffix string // suffix for every log string (e.g. to mark upload-only flows)
  51. tdKeys tapdanceSharedKeys
  52. }
  53. func makeTdRaw(handshakeType tdTagType, stationPubkey []byte) *tdRawConn {
  54. tdRaw := &tdRawConn{tagType: handshakeType,
  55. stationPubkey: stationPubkey,
  56. }
  57. tdRaw.closed = make(chan struct{})
  58. return tdRaw
  59. }
  60. func (tdRaw *tdRawConn) DialContext(ctx context.Context) error {
  61. return tdRaw.dial(ctx, false)
  62. }
  63. func (tdRaw *tdRawConn) RedialContext(ctx context.Context) error {
  64. tdRaw.flowId++
  65. return tdRaw.dial(ctx, true)
  66. }
  67. func (tdRaw *tdRawConn) dial(ctx context.Context, reconnect bool) error {
  68. var maxConnectionAttempts int
  69. var err error
  70. dialStartTs := time.Now()
  71. var expectedTransition pb.S2C_Transition
  72. if reconnect {
  73. maxConnectionAttempts = 5
  74. expectedTransition = pb.S2C_Transition_S2C_CONFIRM_RECONNECT
  75. tdRaw.tlsConn.Close()
  76. } else {
  77. maxConnectionAttempts = 20
  78. expectedTransition = pb.S2C_Transition_S2C_SESSION_INIT
  79. if len(tdRaw.covert) > 0 {
  80. expectedTransition = pb.S2C_Transition_S2C_SESSION_COVERT_INIT
  81. }
  82. }
  83. for i := 0; i < maxConnectionAttempts; i++ {
  84. if tdRaw.IsClosed() {
  85. return errors.New("Closed")
  86. }
  87. // sleep to prevent overwhelming decoy servers
  88. if waitTime := sleepBeforeConnect(i); waitTime != nil {
  89. select {
  90. case <-waitTime:
  91. case <-ctx.Done():
  92. return context.Canceled
  93. case <-tdRaw.closed:
  94. return errors.New("Closed")
  95. }
  96. }
  97. if tdRaw.pinDecoySpec {
  98. if tdRaw.decoySpec.Ipv4Addr == nil {
  99. return errors.New("decoySpec is pinned, but empty!")
  100. }
  101. } else {
  102. if !reconnect {
  103. tdRaw.decoySpec = Assets().GetDecoy()
  104. if tdRaw.decoySpec.GetIpAddrStr() == "" {
  105. return errors.New("tdConn.decoyAddr is empty!")
  106. }
  107. }
  108. }
  109. if !reconnect {
  110. // generate a new remove conn ID for each attempt to dial
  111. // keep same remote conn ID for reconnect, since that's what it is for
  112. tdRaw.remoteConnId = make([]byte, 16)
  113. rand.Read(tdRaw.remoteConnId[:])
  114. }
  115. err = tdRaw.tryDialOnce(ctx, expectedTransition)
  116. if err == nil {
  117. tdRaw.sessionStats.TotalTimeToConnect = durationToU32ptrMs(time.Since(dialStartTs))
  118. return nil
  119. }
  120. tdRaw.failedDecoys = append(tdRaw.failedDecoys,
  121. tdRaw.decoySpec.GetHostname()+" "+tdRaw.decoySpec.GetIpAddrStr())
  122. if tdRaw.sessionStats.FailedDecoysAmount == nil {
  123. tdRaw.sessionStats.FailedDecoysAmount = new(uint32)
  124. }
  125. *tdRaw.sessionStats.FailedDecoysAmount += uint32(1)
  126. }
  127. return err
  128. }
  129. func (tdRaw *tdRawConn) tryDialOnce(ctx context.Context, expectedTransition pb.S2C_Transition) (err error) {
  130. Logger().Infoln(tdRaw.idStr() + " Attempting to connect to decoy " +
  131. tdRaw.decoySpec.GetHostname() + " (" + tdRaw.decoySpec.GetIpAddrStr() + ")")
  132. tlsToDecoyStartTs := time.Now()
  133. err = tdRaw.establishTLStoDecoy(ctx)
  134. tlsToDecoyTotalTs := time.Since(tlsToDecoyStartTs)
  135. if err != nil {
  136. Logger().Errorf(tdRaw.idStr() + " establishTLStoDecoy(" +
  137. tdRaw.decoySpec.GetHostname() + "," + tdRaw.decoySpec.GetIpAddrStr() +
  138. ") failed with " + err.Error())
  139. return err
  140. }
  141. err = WriteTlsLog(tdRaw.tlsConn.HandshakeState.Hello.Random,
  142. tdRaw.tlsConn.HandshakeState.MasterSecret)
  143. if err != nil {
  144. Logger().Warningf("Failed to write TLS secret log: %s", err)
  145. }
  146. tdRaw.sessionStats.TlsToDecoy = durationToU32ptrMs(tlsToDecoyTotalTs)
  147. Logger().Infof("%s Connected to decoy %s(%s) in %s", tdRaw.idStr(), tdRaw.decoySpec.GetHostname(),
  148. tdRaw.decoySpec.GetIpAddrStr(), tlsToDecoyTotalTs.String())
  149. if tdRaw.IsClosed() {
  150. // if connection was closed externally while in establishTLStoDecoy()
  151. tdRaw.tlsConn.Close()
  152. return errors.New("Closed")
  153. }
  154. tdRequest, err := tdRaw.prepareTDRequest(tdRaw.tagType)
  155. if err != nil {
  156. Logger().Errorf(tdRaw.idStr() +
  157. " Preparation of initial TD request failed with " + err.Error())
  158. tdRaw.tlsConn.Close()
  159. return
  160. }
  161. tdRaw.establishedAt = time.Now() // TODO: recheck how ClientConf's timeout is calculated and move, if needed
  162. Logger().Infoln(tdRaw.idStr() + " Attempting to connect to TapDance Station" +
  163. " with connection ID: " + hex.EncodeToString(tdRaw.remoteConnId[:]) + ", method: " +
  164. tdRaw.tagType.Str())
  165. rttToStationStartTs := time.Now()
  166. _, err = tdRaw.tlsConn.Write([]byte(tdRequest))
  167. if err != nil {
  168. Logger().Errorf(tdRaw.idStr() +
  169. " Could not send initial TD request, error: " + err.Error())
  170. tdRaw.tlsConn.Close()
  171. return
  172. }
  173. // Give up waiting for the station pretty quickly (2x handshake time == ~4RTT)
  174. tdRaw.tlsConn.SetDeadline(time.Now().Add(tlsToDecoyTotalTs * 2))
  175. switch tdRaw.tagType {
  176. case tagHttpGetIncomplete:
  177. tdRaw.initialMsg, err = tdRaw.readProto()
  178. rttToStationTotalTs := time.Since(rttToStationStartTs)
  179. tdRaw.sessionStats.RttToStation = durationToU32ptrMs(rttToStationTotalTs)
  180. if err != nil {
  181. if errIsTimeout(err) {
  182. Logger().Errorf("%s %s: %v", tdRaw.idStr(),
  183. "TapDance station didn't pick up the request", err)
  184. // lame fix for issue #38 with abrupt drop of not picked up flows
  185. tdRaw.tlsConn.SetDeadline(time.Now().Add(
  186. getRandomDuration(deadlineTCPtoDecoyMin,
  187. deadlineTCPtoDecoyMax)))
  188. tdRaw.tlsConn.Write([]byte(getRandPadding(456, 789, 5) + "\r\n" +
  189. "Connection: close\r\n\r\n"))
  190. go readAndClose(tdRaw.tlsConn,
  191. getRandomDuration(deadlineTCPtoDecoyMin,
  192. deadlineTCPtoDecoyMax))
  193. } else {
  194. // any other error will be fatal
  195. Logger().Errorf(tdRaw.idStr() +
  196. " fatal error reading from TapDance station: " +
  197. err.Error())
  198. tdRaw.tlsConn.Close()
  199. return
  200. }
  201. return
  202. }
  203. if tdRaw.initialMsg.GetStateTransition() != expectedTransition {
  204. err = errors.New("Init error: state transition mismatch!" +
  205. " Received: " + tdRaw.initialMsg.GetStateTransition().String() +
  206. " Expected: " + expectedTransition.String())
  207. Logger().Infof("%s Failed to connect to TapDance Station [%s]: %s",
  208. tdRaw.idStr(), tdRaw.initialMsg.GetStationId(), err.Error())
  209. // this exceptional error implies that station has lost state, thus is fatal
  210. return err
  211. }
  212. Logger().Infoln(tdRaw.idStr() + " Successfully connected to TapDance Station [" + tdRaw.initialMsg.GetStationId() + "]")
  213. case tagHttpPostIncomplete, tagHttpGetComplete:
  214. // don't wait for response
  215. default:
  216. panic("Unsupported td handshake type:" + tdRaw.tagType.Str())
  217. }
  218. // TapDance should NOT have a timeout, timeouts have to be handled by client and server
  219. tdRaw.tlsConn.SetDeadline(time.Time{}) // unsets timeout
  220. return nil
  221. }
  222. func (tdRaw *tdRawConn) establishTLStoDecoy(ctx context.Context) error {
  223. deadline, deadlineAlreadySet := ctx.Deadline()
  224. if !deadlineAlreadySet {
  225. deadline = time.Now().Add(getRandomDuration(deadlineTCPtoDecoyMin, deadlineTCPtoDecoyMax))
  226. }
  227. childCtx, childCancelFunc := context.WithDeadline(ctx, deadline)
  228. defer childCancelFunc()
  229. tcpDialer := tdRaw.TcpDialer
  230. if tcpDialer == nil {
  231. // custom dialer is not set, use default
  232. d := net.Dialer{}
  233. tcpDialer = d.DialContext
  234. }
  235. tcpToDecoyStartTs := time.Now()
  236. dialConn, err := tcpDialer(childCtx, "tcp", tdRaw.decoySpec.GetIpAddrStr())
  237. tcpToDecoyTotalTs := time.Since(tcpToDecoyStartTs)
  238. if err != nil {
  239. return err
  240. }
  241. tdRaw.sessionStats.TcpToDecoy = durationToU32ptrMs(tcpToDecoyTotalTs)
  242. config := tls.Config{ServerName: tdRaw.decoySpec.GetHostname()}
  243. if config.ServerName == "" {
  244. // if SNI is unset -- try IP
  245. config.ServerName, _, err = net.SplitHostPort(tdRaw.decoySpec.GetIpAddrStr())
  246. if err != nil {
  247. dialConn.Close()
  248. return err
  249. }
  250. Logger().Infoln(tdRaw.idStr() + ": SNI was nil. Setting it to" +
  251. config.ServerName)
  252. }
  253. // parrot Chrome 62 ClientHello
  254. tdRaw.tlsConn = tls.UClient(dialConn, &config, tls.HelloChrome_62)
  255. err = tdRaw.tlsConn.BuildHandshakeState()
  256. if err != nil {
  257. dialConn.Close()
  258. return err
  259. }
  260. err = tdRaw.tlsConn.MarshalClientHello()
  261. if err != nil {
  262. dialConn.Close()
  263. return err
  264. }
  265. tdRaw.tlsConn.SetDeadline(deadline)
  266. err = tdRaw.tlsConn.Handshake()
  267. if err != nil {
  268. dialConn.Close()
  269. return err
  270. }
  271. closeWriter, ok := dialConn.(closeWriterConn)
  272. if !ok {
  273. return errors.New("dialConn is not a closeWriter")
  274. }
  275. tdRaw.tcpConn = closeWriter
  276. return nil
  277. }
  278. func (tdRaw *tdRawConn) Close() error {
  279. var err error
  280. tdRaw.closeOnce.Do(func() {
  281. close(tdRaw.closed)
  282. if tdRaw.tlsConn != nil {
  283. err = tdRaw.tlsConn.Close()
  284. }
  285. })
  286. return err
  287. }
  288. type closeWriterConn interface {
  289. net.Conn
  290. CloseWrite() error
  291. }
  292. func (tdRaw *tdRawConn) closeWrite() error {
  293. return tdRaw.tcpConn.CloseWrite()
  294. }
  295. // func (tdRaw *tdRawConn) generateFSP(espSize uint16) []byte {
  296. // buf := make([]byte, 6)
  297. // binary.BigEndian.PutUint16(buf[0:2], espSize)
  298. // flags := default_flags
  299. // if tdRaw.tagType == tagHttpPostIncomplete {
  300. // flags |= tdFlagUploadOnly
  301. // }
  302. // if tdRaw.useProxyHeader {
  303. // flags |= tdFlagProxyHeader
  304. // }
  305. // buf[2] = flags
  306. // return buf
  307. // }
  308. func (tdRaw *tdRawConn) generateVSP() ([]byte, error) {
  309. // Generate and marshal protobuf
  310. transition := pb.C2S_Transition_C2S_SESSION_INIT
  311. var covert *string
  312. if len(tdRaw.covert) > 0 {
  313. transition = pb.C2S_Transition_C2S_SESSION_COVERT_INIT
  314. covert = &tdRaw.covert
  315. }
  316. currGen := Assets().GetGeneration()
  317. initProto := &pb.ClientToStation{
  318. CovertAddress: covert,
  319. StateTransition: &transition,
  320. DecoyListGeneration: &currGen,
  321. }
  322. Logger().Debugln(tdRaw.idStr()+" Initial protobuf", initProto)
  323. const AES_GCM_TAG_SIZE = 16
  324. for (proto.Size(initProto)+AES_GCM_TAG_SIZE)%3 != 0 {
  325. initProto.Padding = append(initProto.Padding, byte(0))
  326. }
  327. return proto.Marshal(initProto)
  328. }
  329. func (tdRaw *tdRawConn) prepareTDRequest(handshakeType tdTagType) (string, error) {
  330. // Generate tag for the initial TapDance request
  331. buf := new(bytes.Buffer) // What we have to encrypt with the shared secret using AES
  332. masterKey := tdRaw.tlsConn.HandshakeState.MasterSecret
  333. // write flags
  334. flags := default_flags
  335. if tdRaw.tagType == tagHttpPostIncomplete {
  336. flags |= tdFlagUploadOnly
  337. }
  338. if tdRaw.useProxyHeader {
  339. flags |= tdFlagProxyHeader
  340. }
  341. if err := binary.Write(buf, binary.BigEndian, flags); err != nil {
  342. return "", err
  343. }
  344. buf.Write([]byte{0}) // Unassigned byte
  345. negotiatedCipher := tdRaw.tlsConn.HandshakeState.State12.Suite.Id
  346. if tdRaw.tlsConn.HandshakeState.ServerHello.Vers == tls.VersionTLS13 {
  347. negotiatedCipher = tdRaw.tlsConn.HandshakeState.State13.Suite.Id
  348. }
  349. buf.Write([]byte{byte(negotiatedCipher >> 8),
  350. byte(negotiatedCipher & 0xff)})
  351. buf.Write(masterKey[:])
  352. buf.Write(tdRaw.tlsConn.HandshakeState.ServerHello.Random)
  353. buf.Write(tdRaw.tlsConn.HandshakeState.Hello.Random)
  354. buf.Write(tdRaw.remoteConnId[:]) // connection id for persistence
  355. err := WriteTlsLog(tdRaw.tlsConn.HandshakeState.Hello.Random,
  356. tdRaw.tlsConn.HandshakeState.MasterSecret)
  357. if err != nil {
  358. Logger().Warningf("Failed to write TLS secret log: %s", err)
  359. }
  360. // Generate and marshal protobuf
  361. transition := pb.C2S_Transition_C2S_SESSION_INIT
  362. var covert *string
  363. if len(tdRaw.covert) > 0 {
  364. transition = pb.C2S_Transition_C2S_SESSION_COVERT_INIT
  365. covert = &tdRaw.covert
  366. }
  367. currGen := Assets().GetGeneration()
  368. initProto := &pb.ClientToStation{
  369. CovertAddress: covert,
  370. StateTransition: &transition,
  371. DecoyListGeneration: &currGen,
  372. }
  373. initProtoBytes, err := proto.Marshal(initProto)
  374. if err != nil {
  375. return "", err
  376. }
  377. Logger().Debugln(tdRaw.idStr()+" Initial protobuf", initProto)
  378. // Choose the station pubkey
  379. pubkey := tdRaw.stationPubkey
  380. if perDecoyKey := tdRaw.decoySpec.GetPubkey().GetKey(); perDecoyKey != nil {
  381. pubkey = perDecoyKey // per-decoy key takes preference over default global pubkey
  382. }
  383. // Obfuscate/encrypt tag and protobuf
  384. tag, encryptedProtoMsg, err := obfuscateTagAndProtobuf(buf.Bytes(), initProtoBytes, pubkey)
  385. if err != nil {
  386. return "", err
  387. }
  388. return tdRaw.genHTTP1Tag(tag, encryptedProtoMsg)
  389. }
  390. func (tdRaw *tdRawConn) idStr() string {
  391. return "[Session " + strconv.FormatUint(tdRaw.sessionId, 10) + ", " +
  392. "Flow " + strconv.FormatUint(tdRaw.flowId, 10) + tdRaw.strIdSuffix + "]"
  393. }
  394. // Simply reads and returns protobuf
  395. // Returns error if it's not a protobuf
  396. // TODO: redesign it pb, data, err
  397. func (tdRaw *tdRawConn) readProto() (msg *pb.StationToClient, err error) {
  398. var readBuffer bytes.Buffer
  399. var outerProtoMsgType msgType
  400. var msgLen int64 // just the body (e.g. raw data or protobuf)
  401. // Get TIL
  402. _, err = io.CopyN(&readBuffer, tdRaw.tlsConn, 2)
  403. if err != nil {
  404. return
  405. }
  406. typeLen := uint16toInt16(binary.BigEndian.Uint16(readBuffer.Next(2)))
  407. if typeLen < 0 {
  408. outerProtoMsgType = msgRawData
  409. msgLen = int64(-typeLen)
  410. } else if typeLen > 0 {
  411. outerProtoMsgType = msgProtobuf
  412. msgLen = int64(typeLen)
  413. } else {
  414. // protobuf with size over 32KB, not fitting into 2-byte TL
  415. outerProtoMsgType = msgProtobuf
  416. _, err = io.CopyN(&readBuffer, tdRaw.tlsConn, 4)
  417. if err != nil {
  418. return
  419. }
  420. msgLen = int64(binary.BigEndian.Uint32(readBuffer.Next(4)))
  421. }
  422. if outerProtoMsgType == msgRawData {
  423. err = errors.New("Received data message in uninitialized flow")
  424. return
  425. }
  426. // Get the message itself
  427. _, err = io.CopyN(&readBuffer, tdRaw.tlsConn, msgLen)
  428. if err != nil {
  429. return
  430. }
  431. msg = &pb.StationToClient{}
  432. err = proto.Unmarshal(readBuffer.Bytes(), msg)
  433. if err != nil {
  434. return
  435. }
  436. Logger().Debugln(tdRaw.idStr() + " INIT: received protobuf: " + msg.String())
  437. return
  438. }
  439. // Generates padding and stuff
  440. // Currently guaranteed to be less than 1024 bytes long
  441. func (tdRaw *tdRawConn) writeTransition(transition pb.C2S_Transition) (n int, err error) {
  442. const paddingMinSize = 250
  443. const paddingMaxSize = 800
  444. const paddingSmoothness = 5
  445. paddingDecrement := 0 // reduce potential padding size by this value
  446. currGen := Assets().GetGeneration()
  447. msg := pb.ClientToStation{
  448. DecoyListGeneration: &currGen,
  449. StateTransition: &transition,
  450. UploadSync: new(uint64)} // TODO: remove
  451. if tdRaw.flowId == 0 {
  452. // we have stats for each reconnect, but only send stats for the initial connection
  453. msg.Stats = &tdRaw.sessionStats
  454. }
  455. if len(tdRaw.failedDecoys) > 0 {
  456. failedDecoysIdx := 0 // how many failed decoys to report now
  457. for failedDecoysIdx < len(tdRaw.failedDecoys) {
  458. if paddingMinSize < proto.Size(&pb.ClientToStation{
  459. FailedDecoys: tdRaw.failedDecoys[:failedDecoysIdx+1]}) {
  460. // if failedDecoys list is too big to fit in place of min padding
  461. // then send the rest on the next reconnect
  462. break
  463. }
  464. failedDecoysIdx += 1
  465. }
  466. paddingDecrement = proto.Size(&pb.ClientToStation{
  467. FailedDecoys: tdRaw.failedDecoys[:failedDecoysIdx]})
  468. msg.FailedDecoys = tdRaw.failedDecoys[:failedDecoysIdx]
  469. tdRaw.failedDecoys = tdRaw.failedDecoys[failedDecoysIdx:]
  470. }
  471. msg.Padding = []byte(getRandPadding(paddingMinSize-paddingDecrement,
  472. paddingMaxSize-paddingDecrement, paddingSmoothness))
  473. msgBytes, err := proto.Marshal(&msg)
  474. if err != nil {
  475. return
  476. }
  477. Logger().Infoln(tdRaw.idStr()+" sending transition: ", msg.String())
  478. b := getMsgWithHeader(msgProtobuf, msgBytes)
  479. n, err = tdRaw.tlsConn.Write(b)
  480. return
  481. }
  482. // mutates tdRaw: sets tdRaw.UploadLimit
  483. func (tdRaw *tdRawConn) genHTTP1Tag(tag, encryptedProtoMsg []byte) (string, error) {
  484. sharedHeaders := `Host: ` + tdRaw.decoySpec.GetHostname() +
  485. "\nUser-Agent: TapDance/1.2 (+https://refraction.network/info)"
  486. if len(encryptedProtoMsg) > 0 {
  487. sharedHeaders += "\nX-Proto: " + base64.StdEncoding.EncodeToString(encryptedProtoMsg)
  488. }
  489. var httpTag string
  490. switch tdRaw.tagType {
  491. // for complete copy http generator of golang
  492. case tagHttpGetComplete:
  493. fallthrough
  494. case tagHttpGetIncomplete:
  495. tdRaw.UploadLimit = int(tdRaw.decoySpec.GetTcpwin()) - getRandInt(1, 1045)
  496. httpTag = fmt.Sprintf(`GET / HTTP/1.1
  497. %s
  498. X-Ignore: %s`, sharedHeaders, getRandPadding(7, maxInt(612-len(sharedHeaders), 7), 10))
  499. httpTag = strings.Replace(httpTag, "\n", "\r\n", -1)
  500. case tagHttpPostIncomplete:
  501. ContentLength := getRandInt(900000, 1045000)
  502. tdRaw.UploadLimit = ContentLength - 1
  503. httpTag = fmt.Sprintf(`POST / HTTP/1.1
  504. %s
  505. Accept-Encoding: None
  506. X-Padding: %s
  507. Content-Type: application/zip; boundary=----WebKitFormBoundaryaym16ehT29q60rUx
  508. Content-Length: %s
  509. ----WebKitFormBoundaryaym16ehT29q60rUx
  510. Content-Disposition: form-data; name=\"td.zip\"
  511. `, sharedHeaders, getRandPadding(1, maxInt(461-len(sharedHeaders), 1), 10), strconv.Itoa(ContentLength))
  512. httpTag = strings.Replace(httpTag, "\n", "\r\n", -1)
  513. }
  514. keystreamOffset := len(httpTag)
  515. keystreamSize := (len(tag)/3+1)*4 + keystreamOffset // we can't use first 2 bits of every byte
  516. wholeKeystream, err := tdRaw.tlsConn.GetOutKeystream(keystreamSize)
  517. if err != nil {
  518. return httpTag, err
  519. }
  520. keystreamAtTag := wholeKeystream[keystreamOffset:]
  521. httpTag += string(reverseEncrypt(tag, keystreamAtTag))
  522. if tdRaw.tagType == tagHttpGetComplete {
  523. httpTag += "\r\n\r\n"
  524. }
  525. Logger().Debugf("Generated HTTP TAG:\n%s\n", httpTag)
  526. return httpTag, nil
  527. }
  528. func (tdRaw *tdRawConn) IsClosed() bool {
  529. select {
  530. case <-tdRaw.closed:
  531. return true
  532. default:
  533. return false
  534. }
  535. }