Abstract the code to blacklist IP address resolutions.

pull/8821/head
Patrick Cloke 2020-11-25 14:23:09 -05:00
parent 82c067d2e8
commit f559354dd1
2 changed files with 36 additions and 31 deletions

View File

@ -125,7 +125,7 @@ def _make_scheduler(reactor):
return _scheduler return _scheduler
class IPBlacklistingResolver: class _IPBlacklistingResolver:
""" """
A proxy for reactor.nameResolver which only produces non-blacklisted IP A proxy for reactor.nameResolver which only produces non-blacklisted IP
addresses, preventing DNS rebinding attacks on URL preview. addresses, preventing DNS rebinding attacks on URL preview.
@ -199,6 +199,35 @@ class IPBlacklistingResolver:
return r return r
@implementer(IReactorPluggableNameResolver)
class BlacklistingReactorWrapper:
"""
A Reactor wrapper which will prevent DNS resolution to blacklisted IP
addresses, to prevent DNS rebinding.
"""
def __init__(
self,
reactor: IReactorPluggableNameResolver,
ip_whitelist: Optional[IPSet],
ip_blacklist: IPSet,
):
self._reactor = reactor
# We need to use a DNS resolver which filters out blacklisted IP
# addresses, to prevent DNS rebinding.
self._nameResolver = _IPBlacklistingResolver(
self._reactor, ip_whitelist, ip_blacklist
)
def __getattr__(self, attr: str) -> Any:
# Passthrough to the real reactor except for the DNS resolver.
if attr == "nameResolver":
return self._nameResolver
else:
return getattr(self._reactor, attr)
class BlacklistingAgentWrapper(Agent): class BlacklistingAgentWrapper(Agent):
""" """
An Agent wrapper which will prevent access to IP addresses being accessed An Agent wrapper which will prevent access to IP addresses being accessed
@ -292,22 +321,11 @@ class SimpleHttpClient:
self.user_agent = self.user_agent.encode("ascii") self.user_agent = self.user_agent.encode("ascii")
if self._ip_blacklist: if self._ip_blacklist:
real_reactor = hs.get_reactor()
# If we have an IP blacklist, we need to use a DNS resolver which # If we have an IP blacklist, we need to use a DNS resolver which
# filters out blacklisted IP addresses, to prevent DNS rebinding. # filters out blacklisted IP addresses, to prevent DNS rebinding.
nameResolver = IPBlacklistingResolver( self.reactor = BlacklistingReactorWrapper(
real_reactor, self._ip_whitelist, self._ip_blacklist hs.get_reactor(), self._ip_whitelist, self._ip_blacklist
) )
@implementer(IReactorPluggableNameResolver)
class Reactor:
def __getattr__(_self, attr):
if attr == "nameResolver":
return nameResolver
else:
return getattr(real_reactor, attr)
self.reactor = Reactor()
else: else:
self.reactor = hs.get_reactor() self.reactor = hs.get_reactor()

View File

@ -26,11 +26,10 @@ import treq
from canonicaljson import encode_canonical_json from canonicaljson import encode_canonical_json
from prometheus_client import Counter from prometheus_client import Counter
from signedjson.sign import sign_json from signedjson.sign import sign_json
from zope.interface import implementer
from twisted.internet import defer from twisted.internet import defer
from twisted.internet.error import DNSLookupError from twisted.internet.error import DNSLookupError
from twisted.internet.interfaces import IReactorPluggableNameResolver, IReactorTime from twisted.internet.interfaces import IReactorTime
from twisted.internet.task import _EPSILON, Cooperator from twisted.internet.task import _EPSILON, Cooperator
from twisted.web.http_headers import Headers from twisted.web.http_headers import Headers
from twisted.web.iweb import IBodyProducer, IResponse from twisted.web.iweb import IBodyProducer, IResponse
@ -45,7 +44,7 @@ from synapse.api.errors import (
from synapse.http import QuieterFileBodyProducer from synapse.http import QuieterFileBodyProducer
from synapse.http.client import ( from synapse.http.client import (
BlacklistingAgentWrapper, BlacklistingAgentWrapper,
IPBlacklistingResolver, BlacklistingReactorWrapper,
encode_query_args, encode_query_args,
readBodyToFile, readBodyToFile,
) )
@ -221,24 +220,12 @@ class MatrixFederationHttpClient:
self.signing_key = hs.signing_key self.signing_key = hs.signing_key
self.server_name = hs.hostname self.server_name = hs.hostname
real_reactor = hs.get_reactor()
# We need to use a DNS resolver which filters out blacklisted IP # We need to use a DNS resolver which filters out blacklisted IP
# addresses, to prevent DNS rebinding. # addresses, to prevent DNS rebinding.
nameResolver = IPBlacklistingResolver( self.reactor = BlacklistingReactorWrapper(
real_reactor, None, hs.config.federation_ip_range_blacklist hs.get_reactor(), None, hs.config.federation_ip_range_blacklist
) )
@implementer(IReactorPluggableNameResolver)
class Reactor:
def __getattr__(_self, attr):
if attr == "nameResolver":
return nameResolver
else:
return getattr(real_reactor, attr)
self.reactor = Reactor()
user_agent = hs.version_string user_agent = hs.version_string
if hs.config.user_agent_suffix: if hs.config.user_agent_suffix:
user_agent = "%s %s" % (user_agent, hs.config.user_agent_suffix) user_agent = "%s %s" % (user_agent, hs.config.user_agent_suffix)