From cd6d172cfadb9fe82b563ea66c779c3a4e57d4fc Mon Sep 17 00:00:00 2001 From: "Jonathan Leibiusky @xetorthio" Date: Mon, 19 Jun 2017 11:03:31 -0300 Subject: [PATCH] WIP --- api.go | 32 +---- {handlers => router/dns}/dns.go | 2 +- router/router.go | 117 ++++++++++++++++++ router/router_test.go | 49 ++++++++ handlers/reverseproxy.go => router/tcp/tcp.go | 4 +- handlers/tlsproxy.go => router/tls/tls.go | 2 +- 6 files changed, 173 insertions(+), 33 deletions(-) rename {handlers => router/dns}/dns.go (99%) create mode 100644 router/router.go create mode 100644 router/router_test.go rename handlers/reverseproxy.go => router/tcp/tcp.go (97%) rename handlers/tlsproxy.go => router/tls/tls.go (99%) diff --git a/api.go b/api.go index 313e2bf..eff0941 100644 --- a/api.go +++ b/api.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "log" "net/http" "os" @@ -9,7 +8,6 @@ import ( gh "github.com/gorilla/handlers" "github.com/gorilla/mux" - "github.com/miekg/dns" "github.com/play-with-docker/play-with-docker/config" "github.com/play-with-docker/play-with-docker/handlers" "github.com/play-with-docker/play-with-docker/templates" @@ -18,29 +16,11 @@ import ( ) func main() { - config.ParseFlags() handlers.Bootstrap() bypassCaptcha := len(os.Getenv("GOOGLE_RECAPTCHA_DISABLED")) > 0 - // Start the DNS server - dns.HandleFunc(".", handlers.DnsRequest) - udpDnsServer := &dns.Server{Addr: ":53", Net: "udp"} - go func() { - err := udpDnsServer.ListenAndServe() - if err != nil { - log.Fatal(err) - } - }() - tcpDnsServer := &dns.Server{Addr: ":53", Net: "tcp"} - go func() { - err := tcpDnsServer.ListenAndServe() - if err != nil { - log.Fatal(err) - } - }() - server := handlers.Broadcast.GetHandler() r := mux.NewRouter() @@ -55,10 +35,6 @@ func main() { corsHandler := gh.CORS(gh.AllowCredentials(), gh.AllowedHeaders([]string{"x-requested-with", "content-type"}), gh.AllowedOrigins([]string{"*"})) // Specific routes - r.Host(fmt.Sprintf("{subdomain:.*}pwd{node:%s}-{port:%s}.{tld:.*}", config.PWDHostnameRegex, config.PortRegex)).Handler(tcpHandler) - r.Host(fmt.Sprintf("{subdomain:.*}pwd{node:%s}.{tld:.*}", config.PWDHostnameRegex)).Handler(tcpHandler) - r.Host(fmt.Sprintf("pwd{alias:%s}-{session:%s}-{port:%s}.{tld:.*}", config.AliasnameRegex, config.AliasSessionRegex, config.PortRegex)).Handler(tcpHandler) - r.Host(fmt.Sprintf("pwd{alias:%s}-{session:%s}.{tld:.*}", config.AliasnameRegex, config.AliasSessionRegex)).Handler(tcpHandler) r.HandleFunc("/ping", handlers.Ping).Methods("GET") corsRouter.HandleFunc("/instances/images", handlers.GetInstanceImages).Methods("GET") corsRouter.HandleFunc("/sessions/{sessionId}", handlers.GetSession).Methods("GET") @@ -106,13 +82,11 @@ func main() { ReadHeaderTimeout: 5 * time.Second, } - go func() { - log.Println("Listening on port " + config.PortNumber) - log.Fatal(httpServer.ListenAndServe()) - }() - go handlers.ListenSSHProxy("0.0.0.0:1022") // Now listen for TLS connections that need to be proxied handlers.StartTLSProxy(config.SSLPortNumber) + + log.Println("Listening on port " + config.PortNumber) + log.Fatal(httpServer.ListenAndServe()) } diff --git a/handlers/dns.go b/router/dns/dns.go similarity index 99% rename from handlers/dns.go rename to router/dns/dns.go index e199296..2160e92 100644 --- a/handlers/dns.go +++ b/router/dns/dns.go @@ -1,4 +1,4 @@ -package handlers +package dns import ( "fmt" diff --git a/router/router.go b/router/router.go new file mode 100644 index 0000000..0bb0d8c --- /dev/null +++ b/router/router.go @@ -0,0 +1,117 @@ +package router + +import ( + "fmt" + "io" + "log" + "net" + + vhost "github.com/inconshreveable/go-vhost" +) + +type Director func(host string) (*net.TCPAddr, error) + +type proxyRouter struct { + director Director +} + +func (r *proxyRouter) Listen(laddr string) { + l, err := net.Listen("tcp", laddr) + defer l.Close() + if err != nil { + log.Fatal(err) + } + for { + conn, err := l.Accept() + if err != nil { + log.Println(err) + continue + } + go r.handleConnection(conn) + } +} + +func (r *proxyRouter) handleConnection(c net.Conn) { + defer c.Close() + // first try tls + vhostConn, err := vhost.TLS(c) + if err != nil { + log.Printf("Incoming TLS connection produced an error. Error: %s", err) + return + } + defer vhostConn.Close() + + host := vhostConn.ClientHelloMsg.ServerName + c.LocalAddr() + dstHost, err := r.director(fmt.Sprintf("%s:%d", host, 12)) + if err != nil { + log.Printf("Error directing request: %v\n", err) + return + } + + d, err := net.Dial("tcp", dstHost.String()) + if err != nil { + log.Printf("Error dialing backend %s: %v\n", dstHost.String(), err) + return + } + + errc := make(chan error, 2) + cp := func(dst io.Writer, src io.Reader) { + _, err := io.Copy(dst, src) + errc <- err + } + go cp(d, vhostConn) + go cp(vhostConn, d) + <-errc + /* + req, err := http.ReadRequest(bufio.NewReader(c)) + if err != nil { + log.Println(err) + return + } + + log.Println(req.Header) + */ +} + +func NewRouter(director Director) *proxyRouter { + return &proxyRouter{director: director} +} + +/* + // Start the DNS server + dns.HandleFunc(".", routerDns.DnsRequest) + udpDnsServer := &dns.Server{Addr: ":53", Net: "udp"} + go func() { + err := udpDnsServer.ListenAndServe() + if err != nil { + log.Fatal(err) + } + }() + tcpDnsServer := &dns.Server{Addr: ":53", Net: "tcp"} + go func() { + err := tcpDnsServer.ListenAndServe() + if err != nil { + log.Fatal(err) + } + }() + r := mux.NewRouter() + tcpHandler := handlers.NewTCPProxy() + r.Host(fmt.Sprintf("{subdomain:.*}pwd{node:%s}-{port:%s}.{tld:.*}", config.PWDHostnameRegex, config.PortRegex)).Handler(tcpHandler) + r.Host(fmt.Sprintf("{subdomain:.*}pwd{node:%s}.{tld:.*}", config.PWDHostnameRegex)).Handler(tcpHandler) + r.Host(fmt.Sprintf("pwd{alias:%s}-{session:%s}-{port:%s}.{tld:.*}", config.AliasnameRegex, config.AliasSessionRegex, config.PortRegex)).Handler(tcpHandler) + r.Host(fmt.Sprintf("pwd{alias:%s}-{session:%s}.{tld:.*}", config.AliasnameRegex, config.AliasSessionRegex)).Handler(tcpHandler) + r.HandleFunc("/ping", handlers.Ping).Methods("GET") + n := negroni.Classic() + n.UseHandler(r) + + httpServer := http.Server{ + Addr: "0.0.0.0:" + config.PortNumber, + Handler: n, + IdleTimeout: 30 * time.Second, + ReadHeaderTimeout: 5 * time.Second, + } + // Now listen for TLS connections that need to be proxied + tls.StartTLSProxy(config.SSLPortNumber) + http.ListenAndServe() +*/ diff --git a/router/router_test.go b/router/router_test.go new file mode 100644 index 0000000..192b524 --- /dev/null +++ b/router/router_test.go @@ -0,0 +1,49 @@ +package router + +import ( + "crypto/tls" + "fmt" + "io/ioutil" + "net" + "net/http" + "net/http/httptest" + "net/url" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestProxy_TLS(t *testing.T) { + tr := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + client := &http.Client{Transport: tr} + + const msg = "It works!" + + var receivedHost string + + ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprint(w, msg) + })) + defer ts.Close() + + r := NewRouter(func(host string) (*net.TCPAddr, error) { + receivedHost = host + u, _ := url.Parse(ts.URL) + a, _ := net.ResolveTCPAddr("tcp", u.Host) + return a, nil + }) + go r.Listen(":8080") + + req, err := http.NewRequest("GET", "https://localhost:8080", nil) + assert.Nil(t, err) + + resp, err := client.Do(req) + assert.Nil(t, err) + + body, err := ioutil.ReadAll(resp.Body) + assert.Nil(t, err) + assert.Equal(t, msg, string(body)) + assert.Equal(t, "localhost:8080", receivedHost) +} diff --git a/handlers/reverseproxy.go b/router/tcp/tcp.go similarity index 97% rename from handlers/reverseproxy.go rename to router/tcp/tcp.go index ed5a72e..80a1cca 100644 --- a/handlers/reverseproxy.go +++ b/router/tcp/tcp.go @@ -1,4 +1,4 @@ -package handlers +package tcp import ( "crypto/tls" @@ -9,8 +9,8 @@ import ( "net/http" "strings" + "github.com/franela/pwd.old/config" "github.com/gorilla/mux" - "github.com/play-with-docker/play-with-docker/config" ) func getTargetInfo(vars map[string]string, req *http.Request) (string, string) { diff --git a/handlers/tlsproxy.go b/router/tls/tls.go similarity index 99% rename from handlers/tlsproxy.go rename to router/tls/tls.go index 4a1ed03..a3c2ada 100644 --- a/handlers/tlsproxy.go +++ b/router/tls/tls.go @@ -1,4 +1,4 @@ -package handlers +package tls import ( "fmt"