mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2025-08-20 09:53:01 +08:00
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>
This commit is contained in:
parent
c6d9756933
commit
0703308270
@ -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")
|
||||
}
|
||||
return
|
||||
|
||||
// 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 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) {
|
||||
|
||||
@ -259,10 +259,8 @@ func (ms *MasterServer) proxyToLeader(f http.HandlerFunc) http.HandlerFunc {
|
||||
proxy := httputil.NewSingleHostReverseProxy(targetUrl)
|
||||
director := proxy.Director
|
||||
proxy.Director = func(req *http.Request) {
|
||||
actualHost, err := security.GetActualRemoteHost(req)
|
||||
if err == nil {
|
||||
req.Header.Set("HTTP_X_FORWARDED_FOR", actualHost)
|
||||
}
|
||||
actualHost := security.GetActualRemoteHost(req)
|
||||
req.Header.Set("HTTP_X_FORWARDED_FOR", actualHost)
|
||||
director(req)
|
||||
}
|
||||
proxy.Transport = util_http.GetGlobalHttpClient().GetClientTransport()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user