aboutsummaryrefslogtreecommitdiff
path: root/weed/security/guard.go
diff options
context:
space:
mode:
authorChris Lu <chrislusf@users.noreply.github.com>2025-08-06 01:03:00 -0700
committerGitHub <noreply@github.com>2025-08-06 01:03:00 -0700
commit0703308270dad1c31c02f0b0e75c829156748ff8 (patch)
tree4fdb13d90a304570a8e111cfcc90ce153bc1011e /weed/security/guard.go
parentc6d97569331eae8e6038b6280f309a80e3a8450f (diff)
downloadseaweedfs-0703308270dad1c31c02f0b0e75c829156748ff8.tar.xz
seaweedfs-0703308270dad1c31c02f0b0e75c829156748ff8.zip
remote address parsing should handle special cases (#7101)
* remote address parsing should handle special cases * handling ipv6 * simplify * Update weed/security/guard.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update weed/security/guard.go Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * x-real-ip * Update guard.go * fixes Hostname Whitelisting: Fully restored - supports localhost, example.com, etc. IP Whitelisting: Still works - supports exact IPs and CIDR ranges Header Support: Consistent handling of X-Forwarded-For, X-Real-IP * simplify * Update weed/security/guard.go Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update weed/security/guard.go Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update guard.go * adjust function signature * Update weed/security/guard.go Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * indention * skip empty host --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Diffstat (limited to 'weed/security/guard.go')
-rw-r--r--weed/security/guard.go73
1 files changed, 54 insertions, 19 deletions
diff --git a/weed/security/guard.go b/weed/security/guard.go
index f92b10044..a857c8549 100644
--- a/weed/security/guard.go
+++ b/weed/security/guard.go
@@ -3,10 +3,11 @@ package security
import (
"errors"
"fmt"
- "github.com/seaweedfs/seaweedfs/weed/glog"
"net"
"net/http"
"strings"
+
+ "github.com/seaweedfs/seaweedfs/weed/glog"
)
var (
@@ -75,18 +76,51 @@ func (g *Guard) WhiteList(f http.HandlerFunc) http.HandlerFunc {
}
}
-func GetActualRemoteHost(r *http.Request) (host string, err error) {
- host = r.Header.Get("HTTP_X_FORWARDED_FOR")
+func GetActualRemoteHost(r *http.Request) string {
+ // Check X-Forwarded-For headers first (may contain comma-separated IPs)
+ // HTTP_X_FORWARDED_FOR is used for SeaweedFS internal communication when master proxies to leader
+ host := r.Header.Get("HTTP_X_FORWARDED_FOR")
if host == "" {
host = r.Header.Get("X-FORWARDED-FOR")
}
- if strings.Contains(host, ",") {
- host = host[0:strings.Index(host, ",")]
+ if host != "" {
+ for _, ipStr := range strings.Split(host, ",") {
+ host = strings.TrimSpace(ipStr)
+ if host != "" {
+ break
+ }
+ }
}
+
+ // If no valid IP from X-Forwarded-For, try X-Real-IP (single IP)
if host == "" {
- host, _, err = net.SplitHostPort(r.RemoteAddr)
+ host = r.Header.Get("X-Real-IP")
+ }
+
+ // If we got a host from headers, use it (can be IP or hostname)
+ if host != "" {
+ if host = strings.TrimSpace(host); host != "" {
+ return host
+ }
+ }
+
+ // If no host from headers, extract from RemoteAddr
+ host, _, err := net.SplitHostPort(r.RemoteAddr)
+ if err == nil {
+ return host
+ }
+
+ // If SplitHostPort fails, it may be because of a missing port.
+ // We try to parse RemoteAddr as a raw host (IP or hostname).
+ host = strings.TrimSpace(r.RemoteAddr)
+ // It might be an IPv6 address without a port, but with brackets.
+ // e.g. "[::1]"
+ if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
+ host = host[1 : len(host)-1]
}
- return
+
+ // Return the host (can be IP or hostname, just like headers)
+ return host
}
func (g *Guard) checkWhiteList(w http.ResponseWriter, r *http.Request) error {
@@ -94,26 +128,27 @@ func (g *Guard) checkWhiteList(w http.ResponseWriter, r *http.Request) error {
return nil
}
- host, err := GetActualRemoteHost(r)
- if err != nil {
- return fmt.Errorf("get actual remote host %s in checkWhiteList failed: %v", r.RemoteAddr, err)
- }
+ host := GetActualRemoteHost(r)
+ // Check exact match first (works for both IPs and hostnames)
if _, ok := g.whiteListIp[host]; ok {
return nil
}
- for _, cidrnet := range g.whiteListCIDR {
- // If the whitelist entry contains a "/" it
- // is a CIDR range, and we should check the
- remote := net.ParseIP(host)
- if cidrnet.Contains(remote) {
- return nil
+ // Check CIDR ranges (only for valid IP addresses)
+ remote := net.ParseIP(host)
+ if remote != nil {
+ for _, cidrnet := range g.whiteListCIDR {
+ // If the whitelist entry contains a "/" it
+ // is a CIDR range, and we should check the
+ if cidrnet.Contains(remote) {
+ return nil
+ }
}
}
- glog.V(0).Infof("Not in whitelist: %s", r.RemoteAddr)
- return fmt.Errorf("Not in whitelist: %s", r.RemoteAddr)
+ glog.V(0).Infof("Not in whitelist: %s (original RemoteAddr: %s)", host, r.RemoteAddr)
+ return fmt.Errorf("Not in whitelist: %s", host)
}
func (g *Guard) UpdateWhiteList(whiteList []string) {