configurable rate limit

This commit is contained in:
Pascal Fischer
2025-05-07 20:50:29 +02:00
parent 6ea7c665dc
commit 1bddfa5b7b
+19 -6
View File
@@ -5,6 +5,8 @@ import (
"fmt" "fmt"
"net" "net"
"net/netip" "net/netip"
"os"
"strconv"
"strings" "strings"
"sync" "sync"
"time" "time"
@@ -48,6 +50,9 @@ type GRPCServer struct {
ephemeralManager *EphemeralManager ephemeralManager *EphemeralManager
peerLocks sync.Map peerLocks sync.Map
authManager auth.Manager authManager auth.Manager
syncLimiter *rate.Limiter
loginLimiter *rate.Limiter
} }
// NewServer creates a new Management server // NewServer creates a new Management server
@@ -77,6 +82,16 @@ func NewServer(
} }
} }
loginRatePerS, err := strconv.Atoi(os.Getenv("NB_LOGIN_RATE_PER_M"))
if loginRatePerS == 0 || err != nil {
loginRatePerS = 300
}
syncRatePerS, err := strconv.Atoi(os.Getenv("NB_SYNC_RATE_PER_M"))
if syncRatePerS == 0 || err != nil {
syncRatePerS = 300
}
return &GRPCServer{ return &GRPCServer{
wgKey: key, wgKey: key,
// peerKey -> event channel // peerKey -> event channel
@@ -88,6 +103,8 @@ func NewServer(
authManager: authManager, authManager: authManager,
appMetrics: appMetrics, appMetrics: appMetrics,
ephemeralManager: ephemeralManager, ephemeralManager: ephemeralManager,
syncLimiter: rate.NewLimiter(rate.Every(time.Minute/time.Duration(syncRatePerS)), 1),
loginLimiter: rate.NewLimiter(rate.Every(time.Minute/time.Duration(loginRatePerS)), 1),
}, nil }, nil
} }
@@ -126,12 +143,10 @@ func getRealIP(ctx context.Context) net.IP {
return nil return nil
} }
var syncLimiter = rate.NewLimiter(rate.Every(time.Minute/300), 1)
// Sync validates the existence of a connecting peer, sends an initial state (all available for the connecting peers) and // Sync validates the existence of a connecting peer, sends an initial state (all available for the connecting peers) and
// notifies the connected peer of any updates (e.g. new peers under the same account) // notifies the connected peer of any updates (e.g. new peers under the same account)
func (s *GRPCServer) Sync(req *proto.EncryptedMessage, srv proto.ManagementService_SyncServer) error { func (s *GRPCServer) Sync(req *proto.EncryptedMessage, srv proto.ManagementService_SyncServer) error {
if !syncLimiter.Allow() { if !s.syncLimiter.Allow() {
return status.Errorf(codes.Internal, "temp rate limit reached") return status.Errorf(codes.Internal, "temp rate limit reached")
} }
@@ -418,14 +433,12 @@ func (s *GRPCServer) parseRequest(ctx context.Context, req *proto.EncryptedMessa
return peerKey, nil return peerKey, nil
} }
var loginLimiter = rate.NewLimiter(rate.Every(time.Minute/300), 1)
// Login endpoint first checks whether peer is registered under any account // Login endpoint first checks whether peer is registered under any account
// In case it is, the login is successful // In case it is, the login is successful
// In case it isn't, the endpoint checks whether setup key is provided within the request and tries to register a peer. // In case it isn't, the endpoint checks whether setup key is provided within the request and tries to register a peer.
// In case of the successful registration login is also successful // In case of the successful registration login is also successful
func (s *GRPCServer) Login(ctx context.Context, req *proto.EncryptedMessage) (*proto.EncryptedMessage, error) { func (s *GRPCServer) Login(ctx context.Context, req *proto.EncryptedMessage) (*proto.EncryptedMessage, error) {
if !loginLimiter.Allow() { if !s.loginLimiter.Allow() {
return nil, status.Errorf(codes.Internal, "temp rate limit reached") return nil, status.Errorf(codes.Internal, "temp rate limit reached")
} }