summary refs log tree commit diff
path: root/synapse/http
diff options
context:
space:
mode:
Diffstat (limited to 'synapse/http')
-rw-r--r--synapse/http/client.py120
-rw-r--r--synapse/http/federation/matrix_federation_agent.py24
-rw-r--r--synapse/http/matrixfederationclient.py14
-rw-r--r--synapse/http/proxyagent.py2
-rw-r--r--synapse/http/replicationagent.py34
5 files changed, 103 insertions, 91 deletions
diff --git a/synapse/http/client.py b/synapse/http/client.py

index c9479c81ff..09ea93e10d 100644 --- a/synapse/http/client.py +++ b/synapse/http/client.py
@@ -117,22 +117,22 @@ RawHeaderValue = Union[ ] -def check_against_blacklist( - ip_address: IPAddress, ip_whitelist: Optional[IPSet], ip_blacklist: IPSet +def _is_ip_blocked( + ip_address: IPAddress, allowlist: Optional[IPSet], blocklist: IPSet ) -> bool: """ Compares an IP address to allowed and disallowed IP sets. Args: ip_address: The IP address to check - ip_whitelist: Allowed IP addresses. - ip_blacklist: Disallowed IP addresses. + allowlist: Allowed IP addresses. + blocklist: Disallowed IP addresses. Returns: - True if the IP address is in the blacklist and not in the whitelist. + True if the IP address is in the blocklist and not in the allowlist. """ - if ip_address in ip_blacklist: - if ip_whitelist is None or ip_address not in ip_whitelist: + if ip_address in blocklist: + if allowlist is None or ip_address not in allowlist: return True return False @@ -154,27 +154,27 @@ def _make_scheduler( return _scheduler -class _IPBlacklistingResolver: +class _IPBlockingResolver: """ - A proxy for reactor.nameResolver which only produces non-blacklisted IP - addresses, preventing DNS rebinding attacks on URL preview. + A proxy for reactor.nameResolver which only produces non-blocklisted IP + addresses, preventing DNS rebinding attacks. """ def __init__( self, reactor: IReactorPluggableNameResolver, - ip_whitelist: Optional[IPSet], - ip_blacklist: IPSet, + ip_allowlist: Optional[IPSet], + ip_blocklist: IPSet, ): """ Args: reactor: The twisted reactor. - ip_whitelist: IP addresses to allow. - ip_blacklist: IP addresses to disallow. + ip_allowlist: IP addresses to allow. + ip_blocklist: IP addresses to disallow. """ self._reactor = reactor - self._ip_whitelist = ip_whitelist - self._ip_blacklist = ip_blacklist + self._ip_allowlist = ip_allowlist + self._ip_blocklist = ip_blocklist def resolveHostName( self, recv: IResolutionReceiver, hostname: str, portNumber: int = 0 @@ -191,16 +191,13 @@ class _IPBlacklistingResolver: ip_address = IPAddress(address.host) - if check_against_blacklist( - ip_address, self._ip_whitelist, self._ip_blacklist - ): + if _is_ip_blocked(ip_address, self._ip_allowlist, self._ip_blocklist): logger.info( - "Dropped %s from DNS resolution to %s due to blacklist" - % (ip_address, hostname) + "Blocked %s from DNS resolution to %s" % (ip_address, hostname) ) has_bad_ip = True - # if we have a blacklisted IP, we'd like to raise an error to block the + # if we have a blocked IP, we'd like to raise an error to block the # request, but all we can really do from here is claim that there were no # valid results. if not has_bad_ip: @@ -232,24 +229,24 @@ class _IPBlacklistingResolver: # ISynapseReactor implies IReactorCore, but explicitly marking it this as an implementer # of IReactorCore seems to keep mypy-zope happier. @implementer(IReactorCore, ISynapseReactor) -class BlacklistingReactorWrapper: +class BlocklistingReactorWrapper: """ - A Reactor wrapper which will prevent DNS resolution to blacklisted IP + A Reactor wrapper which will prevent DNS resolution to blocked IP addresses, to prevent DNS rebinding. """ def __init__( self, reactor: IReactorPluggableNameResolver, - ip_whitelist: Optional[IPSet], - ip_blacklist: IPSet, + ip_allowlist: Optional[IPSet], + ip_blocklist: IPSet, ): self._reactor = reactor - # We need to use a DNS resolver which filters out blacklisted IP + # We need to use a DNS resolver which filters out blocked IP # addresses, to prevent DNS rebinding. - self._nameResolver = _IPBlacklistingResolver( - self._reactor, ip_whitelist, ip_blacklist + self._nameResolver = _IPBlockingResolver( + self._reactor, ip_allowlist, ip_blocklist ) def __getattr__(self, attr: str) -> Any: @@ -260,7 +257,7 @@ class BlacklistingReactorWrapper: return getattr(self._reactor, attr) -class BlacklistingAgentWrapper(Agent): +class BlocklistingAgentWrapper(Agent): """ An Agent wrapper which will prevent access to IP addresses being accessed directly (without an IP address lookup). @@ -269,18 +266,18 @@ class BlacklistingAgentWrapper(Agent): def __init__( self, agent: IAgent, - ip_blacklist: IPSet, - ip_whitelist: Optional[IPSet] = None, + ip_blocklist: IPSet, + ip_allowlist: Optional[IPSet] = None, ): """ Args: agent: The Agent to wrap. - ip_whitelist: IP addresses to allow. - ip_blacklist: IP addresses to disallow. + ip_allowlist: IP addresses to allow. + ip_blocklist: IP addresses to disallow. """ self._agent = agent - self._ip_whitelist = ip_whitelist - self._ip_blacklist = ip_blacklist + self._ip_allowlist = ip_allowlist + self._ip_blocklist = ip_blocklist def request( self, @@ -299,13 +296,9 @@ class BlacklistingAgentWrapper(Agent): # Not an IP pass else: - if check_against_blacklist( - ip_address, self._ip_whitelist, self._ip_blacklist - ): - logger.info("Blocking access to %s due to blacklist" % (ip_address,)) - e = SynapseError( - HTTPStatus.FORBIDDEN, "IP address blocked by IP blacklist entry" - ) + if _is_ip_blocked(ip_address, self._ip_allowlist, self._ip_blocklist): + logger.info("Blocking access to %s" % (ip_address,)) + e = SynapseError(HTTPStatus.FORBIDDEN, "IP address blocked") return defer.fail(Failure(e)) return self._agent.request( @@ -763,10 +756,9 @@ class SimpleHttpClient(BaseHttpClient): Args: hs: The HomeServer instance to pass in treq_args: Extra keyword arguments to be given to treq.request. - ip_blacklist: The IP addresses that are blacklisted that - we may not request. - ip_whitelist: The whitelisted IP addresses, that we can - request if it were otherwise caught in a blacklist. + ip_blocklist: The IP addresses that we may not request. + ip_allowlist: The allowed IP addresses, that we can + request if it were otherwise caught in a blocklist. use_proxy: Whether proxy settings should be discovered and used from conventional environment variables. """ @@ -775,19 +767,19 @@ class SimpleHttpClient(BaseHttpClient): self, hs: "HomeServer", treq_args: Optional[Dict[str, Any]] = None, - ip_whitelist: Optional[IPSet] = None, - ip_blacklist: Optional[IPSet] = None, + ip_allowlist: Optional[IPSet] = None, + ip_blocklist: Optional[IPSet] = None, use_proxy: bool = False, ): super().__init__(hs, treq_args=treq_args) - self._ip_whitelist = ip_whitelist - self._ip_blacklist = ip_blacklist - - if self._ip_blacklist: - # If we have an IP blacklist, we need to use a DNS resolver which - # filters out blacklisted IP addresses, to prevent DNS rebinding. - self.reactor: ISynapseReactor = BlacklistingReactorWrapper( - self.reactor, self._ip_whitelist, self._ip_blacklist + self._ip_allowlist = ip_allowlist + self._ip_blocklist = ip_blocklist + + if self._ip_blocklist: + # If we have an IP blocklist, we need to use a DNS resolver which + # filters out blocked IP addresses, to prevent DNS rebinding. + self.reactor: ISynapseReactor = BlocklistingReactorWrapper( + self.reactor, self._ip_allowlist, self._ip_blocklist ) # the pusher makes lots of concurrent SSL connections to Sygnal, and tends to @@ -809,14 +801,13 @@ class SimpleHttpClient(BaseHttpClient): use_proxy=use_proxy, ) - if self._ip_blacklist: - # If we have an IP blacklist, we then install the blacklisting Agent - # which prevents direct access to IP addresses, that are not caught - # by the DNS resolution. - self.agent = BlacklistingAgentWrapper( + if self._ip_blocklist: + # If we have an IP blocklist, we then install the Agent which prevents + # direct access to IP addresses, that are not caught by the DNS resolution. + self.agent = BlocklistingAgentWrapper( self.agent, - ip_blacklist=self._ip_blacklist, - ip_whitelist=self._ip_whitelist, + ip_blocklist=self._ip_blocklist, + ip_allowlist=self._ip_allowlist, ) @@ -844,6 +835,7 @@ class ReplicationClient(BaseHttpClient): self.agent: IAgent = ReplicationAgent( hs.get_reactor(), + hs.config.worker.instance_map, contextFactory=hs.get_http_client_context_factory(), pool=pool, ) diff --git a/synapse/http/federation/matrix_federation_agent.py b/synapse/http/federation/matrix_federation_agent.py
index 8d7d0a3875..7e8cf31682 100644 --- a/synapse/http/federation/matrix_federation_agent.py +++ b/synapse/http/federation/matrix_federation_agent.py
@@ -36,7 +36,7 @@ from twisted.web.iweb import IAgent, IAgentEndpointFactory, IBodyProducer, IResp from synapse.crypto.context_factory import FederationPolicyForHTTPS from synapse.http import proxyagent -from synapse.http.client import BlacklistingAgentWrapper, BlacklistingReactorWrapper +from synapse.http.client import BlocklistingAgentWrapper, BlocklistingReactorWrapper from synapse.http.connectproxyclient import HTTPConnectProxyEndpoint from synapse.http.federation.srv_resolver import Server, SrvResolver from synapse.http.federation.well_known_resolver import WellKnownResolver @@ -65,12 +65,12 @@ class MatrixFederationAgent: user_agent: The user agent header to use for federation requests. - ip_whitelist: Allowed IP addresses. + ip_allowlist: Allowed IP addresses. - ip_blacklist: Disallowed IP addresses. + ip_blocklist: Disallowed IP addresses. proxy_reactor: twisted reactor to use for connections to the proxy server - reactor might have some blacklisting applied (i.e. for DNS queries), + reactor might have some blocking applied (i.e. for DNS queries), but we need unblocked access to the proxy. _srv_resolver: @@ -87,17 +87,17 @@ class MatrixFederationAgent: reactor: ISynapseReactor, tls_client_options_factory: Optional[FederationPolicyForHTTPS], user_agent: bytes, - ip_whitelist: Optional[IPSet], - ip_blacklist: IPSet, + ip_allowlist: Optional[IPSet], + ip_blocklist: IPSet, _srv_resolver: Optional[SrvResolver] = None, _well_known_resolver: Optional[WellKnownResolver] = None, ): - # proxy_reactor is not blacklisted + # proxy_reactor is not blocklisting reactor proxy_reactor = reactor - # We need to use a DNS resolver which filters out blacklisted IP + # We need to use a DNS resolver which filters out blocked IP # addresses, to prevent DNS rebinding. - reactor = BlacklistingReactorWrapper(reactor, ip_whitelist, ip_blacklist) + reactor = BlocklistingReactorWrapper(reactor, ip_allowlist, ip_blocklist) self._clock = Clock(reactor) self._pool = HTTPConnectionPool(reactor) @@ -120,7 +120,7 @@ class MatrixFederationAgent: if _well_known_resolver is None: _well_known_resolver = WellKnownResolver( reactor, - agent=BlacklistingAgentWrapper( + agent=BlocklistingAgentWrapper( ProxyAgent( reactor, proxy_reactor, @@ -128,7 +128,7 @@ class MatrixFederationAgent: contextFactory=tls_client_options_factory, use_proxy=True, ), - ip_blacklist=ip_blacklist, + ip_blocklist=ip_blocklist, ), user_agent=self.user_agent, ) @@ -256,7 +256,7 @@ class MatrixHostnameEndpoint: Args: reactor: twisted reactor to use for underlying requests proxy_reactor: twisted reactor to use for connections to the proxy server. - 'reactor' might have some blacklisting applied (i.e. for DNS queries), + 'reactor' might have some blocking applied (i.e. for DNS queries), but we need unblocked access to the proxy. tls_client_options_factory: factory to use for fetching client tls options, or none to disable TLS. diff --git a/synapse/http/matrixfederationclient.py b/synapse/http/matrixfederationclient.py
index 634882487c..9094dab0fe 100644 --- a/synapse/http/matrixfederationclient.py +++ b/synapse/http/matrixfederationclient.py
@@ -64,7 +64,7 @@ from synapse.api.errors import ( from synapse.crypto.context_factory import FederationPolicyForHTTPS from synapse.http import QuieterFileBodyProducer from synapse.http.client import ( - BlacklistingAgentWrapper, + BlocklistingAgentWrapper, BodyExceededMaxSize, ByteWriteable, _make_scheduler, @@ -392,15 +392,15 @@ class MatrixFederationHttpClient: self.reactor, tls_client_options_factory, user_agent.encode("ascii"), - hs.config.server.federation_ip_range_whitelist, - hs.config.server.federation_ip_range_blacklist, + hs.config.server.federation_ip_range_allowlist, + hs.config.server.federation_ip_range_blocklist, ) - # Use a BlacklistingAgentWrapper to prevent circumventing the IP - # blacklist via IP literals in server names - self.agent = BlacklistingAgentWrapper( + # Use a BlocklistingAgentWrapper to prevent circumventing the IP + # blocking via IP literals in server names + self.agent = BlocklistingAgentWrapper( federation_agent, - ip_blacklist=hs.config.server.federation_ip_range_blacklist, + ip_blocklist=hs.config.server.federation_ip_range_blocklist, ) self.clock = hs.get_clock() diff --git a/synapse/http/proxyagent.py b/synapse/http/proxyagent.py
index 94ef737b9e..7bdc4acae7 100644 --- a/synapse/http/proxyagent.py +++ b/synapse/http/proxyagent.py
@@ -53,7 +53,7 @@ class ProxyAgent(_AgentBase): connections. proxy_reactor: twisted reactor to use for connections to the proxy server - reactor might have some blacklisting applied (i.e. for DNS queries), + reactor might have some blocking applied (i.e. for DNS queries), but we need unblocked access to the proxy. contextFactory: A factory for TLS contexts, to control the diff --git a/synapse/http/replicationagent.py b/synapse/http/replicationagent.py
index 5ecd08be0f..800f21873d 100644 --- a/synapse/http/replicationagent.py +++ b/synapse/http/replicationagent.py
@@ -13,7 +13,7 @@ # limitations under the License. import logging -from typing import Optional +from typing import Dict, Optional from zope.interface import implementer @@ -32,6 +32,7 @@ from twisted.web.iweb import ( IResponse, ) +from synapse.config.workers import InstanceLocationConfig from synapse.types import ISynapseReactor logger = logging.getLogger(__name__) @@ -44,9 +45,11 @@ class ReplicationEndpointFactory: def __init__( self, reactor: ISynapseReactor, + instance_map: Dict[str, InstanceLocationConfig], context_factory: IPolicyForHTTPS, ) -> None: self.reactor = reactor + self.instance_map = instance_map self.context_factory = context_factory def endpointForURI(self, uri: URI) -> IStreamClientEndpoint: @@ -58,15 +61,29 @@ class ReplicationEndpointFactory: Returns: The correct client endpoint object """ - if uri.scheme in (b"http", b"https"): - endpoint = HostnameEndpoint(self.reactor, uri.host, uri.port) - if uri.scheme == b"https": + # The given URI has a special scheme and includes the worker name. The + # actual connection details are pulled from the instance map. + worker_name = uri.netloc.decode("utf-8") + scheme = self.instance_map[worker_name].scheme() + + if scheme in ("http", "https"): + endpoint = HostnameEndpoint( + self.reactor, + self.instance_map[worker_name].host, + self.instance_map[worker_name].port, + ) + if scheme == "https": endpoint = wrapClientTLS( - self.context_factory.creatorForNetloc(uri.host, uri.port), endpoint + # The 'port' argument below isn't actually used by the function + self.context_factory.creatorForNetloc( + self.instance_map[worker_name].host, + self.instance_map[worker_name].port, + ), + endpoint, ) return endpoint else: - raise SchemeNotSupported(f"Unsupported scheme: {uri.scheme!r}") + raise SchemeNotSupported(f"Unsupported scheme: {scheme}") @implementer(IAgent) @@ -80,6 +97,7 @@ class ReplicationAgent(_AgentBase): def __init__( self, reactor: ISynapseReactor, + instance_map: Dict[str, InstanceLocationConfig], contextFactory: IPolicyForHTTPS, connectTimeout: Optional[float] = None, bindAddress: Optional[bytes] = None, @@ -102,7 +120,9 @@ class ReplicationAgent(_AgentBase): created. """ _AgentBase.__init__(self, reactor, pool) - endpoint_factory = ReplicationEndpointFactory(reactor, contextFactory) + endpoint_factory = ReplicationEndpointFactory( + reactor, instance_map, contextFactory + ) self._endpointFactory = endpoint_factory def request(