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 20package psiphon 21 22import ( 23 "bytes" 24 "context" 25 "crypto/rand" 26 "crypto/tls" 27 "encoding/base64" 28 "encoding/json" 29 "fmt" 30 "io" 31 "io/ioutil" 32 "net" 33 "net/http" 34 "net/url" 35 "strings" 36 "sync" 37 "sync/atomic" 38 "time" 39 40 "github.com/ooni/psiphon/oopsi/github.com/Psiphon-Labs/net/http2" 41 "github.com/ooni/psiphon/oopsi/github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common" 42 "github.com/ooni/psiphon/oopsi/github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors" 43 "github.com/ooni/psiphon/oopsi/github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/obfuscator" 44 "github.com/ooni/psiphon/oopsi/github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/parameters" 45 "github.com/ooni/psiphon/oopsi/github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/prng" 46 "github.com/ooni/psiphon/oopsi/github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/protocol" 47 "github.com/ooni/psiphon/oopsi/github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/quic" 48 "github.com/ooni/psiphon/oopsi/github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/upstreamproxy" 49 "github.com/ooni/psiphon/oopsi/golang.org/x/crypto/nacl/box" 50) 51 52// MeekConn is based on meek-client.go from Tor: 53// 54// https://gitweb.torproject.org/pluggable-transports/meek.git/blob/HEAD:/meek-client/meek-client.go 55// CC0 1.0 Universal 56 57const ( 58 MEEK_PROTOCOL_VERSION = 3 59 MEEK_MAX_REQUEST_PAYLOAD_LENGTH = 65536 60) 61 62type MeekMode int 63 64const ( 65 MeekModeRelay = iota 66 MeekModeObfuscatedRoundTrip 67 MeekModePlaintextRoundTrip 68) 69 70// MeekConfig specifies the behavior of a MeekConn. 71type MeekConfig struct { 72 73 // DiagnosticID is the server ID to record in any diagnostics notices. 74 DiagnosticID string 75 76 // Parameters is the active set of parameters.Parameters to use 77 // for the meek dial. 78 Parameters *parameters.Parameters 79 80 // Mode selects the mode of operation: 81 // 82 // MeekModeRelay: encapsulates net.Conn flows in HTTP requests and responses; 83 // secures and obfuscates metadata in an encrypted HTTP cookie, making it 84 // suitable for non-TLS HTTP and HTTPS with unverifed server certificates; 85 // the caller is responsible for securing and obfuscating the net.Conn flows; 86 // the origin server should be a meek server; used for the meek tunnel 87 // protocols. 88 // 89 // MeekModeObfuscatedRoundTrip: enables ObfuscatedRoundTrip, which performs 90 // HTTP round trips; secures and obfuscates metadata, including the end point 91 // (or path), in an encrypted HTTP cookie, making it suitable for non-TLS 92 // HTTP and HTTPS with unverifed server certificates; the caller is 93 // responsible for securing and obfuscating request/response payloads; the 94 // origin server should be a meek server; used for tactics requests. 95 // 96 // MeekModePlaintextRoundTrip: enables RoundTrip; the MeekConn is an 97 // http.RoundTripper; there are no security or obfuscation measures at the 98 // HTTP level; TLS and server certificate verification is required; the 99 // origin server may be any HTTP(S) server. 100 // 101 // As with the other modes, MeekModePlaintextRoundTrip supports HTTP/2 with 102 // utls, and integration with DialParameters for replay -- which are not 103 // otherwise implemented if using just CustomTLSDialer and net.http. 104 Mode MeekMode 105 106 // DialAddress is the actual network address to dial to establish a 107 // connection to the meek server. This may be either a fronted or 108 // direct address. The address must be in the form "host:port", 109 // where host may be a domain name or IP address. 110 DialAddress string 111 112 // UseQUIC indicates whether to use HTTP/2 over QUIC. 113 UseQUIC bool 114 115 // QUICVersion indicates which QUIC version to use. 116 QUICVersion string 117 118 // UseHTTPS indicates whether to use HTTPS (true) or HTTP (false). 119 UseHTTPS bool 120 121 // TLSProfile specifies the value for CustomTLSConfig.TLSProfile for all 122 // underlying TLS connections created by this meek connection. 123 TLSProfile string 124 125 // NoDefaultTLSSessionID specifies the value for 126 // CustomTLSConfig.NoDefaultTLSSessionID for all underlying TLS connections 127 // created by this meek connection. 128 NoDefaultTLSSessionID bool 129 130 // RandomizedTLSProfileSeed specifies the value for 131 // CustomTLSConfig.RandomizedTLSProfileSeed for all underlying TLS 132 // connections created by this meek connection. 133 RandomizedTLSProfileSeed *prng.Seed 134 135 // UseObfuscatedSessionTickets indicates whether to use obfuscated session 136 // tickets. Assumes UseHTTPS is true. Ignored for MeekModePlaintextRoundTrip. 137 // 138 UseObfuscatedSessionTickets bool 139 140 // SNIServerName is the value to place in the TLS/QUIC SNI server_name field 141 // when HTTPS or QUIC is used. 142 SNIServerName string 143 144 // HostHeader is the value to place in the HTTP request Host header. 145 HostHeader string 146 147 // TransformedHostName records whether a hostname transformation is 148 // in effect. This value is used for stats reporting. 149 TransformedHostName bool 150 151 // VerifyServerName specifies a domain name that must appear in the server 152 // certificate. When blank, server certificate verification is disabled. 153 VerifyServerName string 154 155 // VerifyPins specifies one or more certificate pin values, one of which must 156 // appear in the verified server certificate chain. A pin value is the 157 // base64-encoded SHA2 digest of a certificate's public key. When specified, 158 // at least one pin must match at least one certificate in the chain, at any 159 // position; e.g., the root CA may be pinned, or the server certificate, 160 // etc. 161 VerifyPins []string 162 163 // ClientTunnelProtocol is the protocol the client is using. It's included in 164 // the meek cookie for optional use by the server, in cases where the server 165 // cannot unambiguously determine the tunnel protocol. ClientTunnelProtocol 166 // is used when selecting tactics targeted at specific protocols. Ignored for 167 // MeekModePlaintextRoundTrip. 168 ClientTunnelProtocol string 169 170 // NetworkLatencyMultiplier specifies a custom network latency multiplier to 171 // apply to client parameters used by this meek connection. 172 NetworkLatencyMultiplier float64 173 174 // The following values are used to create the obfuscated meek cookie. 175 // Ignored for MeekModePlaintextRoundTrip. 176 177 MeekCookieEncryptionPublicKey string 178 MeekObfuscatedKey string 179 MeekObfuscatorPaddingSeed *prng.Seed 180} 181 182// MeekConn is a network connection that tunnels net.Conn flows over HTTP and supports 183// "domain fronting". Meek sends client->server flow in HTTP request bodies and 184// receives server->client flow in HTTP response bodies. Polling is used to 185// approximate full duplex TCP. MeekConn also offers HTTP round trip modes. 186// 187// Domain fronting is a network obfuscation technique in which the connection to a web 188// server, typically a CDN, is indistinguishable from any other HTTPS 189// connection to the generic "fronting domain" -- the HTTP Host header is used 190// to route the requests to the actual destination. See 191// https://trac.torproject.org/projects/tor/wiki/doc/meek for more details. 192// 193// MeekConn also support unfronted operation, in which connections are made 194// without routing through a CDN; and plain HTTP operation, without TLS or 195// QUIC, with connection metadata obfuscated in HTTP cookies. 196type MeekConn struct { 197 params *parameters.Parameters 198 mode MeekMode 199 networkLatencyMultiplier float64 200 isQUIC bool 201 url *url.URL 202 additionalHeaders http.Header 203 cookie *http.Cookie 204 cookieSize int 205 tlsPadding int 206 limitRequestPayloadLength int 207 redialTLSProbability float64 208 cachedTLSDialer *cachedTLSDialer 209 transport transporter 210 mutex sync.Mutex 211 isClosed bool 212 runCtx context.Context 213 stopRunning context.CancelFunc 214 relayWaitGroup *sync.WaitGroup 215 216 // For MeekModeObfuscatedRoundTrip 217 meekCookieEncryptionPublicKey string 218 meekObfuscatedKey string 219 meekObfuscatorPaddingSeed *prng.Seed 220 clientTunnelProtocol string 221 222 // For MeekModeRelay 223 fullReceiveBufferLength int 224 readPayloadChunkLength int 225 emptyReceiveBuffer chan *bytes.Buffer 226 partialReceiveBuffer chan *bytes.Buffer 227 fullReceiveBuffer chan *bytes.Buffer 228 emptySendBuffer chan *bytes.Buffer 229 partialSendBuffer chan *bytes.Buffer 230 fullSendBuffer chan *bytes.Buffer 231} 232 233func (conn *MeekConn) getCustomParameters() parameters.ParametersAccessor { 234 return conn.params.GetCustom(conn.networkLatencyMultiplier) 235} 236 237// transporter is implemented by both http.Transport and upstreamproxy.ProxyAuthTransport. 238type transporter interface { 239 CloseIdleConnections() 240 RoundTrip(req *http.Request) (resp *http.Response, err error) 241} 242 243// DialMeek returns an initialized meek connection. A meek connection is 244// an HTTP session which does not depend on an underlying socket connection (although 245// persistent HTTP connections are used for performance). This function may not 246// wait for the connection to be established before returning. 247func DialMeek( 248 ctx context.Context, 249 meekConfig *MeekConfig, 250 dialConfig *DialConfig) (*MeekConn, error) { 251 252 if meekConfig.UseQUIC && meekConfig.UseHTTPS { 253 return nil, errors.TraceNew( 254 "invalid config: only one of UseQUIC or UseHTTPS may be set") 255 } 256 257 if meekConfig.UseQUIC && 258 (meekConfig.VerifyServerName != "" || len(meekConfig.VerifyPins) > 0) { 259 260 // TODO: UseQUIC VerifyServerName and VerifyPins support (required for MeekModePlaintextRoundTrip). 261 262 return nil, errors.TraceNew( 263 "invalid config: VerifyServerName and VerifyPins not supported for UseQUIC") 264 } 265 266 skipVerify := meekConfig.VerifyServerName == "" 267 if len(meekConfig.VerifyPins) > 0 && skipVerify { 268 return nil, errors.TraceNew( 269 "invalid config: VerifyServerName must be set when VerifyPins is set") 270 } 271 272 if meekConfig.Mode == MeekModePlaintextRoundTrip && 273 (!meekConfig.UseHTTPS || skipVerify) { 274 return nil, errors.TraceNew( 275 "invalid config: MeekModePlaintextRoundTrip requires UseHTTPS and VerifyServerName") 276 } 277 278 runCtx, stopRunning := context.WithCancel(context.Background()) 279 280 cleanupStopRunning := true 281 cleanupCachedTLSDialer := true 282 var cachedTLSDialer *cachedTLSDialer 283 284 // Cleanup in error cases 285 defer func() { 286 if cleanupStopRunning { 287 stopRunning() 288 } 289 if cleanupCachedTLSDialer && cachedTLSDialer != nil { 290 cachedTLSDialer.close() 291 } 292 }() 293 294 meek := &MeekConn{ 295 params: meekConfig.Parameters, 296 mode: meekConfig.Mode, 297 networkLatencyMultiplier: meekConfig.NetworkLatencyMultiplier, 298 isClosed: false, 299 runCtx: runCtx, 300 stopRunning: stopRunning, 301 relayWaitGroup: new(sync.WaitGroup), 302 } 303 304 if meek.mode == MeekModeRelay { 305 var err error 306 meek.cookie, 307 meek.tlsPadding, 308 meek.limitRequestPayloadLength, 309 meek.redialTLSProbability, 310 err = 311 makeMeekObfuscationValues( 312 meek.getCustomParameters(), 313 meekConfig.MeekCookieEncryptionPublicKey, 314 meekConfig.MeekObfuscatedKey, 315 meekConfig.MeekObfuscatorPaddingSeed, 316 meekConfig.ClientTunnelProtocol, 317 "") 318 if err != nil { 319 return nil, errors.Trace(err) 320 } 321 322 // For stats, record the size of the initial obfuscated cookie. 323 meek.cookieSize = len(meek.cookie.Name) + len(meek.cookie.Value) 324 } 325 326 // Configure transport: QUIC or HTTPS or HTTP 327 328 var ( 329 scheme string 330 transport transporter 331 additionalHeaders http.Header 332 proxyUrl func(*http.Request) (*url.URL, error) 333 ) 334 335 if meekConfig.UseQUIC { 336 337 meek.isQUIC = true 338 339 scheme = "https" 340 341 udpDialer := func(ctx context.Context) (net.PacketConn, *net.UDPAddr, error) { 342 packetConn, remoteAddr, err := NewUDPConn( 343 ctx, 344 meekConfig.DialAddress, 345 dialConfig) 346 if err != nil { 347 return nil, nil, errors.Trace(err) 348 } 349 return packetConn, remoteAddr, nil 350 } 351 352 _, port, _ := net.SplitHostPort(meekConfig.DialAddress) 353 quicDialSNIAddress := fmt.Sprintf("%s:%s", meekConfig.SNIServerName, port) 354 355 var err error 356 transport, err = quic.NewQUICTransporter( 357 ctx, 358 func(message string) { 359 NoticeInfo(message) 360 }, 361 udpDialer, 362 quicDialSNIAddress, 363 meekConfig.QUICVersion) 364 if err != nil { 365 return nil, errors.Trace(err) 366 } 367 368 } else if meekConfig.UseHTTPS { 369 370 // Custom TLS dialer: 371 // 372 // 1. ignores the HTTP request address and uses the fronting domain 373 // 2. optionally disables SNI -- SNI breaks fronting when used with certain CDNs. 374 // 3. may skip verifying the server cert. 375 // 376 // Reasoning for #3: 377 // 378 // With a TLS MiM attack in place, and server certs verified, we'll fail to connect because the client 379 // will refuse to connect. That's not a successful outcome. 380 // 381 // With a MiM attack in place, and server certs not verified, we'll fail to connect if the MiM is actively 382 // targeting Psiphon and classifying the HTTP traffic by Host header or payload signature. 383 // 384 // However, in the case of a passive MiM that's just recording traffic or an active MiM that's targeting 385 // something other than Psiphon, the client will connect. This is a successful outcome. 386 // 387 // What is exposed to the MiM? The Host header does not contain a Psiphon server IP address, just an 388 // unrelated, randomly generated domain name which cannot be used to block direct connections. The 389 // Psiphon server IP is sent over meek, but it's in the encrypted cookie. 390 // 391 // The payload (user traffic) gets its confidentiality and integrity from the underlying SSH protocol. 392 // So, nothing is leaked to the MiM apart from signatures which could be used to classify the traffic 393 // as Psiphon to possibly block it; but note that not revealing that the client is Psiphon is outside 394 // our threat model; we merely seek to evade mass blocking by taking steps that require progressively 395 // more effort to block. 396 // 397 // There is a subtle attack remaining: an adversary that can MiM some CDNs but not others (and so can 398 // classify Psiphon traffic on some CDNs but not others) may throttle non-MiM CDNs so that our server 399 // selection always chooses tunnels to the MiM CDN (without any server cert verification, we won't 400 // exclusively connect to non-MiM CDNs); then the adversary kills the underlying TCP connection after 401 // some short period. This is partially mitigated by tactics mechanisms. 402 403 scheme = "https" 404 405 tlsConfig := &CustomTLSConfig{ 406 Parameters: meekConfig.Parameters, 407 DialAddr: meekConfig.DialAddress, 408 Dial: NewTCPDialer(dialConfig), 409 SNIServerName: meekConfig.SNIServerName, 410 SkipVerify: skipVerify, 411 VerifyServerName: meekConfig.VerifyServerName, 412 VerifyPins: meekConfig.VerifyPins, 413 TLSProfile: meekConfig.TLSProfile, 414 NoDefaultTLSSessionID: &meekConfig.NoDefaultTLSSessionID, 415 RandomizedTLSProfileSeed: meekConfig.RandomizedTLSProfileSeed, 416 TLSPadding: meek.tlsPadding, 417 TrustedCACertificatesFilename: dialConfig.TrustedCACertificatesFilename, 418 } 419 tlsConfig.EnableClientSessionCache() 420 421 if meekConfig.UseObfuscatedSessionTickets { 422 tlsConfig.ObfuscatedSessionTicketKey = meekConfig.MeekObfuscatedKey 423 } 424 425 if meekConfig.Mode != MeekModePlaintextRoundTrip && 426 meekConfig.MeekObfuscatedKey != "" { 427 428 // As the passthrough message is unique and indistinguishable from a normal 429 // TLS client random value, we set it unconditionally and not just for 430 // protocols which may support passthrough (even for those protocols, 431 // clients don't know which servers are configured to use it). 432 433 passthroughMessage, err := obfuscator.MakeTLSPassthroughMessage( 434 meekConfig.MeekObfuscatedKey) 435 if err != nil { 436 return nil, errors.Trace(err) 437 } 438 tlsConfig.PassthroughMessage = passthroughMessage 439 } 440 441 tlsDialer := NewCustomTLSDialer(tlsConfig) 442 443 // Pre-dial one TLS connection in order to inspect the negotiated 444 // application protocol. Then we create an HTTP/2 or HTTP/1.1 transport 445 // depending on which protocol was negotiated. The TLS dialer 446 // is assumed to negotiate only "h2" or "http/1.1"; or not negotiate 447 // an application protocol. 448 // 449 // We cannot rely on net/http's HTTP/2 support since it's only 450 // activated when http.Transport.DialTLS returns a golang crypto/tls.Conn; 451 // e.g., https://github.com/ooni/psiphon/oopsi/github.com/golang/go/blob/c8aec4095e089ff6ac50d18e97c3f46561f14f48/src/net/http/transport.go#L1040 452 // 453 // The pre-dialed connection is stored in a cachedTLSDialer, which will 454 // return the cached pre-dialed connection to its first Dial caller, and 455 // use the tlsDialer for all other Dials. 456 // 457 // cachedTLSDialer.close() must be called on all exits paths from this 458 // function and in meek.Close() to ensure the cached conn is closed in 459 // any case where no Dial call is made. 460 // 461 // The pre-dial must be interruptible so that DialMeek doesn't block and 462 // hang/delay a shutdown or end of establishment. So the pre-dial uses 463 // the Controller's PendingConns, not the MeekConn PendingConns. For this 464 // purpose, a special preDialer is configured. 465 // 466 // Only one pre-dial attempt is made; there are no retries. This differs 467 // from relayRoundTrip, which retries and may redial for each retry. 468 // Retries at the pre-dial phase are less useful since there's no active 469 // session to preserve, and establishment will simply try another server. 470 // Note that the underlying TCPDial may still try multiple IP addreses when 471 // the destination is a domain and it resolves to multiple IP adresses. 472 473 // The pre-dial is made within the parent dial context, so that DialMeek 474 // may be interrupted. Subsequent dials are made within the meek round trip 475 // request context. Since http.DialTLS doesn't take a context argument 476 // (yet; as of Go 1.9 this issue is still open: https://github.com/ooni/psiphon/oopsi/github.com/golang/go/issues/21526), 477 // cachedTLSDialer is used as a conduit to send the request context. 478 // meekConn.relayRoundTrip sets its request context into cachedTLSDialer, 479 // and cachedTLSDialer.dial uses that context. 480 481 // As DialAddr is set in the CustomTLSConfig, no address is required here. 482 preConn, err := tlsDialer(ctx, "tcp", "") 483 if err != nil { 484 return nil, errors.Trace(err) 485 } 486 487 cachedTLSDialer = newCachedTLSDialer(preConn, tlsDialer) 488 489 if IsTLSConnUsingHTTP2(preConn) { 490 NoticeInfo("negotiated HTTP/2 for %s", meekConfig.DiagnosticID) 491 transport = &http2.Transport{ 492 DialTLS: func(network, addr string, _ *tls.Config) (net.Conn, error) { 493 return cachedTLSDialer.dial(network, addr) 494 }, 495 } 496 } else { 497 transport = &http.Transport{ 498 DialTLS: func(network, addr string) (net.Conn, error) { 499 return cachedTLSDialer.dial(network, addr) 500 }, 501 } 502 } 503 504 } else { 505 506 scheme = "http" 507 508 var dialer common.Dialer 509 510 // For HTTP, and when the meekConfig.DialAddress matches the 511 // meekConfig.HostHeader, we let http.Transport handle proxying. 512 // http.Transport will put the the HTTP server address in the HTTP 513 // request line. In this one case, we can use an HTTP proxy that does 514 // not offer CONNECT support. 515 if strings.HasPrefix(dialConfig.UpstreamProxyURL, "http://") && 516 (meekConfig.DialAddress == meekConfig.HostHeader || 517 meekConfig.DialAddress == meekConfig.HostHeader+":80") { 518 519 url, err := common.SafeParseURL(dialConfig.UpstreamProxyURL) 520 if err != nil { 521 return nil, errors.Trace(err) 522 } 523 proxyUrl = http.ProxyURL(url) 524 525 // Here, the dialer must use the address that http.Transport 526 // passes in (which will be proxy address). 527 copyDialConfig := new(DialConfig) 528 *copyDialConfig = *dialConfig 529 copyDialConfig.UpstreamProxyURL = "" 530 531 dialer = NewTCPDialer(copyDialConfig) 532 533 } else { 534 535 baseDialer := NewTCPDialer(dialConfig) 536 537 // The dialer ignores any address that http.Transport will pass in 538 // (derived from the HTTP request URL) and always dials 539 // meekConfig.DialAddress. 540 dialer = func(ctx context.Context, network, _ string) (net.Conn, error) { 541 return baseDialer(ctx, network, meekConfig.DialAddress) 542 } 543 } 544 545 httpTransport := &http.Transport{ 546 Proxy: proxyUrl, 547 DialContext: dialer, 548 } 549 550 if proxyUrl != nil { 551 // Wrap transport with a transport that can perform HTTP proxy auth negotiation 552 var err error 553 transport, err = upstreamproxy.NewProxyAuthTransport(httpTransport, dialConfig.CustomHeaders) 554 if err != nil { 555 return nil, errors.Trace(err) 556 } 557 } else { 558 transport = httpTransport 559 } 560 } 561 562 url := &url.URL{ 563 Scheme: scheme, 564 Host: meekConfig.HostHeader, 565 Path: "/", 566 } 567 568 if meekConfig.UseHTTPS { 569 host, _, err := net.SplitHostPort(meekConfig.DialAddress) 570 if err != nil { 571 return nil, errors.Trace(err) 572 } 573 additionalHeaders = map[string][]string{ 574 "X-Psiphon-Fronting-Address": {host}, 575 } 576 } else { 577 if proxyUrl == nil { 578 additionalHeaders = dialConfig.CustomHeaders 579 } 580 } 581 582 meek.url = url 583 meek.additionalHeaders = additionalHeaders 584 meek.cachedTLSDialer = cachedTLSDialer 585 meek.transport = transport 586 587 // stopRunning and cachedTLSDialer will now be closed in meek.Close() 588 cleanupStopRunning = false 589 cleanupCachedTLSDialer = false 590 591 // Allocate relay resources, including buffers and running the relay 592 // go routine, only when running in relay mode. 593 if meek.mode == MeekModeRelay { 594 595 // The main loop of a MeekConn is run in the relay() goroutine. 596 // A MeekConn implements net.Conn concurrency semantics: 597 // "Multiple goroutines may invoke methods on a Conn simultaneously." 598 // 599 // Read() calls and relay() are synchronized by exchanging control of a single 600 // receiveBuffer (bytes.Buffer). This single buffer may be: 601 // - in the emptyReceiveBuffer channel when it is available and empty; 602 // - in the partialReadBuffer channel when it is available and contains data; 603 // - in the fullReadBuffer channel when it is available and full of data; 604 // - "checked out" by relay or Read when they are are writing to or reading from the 605 // buffer, respectively. 606 // relay() will obtain the buffer from either the empty or partial channel but block when 607 // the buffer is full. Read will obtain the buffer from the partial or full channel when 608 // there is data to read but block when the buffer is empty. 609 // Write() calls and relay() are synchronized in a similar way, using a single 610 // sendBuffer. 611 612 p := meek.getCustomParameters() 613 if p.Bool(parameters.MeekLimitBufferSizes) { 614 meek.fullReceiveBufferLength = p.Int(parameters.MeekLimitedFullReceiveBufferLength) 615 meek.readPayloadChunkLength = p.Int(parameters.MeekLimitedReadPayloadChunkLength) 616 } else { 617 meek.fullReceiveBufferLength = p.Int(parameters.MeekFullReceiveBufferLength) 618 meek.readPayloadChunkLength = p.Int(parameters.MeekReadPayloadChunkLength) 619 } 620 621 meek.emptyReceiveBuffer = make(chan *bytes.Buffer, 1) 622 meek.partialReceiveBuffer = make(chan *bytes.Buffer, 1) 623 meek.fullReceiveBuffer = make(chan *bytes.Buffer, 1) 624 meek.emptySendBuffer = make(chan *bytes.Buffer, 1) 625 meek.partialSendBuffer = make(chan *bytes.Buffer, 1) 626 meek.fullSendBuffer = make(chan *bytes.Buffer, 1) 627 628 meek.emptyReceiveBuffer <- new(bytes.Buffer) 629 meek.emptySendBuffer <- new(bytes.Buffer) 630 631 meek.relayWaitGroup.Add(1) 632 go meek.relay() 633 634 } else if meek.mode == MeekModeObfuscatedRoundTrip { 635 636 meek.meekCookieEncryptionPublicKey = meekConfig.MeekCookieEncryptionPublicKey 637 meek.meekObfuscatedKey = meekConfig.MeekObfuscatedKey 638 meek.meekObfuscatorPaddingSeed = meekConfig.MeekObfuscatorPaddingSeed 639 meek.clientTunnelProtocol = meekConfig.ClientTunnelProtocol 640 } 641 642 return meek, nil 643} 644 645type cachedTLSDialer struct { 646 usedCachedConn int32 647 cachedConn net.Conn 648 dialer common.Dialer 649 650 mutex sync.Mutex 651 requestCtx context.Context 652} 653 654func newCachedTLSDialer(cachedConn net.Conn, dialer common.Dialer) *cachedTLSDialer { 655 return &cachedTLSDialer{ 656 cachedConn: cachedConn, 657 dialer: dialer, 658 } 659} 660 661func (c *cachedTLSDialer) setRequestContext(requestCtx context.Context) { 662 // Note: not using sync.Value since underlying type of requestCtx may change. 663 c.mutex.Lock() 664 defer c.mutex.Unlock() 665 c.requestCtx = requestCtx 666} 667 668func (c *cachedTLSDialer) dial(network, addr string) (net.Conn, error) { 669 if atomic.CompareAndSwapInt32(&c.usedCachedConn, 0, 1) { 670 conn := c.cachedConn 671 c.cachedConn = nil 672 return conn, nil 673 } 674 675 c.mutex.Lock() 676 ctx := c.requestCtx 677 c.mutex.Unlock() 678 if ctx == nil { 679 ctx = context.Background() 680 } 681 682 return c.dialer(ctx, network, addr) 683} 684 685func (c *cachedTLSDialer) close() { 686 if atomic.CompareAndSwapInt32(&c.usedCachedConn, 0, 1) { 687 c.cachedConn.Close() 688 c.cachedConn = nil 689 } 690} 691 692// Close terminates the meek connection and releases its resources. In in 693// MeekModeRelay, Close waits for the relay goroutine to stop. 694func (meek *MeekConn) Close() (err error) { 695 696 // A mutex is required to support net.Conn concurrency semantics. 697 698 meek.mutex.Lock() 699 isClosed := meek.isClosed 700 meek.isClosed = true 701 meek.mutex.Unlock() 702 703 if !isClosed { 704 meek.stopRunning() 705 if meek.cachedTLSDialer != nil { 706 meek.cachedTLSDialer.close() 707 } 708 709 // stopRunning interrupts HTTP requests in progress by closing the context 710 // associated with the request. In the case of h2quic.RoundTripper, testing 711 // indicates that quic-go.receiveStream.readImpl in _not_ interrupted in 712 // this case, and so an in-flight FRONTED-MEEK-QUIC round trip may hang shutdown 713 // in relayRoundTrip->readPayload->...->quic-go.receiveStream.readImpl. 714 // 715 // To workaround this, we call CloseIdleConnections _before_ Wait, as, in 716 // the case of QUICTransporter, this closes the underlying UDP sockets which 717 // interrupts any blocking I/O calls. 718 // 719 // The standard CloseIdleConnections call _after_ wait is for the net/http 720 // case: it only closes idle connections, so the call should be after wait. 721 // This call is intended to clean up all network resources deterministically 722 // before Close returns. 723 if meek.isQUIC { 724 meek.transport.CloseIdleConnections() 725 } 726 727 meek.relayWaitGroup.Wait() 728 meek.transport.CloseIdleConnections() 729 } 730 return nil 731} 732 733// IsClosed implements the Closer interface. The return value 734// indicates whether the MeekConn has been closed. 735func (meek *MeekConn) IsClosed() bool { 736 737 meek.mutex.Lock() 738 isClosed := meek.isClosed 739 meek.mutex.Unlock() 740 741 return isClosed 742} 743 744// GetMetrics implements the common.MetricsSource interface. 745func (meek *MeekConn) GetMetrics() common.LogFields { 746 logFields := make(common.LogFields) 747 if meek.mode == MeekModeRelay { 748 logFields["meek_cookie_size"] = meek.cookieSize 749 logFields["meek_tls_padding"] = meek.tlsPadding 750 logFields["meek_limit_request"] = meek.limitRequestPayloadLength 751 } 752 return logFields 753} 754 755// ObfuscatedRoundTrip makes a request to the meek server and returns the 756// response. A new, obfuscated meek cookie is created for every request. The 757// specified end point is recorded in the cookie and is not exposed as 758// plaintext in the meek traffic. The caller is responsible for securing and 759// obfuscating the request body. 760// 761// ObfuscatedRoundTrip is not safe for concurrent use, and Close must not be 762// called concurrently. The caller must ensure only one ObfuscatedRoundTrip 763// call is active at once and that it completes or is cancelled before calling 764// Close. 765func (meek *MeekConn) ObfuscatedRoundTrip( 766 requestCtx context.Context, endPoint string, requestBody []byte) ([]byte, error) { 767 768 if meek.mode != MeekModeObfuscatedRoundTrip { 769 return nil, errors.TraceNew("operation unsupported") 770 } 771 772 cookie, _, _, _, err := makeMeekObfuscationValues( 773 meek.getCustomParameters(), 774 meek.meekCookieEncryptionPublicKey, 775 meek.meekObfuscatedKey, 776 meek.meekObfuscatorPaddingSeed, 777 meek.clientTunnelProtocol, 778 endPoint) 779 if err != nil { 780 return nil, errors.Trace(err) 781 } 782 783 // Note: 784 // 785 // - multiple, concurrent ObfuscatedRoundTrip calls are unsafe due to the 786 // setDialerRequestContext calls in newRequest. 787 // 788 // - concurrent Close and ObfuscatedRoundTrip calls are unsafe as Close does 789 // not synchronize with ObfuscatedRoundTrip before calling 790 // meek.transport.CloseIdleConnections(), so resources could be left open. 791 // 792 // At this time, ObfuscatedRoundTrip is used for tactics in Controller and 793 // the concurrency constraints are satisfied. 794 795 request, err := meek.newRequest( 796 requestCtx, cookie, bytes.NewReader(requestBody), 0) 797 if err != nil { 798 return nil, errors.Trace(err) 799 } 800 801 meek.scheduleQUICCloseIdle(request) 802 803 response, err := meek.transport.RoundTrip(request) 804 if err == nil { 805 defer response.Body.Close() 806 if response.StatusCode != http.StatusOK { 807 err = fmt.Errorf("unexpected response status code: %d", response.StatusCode) 808 } 809 } 810 if err != nil { 811 return nil, errors.Trace(err) 812 } 813 814 responseBody, err := ioutil.ReadAll(response.Body) 815 if err != nil { 816 return nil, errors.Trace(err) 817 } 818 819 return responseBody, nil 820} 821 822// RoundTrip implements the http.RoundTripper interface. RoundTrip may only be 823// used when TLS and server certificate verification are configured. RoundTrip 824// does not implement any security or obfuscation at the HTTP layer. 825// 826// RoundTrip is not safe for concurrent use, and Close must not be called 827// concurrently. The caller must ensure only one RoundTrip call is active at 828// once and that it completes or is cancelled before calling Close. 829func (meek *MeekConn) RoundTrip(request *http.Request) (*http.Response, error) { 830 831 if meek.mode != MeekModePlaintextRoundTrip { 832 return nil, errors.TraceNew("operation unsupported") 833 } 834 835 requestCtx := request.Context() 836 837 // The setDialerRequestContext/CloseIdleConnections concurrency note in 838 // ObfuscatedRoundTrip applies to RoundTrip as well. 839 840 // Ensure dials are made within the request context. 841 meek.setDialerRequestContext(requestCtx) 842 843 meek.scheduleQUICCloseIdle(request) 844 845 return meek.transport.RoundTrip(request) 846} 847 848// Read reads data from the connection. 849// net.Conn Deadlines are ignored. net.Conn concurrency semantics are supported. 850func (meek *MeekConn) Read(buffer []byte) (n int, err error) { 851 if meek.mode != MeekModeRelay { 852 return 0, errors.TraceNew("operation unsupported") 853 } 854 if meek.IsClosed() { 855 return 0, errors.TraceNew("meek connection is closed") 856 } 857 // Block until there is received data to consume 858 var receiveBuffer *bytes.Buffer 859 select { 860 case receiveBuffer = <-meek.partialReceiveBuffer: 861 case receiveBuffer = <-meek.fullReceiveBuffer: 862 case <-meek.runCtx.Done(): 863 return 0, errors.TraceNew("meek connection has closed") 864 } 865 n, err = receiveBuffer.Read(buffer) 866 meek.replaceReceiveBuffer(receiveBuffer) 867 return n, err 868} 869 870// Write writes data to the connection. 871// net.Conn Deadlines are ignored. net.Conn concurrency semantics are supported. 872func (meek *MeekConn) Write(buffer []byte) (n int, err error) { 873 if meek.mode != MeekModeRelay { 874 return 0, errors.TraceNew("operation unsupported") 875 } 876 if meek.IsClosed() { 877 return 0, errors.TraceNew("meek connection is closed") 878 } 879 // Repeats until all n bytes are written 880 n = len(buffer) 881 for len(buffer) > 0 { 882 // Block until there is capacity in the send buffer 883 var sendBuffer *bytes.Buffer 884 select { 885 case sendBuffer = <-meek.emptySendBuffer: 886 case sendBuffer = <-meek.partialSendBuffer: 887 case <-meek.runCtx.Done(): 888 return 0, errors.TraceNew("meek connection has closed") 889 } 890 writeLen := meek.limitRequestPayloadLength - sendBuffer.Len() 891 if writeLen > 0 { 892 if writeLen > len(buffer) { 893 writeLen = len(buffer) 894 } 895 _, err = sendBuffer.Write(buffer[:writeLen]) 896 buffer = buffer[writeLen:] 897 } 898 meek.replaceSendBuffer(sendBuffer) 899 } 900 return n, err 901} 902 903// LocalAddr is a stub implementation of net.Conn.LocalAddr 904func (meek *MeekConn) LocalAddr() net.Addr { 905 return nil 906} 907 908// RemoteAddr is a stub implementation of net.Conn.RemoteAddr 909func (meek *MeekConn) RemoteAddr() net.Addr { 910 return nil 911} 912 913// SetDeadline is a stub implementation of net.Conn.SetDeadline 914func (meek *MeekConn) SetDeadline(t time.Time) error { 915 return errors.TraceNew("not supported") 916} 917 918// SetReadDeadline is a stub implementation of net.Conn.SetReadDeadline 919func (meek *MeekConn) SetReadDeadline(t time.Time) error { 920 return errors.TraceNew("not supported") 921} 922 923// SetWriteDeadline is a stub implementation of net.Conn.SetWriteDeadline 924func (meek *MeekConn) SetWriteDeadline(t time.Time) error { 925 return errors.TraceNew("not supported") 926} 927 928func (meek *MeekConn) replaceReceiveBuffer(receiveBuffer *bytes.Buffer) { 929 switch { 930 case receiveBuffer.Len() == 0: 931 meek.emptyReceiveBuffer <- receiveBuffer 932 case receiveBuffer.Len() >= meek.fullReceiveBufferLength: 933 meek.fullReceiveBuffer <- receiveBuffer 934 default: 935 meek.partialReceiveBuffer <- receiveBuffer 936 } 937} 938 939func (meek *MeekConn) replaceSendBuffer(sendBuffer *bytes.Buffer) { 940 switch { 941 case sendBuffer.Len() == 0: 942 meek.emptySendBuffer <- sendBuffer 943 case sendBuffer.Len() >= meek.limitRequestPayloadLength: 944 meek.fullSendBuffer <- sendBuffer 945 default: 946 meek.partialSendBuffer <- sendBuffer 947 } 948} 949 950// relay sends and receives tunneled traffic (payload). An HTTP request is 951// triggered when data is in the write queue or at a polling interval. 952// There's a geometric increase, up to a maximum, in the polling interval when 953// no data is exchanged. Only one HTTP request is in flight at a time. 954func (meek *MeekConn) relay() { 955 // Note: meek.Close() calls here in relay() are made asynchronously 956 // (using goroutines) since Close() will wait on this WaitGroup. 957 defer meek.relayWaitGroup.Done() 958 959 p := meek.getCustomParameters() 960 interval := prng.JitterDuration( 961 p.Duration(parameters.MeekMinPollInterval), 962 p.Float(parameters.MeekMinPollIntervalJitter)) 963 p.Close() 964 965 timeout := time.NewTimer(interval) 966 defer timeout.Stop() 967 968 for { 969 timeout.Reset(interval) 970 971 // Block until there is payload to send or it is time to poll 972 var sendBuffer *bytes.Buffer 973 select { 974 case sendBuffer = <-meek.partialSendBuffer: 975 case sendBuffer = <-meek.fullSendBuffer: 976 case <-timeout.C: 977 // In the polling case, send an empty payload 978 case <-meek.runCtx.Done(): 979 // Drop through to second Done() check 980 } 981 982 // Check Done() again, to ensure it takes precedence 983 select { 984 case <-meek.runCtx.Done(): 985 return 986 default: 987 } 988 989 sendPayloadSize := 0 990 if sendBuffer != nil { 991 sendPayloadSize = sendBuffer.Len() 992 } 993 994 // relayRoundTrip will replace sendBuffer (by calling replaceSendBuffer). This 995 // is a compromise to conserve memory. Using a second buffer here, we could 996 // copy sendBuffer and immediately replace it, unblocking meekConn.Write() and 997 // allowing more upstream payload to immediately enqueue. Instead, the request 998 // payload is read directly from sendBuffer, including retries. Only once the 999 // server has acknowledged the request payload is sendBuffer replaced. This 1000 // still allows meekConn.Write() to unblock before the round trip response is 1001 // read. 1002 1003 receivedPayloadSize, err := meek.relayRoundTrip(sendBuffer) 1004 1005 if err != nil { 1006 select { 1007 case <-meek.runCtx.Done(): 1008 // In this case, meek.relayRoundTrip encountered Done(). Exit without 1009 // logging error. 1010 return 1011 default: 1012 } 1013 NoticeWarning("%s", errors.Trace(err)) 1014 go meek.Close() 1015 return 1016 } 1017 1018 // Periodically re-dial the underlying TLS connection. 1019 1020 if prng.FlipWeightedCoin(meek.redialTLSProbability) { 1021 meek.transport.CloseIdleConnections() 1022 } 1023 1024 // Calculate polling interval. When data is received, 1025 // immediately request more. Otherwise, schedule next 1026 // poll with exponential back off. Jitter and coin 1027 // flips are used to avoid trivial, static traffic 1028 // timing patterns. 1029 1030 p := meek.getCustomParameters() 1031 1032 if receivedPayloadSize > 0 || sendPayloadSize > 0 { 1033 1034 interval = 0 1035 1036 } else if interval == 0 { 1037 1038 interval = prng.JitterDuration( 1039 p.Duration(parameters.MeekMinPollInterval), 1040 p.Float(parameters.MeekMinPollIntervalJitter)) 1041 1042 } else { 1043 1044 if p.WeightedCoinFlip(parameters.MeekApplyPollIntervalMultiplierProbability) { 1045 1046 interval = 1047 time.Duration(float64(interval) * 1048 p.Float(parameters.MeekPollIntervalMultiplier)) 1049 } 1050 1051 interval = prng.JitterDuration( 1052 interval, 1053 p.Float(parameters.MeekPollIntervalJitter)) 1054 1055 if interval >= p.Duration(parameters.MeekMaxPollInterval) { 1056 1057 interval = prng.JitterDuration( 1058 p.Duration(parameters.MeekMaxPollInterval), 1059 p.Float(parameters.MeekMaxPollIntervalJitter)) 1060 } 1061 } 1062 1063 p.Close() 1064 } 1065} 1066 1067// readCloseSignaller is an io.ReadCloser wrapper for an io.Reader 1068// that is passed, as the request body, to http.Transport.RoundTrip. 1069// readCloseSignaller adds the AwaitClosed call, which is used 1070// to schedule recycling the buffer underlying the reader only after 1071// RoundTrip has called Close and will no longer use the buffer. 1072// See: https://github.com/ooni/psiphon/oopsi/golang.org/pkg/net/http/#RoundTripper 1073type readCloseSignaller struct { 1074 context context.Context 1075 reader io.Reader 1076 closed chan struct{} 1077} 1078 1079func NewReadCloseSignaller( 1080 context context.Context, 1081 reader io.Reader) *readCloseSignaller { 1082 1083 return &readCloseSignaller{ 1084 context: context, 1085 reader: reader, 1086 closed: make(chan struct{}, 1), 1087 } 1088} 1089 1090func (r *readCloseSignaller) Read(p []byte) (int, error) { 1091 return r.reader.Read(p) 1092} 1093 1094func (r *readCloseSignaller) Close() error { 1095 select { 1096 case r.closed <- struct{}{}: 1097 default: 1098 } 1099 return nil 1100} 1101 1102func (r *readCloseSignaller) AwaitClosed() bool { 1103 select { 1104 case <-r.context.Done(): 1105 case <-r.closed: 1106 return true 1107 } 1108 return false 1109} 1110 1111// newRequest performs common request setup for both MeekModeRelay and 1112// MeekModeObfuscatedRoundTrip. 1113// 1114// newRequest is not safe for concurrent calls due to its use of 1115// setRequestContext. 1116// 1117// The caller must call the returned cancelFunc. 1118func (meek *MeekConn) newRequest( 1119 requestCtx context.Context, 1120 cookie *http.Cookie, 1121 body io.Reader, 1122 contentLength int) (*http.Request, error) { 1123 1124 // Ensure dials are made within the request context. 1125 meek.setDialerRequestContext(requestCtx) 1126 1127 request, err := http.NewRequest("POST", meek.url.String(), body) 1128 if err != nil { 1129 return nil, errors.Trace(err) 1130 } 1131 1132 request = request.WithContext(requestCtx) 1133 1134 // Content-Length may not be be set automatically due to the 1135 // underlying type of requestBody. 1136 if contentLength > 0 { 1137 request.ContentLength = int64(contentLength) 1138 } 1139 1140 meek.addAdditionalHeaders(request) 1141 1142 request.Header.Set("Content-Type", "application/octet-stream") 1143 1144 if cookie == nil { 1145 cookie = meek.cookie 1146 } 1147 request.AddCookie(cookie) 1148 1149 return request, nil 1150} 1151 1152// setDialerRequestContext ensures that underlying TLS/QUIC dials operate 1153// within the context of the request context. setDialerRequestContext must not 1154// be called while another request is already in flight. 1155func (meek *MeekConn) setDialerRequestContext(requestCtx context.Context) { 1156 if meek.isQUIC { 1157 meek.transport.(*quic.QUICTransporter).SetRequestContext(requestCtx) 1158 } else if meek.cachedTLSDialer != nil { 1159 meek.cachedTLSDialer.setRequestContext(requestCtx) 1160 } 1161} 1162 1163// Workaround for h2quic.RoundTripper context issue. See comment in 1164// MeekConn.Close. 1165func (meek *MeekConn) scheduleQUICCloseIdle(request *http.Request) { 1166 requestCtx := request.Context() 1167 if meek.isQUIC && requestCtx != context.Background() { 1168 go func() { 1169 <-requestCtx.Done() 1170 meek.transport.CloseIdleConnections() 1171 }() 1172 } 1173} 1174 1175// relayRoundTrip configures and makes the actual HTTP POST request 1176func (meek *MeekConn) relayRoundTrip(sendBuffer *bytes.Buffer) (int64, error) { 1177 1178 // Retries are made when the round trip fails. This adds resiliency 1179 // to connection interruption and intermittent failures. 1180 // 1181 // At least one retry is always attempted, and retries continue 1182 // while still within a brief deadline -- 5 seconds, currently the 1183 // deadline for an actively probed SSH connection to timeout. There 1184 // is a brief delay between retries, allowing for intermittent 1185 // failure states to resolve. 1186 // 1187 // Failure may occur at various stages of the HTTP request: 1188 // 1189 // 1. Before the request begins. In this case, the entire request 1190 // may be rerun. 1191 // 1192 // 2. While sending the request payload. In this case, the client 1193 // must resend its request payload. The server will not have 1194 // relayed its partially received request payload. 1195 // 1196 // 3. After sending the request payload but before receiving 1197 // a response. The client cannot distinguish between case 2 and 1198 // this case, case 3. The client resends its payload and the 1199 // server detects this and skips relaying the request payload. 1200 // 1201 // 4. While reading the response payload. The client will omit its 1202 // request payload when retrying, as the server has already 1203 // acknowledged it. The client will also indicate to the server 1204 // the amount of response payload already received, and the 1205 // server will skip resending the indicated amount of response 1206 // payload. 1207 // 1208 // Retries are indicated to the server by adding a Range header, 1209 // which includes the response payload resend position. 1210 1211 defer func() { 1212 // Ensure sendBuffer is replaced, even in error code paths. 1213 if sendBuffer != nil { 1214 sendBuffer.Truncate(0) 1215 meek.replaceSendBuffer(sendBuffer) 1216 } 1217 }() 1218 1219 retries := uint(0) 1220 1221 p := meek.getCustomParameters() 1222 retryDeadline := time.Now().Add(p.Duration(parameters.MeekRoundTripRetryDeadline)) 1223 retryDelay := p.Duration(parameters.MeekRoundTripRetryMinDelay) 1224 retryMaxDelay := p.Duration(parameters.MeekRoundTripRetryMaxDelay) 1225 retryMultiplier := p.Float(parameters.MeekRoundTripRetryMultiplier) 1226 p.Close() 1227 1228 serverAcknowledgedRequestPayload := false 1229 1230 receivedPayloadSize := int64(0) 1231 1232 for try := 0; ; try++ { 1233 1234 // Omit the request payload when retrying after receiving a 1235 // partial server response. 1236 1237 var signaller *readCloseSignaller 1238 var requestBody io.ReadCloser 1239 contentLength := 0 1240 if !serverAcknowledgedRequestPayload && sendBuffer != nil { 1241 1242 // sendBuffer will be replaced once the data is no longer needed, 1243 // when RoundTrip calls Close on the Body; this allows meekConn.Write() 1244 // to unblock and start buffering data for the next roung trip while 1245 // still reading the current round trip response. signaller provides 1246 // the hook for awaiting RoundTrip's call to Close. 1247 1248 signaller = NewReadCloseSignaller(meek.runCtx, bytes.NewReader(sendBuffer.Bytes())) 1249 requestBody = signaller 1250 contentLength = sendBuffer.Len() 1251 } 1252 1253 // - meek.stopRunning() will abort a round trip in flight 1254 // - round trip will abort if it exceeds timeout 1255 requestCtx, cancelFunc := context.WithTimeout( 1256 meek.runCtx, 1257 meek.getCustomParameters().Duration(parameters.MeekRoundTripTimeout)) 1258 defer cancelFunc() 1259 1260 request, err := meek.newRequest( 1261 requestCtx, 1262 nil, 1263 requestBody, 1264 contentLength) 1265 if err != nil { 1266 // Don't retry when can't initialize a Request 1267 return 0, errors.Trace(err) 1268 } 1269 1270 expectedStatusCode := http.StatusOK 1271 1272 // When retrying, add a Range header to indicate how much 1273 // of the response was already received. 1274 1275 if try > 0 { 1276 expectedStatusCode = http.StatusPartialContent 1277 request.Header.Set("Range", fmt.Sprintf("bytes=%d-", receivedPayloadSize)) 1278 } 1279 1280 response, err := meek.transport.RoundTrip(request) 1281 1282 // Wait for RoundTrip to call Close on the request body, when 1283 // there is one. This is necessary to ensure it's safe to 1284 // subsequently replace sendBuffer in both the success and 1285 // error cases. 1286 if signaller != nil { 1287 if !signaller.AwaitClosed() { 1288 // AwaitClosed encountered Done(). Abort immediately. Do not 1289 // replace sendBuffer, as we cannot be certain RoundTrip is 1290 // done with it. MeekConn.Write will exit on Done and not hang 1291 // awaiting sendBuffer. 1292 sendBuffer = nil 1293 return 0, errors.TraceNew("meek connection has closed") 1294 } 1295 } 1296 1297 if err != nil { 1298 select { 1299 case <-meek.runCtx.Done(): 1300 // Exit without retrying and without logging error. 1301 return 0, errors.Trace(err) 1302 default: 1303 } 1304 NoticeWarning("meek round trip failed: %s", err) 1305 // ...continue to retry 1306 } 1307 1308 if err == nil { 1309 1310 if response.StatusCode != expectedStatusCode && 1311 // Certain http servers return 200 OK where we expect 206, so accept that. 1312 !(expectedStatusCode == http.StatusPartialContent && response.StatusCode == http.StatusOK) { 1313 1314 // Don't retry when the status code is incorrect 1315 response.Body.Close() 1316 return 0, errors.Tracef( 1317 "unexpected status code: %d instead of %d", 1318 response.StatusCode, expectedStatusCode) 1319 } 1320 1321 // Update meek session cookie 1322 for _, c := range response.Cookies() { 1323 if meek.cookie.Name == c.Name { 1324 meek.cookie.Value = c.Value 1325 break 1326 } 1327 } 1328 1329 // Received the response status code, so the server 1330 // must have received the request payload. 1331 serverAcknowledgedRequestPayload = true 1332 1333 // sendBuffer is now no longer required for retries, and the 1334 // buffer may be replaced; this allows meekConn.Write() to unblock 1335 // and start buffering data for the next round trip while still 1336 // reading the current round trip response. 1337 if sendBuffer != nil { 1338 // Assumes signaller.AwaitClosed is called above, so 1339 // sendBuffer will no longer be accessed by RoundTrip. 1340 sendBuffer.Truncate(0) 1341 meek.replaceSendBuffer(sendBuffer) 1342 sendBuffer = nil 1343 } 1344 1345 readPayloadSize, err := meek.readPayload(response.Body) 1346 response.Body.Close() 1347 1348 // receivedPayloadSize is the number of response 1349 // payload bytes received and relayed. A retry can 1350 // resume after this position. 1351 receivedPayloadSize += readPayloadSize 1352 1353 if err != nil { 1354 NoticeWarning("meek read payload failed: %s", err) 1355 // ...continue to retry 1356 } else { 1357 // Round trip completed successfully 1358 break 1359 } 1360 } 1361 1362 // Release context resources immediately. 1363 cancelFunc() 1364 1365 // Either the request failed entirely, or there was a failure 1366 // streaming the response payload. Always retry once. Then 1367 // retry if time remains; when the next delay exceeds the time 1368 // remaining until the deadline, do not retry. 1369 1370 now := time.Now() 1371 1372 if retries >= 1 && 1373 (now.After(retryDeadline) || retryDeadline.Sub(now) <= retryDelay) { 1374 return 0, errors.Trace(err) 1375 } 1376 retries += 1 1377 1378 delayTimer := time.NewTimer(retryDelay) 1379 1380 select { 1381 case <-delayTimer.C: 1382 case <-meek.runCtx.Done(): 1383 delayTimer.Stop() 1384 return 0, errors.Trace(err) 1385 } 1386 1387 // Increase the next delay, to back off and avoid excessive 1388 // activity in conditions such as no network connectivity. 1389 1390 retryDelay = time.Duration( 1391 float64(retryDelay) * retryMultiplier) 1392 if retryDelay >= retryMaxDelay { 1393 retryDelay = retryMaxDelay 1394 } 1395 } 1396 1397 return receivedPayloadSize, nil 1398} 1399 1400// Add additional headers to the HTTP request using the same method we use for adding 1401// custom headers to HTTP proxy requests. 1402func (meek *MeekConn) addAdditionalHeaders(request *http.Request) { 1403 for name, value := range meek.additionalHeaders { 1404 // hack around special case of "Host" header 1405 // https://github.com/ooni/psiphon/oopsi/golang.org/src/net/http/request.go#L474 1406 // using URL.Opaque, see URL.RequestURI() https://github.com/ooni/psiphon/oopsi/golang.org/src/net/url/url.go#L915 1407 if name == "Host" { 1408 if len(value) > 0 { 1409 if request.URL.Opaque == "" { 1410 request.URL.Opaque = request.URL.Scheme + "://" + request.Host + request.URL.RequestURI() 1411 } 1412 request.Host = value[0] 1413 } 1414 } else { 1415 request.Header[name] = value 1416 } 1417 } 1418} 1419 1420// readPayload reads the HTTP response in chunks, making the read buffer available 1421// to MeekConn.Read() calls after each chunk; the intention is to allow bytes to 1422// flow back to the reader as soon as possible instead of buffering the entire payload. 1423// 1424// When readPayload returns an error, the totalSize output is remains valid -- it's the 1425// number of payload bytes successfully read and relayed. 1426func (meek *MeekConn) readPayload( 1427 receivedPayload io.ReadCloser) (totalSize int64, err error) { 1428 1429 defer receivedPayload.Close() 1430 totalSize = 0 1431 for { 1432 reader := io.LimitReader(receivedPayload, int64(meek.readPayloadChunkLength)) 1433 // Block until there is capacity in the receive buffer 1434 var receiveBuffer *bytes.Buffer 1435 select { 1436 case receiveBuffer = <-meek.emptyReceiveBuffer: 1437 case receiveBuffer = <-meek.partialReceiveBuffer: 1438 case <-meek.runCtx.Done(): 1439 return 0, nil 1440 } 1441 // Note: receiveBuffer size may exceed meek.fullReceiveBufferLength by up to the size 1442 // of one received payload. The meek.fullReceiveBufferLength value is just a guideline. 1443 n, err := receiveBuffer.ReadFrom(reader) 1444 meek.replaceReceiveBuffer(receiveBuffer) 1445 totalSize += n 1446 if err != nil { 1447 return totalSize, errors.Trace(err) 1448 } 1449 if n == 0 { 1450 break 1451 } 1452 } 1453 return totalSize, nil 1454} 1455 1456// makeMeekObfuscationValues creates the meek cookie, to be sent with initial 1457// meek HTTP request, and other meek obfuscation values. The cookies contains 1458// obfuscated metadata, including meek version and other protocol information. 1459// 1460// In round tripper mode, the cookie contains the destination endpoint for the 1461// round trip request. 1462// 1463// In relay mode, the server will create a session using the cookie values and 1464// send the session ID back to the client via Set-Cookie header. The client 1465// must use that value with all consequent HTTP requests. 1466// 1467// In plain HTTP meek protocols, the cookie is visible over the adversary 1468// network, so the cookie is encrypted and obfuscated. 1469// 1470// Obsolete meek cookie fields used by the legacy server stack are no longer 1471// sent. These include ServerAddress and SessionID. 1472// 1473// The request payload limit and TLS redial probability apply only to relay 1474// mode and are selected once and used for the duration of a meek connction. 1475func makeMeekObfuscationValues( 1476 p parameters.ParametersAccessor, 1477 meekCookieEncryptionPublicKey string, 1478 meekObfuscatedKey string, 1479 meekObfuscatorPaddingPRNGSeed *prng.Seed, 1480 clientTunnelProtocol string, 1481 endPoint string, 1482 1483) (cookie *http.Cookie, 1484 tlsPadding int, 1485 limitRequestPayloadLength int, 1486 redialTLSProbability float64, 1487 err error) { 1488 1489 if meekCookieEncryptionPublicKey == "" { 1490 return nil, 0, 0, 0.0, errors.TraceNew("missing public key") 1491 } 1492 1493 cookieData := &protocol.MeekCookieData{ 1494 MeekProtocolVersion: MEEK_PROTOCOL_VERSION, 1495 ClientTunnelProtocol: clientTunnelProtocol, 1496 EndPoint: endPoint, 1497 } 1498 serializedCookie, err := json.Marshal(cookieData) 1499 if err != nil { 1500 return nil, 0, 0, 0.0, errors.Trace(err) 1501 } 1502 1503 // Encrypt the JSON data 1504 // NaCl box is used for encryption. The peer public key comes from the server entry. 1505 // Nonce is always all zeros, and is not sent in the cookie (the server also uses an all-zero nonce). 1506 // http://nacl.cace-project.eu/box.html: 1507 // "There is no harm in having the same nonce for different messages if the {sender, receiver} sets are 1508 // different. This is true even if the sets overlap. For example, a sender can use the same nonce for two 1509 // different messages if the messages are sent to two different public keys." 1510 var nonce [24]byte 1511 var publicKey [32]byte 1512 decodedPublicKey, err := base64.StdEncoding.DecodeString(meekCookieEncryptionPublicKey) 1513 if err != nil { 1514 return nil, 0, 0, 0.0, errors.Trace(err) 1515 } 1516 copy(publicKey[:], decodedPublicKey) 1517 ephemeralPublicKey, ephemeralPrivateKey, err := box.GenerateKey(rand.Reader) 1518 if err != nil { 1519 return nil, 0, 0, 0.0, errors.Trace(err) 1520 } 1521 box := box.Seal(nil, serializedCookie, &nonce, &publicKey, ephemeralPrivateKey) 1522 encryptedCookie := make([]byte, 32+len(box)) 1523 copy(encryptedCookie[0:32], ephemeralPublicKey[0:32]) 1524 copy(encryptedCookie[32:], box) 1525 1526 maxPadding := p.Int(parameters.MeekCookieMaxPadding) 1527 1528 // Obfuscate the encrypted data. NewClientObfuscator checks that 1529 // meekObfuscatedKey isn't missing. 1530 obfuscator, err := obfuscator.NewClientObfuscator( 1531 &obfuscator.ObfuscatorConfig{ 1532 Keyword: meekObfuscatedKey, 1533 PaddingPRNGSeed: meekObfuscatorPaddingPRNGSeed, 1534 MaxPadding: &maxPadding}) 1535 if err != nil { 1536 return nil, 0, 0, 0.0, errors.Trace(err) 1537 } 1538 obfuscatedCookie := obfuscator.SendSeedMessage() 1539 seedLen := len(obfuscatedCookie) 1540 obfuscatedCookie = append(obfuscatedCookie, encryptedCookie...) 1541 obfuscator.ObfuscateClientToServer(obfuscatedCookie[seedLen:]) 1542 1543 cookieNamePRNG, err := obfuscator.GetDerivedPRNG("meek-cookie-name") 1544 if err != nil { 1545 return nil, 0, 0, 0.0, errors.Trace(err) 1546 } 1547 1548 // Format the HTTP cookie 1549 // The format is <random letter 'A'-'Z'>=<base64 data>, which is intended to match common cookie formats. 1550 A := int('A') 1551 Z := int('Z') 1552 // letterIndex is integer in range [int('A'), int('Z')] 1553 letterIndex := cookieNamePRNG.Intn(Z - A + 1) 1554 1555 cookie = &http.Cookie{ 1556 Name: string(byte(A + letterIndex)), 1557 Value: base64.StdEncoding.EncodeToString(obfuscatedCookie)} 1558 1559 tlsPadding = 0 1560 limitRequestPayloadLength = MEEK_MAX_REQUEST_PAYLOAD_LENGTH 1561 redialTLSProbability = 0.0 1562 1563 tunnelProtocols := p.TunnelProtocols(parameters.MeekTrafficShapingLimitProtocols) 1564 if (len(tunnelProtocols) == 0 || 1565 common.Contains(tunnelProtocols, clientTunnelProtocol)) && 1566 p.WeightedCoinFlip(parameters.MeekTrafficShapingProbability) { 1567 1568 limitRequestPayloadLengthPRNG, err := obfuscator.GetDerivedPRNG( 1569 "meek-limit-request-payload-length") 1570 if err != nil { 1571 return nil, 0, 0, 0.0, errors.Trace(err) 1572 } 1573 1574 minLength := p.Int(parameters.MeekMinLimitRequestPayloadLength) 1575 if minLength > MEEK_MAX_REQUEST_PAYLOAD_LENGTH { 1576 minLength = MEEK_MAX_REQUEST_PAYLOAD_LENGTH 1577 } 1578 maxLength := p.Int(parameters.MeekMaxLimitRequestPayloadLength) 1579 if maxLength > MEEK_MAX_REQUEST_PAYLOAD_LENGTH { 1580 maxLength = MEEK_MAX_REQUEST_PAYLOAD_LENGTH 1581 } 1582 1583 limitRequestPayloadLength = limitRequestPayloadLengthPRNG.Range( 1584 minLength, maxLength) 1585 1586 minPadding := p.Int(parameters.MeekMinTLSPadding) 1587 maxPadding := p.Int(parameters.MeekMaxTLSPadding) 1588 1589 // Maximum padding size per RFC 7685 1590 if maxPadding > 65535 { 1591 maxPadding = 65535 1592 } 1593 1594 if maxPadding > 0 { 1595 tlsPaddingPRNG, err := obfuscator.GetDerivedPRNG( 1596 "meek-tls-padding") 1597 if err != nil { 1598 return nil, 0, 0, 0.0, errors.Trace(err) 1599 } 1600 1601 tlsPadding = tlsPaddingPRNG.Range(minPadding, maxPadding) 1602 } 1603 1604 redialTLSProbability = p.Float(parameters.MeekRedialTLSProbability) 1605 } 1606 1607 return cookie, tlsPadding, limitRequestPayloadLength, redialTLSProbability, nil 1608} 1609