Add ratelimiting on joins
This commit is contained in:
parent
320ef98852
commit
18de00adb4
|
@ -731,6 +731,10 @@ log_config: "CONFDIR/SERVERNAME.log.config"
|
||||||
# - one for ratelimiting redactions by room admins. If this is not explicitly
|
# - one for ratelimiting redactions by room admins. If this is not explicitly
|
||||||
# set then it uses the same ratelimiting as per rc_message. This is useful
|
# set then it uses the same ratelimiting as per rc_message. This is useful
|
||||||
# to allow room admins to deal with abuse quickly.
|
# to allow room admins to deal with abuse quickly.
|
||||||
|
# - two for ratelimiting number of rooms a user can join, "local" for when
|
||||||
|
# users are joining rooms the server is already in (this is cheap) vs
|
||||||
|
# "remote" for when users are trying to join rooms not on the server (which
|
||||||
|
# can be more expensive)
|
||||||
#
|
#
|
||||||
# The defaults are as shown below.
|
# The defaults are as shown below.
|
||||||
#
|
#
|
||||||
|
@ -756,6 +760,14 @@ log_config: "CONFDIR/SERVERNAME.log.config"
|
||||||
#rc_admin_redaction:
|
#rc_admin_redaction:
|
||||||
# per_second: 1
|
# per_second: 1
|
||||||
# burst_count: 50
|
# burst_count: 50
|
||||||
|
#
|
||||||
|
#rc_joins:
|
||||||
|
# local:
|
||||||
|
# per_second: 0.1
|
||||||
|
# burst_count: 3
|
||||||
|
# remote:
|
||||||
|
# per_second: 0.01
|
||||||
|
# burst_count: 3
|
||||||
|
|
||||||
|
|
||||||
# Ratelimiting settings for incoming federation
|
# Ratelimiting settings for incoming federation
|
||||||
|
|
|
@ -93,6 +93,15 @@ class RatelimitConfig(Config):
|
||||||
if rc_admin_redaction:
|
if rc_admin_redaction:
|
||||||
self.rc_admin_redaction = RateLimitConfig(rc_admin_redaction)
|
self.rc_admin_redaction = RateLimitConfig(rc_admin_redaction)
|
||||||
|
|
||||||
|
self.rc_joins_local = RateLimitConfig(
|
||||||
|
config.get("rc_joins", {}).get("local", {}),
|
||||||
|
defaults={"per_second": 0.1, "burst_count": 3},
|
||||||
|
)
|
||||||
|
self.rc_joins_remote = RateLimitConfig(
|
||||||
|
config.get("rc_joins", {}).get("remote", {}),
|
||||||
|
defaults={"per_second": 0.01, "burst_count": 3},
|
||||||
|
)
|
||||||
|
|
||||||
def generate_config_section(self, **kwargs):
|
def generate_config_section(self, **kwargs):
|
||||||
return """\
|
return """\
|
||||||
## Ratelimiting ##
|
## Ratelimiting ##
|
||||||
|
@ -118,6 +127,10 @@ class RatelimitConfig(Config):
|
||||||
# - one for ratelimiting redactions by room admins. If this is not explicitly
|
# - one for ratelimiting redactions by room admins. If this is not explicitly
|
||||||
# set then it uses the same ratelimiting as per rc_message. This is useful
|
# set then it uses the same ratelimiting as per rc_message. This is useful
|
||||||
# to allow room admins to deal with abuse quickly.
|
# to allow room admins to deal with abuse quickly.
|
||||||
|
# - two for ratelimiting number of rooms a user can join, "local" for when
|
||||||
|
# users are joining rooms the server is already in (this is cheap) vs
|
||||||
|
# "remote" for when users are trying to join rooms not on the server (which
|
||||||
|
# can be more expensive)
|
||||||
#
|
#
|
||||||
# The defaults are as shown below.
|
# The defaults are as shown below.
|
||||||
#
|
#
|
||||||
|
@ -143,6 +156,14 @@ class RatelimitConfig(Config):
|
||||||
#rc_admin_redaction:
|
#rc_admin_redaction:
|
||||||
# per_second: 1
|
# per_second: 1
|
||||||
# burst_count: 50
|
# burst_count: 50
|
||||||
|
#
|
||||||
|
#rc_joins:
|
||||||
|
# local:
|
||||||
|
# per_second: 0.1
|
||||||
|
# burst_count: 3
|
||||||
|
# remote:
|
||||||
|
# per_second: 0.01
|
||||||
|
# burst_count: 3
|
||||||
|
|
||||||
|
|
||||||
# Ratelimiting settings for incoming federation
|
# Ratelimiting settings for incoming federation
|
||||||
|
|
|
@ -22,7 +22,8 @@ from unpaddedbase64 import encode_base64
|
||||||
|
|
||||||
from synapse import types
|
from synapse import types
|
||||||
from synapse.api.constants import MAX_DEPTH, EventTypes, Membership
|
from synapse.api.constants import MAX_DEPTH, EventTypes, Membership
|
||||||
from synapse.api.errors import AuthError, Codes, SynapseError
|
from synapse.api.errors import AuthError, Codes, LimitExceededError, SynapseError
|
||||||
|
from synapse.api.ratelimiting import Ratelimiter
|
||||||
from synapse.api.room_versions import EventFormatVersions
|
from synapse.api.room_versions import EventFormatVersions
|
||||||
from synapse.crypto.event_signing import compute_event_reference_hash
|
from synapse.crypto.event_signing import compute_event_reference_hash
|
||||||
from synapse.events import EventBase
|
from synapse.events import EventBase
|
||||||
|
@ -77,6 +78,17 @@ class RoomMemberHandler(object):
|
||||||
if self._is_on_event_persistence_instance:
|
if self._is_on_event_persistence_instance:
|
||||||
self.persist_event_storage = hs.get_storage().persistence
|
self.persist_event_storage = hs.get_storage().persistence
|
||||||
|
|
||||||
|
self._join_rate_limiter_local = Ratelimiter(
|
||||||
|
clock=self.clock,
|
||||||
|
rate_hz=hs.config.ratelimiting.rc_joins_local.per_second,
|
||||||
|
burst_count=hs.config.ratelimiting.rc_joins_local.burst_count,
|
||||||
|
)
|
||||||
|
self._join_rate_limiter_remote = Ratelimiter(
|
||||||
|
clock=self.clock,
|
||||||
|
rate_hz=hs.config.ratelimiting.rc_joins_remote.per_second,
|
||||||
|
burst_count=hs.config.ratelimiting.rc_joins_remote.burst_count,
|
||||||
|
)
|
||||||
|
|
||||||
# This is only used to get at ratelimit function, and
|
# This is only used to get at ratelimit function, and
|
||||||
# maybe_kick_guest_users. It's fine there are multiple of these as
|
# maybe_kick_guest_users. It's fine there are multiple of these as
|
||||||
# it doesn't store state.
|
# it doesn't store state.
|
||||||
|
@ -441,7 +453,28 @@ class RoomMemberHandler(object):
|
||||||
# so don't really fit into the general auth process.
|
# so don't really fit into the general auth process.
|
||||||
raise AuthError(403, "Guest access not allowed")
|
raise AuthError(403, "Guest access not allowed")
|
||||||
|
|
||||||
if not is_host_in_room:
|
if is_host_in_room:
|
||||||
|
time_now_s = self.clock.time()
|
||||||
|
allowed, time_allowed = self._join_rate_limiter_local.can_do_action(
|
||||||
|
requester.user.to_string(),
|
||||||
|
)
|
||||||
|
|
||||||
|
if not allowed:
|
||||||
|
raise LimitExceededError(
|
||||||
|
retry_after_ms=int(1000 * (time_allowed - time_now_s))
|
||||||
|
)
|
||||||
|
|
||||||
|
else:
|
||||||
|
time_now_s = self.clock.time()
|
||||||
|
allowed, time_allowed = self._join_rate_limiter_remote.can_do_action(
|
||||||
|
requester.user.to_string(),
|
||||||
|
)
|
||||||
|
|
||||||
|
if not allowed:
|
||||||
|
raise LimitExceededError(
|
||||||
|
retry_after_ms=int(1000 * (time_allowed - time_now_s))
|
||||||
|
)
|
||||||
|
|
||||||
inviter = await self._get_inviter(target.to_string(), room_id)
|
inviter = await self._get_inviter(target.to_string(), room_id)
|
||||||
if inviter and not self.hs.is_mine(inviter):
|
if inviter and not self.hs.is_mine(inviter):
|
||||||
remote_room_hosts.append(inviter.domain)
|
remote_room_hosts.append(inviter.domain)
|
||||||
|
|
|
@ -154,6 +154,10 @@ def default_config(name, parse=False):
|
||||||
"account": {"per_second": 10000, "burst_count": 10000},
|
"account": {"per_second": 10000, "burst_count": 10000},
|
||||||
"failed_attempts": {"per_second": 10000, "burst_count": 10000},
|
"failed_attempts": {"per_second": 10000, "burst_count": 10000},
|
||||||
},
|
},
|
||||||
|
"rc_joins": {
|
||||||
|
"local": {"per_second": 10000, "burst_count": 10000},
|
||||||
|
"remote": {"per_second": 10000, "burst_count": 10000},
|
||||||
|
},
|
||||||
"saml2_enabled": False,
|
"saml2_enabled": False,
|
||||||
"public_baseurl": None,
|
"public_baseurl": None,
|
||||||
"default_identity_server": None,
|
"default_identity_server": None,
|
||||||
|
|
Loading…
Reference in New Issue