From 4e333c310a0a1659b93923d71395b06fbbdefd09 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 1 Oct 2025 16:28:34 +0100 Subject: [PATCH] Add a new `get_ip_address_from_request` method This method raises a `SynapseException` if Synapse is unable to extract the IP address of a client from an incoming request. This typically indicates that there is an invalid configuration in one's reverse proxy. Raise an exception rather than returning a dummy IP address, as it's typically better to fail loudly in this case. --- synapse/api/auth/__init__.py | 16 ++++++++++++++++ synapse/api/auth/base.py | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/synapse/api/auth/__init__.py b/synapse/api/auth/__init__.py index d253938329..0dd520cdae 100644 --- a/synapse/api/auth/__init__.py +++ b/synapse/api/auth/__init__.py @@ -188,6 +188,22 @@ class Auth(Protocol): request """ + @staticmethod + def get_ip_address_from_request(request: Request) -> str: + """ + Extract the IPv4 or IPv6 address from a client request. + + Args: + request: The request to process. + + Returns: + The IPv4 or IPv6 address of the client. + + Raises: + SynapseError: If an IP address could not be extracted from the + request. + """ + async def check_user_in_room_or_world_readable( self, room_id: str, requester: Requester, allow_departed_users: bool = False ) -> Tuple[str, Optional[str]]: diff --git a/synapse/api/auth/base.py b/synapse/api/auth/base.py index 76c8c71628..7f957dae18 100644 --- a/synapse/api/auth/base.py +++ b/synapse/api/auth/base.py @@ -19,10 +19,12 @@ # # import logging +from http import HTTPStatus from typing import TYPE_CHECKING, Optional, Tuple from netaddr import IPAddress +from twisted.internet.address import IPv4Address, IPv6Address from twisted.web.server import Request from synapse import event_auth @@ -31,6 +33,7 @@ from synapse.api.errors import ( AuthError, Codes, MissingClientTokenError, + SynapseError, UnstableSpecAuthError, ) from synapse.appservice import ApplicationService @@ -291,6 +294,36 @@ class BaseAuth: return query_params[0].decode("ascii") + @staticmethod + def get_ip_address_from_request(request: Request) -> str: + """ + Extract the IPv4 or IPv6 address from a client request. + + Args: + request: The request to process. + + Returns: + The IPv4 or IPv6 address of the client. + + Raises: + SynapseError: If an IP address could not be extracted from the + request. + """ + client_address = request.getClientAddress() + if not isinstance(client_address, IPv4Address) and not isinstance( + client_address, IPv6Address + ): + logger.error( + "Unable to view IP address of the requester. Check that you are setting the X-Forwarded-For header correctly in your reverse proxy. Assuming '127.0.0.1'" + ) + raise SynapseError( + HTTPStatus.INTERNAL_SERVER_ERROR, + "Unable to read client IP address", + Codes.UNKNOWN, + ) + + return client_address.host + @cancellable async def get_appservice_user( self, request: Request, access_token: str