summaryrefslogtreecommitdiffhomepage
path: root/ipn/localapi/localapi.go
diff options
context:
space:
mode:
authorBrad Fitzpatrick <bradfitz@tailscale.com>2022-10-07 21:00:42 -0700
committerBrad Fitzpatrick <bradfitz@tailscale.com>2022-10-10 14:48:38 -0700
commit6438ad54b18ed63c15a1abcfa2ac8fd53910b193 (patch)
treedc6d1624172a87f5254d4d5110471c58d932bdec /ipn/localapi/localapi.go
parent0475ed4a7e28a10f2f9e1b51bc1b07b957bea1c9 (diff)
downloadtailscale-bradfitz/tailpipe.tar.xz
tailscale-bradfitz/tailpipe.zip
WIP tailpipebradfitz/tailpipe
Updates #nnn Change-Id: I719479e4cd58c487b4d987ab563689caacce1549 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Diffstat (limited to 'ipn/localapi/localapi.go')
-rw-r--r--ipn/localapi/localapi.go36
1 files changed, 34 insertions, 2 deletions
diff --git a/ipn/localapi/localapi.go b/ipn/localapi/localapi.go
index 3ebd109f8..1b04f4519 100644
--- a/ipn/localapi/localapi.go
+++ b/ipn/localapi/localapi.go
@@ -67,6 +67,7 @@ var handler = map[string]localAPIHandler{
"login-interactive": (*Handler).serveLoginInteractive,
"logout": (*Handler).serveLogout,
"metrics": (*Handler).serveMetrics,
+ "open-bidi-pipe": (*Handler).serveOpenBidiPipe,
"ping": (*Handler).servePing,
"prefs": (*Handler).servePrefs,
"profile": (*Handler).serveProfile,
@@ -764,8 +765,16 @@ func (h *Handler) serveDial(w http.ResponseWriter, r *http.Request) {
return
}
- addr := net.JoinHostPort(hostStr, portStr)
- outConn, err := h.b.Dialer().UserDial(r.Context(), "tcp", addr)
+ dial := func() (net.Conn, error) {
+ if strings.HasPrefix(portStr, "tailpipe-") {
+ // hostStr is expected to be a Tailscale IP at this point.
+ return h.b.DialTailpipe(r.Context(), hostStr, portStr)
+ }
+ addr := net.JoinHostPort(hostStr, portStr)
+ return h.b.Dialer().UserDial(r.Context(), "tcp", addr)
+ }
+
+ outConn, err := dial()
if err != nil {
http.Error(w, "dial failure: "+err.Error(), http.StatusBadGateway)
return
@@ -933,6 +942,29 @@ func (h *Handler) serveTKAModify(w http.ResponseWriter, r *http.Request) {
w.Write(j)
}
+func (h *Handler) serveOpenBidiPipe(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodPost {
+ http.Error(w, "use POST", http.StatusMethodNotAllowed)
+ return
+ }
+ name := r.FormValue("name")
+ if name != "" && !h.PermitWrite {
+ http.Error(w, "naming a bidi pipe requires write access", http.StatusForbidden)
+ return
+ }
+
+ w.Header().Set("Foo", "bar")
+ w.WriteHeader(http.StatusProcessing) // informational code 102
+
+ time.Sleep(time.Second)
+
+ w.Header().Set("Foo", "baz")
+ w.WriteHeader(http.StatusProcessing) // informational code 102
+
+ w.Header()["Foo"] = nil
+ io.WriteString(w, "the body")
+}
+
func defBool(a string, def bool) bool {
if a == "" {
return def