Files
orbit/internal/transport/httpserver/console_login.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()
}