From ae93cfbf8cdc9cd055c59cddb4f90f436cd2e405 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Mon, 4 Apr 2016 14:26:05 +0200 Subject: Tweak WS Proxy --- ws.go | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/ws.go b/ws.go index b54c2ce..b1cb1a3 100644 --- a/ws.go +++ b/ws.go @@ -5,7 +5,6 @@ import ( "net" "net/http" "net/url" - "path" ) type WebSocketProxy struct { @@ -13,33 +12,32 @@ type WebSocketProxy struct { } func (p *WebSocketProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) { - hj, ok := w.(http.Hijacker) - if !ok { - http.Error(w, "Not a hijacker", http.StatusInternalServerError) - return - } - - conn, _, err := hj.Hijack() + p.Director(r) + d, err := net.Dial("tcp", r.URL.Host) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } - defer conn.Close() - - p.Director(r) + defer d.Close() - d, err := net.Dial("tcp", r.URL.Host) + // pass first request to upstream + err = r.Write(d) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } - defer d.Close() - err = r.Write(d) + hj, ok := w.(http.Hijacker) + if !ok { + http.Error(w, "Not a hijacker", http.StatusInternalServerError) + return + } + conn, _, err := hj.Hijack() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } + defer conn.Close() errc := make(chan error, 2) cp := func(dst io.Writer, src io.Reader) { @@ -55,7 +53,6 @@ func NewWebSocketProxy(target *url.URL) *WebSocketProxy { director := func(req *http.Request) { req.URL.Scheme = target.Scheme req.URL.Host = target.Host - req.URL.Path = path.Join(target.Path, req.URL.Path) } return &WebSocketProxy{Director: director} } -- cgit v1.2.3 From 1ef50ddd7f6ae07c68fec7c87c7052e4004179ea Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Mon, 4 Apr 2016 14:35:55 +0200 Subject: Add Certs debug overview --- server.go | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/server.go b/server.go index 3437590..d31c1d8 100644 --- a/server.go +++ b/server.go @@ -12,40 +12,46 @@ import ( type Server struct { DataFile string Routes - SNI + Certs wwwServer http.Server tlsServer http.Server rpcServer http.Server } -// SNI holds certificates -type SNI map[string]*tls.Certificate +// Certs holds certificates +type Certs map[string]*tls.Certificate // GetCertificate returns certificate for SNI negotiation -func (s SNI) getCertificate(h *tls.ClientHelloInfo) (*tls.Certificate, error) { - if v, ok := s[h.ServerName]; ok { +func (c Certs) getCertificate(h *tls.ClientHelloInfo) (*tls.Certificate, error) { + if v, ok := c[h.ServerName]; ok { return v, nil } return nil, fmt.Errorf("no cert for %q", h.ServerName) } -func (s SNI) addCertificate(cert, key []byte) error { - c, err := tls.X509KeyPair(cert, key) +func (c Certs) ServeHTTP(w http.ResponseWriter, _ *http.Request) { + for k, v := range c { + fmt.Fprintf(w, "%v: valid untill %v\n", k, v.Leaf.NotAfter) + } +} + +func (c Certs) addCertificate(cert, key []byte) error { + crt, err := tls.X509KeyPair(cert, key) if err != nil { return err } - c.Leaf, err = x509.ParseCertificate(c.Certificate[0]) + crt.Leaf, err = x509.ParseCertificate(crt.Certificate[0]) if err != nil { return err } - if cn := c.Leaf.Subject.CommonName; cn != "" { - s[cn] = &c + if cn := crt.Leaf.Subject.CommonName; cn != "" { + c[cn] = &crt } - for _, name := range c.Leaf.DNSNames { - s[name] = &c + for _, name := range crt.Leaf.DNSNames { + c[name] = &crt } - for _, ip := range c.Leaf.IPAddresses { - s[ip.String()] = &c + for _, ip := range crt.Leaf.IPAddresses { + c[ip.String()] = &crt } return nil } @@ -57,7 +63,7 @@ func NewServer(dataFile, listenWWW, listenTLS, listenRPC string) (*Server, error server := &Server{ DataFile: dataFile, Routes: make(Routes), - SNI: make(SNI), + Certs: make(Certs), wwwServer: http.Server{Addr: listenWWW}, tlsServer: http.Server{Addr: listenTLS}, rpcServer: http.Server{Addr: listenRPC}, @@ -69,7 +75,8 @@ func NewServer(dataFile, listenWWW, listenTLS, listenRPC string) (*Server, error server.Load(dataFile) } registerRPC(server) - http.Handle("/debug/route", server) + http.Handle("/debug/routes", server.Routes) + http.Handle("/debug/certs", server.Certs) return server, server.UpdateMux() } @@ -98,7 +105,7 @@ func (s *Server) UpdateMux() error { case "http", "": wwwMux.Handle(host, NewReverseProxy(upstream)) case "https": - err := s.SNI.addCertificate(route.Cert, route.Key) + err := s.Certs.addCertificate(route.Cert, route.Key) if err != nil { return err } @@ -107,7 +114,7 @@ func (s *Server) UpdateMux() error { case "ws": wwwMux.Handle(host, NewWebSocketProxy(upstream)) case "wss": - err := s.SNI.addCertificate(route.Cert, route.Key) + err := s.Certs.addCertificate(route.Cert, route.Key) if err != nil { return err } -- cgit v1.2.3 From a09a47d1f8812e837080d5af9461113109555b23 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Mon, 4 Apr 2016 14:47:27 +0200 Subject: Split files --- cert.go | 46 ++++++++++++++++++++++++++++++++++++++++++++++ route.go | 18 +++--------------- rpc.go | 12 ++++++++++++ server.go | 40 ---------------------------------------- ws.go | 16 ++++++++-------- 5 files changed, 69 insertions(+), 63 deletions(-) create mode 100644 cert.go diff --git a/cert.go b/cert.go new file mode 100644 index 0000000..38c534d --- /dev/null +++ b/cert.go @@ -0,0 +1,46 @@ +package goxy + +import ( + "crypto/tls" + "crypto/x509" + "fmt" + "net/http" +) + +// Certs holds certificates +type Certs map[string]*tls.Certificate + +// GetCertificate returns certificate for SNI negotiation +func (c Certs) getCertificate(h *tls.ClientHelloInfo) (*tls.Certificate, error) { + if v, ok := c[h.ServerName]; ok { + return v, nil + } + return nil, fmt.Errorf("no cert for %q", h.ServerName) +} + +func (c Certs) addCertificate(cert, key []byte) error { + crt, err := tls.X509KeyPair(cert, key) + if err != nil { + return err + } + crt.Leaf, err = x509.ParseCertificate(crt.Certificate[0]) + if err != nil { + return err + } + if cn := crt.Leaf.Subject.CommonName; cn != "" { + c[cn] = &crt + } + for _, name := range crt.Leaf.DNSNames { + c[name] = &crt + } + for _, ip := range crt.Leaf.IPAddresses { + c[ip.String()] = &crt + } + return nil +} + +func (c Certs) ServeHTTP(w http.ResponseWriter, _ *http.Request) { + for k, v := range c { + fmt.Fprintf(w, "%v: valid untill %v\n", k, v.Leaf.NotAfter) + } +} diff --git a/route.go b/route.go index e4de1de..26754ac 100644 --- a/route.go +++ b/route.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "net/http" - "net/url" "os" ) @@ -20,12 +19,6 @@ func (r Route) String() string { return fmt.Sprintf("%v → %v", r.Host, r.Upstream) } -func (r Routes) ServeHTTP(w http.ResponseWriter, _ *http.Request) { - for _, v := range r { - fmt.Fprintln(w, v) - } -} - func (r Routes) Save(fname string) error { fd, err := os.Create(fname) if err != nil { @@ -44,13 +37,8 @@ func (r *Routes) Load(fname string) error { return json.NewDecoder(fd).Decode(r) } -func Slug(host string) (string, bool, error) { - h, err := url.Parse(host) - if err != nil { - return "", false, err - } - if h.Path == "" { - h.Path = "/" +func (r Routes) ServeHTTP(w http.ResponseWriter, _ *http.Request) { + for _, v := range r { + fmt.Fprintln(w, v) } - return h.Host + h.Path, h.Scheme == "https", nil } diff --git a/rpc.go b/rpc.go index 1f3c877..10c311f 100644 --- a/rpc.go +++ b/rpc.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "net/rpc" + "net/url" ) var ( @@ -65,3 +66,14 @@ func (s GoXY) List(_ struct{}, ret *[]string) error { } return nil } + +func Slug(host string) (string, bool, error) { + h, err := url.Parse(host) + if err != nil { + return "", false, err + } + if h.Path == "" { + h.Path = "/" + } + return h.Host + h.Path, h.Scheme == "https", nil +} diff --git a/server.go b/server.go index d31c1d8..d47ba52 100644 --- a/server.go +++ b/server.go @@ -2,8 +2,6 @@ package goxy import ( "crypto/tls" - "crypto/x509" - "fmt" "net/http" "net/http/httputil" "net/url" @@ -18,44 +16,6 @@ type Server struct { rpcServer http.Server } -// Certs holds certificates -type Certs map[string]*tls.Certificate - -// GetCertificate returns certificate for SNI negotiation -func (c Certs) getCertificate(h *tls.ClientHelloInfo) (*tls.Certificate, error) { - if v, ok := c[h.ServerName]; ok { - return v, nil - } - return nil, fmt.Errorf("no cert for %q", h.ServerName) -} - -func (c Certs) ServeHTTP(w http.ResponseWriter, _ *http.Request) { - for k, v := range c { - fmt.Fprintf(w, "%v: valid untill %v\n", k, v.Leaf.NotAfter) - } -} - -func (c Certs) addCertificate(cert, key []byte) error { - crt, err := tls.X509KeyPair(cert, key) - if err != nil { - return err - } - crt.Leaf, err = x509.ParseCertificate(crt.Certificate[0]) - if err != nil { - return err - } - if cn := crt.Leaf.Subject.CommonName; cn != "" { - c[cn] = &crt - } - for _, name := range crt.Leaf.DNSNames { - c[name] = &crt - } - for _, ip := range crt.Leaf.IPAddresses { - c[ip.String()] = &crt - } - return nil -} - func NewServer(dataFile, listenWWW, listenTLS, listenRPC string) (*Server, error) { if listenRPC == "" { listenRPC = RPCPort diff --git a/ws.go b/ws.go index b1cb1a3..b07a17b 100644 --- a/ws.go +++ b/ws.go @@ -11,6 +11,14 @@ type WebSocketProxy struct { Director func(*http.Request) } +func NewWebSocketProxy(target *url.URL) *WebSocketProxy { + director := func(req *http.Request) { + req.URL.Scheme = target.Scheme + req.URL.Host = target.Host + } + return &WebSocketProxy{Director: director} +} + func (p *WebSocketProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) { p.Director(r) d, err := net.Dial("tcp", r.URL.Host) @@ -48,11 +56,3 @@ func (p *WebSocketProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) { go cp(conn, d) <-errc } - -func NewWebSocketProxy(target *url.URL) *WebSocketProxy { - director := func(req *http.Request) { - req.URL.Scheme = target.Scheme - req.URL.Host = target.Host - } - return &WebSocketProxy{Director: director} -} -- cgit v1.2.3