fix: resolve nethernet connection, ban deadlock, and nil RemoteAddr crashes
This commit is contained in:
+52
-23
@@ -21,7 +21,7 @@ type BanEntry struct {
|
||||
|
||||
// BanManager handles player bans.
|
||||
type BanManager struct {
|
||||
mu sync.Mutex
|
||||
mu sync.RWMutex
|
||||
bans map[string]BanEntry
|
||||
path string
|
||||
}
|
||||
@@ -54,14 +54,15 @@ func (bm *BanManager) Load() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Save saves the banned players to bans.json.
|
||||
func (bm *BanManager) Save() error {
|
||||
bm.mu.Lock()
|
||||
defer bm.mu.Unlock()
|
||||
// save writes bans to disk. Must be called WITHOUT holding bm.mu.
|
||||
func (bm *BanManager) save() error {
|
||||
bm.mu.RLock()
|
||||
var list []BanEntry
|
||||
for _, entry := range bm.bans {
|
||||
list = append(list, entry)
|
||||
}
|
||||
bm.mu.RUnlock()
|
||||
|
||||
data, err := json.MarshalIndent(list, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -69,23 +70,30 @@ func (bm *BanManager) Save() error {
|
||||
return os.WriteFile(bm.path, data, 0644)
|
||||
}
|
||||
|
||||
// Save saves the banned players to bans.json.
|
||||
func (bm *BanManager) Save() error {
|
||||
return bm.save()
|
||||
}
|
||||
|
||||
// Ban bans a player by name, with optional XUID, UUID, and IP.
|
||||
// IP bans are intentionally NOT stored to prevent blocking all
|
||||
// players on the same local network (LAN/nethernet).
|
||||
func (bm *BanManager) Ban(name string, duration time.Duration, reason string, xuid string, uuidStr string, ip string) {
|
||||
bm.mu.Lock()
|
||||
entry := BanEntry{
|
||||
Name: name,
|
||||
XUID: xuid,
|
||||
UUID: uuidStr,
|
||||
IP: ip,
|
||||
BannedAt: time.Now(),
|
||||
Reason: reason,
|
||||
Name: name,
|
||||
XUID: xuid,
|
||||
UUID: uuidStr,
|
||||
IP: "", // Do NOT store IP to prevent LAN-wide bans
|
||||
BannedAt: time.Now(),
|
||||
Reason: reason,
|
||||
}
|
||||
if duration > 0 {
|
||||
entry.ExpiresAt = time.Now().Add(duration)
|
||||
}
|
||||
bm.bans[strings.ToLower(name)] = entry
|
||||
bm.mu.Unlock()
|
||||
_ = bm.Save()
|
||||
_ = bm.save()
|
||||
}
|
||||
|
||||
// Unban unbans a player by name.
|
||||
@@ -98,15 +106,28 @@ func (bm *BanManager) Unban(name string) bool {
|
||||
}
|
||||
bm.mu.Unlock()
|
||||
if exists {
|
||||
_ = bm.Save()
|
||||
_ = bm.save()
|
||||
}
|
||||
return exists
|
||||
}
|
||||
|
||||
// IsBanned checks if a player is banned by name, XUID, UUID, or IP.
|
||||
func (bm *BanManager) IsBanned(name, xuid, uuidStr, ip string) (BanEntry, bool) {
|
||||
// UnbanAll removes all bans. Useful for emergency reset.
|
||||
func (bm *BanManager) UnbanAll() int {
|
||||
bm.mu.Lock()
|
||||
defer bm.mu.Unlock()
|
||||
count := len(bm.bans)
|
||||
bm.bans = make(map[string]BanEntry)
|
||||
bm.mu.Unlock()
|
||||
if count > 0 {
|
||||
_ = bm.save()
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
// IsBanned checks if a player is banned by name, XUID, or UUID.
|
||||
// IP-based checking is intentionally excluded to prevent false
|
||||
// positives on local networks where all players share the same IP.
|
||||
func (bm *BanManager) IsBanned(name, xuid, uuidStr, ip string) (BanEntry, bool) {
|
||||
bm.mu.RLock()
|
||||
|
||||
now := time.Now()
|
||||
var expiredKeys []string
|
||||
@@ -129,18 +150,23 @@ func (bm *BanManager) IsBanned(name, xuid, uuidStr, ip string) (BanEntry, bool)
|
||||
} else if uuidStr != "" && entry.UUID != "" && strings.EqualFold(entry.UUID, uuidStr) {
|
||||
foundEntry = entry
|
||||
found = true
|
||||
} else if ip != "" && entry.IP != "" && entry.IP == ip {
|
||||
foundEntry = entry
|
||||
found = true
|
||||
}
|
||||
// NOTE: IP matching is intentionally removed.
|
||||
// On local networks (LAN/nethernet), all players share the
|
||||
// same IP address. Matching by IP would block ALL players
|
||||
// from the same network when only one should be banned.
|
||||
}
|
||||
}
|
||||
bm.mu.RUnlock()
|
||||
|
||||
// Clean up expired entries with a separate write lock.
|
||||
if len(expiredKeys) > 0 {
|
||||
bm.mu.Lock()
|
||||
for _, k := range expiredKeys {
|
||||
delete(bm.bans, k)
|
||||
}
|
||||
go func() { _ = bm.Save() }()
|
||||
bm.mu.Unlock()
|
||||
go func() { _ = bm.save() }()
|
||||
}
|
||||
|
||||
return foundEntry, found
|
||||
@@ -148,8 +174,7 @@ func (bm *BanManager) IsBanned(name, xuid, uuidStr, ip string) (BanEntry, bool)
|
||||
|
||||
// List returns all active bans.
|
||||
func (bm *BanManager) List() []BanEntry {
|
||||
bm.mu.Lock()
|
||||
defer bm.mu.Unlock()
|
||||
bm.mu.RLock()
|
||||
var active []BanEntry
|
||||
now := time.Now()
|
||||
var expiredKeys []string
|
||||
@@ -160,11 +185,15 @@ func (bm *BanManager) List() []BanEntry {
|
||||
}
|
||||
active = append(active, entry)
|
||||
}
|
||||
bm.mu.RUnlock()
|
||||
|
||||
if len(expiredKeys) > 0 {
|
||||
bm.mu.Lock()
|
||||
for _, k := range expiredKeys {
|
||||
delete(bm.bans, k)
|
||||
}
|
||||
go func() { _ = bm.Save() }()
|
||||
bm.mu.Unlock()
|
||||
go func() { _ = bm.save() }()
|
||||
}
|
||||
return active
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user