mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2025-12-09 13:46:07 +08:00
permit works
This commit is contained in:
parent
c2a64002fe
commit
cc8884824d
7 changed files with 137 additions and 59 deletions
|
|
@ -22,9 +22,10 @@ func Test_whichZonesToProcess(t *testing.T) {
|
|||
dcTaggedEmpty,
|
||||
}
|
||||
|
||||
// for _, dc := range allDC {
|
||||
// dc.UpdateSplitHorizonNames()
|
||||
// }
|
||||
for _, dc := range allDC {
|
||||
//dc.UpdateSplitHorizonNames()
|
||||
dc.PostProcess()
|
||||
}
|
||||
|
||||
type args struct {
|
||||
dc []*models.DomainConfig
|
||||
|
|
@ -158,6 +159,7 @@ func Test_whichZonesToProcess(t *testing.T) {
|
|||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Logf("whichZonesToProcess() %s filter=%v", tt.name, tt.args.filter)
|
||||
got := whichZonesToProcess(tt.args.dc, tt.args.filter)
|
||||
if len(got) != len(tt.want) {
|
||||
t.Errorf("whichZonesToProcess() %s: %s", tt.name, tt.why)
|
||||
|
|
|
|||
|
|
@ -69,7 +69,8 @@ func (dc *DomainConfig) PostProcess() {
|
|||
}
|
||||
|
||||
// Turn the user-supplied name into the fixed forms.
|
||||
dc.Tag, dc.NameRaw, dc.Name, dc.NameUnicode, dc.UniqueName = domaintags.MakeDomainFixForms(dc.Name)
|
||||
ff := domaintags.MakeDomainFixForms(dc.Name)
|
||||
dc.Tag, dc.NameRaw, dc.Name, dc.NameUnicode, dc.UniqueName = ff.Tag, ff.NameRaw, ff.NameIDN, ff.NameUnicode, ff.UniqueName
|
||||
|
||||
// Store the split horizon info in metadata for backward compatibility.
|
||||
dc.Metadata[DomainTag] = dc.Tag
|
||||
|
|
@ -90,7 +91,6 @@ func (dc *DomainConfig) GetUniqueName() (uniquename string) {
|
|||
// // (uniquename and tag) based on name.
|
||||
// func (dc *DomainConfig) UpdateSplitHorizonNames() {
|
||||
|
||||
// // This should probably be done elsewhere (maybe where we first ingest a domain).
|
||||
// // Convert all domain names to punycode.
|
||||
// for _, domain := range config.Domains {
|
||||
|
||||
|
|
|
|||
|
|
@ -6,20 +6,36 @@ import (
|
|||
"golang.org/x/net/idna"
|
||||
)
|
||||
|
||||
// DomainFixedForms stores the various fixed forms of a domain name and tag.
|
||||
type DomainFixedForms struct {
|
||||
NameRaw string // "originalinput.com" (name as input by the user, lowercased (no tag))
|
||||
NameIDN string // "punycode.com"
|
||||
NameUnicode string // "unicode.com"
|
||||
UniqueName string // "punycode.com!tag"
|
||||
|
||||
Tag string // The tag portion of `example.com!tag`
|
||||
HasBang bool // Was there a "!" in the input when creating this struct?
|
||||
}
|
||||
|
||||
// MakeDomainFixedForms turns the user-supplied name into the fixed forms.
|
||||
// * .Tag: the domain tag (of "example.com!tag")
|
||||
// * .NameRaw: lowercase version of how the user input the name in dnsconfig.js.
|
||||
// * .Name: punycode version, downcased.
|
||||
// * .NameUnicode: unicode version of the name, downcased.
|
||||
// * .UniqueName: "example.com!tag" unique across the entire config.
|
||||
func MakeDomainFixForms(n string) (tag, nameRaw, nameIDN, nameUnicode, UniqueName string) {
|
||||
func MakeDomainFixForms(n string) DomainFixedForms {
|
||||
var err error
|
||||
var tag, nameRaw, nameIDN, nameUnicode, uniqueName string
|
||||
var hasBang bool
|
||||
|
||||
// Split tag from name.
|
||||
p := strings.SplitN(n, "!", 2)
|
||||
if len(p) != 2 {
|
||||
tag = ""
|
||||
} else {
|
||||
if len(p) == 2 {
|
||||
tag = p[1]
|
||||
hasBang = true
|
||||
} else {
|
||||
tag = ""
|
||||
hasBang = false
|
||||
}
|
||||
|
||||
nameRaw = strings.ToLower(p[0])
|
||||
|
|
@ -48,7 +64,18 @@ func MakeDomainFixForms(n string) (tag, nameRaw, nameIDN, nameUnicode, UniqueNam
|
|||
}
|
||||
}
|
||||
|
||||
UniqueName = nameIDN + "!" + tag
|
||||
if hasBang {
|
||||
uniqueName = nameIDN + "!" + tag
|
||||
} else {
|
||||
uniqueName = nameIDN
|
||||
}
|
||||
|
||||
return
|
||||
return DomainFixedForms{
|
||||
Tag: tag,
|
||||
NameRaw: nameRaw,
|
||||
NameIDN: nameIDN,
|
||||
NameUnicode: nameUnicode,
|
||||
UniqueName: uniqueName,
|
||||
HasBang: hasBang,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ func Test_MakeDomainFixForms(t *testing.T) {
|
|||
wantNameIDN string
|
||||
wantNameUnicode string
|
||||
wantUniqueName string
|
||||
wantHasBang bool
|
||||
}{
|
||||
{
|
||||
name: "simple domain",
|
||||
|
|
@ -21,7 +22,8 @@ func Test_MakeDomainFixForms(t *testing.T) {
|
|||
wantNameRaw: "example.com",
|
||||
wantNameIDN: "example.com",
|
||||
wantNameUnicode: "example.com",
|
||||
wantUniqueName: "example.com!",
|
||||
wantUniqueName: "example.com",
|
||||
wantHasBang: false,
|
||||
},
|
||||
{
|
||||
name: "domain with tag",
|
||||
|
|
@ -31,6 +33,7 @@ func Test_MakeDomainFixForms(t *testing.T) {
|
|||
wantNameIDN: "example.com",
|
||||
wantNameUnicode: "example.com",
|
||||
wantUniqueName: "example.com!mytag",
|
||||
wantHasBang: true,
|
||||
},
|
||||
{
|
||||
name: "domain with empty tag",
|
||||
|
|
@ -40,6 +43,7 @@ func Test_MakeDomainFixForms(t *testing.T) {
|
|||
wantNameIDN: "example.com",
|
||||
wantNameUnicode: "example.com",
|
||||
wantUniqueName: "example.com!",
|
||||
wantHasBang: true,
|
||||
},
|
||||
{
|
||||
name: "unicode domain",
|
||||
|
|
@ -48,7 +52,8 @@ func Test_MakeDomainFixForms(t *testing.T) {
|
|||
wantNameRaw: "उदाहरण.com",
|
||||
wantNameIDN: "xn--p1b6ci4b4b3a.com",
|
||||
wantNameUnicode: "उदाहरण.com",
|
||||
wantUniqueName: "xn--p1b6ci4b4b3a.com!",
|
||||
wantUniqueName: "xn--p1b6ci4b4b3a.com",
|
||||
wantHasBang: false,
|
||||
},
|
||||
{
|
||||
name: "unicode domain with tag",
|
||||
|
|
@ -58,6 +63,7 @@ func Test_MakeDomainFixForms(t *testing.T) {
|
|||
wantNameIDN: "xn--p1b6ci4b4b3a.com",
|
||||
wantNameUnicode: "उदाहरण.com",
|
||||
wantUniqueName: "xn--p1b6ci4b4b3a.com!mytag",
|
||||
wantHasBang: true,
|
||||
},
|
||||
{
|
||||
name: "punycode domain",
|
||||
|
|
@ -66,7 +72,8 @@ func Test_MakeDomainFixForms(t *testing.T) {
|
|||
wantNameRaw: "xn--p1b6ci4b4b3a.com",
|
||||
wantNameIDN: "xn--p1b6ci4b4b3a.com",
|
||||
wantNameUnicode: "उदाहरण.com",
|
||||
wantUniqueName: "xn--p1b6ci4b4b3a.com!",
|
||||
wantUniqueName: "xn--p1b6ci4b4b3a.com",
|
||||
wantHasBang: false,
|
||||
},
|
||||
{
|
||||
name: "punycode domain with tag",
|
||||
|
|
@ -76,6 +83,7 @@ func Test_MakeDomainFixForms(t *testing.T) {
|
|||
wantNameIDN: "xn--p1b6ci4b4b3a.com",
|
||||
wantNameUnicode: "उदाहरण.com",
|
||||
wantUniqueName: "xn--p1b6ci4b4b3a.com!mytag",
|
||||
wantHasBang: true,
|
||||
},
|
||||
{
|
||||
name: "mixed case domain",
|
||||
|
|
@ -84,7 +92,8 @@ func Test_MakeDomainFixForms(t *testing.T) {
|
|||
wantNameRaw: "example.com",
|
||||
wantNameIDN: "example.com",
|
||||
wantNameUnicode: "example.com",
|
||||
wantUniqueName: "example.com!",
|
||||
wantUniqueName: "example.com",
|
||||
wantHasBang: false,
|
||||
},
|
||||
{
|
||||
name: "mixed case domain with tag",
|
||||
|
|
@ -94,26 +103,30 @@ func Test_MakeDomainFixForms(t *testing.T) {
|
|||
wantNameIDN: "example.com",
|
||||
wantNameUnicode: "example.com",
|
||||
wantUniqueName: "example.com!MyTag",
|
||||
wantHasBang: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
gotTag, gotNameRaw, gotNameIDN, gotNameUnicode, gotUniqueName := MakeDomainFixForms(tt.input)
|
||||
if gotTag != tt.wantTag {
|
||||
t.Errorf("MakeDomainFixForms() gotTag = %v, want %v", gotTag, tt.wantTag)
|
||||
got := MakeDomainFixForms(tt.input)
|
||||
if got.Tag != tt.wantTag {
|
||||
t.Errorf("MakeDomainFixForms() gotTag = %v, want %v", got.Tag, tt.wantTag)
|
||||
}
|
||||
if gotNameRaw != tt.wantNameRaw {
|
||||
t.Errorf("MakeDomainFixForms() gotNameRaw = %v, want %v", gotNameRaw, tt.wantNameRaw)
|
||||
if got.NameRaw != tt.wantNameRaw {
|
||||
t.Errorf("MakeDomainFixForms() gotNameRaw = %v, want %v", got.NameRaw, tt.wantNameRaw)
|
||||
}
|
||||
if gotNameIDN != tt.wantNameIDN {
|
||||
t.Errorf("MakeDomainFixForms() gotNameIDN = %v, want %v", gotNameIDN, tt.wantNameIDN)
|
||||
if got.NameIDN != tt.wantNameIDN {
|
||||
t.Errorf("MakeDomainFixForms() gotNameIDN = %v, want %v", got.NameIDN, tt.wantNameIDN)
|
||||
}
|
||||
if gotNameUnicode != tt.wantNameUnicode {
|
||||
t.Errorf("MakeDomainFixForms() gotNameUnicode = %v, want %v", gotNameUnicode, tt.wantNameUnicode)
|
||||
if got.NameUnicode != tt.wantNameUnicode {
|
||||
t.Errorf("MakeDomainFixForms() gotNameUnicode = %v, want %v", got.NameUnicode, tt.wantNameUnicode)
|
||||
}
|
||||
if gotUniqueName != tt.wantUniqueName {
|
||||
t.Errorf("MakeDomainFixForms() gotUniqueName = %v, want %v", gotUniqueName, tt.wantUniqueName)
|
||||
if got.UniqueName != tt.wantUniqueName {
|
||||
t.Errorf("MakeDomainFixForms() gotUniqueName = %v, want %v", got.UniqueName, tt.wantUniqueName)
|
||||
}
|
||||
if got.HasBang != tt.wantHasBang {
|
||||
t.Errorf("MakeDomainFixForms() gotHasTag = %v, want %v", got.HasBang, tt.wantHasBang)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,22 @@
|
|||
package domaintags
|
||||
|
||||
import "strings"
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type PermitList struct {
|
||||
// If the permit list is "all" or "".
|
||||
all bool
|
||||
items []permitListItem
|
||||
}
|
||||
type permitListItem struct {
|
||||
tag, nameRaw, nameIDN, nameUnicode, uniqueName string
|
||||
items []DomainFixedForms
|
||||
}
|
||||
|
||||
// CompilePermitList compiles a list of domain strings into a PermitList structure. The
|
||||
func CompilePermitList(s string) PermitList {
|
||||
//fmt.Printf("DEBUG: CompilePermitList(%q)\n", s)
|
||||
|
||||
s = strings.TrimSpace(s)
|
||||
if s == "" || strings.ToLower(s) == "all" {
|
||||
if s == "" || s == "*" || strings.ToLower(s) == "all" {
|
||||
//fmt.Printf("DEBUG: CompilePermitList: ALL\n")
|
||||
return PermitList{all: true}
|
||||
}
|
||||
|
||||
|
|
@ -24,58 +26,72 @@ func CompilePermitList(s string) PermitList {
|
|||
if l == "" { // Skip empty entries. They match nothing.
|
||||
continue
|
||||
}
|
||||
tag, nameRaw, nameIDN, nameUnicode, uniqueName := MakeDomainFixForms(l)
|
||||
if tag == "" { // Treat empty tag as wildcard.
|
||||
tag = "*"
|
||||
ff := MakeDomainFixForms(l)
|
||||
if ff.HasBang && ff.NameIDN == "" { // Treat empty name as wildcard.
|
||||
ff.NameIDN = "*"
|
||||
}
|
||||
if nameIDN == "" { // Treat empty name as wildcard.
|
||||
nameIDN = "*"
|
||||
}
|
||||
sl.items = append(sl.items, permitListItem{
|
||||
tag: tag,
|
||||
nameRaw: nameRaw,
|
||||
nameIDN: nameIDN,
|
||||
nameUnicode: nameUnicode,
|
||||
uniqueName: uniqueName,
|
||||
})
|
||||
sl.items = append(sl.items, ff)
|
||||
}
|
||||
|
||||
//fmt.Printf("DEBUG: CompilePermitList: RETURN %+v\n", sl)
|
||||
return sl
|
||||
}
|
||||
|
||||
func (pl *PermitList) Permitted(u string) bool {
|
||||
func (pl *PermitList) Permitted(domToCheck string) bool {
|
||||
//fmt.Printf("DEBUG: Permitted(%q)\n", domToCheck)
|
||||
|
||||
// If the permit list is "all", everything is permitted.
|
||||
if pl.all {
|
||||
//fmt.Printf("DEBUG: Permitted RETURN true\n")
|
||||
return true
|
||||
}
|
||||
|
||||
tag, _, nameIDN, nameUnicode, _ := MakeDomainFixForms(u)
|
||||
domToCheckFF := MakeDomainFixForms(domToCheck)
|
||||
// fmt.Printf("DEBUG: input: %+v\n", domToCheckFF)
|
||||
|
||||
for _, filterItem := range pl.items {
|
||||
// fmt.Printf("DEBUG: Checking item %+v\n", filterItem)
|
||||
|
||||
// Special case: filter=example.com!* does not match example.com (no tag)
|
||||
if filterItem.Tag == "*" && !domToCheckFF.HasBang {
|
||||
// fmt.Printf("DEBUG: Skipping due to no tag present\n")
|
||||
continue
|
||||
}
|
||||
// Special case: filter=example.com!* does not match example.com! (empty tag)
|
||||
if filterItem.Tag == "*" && domToCheckFF.HasBang && domToCheckFF.Tag == "" {
|
||||
// fmt.Printf("DEBUG: Skipping due to empty tag present\n")
|
||||
continue
|
||||
}
|
||||
// Special case: filter=example.com! does not match example.com!tag
|
||||
if filterItem.HasBang && filterItem.Tag == "" && domToCheckFF.HasBang && domToCheckFF.Tag != "" {
|
||||
// fmt.Printf("DEBUG: Skipping due to non-empty tag present\n")
|
||||
continue
|
||||
}
|
||||
|
||||
for _, item := range pl.items {
|
||||
// Skip if the tag doesn't match
|
||||
if item.tag != "*" && tag != item.tag {
|
||||
if (filterItem.Tag != "*") && (domToCheckFF.Tag != filterItem.Tag) {
|
||||
continue
|
||||
}
|
||||
// Now that we know the tag matches, we can focus on the name.
|
||||
|
||||
if item.nameIDN == "*" {
|
||||
if filterItem.NameIDN == "*" {
|
||||
// `*!tag` or `*` matches everything.
|
||||
return true
|
||||
}
|
||||
// If the name starts with "*." then match the suffix.
|
||||
if strings.HasPrefix(item.nameIDN, "*.") {
|
||||
if strings.HasPrefix(filterItem.NameIDN, "*.") {
|
||||
// example.com matches *.example.com
|
||||
if nameIDN == item.nameIDN[2:] || nameUnicode == item.nameUnicode[2:] {
|
||||
if domToCheckFF.NameIDN == filterItem.NameIDN[2:] || domToCheckFF.NameUnicode == filterItem.NameUnicode[2:] {
|
||||
return true
|
||||
}
|
||||
// foo.example.com matches *.example.com
|
||||
if strings.HasSuffix(nameIDN, item.nameIDN[1:]) || strings.HasSuffix(nameUnicode, item.nameUnicode[1:]) {
|
||||
if strings.HasSuffix(domToCheckFF.NameIDN, filterItem.NameIDN[1:]) || strings.HasSuffix(domToCheckFF.NameUnicode, filterItem.NameUnicode[1:]) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// No wildcards? Exact match.
|
||||
if item.nameIDN == nameIDN || item.nameUnicode == nameUnicode {
|
||||
if filterItem.NameIDN == domToCheckFF.NameIDN || filterItem.NameUnicode == domToCheckFF.NameUnicode {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ func TestPermitList_Permitted(t *testing.T) {
|
|||
|
||||
// Wildcard tag
|
||||
{"wildcard tag matches", "example.com!*", "example.com!tag1", true},
|
||||
{"wildcard tag matches no tag", "example.com!*", "example.com", true},
|
||||
{"wildcard tag matches no tag", "example.com!*", "example.com", false},
|
||||
{"wildcard tag mismatch domain", "example.com!*", "google.com!tag1", false},
|
||||
|
||||
// Suffix matching
|
||||
|
|
@ -66,12 +66,12 @@ func TestPermitList_Permitted(t *testing.T) {
|
|||
// IDN/Unicode cases (assuming MakeDomainFixForms works)
|
||||
{"IDN exact match punycode", "xn--e1a4c.com", "xn--e1a4c.com", true}, // д.com
|
||||
{"IDN exact match unicode", "д.com", "д.com", true},
|
||||
{"IDN mixed match", "xn--e1a4c.com", "д.com", true},
|
||||
{"IDN mixed match reversed", "д.com", "xn--e1a4c.com", true},
|
||||
{"IDN mixed match", "xn--d1a.com", "д.com", true},
|
||||
{"IDN mixed match reversed", "д.com", "xn--d1a.com", true},
|
||||
{"IDN suffix match punycode", "*.xn--e1a4c.com", "sub.xn--e1a4c.com", true},
|
||||
{"IDN suffix match unicode", "*.д.com", "sub.д.com", true},
|
||||
{"IDN suffix match mixed", "*.xn--e1a4c.com", "sub.д.com", true},
|
||||
{"IDN suffix match mixed reversed", "*.д.com", "sub.xn--e1a4c.com", true},
|
||||
{"IDN suffix match mixed", "*.xn--d1a.com", "sub.д.com", true},
|
||||
{"IDN suffix match mixed reversed", "*.д.com", "sub.xn--d1a.com", true},
|
||||
{"IDN suffix match base", "*.д.com", "д.com", true},
|
||||
|
||||
// Edge cases
|
||||
|
|
@ -80,6 +80,22 @@ func TestPermitList_Permitted(t *testing.T) {
|
|||
{"list with empty items 2", "one.com,,two.com", "two.com", true},
|
||||
{"list with empty items no match", "one.com,,two.com", "three.com", false},
|
||||
{"no match on empty list", "nonexistent", "example.com", false},
|
||||
|
||||
// Weird backwards compatibility with no tag being different than empty tag
|
||||
{"empty tag vs no tag mismatch", "example.com", "example.com!foo", false},
|
||||
|
||||
// testMultiFilterTaggedWildcard
|
||||
{"testMultiFilterTaggedWildcard_0", "example.com!*", "example.com!", false},
|
||||
{"testMultiFilterTaggedWildcard_1", "example.com!*", "example.com", false},
|
||||
{"testMultiFilterTaggedWildcard_2", "example.com!*", "example.net", false},
|
||||
{"testMultiFilterTaggedWildcard_3", "example.com!*", "example.com!george", true},
|
||||
{"testMultiFilterTaggedWildcard_4", "example.com!*", "example.com!john", true},
|
||||
|
||||
// testFilterEmptyTagAndNoTag
|
||||
{"testFilterEmptyTagAndNoTag_0", "example.com!,example.com", "example.com!", true},
|
||||
{"testFilterEmptyTagAndNoTag_1", "example.com!,example.com", "example.com", true},
|
||||
{"testFilterEmptyTagAndNoTag_2", "example.com!,example.com", "example.net", false},
|
||||
{"testFilterEmptyTagAndNoTag_3", "example.com!,example.com", "example.com!tag", false},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,10 @@ func TestImportTransform(t *testing.T) {
|
|||
cfg := &models.DNSConfig{
|
||||
Domains: []*models.DomainConfig{src, dst},
|
||||
}
|
||||
err := cfg.PostProcess()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if errs := ValidateAndNormalizeConfig(cfg); len(errs) != 0 {
|
||||
for _, err := range errs {
|
||||
t.Error(err)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue