diff --git a/metrics/service.go b/metrics/service.go index 66a05c2..e506192 100644 --- a/metrics/service.go +++ b/metrics/service.go @@ -20,13 +20,14 @@ package metrics import ( "time" - "github.com/mysteriumnetwork/openvpn-forwarder/proxy" "github.com/prometheus/client_golang/prometheus" + + "github.com/mysteriumnetwork/openvpn-forwarder/proxy" ) type service struct { proxyRequestDuration *prometheus.HistogramVec - proxyNumberOfLiveConnecions *prometheus.GaugeVec + proxyNumberOfLiveConnections *prometheus.GaugeVec proxyNumberOfProcessedConnections *prometheus.CounterVec } @@ -35,7 +36,7 @@ func NewMetricsService() (*service, error) { proxyRequestDuration := prometheus.NewHistogramVec(prometheus.HistogramOpts{ Name: "proxy_request_duration", Help: "Proxy request duration in seconds", - }, []string{"request_type"}) + }, []string{"request_type", "hostname"}) if err := prometheus.Register(proxyRequestDuration); err != nil { return nil, err @@ -44,7 +45,7 @@ func NewMetricsService() (*service, error) { proxyNumberOfLiveConnections := prometheus.NewGaugeVec(prometheus.GaugeOpts{ Name: "proxy_number_of_live_connections", Help: "Number of currently live connections", - }, []string{"request_type"}) + }, []string{"request_type", "hostname"}) if err := prometheus.Register(proxyNumberOfLiveConnections); err != nil { return nil, err @@ -53,7 +54,7 @@ func NewMetricsService() (*service, error) { proxyNumberOfProcessedConnections := prometheus.NewCounterVec(prometheus.CounterOpts{ Name: "proxy_number_of_processed_connections", Help: "Number of incoming connections which were successfully assigned and processed", - }, []string{"request_type"}) + }, []string{"request_type", "hostname"}) if err := prometheus.Register(proxyNumberOfProcessedConnections); err != nil { return nil, err @@ -61,7 +62,7 @@ func NewMetricsService() (*service, error) { return &service{ proxyRequestDuration: proxyRequestDuration, - proxyNumberOfLiveConnecions: proxyNumberOfLiveConnections, + proxyNumberOfLiveConnections: proxyNumberOfLiveConnections, proxyNumberOfProcessedConnections: proxyNumberOfProcessedConnections, }, nil } @@ -70,22 +71,28 @@ func (s *service) ProxyHandlerMiddleware(next func(c *proxy.Context)) func(c *pr return func(c *proxy.Context) { startTime := time.Now() - s.proxyNumberOfLiveConnecions.With(prometheus.Labels{ - "request_type": c.RequestType(), - }).Inc() + go func() { + s.proxyNumberOfLiveConnections.With(prometheus.Labels{ + "request_type": c.RequestType(), + "hostname": c.WaitHostname(), + }).Inc() + }() next(c) - s.proxyNumberOfLiveConnecions.With(prometheus.Labels{ + s.proxyNumberOfLiveConnections.With(prometheus.Labels{ "request_type": c.RequestType(), + "hostname": c.Hostname(), }).Dec() s.proxyRequestDuration.With(prometheus.Labels{ "request_type": c.RequestType(), + "hostname": c.Hostname(), }).Observe(time.Since(startTime).Seconds()) s.proxyNumberOfProcessedConnections.With(prometheus.Labels{ "request_type": c.RequestType(), + "hostname": c.Hostname(), }).Inc() } } diff --git a/proxy/conn.go b/proxy/conn.go index e0789a0..caaa73c 100644 --- a/proxy/conn.go +++ b/proxy/conn.go @@ -27,7 +27,7 @@ var ( proxyRequestData = prometheus.NewCounterVec(prometheus.CounterOpts{ Name: "proxy_request_data", Help: "Proxy request data in bytes", - }, []string{"request_type", "direction"}) + }, []string{"request_type", "direction", "hostname"}) proxyNumberOfIncommingConnections = prometheus.NewCounterVec(prometheus.CounterOpts{ Name: "proxy_number_of_incomming_connections", @@ -60,9 +60,12 @@ type Conn struct { func (c Conn) Read(b []byte) (n int, err error) { count, err := c.Conn.Read(b) - proxyRequestData.MustCurryWith(prometheus.Labels{ - "request_type": c.Context.RequestType(), - }).WithLabelValues("received").Add(float64(count)) + go func() { + proxyRequestData.MustCurryWith(prometheus.Labels{ + "request_type": c.Context.RequestType(), + "hostname": c.Context.WaitHostname(), + }).WithLabelValues("received").Add(float64(count)) + }() return count, err } @@ -71,9 +74,12 @@ func (c Conn) Read(b []byte) (n int, err error) { func (c Conn) Write(b []byte) (n int, err error) { count, err := c.Conn.Write(b) - proxyRequestData.MustCurryWith(prometheus.Labels{ - "request_type": c.Context.RequestType(), - }).WithLabelValues("sent").Add(float64(count)) + go func() { + proxyRequestData.MustCurryWith(prometheus.Labels{ + "request_type": c.Context.RequestType(), + "hostname": c.Context.WaitHostname(), + }).WithLabelValues("sent").Add(float64(count)) + }() return count, err } diff --git a/proxy/context.go b/proxy/context.go index 0364ed2..3c2f06e 100644 --- a/proxy/context.go +++ b/proxy/context.go @@ -19,6 +19,8 @@ package proxy import ( "net" + "regexp" + "strings" ) // Context is the Proxy context, contains useful information about every request. @@ -27,11 +29,33 @@ type Context struct { conn net.Conn connOriginalDst *net.TCPAddr + hostnameSet chan struct{} destinationHost string destinationAddress string } // RequestType HTTP or HTTPS. -func (c Context) RequestType() string { +func (c *Context) RequestType() string { return c.scheme } + +func (c *Context) setHost(host string) { + c.destinationHost = host + close(c.hostnameSet) +} + +// WaitHostname waits for hostname to be set and returns it. +func (c *Context) WaitHostname() string { + <-c.hostnameSet + + hostname := hostname.FindString(strings.ToLower(c.destinationHost)) + + return hostname +} + +// Hostname returns hostname. +func (c *Context) Hostname() string { + return hostname.FindString(strings.ToLower(c.destinationHost)) +} + +var hostname = regexp.MustCompile(`\w+\.\w+$`) diff --git a/proxy/server.go b/proxy/server.go index a9c7dee..d63a245 100644 --- a/proxy/server.go +++ b/proxy/server.go @@ -104,7 +104,7 @@ func (s *proxyServer) handler(l net.Listener, f func(c *Context), scheme string) for { conn, err := l.Accept() - c := Context{} + c := Context{hostnameSet: make(chan struct{})} c.scheme = scheme c.conn = NewConn(conn, &c) @@ -166,7 +166,7 @@ func (s *proxyServer) serveHTTP(c *Context) { return } - c.destinationHost = req.Host + c.setHost(req.Host) c.destinationAddress = s.authorityAddr("http", c.destinationHost) s.logAccess("HTTP request", c) @@ -227,10 +227,10 @@ func (s *proxyServer) serveTLS(c *Context) { return } - c.destinationHost = tlsConn.Host() + ":" + port + c.setHost(tlsConn.Host() + ":" + port) c.destinationAddress = s.authorityAddr("https", c.destinationHost) } else if c.connOriginalDst != nil { - c.destinationHost = "" + c.setHost("") c.destinationAddress = c.connOriginalDst.String() s.logWarn("Cannon parse SNI in TLS request", c) } else {