mirror of
				https://github.com/tailscale/tailscale.git
				synced 2025-10-31 16:22:03 +01:00 
			
		
		
		
	Or unless the new "ts_debug_websockets" build tag is set. Updates #1278 Change-Id: Ic4c4f81c1924250efd025b055585faec37a5491d Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
		
			
				
	
	
		
			63 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			63 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright (c) Tailscale Inc & AUTHORS
 | |
| // SPDX-License-Identifier: BSD-3-Clause
 | |
| 
 | |
| package controlhttp
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"encoding/base64"
 | |
| 	"errors"
 | |
| 	"net"
 | |
| 	"net/url"
 | |
| 
 | |
| 	"github.com/coder/websocket"
 | |
| 	"tailscale.com/control/controlbase"
 | |
| 	"tailscale.com/control/controlhttp/controlhttpcommon"
 | |
| 	"tailscale.com/net/wsconn"
 | |
| )
 | |
| 
 | |
| // Variant of Dial that tunnels the request over WebSockets, since we cannot do
 | |
| // bi-directional communication over an HTTP connection when in JS.
 | |
| func (d *Dialer) Dial(ctx context.Context) (*ClientConn, error) {
 | |
| 	if d.Hostname == "" {
 | |
| 		return nil, errors.New("required Dialer.Hostname empty")
 | |
| 	}
 | |
| 
 | |
| 	init, cont, err := controlbase.ClientDeferred(d.MachineKey, d.ControlKey, d.ProtocolVersion)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	wsScheme := "wss"
 | |
| 	host := d.Hostname
 | |
| 	// If using a custom control server (on a non-standard port), prefer that.
 | |
| 	// This mirrors the port selection in newNoiseClient from noise.go.
 | |
| 	if d.HTTPPort != "" && d.HTTPPort != "80" && d.HTTPSPort == "443" {
 | |
| 		wsScheme = "ws"
 | |
| 		host = net.JoinHostPort(host, d.HTTPPort)
 | |
| 	}
 | |
| 	wsURL := &url.URL{
 | |
| 		Scheme: wsScheme,
 | |
| 		Host:   host,
 | |
| 		Path:   serverUpgradePath,
 | |
| 		// Can't set HTTP headers on the websocket request, so we have to to send
 | |
| 		// the handshake via an HTTP header.
 | |
| 		RawQuery: url.Values{
 | |
| 			controlhttpcommon.HandshakeHeaderName: []string{base64.StdEncoding.EncodeToString(init)},
 | |
| 		}.Encode(),
 | |
| 	}
 | |
| 	wsConn, _, err := websocket.Dial(ctx, wsURL.String(), &websocket.DialOptions{
 | |
| 		Subprotocols: []string{controlhttpcommon.UpgradeHeaderValue},
 | |
| 	})
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	netConn := wsconn.NetConn(context.Background(), wsConn, websocket.MessageBinary, wsURL.String())
 | |
| 	cbConn, err := cont(ctx, netConn)
 | |
| 	if err != nil {
 | |
| 		netConn.Close()
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return &ClientConn{Conn: cbConn}, nil
 | |
| }
 |