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

Commit 232b324

Browse files
Port "Add support for no_proxy and case insensitive env variables" from mainline to dinsic (#93)
This PR is simply porting matrix-org/synapse#9372 to dinsic. I also had to bring in matrix-org/synapse#8821 and matrix-org/synapse#9084 for this code to work properly - a sign that we should merge mainline into dinsic again soon.
1 parent 396e7d4 commit 232b324

Some content is hidden

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

48 files changed

+398
-154
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.

changelog.d/9084.bugfix

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Don't blacklist connections to the configured proxy. Contributed by @Bubu.

changelog.d/9372.feature

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
The `no_proxy` and `NO_PROXY` environment variables are now respected in proxied HTTP clients with the lowercase form taking precedence if both are present. Additionally, the lowercase `https_proxy` environment variable is now respected in proxied HTTP clients on top of existing support for the uppercase `HTTPS_PROXY` form and takes precedence if both are present. Contributed by Timothy Leung.

docs/sample_config.yaml

+8-6
Original file line numberDiff line numberDiff line change
@@ -710,17 +710,19 @@ acme:
710710
# - nyc.example.com
711711
# - syd.example.com
712712

713-
# Prevent federation requests from being sent to the following
714-
# blacklist IP address CIDR ranges. If this option is not specified, or
715-
# specified with an empty list, no ip range blacklist will be enforced.
713+
# Prevent outgoing requests from being sent to the following blacklisted IP address
714+
# CIDR ranges. If this option is not specified, or specified with an empty list,
715+
# no IP range blacklist will be enforced.
716716
#
717-
# As of Synapse v1.4.0 this option also affects any outbound requests to identity
718-
# servers provided by user input.
717+
# The blacklist applies to the outbound requests for federation, identity servers,
718+
# push servers, and for checking key validitity for third-party invite events.
719719
#
720720
# (0.0.0.0 and :: are always blacklisted, whether or not they are explicitly
721721
# listed here, since they correspond to unroutable addresses.)
722722
#
723-
federation_ip_range_blacklist:
723+
# This option replaces federation_ip_range_blacklist in Synapse v1.24.0.
724+
#
725+
ip_range_blacklist:
724726
- '127.0.0.0/8'
725727
- '10.0.0.0/8'
726728
- '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
@@ -916,7 +916,6 @@ class FederationHandlerRegistry:
916916

917917
def __init__(self, hs: "HomeServer"):
918918
self.config = hs.config
919-
self.http_client = hs.get_simple_http_client()
920919
self.clock = hs.get_clock()
921920
self._instance_name = hs.get_instance_name()
922921

synapse/federation/transport/client.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class TransportLayerClient:
3838

3939
def __init__(self, hs):
4040
self.server_name = hs.hostname
41-
self.client = hs.get_http_client()
41+
self.client = hs.get_federation_http_client()
4242

4343
@log_function
4444
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
@@ -141,7 +141,7 @@ def __init__(self, hs: "HomeServer"):
141141
self._message_handler = hs.get_message_handler()
142142
self._server_notices_mxid = hs.config.server_notices_mxid
143143
self.config = hs.config
144-
self.http_client = hs.get_simple_http_client()
144+
self.http_client = hs.get_proxied_blacklisted_http_client()
145145
self._instance_name = hs.get_instance_name()
146146
self._replication = hs.get_replication_data_handler()
147147

synapse/handlers/identity.py

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

49-
self.hs = hs
49+
# An HTTP client for contacting trusted URLs.
5050
self.http_client = hs.get_simple_http_client()
51-
# We create a blacklisting instance of SimpleHttpClient for contacting identity
52-
# servers specified by clients
51+
# An HTTP client for contacting identity servers specified by clients.
5352
self.blacklisting_http_client = SimpleHttpClient(
5453
hs, ip_blacklist=hs.config.federation_ip_range_blacklist
5554
)
56-
self.federation_http_client = hs.get_http_client()
55+
self.federation_http_client = hs.get_federation_http_client()
56+
self.hs = hs
5757

5858
self.trusted_id_servers = set(hs.config.trusted_third_party_id_servers)
5959
self.trust_any_id_server_just_for_testing_do_not_use = (

synapse/http/client.py

+37-20
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
@@ -260,8 +289,7 @@ def __init__(
260289
treq_args: Dict[str, Any] = {},
261290
ip_whitelist: Optional[IPSet] = None,
262291
ip_blacklist: Optional[IPSet] = None,
263-
http_proxy: Optional[bytes] = None,
264-
https_proxy: Optional[bytes] = None,
292+
use_proxy: bool = False,
265293
):
266294
"""
267295
Args:
@@ -271,8 +299,8 @@ def __init__(
271299
we may not request.
272300
ip_whitelist: The whitelisted IP addresses, that we can
273301
request if it were otherwise caught in a blacklist.
274-
http_proxy: proxy server to use for http connections. host[:port]
275-
https_proxy: proxy server to use for https connections. host[:port]
302+
use_proxy: Whether proxy settings should be discovered and used
303+
from conventional environment variables.
276304
"""
277305
self.hs = hs
278306

@@ -292,22 +320,11 @@ def __init__(
292320
self.user_agent = self.user_agent.encode("ascii")
293321

294322
if self._ip_blacklist:
295-
real_reactor = hs.get_reactor()
296323
# If we have an IP blacklist, we need to use a DNS resolver which
297324
# filters out blacklisted IP addresses, to prevent DNS rebinding.
298-
nameResolver = IPBlacklistingResolver(
299-
real_reactor, self._ip_whitelist, self._ip_blacklist
325+
self.reactor = BlacklistingReactorWrapper(
326+
hs.get_reactor(), self._ip_whitelist, self._ip_blacklist
300327
)
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()
311328
else:
312329
self.reactor = hs.get_reactor()
313330

@@ -323,11 +340,11 @@ def __getattr__(_self, attr):
323340

324341
self.agent = ProxyAgent(
325342
self.reactor,
343+
hs.get_reactor(),
326344
connectTimeout=15,
327345
contextFactory=self.hs.get_http_client_context_factory(),
328346
pool=pool,
329-
http_proxy=http_proxy,
330-
https_proxy=https_proxy,
347+
use_proxy=use_proxy,
331348
)
332349

333350
if self._ip_blacklist:

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

0 commit comments

Comments
 (0)