From 44dce553647f6118afd221a8eb32726f6cb834a2 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Tue, 21 Jul 2020 03:29:49 -0600 Subject: [PATCH] add http reverse proxy --- cmd/telebit/telebit.go | 9 ++++++--- routemux.go | 27 +++++++++++++++++++++++++-- telebit.go | 28 ++++++++++++++++++++++++++++ v1.go | 2 +- 4 files changed, 60 insertions(+), 6 deletions(-) diff --git a/cmd/telebit/telebit.go b/cmd/telebit/telebit.go index 6d88caa..b553a0d 100644 --- a/cmd/telebit/telebit.go +++ b/cmd/telebit/telebit.go @@ -388,9 +388,9 @@ func muxAll( *apiHostname = os.Getenv("API_HOSTNAME") } if "" != *apiHostname { - listener := httpshim.NewListener() + apiListener := httpshim.NewListener() go func() { - httpsrv.Serve(listener) + httpsrv.Serve(apiListener) }() fmt.Printf("Will respond to Websocket and API requests to %q\n", *apiHostname) mux.HandleTLS(*apiHostname, acme, mux, "[Terminate TLS & Recurse] for "+*apiHostname) @@ -398,7 +398,7 @@ func muxAll( if dbg.Debug { fmt.Printf("[debug] Accepting API or WebSocket client %q\n", *apiHostname) } - listener.Feed(client) + apiListener.Feed(client) if dbg.Debug { fmt.Printf("[debug] done with %q client\n", *apiHostname) } @@ -426,6 +426,9 @@ func muxAll( //}, acme, mux, "[Terminate TLS & Recurse]") for _, fwd := range forwards { //mux.ForwardTCP("*", "localhost:"+fwd.port, 120*time.Second) + if "https" == fwd.scheme { + mux.ReverseProxyHTTP(fwd.pattern, "localhost:"+fwd.port, 120*time.Second, "[Servername Reverse Proxy]") + } mux.ForwardTCP(fwd.pattern, "localhost:"+fwd.port, 120*time.Second, "[Servername Forward]") } diff --git a/routemux.go b/routemux.go index 8d8ebb9..2c3cbc2 100644 --- a/routemux.go +++ b/routemux.go @@ -67,7 +67,13 @@ func (m *RouteMux) Serve(client net.Conn) error { if "" == connServername { wconn.SetServername(servername) } else { - fmt.Printf("Has servername: current=%s new=%s\n", connServername, servername) + if connServername != servername { + fmt.Fprintf( + os.Stderr, + "[mux] Mismatch Servername: (current) %s != (new) %s\n", + connServername, servername, + ) + } wconn.SetServername(servername) //panic(errors.New("Can't SetServername() over existing servername")) } @@ -152,6 +158,16 @@ func (m *RouteMux) ForwardTCP(servername string, target string, timeout time.Dur return nil } +func (m *RouteMux) ReverseProxyHTTP(servername string, target string, timeout time.Duration, comment ...string) error { + m.routes = append(m.routes, meta{ + addr: servername, + terminate: false, + handler: NewReverseProxier(target, timeout), + comment: append(comment, "")[0], + }) + return nil +} + // HandleTCP creates and returns a connection to a local handler target. func (m *RouteMux) HandleTCP(servername string, handler Handler, comment ...string) error { // TODO check servername @@ -193,7 +209,14 @@ func (m *RouteMux) HandleTLS(servername string, acme *ACME, next Handler, commen //NewTerminator(acme, handler)(client) //return handler.Serve(client) - return next.Serve(TerminateTLS(wconn, acme)) + go func() { + if err := next.Serve(TerminateTLS(wconn, acme)); nil != err { + fmt.Fprintf(os.Stderr, "error Terminating TLS: %s\n", err) + } + }() + // at this point, we've handled it + // TODO could we move termination further in? + return nil }), comment: append(comment, "")[0], }) diff --git a/telebit.go b/telebit.go index 6183925..b928252 100644 --- a/telebit.go +++ b/telebit.go @@ -10,10 +10,14 @@ import ( "io/ioutil" "net" "net/http" + "net/http/httputil" + "net/url" "os" "strings" "time" + httpshim "git.rootprojects.org/root/telebit/tunnel" + "github.com/caddyserver/certmagic" "github.com/go-acme/lego/v3/challenge" "github.com/go-acme/lego/v3/challenge/dns01" @@ -64,6 +68,29 @@ func NewForwarder(target string, timeout time.Duration) HandlerFunc { } } +func NewReverseProxier(target string, timeout time.Duration) HandlerFunc { + // TODO accept listener? + proxyListener := httpshim.NewListener() + myURL, err := url.Parse("http://" + target) + if nil != err { + panic(err) + } + // TODO headers + proxyHandler := httputil.NewSingleHostReverseProxy(myURL) + proxyServer := &http.Server{ + Handler: proxyHandler, + } + go func() { + proxyServer.Serve(proxyListener) + }() + + return func(client net.Conn) error { + // TODO Peek to see if this is HTTP + proxyListener.Feed(client) + return nil + } +} + // Forward port-forwards a relay (websocket) client to a target (local) server func Forward(client net.Conn, target net.Conn, timeout time.Duration) error { @@ -234,6 +261,7 @@ func TerminateTLS(client net.Conn, acme *ACME) net.Conn { acmecert = magic } + // TODO NextProtos: []string{ "h2", "http/1.1" } tlsConfig := &tls.Config{ GetCertificate: func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) { return acmecert.GetCertificate(hello) diff --git a/v1.go b/v1.go index 9ace3b4..28dcc95 100644 --- a/v1.go +++ b/v1.go @@ -196,7 +196,7 @@ func (p *Parser) unpackV1Header(b []byte, n int) ([]byte, error) { } if "end" == service { - fmt.Println("[debug] unpackV1 end") + fmt.Printf("[codec] [v1] unpack control message: 'end'\n") p.handler.RouteBytes(p.state.srcAddr, p.state.dstAddr, []byte{}) } return b, nil