feat: ACL IDN (punycode domains) support

This commit is contained in:
Toby 2023-10-29 14:44:29 -07:00
parent affe092336
commit b2d4bac556
3 changed files with 65 additions and 4 deletions

View File

@ -10,6 +10,7 @@ require (
github.com/stretchr/testify v1.8.4 github.com/stretchr/testify v1.8.4
github.com/txthinking/socks5 v0.0.0-20230325130024-4230056ae301 github.com/txthinking/socks5 v0.0.0-20230325130024-4230056ae301
golang.org/x/crypto v0.14.0 golang.org/x/crypto v0.14.0
golang.org/x/net v0.17.0
google.golang.org/protobuf v1.28.1 google.golang.org/protobuf v1.28.1
) )
@ -28,7 +29,6 @@ require (
go.uber.org/mock v0.3.0 // indirect go.uber.org/mock v0.3.0 // indirect
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect
golang.org/x/mod v0.12.0 // indirect golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/sys v0.13.0 // indirect golang.org/x/sys v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect
golang.org/x/tools v0.11.1 // indirect golang.org/x/tools v0.11.1 // indirect

View File

@ -2,6 +2,8 @@ package acl
import ( import (
"net" "net"
"golang.org/x/net/idna"
) )
type hostMatcher interface { type hostMatcher interface {
@ -30,10 +32,14 @@ type domainMatcher struct {
} }
func (m *domainMatcher) Match(host HostInfo) bool { func (m *domainMatcher) Match(host HostInfo) bool {
if m.Wildcard { name, err := idna.ToUnicode(host.Name)
return deepMatchRune([]rune(host.Name), []rune(m.Pattern)) if err != nil {
name = host.Name
} }
return m.Pattern == host.Name if m.Wildcard {
return deepMatchRune([]rune(name), []rune(m.Pattern))
}
return name == m.Pattern
} }
func deepMatchRune(str, pattern []rune) bool { func deepMatchRune(str, pattern []rune) bool {

View File

@ -162,6 +162,17 @@ func Test_domainMatcher_Match(t *testing.T) {
}, },
want: true, want: true,
}, },
{
name: "non-wildcard IDN match",
fields: fields{
Pattern: "政府.中国",
Wildcard: false,
},
host: HostInfo{
Name: "xn--mxtq1m.xn--fiqs8s",
},
want: true,
},
{ {
name: "non-wildcard no match", name: "non-wildcard no match",
fields: fields{ fields: fields{
@ -173,6 +184,17 @@ func Test_domainMatcher_Match(t *testing.T) {
}, },
want: false, want: false,
}, },
{
name: "non-wildcard IDN no match",
fields: fields{
Pattern: "政府.中国",
Wildcard: false,
},
host: HostInfo{
Name: "xn--mxtq1m.xn--yfro4i67o",
},
want: false,
},
{ {
name: "wildcard match 1", name: "wildcard match 1",
fields: fields{ fields: fields{
@ -195,6 +217,28 @@ func Test_domainMatcher_Match(t *testing.T) {
}, },
want: true, want: true,
}, },
{
name: "wildcard IDN match 1",
fields: fields{
Pattern: "战狼*.com",
Wildcard: true,
},
host: HostInfo{
Name: "xn--2-x14by21c.com",
},
want: true,
},
{
name: "wildcard IDN match 2",
fields: fields{
Pattern: "*大学*",
Wildcard: true,
},
host: HostInfo{
Name: "xn--xkry9kk1bz66a.xn--ses554g",
},
want: true,
},
{ {
name: "wildcard no match", name: "wildcard no match",
fields: fields{ fields: fields{
@ -206,6 +250,17 @@ func Test_domainMatcher_Match(t *testing.T) {
}, },
want: false, want: false,
}, },
{
name: "wildcard IDN no match",
fields: fields{
Pattern: "*呵呵*",
Wildcard: true,
},
host: HostInfo{
Name: "xn--6qqt7juua.cn",
},
want: false,
},
{ {
name: "empty", name: "empty",
fields: fields{ fields: fields{