Bug 295882 - www/seahub: seafdav does not log real client IP address
Summary: www/seahub: seafdav does not log real client IP address
Status: New
Alias: None
Product: Ports & Packages
Classification: Unclassified
Component: Individual Port(s) (show other bugs)
Version: Latest
Hardware: Any Any
: --- Affects Some People
Assignee: freebsd-ports-bugs (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2026-06-05 18:26 UTC by LloydSystems
Modified: 2026-06-05 18:26 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description LloydSystems 2026-06-05 18:26:39 UTC
Seafile server version 11.0.12 running on FreeBSD 14 with WebDAV extension enabled.

The seafdav.log file records all client requests as coming from 127.0.0.1 (the Apache reverse proxy) rather than the real client IP address. Given that Seafile will be running behind an Apache or Nginx proxy 99% of the time, I can’t imagine any case where this would be at all useful.

I have this in the Apache virtual host:

<Location /seafdav>
    ProxyPass http://127.0.0.1:8081/seafdav
    RequestHeader set X-Forwarded-Proto "https"
    RequestHeader set X-Forwarded-For %{REMOTE_ADDR}s
</Location>

Expected behaviour is to look for and log the X-Forwarded-For header, but it does not.

The Seafile manual recommends using Fail2Ban to protect the server. This should logically apply to the SeafDAV service also, but it needs the remote IP address.

By searching the code I found the routine responsible for logging the client requests is /usr/local/www/haiwen/seafile-server/seahub/thirdpart/wsgidav/wsgidav_app.py and patched it to add xff as shown below.

class WsgiDAVApp:
...
    def __call__(self, environ, start_response):
    # util.log(“SCRIPT_NAME={!r}, PATH_INFO={!r}”.format(
    #    environ.get(“SCRIPT_NAME”), environ.get(“PATH_INFO”)))

        path = environ["PATH_INFO"]

        # --- Added ---
        xff = environ.get("HTTP_X_FORWARDED_FOR")
        if xff:
            environ["REMOTE_ADDR"] = xff.split(",")[0].strip()
        # --- End ---

Now seafdav.log shows the real client IP address, but more needs to be done to properly protect SeafDAV with Fail2Ban.

Due to the default behaviour of WebDAV, valid clients will generate “401 Not Authorized” errors in the log before they authenticate. When processed by Fail2Ban, these false positives could block legitimate users. A more reliable indicator for Fail2Ban would be the “Authentication (basic) failed for user” messages, but these do not include the IP address.

The file /usr/local/www/haiwen/seafile-server/seahub/thirdpart/wsgidav/http_authenticator.py is responsible for logging authentication failures. The code was patched to read REMOTE_ADDR and append it to the log entries.

class HTTPAuthenticator(BaseMiddleware):
    ...
    def handle_basic_auth_request(self, environ, start_response):
        realm = self.domain_controller.get_domain_realm(environ["PATH_INFO"], environ)
        auth_header = environ["HTTP_AUTHORIZATION"]
        auth_value = ""
        try:
            auth_value = auth_header[len("Basic ") :].strip()
        except Exception:
            auth_value = ""

        auth_value = base64.decodebytes(util.to_bytes(auth_value))
        auth_value = util.to_str(auth_value)
        user_name, password = auth_value.split(":", 1)

        # --- Get client IP ---
        client_ip = environ.get("REMOTE_ADDR", "unknown")

        if self.domain_controller.basic_auth_user(realm, user_name, password, environ):
            environ["wsgidav.auth.realm"] = realm
            environ["wsgidav.auth.user_name"] = user_name
            return self.next_app(environ, start_response)

        # --- Append client IP ---
        _logger.warning(
            "Authentication (basic) failed for user {!r}, realm {!r}, IP {!r}.".format(
                user_name, realm, client_ip

The seafdav.log can now be parsed with a Fail2Ban filter like this:

[Definition]

failregex = ^.*WARNING\s+:\s+Authentication \([^)]*\) failed for user '[^']*', realm '[^']*', IP '<HOST>'\.$

ignoreregex = 

I think the SeafDAV code should be fixed to make the logging useful and workable for Fail2Ban, as it is recommended by Seafile.