我有hostnameWhitelist地图
C:/fakepath/myfilename.txt
我检查是否允许传入请求的主机名的方式是 -
var hostnameWhitelist = map[string] bool { "test.mydomain.com":true, "test12.mydomaindev.com":true}
虽然这很有效,但我如何进行像 -
这样的外卡匹配 url, errURL := url.Parse("test.mydomain.com")
if errURL != nil {
fmt.Println("error during parsing URL")
return false
}
fmt.Println("HOSTNAME = " + url.Hostname())
if ok := hostnameWhitelist[url.Hostname()]; ok {
fmt.Println("valid domain, allow access")
} else {
fmt.Println("NOT valid domain")
return false
}
这两个都应该通过。
虽然
*.mydomain.com
*.mydomaindev.com
应该失败
答案 0 :(得分:2)
您可以使用* .domain.com
格式存储地图的键使用strings.SplitAfterN
和strings.Join
将您获得的所有主机名转换为该格式。
split := strings.SplitAfterN(url.Hostname(),".",2)
split[0] = "*"
hostName := strings.Join(split,".")
...
hostnameWhitelist[hostName]
...
无关的改进
如果您将地图纯粹用作白名单,则可以使用map[string]struct{}
代替map[string]bool
。但正如Peter
在他的评论中提到的那样,只有当你拥有一个非常大的白名单时它才有意义。
答案 1 :(得分:1)
正则表达式是您解决问题的方法,map [string] bool可能无法正常工作,因为您尝试将正则表达式与单个值匹配。
package main
import (
"fmt"
"regexp"
)
func main() {
if matched, _ := regexp.MatchString(".*\\.?mydomain.*", "mydomaindev.com"); matched {
fmt.Println("Valid domain")
}
}
这将匹配所有域与模式mydomain,因此www.mydomain.com www.mydomaindev.com将匹配byt test.com并且hello.com将失败
其他方便的字符串操作是,
//This would match a.mydomain.com, b.mydomain.com etc.,
if strings.HasSuffix(url1.Hostname(), ".mydomain.com") {
fmt.Println("Valid domain allow access")
}
//To match anything with mydomain - like mydomain.com, mydomaindev.com
if strings.Contains(url2.Hostname(), "mydomain.com") {
fmt.Println("Valid domain allow access")
}
答案 2 :(得分:1)
在开始时与通配符进行通配符匹配非常昂贵。正则表达式在性能方面可能很困难,具体取决于数据集的大小和针对数据集进行评估的速度。您可以尝试使用后缀树,但是我怀疑性能可能会成为问题(我尚未在数据中对其进行测试)。
我们使用的一种方法是构建一个Radix Trie(紧凑前缀trie),其签名域名的标签按相反的八位字节顺序排列。您的签名域*.foo.example.com
变为com.example.foo.*
,这将通配符放在末尾。然后,自定义构建的Radix树只有到达通配符节点时才需要停止匹配。您的Trie可以支持完全字符串匹配和通配符匹配。如果您希望允许通配符位于域名中间,那么性能可能会成为问题。
使用Trie评估域名的最大挑战之一不是搜索时间,而是内存消耗,以及当您有很多签名时启动程序需要多长时间。
我们评估了一些实现(主要是在开始时没有通配符支持的情况下),用于测试加载时间,分配,内部节点数量,内存消耗,GC时间以及搜索/插入/删除时间。
我们测试过的实现方式
很明显,使用golang映射将提供最佳性能,但是当需要检索(因此使用Trie这个词)时,例如来自数据集的前缀信息,golang映射无法提供我们所需的功能。
我们在Trie中保留了大约70万个域名签名。构建时间为2秒,300MB内存,500万个分配,2秒GC和搜索成本为150ns / op。
如果我们对相同的签名使用golang映射(不使用通配符),则会获得0.5秒的加载时间,50MB的内存,可忽略的分配,1.6秒的GC和25ns / op的搜索成本。
在我们最初的实现中,构建时间为6秒,1GB内存,6000万个分配,5秒的GC和约200 ns / op的搜索成本。
从这些结果可以看出,我们设法降低了内存消耗和加载时间,而搜索成本却保持不变。
如果您要进行CIDR匹配,建议您检出https://github.com/kentik/patricia。为了减少GC时间,它可以避免指针。
祝你工作顺利!
答案 3 :(得分:0)
如果您希望在您的域中拥有多个深度,例如:
然后我会为通配符添加第二个容器:
endColor
然后,检查您的测试域是否以其中一个条目结束:
var wdomains = []string { ".foo.example.org", ".example.com"}
注意:如果您有超过数百个域,则可以使用基数树。
答案 4 :(得分:0)
您可以像使用 Set 数据结构一样使用 fstest.MapFS
全局匹配:
package main
import "testing/fstest"
var tests = []struct {
pat string
res int
} {
{"*.hello.com", 0},
{"*.mydomain.com", 1},
{"*.mydomaindev.com", 1},
{"*.test.com", 0},
}
func main() {
m := fstest.MapFS{"test.mydomain.com": nil, "test12.mydomaindev.com": nil}
for _, test := range tests {
a, e := m.Glob(test.pat)
if e != nil {
panic(e)
}
if len(a) != test.res {
panic(len(a))
}
}
}