diff --git a/management/server/account.go b/management/server/account.go index 97dccfc4e..8801f2559 100644 --- a/management/server/account.go +++ b/management/server/account.go @@ -1531,7 +1531,7 @@ func domainIsUpToDate(domain string, domainCategory string, userAuth nbcontext.U } func (am *DefaultAccountManager) AllowSync(wgPubKey, metahash string) bool { - return am.loginFilter.allowLogin(wgPubKey, metahash) + return true } func (am *DefaultAccountManager) SyncAndMarkPeer(ctx context.Context, accountID string, peerPubKey string, meta nbpeer.PeerSystemMeta, realIP net.IP) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) { @@ -1571,7 +1571,6 @@ func (am *DefaultAccountManager) OnPeerDisconnected(ctx context.Context, account if err != nil { log.WithContext(ctx).Warnf("failed marking peer as disconnected %s %v", peerPubKey, err) } - am.loginFilter.removeLogin(peerPubKey) return nil } diff --git a/management/server/grpcserver.go b/management/server/grpcserver.go index fd794ecdd..89a1e95dc 100644 --- a/management/server/grpcserver.go +++ b/management/server/grpcserver.go @@ -141,11 +141,6 @@ func (s *GRPCServer) Sync(req *proto.EncryptedMessage, srv proto.ManagementServi if err != nil { return err } - peerMeta := extractPeerMeta(ctx, syncReq.GetMeta()) - metahashed := metaHash(peerMeta) - if !s.accountManager.AllowSync(peerKey.String(), metahashed) { - return mapError(ctx, internalStatus.ErrPeerAlreadyLoggedIn) - } // nolint:staticcheck ctx = context.WithValue(ctx, nbContext.PeerIDKey, peerKey.String()) @@ -178,7 +173,7 @@ func (s *GRPCServer) Sync(req *proto.EncryptedMessage, srv proto.ManagementServi log.WithContext(ctx).Tracef("peer system meta has to be provided on sync. Peer %s, remote addr %s", peerKey.String(), realIP) } - peer, netMap, postureChecks, err := s.accountManager.SyncAndMarkPeer(ctx, accountID, peerKey.String(), peerMeta, realIP) + peer, netMap, postureChecks, err := s.accountManager.SyncAndMarkPeer(ctx, accountID, peerKey.String(), extractPeerMeta(ctx, syncReq.GetMeta()), realIP) if err != nil { log.WithContext(ctx).Debugf("error while syncing peer %s: %v", peerKey.String(), err) return mapError(ctx, err) @@ -455,12 +450,6 @@ func (s *GRPCServer) Login(ctx context.Context, req *proto.EncryptedMessage) (*p return nil, err } - peerMeta := extractPeerMeta(ctx, loginReq.GetMeta()) - metahashed := metaHash(peerMeta) - if !s.accountManager.AllowSync(peerKey.String(), metahashed) { - return nil, mapError(ctx, internalStatus.ErrPeerAlreadyLoggedIn) - } - //nolint ctx = context.WithValue(ctx, nbContext.PeerIDKey, peerKey.String()) accountID, err := s.accountManager.GetAccountIDForPeerKey(ctx, peerKey.String()) @@ -491,7 +480,7 @@ func (s *GRPCServer) Login(ctx context.Context, req *proto.EncryptedMessage) (*p peer, netMap, postureChecks, err := s.accountManager.LoginPeer(ctx, types.PeerLogin{ WireGuardPubKey: peerKey.String(), SSHKey: string(sshKey), - Meta: peerMeta, + Meta: extractPeerMeta(ctx, loginReq.GetMeta()), UserID: userID, SetupKey: loginReq.GetSetupKey(), ConnectionIP: realIP, diff --git a/management/server/loginfilter.go b/management/server/loginfilter.go index b89338649..f28b999db 100644 --- a/management/server/loginfilter.go +++ b/management/server/loginfilter.go @@ -5,12 +5,16 @@ import ( "sync" "time" + log "github.com/sirupsen/logrus" + nbpeer "github.com/netbirdio/netbird/management/server/peer" ) const ( loginFilterSize = 100_000 // Size of the login filter map, making it large enough for a future filterTimeout = 5 * time.Minute // Duration to secure the previous login information in the filter + + loggingLimit = 100 ) type loginFilter struct { @@ -19,8 +23,9 @@ type loginFilter struct { } type metahash struct { - hash string - lastlogin time.Time + hashes map[string]struct{} + counter int + start time.Time } func newLoginFilter() *loginFilter { @@ -32,25 +37,35 @@ func newLoginFilter() *loginFilter { func (l *loginFilter) addLogin(wgPubKey, metaHash string) { l.mu.Lock() defer l.mu.Unlock() - l.logged[wgPubKey] = metahash{ - hash: metaHash, - lastlogin: time.Now(), + mh, ok := l.logged[wgPubKey] + if !ok { + mh = metahash{ + hashes: make(map[string]struct{}, loggingLimit), + start: time.Now(), + } + l.logged[wgPubKey] = mh + } + mh.hashes[metaHash] = struct{}{} + mh.counter++ + if mh.counter > loggingLimit && len(mh.hashes) > 1 { + log.WithFields(log.Fields{ + "wgPubKey": wgPubKey, + "number of different hashes": len(mh.hashes), + "elapsed time for number of attempts": time.Since(mh.start), + "number of syncs": mh.counter, + }).Info(mh.prepareHashes()) + + delete(l.logged, wgPubKey) } } -func (l *loginFilter) allowLogin(wgPubKey, metaHash string) bool { - l.mu.RLock() - defer l.mu.RUnlock() - if loggedMetaHash, ok := l.logged[wgPubKey]; ok { - return loggedMetaHash.hash == metaHash && time.Since(loggedMetaHash.lastlogin) < filterTimeout +func (m *metahash) prepareHashes() string { + var sb strings.Builder + for hash := range m.hashes { + sb.WriteString(hash) + sb.WriteString(", ") } - return true -} - -func (l *loginFilter) removeLogin(wgPubKey string) { - l.mu.Lock() - defer l.mu.Unlock() - delete(l.logged, wgPubKey) + return sb.String() } func metaHash(meta nbpeer.PeerSystemMeta) string {