|
|
@ -18,6 +18,7 @@ import (
|
|
|
|
"net"
|
|
|
|
"net"
|
|
|
|
"net/http"
|
|
|
|
"net/http"
|
|
|
|
"net/netip"
|
|
|
|
"net/netip"
|
|
|
|
|
|
|
|
"net/url"
|
|
|
|
"os"
|
|
|
|
"os"
|
|
|
|
"runtime"
|
|
|
|
"runtime"
|
|
|
|
"strconv"
|
|
|
|
"strconv"
|
|
|
@ -25,14 +26,17 @@ import (
|
|
|
|
"time"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/peterbourgon/ff/v3/ffcli"
|
|
|
|
"github.com/peterbourgon/ff/v3/ffcli"
|
|
|
|
|
|
|
|
"golang.org/x/net/http/httpproxy"
|
|
|
|
"tailscale.com/control/controlhttp"
|
|
|
|
"tailscale.com/control/controlhttp"
|
|
|
|
"tailscale.com/hostinfo"
|
|
|
|
"tailscale.com/hostinfo"
|
|
|
|
"tailscale.com/ipn"
|
|
|
|
"tailscale.com/ipn"
|
|
|
|
"tailscale.com/net/tsaddr"
|
|
|
|
"tailscale.com/net/tsaddr"
|
|
|
|
|
|
|
|
"tailscale.com/net/tshttpproxy"
|
|
|
|
"tailscale.com/paths"
|
|
|
|
"tailscale.com/paths"
|
|
|
|
"tailscale.com/safesocket"
|
|
|
|
"tailscale.com/safesocket"
|
|
|
|
"tailscale.com/tailcfg"
|
|
|
|
"tailscale.com/tailcfg"
|
|
|
|
"tailscale.com/types/key"
|
|
|
|
"tailscale.com/types/key"
|
|
|
|
|
|
|
|
"tailscale.com/types/logger"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
var debugCmd = &ffcli.Command{
|
|
|
|
var debugCmd = &ffcli.Command{
|
|
|
@ -141,6 +145,7 @@ var debugCmd = &ffcli.Command{
|
|
|
|
fs := newFlagSet("ts2021")
|
|
|
|
fs := newFlagSet("ts2021")
|
|
|
|
fs.StringVar(&ts2021Args.host, "host", "controlplane.tailscale.com", "hostname of control plane")
|
|
|
|
fs.StringVar(&ts2021Args.host, "host", "controlplane.tailscale.com", "hostname of control plane")
|
|
|
|
fs.IntVar(&ts2021Args.version, "version", int(tailcfg.CurrentCapabilityVersion), "protocol version")
|
|
|
|
fs.IntVar(&ts2021Args.version, "version", int(tailcfg.CurrentCapabilityVersion), "protocol version")
|
|
|
|
|
|
|
|
fs.BoolVar(&ts2021Args.verbose, "verbose", false, "be extra verbose")
|
|
|
|
return fs
|
|
|
|
return fs
|
|
|
|
})(),
|
|
|
|
})(),
|
|
|
|
},
|
|
|
|
},
|
|
|
@ -465,19 +470,35 @@ func runVia(ctx context.Context, args []string) error {
|
|
|
|
var ts2021Args struct {
|
|
|
|
var ts2021Args struct {
|
|
|
|
host string // "controlplane.tailscale.com"
|
|
|
|
host string // "controlplane.tailscale.com"
|
|
|
|
version int // 27 or whatever
|
|
|
|
version int // 27 or whatever
|
|
|
|
|
|
|
|
verbose bool
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func runTS2021(ctx context.Context, args []string) error {
|
|
|
|
func runTS2021(ctx context.Context, args []string) error {
|
|
|
|
log.SetOutput(os.Stdout)
|
|
|
|
log.SetOutput(os.Stdout)
|
|
|
|
log.SetFlags(log.Ltime | log.Lmicroseconds)
|
|
|
|
log.SetFlags(log.Ltime | log.Lmicroseconds)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
keysURL := "https://" + ts2021Args.host + "/key?v=" + strconv.Itoa(ts2021Args.version)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ts2021Args.verbose {
|
|
|
|
|
|
|
|
u, err := url.Parse(keysURL)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
envConf := httpproxy.FromEnvironment()
|
|
|
|
|
|
|
|
if *envConf == (httpproxy.Config{}) {
|
|
|
|
|
|
|
|
log.Printf("HTTP proxy env: (none)")
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
log.Printf("HTTP proxy env: %+v", envConf)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
proxy, err := tshttpproxy.ProxyFromEnvironment(&http.Request{URL: u})
|
|
|
|
|
|
|
|
log.Printf("tshttpproxy.ProxyFromEnvironment = (%v, %v)", proxy, err)
|
|
|
|
|
|
|
|
}
|
|
|
|
machinePrivate := key.NewMachine()
|
|
|
|
machinePrivate := key.NewMachine()
|
|
|
|
var dialer net.Dialer
|
|
|
|
var dialer net.Dialer
|
|
|
|
|
|
|
|
|
|
|
|
var keys struct {
|
|
|
|
var keys struct {
|
|
|
|
PublicKey key.MachinePublic
|
|
|
|
PublicKey key.MachinePublic
|
|
|
|
}
|
|
|
|
}
|
|
|
|
keysURL := "https://" + ts2021Args.host + "/key?v=" + strconv.Itoa(ts2021Args.version)
|
|
|
|
|
|
|
|
log.Printf("Fetching keys from %s ...", keysURL)
|
|
|
|
log.Printf("Fetching keys from %s ...", keysURL)
|
|
|
|
req, err := http.NewRequestWithContext(ctx, "GET", keysURL, nil)
|
|
|
|
req, err := http.NewRequestWithContext(ctx, "GET", keysURL, nil)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
@ -497,6 +518,9 @@ func runTS2021(ctx context.Context, args []string) error {
|
|
|
|
return fmt.Errorf("decoding /keys JSON: %w", err)
|
|
|
|
return fmt.Errorf("decoding /keys JSON: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
res.Body.Close()
|
|
|
|
res.Body.Close()
|
|
|
|
|
|
|
|
if ts2021Args.verbose {
|
|
|
|
|
|
|
|
log.Printf("got public key: %v", keys.PublicKey)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
dialFunc := func(ctx context.Context, network, address string) (net.Conn, error) {
|
|
|
|
dialFunc := func(ctx context.Context, network, address string) (net.Conn, error) {
|
|
|
|
log.Printf("Dial(%q, %q) ...", network, address)
|
|
|
|
log.Printf("Dial(%q, %q) ...", network, address)
|
|
|
@ -508,7 +532,10 @@ func runTS2021(ctx context.Context, args []string) error {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return c, err
|
|
|
|
return c, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var logf logger.Logf
|
|
|
|
|
|
|
|
if ts2021Args.verbose {
|
|
|
|
|
|
|
|
logf = log.Printf
|
|
|
|
|
|
|
|
}
|
|
|
|
conn, err := (&controlhttp.Dialer{
|
|
|
|
conn, err := (&controlhttp.Dialer{
|
|
|
|
Hostname: ts2021Args.host,
|
|
|
|
Hostname: ts2021Args.host,
|
|
|
|
HTTPPort: "80",
|
|
|
|
HTTPPort: "80",
|
|
|
@ -517,6 +544,7 @@ func runTS2021(ctx context.Context, args []string) error {
|
|
|
|
ControlKey: keys.PublicKey,
|
|
|
|
ControlKey: keys.PublicKey,
|
|
|
|
ProtocolVersion: uint16(ts2021Args.version),
|
|
|
|
ProtocolVersion: uint16(ts2021Args.version),
|
|
|
|
Dialer: dialFunc,
|
|
|
|
Dialer: dialFunc,
|
|
|
|
|
|
|
|
Logf: logf,
|
|
|
|
}).Dial(ctx)
|
|
|
|
}).Dial(ctx)
|
|
|
|
log.Printf("controlhttp.Dial = %p, %v", conn, err)
|
|
|
|
log.Printf("controlhttp.Dial = %p, %v", conn, err)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|