From 4ca054a4eaa714d0befb4fc30b19a1131e52c9cc Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 3 Feb 2021 07:13:46 -0500 Subject: Convert blacklisted IPv4 addresses to compatible IPv6 addresses. (#9240) Also add a few more IP ranges to the default blacklist. --- synapse/config/repository.py | 19 ++++----- synapse/config/server.py | 99 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 91 insertions(+), 27 deletions(-) (limited to 'synapse/config') diff --git a/synapse/config/repository.py b/synapse/config/repository.py index 850ac3ebd6..fcaea8fb93 100644 --- a/synapse/config/repository.py +++ b/synapse/config/repository.py @@ -17,9 +17,7 @@ import os from collections import namedtuple from typing import Dict, List -from netaddr import IPSet - -from synapse.config.server import DEFAULT_IP_RANGE_BLACKLIST +from synapse.config.server import DEFAULT_IP_RANGE_BLACKLIST, generate_ip_set from synapse.python_dependencies import DependencyException, check_requirements from synapse.util.module_loader import load_module @@ -187,16 +185,17 @@ class ContentRepositoryConfig(Config): "to work" ) - self.url_preview_ip_range_blacklist = IPSet( - config["url_preview_ip_range_blacklist"] - ) - # we always blacklist '0.0.0.0' and '::', which are supposed to be # unroutable addresses. - self.url_preview_ip_range_blacklist.update(["0.0.0.0", "::"]) + self.url_preview_ip_range_blacklist = generate_ip_set( + config["url_preview_ip_range_blacklist"], + ["0.0.0.0", "::"], + config_path=("url_preview_ip_range_blacklist",), + ) - self.url_preview_ip_range_whitelist = IPSet( - config.get("url_preview_ip_range_whitelist", ()) + self.url_preview_ip_range_whitelist = generate_ip_set( + config.get("url_preview_ip_range_whitelist", ()), + config_path=("url_preview_ip_range_whitelist",), ) self.url_preview_url_blacklist = config.get("url_preview_url_blacklist", ()) diff --git a/synapse/config/server.py b/synapse/config/server.py index 47a0370173..b5e82ba3d0 100644 --- a/synapse/config/server.py +++ b/synapse/config/server.py @@ -15,6 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import itertools import logging import os.path import re @@ -23,7 +24,7 @@ from typing import Any, Dict, Iterable, List, Optional, Set import attr import yaml -from netaddr import IPSet +from netaddr import AddrFormatError, IPNetwork, IPSet from synapse.api.room_versions import KNOWN_ROOM_VERSIONS from synapse.util.stringutils import parse_and_validate_server_name @@ -40,6 +41,66 @@ logger = logging.Logger(__name__) # in the list. DEFAULT_BIND_ADDRESSES = ["::", "0.0.0.0"] + +def _6to4(network: IPNetwork) -> IPNetwork: + """Convert an IPv4 network into a 6to4 IPv6 network per RFC 3056.""" + + # 6to4 networks consist of: + # * 2002 as the first 16 bits + # * The first IPv4 address in the network hex-encoded as the next 32 bits + # * The new prefix length needs to include the bits from the 2002 prefix. + hex_network = hex(network.first)[2:] + hex_network = ("0" * (8 - len(hex_network))) + hex_network + return IPNetwork( + "2002:%s:%s::/%d" % (hex_network[:4], hex_network[4:], 16 + network.prefixlen,) + ) + + +def generate_ip_set( + ip_addresses: Optional[Iterable[str]], + extra_addresses: Optional[Iterable[str]] = None, + config_path: Optional[Iterable[str]] = None, +) -> IPSet: + """ + Generate an IPSet from a list of IP addresses or CIDRs. + + Additionally, for each IPv4 network in the list of IP addresses, also + includes the corresponding IPv6 networks. + + This includes: + + * IPv4-Compatible IPv6 Address (see RFC 4291, section 2.5.5.1) + * IPv4-Mapped IPv6 Address (see RFC 4291, section 2.5.5.2) + * 6to4 Address (see RFC 3056, section 2) + + Args: + ip_addresses: An iterable of IP addresses or CIDRs. + extra_addresses: An iterable of IP addresses or CIDRs. + config_path: The path in the configuration for error messages. + + Returns: + A new IP set. + """ + result = IPSet() + for ip in itertools.chain(ip_addresses or (), extra_addresses or ()): + try: + network = IPNetwork(ip) + except AddrFormatError as e: + raise ConfigError( + "Invalid IP range provided: %s." % (ip,), config_path + ) from e + result.add(network) + + # It is possible that these already exist in the set, but that's OK. + if ":" not in str(network): + result.add(IPNetwork(network).ipv6(ipv4_compatible=True)) + result.add(IPNetwork(network).ipv6(ipv4_compatible=False)) + result.add(_6to4(network)) + + return result + + +# IP ranges that are considered private / unroutable / don't make sense. DEFAULT_IP_RANGE_BLACKLIST = [ # Localhost "127.0.0.0/8", @@ -53,6 +114,8 @@ DEFAULT_IP_RANGE_BLACKLIST = [ "192.0.0.0/24", # Link-local networks. "169.254.0.0/16", + # Formerly used for 6to4 relay. + "192.88.99.0/24", # Testing networks. "198.18.0.0/15", "192.0.2.0/24", @@ -66,6 +129,12 @@ DEFAULT_IP_RANGE_BLACKLIST = [ "fe80::/10", # Unique local addresses. "fc00::/7", + # Testing networks. + "2001:db8::/32", + # Multicast. + "ff00::/8", + # Site-local addresses + "fec0::/10", ] DEFAULT_ROOM_VERSION = "6" @@ -294,17 +363,15 @@ class ServerConfig(Config): ) # Attempt to create an IPSet from the given ranges - try: - self.ip_range_blacklist = IPSet(ip_range_blacklist) - except Exception as e: - raise ConfigError("Invalid range(s) provided in ip_range_blacklist.") from e + # Always blacklist 0.0.0.0, :: - self.ip_range_blacklist.update(["0.0.0.0", "::"]) + self.ip_range_blacklist = generate_ip_set( + ip_range_blacklist, ["0.0.0.0", "::"], config_path=("ip_range_blacklist",) + ) - try: - self.ip_range_whitelist = IPSet(config.get("ip_range_whitelist", ())) - except Exception as e: - raise ConfigError("Invalid range(s) provided in ip_range_whitelist.") from e + self.ip_range_whitelist = generate_ip_set( + config.get("ip_range_whitelist", ()), config_path=("ip_range_whitelist",) + ) # The federation_ip_range_blacklist is used for backwards-compatibility # and only applies to federation and identity servers. If it is not given, @@ -312,14 +379,12 @@ class ServerConfig(Config): federation_ip_range_blacklist = config.get( "federation_ip_range_blacklist", ip_range_blacklist ) - try: - self.federation_ip_range_blacklist = IPSet(federation_ip_range_blacklist) - except Exception as e: - raise ConfigError( - "Invalid range(s) provided in federation_ip_range_blacklist." - ) from e # Always blacklist 0.0.0.0, :: - self.federation_ip_range_blacklist.update(["0.0.0.0", "::"]) + self.federation_ip_range_blacklist = generate_ip_set( + federation_ip_range_blacklist, + ["0.0.0.0", "::"], + config_path=("federation_ip_range_blacklist",), + ) self.start_pushers = config.get("start_pushers", True) -- cgit 1.5.1 From e4cdecb3107727d17c34b253d65cd56e2acd526b Mon Sep 17 00:00:00 2001 From: dykstranet Date: Wed, 3 Feb 2021 23:21:30 +0800 Subject: config: Add detail to auto_join_rooms comment (#9291) config: Add detail to auto_join_rooms comment Signed-off-by: Gary Dykstra --- changelog.d/9291.doc | 1 + docs/sample_config.yaml | 2 ++ synapse/config/registration.py | 2 ++ 3 files changed, 5 insertions(+) create mode 100644 changelog.d/9291.doc (limited to 'synapse/config') diff --git a/changelog.d/9291.doc b/changelog.d/9291.doc new file mode 100644 index 0000000000..422acd3891 --- /dev/null +++ b/changelog.d/9291.doc @@ -0,0 +1 @@ +Add note to `auto_join_rooms` config option explaining existing rooms must be publicly joinable. diff --git a/docs/sample_config.yaml b/docs/sample_config.yaml index 0e323846fa..601a8338eb 100644 --- a/docs/sample_config.yaml +++ b/docs/sample_config.yaml @@ -1328,6 +1328,8 @@ account_threepid_delegates: # By default, any room aliases included in this list will be created # as a publicly joinable room when the first user registers for the # homeserver. This behaviour can be customised with the settings below. +# If the room already exists, make certain it is a publicly joinable +# room. The join rule of the room must be set to 'public'. # #auto_join_rooms: # - "#example:example.com" diff --git a/synapse/config/registration.py b/synapse/config/registration.py index ac48913a0b..afb3e0b2a1 100644 --- a/synapse/config/registration.py +++ b/synapse/config/registration.py @@ -378,6 +378,8 @@ class RegistrationConfig(Config): # By default, any room aliases included in this list will be created # as a publicly joinable room when the first user registers for the # homeserver. This behaviour can be customised with the settings below. + # If the room already exists, make certain it is a publicly joinable + # room. The join rule of the room must be set to 'public'. # #auto_join_rooms: # - "#example:example.com" -- cgit 1.5.1 From afa18f1baa58317a0747c4ef07e224ff49871da7 Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Wed, 3 Feb 2021 14:51:38 -0500 Subject: Clarify documentation about escaping URLs in templates. (#9310) --- changelog.d/9310.doc | 1 + docs/sample_config.yaml | 14 ++++---------- synapse/config/sso.py | 14 ++++---------- 3 files changed, 9 insertions(+), 20 deletions(-) create mode 100644 changelog.d/9310.doc (limited to 'synapse/config') diff --git a/changelog.d/9310.doc b/changelog.d/9310.doc new file mode 100644 index 0000000000..f61705b73a --- /dev/null +++ b/changelog.d/9310.doc @@ -0,0 +1 @@ +Clarify the sample configuration for changes made to the template loading code. diff --git a/docs/sample_config.yaml b/docs/sample_config.yaml index 6d265d2972..236abd9a3f 100644 --- a/docs/sample_config.yaml +++ b/docs/sample_config.yaml @@ -1961,8 +1961,7 @@ sso: # # When rendering, this template is given the following variables: # * redirect_url: the URL that the user will be redirected to after - # login. Needs manual escaping (see - # https://jinja.palletsprojects.com/en/2.11.x/templates/#html-escaping). + # login. # # * server_name: the homeserver's name. # @@ -2040,15 +2039,12 @@ sso: # # When rendering, this template is given the following variables: # - # * redirect_url: the URL the user is about to be redirected to. Needs - # manual escaping (see - # https://jinja.palletsprojects.com/en/2.11.x/templates/#html-escaping). + # * redirect_url: the URL the user is about to be redirected to. # # * display_url: the same as `redirect_url`, but with the query # parameters stripped. The intention is to have a # human-readable URL to show to users, not to use it as - # the final address to redirect to. Needs manual escaping - # (see https://jinja.palletsprojects.com/en/2.11.x/templates/#html-escaping). + # the final address to redirect to. # # * server_name: the homeserver's name. # @@ -2068,9 +2064,7 @@ sso: # process: 'sso_auth_confirm.html'. # # When rendering, this template is given the following variables: - # * redirect_url: the URL the user is about to be redirected to. Needs - # manual escaping (see - # https://jinja.palletsprojects.com/en/2.11.x/templates/#html-escaping). + # * redirect_url: the URL the user is about to be redirected to. # # * description: the operation which the user is being asked to confirm # diff --git a/synapse/config/sso.py b/synapse/config/sso.py index 939eeac6de..6c60c6fea4 100644 --- a/synapse/config/sso.py +++ b/synapse/config/sso.py @@ -106,8 +106,7 @@ class SSOConfig(Config): # # When rendering, this template is given the following variables: # * redirect_url: the URL that the user will be redirected to after - # login. Needs manual escaping (see - # https://jinja.palletsprojects.com/en/2.11.x/templates/#html-escaping). + # login. # # * server_name: the homeserver's name. # @@ -185,15 +184,12 @@ class SSOConfig(Config): # # When rendering, this template is given the following variables: # - # * redirect_url: the URL the user is about to be redirected to. Needs - # manual escaping (see - # https://jinja.palletsprojects.com/en/2.11.x/templates/#html-escaping). + # * redirect_url: the URL the user is about to be redirected to. # # * display_url: the same as `redirect_url`, but with the query # parameters stripped. The intention is to have a # human-readable URL to show to users, not to use it as - # the final address to redirect to. Needs manual escaping - # (see https://jinja.palletsprojects.com/en/2.11.x/templates/#html-escaping). + # the final address to redirect to. # # * server_name: the homeserver's name. # @@ -213,9 +209,7 @@ class SSOConfig(Config): # process: 'sso_auth_confirm.html'. # # When rendering, this template is given the following variables: - # * redirect_url: the URL the user is about to be redirected to. Needs - # manual escaping (see - # https://jinja.palletsprojects.com/en/2.11.x/templates/#html-escaping). + # * redirect_url: the URL the user is about to be redirected to. # # * description: the operation which the user is being asked to confirm # -- cgit 1.5.1 From 2ab6e67ab73ff4ed0264116853a3eaf66a66d3ba Mon Sep 17 00:00:00 2001 From: Patrick Cloke Date: Thu, 4 Feb 2021 09:06:20 -0500 Subject: Fix escaping of braces in OIDC sample config. (#9317) This fixes the Jinja2 templates for the mapping provider. --- changelog.d/9317.doc | 1 + docs/sample_config.yaml | 10 +++++----- synapse/config/oidc_config.py | 10 +++++----- 3 files changed, 11 insertions(+), 10 deletions(-) create mode 100644 changelog.d/9317.doc (limited to 'synapse/config') diff --git a/changelog.d/9317.doc b/changelog.d/9317.doc new file mode 100644 index 0000000000..f4d508e090 --- /dev/null +++ b/changelog.d/9317.doc @@ -0,0 +1 @@ +Fix the braces in the `oidc_providers` section of the sample config. diff --git a/docs/sample_config.yaml b/docs/sample_config.yaml index 9dbba63bac..fbbf71edd9 100644 --- a/docs/sample_config.yaml +++ b/docs/sample_config.yaml @@ -1872,9 +1872,9 @@ oidc_providers: # user_mapping_provider: # config: # subject_claim: "id" - # localpart_template: "{ user.login }" - # display_name_template: "{ user.name }" - # email_template: "{ user.email }" + # localpart_template: "{{ user.login }}" + # display_name_template: "{{ user.name }}" + # email_template: "{{ user.email }}" # For use with Keycloak # @@ -1901,8 +1901,8 @@ oidc_providers: # user_mapping_provider: # config: # subject_claim: "id" - # localpart_template: "{ user.login }" - # display_name_template: "{ user.name }" + # localpart_template: "{{ user.login }}" + # display_name_template: "{{ user.name }}" # Enable Central Authentication Service (CAS) for registration and login. diff --git a/synapse/config/oidc_config.py b/synapse/config/oidc_config.py index 4c24c50629..9d8196d8c3 100644 --- a/synapse/config/oidc_config.py +++ b/synapse/config/oidc_config.py @@ -198,9 +198,9 @@ class OIDCConfig(Config): # user_mapping_provider: # config: # subject_claim: "id" - # localpart_template: "{{ user.login }}" - # display_name_template: "{{ user.name }}" - # email_template: "{{ user.email }}" + # localpart_template: "{{{{ user.login }}}}" + # display_name_template: "{{{{ user.name }}}}" + # email_template: "{{{{ user.email }}}}" # For use with Keycloak # @@ -227,8 +227,8 @@ class OIDCConfig(Config): # user_mapping_provider: # config: # subject_claim: "id" - # localpart_template: "{{ user.login }}" - # display_name_template: "{{ user.name }}" + # localpart_template: "{{{{ user.login }}}}" + # display_name_template: "{{{{ user.name }}}}" """.format( mapping_provider=DEFAULT_USER_MAPPING_PROVIDER ) -- cgit 1.5.1