summaryrefslogtreecommitdiffhomepage
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/tailscale/localclient.go65
1 files changed, 64 insertions, 1 deletions
diff --git a/client/tailscale/localclient.go b/client/tailscale/localclient.go
index 01b7a08fd..ce6bd95de 100644
--- a/client/tailscale/localclient.go
+++ b/client/tailscale/localclient.go
@@ -19,6 +19,7 @@ import (
"net/http"
"net/http/httptrace"
"net/netip"
+ "net/textproto"
"net/url"
"os/exec"
"runtime"
@@ -558,6 +559,15 @@ func (lc *LocalClient) SetDNS(ctx context.Context, name, value string) error {
//
// The ctx is only used for the duration of the call, not the lifetime of the net.Conn.
func (lc *LocalClient) DialTCP(ctx context.Context, host string, port uint16) (net.Conn, error) {
+ return lc.dialViaLocalAPI(ctx, host, fmt.Sprint(port))
+}
+
+// DialTCPNamedPort is like DialTCP but takes a named port rather than an integer.
+func (lc *LocalClient) DialTCPNamedPort(ctx context.Context, host, portName string) (net.Conn, error) {
+ return lc.dialViaLocalAPI(ctx, host, portName)
+}
+
+func (lc *LocalClient) dialViaLocalAPI(ctx context.Context, host, port string) (net.Conn, error) {
connCh := make(chan net.Conn, 1)
trace := httptrace.ClientTrace{
GotConn: func(info httptrace.GotConnInfo) {
@@ -573,7 +583,7 @@ func (lc *LocalClient) DialTCP(ctx context.Context, host string, port uint16) (n
"Upgrade": []string{"ts-dial"},
"Connection": []string{"upgrade"},
"Dial-Host": []string{host},
- "Dial-Port": []string{fmt.Sprint(port)},
+ "Dial-Port": []string{port},
}
res, err := lc.DoLocalRequest(req)
if err != nil {
@@ -605,6 +615,59 @@ func (lc *LocalClient) DialTCP(ctx context.Context, host string, port uint16) (n
return netutil.NewAltReadWriteCloserConn(rwc, switchedConn), nil
}
+// ListenNewRandomPortName...
+func (lc *LocalClient) ListenNewRandomPortName(ctx context.Context) (portName string, accept func(context.Context) (net.Conn, error), err error) {
+ connCh := make(chan net.Conn, 1)
+ portNameCh := make(chan string, 1)
+ trace := httptrace.ClientTrace{
+ GotConn: func(info httptrace.GotConnInfo) {
+ connCh <- info.Conn
+ },
+ Got1xxResponse: func(code int, header textproto.MIMEHeader) error {
+ portNameCh <- fmt.Sprintf("Got %v, %v", code, header)
+ return nil
+ },
+ }
+ ctx = httptrace.WithClientTrace(ctx, &trace)
+ req, err := http.NewRequestWithContext(ctx, "POST", "http://local-tailscaled.sock/localapi/v0/open-bidi-pipe", nil)
+ if err != nil {
+ return "", nil, err
+ }
+ req.Header = http.Header{
+ "Upgrade": []string{"ts-open-bidi-pipe"},
+ "Connection": []string{"upgrade"},
+ }
+
+ doErrc := make(chan error, 1)
+
+ go func() {
+ res, err := lc.DoLocalRequest(req)
+ if err != nil {
+ doErrc <- err
+ return
+ }
+ _ = res
+ }()
+
+ accept = func(ctx context.Context) (net.Conn, error) {
+ panic("TODO")
+ }
+
+ select {
+ case name := <-portNameCh:
+ return name, accept, nil
+ case err := <-doErrc:
+ return "", nil, err
+ }
+
+ // if res.StatusCode != http.StatusSwitchingProtocols {
+ // body, _ := io.ReadAll(res.Body)
+ // res.Body.Close()
+ // return nil, fmt.Errorf("unexpected HTTP response: %s, %s", res.Status, body)
+ // }
+ panic("TODO")
+}
+
// CurrentDERPMap returns the current DERPMap that is being used by the local tailscaled.
// It is intended to be used with netcheck to see availability of DERPs.
func (lc *LocalClient) CurrentDERPMap(ctx context.Context) (*tailcfg.DERPMap, error) {