@@ -3,16 +3,18 @@ import { RelayConfig } from '../utils/RelayConfig';
33import { IncomingMessage } from 'http' ;
44import { Socket } from 'net' ;
55import { RelayLogger } from '../utils/RelayLogger' ;
6- import { RelayPacket } from '../pkt/RelayPacket' ;
7- import { RelayPacket00Handshake } from '../pkt/RelayPacket00Handshake' ;
8- import { RelayPacketFFErrorCode } from '../pkt/RelayPacketFFErrorCode' ;
96import { EaglerSPClient } from './EaglerSPClient' ;
107import { EaglerSPServer } from './EaglerSPServer' ;
8+ import { RelayPacket } from '../pkt/RelayPacket' ;
119import { RelayPacket01ICEServers } from '../pkt/RelayPacket01ICEServers' ;
10+ import { RelayPacket00Handshake } from '../pkt/RelayPacket00Handshake' ;
11+ import { LocalWorld , RelayPacket07LocalWorlds } from '../pkt/RelayPacket07LocalWorlds' ;
1212import { RelayPacket69Pong } from '../pkt/RelayPacket69Pong' ;
13+ import { RelayPacketFEDisconnectClient } from '../pkt/RelayPacketFEDisconnectClient' ;
14+ import { RelayPacketFFErrorCode } from '../pkt/RelayPacketFFErrorCode' ;
1315import { RelayVersion } from '../utils/RelayVersion' ;
14- import { LocalWorld , RelayPacket07LocalWorlds } from '../pkt/RelayPacket07LocalWorlds' ;
1516import { SocketAddress } from '../utils/SocketAddress' ;
17+ import { RateLimit , RateLimiter } from './RateLimiter' ;
1618import '../pkt/RegisterPackets' ;
1719
1820export class EaglerSPRelay {
@@ -24,13 +26,22 @@ export class EaglerSPRelay {
2426 private readonly SERVER_CONNECTIONS : Map < WebSocket , EaglerSPServer > ;
2527 private readonly SERVER_ADDRESS_SETS : Map < string , EaglerSPServer [ ] > ;
2628
29+ private readonly WORLD_RATE_LIMITER : RateLimiter | undefined ;
30+ private readonly PING_RATE_LIMITER : RateLimiter | undefined ;
31+
2732 public constructor ( ) ;
2833 public constructor ( config : object ) ;
2934 public constructor ( config ?: object ) {
3035 this . WSS = new WebSocketServer ( { noServer : true } ) ;
3136 if ( config !== undefined ) RelayConfig . loadConfigJSON ( config ) ;
3237 else RelayConfig . loadConfigFile ( 'config.json' ) ;
3338 RelayLogger . debug ( 'Debug logging enabled' ) ;
39+ if ( RelayConfig . get ( 'limits.world_ratelimit.enabled' ) ) this . WORLD_RATE_LIMITER = new RateLimiter ( Number ( RelayConfig . get ( 'limits.world_ratelimit.period' ) ) * 1000 , Number ( RelayConfig . get ( 'limits.world_ratelimit.limit' ) ) , Number ( RelayConfig . get ( 'limits.world_ratelimit.lockout_limit' ) ) , Number ( RelayConfig . get ( 'limits.world_ratelimit.lockout_time' ) ) * 1000 ) ;
40+ if ( RelayConfig . get ( 'limits.ping_ratelimit.enabled' ) ) this . PING_RATE_LIMITER = new RateLimiter ( Number ( RelayConfig . get ( 'limits.ping_ratelimit.period' ) ) * 1000 , Number ( RelayConfig . get ( 'limits.ping_ratelimit.limit' ) ) , Number ( RelayConfig . get ( 'limits.ping_ratelimit.lockout_limit' ) ) , Number ( RelayConfig . get ( 'limits.ping_ratelimit.lockout_time' ) ) * 1000 ) ;
41+ setInterval ( ( ) => {
42+ this . WORLD_RATE_LIMITER ?. update ( ) ;
43+ this . PING_RATE_LIMITER ?. update ( ) ;
44+ } , 30000 ) ;
3445 this . CLIENT_IDS = new Map ( ) ;
3546 this . SERVER_CODES = new Map ( ) ;
3647 this . PENDING_CONNECTIONS = new Map ( ) ;
@@ -65,6 +76,14 @@ export class EaglerSPRelay {
6576 let id : string | undefined ;
6677 let srv : EaglerSPServer | undefined ;
6778 if ( ipkt . CONNECTION_TYPE === 1 ) {
79+ if ( ! this . rateLimit ( this . WORLD_RATE_LIMITER , ws , waiting . ADDRESS ) ) return ;
80+ let arr : EaglerSPServer [ ] | undefined = this . SERVER_ADDRESS_SETS . get ( waiting . ADDRESS ) ;
81+ if ( arr !== undefined && arr . length >= Number ( RelayConfig . get ( 'limits.worlds_per_ip' ) ) ) {
82+ RelayLogger . debug ( '[{}]: Too many worlds are open on this address' , waiting . ADDRESS ) ;
83+ ws . send ( RelayPacketFEDisconnectClient . RATELIMIT_PACKET_TOO_MANY ) ;
84+ ws . close ( ) ;
85+ return ;
86+ }
6887 RelayLogger . debug ( '[{}]: Connected as a server' , waiting . ADDRESS ) ;
6988 let i : number = 0 ;
7089 while ( true ) {
@@ -91,7 +110,7 @@ export class EaglerSPRelay {
91110 RelayLogger . debug ( '[{}] [Relay -> Server]: PKT 0x00: Assign join code: {}' , waiting . ADDRESS , id ) ;
92111 this . SERVER_CONNECTIONS . set ( ws , srv ) ;
93112 this . PENDING_CONNECTIONS . delete ( ws ) ;
94- let arr : EaglerSPServer [ ] | undefined = this . SERVER_ADDRESS_SETS . get ( srv . SERVER_ADDRESS ) ;
113+ arr = this . SERVER_ADDRESS_SETS . get ( srv . SERVER_ADDRESS ) ;
95114 if ( arr == undefined ) {
96115 arr = [ ] ;
97116 this . SERVER_ADDRESS_SETS . set ( srv . SERVER_ADDRESS , arr ) ;
@@ -100,6 +119,7 @@ export class EaglerSPRelay {
100119 ( srv ) . send ( new RelayPacket01ICEServers ( RelayConfig . getRelayServers ( ) ) ) ;
101120 RelayLogger . debug ( '[{}] [Relay -> Server]: PKT 0x01: Send ICE server list to server' , waiting . ADDRESS ) ;
102121 } else if ( ipkt . CONNECTION_TYPE === 2 ) {
122+ if ( ! this . rateLimit ( this . PING_RATE_LIMITER , ws , waiting . ADDRESS ) ) return ;
103123 const codeLen : number = ( RelayConfig . get ( 'join_codes.length' ) as number ) ;
104124 let code : string = ipkt . CONNECTION_CODE ;
105125 RelayLogger . debug ( '[{}]: Connected as a client, requested server code: {}' , waiting . ADDRESS , code ) ;
@@ -129,10 +149,12 @@ export class EaglerSPRelay {
129149 RelayLogger . debug ( '[{}] [Relay -> Client]: PKT 0x01: Send ICE server list to client' , waiting . ADDRESS ) ;
130150 }
131151 } else if ( ipkt . CONNECTION_TYPE === 3 ) {
152+ if ( ! this . rateLimit ( this . PING_RATE_LIMITER , ws , waiting . ADDRESS ) ) return ;
132153 RelayLogger . debug ( '[{}]: Pinging the server' , waiting . ADDRESS ) ;
133154 ws . send ( RelayPacket . writePacket ( new RelayPacket69Pong ( 1 , RelayConfig . get ( 'server.comment' ) as string , RelayVersion . BRAND ) ) ) ;
134155 ws . close ( ) ;
135156 } else if ( ipkt . CONNECTION_TYPE === 4 ) {
157+ if ( ! this . rateLimit ( this . PING_RATE_LIMITER , ws , waiting . ADDRESS ) ) return ;
136158 RelayLogger . debug ( '[{}]: Polling the server for other worlds' , waiting . ADDRESS ) ;
137159 if ( RelayConfig . get ( 'server.show_local_worlds' ) ) ws . send ( RelayPacket . writePacket ( new RelayPacket07LocalWorlds ( this . getLocalWorlds ( SocketAddress . getAddress ( ws ) ) ) ) ) ;
138160 else ws . send ( RelayPacket . writePacket ( new RelayPacket07LocalWorlds ( [ ] ) ) ) ;
@@ -220,6 +242,19 @@ export class EaglerSPRelay {
220242 if ( srvs != undefined && srvs . length > 0 ) for ( const s of srvs ) if ( ! s . SERVER_HIDDEN ) arr . push ( new LocalWorld ( s . SERVER_NAME , s . CODE ) ) ;
221243 return arr ;
222244 }
245+
246+ private rateLimit ( l : RateLimiter | undefined , ws : WebSocket , addr : string ) : boolean {
247+ if ( l === undefined ) return true ;
248+ const r = l . limit ( addr ) ;
249+ if ( r === RateLimit . NONE ) return true ;
250+ if ( r === RateLimit . LIMIT ) {
251+ ws . send ( RelayPacketFEDisconnectClient . RATELIMIT_PACKET_BLOCK ) ;
252+ } else if ( r === RateLimit . LIMIT_NOW_LOCKOUT ) {
253+ ws . send ( RelayPacketFEDisconnectClient . RATELIMIT_PACKET_BLOCK_LOCK ) ;
254+ }
255+ ws . close ( ) ;
256+ return false ;
257+ }
223258}
224259
225260class PendingConnection {
0 commit comments