This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ClientIP returns the client address for access control, using X-Forwarded-For /
|
||||
// X-Real-IP only when the direct peer is in trusted CIDRs.
|
||||
func ClientIP(r *http.Request, trusted []netip.Prefix) netip.Addr {
|
||||
host, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||
if err != nil {
|
||||
host = r.RemoteAddr
|
||||
}
|
||||
peer, err := netip.ParseAddr(host)
|
||||
if err != nil {
|
||||
return netip.Addr{}
|
||||
}
|
||||
if !containsIP(trusted, peer) {
|
||||
return peer
|
||||
}
|
||||
if xff := r.Header.Get("X-Forwarded-For"); xff != "" {
|
||||
parts := strings.Split(xff, ",")
|
||||
for _, p := range parts {
|
||||
p = strings.TrimSpace(p)
|
||||
if p == "" {
|
||||
continue
|
||||
}
|
||||
if a, err := netip.ParseAddr(p); err == nil {
|
||||
return a
|
||||
}
|
||||
}
|
||||
}
|
||||
if xr := strings.TrimSpace(r.Header.Get("X-Real-IP")); xr != "" {
|
||||
if a, err := netip.ParseAddr(xr); err == nil {
|
||||
return a
|
||||
}
|
||||
}
|
||||
return peer
|
||||
}
|
||||
|
||||
func containsIP(prefixes []netip.Prefix, addr netip.Addr) bool {
|
||||
for _, p := range prefixes {
|
||||
if p.Contains(addr) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Allowed reports whether addr matches whitelist rules.
|
||||
func Allowed(addr netip.Addr, allowAll bool, whitelist []netip.Prefix) bool {
|
||||
if !addr.IsValid() {
|
||||
return false
|
||||
}
|
||||
if allowAll {
|
||||
return true
|
||||
}
|
||||
if len(whitelist) == 0 {
|
||||
return false
|
||||
}
|
||||
return containsIP(whitelist, addr)
|
||||
}
|
||||
Reference in New Issue
Block a user