From 1170e2bd27a469a005a8a60aa4c3fe83c40eabfb Mon Sep 17 00:00:00 2001 From: Andreas Dewes Date: Wed, 18 Aug 2021 11:44:13 +0200 Subject: [PATCH] Add rate-limiting support for the public proxy. --- http/server.go | 4 ++- net/listener.go | 1 + net/time_window.go | 30 ------------------- proxy/forms.go | 2 ++ proxy/public_server.go | 21 +++++++++---- proxy/settings.go | 2 ++ .../dev/roles/public-proxy-1/001_default.yml | 3 ++ 7 files changed, 27 insertions(+), 36 deletions(-) diff --git a/http/server.go b/http/server.go index 6db5f45..7878857 100644 --- a/http/server.go +++ b/http/server.go @@ -186,8 +186,10 @@ func (s *HTTPServer) Start() error { if s.listener == nil { if listener, err := net.Listen("tcp", s.settings.BindAddress); err != nil { return err - } else { + } else if s.settings.TCPRateLimits != nil { s.listener = epsNet.MakeRateLimitedListener(listener, s.settings.TCPRateLimits) + } else { + s.listener = listener } } diff --git a/net/listener.go b/net/listener.go index 778dc0a..6b459fd 100644 --- a/net/listener.go +++ b/net/listener.go @@ -38,6 +38,7 @@ type RateLimitedListener struct { } func MakeRateLimitedListener(listener net.Listener, rateLimits []*RateLimit) *RateLimitedListener { + eps.Log.Tracef("Creating rate-limited network listener...") rates := make([]map[string]int64, len(rateLimits)) for i, _ := range rateLimits { rates[i] = make(map[string]int64) diff --git a/net/time_window.go b/net/time_window.go index affb0b4..b1e27bb 100644 --- a/net/time_window.go +++ b/net/time_window.go @@ -144,33 +144,3 @@ func (t *TimeWindow) Copy() TimeWindow { To: t.To, } } - -func (t *TimeWindow) IncreaseBy(n int64) { - from := time.Unix(t.From/1e9, t.From%1e9).UTC() - to := time.Unix(t.To/1e9, t.To%1e9).UTC() - switch t.Type { - case "second": - from = from.Add(time.Second * time.Duration(n)) - to = to.Add(time.Second * time.Duration(n)) - case "minute": - from = from.Add(time.Minute * time.Duration(n)) - to = to.Add(time.Minute * time.Duration(n)) - case "quarterHour": - from = from.Add(time.Minute * time.Duration(15*n)) - to = to.Add(time.Minute * time.Duration(15*n)) - case "hour": - from = from.Add(time.Hour * time.Duration(n)) - to = to.Add(time.Hour * time.Duration(n)) - case "day": - from = from.AddDate(0, 0, int(n)) - to = to.AddDate(0, 0, int(n)) - case "week": - from = from.AddDate(0, 0, 7*int(n)) - to = to.AddDate(0, 0, 7*int(n)) - case "month": - from = from.AddDate(0, int(n), 0) - to = to.AddDate(0, int(n), 0) - } - t.From = from.UnixNano() - t.To = to.UnixNano() -} diff --git a/proxy/forms.go b/proxy/forms.go index 8f7c0fe..11086a8 100644 --- a/proxy/forms.go +++ b/proxy/forms.go @@ -20,6 +20,7 @@ import ( "fmt" epsForms "github.com/iris-connect/eps/forms" "github.com/iris-connect/eps/jsonrpc" + "github.com/iris-connect/eps/net" "github.com/iris-connect/eps/tls" "github.com/kiprotect/go-helpers/forms" "regexp" @@ -184,6 +185,7 @@ var PublicSettingsForm = forms.Form{ forms.IsString{}, }, }, + net.TCPRateLimitsField, { Name: "tls_bind_address", Validators: []forms.Validator{ diff --git a/proxy/public_server.go b/proxy/public_server.go index 79c06f8..2530050 100644 --- a/proxy/public_server.go +++ b/proxy/public_server.go @@ -30,6 +30,7 @@ import ( epsForms "github.com/iris-connect/eps/forms" "github.com/iris-connect/eps/helpers" "github.com/iris-connect/eps/jsonrpc" + epsNet "github.com/iris-connect/eps/net" "github.com/iris-connect/eps/tls" "github.com/kiprotect/go-helpers/forms" "net" @@ -571,14 +572,24 @@ func (s *PublicServer) listenForInternalConnections() { } +func (s *PublicServer) makeListener(address string) (net.Listener, error) { + if listener, err := net.Listen("tcp", address); err != nil { + return nil, err + } else if s.settings.TCPRateLimits != nil { + return epsNet.MakeRateLimitedListener(listener, s.settings.TCPRateLimits), nil + } else { + return listener, nil + } + +} + func (s *PublicServer) Start() error { var err error - s.tlsListener, err = net.Listen("tcp", s.settings.TLSBindAddress) - if err != nil { - return err - } + + s.tlsListener, err = s.makeListener(s.settings.TLSBindAddress) go s.listenForTlsConnections() - s.internalListener, err = net.Listen("tcp", s.settings.InternalBindAddress) + + s.internalListener, err = s.makeListener(s.settings.InternalBindAddress) if err != nil { return err } diff --git a/proxy/settings.go b/proxy/settings.go index 43f757a..f4387f7 100644 --- a/proxy/settings.go +++ b/proxy/settings.go @@ -19,6 +19,7 @@ package proxy import ( "github.com/iris-connect/eps" "github.com/iris-connect/eps/jsonrpc" + "github.com/iris-connect/eps/net" "github.com/iris-connect/eps/tls" "time" ) @@ -47,6 +48,7 @@ type PublicServerSettings struct { InternalEndpoint string `json:"internal_endpoint"` JSONRPCClient *jsonrpc.JSONRPCClientSettings `json:"jsonrpc_client"` JSONRPCServer *jsonrpc.JSONRPCServerSettings `json:"jsonrpc_server` + TCPRateLimits []*net.RateLimit `json:"tcp_rate_limits"` } type PublicAnnouncement struct { diff --git a/settings/dev/roles/public-proxy-1/001_default.yml b/settings/dev/roles/public-proxy-1/001_default.yml index e02ba5a..286a118 100644 --- a/settings/dev/roles/public-proxy-1/001_default.yml +++ b/settings/dev/roles/public-proxy-1/001_default.yml @@ -1,5 +1,8 @@ public: name: public-proxy-1.ga + tcp_rate_limits: + - type: minute + limit: 10 datastore: type: redis settings: