[Bug 295882] www/seahub: seafdav does not log real client IP address
Date: Fri, 05 Jun 2026 18:26:39 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=295882
Bug ID: 295882
Summary: www/seahub: seafdav does not log real client IP
address
Product: Ports & Packages
Version: Latest
Hardware: Any
OS: Any
Status: New
Severity: Affects Some People
Priority: ---
Component: Individual Port(s)
Assignee: ports-bugs@FreeBSD.org
Reporter: lloydsystems1@tpg.com.au
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.
--
You are receiving this mail because:
You are the assignee for the bug.