[GH-ISSUE #293] Add unauthorized logging to stdout #154

Closed
opened 2026-04-08 16:50:43 +03:00 by zhus · 3 comments
Owner

Originally created by @vuhuy on GitHub (Nov 24, 2023).
Original GitHub issue: https://github.com/sigoden/dufs/issues/293

Specific Demand

It would be nice to see failed basic authentication in the logging. That way, we can use third-party tools like fail2ban to block bots and unwanted visitors. These tools need the client IP address, and perhaps we need to accommodate some reverse proxy setups too.

Thanks for this lightweight project!

Implement Suggestion

This is my quick and dirty implementation to test my setup. I'm pretty sure my coding standard wouldn't meet the quality of this project, I never programmed in rust before, don't even have a compiler and just abused GitHub Actions and notepad to test this. But it might give you an exact idea of what I'm trying to achieve here.

Hacky addition to server.rs

let (user, access_paths) = match guard {
    (None, None) => {
        if let Some(real_ip_header) = headers.get("X-Real-IP") {
            if let Ok(real_ip_str) = real_ip_header.to_str() {
                let timestamp = Local::now().to_rfc3339_opts(SecondsFormat::Secs, true);
                println!("{} basic authentication failed, client: {}", timestamp, real_ip_str);
            }
        }
        self.auth_reject(&mut res)?;
        return Ok(res);
    }
    (Some(_), None) => {
        status_forbid(&mut res);
        return Ok(res);
    }
    (x, Some(y)) => (x, y),
};
  • This example code is really bad. Should probably be cleanly implemented in auth.rs instead.
  • Usage of only X-Real-IP header due to reverse proxy. Should probably look at this header first, if not present, use session.remote_addr().
  • Writes an unauthenticated message before presenting the user with the basic auth browser dialog (which count as 1 failed login attempt using fail2ban).

Systemd example service file

[Unit]
Description=Dufs
After=network.target

[Service]
WorkingDirectory=/opt/dufs
User=dufs
Group=dufs
ExecStart=/opt/dufs/dufs --config /opt/dufs/config.yaml
KillSignal=SIGINT
Restart=always
RestartSec=15
StandardOutput=append:/var/log/dufs.log

[Install]
WantedBy=multi-user.target

Fail2ban example filter

# fail2ban filter configuration for dufs

[Definition]
failregex = ^ basic authentication failed, client: <ADDR>.*$
ignoreregex =

Fail2ban example jail

[dufs]
enabled = true
ports = 80,443
filter = dufs
logpath = /var/log/dufs.log

Nginx reverse proxy configuration snippet

location / {
    proxy_pass http://127.0.0.1:5000;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Protocol $scheme;
    proxy_set_header X-Forwarded-Host $http_host;

    client_max_body_size 2048m;
}
Originally created by @vuhuy on GitHub (Nov 24, 2023). Original GitHub issue: https://github.com/sigoden/dufs/issues/293 ## Specific Demand It would be nice to see failed basic authentication in the logging. That way, we can use third-party tools like fail2ban to block bots and unwanted visitors. These tools need the client IP address, and perhaps we need to accommodate some reverse proxy setups too. Thanks for this lightweight project! ## Implement Suggestion This is my quick and dirty implementation to test my setup. I'm pretty sure my coding standard wouldn't meet the quality of this project, I never programmed in rust before, don't even have a compiler and just abused GitHub Actions and notepad to test this. But it might give you an exact idea of what I'm trying to achieve here. **Hacky addition to server.rs** ``` let (user, access_paths) = match guard { (None, None) => { if let Some(real_ip_header) = headers.get("X-Real-IP") { if let Ok(real_ip_str) = real_ip_header.to_str() { let timestamp = Local::now().to_rfc3339_opts(SecondsFormat::Secs, true); println!("{} basic authentication failed, client: {}", timestamp, real_ip_str); } } self.auth_reject(&mut res)?; return Ok(res); } (Some(_), None) => { status_forbid(&mut res); return Ok(res); } (x, Some(y)) => (x, y), }; ``` - This example code is really bad. Should probably be cleanly implemented in `auth.rs` instead. - Usage of only `X-Real-IP` header due to reverse proxy. Should probably look at this header first, if not present, use `session.remote_addr()`. - Writes an unauthenticated message before presenting the user with the basic auth browser dialog (which count as 1 failed login attempt using fail2ban). **Systemd example service file** ``` [Unit] Description=Dufs After=network.target [Service] WorkingDirectory=/opt/dufs User=dufs Group=dufs ExecStart=/opt/dufs/dufs --config /opt/dufs/config.yaml KillSignal=SIGINT Restart=always RestartSec=15 StandardOutput=append:/var/log/dufs.log [Install] WantedBy=multi-user.target ``` **Fail2ban example filter** ``` # fail2ban filter configuration for dufs [Definition] failregex = ^ basic authentication failed, client: <ADDR>.*$ ignoreregex = ``` **Fail2ban example jail** ``` [dufs] enabled = true ports = 80,443 filter = dufs logpath = /var/log/dufs.log ``` **Nginx reverse proxy configuration snippet** ``` location / { proxy_pass http://127.0.0.1:5000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Protocol $scheme; proxy_set_header X-Forwarded-Host $http_host; client_max_body_size 2048m; } ```
zhus closed this issue 2026-04-08 16:50:44 +03:00
Author
Owner

@sigoden commented on GitHub (Nov 25, 2023):

You can achieve your goals by configuring log-format. @vuhuy

Run dufs with dufs --log-format '$http_x_real_ip "$request" $status'. You will get what you want.

To learn how to config log-format, please see readme.

Log sample:

2023-11-25T11:13:26Z INFO - 112.96.227.213 "GET /" 401

Fail2ban example filter

# fail2ban filter configuration for dufs

[Definition]
failregex = ^.* INFO - <HOST> "<REQUEST>" 401$
ignoreregex =

I have never used fail2ban before, so I wrote the regular expression based on my instincts, it may not be correct.

<!-- gh-comment-id:1826286364 --> @sigoden commented on GitHub (Nov 25, 2023): You can achieve your goals by configuring log-format. @vuhuy Run dufs with `dufs --log-format '$http_x_real_ip "$request" $status'`. You will get what you want. To learn how to config log-format, please see readme. Log sample: ``` 2023-11-25T11:13:26Z INFO - 112.96.227.213 "GET /" 401 ``` Fail2ban example filter ``` # fail2ban filter configuration for dufs [Definition] failregex = ^.* INFO - <HOST> "<REQUEST>" 401$ ignoreregex = ``` > I have never used fail2ban before, so I wrote the regular expression based on my instincts, it may not be correct.
Author
Owner

@vuhuy commented on GitHub (Nov 25, 2023):

Ah, sorry for wasting your time. I totally missed the 401 in the logging. Thank you!

<!-- gh-comment-id:1826286997 --> @vuhuy commented on GitHub (Nov 25, 2023): Ah, sorry for wasting your time. I totally missed the 401 in the logging. Thank you!
Author
Owner

@sigoden commented on GitHub (Nov 25, 2023):

I don't mind, I'm happy if someone likes dufs.

Note: the default log-format is '$remote_addr "$request" $status'. In your case, it is appropriate to use $http_real_ip or $http_x_forwarded_for instead of $remote_addr.

<!-- gh-comment-id:1826288652 --> @sigoden commented on GitHub (Nov 25, 2023): I don't mind, I'm happy if someone likes dufs. Note: the default log-format is `'$remote_addr "$request" $status'`. In your case, it is appropriate to use `$http_real_ip` or `$http_x_forwarded_for` instead of `$remote_addr`.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sigoden/dufs#154