mirror of
https://github.com/golang/net.git
synced 2026-03-31 18:37:08 +09:00
When matching against a host "example.com", don't match an IPv6 address like "[1000::1%25.example.com]:80". Thanks to Juho Forsén of Mattermost for reporting this issue. Fixes CVE-2025-22870 For #71984 Change-Id: I0c4fdf18765decc27e6ddf220ebe3a9bf4a6454d Reviewed-on: https://go-review.googlesource.com/c/net/+/654697 Auto-Submit: Roland Shoemaker <roland@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Commit-Queue: Roland Shoemaker <roland@golang.org> Reviewed-by: Roland Shoemaker <roland@golang.org> Reviewed-by: Damien Neil <dneil@google.com>
141 lines
3.0 KiB
Go
141 lines
3.0 KiB
Go
// Copyright 2011 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package proxy
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"slices"
|
|
"testing"
|
|
)
|
|
|
|
type recordingProxy struct {
|
|
addrs []string
|
|
}
|
|
|
|
func (r *recordingProxy) Dial(network, addr string) (net.Conn, error) {
|
|
r.addrs = append(r.addrs, addr)
|
|
return nil, errors.New("recordingProxy")
|
|
}
|
|
|
|
func TestPerHost(t *testing.T) {
|
|
for _, test := range []struct {
|
|
config string // passed to PerHost.AddFromString
|
|
nomatch []string // addrs using the default dialer
|
|
match []string // addrs using the bypass dialer
|
|
}{{
|
|
config: "localhost,*.zone,127.0.0.1,10.0.0.1/8,1000::/16",
|
|
nomatch: []string{
|
|
"example.com:123",
|
|
"1.2.3.4:123",
|
|
"[1001::]:123",
|
|
},
|
|
match: []string{
|
|
"localhost:123",
|
|
"zone:123",
|
|
"foo.zone:123",
|
|
"127.0.0.1:123",
|
|
"10.1.2.3:123",
|
|
"[1000::]:123",
|
|
"[1000::%25.example.com]:123",
|
|
},
|
|
}, {
|
|
config: "localhost",
|
|
nomatch: []string{
|
|
"127.0.0.1:80",
|
|
},
|
|
match: []string{
|
|
"localhost:80",
|
|
},
|
|
}, {
|
|
config: "*.zone",
|
|
nomatch: []string{
|
|
"foo.com:80",
|
|
},
|
|
match: []string{
|
|
"foo.zone:80",
|
|
"foo.bar.zone:80",
|
|
},
|
|
}, {
|
|
config: "1.2.3.4",
|
|
nomatch: []string{
|
|
"127.0.0.1:80",
|
|
"11.2.3.4:80",
|
|
},
|
|
match: []string{
|
|
"1.2.3.4:80",
|
|
},
|
|
}, {
|
|
config: "10.0.0.0/24",
|
|
nomatch: []string{
|
|
"10.0.1.1:80",
|
|
},
|
|
match: []string{
|
|
"10.0.0.1:80",
|
|
"10.0.0.255:80",
|
|
},
|
|
}, {
|
|
config: "fe80::/10",
|
|
nomatch: []string{
|
|
"[fec0::1]:80",
|
|
"[fec0::1%en0]:80",
|
|
},
|
|
match: []string{
|
|
"[fe80::1]:80",
|
|
"[fe80::1%en0]:80",
|
|
},
|
|
}, {
|
|
// We don't allow zone IDs in network prefixes,
|
|
// so this config matches nothing.
|
|
config: "fe80::%en0/10",
|
|
nomatch: []string{
|
|
"[fec0::1]:80",
|
|
"[fec0::1%en0]:80",
|
|
"[fe80::1]:80",
|
|
"[fe80::1%en0]:80",
|
|
"[fe80::1%en1]:80",
|
|
},
|
|
}} {
|
|
for _, addr := range test.match {
|
|
testPerHost(t, test.config, addr, true)
|
|
}
|
|
for _, addr := range test.nomatch {
|
|
testPerHost(t, test.config, addr, false)
|
|
}
|
|
}
|
|
}
|
|
|
|
func testPerHost(t *testing.T, config, addr string, wantMatch bool) {
|
|
name := fmt.Sprintf("config %q, dial %q", config, addr)
|
|
|
|
var def, bypass recordingProxy
|
|
perHost := NewPerHost(&def, &bypass)
|
|
perHost.AddFromString(config)
|
|
perHost.Dial("tcp", addr)
|
|
|
|
// Dial and DialContext should have the same results.
|
|
var defc, bypassc recordingProxy
|
|
perHostc := NewPerHost(&defc, &bypassc)
|
|
perHostc.AddFromString(config)
|
|
perHostc.DialContext(context.Background(), "tcp", addr)
|
|
if !slices.Equal(def.addrs, defc.addrs) {
|
|
t.Errorf("%v: Dial default=%v, bypass=%v; DialContext default=%v, bypass=%v", name, def.addrs, bypass.addrs, defc.addrs, bypass.addrs)
|
|
return
|
|
}
|
|
|
|
if got, want := slices.Concat(def.addrs, bypass.addrs), []string{addr}; !slices.Equal(got, want) {
|
|
t.Errorf("%v: dialed %q, want %q", name, got, want)
|
|
return
|
|
}
|
|
|
|
gotMatch := len(bypass.addrs) > 0
|
|
if gotMatch != wantMatch {
|
|
t.Errorf("%v: matched=%v, want %v", name, gotMatch, wantMatch)
|
|
return
|
|
}
|
|
}
|