Merge e4e36348b52f730146f4eafffe8882fa3f4333b1 into d3ffc9985281dcf4d3bef604cce4e662b1a327a6

This commit is contained in:
阿震 2026-03-17 11:26:59 +09:00 committed by GitHub
commit 43a95889ae
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 128 additions and 1 deletions

26
gin.go
View File

@ -483,9 +483,33 @@ func (engine *Engine) validateHeader(header string) (clientIP string, valid bool
if header == "" {
return "", false
}
var ipStr string
items := strings.Split(header, ",")
for i := len(items) - 1; i >= 0; i-- {
ipStr := strings.TrimSpace(items[i])
item := strings.TrimSpace(items[i])
// [IPv6] or [IPv6]:port
if strings.HasPrefix(item, "[") {
if idx := strings.IndexByte(item, ']'); idx > 0 {
ipPart := item[1:idx]
if ip := net.ParseIP(ipPart); ip != nil {
if idx == len(item)-1 || (idx+1 < len(item) && item[idx+1] == ':') {
ipStr = ipPart
}
}
}
} else if ip := net.ParseIP(item); ip != nil {
// plain IPv4 or IPv6
ipStr = item
} else if idx := strings.LastIndexByte(item, ':'); idx > 0 {
// IPv4:port
ipPart := item[:idx]
if ip := net.ParseIP(ipPart); ip != nil {
ipStr = ipPart
}
}
if ipStr == "" {
break
}
ip := net.ParseIP(ipStr)
if ip == nil {
break

View File

@ -1156,3 +1156,106 @@ func TestUpdateRouteTreesCalledOnce(t *testing.T) {
assert.Equal(t, "ok", w.Body.String())
}
}
func TestValidateHeader_IssueCases(t *testing.T) {
r := New()
err := r.SetTrustedProxies([]string{"0.0.0.0/0", "::/0"})
if err != nil {
t.Fatalf("SetTrustedProxies failed: %v", err)
}
tests := []struct {
name string
header string
wantIP string
wantValid bool
}{
{
name: "IPv4 plain",
header: "127.0.0.1",
wantIP: "127.0.0.1",
wantValid: true,
},
{
name: "IPv4 with port (ARR/IIS)",
header: "127.0.0.1:38792",
wantIP: "127.0.0.1",
wantValid: true,
},
{
name: "IPv6 plain",
header: "240e:318:2f4a:de56::240",
wantIP: "240e:318:2f4a:de56::240",
wantValid: true,
},
{
name: "IPv6 with brackets (IIS style)",
header: "[240e:318:2f4a:de56::240]",
wantIP: "240e:318:2f4a:de56::240",
wantValid: true,
},
{
name: "IPv6 with brackets + port (ARR/IIS or cloud LB)",
header: "[240e:318:2f4a:de56::240]:38792",
wantIP: "240e:318:2f4a:de56::240",
wantValid: true,
},
{
name: "invalid ip",
header: "abc",
wantIP: "",
wantValid: false,
},
{
name: "ipv6 missing closing bracket",
header: "[240e:318:2f4a:de56::240",
wantIP: "",
wantValid: false,
},
{
name: "ipv6 bracket invalid suffix",
header: "[240e:318:2f4a:de56::240]abc",
wantIP: "",
wantValid: false,
},
{
name: "multiple ipv4",
header: "1.1.1.1, 127.0.0.1",
wantIP: "1.1.1.1",
wantValid: true,
},
{
name: "multiple ipv6",
header: "240e:318:2f4a:de56::111, 240e:318:2f4a:de56::240",
wantIP: "240e:318:2f4a:de56::111",
wantValid: true,
},
{
name: "full",
header: "1.1.1.1, 127.0.0.1, 192.168.3.1:5050, 240e:318:2f4a:de56::1111, [240e:318:2f4a:de56::2222], [240e:318:2f4a:de56::3333]:7080",
wantIP: "1.1.1.1",
wantValid: true,
},
// ---------- empty / whitespace ----------
{
name: "empty header",
header: "",
wantIP: "",
wantValid: false,
},
{
name: "whitespace header",
header: " ",
wantIP: "",
wantValid: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ip, valid := r.validateHeader(tt.header)
assert.Equal(t, tt.wantIP, ip)
assert.Equal(t, tt.wantValid, valid)
})
}
}