diff options
| author | Chris Lu <chrislusf@users.noreply.github.com> | 2025-08-06 01:03:00 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-06 01:03:00 -0700 |
| commit | 0703308270dad1c31c02f0b0e75c829156748ff8 (patch) | |
| tree | 4fdb13d90a304570a8e111cfcc90ce153bc1011e /weed/security/guard.go | |
| parent | c6d97569331eae8e6038b6280f309a80e3a8450f (diff) | |
| download | seaweedfs-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.go | 73 |
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) { |
