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