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