mirror of
https://github.com/daeuniverse/dae.git
synced 2025-01-05 21:11:55 +07:00
247 lines
5.8 KiB
Go
247 lines
5.8 KiB
Go
/*
|
|
* SPDX-License-Identifier: AGPL-3.0-only
|
|
* Copyright (c) 2022-2024, daeuniverse Organization <dae@v2raya.org>
|
|
*/
|
|
|
|
package domain_matcher
|
|
|
|
import (
|
|
"fmt"
|
|
"hash/fnv"
|
|
"math/rand"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/daeuniverse/dae/common/assets"
|
|
|
|
"github.com/daeuniverse/dae/common/consts"
|
|
"github.com/daeuniverse/dae/component/routing"
|
|
"github.com/daeuniverse/dae/config"
|
|
"github.com/daeuniverse/dae/pkg/config_parser"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
var TestSample = []string{
|
|
"9game.cn",
|
|
"aliapp.org",
|
|
"alibaba-inc.com",
|
|
"alibaba.com",
|
|
"alibabacapital.com",
|
|
"alibabacorp.com",
|
|
"alibabadoctor.com",
|
|
"alibabafuturehotel.com",
|
|
"alibabagroup.com",
|
|
"alibabaplanet.com",
|
|
"alibabaued.com",
|
|
"alibabausercontent.com",
|
|
"alifanyi.com",
|
|
"alihealth.com.cn",
|
|
"alihealth.hk",
|
|
"aliimg.com",
|
|
"51y5.net",
|
|
"a.adtng.com",
|
|
"aaxads.com",
|
|
"addthisedge.com",
|
|
"adtrue.com",
|
|
"ad-srv.net",
|
|
"ad.api.moji.com",
|
|
"ad.wang502.com",
|
|
"adbutter.net",
|
|
"ads.trafficjunky.net",
|
|
"adtechus.com",
|
|
"adxprtz.com",
|
|
"cdn.advertserve.com",
|
|
"cdn.banclip.com",
|
|
"cfts1tifqr.com",
|
|
"contentabc.com",
|
|
"cretgate.com",
|
|
"ero-advertising.com",
|
|
"eroadvertising.com",
|
|
"exoclick.com",
|
|
"exosrv.com",
|
|
"go2.global",
|
|
"img-bss.csdn.net",
|
|
"imglnkc.com",
|
|
"imglnkd.com",
|
|
"innovid.com",
|
|
"ja2.gamersky.com",
|
|
"jl3.yjaxa.top",
|
|
"juicyads.com",
|
|
"kepler-37b.com",
|
|
"lqc006.com",
|
|
"moat.com",
|
|
"moatads.com",
|
|
"realsrv.com",
|
|
"s4yxaqyq95.com",
|
|
"shhs-ydd8x2.yjrmss.cn",
|
|
"static.javhd.com",
|
|
"tm-banners.gamingadult.com",
|
|
"trafficfactory.biz",
|
|
"tsyndicate.com",
|
|
"abchina.com",
|
|
"bankcomm.com",
|
|
"bankofbeijing.com.cn",
|
|
"bosc.cn",
|
|
"bsb.com.cn",
|
|
"ccb.com",
|
|
"cgbchina.com.cn",
|
|
"cib.com.cn",
|
|
"citibank.com.cn",
|
|
"cmbc.com.cn",
|
|
"hsbc.com.cn",
|
|
"hxb.com.cn",
|
|
"njcb.com.cn",
|
|
"psbc.com",
|
|
"spdb.com.cn",
|
|
"whccb.com",
|
|
"_https._tcp.mirrors.ustc.edu.cn",
|
|
"ipv4.master.test-ipv6.com",
|
|
}
|
|
|
|
type RoutingMatcherBuilder struct {
|
|
simulatedDomainSet []routing.DomainSet
|
|
Fallback string
|
|
|
|
err error
|
|
}
|
|
|
|
func (b *RoutingMatcherBuilder) OutboundToId(outbound string) uint8 {
|
|
h := fnv.New64()
|
|
h.Write([]byte(outbound))
|
|
return uint8(h.Sum64() & 0xFF)
|
|
}
|
|
|
|
func (b *RoutingMatcherBuilder) AddDomain(f *config_parser.Function, key string, values []string, outbound *routing.Outbound) {
|
|
if b.err != nil {
|
|
return
|
|
}
|
|
switch consts.RoutingDomainKey(key) {
|
|
case consts.RoutingDomainKey_Regex,
|
|
consts.RoutingDomainKey_Full,
|
|
consts.RoutingDomainKey_Keyword,
|
|
consts.RoutingDomainKey_Suffix:
|
|
default:
|
|
b.err = fmt.Errorf("addDomain: unsupported key: %v", key)
|
|
return
|
|
}
|
|
b.simulatedDomainSet = append(b.simulatedDomainSet, routing.DomainSet{
|
|
Key: consts.RoutingDomainKey(key),
|
|
RuleIndex: len(b.simulatedDomainSet),
|
|
Domains: values,
|
|
})
|
|
}
|
|
|
|
func getDomain() (simulatedDomainSet []routing.DomainSet, err error) {
|
|
var rules []*config_parser.RoutingRule
|
|
sections, err := config_parser.Parse(`
|
|
routing {
|
|
domain(suffix: test-ipv6.com)->direct
|
|
domain(geosite:bing)->us
|
|
domain(_https._tcp.mirrors.ustc.edu.cn)->us
|
|
domain(full:dns.google.com) -> direct
|
|
domain(geosite:category-ads-all) -> block
|
|
domain(geosite:cn) -> direct
|
|
}`)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var r config.Routing
|
|
if err = config.SectionParser(reflect.ValueOf(&r), sections[0]); err != nil {
|
|
return nil, err
|
|
}
|
|
if rules, err = routing.ApplyRulesOptimizers(r.Rules,
|
|
&routing.AliasOptimizer{},
|
|
&routing.DatReaderOptimizer{Logger: logrus.StandardLogger(), LocationFinder: assets.NewLocationFinder(nil)},
|
|
&routing.MergeAndSortRulesOptimizer{},
|
|
&routing.DeduplicateParamsOptimizer{},
|
|
); err != nil {
|
|
return nil, fmt.Errorf("ApplyRulesOptimizers error:\n%w", err)
|
|
}
|
|
builder := RoutingMatcherBuilder{}
|
|
rb := routing.NewRulesBuilder(logrus.StandardLogger())
|
|
rb.RegisterFunctionParser("domain", func(log *logrus.Logger, f *config_parser.Function, key string, paramValueGroup []string, overrideOutbound *routing.Outbound) (err error) {
|
|
builder.AddDomain(f, key, paramValueGroup, overrideOutbound)
|
|
return nil
|
|
})
|
|
if err = rb.Apply(rules); err != nil {
|
|
return nil, fmt.Errorf("Apply: %w", err)
|
|
}
|
|
return builder.simulatedDomainSet, nil
|
|
}
|
|
|
|
func BenchmarkBruteforce(b *testing.B) {
|
|
b.StopTimer()
|
|
logrus.SetLevel(logrus.WarnLevel)
|
|
simulatedDomainSet, err := getDomain()
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
bf := NewBruteforce(consts.MaxMatchSetLen)
|
|
for _, domains := range simulatedDomainSet {
|
|
bf.AddSet(domains.RuleIndex, domains.Domains, domains.Key)
|
|
}
|
|
if err = bf.Build(); err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
b.StartTimer()
|
|
runBenchmark(b, bf)
|
|
}
|
|
|
|
func BenchmarkGoRegexpNfa(b *testing.B) {
|
|
b.StopTimer()
|
|
logrus.SetLevel(logrus.WarnLevel)
|
|
simulatedDomainSet, err := getDomain()
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
nfa := NewGoRegexpNfa(consts.MaxMatchSetLen)
|
|
for _, domains := range simulatedDomainSet {
|
|
nfa.AddSet(domains.RuleIndex, domains.Domains, domains.Key)
|
|
}
|
|
if err = nfa.Build(); err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
b.StartTimer()
|
|
runBenchmark(b, nfa)
|
|
}
|
|
|
|
func BenchmarkAhocorasickSlimtrie(b *testing.B) {
|
|
b.StopTimer()
|
|
logrus.SetLevel(logrus.WarnLevel)
|
|
simulatedDomainSet, err := getDomain()
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
ahocorasick := NewAhocorasickSlimtrie(logrus.StandardLogger(), consts.MaxMatchSetLen)
|
|
for _, domains := range simulatedDomainSet {
|
|
ahocorasick.AddSet(domains.RuleIndex, domains.Domains, domains.Key)
|
|
}
|
|
if err = ahocorasick.Build(); err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
b.StartTimer()
|
|
runBenchmark(b, ahocorasick)
|
|
}
|
|
|
|
func runBenchmark(b *testing.B, matcher routing.DomainMatcher) {
|
|
rand.Seed(100)
|
|
for i := 0; i < b.N; i++ {
|
|
sample := TestSample[rand.Intn(len(TestSample))]
|
|
choice := rand.Intn(10)
|
|
switch {
|
|
case choice < 4:
|
|
addN := rand.Intn(5)
|
|
buf := make([]byte, addN)
|
|
for i := range buf {
|
|
buf[i] = 'a' + byte(rand.Intn('z'-'a'))
|
|
}
|
|
sample = string(buf) + "." + sample
|
|
case choice >= 4 && choice < 6:
|
|
k := rand.Intn(len(sample))
|
|
sample = sample[k:]
|
|
default:
|
|
}
|
|
matcher.MatchDomainBitmap(sample)
|
|
}
|
|
}
|