58 lines
1.4 KiB
Go
58 lines
1.4 KiB
Go
package httpserver
|
|
|
|
import (
|
|
"git.yuntuo.hk/k2safe/orbit/internal/consoleauth"
|
|
"net/http"
|
|
"net/netip"
|
|
"strings"
|
|
)
|
|
|
|
// loginRemoteAddress 默认只信任 TCP 对端;仅受信反代可提供 X-Forwarded-For。
|
|
// 从右往左剥离可信跳点,遇到首个非可信地址即停止;不接受任意客户端伪造的首项。
|
|
func loginRemoteAddress(r *http.Request, store consoleauth.Store) string {
|
|
peer, err := netip.ParseAddr(remoteAddress(r))
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
peer = peer.Unmap()
|
|
policyStore, ok := store.(interface {
|
|
LoginPolicy() consoleauth.LoginPolicy
|
|
})
|
|
if !ok {
|
|
return peer.String()
|
|
}
|
|
trusted := policyStore.LoginPolicy().TrustedProxies
|
|
isTrusted := func(ip netip.Addr) bool {
|
|
for _, n := range trusted {
|
|
if n.Contains(ip) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
if !isTrusted(peer) {
|
|
return peer.String()
|
|
}
|
|
raw := strings.Join(r.Header.Values("X-Forwarded-For"), ",")
|
|
if raw == "" || len(raw) > 2048 {
|
|
return peer.String()
|
|
}
|
|
hops := strings.Split(raw, ",")
|
|
if len(hops) > 32 {
|
|
return peer.String()
|
|
}
|
|
addresses := make([]netip.Addr, len(hops))
|
|
for i, h := range hops {
|
|
a, e := netip.ParseAddr(strings.TrimSpace(h))
|
|
if e != nil {
|
|
return peer.String()
|
|
}
|
|
addresses[i] = a.Unmap()
|
|
}
|
|
current := peer
|
|
for i := len(addresses) - 1; i >= 0 && isTrusted(current); i-- {
|
|
current = addresses[i]
|
|
}
|
|
return current.String()
|
|
}
|