mirror of
https://github.com/infinite-iroha/touka.git
synced 2026-02-02 16:31:11 +08:00
update reqip
This commit is contained in:
parent
99b48371b3
commit
295852e1a1
1 changed files with 44 additions and 25 deletions
63
context.go
63
context.go
|
|
@ -14,7 +14,6 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"mime"
|
"mime"
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
@ -523,39 +522,59 @@ func (c *Context) GetReqBodyBuffer() (*bytes.Buffer, error) {
|
||||||
func (c *Context) RequestIP() string {
|
func (c *Context) RequestIP() string {
|
||||||
if c.engine.ForwardByClientIP {
|
if c.engine.ForwardByClientIP {
|
||||||
for _, headerName := range c.engine.RemoteIPHeaders {
|
for _, headerName := range c.engine.RemoteIPHeaders {
|
||||||
if ipValue := c.Request.Header.Get(headerName); ipValue != "" {
|
ipValue := c.Request.Header.Get(headerName)
|
||||||
// X-Forwarded-For 可能包含多个 IP,约定第一个(最左边)是客户端 IP
|
if ipValue == "" {
|
||||||
// 其他头部(如 X-Real-IP)通常只有一个
|
continue // 头部为空, 继续检查下一个
|
||||||
ips := strings.Split(ipValue, ",")
|
}
|
||||||
for _, singleIP := range ips {
|
|
||||||
trimmedIP := strings.TrimSpace(singleIP)
|
// 使用索引高效遍历逗号分隔的 IP 列表, 避免 strings.Split 的内存分配
|
||||||
// 使用 netip.ParseAddr 进行 IP 地址的解析和格式验证
|
currentPos := 0
|
||||||
|
for currentPos < len(ipValue) {
|
||||||
|
nextComma := strings.IndexByte(ipValue[currentPos:], ',')
|
||||||
|
|
||||||
|
var ipSegment string
|
||||||
|
if nextComma == -1 {
|
||||||
|
// 这是列表中的最后一个 IP
|
||||||
|
ipSegment = ipValue[currentPos:]
|
||||||
|
currentPos = len(ipValue) // 结束循环
|
||||||
|
} else {
|
||||||
|
// 截取当前 IP 段
|
||||||
|
ipSegment = ipValue[currentPos : currentPos+nextComma]
|
||||||
|
currentPos += nextComma + 1 // 移动到下一个 IP 段的起始位置
|
||||||
|
}
|
||||||
|
|
||||||
|
// 去除空格并检查是否为空 (例如 "ip1,,ip2")
|
||||||
|
trimmedIP := strings.TrimSpace(ipSegment)
|
||||||
|
if trimmedIP == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 netip.ParseAddr 进行 IP 地址的解析和验证
|
||||||
addr, err := netip.ParseAddr(trimmedIP)
|
addr, err := netip.ParseAddr(trimmedIP)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// 成功解析到合法的 IP 地址格式,立即返回
|
// 成功解析到合法的 IP, 立即返回
|
||||||
return addr.String()
|
return addr.String()
|
||||||
}
|
}
|
||||||
// 如果当前 singleIP 无效,继续检查列表中的下一个
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果没有启用 ForwardByClientIP 或头部中没有找到有效 IP,回退到 Request.RemoteAddr
|
// 回退到 Request.RemoteAddr 的处理
|
||||||
// RemoteAddr 通常是 "host:port" 格式,但也可能直接就是 IP 地址
|
// 优先使用 netip.ParseAddrPort, 它比 net.SplitHostPort 更高效且分配更少
|
||||||
remoteAddrStr := c.Request.RemoteAddr
|
addrp, err := netip.ParseAddrPort(c.Request.RemoteAddr)
|
||||||
ip, _, err := net.SplitHostPort(remoteAddrStr) // 尝试分离 host 和 port
|
if err == nil {
|
||||||
if err != nil {
|
// 成功从 "ip:port" 格式中解析出 IP
|
||||||
// 如果分离失败,意味着 remoteAddrStr 可能直接就是 IP 地址(或畸形)
|
return addrp.String()
|
||||||
ip = remoteAddrStr // 此时将整个 remoteAddrStr 作为候选 IP
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 对从 RemoteAddr 中提取/使用的 IP 进行最终的合法性验证
|
// 如果上面的解析失败 (例如 RemoteAddr 只有 IP, 没有端口),
|
||||||
addr, parseErr := netip.ParseAddr(ip)
|
// 则尝试将整个字符串作为 IP 地址进行解析
|
||||||
if parseErr == nil {
|
addr, err := netip.ParseAddr(c.Request.RemoteAddr)
|
||||||
return addr.String() // 成功解析并返回合法 IP
|
if err == nil {
|
||||||
|
return addr.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 所有方法都失败, 返回空字符串
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue