diff --git a/evennia/server/portal/portalsessionhandler.py b/evennia/server/portal/portalsessionhandler.py index f4cad5d2aa..b6eaf82d41 100644 --- a/evennia/server/portal/portalsessionhandler.py +++ b/evennia/server/portal/portalsessionhandler.py @@ -1,17 +1,19 @@ """ Sessionhandler for portal sessions """ -from collections import deque + from time import time -from twisted.internet import reactor, task +from twisted.internet import reactor +from django.conf import settings from evennia.server.sessionhandler import SessionHandler, PCONN, PDISCONN, PCONNSYNC -_CONNECTION_RATE = 5.0 -_MIN_TIME_BETWEEN_CONNECTS = 1.0 / _CONNECTION_RATE +# module import _MOD_IMPORT = None -#_MAX_CMD_RATE = 80.0 -#_ERROR_COMMAND_OVERFLOW = "You entered commands too fast. Wait a moment and try again." +# throttles +_MIN_TIME_BETWEEN_CONNECTS = 1.0 / float(settings.MAX_CONNECTION_RATE) if float(settings.MAX_CONNECTION_RATE) > 0 else 1.0 / 5.0 +_MIN_TIME_BETWEEN_CMDS = 1.0 / float(settings.MAX_COMMAND_RATE) if float(settings.MAX_COMMAND_RATE) > 0 else -10 +_ERROR_COMMAND_OVERFLOW = settings.COMMAND_RATE_WARNING #------------------------------------------------------------ # Portal-SessionHandler class @@ -66,9 +68,8 @@ class PortalSessionHandler(SessionHandler): session.sessid = self.latest_sessid now = time() - current_rate = 1.0 / (now - self.time_last_connect) - if current_rate > _CONNECTION_RATE: + if now - self.time_last_connect < _MIN_TIME_BETWEEN_CONNECTS: # we have too many connections per second. Delay. #print " delaying connecting", session.sessid reactor.callLater(_MIN_TIME_BETWEEN_CONNECTS, self.connect, session) @@ -80,9 +81,9 @@ class PortalSessionHandler(SessionHandler): reactor.callLater(0.5, self.connect, session) return - # sync with server-side - self.time_last_connect = now + + # sync with server-side sessdata = session.get_sync_data() self.sessions[session.sessid] = session session.server_connected = True @@ -290,7 +291,13 @@ class PortalSessionHandler(SessionHandler): serialized before passed on. """ + # data throttle (anti DoS measure) + prev_cmd_last = session.cmd_last session.cmd_last = time() + if session.cmd_last - prev_cmd_last < _MIN_TIME_BETWEEN_CMDS: + self.data_out(session.sessid, text=_ERROR_COMMAND_OVERFLOW) + return + # relay data to Server self.portal.amp_protocol.call_remote_MsgPortal2Server(session.sessid, msg=text, data=kwargs) diff --git a/evennia/settings_default.py b/evennia/settings_default.py index fe6abf40e7..ad7a06ae56 100644 --- a/evennia/settings_default.py +++ b/evennia/settings_default.py @@ -71,7 +71,7 @@ WEBSOCKET_CLIENT_ENABLED = True WEBSOCKET_CLIENT_PORT = 8001 # Interface addresses to listen to. If 0.0.0.0, listen to all. Use :: for IPv6. WEBSOCKET_CLIENT_INTERFACE = '0.0.0.0' -# Actual URL for webclient component to reach the websocket. +# Actual URL for webclient component to reach the websocket. # The WEBSOCKET_CLIENT_PORT will be automatically appended to this URL. WEBSOCKET_CLIENT_URL = "ws://localhost" # Activate SSH protocol communication (SecureShell) @@ -179,6 +179,19 @@ AMP_INTERFACE = '127.0.0.1' # be necessary (use @server to see how many objects are in the idmapper # cache at any time). Setting this to None disables the cache cap. IDMAPPER_CACHE_MAXSIZE = 200 # (MB) +# This determines how many connections per second the Portal should +# accept, as a DoS countermeasure. If the rate exceeds this number, incoming +# connections will be queued to this rate, so none will be lost. +# Must be set to a value > 0. +MAX_CONNECTION_RATE = 5 +# Determine how many commands per second a given Session is allowed +# to send to the Portal via a connected protocol. Too high rate will +# drop the command and echo a warning. Note that this will also cap +# OOB messages so don't set it too low if you expect a lot of events +# from the client! To turn the limiter off, set to <= 0. +MAX_COMMAND_RATE = 80 +# The warning to echo back to users if they send commands too fast +COMMAND_RATE_WARNING ="You entered commands too fast. Wait a moment and try again." ###################################################################### # Evennia Database config