From 94899ddaf95e79324de8bcdd70ca18ff834ec0be Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Thu, 31 Mar 2016 11:28:15 +0200 Subject: Separated routes branch --- entry.go | 13 +++++++++++++ route.go | 29 +---------------------------- server.go | 40 +++++++++++++++++++++++++++------------- server_test.go | 4 ++-- sni.go | 17 +++++++++++++++++ 5 files changed, 60 insertions(+), 43 deletions(-) create mode 100644 entry.go create mode 100644 sni.go diff --git a/entry.go b/entry.go new file mode 100644 index 0000000..de7c1e3 --- /dev/null +++ b/entry.go @@ -0,0 +1,13 @@ +package goxy + +// Entry holds routing settings +type Entry struct { + Host string // HostName + Upstream string // URL + Cert []byte // PEM + Key []byte // PEM +} + +func (e Entry) String() string { + return e.Host + " → " + e.Upstream +} diff --git a/route.go b/route.go index 544fd2f..92d318d 100644 --- a/route.go +++ b/route.go @@ -1,9 +1,7 @@ package goxy import ( - "crypto/tls" "encoding/json" - "errors" "fmt" "net/http" "os" @@ -12,14 +10,6 @@ import ( // Route defines a set of routes including correspondent TLS certificates type Route map[string]Entry -// GetCertificate returns certificate for SNI negotiation -func (r Route) GetCertificate(h *tls.ClientHelloInfo) (*tls.Certificate, error) { - if e, ok := r[h.ServerName]; ok && e.cert != nil { - return e.cert, nil - } - return nil, errors.New("no cert for " + h.ServerName) -} - // Save routes to persistent file func (r Route) Save(fname string) error { fd, err := os.Create(fname) @@ -42,23 +32,6 @@ func (r *Route) Load(fname string) error { func (r Route) ServeHTTP(w http.ResponseWriter, _ *http.Request) { for k, v := range r { - fmt.Fprintln(w, k, v) - } -} - -// Entry holds routing settings -type Entry struct { - Host string // HostName - Upstream string // URL - Cert []byte // PEM - Key []byte // PEM - cert *tls.Certificate // Parsed -} - -func (e Entry) String() string { - ret := e.Host + " → " + e.Upstream - if e.cert != nil { - ret += " with TLS" + fmt.Fprintln(w, k, "→", v) } - return ret } diff --git a/server.go b/server.go index e4afc91..a000cad 100644 --- a/server.go +++ b/server.go @@ -10,33 +10,47 @@ import ( type Server struct { DataFile string + SNI Route - http.Server + httpServer http.Server + tlsServer http.Server } func NewServer(dataFile string) (*Server, error) { - r := make(Route) - s := http.Server{TLSConfig: &tls.Config{GetCertificate: r.GetCertificate}} - server := &Server{Route: r, Server: s, DataFile: dataFile} + sni := make(SNI) + + server := &Server{ + DataFile: dataFile, + SNI: sni, + Route: make(Route), + httpServer: http.Server{ + Addr: ":http", + }, + tlsServer: http.Server{ + Addr: ":https", + TLSConfig: &tls.Config{ + GetCertificate: sni.GetCertificate, + }, + }, + } if dataFile != "" { server.Load(dataFile) } RegisterRPC(server) - http.Handle("/debug/route", r) + http.Handle("/debug/route", server.Route) return server, server.Update() } // Update routes from in-memory state func (s *Server) Update() error { - mux := http.NewServeMux() + httpMux := http.NewServeMux() for k, v := range s.Route { if v.Cert != nil && v.Key != nil { cert, err := tls.X509KeyPair(v.Cert, v.Key) if err != nil { return err } - v.cert = &cert - s.Route[k] = v + s.SNI[k] = &cert } up, err := url.Parse(v.Upstream) if err != nil { @@ -47,19 +61,19 @@ func (s *Server) Update() error { } switch up.Scheme { case "ws": - mux.Handle(v.Host, NewWebSocketProxy(up)) + httpMux.Handle(v.Host, NewWebSocketProxy(up)) default: - mux.Handle(v.Host, httputil.NewSingleHostReverseProxy(up)) + httpMux.Handle(v.Host, httputil.NewSingleHostReverseProxy(up)) } } - s.Server.Handler = mux + s.httpServer.Handler = httpMux return nil } func (s *Server) Start() error { errc := make(chan error) - go func() { errc <- s.ListenAndServe() }() - go func() { errc <- s.ListenAndServeTLS("", "") }() + go func() { errc <- s.httpServer.ListenAndServe() }() + go func() { errc <- s.tlsServer.ListenAndServeTLS("", "") }() go func() { errc <- http.ListenAndServe(":http-alt", nil) }() return <-errc } diff --git a/server_test.go b/server_test.go index ee72cb0..39a5826 100644 --- a/server_test.go +++ b/server_test.go @@ -73,7 +73,7 @@ func TestReverseProxy(t *testing.T) { t.Error(err) } - frontServer.Config.Handler = server.Handler + frontServer.Config.Handler = server.httpServer.Handler resp, err := http.Get(frontServer.URL) if err != nil { @@ -101,7 +101,7 @@ func TestReverseProxy(t *testing.T) { t.Error(err) } - frontServer.Config.Handler = server.Handler + frontServer.Config.Handler = server.httpServer.Handler ws, err := websocket.Dial("ws://"+frontURL.Host, "", "http://localhost") if err != nil { diff --git a/sni.go b/sni.go new file mode 100644 index 0000000..cc73fb3 --- /dev/null +++ b/sni.go @@ -0,0 +1,17 @@ +package goxy + +import ( + "crypto/tls" + "errors" +) + +// SNI holds Certificates for Server Name Identication +type SNI map[string]*tls.Certificate + +// GetCertificate returns certificate for SNI negotiation +func (s SNI) GetCertificate(h *tls.ClientHelloInfo) (*tls.Certificate, error) { + if crt, ok := s[h.ServerName]; ok { + return crt, nil + } + return nil, errors.New("no cert for " + h.ServerName) +} -- cgit v1.2.3