diff --git a/.vscode/launch.json b/.vscode/launch.json index f837e0b..35ebee9 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -13,7 +13,7 @@ "program": "${workspaceFolder}/cmd/${workspaceFolderBasename}", "args": [ "--addr=localhost:7788", - "--tls=true" + // "--tls=true" ] } ] diff --git a/go.mod b/go.mod index 35a5870..1306d14 100644 --- a/go.mod +++ b/go.mod @@ -1,10 +1,23 @@ module go_web_server -require gopkg.in/natefinch/lumberjack.v2 v2.0.0 +require ( + github.com/prometheus/client_golang v1.17.0 + gopkg.in/natefinch/lumberjack.v2 v2.0.0 + gopkg.in/yaml.v2 v2.4.0 +) require ( github.com/BurntSushi/toml v1.2.1 // indirect - gopkg.in/yaml.v2 v2.4.0 + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect + github.com/prometheus/common v0.44.0 // indirect + github.com/prometheus/procfs v0.11.1 // indirect + golang.org/x/sys v0.11.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect ) -go 1.16 +go 1.21 diff --git a/go.sum b/go.sum index e9e2fee..5a6f352 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,46 @@ github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= +github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= +github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM= +github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= +github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= +github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= +github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= diff --git a/internal/server/connectHandlerFunc.go b/internal/server/connectHandlerFunc.go index 2d1d45a..a06f383 100644 --- a/internal/server/connectHandlerFunc.go +++ b/internal/server/connectHandlerFunc.go @@ -8,6 +8,7 @@ import ( "math/rand" "net" "net/http" + "strings" "sync" ) @@ -18,8 +19,9 @@ func dialContextCheckACL(network, hostPort string) (net.Conn, error) { } func connect(w http.ResponseWriter, r *http.Request) { + clientAddr := strings.Split(r.RemoteAddr, ":")[0] if r.Header.Get("proxy-authorization") != config.Instance.BasicAuth { - log.Println("wrong basic auth from", r.RemoteAddr) + log.Println("wrong basic auth from", clientAddr) http.Error(w, "InternalServerError", http.StatusInternalServerError) return } @@ -46,10 +48,13 @@ func connect(w http.ResponseWriter, r *http.Request) { return } defer targetConn.Close() + // 使用prometheus埋点统计 tag=hostPort的次数 + ProxyAccess.WithLabelValues(clientAddr, hostPort).Inc() + ProxyAccess.WithLabelValues("all", "all").Inc() switch r.ProtoMajor { case 1: // http1: hijack the whole flow - _, err := serveHijack(w, targetConn) + _, err := serveHijack(w, targetConn, clientAddr, hostPort) if err != nil { log.Println(err, r.RemoteAddr) } @@ -67,7 +72,7 @@ func connect(w http.ResponseWriter, r *http.Request) { w.Header().Add("Server", "go_web_server") } wFlusher.Flush() - err := dualStream(targetConn, r.Body, w) + err := dualStream(targetConn, r.Body, w, clientAddr, hostPort) if err != nil { log.Println(err, r.RemoteAddr) } @@ -79,7 +84,7 @@ func connect(w http.ResponseWriter, r *http.Request) { // Hijacks the connection from ResponseWriter, writes the response and proxies data between targetConn // and hijacked connection. -func serveHijack(w http.ResponseWriter, targetConn net.Conn) (int, error) { +func serveHijack(w http.ResponseWriter, targetConn net.Conn, clientAddr string, hostPort string) (int, error) { hijacker, ok := w.(http.Hijacker) if !ok { return http.StatusInternalServerError, errors.New("ResponseWriter does not implement Hijacker") @@ -117,20 +122,22 @@ func serveHijack(w http.ResponseWriter, targetConn net.Conn) (int, error) { return http.StatusInternalServerError, errors.New("failed to send response to client: " + err.Error()) } - return 0, dualStream(targetConn, clientConn, clientConn) + return 0, dualStream(targetConn, clientConn, clientConn, clientAddr, hostPort) } var bufferPool = &sync.Pool{New: func() interface{} { return make([]byte, 32*1024) }} -func dualStream(target net.Conn, clientReader io.ReadCloser, clientWriter io.Writer) error { +func dualStream(target net.Conn, clientReader io.ReadCloser, clientWriter io.Writer, clientAddr string, hostPort string) error { stream := func(w io.Writer, r io.Reader) error { // copy bytes from r to w buf := bufferPool.Get().([]byte) defer bufferPool.Put(buf) buf = buf[0:cap(buf)] - _, _err := flushingIoCopy(w, r, buf) + nw, _err := flushingIoCopy(w, r, buf) + ProxyTraffic.WithLabelValues(clientAddr, hostPort).Add(float64(nw)) + ProxyTraffic.WithLabelValues("all", "all").Add(float64(nw)) if closeWriter, ok := w.(interface { CloseWrite() error }); ok { diff --git a/internal/server/server.go b/internal/server/server.go index c2da378..9d61d51 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -6,6 +6,10 @@ import ( "log" "net/http" "time" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/prometheus/client_golang/prometheus/promhttp" ) var ssl_cert *tls.Certificate = nil @@ -13,8 +17,24 @@ var ssl_last_cert_update time.Time = time.Now() const ssl_cert_update_interval = 5 * time.Hour +var ( + // HttpRequst = promauto.NewCounterVec(prometheus.CounterOpts{ + // Name: "req_from_out", + // Help: "Number of HTTP requests received", + // }, []string{"referer", "path"}) + ProxyAccess = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "proxy_access", + Help: "num proxy_access", + }, []string{"client", "target"}) + ProxyTraffic = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "proxy_traffic", + Help: "num proxy_traffic", + }, []string{"client", "target"}) +) + func Serve() error { http.HandleFunc("/ip", writeIp) + http.Handle("/metrics", promhttp.Handler()) http.HandleFunc("/", fileHandlerFunc()) instance := config.Instance