meekConn.go 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741
  1. /*
  2. * Copyright (c) 2015, Psiphon Inc.
  3. * All rights reserved.
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. */
  19. package psiphon
  20. import (
  21. "bytes"
  22. "crypto/rand"
  23. "encoding/base64"
  24. "encoding/json"
  25. "errors"
  26. "fmt"
  27. "io"
  28. "net"
  29. "net/http"
  30. "net/url"
  31. "strings"
  32. "sync"
  33. "time"
  34. "github.com/Psiphon-Inc/crypto/nacl/box"
  35. "github.com/Psiphon-Inc/goarista/monotime"
  36. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
  37. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/upstreamproxy"
  38. )
  39. // MeekConn is based on meek-client.go from Tor and Psiphon:
  40. //
  41. // https://gitweb.torproject.org/pluggable-transports/meek.git/blob/HEAD:/meek-client/meek-client.go
  42. // CC0 1.0 Universal
  43. //
  44. // https://bitbucket.org/psiphon/psiphon-circumvention-system/src/default/go/meek-client/meek-client.go
  45. const (
  46. MEEK_PROTOCOL_VERSION = 2
  47. MEEK_COOKIE_MAX_PADDING = 32
  48. MAX_SEND_PAYLOAD_LENGTH = 65536
  49. FULL_RECEIVE_BUFFER_LENGTH = 4194304
  50. READ_PAYLOAD_CHUNK_LENGTH = 65536
  51. MIN_POLL_INTERVAL = 100 * time.Millisecond
  52. MAX_POLL_INTERVAL = 5 * time.Second
  53. POLL_INTERNAL_MULTIPLIER = 1.5
  54. MEEK_ROUND_TRIP_RETRY_DEADLINE = 1 * time.Second
  55. MEEK_ROUND_TRIP_RETRY_DELAY = 50 * time.Millisecond
  56. MEEK_ROUND_TRIP_TIMEOUT = 20 * time.Second
  57. )
  58. // MeekConfig specifies the behavior of a MeekConn
  59. type MeekConfig struct {
  60. // DialAddress is the actual network address to dial to establish a
  61. // connection to the meek server. This may be either a fronted or
  62. // direct address. The address must be in the form "host:port",
  63. // where host may be a domain name or IP address.
  64. DialAddress string
  65. // UseHTTPS indicates whether to use HTTPS (true) or HTTP (false).
  66. UseHTTPS bool
  67. // UseObfuscatedSessionTickets indicates whether to use obfuscated
  68. // session tickets. Assumes UseHTTPS is true.
  69. UseObfuscatedSessionTickets bool
  70. // SNIServerName is the value to place in the TLS SNI server_name
  71. // field when HTTPS is used.
  72. SNIServerName string
  73. // HostHeader is the value to place in the HTTP request Host header.
  74. HostHeader string
  75. // TransformedHostName records whether a hostname transformation is
  76. // in effect. This value is used for stats reporting.
  77. TransformedHostName bool
  78. // The following values are used to create the obfuscated meek cookie.
  79. PsiphonServerAddress string
  80. SessionID string
  81. MeekCookieEncryptionPublicKey string
  82. MeekObfuscatedKey string
  83. }
  84. // MeekConn is a network connection that tunnels TCP over HTTP and supports "fronting". Meek sends
  85. // client->server flow in HTTP request bodies and receives server->client flow in HTTP response bodies.
  86. // Polling is used to achieve full duplex TCP.
  87. //
  88. // Fronting is an obfuscation technique in which the connection
  89. // to a web server, typically a CDN, is indistinguishable from any other HTTPS connection to the generic
  90. // "fronting domain" -- the HTTP Host header is used to route the requests to the actual destination.
  91. // See https://trac.torproject.org/projects/tor/wiki/doc/meek for more details.
  92. //
  93. // MeekConn also operates in unfronted mode, in which plain HTTP connections are made without routing
  94. // through a CDN.
  95. type MeekConn struct {
  96. url *url.URL
  97. additionalHeaders http.Header
  98. cookie *http.Cookie
  99. pendingConns *common.Conns
  100. transport transporter
  101. mutex sync.Mutex
  102. isClosed bool
  103. broadcastClosed chan struct{}
  104. relayWaitGroup *sync.WaitGroup
  105. emptyReceiveBuffer chan *bytes.Buffer
  106. partialReceiveBuffer chan *bytes.Buffer
  107. fullReceiveBuffer chan *bytes.Buffer
  108. emptySendBuffer chan *bytes.Buffer
  109. partialSendBuffer chan *bytes.Buffer
  110. fullSendBuffer chan *bytes.Buffer
  111. }
  112. // transporter is implemented by both http.Transport and upstreamproxy.ProxyAuthTransport.
  113. type transporter interface {
  114. CancelRequest(req *http.Request)
  115. CloseIdleConnections()
  116. RegisterProtocol(scheme string, rt http.RoundTripper)
  117. RoundTrip(req *http.Request) (resp *http.Response, err error)
  118. }
  119. // DialMeek returns an initialized meek connection. A meek connection is
  120. // an HTTP session which does not depend on an underlying socket connection (although
  121. // persistent HTTP connections are used for performance). This function does not
  122. // wait for the connection to be "established" before returning. A goroutine
  123. // is spawned which will eventually start HTTP polling.
  124. // When frontingAddress is not "", fronting is used. This option assumes caller has
  125. // already checked server entry capabilities.
  126. func DialMeek(
  127. meekConfig *MeekConfig,
  128. dialConfig *DialConfig) (meek *MeekConn, err error) {
  129. // Configure transport
  130. // Note: MeekConn has its own PendingConns to manage the underlying HTTP transport connections,
  131. // which may be interrupted on MeekConn.Close(). This code previously used the establishTunnel
  132. // pendingConns here, but that was a lifecycle mismatch: we don't want to abort HTTP transport
  133. // connections while MeekConn is still in use
  134. pendingConns := new(common.Conns)
  135. // Use a copy of DialConfig with the meek pendingConns
  136. meekDialConfig := new(DialConfig)
  137. *meekDialConfig = *dialConfig
  138. meekDialConfig.PendingConns = pendingConns
  139. var transport transporter
  140. var additionalHeaders http.Header
  141. var proxyUrl func(*http.Request) (*url.URL, error)
  142. if meekConfig.UseHTTPS {
  143. // Custom TLS dialer:
  144. //
  145. // 1. ignores the HTTP request address and uses the fronting domain
  146. // 2. optionally disables SNI -- SNI breaks fronting when used with certain CDNs.
  147. // 3. skips verifying the server cert.
  148. //
  149. // Reasoning for #3:
  150. //
  151. // With a TLS MiM attack in place, and server certs verified, we'll fail to connect because the client
  152. // will refuse to connect. That's not a successful outcome.
  153. //
  154. // With a MiM attack in place, and server certs not verified, we'll fail to connect if the MiM is actively
  155. // targeting Psiphon and classifying the HTTP traffic by Host header or payload signature.
  156. //
  157. // However, in the case of a passive MiM that's just recording traffic or an active MiM that's targeting
  158. // something other than Psiphon, the client will connect. This is a successful outcome.
  159. //
  160. // What is exposed to the MiM? The Host header does not contain a Psiphon server IP address, just an
  161. // unrelated, randomly generated domain name which cannot be used to block direct connections. The
  162. // Psiphon server IP is sent over meek, but it's in the encrypted cookie.
  163. //
  164. // The payload (user traffic) gets its confidentiality and integrity from the underlying SSH protocol.
  165. // So, nothing is leaked to the MiM apart from signatures which could be used to classify the traffic
  166. // as Psiphon to possibly block it; but note that not revealing that the client is Psiphon is outside
  167. // our threat model; we merely seek to evade mass blocking by taking steps that require progressively
  168. // more effort to block.
  169. //
  170. // There is a subtle attack remaining: an adversary that can MiM some CDNs but not others (and so can
  171. // classify Psiphon traffic on some CDNs but not others) may throttle non-MiM CDNs so that our server
  172. // selection always chooses tunnels to the MiM CDN (without any server cert verification, we won't
  173. // exclusively connect to non-MiM CDNs); then the adversary kills the underlying TCP connection after
  174. // some short period. This is mitigated by the "impaired" protocol classification mechanism.
  175. tlsConfig := &CustomTLSConfig{
  176. DialAddr: meekConfig.DialAddress,
  177. Dial: NewTCPDialer(meekDialConfig),
  178. Timeout: meekDialConfig.ConnectTimeout,
  179. SNIServerName: meekConfig.SNIServerName,
  180. SkipVerify: true,
  181. UseIndistinguishableTLS: meekDialConfig.UseIndistinguishableTLS,
  182. TrustedCACertificatesFilename: meekDialConfig.TrustedCACertificatesFilename,
  183. }
  184. if meekConfig.UseObfuscatedSessionTickets {
  185. tlsConfig.ObfuscatedSessionTicketKey = meekConfig.MeekObfuscatedKey
  186. }
  187. dialer := NewCustomTLSDialer(tlsConfig)
  188. // TODO: wrap in an http.Client and use http.Client.Timeout which actually covers round trip
  189. transport = &http.Transport{
  190. Dial: dialer,
  191. ResponseHeaderTimeout: MEEK_ROUND_TRIP_TIMEOUT,
  192. }
  193. } else {
  194. // The dialer ignores address that http.Transport will pass in (derived
  195. // from the HTTP request URL) and always dials meekConfig.DialAddress.
  196. dialer := func(string, string) (net.Conn, error) {
  197. return NewTCPDialer(meekDialConfig)("tcp", meekConfig.DialAddress)
  198. }
  199. // For HTTP, and when the meekConfig.DialAddress matches the
  200. // meekConfig.HostHeader, we let http.Transport handle proxying.
  201. // http.Transport will put the the HTTP server address in the HTTP
  202. // request line. In this one case, we can use an HTTP proxy that does
  203. // not offer CONNECT support.
  204. if strings.HasPrefix(meekDialConfig.UpstreamProxyUrl, "http://") &&
  205. (meekConfig.DialAddress == meekConfig.HostHeader ||
  206. meekConfig.DialAddress == meekConfig.HostHeader+":80") {
  207. url, err := url.Parse(meekDialConfig.UpstreamProxyUrl)
  208. if err != nil {
  209. return nil, common.ContextError(err)
  210. }
  211. proxyUrl = http.ProxyURL(url)
  212. meekDialConfig.UpstreamProxyUrl = ""
  213. // Here, the dialer must use the address that http.Transport
  214. // passes in (which will be proxy address).
  215. dialer = NewTCPDialer(meekDialConfig)
  216. }
  217. // TODO: wrap in an http.Client and use http.Client.Timeout which actually covers round trip
  218. httpTransport := &http.Transport{
  219. Proxy: proxyUrl,
  220. Dial: dialer,
  221. ResponseHeaderTimeout: MEEK_ROUND_TRIP_TIMEOUT,
  222. }
  223. if proxyUrl != nil {
  224. // Wrap transport with a transport that can perform HTTP proxy auth negotiation
  225. transport, err = upstreamproxy.NewProxyAuthTransport(httpTransport, meekDialConfig.UpstreamProxyCustomHeaders)
  226. if err != nil {
  227. return nil, common.ContextError(err)
  228. }
  229. } else {
  230. transport = httpTransport
  231. }
  232. }
  233. // Scheme is always "http". Otherwise http.Transport will try to do another TLS
  234. // handshake inside the explicit TLS session (in fronting mode).
  235. url := &url.URL{
  236. Scheme: "http",
  237. Host: meekConfig.HostHeader,
  238. Path: "/",
  239. }
  240. if meekConfig.UseHTTPS {
  241. host, _, err := net.SplitHostPort(meekConfig.DialAddress)
  242. if err != nil {
  243. return nil, common.ContextError(err)
  244. }
  245. additionalHeaders = map[string][]string{
  246. "X-Psiphon-Fronting-Address": {host},
  247. }
  248. } else {
  249. if proxyUrl == nil {
  250. additionalHeaders = meekDialConfig.UpstreamProxyCustomHeaders
  251. }
  252. }
  253. cookie, err := makeMeekCookie(meekConfig)
  254. if err != nil {
  255. return nil, common.ContextError(err)
  256. }
  257. // The main loop of a MeekConn is run in the relay() goroutine.
  258. // A MeekConn implements net.Conn concurrency semantics:
  259. // "Multiple goroutines may invoke methods on a Conn simultaneously."
  260. //
  261. // Read() calls and relay() are synchronized by exchanging control of a single
  262. // receiveBuffer (bytes.Buffer). This single buffer may be:
  263. // - in the emptyReceiveBuffer channel when it is available and empty;
  264. // - in the partialReadBuffer channel when it is available and contains data;
  265. // - in the fullReadBuffer channel when it is available and full of data;
  266. // - "checked out" by relay or Read when they are are writing to or reading from the
  267. // buffer, respectively.
  268. // relay() will obtain the buffer from either the empty or partial channel but block when
  269. // the buffer is full. Read will obtain the buffer from the partial or full channel when
  270. // there is data to read but block when the buffer is empty.
  271. // Write() calls and relay() are synchronized in a similar way, using a single
  272. // sendBuffer.
  273. meek = &MeekConn{
  274. url: url,
  275. additionalHeaders: additionalHeaders,
  276. cookie: cookie,
  277. pendingConns: pendingConns,
  278. transport: transport,
  279. isClosed: false,
  280. broadcastClosed: make(chan struct{}),
  281. relayWaitGroup: new(sync.WaitGroup),
  282. emptyReceiveBuffer: make(chan *bytes.Buffer, 1),
  283. partialReceiveBuffer: make(chan *bytes.Buffer, 1),
  284. fullReceiveBuffer: make(chan *bytes.Buffer, 1),
  285. emptySendBuffer: make(chan *bytes.Buffer, 1),
  286. partialSendBuffer: make(chan *bytes.Buffer, 1),
  287. fullSendBuffer: make(chan *bytes.Buffer, 1),
  288. }
  289. // TODO: benchmark bytes.Buffer vs. built-in append with slices?
  290. meek.emptyReceiveBuffer <- new(bytes.Buffer)
  291. meek.emptySendBuffer <- new(bytes.Buffer)
  292. meek.relayWaitGroup.Add(1)
  293. go meek.relay()
  294. // Enable interruption
  295. if !dialConfig.PendingConns.Add(meek) {
  296. meek.Close()
  297. return nil, common.ContextError(errors.New("pending connections already closed"))
  298. }
  299. return meek, nil
  300. }
  301. // Close terminates the meek connection. Close waits for the relay processing goroutine
  302. // to stop and releases HTTP transport resources.
  303. // A mutex is required to support net.Conn concurrency semantics.
  304. func (meek *MeekConn) Close() (err error) {
  305. meek.mutex.Lock()
  306. isClosed := meek.isClosed
  307. meek.isClosed = true
  308. meek.mutex.Unlock()
  309. if !isClosed {
  310. close(meek.broadcastClosed)
  311. meek.pendingConns.CloseAll()
  312. meek.relayWaitGroup.Wait()
  313. meek.transport.CloseIdleConnections()
  314. }
  315. return nil
  316. }
  317. func (meek *MeekConn) closed() bool {
  318. meek.mutex.Lock()
  319. isClosed := meek.isClosed
  320. meek.mutex.Unlock()
  321. return isClosed
  322. }
  323. // Read reads data from the connection.
  324. // net.Conn Deadlines are ignored. net.Conn concurrency semantics are supported.
  325. func (meek *MeekConn) Read(buffer []byte) (n int, err error) {
  326. if meek.closed() {
  327. return 0, common.ContextError(errors.New("meek connection is closed"))
  328. }
  329. // Block until there is received data to consume
  330. var receiveBuffer *bytes.Buffer
  331. select {
  332. case receiveBuffer = <-meek.partialReceiveBuffer:
  333. case receiveBuffer = <-meek.fullReceiveBuffer:
  334. case <-meek.broadcastClosed:
  335. return 0, common.ContextError(errors.New("meek connection has closed"))
  336. }
  337. n, err = receiveBuffer.Read(buffer)
  338. meek.replaceReceiveBuffer(receiveBuffer)
  339. return n, err
  340. }
  341. // Write writes data to the connection.
  342. // net.Conn Deadlines are ignored. net.Conn concurrency semantics are supported.
  343. func (meek *MeekConn) Write(buffer []byte) (n int, err error) {
  344. if meek.closed() {
  345. return 0, common.ContextError(errors.New("meek connection is closed"))
  346. }
  347. // Repeats until all n bytes are written
  348. n = len(buffer)
  349. for len(buffer) > 0 {
  350. // Block until there is capacity in the send buffer
  351. var sendBuffer *bytes.Buffer
  352. select {
  353. case sendBuffer = <-meek.emptySendBuffer:
  354. case sendBuffer = <-meek.partialSendBuffer:
  355. case <-meek.broadcastClosed:
  356. return 0, common.ContextError(errors.New("meek connection has closed"))
  357. }
  358. writeLen := MAX_SEND_PAYLOAD_LENGTH - sendBuffer.Len()
  359. if writeLen > 0 {
  360. if writeLen > len(buffer) {
  361. writeLen = len(buffer)
  362. }
  363. _, err = sendBuffer.Write(buffer[:writeLen])
  364. buffer = buffer[writeLen:]
  365. }
  366. meek.replaceSendBuffer(sendBuffer)
  367. }
  368. return n, err
  369. }
  370. // Stub implementation of net.Conn.LocalAddr
  371. func (meek *MeekConn) LocalAddr() net.Addr {
  372. return nil
  373. }
  374. // Stub implementation of net.Conn.RemoteAddr
  375. func (meek *MeekConn) RemoteAddr() net.Addr {
  376. return nil
  377. }
  378. // Stub implementation of net.Conn.SetDeadline
  379. func (meek *MeekConn) SetDeadline(t time.Time) error {
  380. return common.ContextError(errors.New("not supported"))
  381. }
  382. // Stub implementation of net.Conn.SetReadDeadline
  383. func (meek *MeekConn) SetReadDeadline(t time.Time) error {
  384. return common.ContextError(errors.New("not supported"))
  385. }
  386. // Stub implementation of net.Conn.SetWriteDeadline
  387. func (meek *MeekConn) SetWriteDeadline(t time.Time) error {
  388. return common.ContextError(errors.New("not supported"))
  389. }
  390. func (meek *MeekConn) replaceReceiveBuffer(receiveBuffer *bytes.Buffer) {
  391. switch {
  392. case receiveBuffer.Len() == 0:
  393. meek.emptyReceiveBuffer <- receiveBuffer
  394. case receiveBuffer.Len() >= FULL_RECEIVE_BUFFER_LENGTH:
  395. meek.fullReceiveBuffer <- receiveBuffer
  396. default:
  397. meek.partialReceiveBuffer <- receiveBuffer
  398. }
  399. }
  400. func (meek *MeekConn) replaceSendBuffer(sendBuffer *bytes.Buffer) {
  401. switch {
  402. case sendBuffer.Len() == 0:
  403. meek.emptySendBuffer <- sendBuffer
  404. case sendBuffer.Len() >= MAX_SEND_PAYLOAD_LENGTH:
  405. meek.fullSendBuffer <- sendBuffer
  406. default:
  407. meek.partialSendBuffer <- sendBuffer
  408. }
  409. }
  410. // relay sends and receives tunneled traffic (payload). An HTTP request is
  411. // triggered when data is in the write queue or at a polling interval.
  412. // There's a geometric increase, up to a maximum, in the polling interval when
  413. // no data is exchanged. Only one HTTP request is in flight at a time.
  414. func (meek *MeekConn) relay() {
  415. // Note: meek.Close() calls here in relay() are made asynchronously
  416. // (using goroutines) since Close() will wait on this WaitGroup.
  417. defer meek.relayWaitGroup.Done()
  418. interval := MIN_POLL_INTERVAL
  419. timeout := time.NewTimer(interval)
  420. sendPayload := make([]byte, MAX_SEND_PAYLOAD_LENGTH)
  421. for {
  422. timeout.Reset(interval)
  423. // Block until there is payload to send or it is time to poll
  424. var sendBuffer *bytes.Buffer
  425. select {
  426. case sendBuffer = <-meek.partialSendBuffer:
  427. case sendBuffer = <-meek.fullSendBuffer:
  428. case <-timeout.C:
  429. // In the polling case, send an empty payload
  430. case <-meek.broadcastClosed:
  431. // TODO: timeout case may be selected when broadcastClosed is set?
  432. return
  433. }
  434. sendPayloadSize := 0
  435. if sendBuffer != nil {
  436. var err error
  437. sendPayloadSize, err = sendBuffer.Read(sendPayload)
  438. meek.replaceSendBuffer(sendBuffer)
  439. if err != nil {
  440. NoticeAlert("%s", common.ContextError(err))
  441. go meek.Close()
  442. return
  443. }
  444. }
  445. receivedPayload, err := meek.roundTrip(sendPayload[:sendPayloadSize])
  446. if err != nil {
  447. NoticeAlert("%s", common.ContextError(err))
  448. go meek.Close()
  449. return
  450. }
  451. if receivedPayload == nil {
  452. // In this case, meek.roundTrip encountered broadcastClosed. Exit without error.
  453. return
  454. }
  455. receivedPayloadSize, err := meek.readPayload(receivedPayload)
  456. if err != nil {
  457. NoticeAlert("%s", common.ContextError(err))
  458. go meek.Close()
  459. return
  460. }
  461. if receivedPayloadSize > 0 || sendPayloadSize > 0 {
  462. interval = 0
  463. } else if interval == 0 {
  464. interval = MIN_POLL_INTERVAL
  465. } else {
  466. interval = time.Duration(float64(interval) * POLL_INTERNAL_MULTIPLIER)
  467. if interval >= MAX_POLL_INTERVAL {
  468. interval = MAX_POLL_INTERVAL
  469. }
  470. }
  471. }
  472. }
  473. // readPayload reads the HTTP response in chunks, making the read buffer available
  474. // to MeekConn.Read() calls after each chunk; the intention is to allow bytes to
  475. // flow back to the reader as soon as possible instead of buffering the entire payload.
  476. func (meek *MeekConn) readPayload(receivedPayload io.ReadCloser) (totalSize int64, err error) {
  477. defer receivedPayload.Close()
  478. totalSize = 0
  479. for {
  480. reader := io.LimitReader(receivedPayload, READ_PAYLOAD_CHUNK_LENGTH)
  481. // Block until there is capacity in the receive buffer
  482. var receiveBuffer *bytes.Buffer
  483. select {
  484. case receiveBuffer = <-meek.emptyReceiveBuffer:
  485. case receiveBuffer = <-meek.partialReceiveBuffer:
  486. case <-meek.broadcastClosed:
  487. return 0, nil
  488. }
  489. // Note: receiveBuffer size may exceed FULL_RECEIVE_BUFFER_LENGTH by up to the size
  490. // of one received payload. The FULL_RECEIVE_BUFFER_LENGTH value is just a threshold.
  491. n, err := receiveBuffer.ReadFrom(reader)
  492. meek.replaceReceiveBuffer(receiveBuffer)
  493. if err != nil {
  494. return 0, common.ContextError(err)
  495. }
  496. totalSize += n
  497. if n == 0 {
  498. break
  499. }
  500. }
  501. return totalSize, nil
  502. }
  503. // roundTrip configures and makes the actual HTTP POST request
  504. func (meek *MeekConn) roundTrip(sendPayload []byte) (io.ReadCloser, error) {
  505. // The retry mitigates intermittent failures between the client and front/server.
  506. //
  507. // Note: Retry will only be effective if entire request failed (underlying transport protocol
  508. // such as SSH will fail if extra bytes are replayed in either direction due to partial relay
  509. // success followed by retry).
  510. // At least one retry is always attempted. We retry when still within a brief deadline and wait
  511. // for a short time before re-dialing.
  512. //
  513. // TODO: in principle, we could retry for min(TUNNEL_WRITE_TIMEOUT, meek-server.MAX_SESSION_STALENESS),
  514. // i.e., as long as the underlying tunnel has not timed out and as long as the server has not
  515. // expired the current meek session. Presently not doing this to avoid excessive connection attempts
  516. // through the first hop. In addition, this will require additional support for timely shutdown.
  517. retries := uint(0)
  518. retryDeadline := monotime.Now().Add(MEEK_ROUND_TRIP_RETRY_DEADLINE)
  519. var err error
  520. var response *http.Response
  521. for {
  522. var request *http.Request
  523. request, err = http.NewRequest("POST", meek.url.String(), bytes.NewReader(sendPayload))
  524. if err != nil {
  525. // Don't retry when can't initialize a Request
  526. break
  527. }
  528. // Don't use the default user agent ("Go 1.1 package http").
  529. // For now, just omit the header (net/http/request.go: "may be blank to not send the header").
  530. request.Header.Set("User-Agent", "")
  531. request.Header.Set("Content-Type", "application/octet-stream")
  532. // Set additional headers to the HTTP request using the same method we use for adding
  533. // custom headers to HTTP proxy requests
  534. for name, value := range meek.additionalHeaders {
  535. // hack around special case of "Host" header
  536. // https://golang.org/src/net/http/request.go#L474
  537. // using URL.Opaque, see URL.RequestURI() https://golang.org/src/net/url/url.go#L915
  538. if name == "Host" {
  539. if len(value) > 0 {
  540. if request.URL.Opaque == "" {
  541. request.URL.Opaque = request.URL.Scheme + "://" + request.Host + request.URL.RequestURI()
  542. }
  543. request.Host = value[0]
  544. }
  545. } else {
  546. request.Header[name] = value
  547. }
  548. }
  549. request.AddCookie(meek.cookie)
  550. // The http.Transport.RoundTrip is run in a goroutine to enable cancelling a request in-flight.
  551. type roundTripResponse struct {
  552. response *http.Response
  553. err error
  554. }
  555. roundTripResponseChannel := make(chan *roundTripResponse, 1)
  556. roundTripWaitGroup := new(sync.WaitGroup)
  557. roundTripWaitGroup.Add(1)
  558. go func() {
  559. defer roundTripWaitGroup.Done()
  560. r, err := meek.transport.RoundTrip(request)
  561. roundTripResponseChannel <- &roundTripResponse{r, err}
  562. }()
  563. select {
  564. case roundTripResponse := <-roundTripResponseChannel:
  565. response = roundTripResponse.response
  566. err = roundTripResponse.err
  567. case <-meek.broadcastClosed:
  568. meek.transport.CancelRequest(request)
  569. return nil, nil
  570. }
  571. roundTripWaitGroup.Wait()
  572. if err == nil {
  573. break
  574. }
  575. if retries >= 1 && monotime.Now().After(retryDeadline) {
  576. break
  577. }
  578. retries += 1
  579. time.Sleep(MEEK_ROUND_TRIP_RETRY_DELAY)
  580. }
  581. if err != nil {
  582. return nil, common.ContextError(err)
  583. }
  584. if response.StatusCode != http.StatusOK {
  585. return nil, common.ContextError(fmt.Errorf("http request failed %d", response.StatusCode))
  586. }
  587. // observe response cookies for meek session key token.
  588. // Once found it must be used for all consecutive requests made to the server
  589. for _, c := range response.Cookies() {
  590. if meek.cookie.Name == c.Name {
  591. meek.cookie.Value = c.Value
  592. break
  593. }
  594. }
  595. return response.Body, nil
  596. }
  597. type meekCookieData struct {
  598. ServerAddress string `json:"p"`
  599. SessionID string `json:"s"`
  600. MeekProtocolVersion int `json:"v"`
  601. }
  602. // makeCookie creates the cookie to be sent with initial meek HTTP request.
  603. // The purpose of the cookie is to send the following to the server:
  604. // ServerAddress -- the Psiphon Server address the meek server should relay to
  605. // SessionID -- the Psiphon session ID (used by meek server to relay geolocation
  606. // information obtained from the CDN through to the Psiphon Server)
  607. // MeekProtocolVersion -- tells the meek server that this client understands
  608. // the latest protocol.
  609. // The server will create a session using these values and send the session ID
  610. // back to the client via Set-Cookie header. Client must use that value with
  611. // all consequent HTTP requests
  612. // In unfronted meek mode, the cookie is visible over the adversary network, so the
  613. // cookie is encrypted and obfuscated.
  614. func makeMeekCookie(meekConfig *MeekConfig) (cookie *http.Cookie, err error) {
  615. // Make the JSON data
  616. serverAddress := meekConfig.PsiphonServerAddress
  617. cookieData := &meekCookieData{
  618. ServerAddress: serverAddress,
  619. SessionID: meekConfig.SessionID,
  620. MeekProtocolVersion: MEEK_PROTOCOL_VERSION,
  621. }
  622. serializedCookie, err := json.Marshal(cookieData)
  623. if err != nil {
  624. return nil, common.ContextError(err)
  625. }
  626. // Encrypt the JSON data
  627. // NaCl box is used for encryption. The peer public key comes from the server entry.
  628. // Nonce is always all zeros, and is not sent in the cookie (the server also uses an all-zero nonce).
  629. // http://nacl.cace-project.eu/box.html:
  630. // "There is no harm in having the same nonce for different messages if the {sender, receiver} sets are
  631. // different. This is true even if the sets overlap. For example, a sender can use the same nonce for two
  632. // different messages if the messages are sent to two different public keys."
  633. var nonce [24]byte
  634. var publicKey [32]byte
  635. decodedPublicKey, err := base64.StdEncoding.DecodeString(meekConfig.MeekCookieEncryptionPublicKey)
  636. if err != nil {
  637. return nil, common.ContextError(err)
  638. }
  639. copy(publicKey[:], decodedPublicKey)
  640. ephemeralPublicKey, ephemeralPrivateKey, err := box.GenerateKey(rand.Reader)
  641. if err != nil {
  642. return nil, common.ContextError(err)
  643. }
  644. box := box.Seal(nil, serializedCookie, &nonce, &publicKey, ephemeralPrivateKey)
  645. encryptedCookie := make([]byte, 32+len(box))
  646. copy(encryptedCookie[0:32], ephemeralPublicKey[0:32])
  647. copy(encryptedCookie[32:], box)
  648. // Obfuscate the encrypted data
  649. obfuscator, err := common.NewClientObfuscator(
  650. &common.ObfuscatorConfig{Keyword: meekConfig.MeekObfuscatedKey, MaxPadding: MEEK_COOKIE_MAX_PADDING})
  651. if err != nil {
  652. return nil, common.ContextError(err)
  653. }
  654. obfuscatedCookie := obfuscator.SendSeedMessage()
  655. seedLen := len(obfuscatedCookie)
  656. obfuscatedCookie = append(obfuscatedCookie, encryptedCookie...)
  657. obfuscator.ObfuscateClientToServer(obfuscatedCookie[seedLen:])
  658. // Format the HTTP cookie
  659. // The format is <random letter 'A'-'Z'>=<base64 data>, which is intended to match common cookie formats.
  660. A := int('A')
  661. Z := int('Z')
  662. // letterIndex is integer in range [int('A'), int('Z')]
  663. letterIndex, err := common.MakeSecureRandomInt(Z - A + 1)
  664. if err != nil {
  665. return nil, common.ContextError(err)
  666. }
  667. return &http.Cookie{
  668. Name: string(byte(A + letterIndex)),
  669. Value: base64.StdEncoding.EncodeToString(obfuscatedCookie)},
  670. nil
  671. }