summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorBrad Fitzpatrick <bradfitz@tailscale.com>2021-12-02 12:46:35 -0800
committerBrad Fitzpatrick <bradfitz@tailscale.com>2021-12-02 12:46:37 -0800
commit54b2f16e109bbcf6f39889a42a1008ca5fe67338 (patch)
tree2da99ebaa7fbe28721fb8ab8aaf8016f0ccafb8e
parentadc5997592429e29a8301f812e9e02e107ccee88 (diff)
downloadtailscale-bradfitz/demo_client_hijack.tar.xz
tailscale-bradfitz/demo_client_hijack.zip
client hijack demobradfitz/demo_client_hijack
Change-Id: I68d16b4a26bffe98b3c73feda130bfa4addf9436 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
-rw-r--r--cmd/clienthijackdemo/clienthijackdemo.go94
1 files changed, 94 insertions, 0 deletions
diff --git a/cmd/clienthijackdemo/clienthijackdemo.go b/cmd/clienthijackdemo/clienthijackdemo.go
new file mode 100644
index 000000000..da1a26051
--- /dev/null
+++ b/cmd/clienthijackdemo/clienthijackdemo.go
@@ -0,0 +1,94 @@
+package main
+
+import (
+ "bufio"
+ "context"
+ "flag"
+ "fmt"
+ "io"
+ "log"
+ "net"
+ "net/http"
+ "net/http/httptrace"
+ "os"
+ "runtime"
+ "strings"
+ "time"
+)
+
+var listen = flag.String("listen", ":8070", "listen")
+
+func main() {
+ flag.Parse()
+ log.Printf("%v; listening on %v ...", runtime.Version(), *listen)
+ go client()
+ log.Fatal(http.ListenAndServe(*listen, http.HandlerFunc(serve)))
+}
+
+func client() {
+ time.Sleep(200 * time.Millisecond)
+
+ tr := &http.Transport{
+ DisableKeepAlives: true,
+ }
+ connc := make(chan net.Conn, 1)
+ ctx := httptrace.WithClientTrace(context.Background(), &httptrace.ClientTrace{
+ GotConn: func(ci httptrace.GotConnInfo) {
+ log.Printf("gotconn: %+v", ci)
+ connc <- ci.Conn
+ },
+ })
+ req, _ := http.NewRequestWithContext(ctx, "POST", "http://localhost:8070", nil)
+ req.Header.Set("Connection", "upgrade")
+ req.Header.Set("Upgrade", "tailscale")
+ _, err := tr.RoundTrip(req)
+ if err != nil {
+ log.Printf("Failed: %v", err)
+ return
+ }
+ //log.Printf("client got: %+v", res)
+ //log.Printf("body type is %T", res.Body)
+
+ conn := <-connc
+ log.Printf("Conn was %T", conn)
+ go func() {
+ for {
+ time.Sleep(time.Second)
+ fmt.Fprintf(conn, "it is %v\n", time.Now())
+ }
+ }()
+ _, err = io.Copy(os.Stdout, conn) // res.Body)
+ log.Printf("Copy from conn: %v", err)
+}
+
+func serve(w http.ResponseWriter, r *http.Request) {
+ log.Printf("server got: %+v", r)
+ proto := r.Header.Get("Upgrade")
+ if proto != "tailscale" {
+ http.Error(w, "want tailscale", 400)
+ return
+ }
+
+ conn, brw, err := w.(http.Hijacker).Hijack()
+ if err != nil {
+ panic(err)
+ }
+ defer conn.Close()
+
+ io.WriteString(conn, "HTTP/1.0 101 Switch Protocols\r\nContent-Length: 1234\r\nConnection: upgrade\r\nUpgrade: tailscale\r\n\r\n")
+ /*w.Header().Set("Upgrade", "tailscale")
+ w.Header().Set("Content-Length", "1") // bug workaround
+ w.WriteHeader(101)
+ w.(http.Flusher).Flush()
+ */
+
+ defer log.Printf("ending serve")
+
+ io.WriteString(conn, "hi.\n")
+
+ bs := bufio.NewScanner(brw)
+ for bs.Scan() {
+ fmt.Fprintln(conn, strings.TrimSpace(bs.Text()))
+ }
+ log.Printf("Scan: %v", bs.Err())
+}