diff --git a/cmd/hello/hello.go b/cmd/hello/hello.go index e768c1ef2..c31ccb703 100644 --- a/cmd/hello/hello.go +++ b/cmd/hello/hello.go @@ -16,6 +16,8 @@ import ( "net" "net/http" "net/url" + "os" + "strconv" "strings" "tailscale.com/safesocket" @@ -25,10 +27,21 @@ import ( var ( httpAddr = flag.String("http", ":80", "address to run an HTTP server on, or empty for none") httpsAddr = flag.String("https", ":443", "address to run an HTTPS server on, or empty for none") + testIP = flag.String("test-ip", "", "if non-empty, look up IP and exit before running a server") ) func main() { flag.Parse() + if *testIP != "" { + res, err := whoIs(*testIP) + if err != nil { + log.Fatal(err) + } + e := json.NewEncoder(os.Stdout) + e.SetIndent("", "\t") + e.Encode(res) + return + } if !devMode() { tmpl = template.Must(template.New("home").Parse(slurpHTML())) } @@ -113,6 +126,7 @@ func root(w http.ResponseWriter, r *http.Request) { var data tmplData if err != nil { if devMode() { + log.Printf("warning: using fake data in dev mode due to whois lookup error: %v", err) data = tmplData{ DisplayName: "Taily Scalerson", LoginName: "taily@scaler.son", @@ -153,13 +167,28 @@ func firstLabel(s string) string { var tsSockClient = &http.Client{ Transport: &http.Transport{ DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { + // On macOS, when dialing from non-sandboxed program to sandboxed GUI running + // a TCP server on a random port, find the random port. For HTTP connections, + // we don't send the token. It gets added in an HTTP Basic-Auth header. + if port, _, err := safesocket.LocalTCPPortAndToken(); err == nil { + var d net.Dialer + return d.DialContext(ctx, "tcp", "localhost:"+strconv.Itoa(port)) + } return safesocket.ConnectDefault() }, }, } func whoIs(ip string) (*tailcfg.WhoIsResponse, error) { - res, err := tsSockClient.Get("http://local-tailscaled.sock/localapi/v0/whois?ip=" + url.QueryEscape(ip)) + ctx := context.Background() + req, err := http.NewRequestWithContext(ctx, "GET", "http://local-tailscaled.sock/localapi/v0/whois?ip="+url.QueryEscape(ip), nil) + if err != nil { + return nil, err + } + if _, token, err := safesocket.LocalTCPPortAndToken(); err == nil { + req.SetBasicAuth("", token) + } + res, err := tsSockClient.Do(req) if err != nil { return nil, err }