Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit 30fba62

Browse files
authored
Apply an IP range blacklist to push and key revocation requests. (#8821)
Replaces the `federation_ip_range_blacklist` configuration setting with an `ip_range_blacklist` setting with wider scope. It now applies to: * Federation * Identity servers * Push notifications * Checking key validitity for third-party invite events The old `federation_ip_range_blacklist` setting is still honored if present, but with reduced scope (it only applies to federation and identity servers).
1 parent c5b6abd commit 30fba62

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+176
-115
lines changed

changelog.d/8821.bugfix

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Apply the `federation_ip_range_blacklist` to push and key revocation requests.

docs/sample_config.yaml

+8-6
Original file line numberDiff line numberDiff line change
@@ -642,17 +642,19 @@ acme:
642642
# - nyc.example.com
643643
# - syd.example.com
644644

645-
# Prevent federation requests from being sent to the following
646-
# blacklist IP address CIDR ranges. If this option is not specified, or
647-
# specified with an empty list, no ip range blacklist will be enforced.
645+
# Prevent outgoing requests from being sent to the following blacklisted IP address
646+
# CIDR ranges. If this option is not specified, or specified with an empty list,
647+
# no IP range blacklist will be enforced.
648648
#
649-
# As of Synapse v1.4.0 this option also affects any outbound requests to identity
650-
# servers provided by user input.
649+
# The blacklist applies to the outbound requests for federation, identity servers,
650+
# push servers, and for checking key validitity for third-party invite events.
651651
#
652652
# (0.0.0.0 and :: are always blacklisted, whether or not they are explicitly
653653
# listed here, since they correspond to unroutable addresses.)
654654
#
655-
federation_ip_range_blacklist:
655+
# This option replaces federation_ip_range_blacklist in Synapse v1.24.0.
656+
#
657+
ip_range_blacklist:
656658
- '127.0.0.0/8'
657659
- '10.0.0.0/8'
658660
- '172.16.0.0/12'

synapse/app/generic_worker.py

-1
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,6 @@ def __init__(self, hs):
266266
super().__init__(hs)
267267
self.hs = hs
268268
self.is_mine_id = hs.is_mine_id
269-
self.http_client = hs.get_simple_http_client()
270269

271270
self._presence_enabled = hs.config.use_presence
272271

synapse/config/federation.py

+25-15
Original file line numberDiff line numberDiff line change
@@ -36,22 +36,30 @@ def read_config(self, config, **kwargs):
3636
for domain in federation_domain_whitelist:
3737
self.federation_domain_whitelist[domain] = True
3838

39-
self.federation_ip_range_blacklist = config.get(
40-
"federation_ip_range_blacklist", []
41-
)
39+
ip_range_blacklist = config.get("ip_range_blacklist", [])
4240

4341
# Attempt to create an IPSet from the given ranges
4442
try:
45-
self.federation_ip_range_blacklist = IPSet(
46-
self.federation_ip_range_blacklist
47-
)
48-
49-
# Always blacklist 0.0.0.0, ::
50-
self.federation_ip_range_blacklist.update(["0.0.0.0", "::"])
43+
self.ip_range_blacklist = IPSet(ip_range_blacklist)
44+
except Exception as e:
45+
raise ConfigError("Invalid range(s) provided in ip_range_blacklist: %s" % e)
46+
# Always blacklist 0.0.0.0, ::
47+
self.ip_range_blacklist.update(["0.0.0.0", "::"])
48+
49+
# The federation_ip_range_blacklist is used for backwards-compatibility
50+
# and only applies to federation and identity servers. If it is not given,
51+
# default to ip_range_blacklist.
52+
federation_ip_range_blacklist = config.get(
53+
"federation_ip_range_blacklist", ip_range_blacklist
54+
)
55+
try:
56+
self.federation_ip_range_blacklist = IPSet(federation_ip_range_blacklist)
5157
except Exception as e:
5258
raise ConfigError(
5359
"Invalid range(s) provided in federation_ip_range_blacklist: %s" % e
5460
)
61+
# Always blacklist 0.0.0.0, ::
62+
self.federation_ip_range_blacklist.update(["0.0.0.0", "::"])
5563

5664
federation_metrics_domains = config.get("federation_metrics_domains") or []
5765
validate_config(
@@ -76,17 +84,19 @@ def generate_config_section(self, config_dir_path, server_name, **kwargs):
7684
# - nyc.example.com
7785
# - syd.example.com
7886
79-
# Prevent federation requests from being sent to the following
80-
# blacklist IP address CIDR ranges. If this option is not specified, or
81-
# specified with an empty list, no ip range blacklist will be enforced.
87+
# Prevent outgoing requests from being sent to the following blacklisted IP address
88+
# CIDR ranges. If this option is not specified, or specified with an empty list,
89+
# no IP range blacklist will be enforced.
8290
#
83-
# As of Synapse v1.4.0 this option also affects any outbound requests to identity
84-
# servers provided by user input.
91+
# The blacklist applies to the outbound requests for federation, identity servers,
92+
# push servers, and for checking key validitity for third-party invite events.
8593
#
8694
# (0.0.0.0 and :: are always blacklisted, whether or not they are explicitly
8795
# listed here, since they correspond to unroutable addresses.)
8896
#
89-
federation_ip_range_blacklist:
97+
# This option replaces federation_ip_range_blacklist in Synapse v1.24.0.
98+
#
99+
ip_range_blacklist:
90100
- '127.0.0.0/8'
91101
- '10.0.0.0/8'
92102
- '172.16.0.0/12'

synapse/crypto/keyring.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -578,7 +578,7 @@ class PerspectivesKeyFetcher(BaseV2KeyFetcher):
578578
def __init__(self, hs):
579579
super().__init__(hs)
580580
self.clock = hs.get_clock()
581-
self.client = hs.get_http_client()
581+
self.client = hs.get_federation_http_client()
582582
self.key_servers = self.config.key_servers
583583

584584
async def get_keys(self, keys_to_fetch):
@@ -748,7 +748,7 @@ class ServerKeyFetcher(BaseV2KeyFetcher):
748748
def __init__(self, hs):
749749
super().__init__(hs)
750750
self.clock = hs.get_clock()
751-
self.client = hs.get_http_client()
751+
self.client = hs.get_federation_http_client()
752752

753753
async def get_keys(self, keys_to_fetch):
754754
"""

synapse/federation/federation_server.py

-1
Original file line numberDiff line numberDiff line change
@@ -845,7 +845,6 @@ class FederationHandlerRegistry:
845845

846846
def __init__(self, hs: "HomeServer"):
847847
self.config = hs.config
848-
self.http_client = hs.get_simple_http_client()
849848
self.clock = hs.get_clock()
850849
self._instance_name = hs.get_instance_name()
851850

synapse/federation/transport/client.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class TransportLayerClient:
3535

3636
def __init__(self, hs):
3737
self.server_name = hs.hostname
38-
self.client = hs.get_http_client()
38+
self.client = hs.get_federation_http_client()
3939

4040
@log_function
4141
def get_room_state_ids(self, destination, room_id, event_id):

synapse/handlers/federation.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ def __init__(self, hs: "HomeServer"):
140140
self._message_handler = hs.get_message_handler()
141141
self._server_notices_mxid = hs.config.server_notices_mxid
142142
self.config = hs.config
143-
self.http_client = hs.get_simple_http_client()
143+
self.http_client = hs.get_proxied_blacklisted_http_client()
144144
self._instance_name = hs.get_instance_name()
145145
self._replication = hs.get_replication_data_handler()
146146

synapse/handlers/identity.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,13 @@ class IdentityHandler(BaseHandler):
4646
def __init__(self, hs):
4747
super().__init__(hs)
4848

49+
# An HTTP client for contacting trusted URLs.
4950
self.http_client = SimpleHttpClient(hs)
50-
# We create a blacklisting instance of SimpleHttpClient for contacting identity
51-
# servers specified by clients
51+
# An HTTP client for contacting identity servers specified by clients.
5252
self.blacklisting_http_client = SimpleHttpClient(
5353
hs, ip_blacklist=hs.config.federation_ip_range_blacklist
5454
)
55-
self.federation_http_client = hs.get_http_client()
55+
self.federation_http_client = hs.get_federation_http_client()
5656
self.hs = hs
5757

5858
async def threepid_from_creds(

synapse/http/client.py

+32-14
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ def _scheduler(x):
125125
return _scheduler
126126

127127

128-
class IPBlacklistingResolver:
128+
class _IPBlacklistingResolver:
129129
"""
130130
A proxy for reactor.nameResolver which only produces non-blacklisted IP
131131
addresses, preventing DNS rebinding attacks on URL preview.
@@ -199,6 +199,35 @@ def resolutionComplete() -> None:
199199
return r
200200

201201

202+
@implementer(IReactorPluggableNameResolver)
203+
class BlacklistingReactorWrapper:
204+
"""
205+
A Reactor wrapper which will prevent DNS resolution to blacklisted IP
206+
addresses, to prevent DNS rebinding.
207+
"""
208+
209+
def __init__(
210+
self,
211+
reactor: IReactorPluggableNameResolver,
212+
ip_whitelist: Optional[IPSet],
213+
ip_blacklist: IPSet,
214+
):
215+
self._reactor = reactor
216+
217+
# We need to use a DNS resolver which filters out blacklisted IP
218+
# addresses, to prevent DNS rebinding.
219+
self._nameResolver = _IPBlacklistingResolver(
220+
self._reactor, ip_whitelist, ip_blacklist
221+
)
222+
223+
def __getattr__(self, attr: str) -> Any:
224+
# Passthrough to the real reactor except for the DNS resolver.
225+
if attr == "nameResolver":
226+
return self._nameResolver
227+
else:
228+
return getattr(self._reactor, attr)
229+
230+
202231
class BlacklistingAgentWrapper(Agent):
203232
"""
204233
An Agent wrapper which will prevent access to IP addresses being accessed
@@ -292,22 +321,11 @@ def __init__(
292321
self.user_agent = self.user_agent.encode("ascii")
293322

294323
if self._ip_blacklist:
295-
real_reactor = hs.get_reactor()
296324
# If we have an IP blacklist, we need to use a DNS resolver which
297325
# filters out blacklisted IP addresses, to prevent DNS rebinding.
298-
nameResolver = IPBlacklistingResolver(
299-
real_reactor, self._ip_whitelist, self._ip_blacklist
326+
self.reactor = BlacklistingReactorWrapper(
327+
hs.get_reactor(), self._ip_whitelist, self._ip_blacklist
300328
)
301-
302-
@implementer(IReactorPluggableNameResolver)
303-
class Reactor:
304-
def __getattr__(_self, attr):
305-
if attr == "nameResolver":
306-
return nameResolver
307-
else:
308-
return getattr(real_reactor, attr)
309-
310-
self.reactor = Reactor()
311329
else:
312330
self.reactor = hs.get_reactor()
313331

synapse/http/federation/matrix_federation_agent.py

+12-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import urllib.parse
1717
from typing import List, Optional
1818

19-
from netaddr import AddrFormatError, IPAddress
19+
from netaddr import AddrFormatError, IPAddress, IPSet
2020
from zope.interface import implementer
2121

2222
from twisted.internet import defer
@@ -31,6 +31,7 @@
3131
from twisted.web.iweb import IAgent, IAgentEndpointFactory, IBodyProducer
3232

3333
from synapse.crypto.context_factory import FederationPolicyForHTTPS
34+
from synapse.http.client import BlacklistingAgentWrapper
3435
from synapse.http.federation.srv_resolver import Server, SrvResolver
3536
from synapse.http.federation.well_known_resolver import WellKnownResolver
3637
from synapse.logging.context import make_deferred_yieldable, run_in_background
@@ -70,6 +71,7 @@ def __init__(
7071
reactor: IReactorCore,
7172
tls_client_options_factory: Optional[FederationPolicyForHTTPS],
7273
user_agent: bytes,
74+
ip_blacklist: IPSet,
7375
_srv_resolver: Optional[SrvResolver] = None,
7476
_well_known_resolver: Optional[WellKnownResolver] = None,
7577
):
@@ -90,12 +92,18 @@ def __init__(
9092
self.user_agent = user_agent
9193

9294
if _well_known_resolver is None:
95+
# Note that the name resolver has already been wrapped in a
96+
# IPBlacklistingResolver by MatrixFederationHttpClient.
9397
_well_known_resolver = WellKnownResolver(
9498
self._reactor,
95-
agent=Agent(
99+
agent=BlacklistingAgentWrapper(
100+
Agent(
101+
self._reactor,
102+
pool=self._pool,
103+
contextFactory=tls_client_options_factory,
104+
),
96105
self._reactor,
97-
pool=self._pool,
98-
contextFactory=tls_client_options_factory,
106+
ip_blacklist=ip_blacklist,
99107
),
100108
user_agent=self.user_agent,
101109
)

synapse/http/matrixfederationclient.py

+8-18
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,10 @@
2626
from canonicaljson import encode_canonical_json
2727
from prometheus_client import Counter
2828
from signedjson.sign import sign_json
29-
from zope.interface import implementer
3029

3130
from twisted.internet import defer
3231
from twisted.internet.error import DNSLookupError
33-
from twisted.internet.interfaces import IReactorPluggableNameResolver, IReactorTime
32+
from twisted.internet.interfaces import IReactorTime
3433
from twisted.internet.task import _EPSILON, Cooperator
3534
from twisted.web.http_headers import Headers
3635
from twisted.web.iweb import IBodyProducer, IResponse
@@ -45,7 +44,7 @@
4544
from synapse.http import QuieterFileBodyProducer
4645
from synapse.http.client import (
4746
BlacklistingAgentWrapper,
48-
IPBlacklistingResolver,
47+
BlacklistingReactorWrapper,
4948
encode_query_args,
5049
readBodyToFile,
5150
)
@@ -221,31 +220,22 @@ def __init__(self, hs, tls_client_options_factory):
221220
self.signing_key = hs.signing_key
222221
self.server_name = hs.hostname
223222

224-
real_reactor = hs.get_reactor()
225-
226223
# We need to use a DNS resolver which filters out blacklisted IP
227224
# addresses, to prevent DNS rebinding.
228-
nameResolver = IPBlacklistingResolver(
229-
real_reactor, None, hs.config.federation_ip_range_blacklist
225+
self.reactor = BlacklistingReactorWrapper(
226+
hs.get_reactor(), None, hs.config.federation_ip_range_blacklist
230227
)
231228

232-
@implementer(IReactorPluggableNameResolver)
233-
class Reactor:
234-
def __getattr__(_self, attr):
235-
if attr == "nameResolver":
236-
return nameResolver
237-
else:
238-
return getattr(real_reactor, attr)
239-
240-
self.reactor = Reactor()
241-
242229
user_agent = hs.version_string
243230
if hs.config.user_agent_suffix:
244231
user_agent = "%s %s" % (user_agent, hs.config.user_agent_suffix)
245232
user_agent = user_agent.encode("ascii")
246233

247234
self.agent = MatrixFederationAgent(
248-
self.reactor, tls_client_options_factory, user_agent
235+
self.reactor,
236+
tls_client_options_factory,
237+
user_agent,
238+
hs.config.federation_ip_range_blacklist,
249239
)
250240

251241
# Use a BlacklistingAgentWrapper to prevent circumventing the IP

synapse/push/httppusher.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def __init__(self, hs, pusherdict):
100100
if "url" not in self.data:
101101
raise PusherConfigException("'url' required in data for HTTP pusher")
102102
self.url = self.data["url"]
103-
self.http_client = hs.get_proxied_http_client()
103+
self.http_client = hs.get_proxied_blacklisted_http_client()
104104
self.data_minus_url = {}
105105
self.data_minus_url.update(self.data)
106106
del self.data_minus_url["url"]

synapse/rest/media/v1/media_repository.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ class MediaRepository:
6666
def __init__(self, hs):
6767
self.hs = hs
6868
self.auth = hs.get_auth()
69-
self.client = hs.get_http_client()
69+
self.client = hs.get_federation_http_client()
7070
self.clock = hs.get_clock()
7171
self.server_name = hs.hostname
7272
self.store = hs.get_datastore()

0 commit comments

Comments
 (0)