github.com/metaworking/channeld@v0.7.3/pkg/channeld/ddos.go (about)

     1  package channeld
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  
     7  	"github.com/metaworking/channeld/pkg/channeldpb"
     8  	"go.uber.org/zap"
     9  )
    10  
    11  var unauthenticatedConnections sync.Map
    12  
    13  var failedAuthCounters = make(map[string]int)
    14  var ipBlacklist = make(map[string]time.Time)
    15  var pitBlacklist = make(map[string]time.Time)
    16  
    17  func InitAntiDDoS() {
    18  	Event_AuthComplete.Listen(func(data AuthEventData) {
    19  		if data.Connection.GetConnectionType() == channeldpb.ConnectionType_SERVER {
    20  			return
    21  		}
    22  
    23  		if data.AuthResult == channeldpb.AuthResultMessage_INVALID_LT {
    24  			// Invalid access token - record the PIT
    25  			failedAuthCounters[data.PlayerIdentifierToken]++
    26  			if GlobalSettings.MaxFailedAuthAttempts > 0 && failedAuthCounters[data.PlayerIdentifierToken] >= GlobalSettings.MaxFailedAuthAttempts {
    27  				pitBlacklist[data.PlayerIdentifierToken] = time.Now()
    28  				securityLogger.Info("blacklisted PIT due to too many failed auth attempts", zap.String("pit", data.PlayerIdentifierToken))
    29  				data.Connection.Close()
    30  			}
    31  		} else if data.AuthResult == channeldpb.AuthResultMessage_INVALID_PIT {
    32  			// Invalid username token - record the IP
    33  			addr := data.Connection.RemoteAddr()
    34  			if addr == nil {
    35  				return
    36  			}
    37  			ip := GetIP(addr)
    38  			failedAuthCounters[ip]++
    39  			if GlobalSettings.MaxFailedAuthAttempts > 0 && failedAuthCounters[ip] >= GlobalSettings.MaxFailedAuthAttempts {
    40  				ipBlacklist[ip] = time.Now()
    41  				securityLogger.Info("blacklisted IP due to too many failed auth attempts", zap.String("ip", ip))
    42  				data.Connection.Close()
    43  			}
    44  		}
    45  	})
    46  
    47  	// FSM disallowed - record the PIT
    48  	Event_FsmDisallowed.Listen(func(c *Connection) {
    49  		if c.GetConnectionType() == channeldpb.ConnectionType_SERVER {
    50  			return
    51  		}
    52  
    53  		c.fsmDisallowedCounter++
    54  		if GlobalSettings.MaxFsmDisallowed > 0 && c.fsmDisallowedCounter >= GlobalSettings.MaxFsmDisallowed {
    55  			pitBlacklist[c.pit] = time.Now()
    56  			securityLogger.Info("blacklisted PIT due to too many FSM disallowed", zap.String("pit", c.pit))
    57  			c.Close()
    58  		}
    59  	})
    60  
    61  	go checkUnauthConns()
    62  }
    63  
    64  // Disconnection unauthenticated connections after ConnectionAuthTimeoutMs.
    65  func checkUnauthConns() {
    66  	for {
    67  		unauthenticatedConnections.Range(func(_, v interface{}) bool {
    68  			conn := v.(*Connection)
    69  			if conn.IsClosing() {
    70  				return true
    71  			}
    72  			if conn.state == ConnectionState_UNAUTHENTICATED && time.Since(conn.connTime).Milliseconds() >= GlobalSettings.ConnectionAuthTimeoutMs {
    73  				ipBlacklist[GetIP(conn.RemoteAddr())] = time.Now()
    74  				conn.Close()
    75  				securityLogger.Info("closed and blacklisted unauthenticated connection due to timeout", zap.String("ip", conn.conn.RemoteAddr().String()))
    76  			}
    77  			return true
    78  		})
    79  
    80  		time.Sleep(time.Millisecond * 500)
    81  	}
    82  }