caddyhttp: Convert IDNs to ASCII when provisioning Host matcher

This commit is contained in:
Matthew Holt 2024-06-18 14:43:54 -06:00
parent fab6375a8b
commit 99dcdf7e42
2 changed files with 23 additions and 6 deletions

View File

@ -34,6 +34,7 @@ import (
"github.com/google/cel-go/cel"
"github.com/google/cel-go/common/types"
"github.com/google/cel-go/common/types/ref"
"golang.org/x/net/idna"
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
@ -239,13 +240,20 @@ func (m *MatchHost) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
func (m MatchHost) Provision(_ caddy.Context) error {
// check for duplicates; they are nonsensical and reduce efficiency
// (we could just remove them, but the user should know their config is erroneous)
seen := make(map[string]int)
for i, h := range m {
h = strings.ToLower(h)
if firstI, ok := seen[h]; ok {
return fmt.Errorf("host at index %d is repeated at index %d: %s", firstI, i, h)
seen := make(map[string]int, len(m))
for i, host := range m {
asciiHost, err := idna.ToASCII(host)
if err != nil {
return fmt.Errorf("converting hostname '%s' to ASCII: %v", host, err)
}
seen[h] = i
if asciiHost != host {
m[i] = asciiHost
}
normalizedHost := strings.ToLower(asciiHost)
if firstI, ok := seen[normalizedHost]; ok {
return fmt.Errorf("host at index %d is repeated at index %d: %s", firstI, i, host)
}
seen[normalizedHost] = i
}
if m.large() {

View File

@ -78,6 +78,11 @@ func TestHostMatcher(t *testing.T) {
input: "bar.example.com",
expect: false,
},
{
match: MatchHost{"éxàmplê.com"},
input: "xn--xmpl-0na6cm.com",
expect: true,
},
{
match: MatchHost{"*.example.com"},
input: "example.com",
@ -149,6 +154,10 @@ func TestHostMatcher(t *testing.T) {
ctx := context.WithValue(req.Context(), caddy.ReplacerCtxKey, repl)
req = req.WithContext(ctx)
if err := tc.match.Provision(caddy.Context{}); err != nil {
t.Errorf("Test %d %v: provisioning failed: %v", i, tc.match, err)
}
actual := tc.match.Match(req)
if actual != tc.expect {
t.Errorf("Test %d %v: Expected %t, got %t for '%s'", i, tc.match, tc.expect, actual, tc.input)