mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-19 00:36:38 +00:00
Set forwarded headers from trusted proxies only
This commit is contained in:
@@ -1,43 +1,16 @@
|
||||
package accesslog
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"slices"
|
||||
"strings"
|
||||
"net/netip"
|
||||
|
||||
"github.com/netbirdio/netbird/proxy/internal/proxy"
|
||||
)
|
||||
|
||||
// requestIP attempts to extract the source IP from a request.
|
||||
// Adapted from https://husobee.github.io/golang/ip-address/2015/12/17/remote-ip-go.html
|
||||
// with the addition of some newer stdlib functions that are now
|
||||
// available.
|
||||
// The concept here is to look backwards through IP headers until
|
||||
// the first public IP address is found. The hypothesis is that
|
||||
// even if there are multiple IP addresses specified in these headers,
|
||||
// the last public IP should be the hop immediately before reaching
|
||||
// the server and therefore represents the "true" source IP regardless
|
||||
// of the number of intermediate proxies or network hops.
|
||||
func extractSourceIP(r *http.Request) string {
|
||||
for _, h := range []string{"X-Forwarded-For", "X-Real-IP"} {
|
||||
addresses := strings.Split(r.Header.Get(h), ",")
|
||||
// Iterate from right to left until we get a public address
|
||||
// that should be the address right before our proxy.
|
||||
for _, address := range slices.Backward(addresses) {
|
||||
// Trim the address because sometimes clients put whitespace in there.
|
||||
ip := strings.TrimSpace(address)
|
||||
// Parse the IP so that we can easily check whether it is a valid public address.
|
||||
realIP := net.ParseIP(ip)
|
||||
if !realIP.IsGlobalUnicast() || realIP.IsPrivate() || realIP.IsLoopback() {
|
||||
continue
|
||||
}
|
||||
return ip
|
||||
}
|
||||
}
|
||||
// Fallback to the requests RemoteAddr, this is least likely to be correct but
|
||||
// should at least yield something in the event that the above has failed.
|
||||
ip, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||
if err != nil {
|
||||
ip = r.RemoteAddr
|
||||
}
|
||||
return ip
|
||||
// extractSourceIP resolves the real client IP from the request using trusted
|
||||
// proxy configuration. When trustedProxies is non-empty and the direct
|
||||
// connection is from a trusted source, it walks X-Forwarded-For right-to-left
|
||||
// skipping trusted IPs. Otherwise it returns RemoteAddr directly.
|
||||
func extractSourceIP(r *http.Request, trustedProxies []netip.Prefix) string {
|
||||
return proxy.ResolveClientIP(r.RemoteAddr, r.Header.Get("X-Forwarded-For"), trustedProxies)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user