Browse Source

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>
pull/7103/head
Chris Lu 2 months ago
committed by GitHub
parent
commit
0703308270
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 73
      weed/security/guard.go
  2. 6
      weed/server/master_server.go

73
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) {

6
weed/server/master_server.go

@ -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…
Cancel
Save