aboutsummaryrefslogtreecommitdiff
path: root/hotline
diff options
context:
space:
mode:
Diffstat (limited to 'hotline')
-rw-r--r--hotline/ban.go27
-rw-r--r--hotline/client_conn.go7
-rw-r--r--hotline/server.go40
3 files changed, 52 insertions, 22 deletions
diff --git a/hotline/ban.go b/hotline/ban.go
index 7a9fd31..cc2ecde 100644
--- a/hotline/ban.go
+++ b/hotline/ban.go
@@ -5,7 +5,34 @@ import "time"
// BanDuration is the length of time for temporary bans.
const BanDuration = 30 * time.Minute
+// Redis key constants for ban management and online user tracking
+const (
+ RedisKeyBannedIPs = "mobius:banned:ips"
+ RedisKeyBannedUsers = "mobius:banned:users"
+ RedisKeyBannedNicknames = "mobius:banned:nicknames"
+ RedisKeyTempBannedIPs = "mobius:temp_banned:ips:"
+ RedisKeyOnline = "mobius:online"
+)
+
type BanMgr interface {
Add(ip string, until *time.Time) error
IsBanned(ip string) (bool, *time.Time)
+
+ // IP banning
+ UnbanIP(ip string) error
+
+ // Username banning
+ BanUsername(username string) error
+ UnbanUsername(username string) error
+ IsUsernameBanned(username string) bool
+
+ // Nickname banning
+ BanNickname(nickname string) error
+ UnbanNickname(nickname string) error
+ IsNicknameBanned(nickname string) bool
+
+ // List operations
+ ListBannedIPs() ([]string, error)
+ ListBannedUsernames() ([]string, error)
+ ListBannedNicknames() ([]string, error)
}
diff --git a/hotline/client_conn.go b/hotline/client_conn.go
index a203630..d8fd435 100644
--- a/hotline/client_conn.go
+++ b/hotline/client_conn.go
@@ -6,6 +6,7 @@ import (
"fmt"
"io"
"log/slog"
+ "net"
"strings"
"sync"
@@ -50,6 +51,12 @@ func (cc *ClientConn) FileRoot() string {
return cc.Server.Config.FileRoot
}
+// IP returns the IP address portion of the client's remote address.
+func (cc *ClientConn) IP() string {
+ ip, _, _ := net.SplitHostPort(cc.RemoteAddr)
+ return ip
+}
+
type ClientFileTransferMgr struct {
transfers map[FileTransferType]map[FileTransferID]*FileTransfer
diff --git a/hotline/server.go b/hotline/server.go
index d797c1e..545e84c 100644
--- a/hotline/server.go
+++ b/hotline/server.go
@@ -496,23 +496,17 @@ func (s *Server) handleNewConnection(ctx context.Context, rwc io.ReadWriteCloser
// Check if remoteAddr is present in the ban list, we do this after we have the login name
ipAddr, _, _ := net.SplitHostPort(remoteAddr)
- if s.Redis != nil {
- // Redis-based ban check
- bannedUser, _ := s.Redis.SIsMember(ctx, "mobius:banned:users", login).Result()
- bannedIP, _ := s.Redis.SIsMember(ctx, "mobius:banned:ips", ipAddr).Result()
- if bannedUser {
- s.Redis.SAdd(ctx, "mobius:banned:ips", ipAddr)
- sendBanMessage(rwc, "You are banned on this server")
- s.Logger.Debug("Disconnecting banned user", "login", login, "ip", ipAddr)
- return nil
- }
- if bannedIP {
- sendBanMessage(rwc, "You are banned on this server")
- s.Logger.Debug("Disconnecting banned IP", "ip", ipAddr)
- return nil
- }
- } else {
- // Fallback to in-memory ban list
+
+ // Check if user is banned
+ if s.BanList != nil && s.BanList.IsUsernameBanned(login) {
+ _ = s.BanList.Add(ipAddr, nil)
+ sendBanMessage(rwc, "You are banned on this server")
+ s.Logger.Debug("Disconnecting banned user", "login", login, "ip", ipAddr)
+ return nil
+ }
+
+ // Check if IP is banned
+ if s.BanList != nil {
if isBanned, banUntil := s.BanList.IsBanned(ipAddr); isBanned {
// permaban
if banUntil == nil {
@@ -531,16 +525,18 @@ func (s *Server) handleNewConnection(ctx context.Context, rwc io.ReadWriteCloser
c := s.NewClientConn(rwc, remoteAddr)
// Add the client to the list of connected clients
+
+ // TODO: refactor this into a connection manager interface, maybe?
if s.Redis != nil {
- s.Redis.SAdd(context.Background(), "mobius:online", login+"::"+ipAddr)
+ s.Redis.SAdd(context.Background(), RedisKeyOnline, login+"::"+ipAddr)
}
// Remove the client from the list of connected clients when they disconnect
defer func() {
if s.Redis != nil {
- s.Redis.SRem(context.Background(), "mobius:online", login+"::"+ipAddr)
+ s.Redis.SRem(context.Background(), RedisKeyOnline, login+"::"+ipAddr)
if len(c.UserName) != 0 {
- s.Redis.SRem(context.Background(), "mobius:online", login+":"+string(c.UserName)+":"+ipAddr)
+ s.Redis.SRem(context.Background(), RedisKeyOnline, login+":"+string(c.UserName)+":"+ipAddr)
}
}
c.Disconnect()
@@ -621,9 +617,9 @@ func (s *Server) handleNewConnection(ctx context.Context, rwc io.ReadWriteCloser
// Update the Redis set with the new information
if s.Redis != nil && len(c.UserName) != 0 {
// Remove old entry (login::ip)
- s.Redis.SRem(context.Background(), "mobius:online", login+"::"+ipAddr)
+ s.Redis.SRem(context.Background(), RedisKeyOnline, login+"::"+ipAddr)
// Add new entry with login, nickname, ip
- s.Redis.SAdd(context.Background(), "mobius:online", login+":"+string(c.UserName)+":"+ipAddr)
+ s.Redis.SAdd(context.Background(), RedisKeyOnline, login+":"+string(c.UserName)+":"+ipAddr)
}
// Notify other clients on the server that the new user has logged in. For 1.5+ clients we don't have this