Repository: matrix-org/synapse

Issue:
Calls to `/_matrix/client/v3/account/whoami` return 500 when called on a unix socket
### Description

I have synapse set up to listen on a unix socket, and mautrix-whatsapp trying to connect to it via that socket. This does not work, as when accessing the `whoami`-endpoint the server returns error code 500 with the message `M_UNKNOWN`.

The homeserver log reveals that this is due to the code expecting a host to be set, when this isn't applicable in a unix socket usecase.

### Steps to reproduce

- Configure synapse to listen on unix socket
- Configure appservice (mautrix-whatsapp) that accesses the `whoami` endpoint to connect to server via unix socket


### Homeserver

self-hosted

### Synapse Version

1.29.1

### Installation Method

Other (please mention below)

### Database

fresh postgresql 15.4 setup

### Workers

Single process

### Platform

archlinux arm

### Configuration

_No response_

### Relevant log output

```shell
2023-09-27 18:04:10,377 - synapse.http.server - 140 - ERROR - GET-660 - Failed handle request via 'WhoamiRestServlet': <XForwardedForRequest at 0
xffff94056e50 method='GET' uri='/_matrix/client/v3/account/whoami?user_id=%40whatsappbot%3Asir-photch.xyz' clientproto='HTTP/1.1' site='unix'>
Traceback (most recent call last):
  File "/usr/lib/python3.11/site-packages/synapse/http/server.py", line 326, in _async_render_wrapper
    callback_return = await self._async_render(request)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/synapse/http/server.py", line 538, in _async_render
    callback_return = await raw_callback_return
                      ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/synapse/rest/client/account.py", line 851, in on_GET
    requester = await self.auth.get_user_by_req(request, allow_guest=True)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/synapse/api/auth/internal.py", line 82, in get_user_by_req
    requester = await self._wrapped_get_user_by_req(
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/synapse/api/auth/internal.py", line 118, in _wrapped_get_user_by_req
    ip_addr = request.getClientAddress().host
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'UNIXAddress' object has no attribute 'host'
```


### Anything else that would be useful to know?

_No response_


Discussion:
Just to check my sanity: you are using an 'appservice' user and not your actual user_id for the bridge, right?
It looks like this line:

https://github.com/matrix-org/synapse/blob/954921736b88de25c775c519a206449e46b3bf07/synapse/api/auth/internal.py#L118

Needs to be updated to use [`get_client_ip_if_available`](https://github.com/matrix-org/synapse/blob/1c802de626de3293049206cb788af15cbc8ea17f/synapse/http/site.py#L508-L526).
> Just to check my sanity: you are using an 'appservice' user and not your actual user_id for the bridge, right?

So when it's configured to go through localhost, the bridge successfully asks for the whatsappbot-user. Does that answer your question?
Comparing with my own server, I'm seeing a 502:

```
"synapse_inbound_client_readers" "synapse_inbound_client_readers" >> - "- [28/Sep/2023:18:00:43 +0000] "GET /_matrix/client/v3/account/whoami HTTP/1.1" 502 150 "-" "mautrix-gmessages/0.2.0+dev.622daca7 mautrix-go/v0.16.1 go/1.21.1" 0.000
```

Curiously though, whoami seems to work correctly when a user_id is provided in the query string:

```
"synapse_inbound_client_readers" "unix:/sockets/synapse_inbound_client_reader3.sock" >> - "- [28/Sep/2023:18:00:50 +0000] "GET /_matrix/client/v3/account/whoami?user_id=@signalbot:tcpip.uk HTTP/1.1" 200 92 "-" "mautrix-signal/0.4.3 mautrix-python/0.19.14 aiohttp/3.8.3 Python/3.10.11" 0.004
```
Hm, did this get fixed in 1.93?

Resolving patch:
diff --git a/synapse/api/auth/internal.py b/synapse/api/auth/internal.py
--- a/synapse/api/auth/internal.py
+++ b/synapse/api/auth/internal.py
@@ -115,7 +115,7 @@ async def _wrapped_get_user_by_req(
         Once get_user_by_req has set up the opentracing span, this does the actual work.
         """
         try:
-            ip_addr = request.getClientAddress().host
+            ip_addr = request.get_client_ip_if_available()
             user_agent = get_request_user_agent(request)
 
             access_token = self.get_access_token_from_request(request)


Test patch: