mirror of
https://github.com/daeuniverse/dae.git
synced 2024-12-22 20:24:40 +07:00
feat/optimize: add userspace routing and optimize domain routing (#18)
This commit is contained in:
parent
87efa3d38d
commit
8f6b0a6e2a
2
Makefile
2
Makefile
@ -1,6 +1,6 @@
|
||||
#
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
# Copyright (c) since 2022, v2rayA Organization <team@v2raya.org>
|
||||
# Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
#
|
||||
|
||||
# The development version of clang is distributed as the 'clang' binary,
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, mzz2017 <mzz@tuta.io>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package main
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, mzz2017 <mzz@tuta.io>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package main
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, mzz2017 <mzz@tuta.io>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package cmd
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package assets
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package consts
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package consts
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2022, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package consts
|
||||
@ -41,10 +41,10 @@ const (
|
||||
DisableL4ChecksumPolicy_SetZero
|
||||
)
|
||||
|
||||
type RoutingType uint8
|
||||
type MatchType uint8
|
||||
|
||||
const (
|
||||
MatchType_DomainSet RoutingType = iota
|
||||
MatchType_DomainSet MatchType = iota
|
||||
MatchType_IpSet
|
||||
MatchType_SourceIpSet
|
||||
MatchType_Port
|
||||
@ -65,6 +65,7 @@ const (
|
||||
OutboundControlPlaneDirect OutboundIndex = 0xFD
|
||||
OutboundLogicalOr OutboundIndex = 0xFE
|
||||
OutboundLogicalAnd OutboundIndex = 0xFF
|
||||
OutboundLogicalMask OutboundIndex = 0xFE
|
||||
|
||||
OutboundMax = OutboundLogicalAnd
|
||||
OutboundUserDefinedMax = OutboundMustDirect - 1
|
||||
|
@ -1,15 +1,17 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2022, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package consts
|
||||
|
||||
type RoutingDomainKey string
|
||||
|
||||
const (
|
||||
RoutingDomain_Full = "full"
|
||||
RoutingDomain_Keyword = "keyword"
|
||||
RoutingDomain_Suffix = "suffix"
|
||||
RoutingDomain_Regex = "regex"
|
||||
RoutingDomainKey_Full RoutingDomainKey = "full"
|
||||
RoutingDomainKey_Keyword RoutingDomainKey = "keyword"
|
||||
RoutingDomainKey_Suffix RoutingDomainKey = "suffix"
|
||||
RoutingDomainKey_Regex RoutingDomainKey = "regex"
|
||||
|
||||
Function_Domain = "domain"
|
||||
Function_Ip = "ip"
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package common
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, mzz2017 <mzz@tuta.io>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package netutils
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, mzz2017 <mzz@tuta.io>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package netutils
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, mzz2017 <mzz@tuta.io>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package netutils
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, mzz2017 <mzz@tuta.io>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package netutils
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2022, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package common
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package dialer
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package dialer
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, mzz2017 <mzz@tuta.io>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package dialer
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package dialer
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package dialer
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, mzz2017 <mzz@tuta.io>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package dialer
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package outbound
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package outbound
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, mzz2017 <mzz@tuta.io>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package outbound
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package outbound
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package outbound
|
||||
|
14
component/routing/domain_matcher.go
Normal file
14
component/routing/domain_matcher.go
Normal file
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) 2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package routing
|
||||
|
||||
import "github.com/v2rayA/dae/common/consts"
|
||||
|
||||
type DomainMatcher interface {
|
||||
AddSet(bitIndex int, patterns []string, typ consts.RoutingDomainKey)
|
||||
Build() error
|
||||
MatchDomainBitmap(domain string) (bitmap []uint32)
|
||||
}
|
119
component/routing/domain_matcher/ahocorasick.go
Normal file
119
component/routing/domain_matcher/ahocorasick.go
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) 2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package domain_matcher
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/cloudflare/ahocorasick"
|
||||
"github.com/v2rayA/dae/common/consts"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Ahocorasick struct {
|
||||
validIndexes []int
|
||||
validRegexpIndexes []int
|
||||
matchers []*ahocorasick.Matcher
|
||||
regexp [][]*regexp.Regexp
|
||||
|
||||
toBuild [][][]byte
|
||||
err error
|
||||
}
|
||||
|
||||
func NewAhocorasick(bitLength int) *Ahocorasick {
|
||||
return &Ahocorasick{
|
||||
matchers: make([]*ahocorasick.Matcher, bitLength),
|
||||
toBuild: make([][][]byte, bitLength),
|
||||
regexp: make([][]*regexp.Regexp, bitLength),
|
||||
}
|
||||
}
|
||||
func (n *Ahocorasick) AddSet(bitIndex int, patterns []string, typ consts.RoutingDomainKey) {
|
||||
if n.err != nil {
|
||||
return
|
||||
}
|
||||
switch typ {
|
||||
case consts.RoutingDomainKey_Full:
|
||||
for _, d := range patterns {
|
||||
n.toBuild[bitIndex] = append(n.toBuild[bitIndex], []byte("^"+d+"$"))
|
||||
}
|
||||
case consts.RoutingDomainKey_Suffix:
|
||||
for _, d := range patterns {
|
||||
if strings.HasPrefix(d, ".") {
|
||||
// abc.example.com
|
||||
n.toBuild[bitIndex] = append(n.toBuild[bitIndex], []byte(d+"$"))
|
||||
} else {
|
||||
// xxx.example.com
|
||||
n.toBuild[bitIndex] = append(n.toBuild[bitIndex], []byte("."+d+"$"))
|
||||
// example.com
|
||||
n.toBuild[bitIndex] = append(n.toBuild[bitIndex], []byte("^"+d+"$"))
|
||||
}
|
||||
}
|
||||
case consts.RoutingDomainKey_Keyword:
|
||||
for _, d := range patterns {
|
||||
n.toBuild[bitIndex] = append(n.toBuild[bitIndex], []byte(d))
|
||||
}
|
||||
case consts.RoutingDomainKey_Regex:
|
||||
for _, d := range patterns {
|
||||
r, err := regexp.Compile(d)
|
||||
if err != nil {
|
||||
n.err = fmt.Errorf("failed to compile regex: %v", d)
|
||||
return
|
||||
}
|
||||
n.regexp[bitIndex] = append(n.regexp[bitIndex], r)
|
||||
}
|
||||
default:
|
||||
n.err = fmt.Errorf("unknown RoutingDomainKey: %v", typ)
|
||||
return
|
||||
}
|
||||
}
|
||||
func (n *Ahocorasick) MatchDomainBitmap(domain string) (bitmap []uint32) {
|
||||
N := len(n.matchers) / 32
|
||||
if len(n.matchers)%32 != 0 {
|
||||
N++
|
||||
}
|
||||
bitmap = make([]uint32, N)
|
||||
// Domain should not contain ^ or $.
|
||||
if strings.ContainsAny(domain, "^$") {
|
||||
return bitmap
|
||||
}
|
||||
// Add magic chars as head and tail.
|
||||
domain = "^" + strings.ToLower(strings.TrimSuffix(domain, ".")) + "$"
|
||||
for _, i := range n.validIndexes {
|
||||
if hits := n.matchers[i].MatchThreadSafe([]byte(domain)); len(hits) > 0 {
|
||||
bitmap[i/32] |= 1 << (i % 32)
|
||||
}
|
||||
}
|
||||
// Regex matching is independent.
|
||||
for _, i := range n.validRegexpIndexes {
|
||||
if bitmap[i/32]&(1<<(i%32)) > 0 {
|
||||
// Already matched.
|
||||
continue
|
||||
}
|
||||
for _, r := range n.regexp[i] {
|
||||
if r.MatchString(domain) {
|
||||
bitmap[i/32] |= 1 << (i % 32)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return bitmap
|
||||
}
|
||||
func (n *Ahocorasick) Build() error {
|
||||
if n.err != nil {
|
||||
return n.err
|
||||
}
|
||||
n.validIndexes = make([]int, 0, len(n.toBuild)/8)
|
||||
for i, toBuild := range n.toBuild {
|
||||
if len(toBuild) == 0 {
|
||||
continue
|
||||
}
|
||||
n.matchers[i] = ahocorasick.NewMatcher(toBuild)
|
||||
n.validIndexes = append(n.validIndexes, i)
|
||||
}
|
||||
// Release it.
|
||||
n.toBuild = nil
|
||||
return nil
|
||||
}
|
236
component/routing/domain_matcher/benchmark_test.go
Normal file
236
component/routing/domain_matcher/benchmark_test.go
Normal file
@ -0,0 +1,236 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) 2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package domain_matcher
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/v2rayA/dae/common/consts"
|
||||
"github.com/v2rayA/dae/component/routing"
|
||||
"github.com/v2rayA/dae/config"
|
||||
"github.com/v2rayA/dae/pkg/config_parser"
|
||||
"hash/fnv"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
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",
|
||||
}
|
||||
|
||||
type RoutingMatcherBuilder struct {
|
||||
*routing.DefaultMatcherBuilder
|
||||
outboundName2Id map[string]uint8
|
||||
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 string) {
|
||||
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 {
|
||||
pname(NetworkManager, dnsmasq, systemd-resolved) -> must_direct # Traffic of DNS in local must be direct to avoid loop when binding to WAN.
|
||||
pname(sogou-qimpanel, sogou-qimpanel-watchdog) -> block
|
||||
ip(geoip:private, 224.0.0.0/3, 'ff00::/8') -> direct # Put it in front unless you know what you're doing.
|
||||
domain(geosite:bing)->us
|
||||
domain(full:dns.google) && port(53) -> direct
|
||||
domain(geosite:category-ads-all) -> block
|
||||
ip(geoip:private) -> direct
|
||||
ip(geoip:cn) -> direct
|
||||
domain(geosite:cn) -> direct
|
||||
final: my_group
|
||||
}`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var r config.Routing
|
||||
if err = config.RoutingRuleAndParamParser(reflect.ValueOf(&r), sections[0]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if rules, err = routing.ApplyRulesOptimizers(r.Rules,
|
||||
&routing.RefineFunctionParamKeyOptimizer{},
|
||||
&routing.DatReaderOptimizer{Logger: logrus.StandardLogger()},
|
||||
&routing.MergeAndSortRulesOptimizer{},
|
||||
&routing.DeduplicateParamsOptimizer{},
|
||||
); err != nil {
|
||||
return nil, fmt.Errorf("ApplyRulesOptimizers error:\n%w", err)
|
||||
}
|
||||
builder := RoutingMatcherBuilder{}
|
||||
if err = routing.ApplyMatcherBuilder(logrus.StandardLogger(), &builder, rules, r.Fallback); err != nil {
|
||||
return nil, fmt.Errorf("ApplyMatcherBuilder: %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(simulatedDomainSet)
|
||||
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 BenchmarkAhocorasick(b *testing.B) {
|
||||
b.StopTimer()
|
||||
logrus.SetLevel(logrus.WarnLevel)
|
||||
simulatedDomainSet, err := getDomain()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
ahocorasick := NewAhocorasick(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)
|
||||
}
|
||||
}
|
67
component/routing/domain_matcher/bruteforce.go
Normal file
67
component/routing/domain_matcher/bruteforce.go
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) 2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package domain_matcher
|
||||
|
||||
import (
|
||||
"github.com/v2rayA/dae/common/consts"
|
||||
"github.com/v2rayA/dae/component/routing"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Bruteforce struct {
|
||||
simulatedDomainSet []routing.DomainSet
|
||||
err error
|
||||
}
|
||||
|
||||
func NewBruteforce(simulatedDomainSet []routing.DomainSet) *Bruteforce {
|
||||
return &Bruteforce{
|
||||
simulatedDomainSet: simulatedDomainSet,
|
||||
}
|
||||
}
|
||||
func (n *Bruteforce) AddSet(bitIndex int, patterns []string, typ consts.RoutingDomainKey) {
|
||||
}
|
||||
func (n *Bruteforce) MatchDomainBitmap(domain string) (bitmap []uint32) {
|
||||
N := len(n.simulatedDomainSet) / 32
|
||||
if len(n.simulatedDomainSet)%32 != 0 {
|
||||
N++
|
||||
}
|
||||
bitmap = make([]uint32, N)
|
||||
for _, s := range n.simulatedDomainSet {
|
||||
for _, d := range s.Domains {
|
||||
var hit bool
|
||||
switch s.Key {
|
||||
case consts.RoutingDomainKey_Suffix:
|
||||
if domain == d || strings.HasSuffix(domain, "."+strings.TrimPrefix(d, ".")) {
|
||||
hit = true
|
||||
}
|
||||
case consts.RoutingDomainKey_Full:
|
||||
if strings.EqualFold(domain, d) {
|
||||
hit = true
|
||||
}
|
||||
case consts.RoutingDomainKey_Keyword:
|
||||
if strings.Contains(strings.ToLower(domain), strings.ToLower(d)) {
|
||||
hit = true
|
||||
}
|
||||
case consts.RoutingDomainKey_Regex:
|
||||
if regexp.MustCompile(d).MatchString(strings.ToLower(domain)) {
|
||||
hit = true
|
||||
}
|
||||
}
|
||||
if hit {
|
||||
bitmap[s.RuleIndex/32] |= 1 << (s.RuleIndex % 32)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return bitmap
|
||||
}
|
||||
func (n *Bruteforce) Build() error {
|
||||
if n.err != nil {
|
||||
return n.err
|
||||
}
|
||||
return nil
|
||||
}
|
93
component/routing/domain_matcher/go_regexp_nfa.go
Normal file
93
component/routing/domain_matcher/go_regexp_nfa.go
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) 2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package domain_matcher
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/v2rayA/dae/common/consts"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type GoRegexpNfa struct {
|
||||
validIndexes []int
|
||||
nfa []*regexp.Regexp
|
||||
toBuild [][]string
|
||||
err error
|
||||
}
|
||||
|
||||
func NewGoRegexpNfa(bitLength int) *GoRegexpNfa {
|
||||
return &GoRegexpNfa{
|
||||
nfa: make([]*regexp.Regexp, bitLength),
|
||||
toBuild: make([][]string, bitLength),
|
||||
}
|
||||
}
|
||||
func (n *GoRegexpNfa) AddSet(bitIndex int, patterns []string, typ consts.RoutingDomainKey) {
|
||||
if n.err != nil {
|
||||
return
|
||||
}
|
||||
switch typ {
|
||||
case consts.RoutingDomainKey_Full:
|
||||
for _, d := range patterns {
|
||||
n.toBuild[bitIndex] = append(n.toBuild[bitIndex], "^"+d+"$")
|
||||
}
|
||||
case consts.RoutingDomainKey_Suffix:
|
||||
for _, d := range patterns {
|
||||
n.toBuild[bitIndex] = append(n.toBuild[bitIndex], "."+strings.TrimPrefix(d, ".")+"$")
|
||||
n.toBuild[bitIndex] = append(n.toBuild[bitIndex], "^"+d+"$")
|
||||
}
|
||||
case consts.RoutingDomainKey_Keyword:
|
||||
for _, d := range patterns {
|
||||
n.toBuild[bitIndex] = append(n.toBuild[bitIndex], d)
|
||||
}
|
||||
case consts.RoutingDomainKey_Regex:
|
||||
for _, d := range patterns {
|
||||
// Check if it is a valid regexp.
|
||||
if _, err := regexp.Compile(d); err != nil {
|
||||
n.err = fmt.Errorf("failed to compile regex: %v", d)
|
||||
return
|
||||
}
|
||||
n.toBuild[bitIndex] = append(n.toBuild[bitIndex], d)
|
||||
}
|
||||
default:
|
||||
n.err = fmt.Errorf("unknown RoutingDomainKey: %v", typ)
|
||||
return
|
||||
}
|
||||
}
|
||||
func (n *GoRegexpNfa) MatchDomainBitmap(domain string) (bitmap []uint32) {
|
||||
N := len(n.nfa) / 32
|
||||
if len(n.nfa)%32 != 0 {
|
||||
N++
|
||||
}
|
||||
bitmap = make([]uint32, N)
|
||||
domain = strings.ToLower(strings.TrimSuffix(domain, "."))
|
||||
for _, i := range n.validIndexes {
|
||||
if n.nfa[i].MatchString(domain) {
|
||||
bitmap[i/32] |= 1 << (i % 32)
|
||||
}
|
||||
}
|
||||
return bitmap
|
||||
}
|
||||
func (n *GoRegexpNfa) Build() error {
|
||||
if n.err != nil {
|
||||
return n.err
|
||||
}
|
||||
n.validIndexes = make([]int, 0, len(n.toBuild)/8)
|
||||
for i, toBuild := range n.toBuild {
|
||||
if len(toBuild) == 0 {
|
||||
continue
|
||||
}
|
||||
r, err := regexp.Compile(strings.Join(toBuild, "|"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to build NFA: %w", err)
|
||||
}
|
||||
n.nfa[i] = r
|
||||
n.validIndexes = append(n.validIndexes, i)
|
||||
}
|
||||
// Release it.
|
||||
n.toBuild = nil
|
||||
return nil
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2022, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package routing
|
||||
@ -19,6 +19,12 @@ var FakeOutbound_MUST_DIRECT = consts.OutboundMustDirect.String()
|
||||
var FakeOutbound_AND = consts.OutboundLogicalAnd.String()
|
||||
var FakeOutbound_OR = consts.OutboundLogicalOr.String()
|
||||
|
||||
type DomainSet struct {
|
||||
Key consts.RoutingDomainKey
|
||||
RuleIndex int
|
||||
Domains []string
|
||||
}
|
||||
|
||||
type MatcherBuilder interface {
|
||||
AddDomain(f *config_parser.Function, key string, values []string, outbound string)
|
||||
AddIp(f *config_parser.Function, values []netip.Prefix, outbound string)
|
||||
@ -32,7 +38,6 @@ type MatcherBuilder interface {
|
||||
AddFallback(outbound string)
|
||||
AddAnyBefore(f *config_parser.Function, key string, values []string, outbound string)
|
||||
AddAnyAfter(f *config_parser.Function, key string, values []string, outbound string)
|
||||
Build() (err error)
|
||||
}
|
||||
|
||||
func GroupParamValuesByKey(params []*config_parser.Param) (keyToValues map[string][]string, keyOrder []string) {
|
||||
@ -207,4 +212,3 @@ func (d *DefaultMatcherBuilder) AddProcessName(f *config_parser.Function, values
|
||||
}
|
||||
func (d *DefaultMatcherBuilder) AddAnyAfter(f *config_parser.Function, key string, values []string, outbound string) {
|
||||
}
|
||||
func (d *DefaultMatcherBuilder) Build() (err error) { return nil }
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2022, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package routing
|
||||
@ -49,9 +49,9 @@ func (o *RefineFunctionParamKeyOptimizer) Optimize(rules []*config_parser.Routin
|
||||
// Rewrite to authoritative key name.
|
||||
switch param.Key {
|
||||
case "", "domain":
|
||||
param.Key = consts.RoutingDomain_Suffix
|
||||
param.Key = string(consts.RoutingDomainKey_Suffix)
|
||||
case "contains":
|
||||
param.Key = consts.RoutingDomain_Keyword
|
||||
param.Key = string(consts.RoutingDomainKey_Keyword)
|
||||
default:
|
||||
}
|
||||
}
|
||||
@ -169,25 +169,25 @@ func (o *DatReaderOptimizer) loadGeoSite(filename string, code string) (params [
|
||||
case geodata.Domain_Full:
|
||||
// Full.
|
||||
params = append(params, &config_parser.Param{
|
||||
Key: consts.RoutingDomain_Full,
|
||||
Key: string(consts.RoutingDomainKey_Full),
|
||||
Val: item.Value,
|
||||
})
|
||||
case geodata.Domain_RootDomain:
|
||||
// Suffix.
|
||||
params = append(params, &config_parser.Param{
|
||||
Key: consts.RoutingDomain_Suffix,
|
||||
Key: string(consts.RoutingDomainKey_Suffix),
|
||||
Val: item.Value,
|
||||
})
|
||||
case geodata.Domain_Plain:
|
||||
// Keyword.
|
||||
params = append(params, &config_parser.Param{
|
||||
Key: consts.RoutingDomain_Keyword,
|
||||
Key: string(consts.RoutingDomainKey_Keyword),
|
||||
Val: item.Value,
|
||||
})
|
||||
case geodata.Domain_Regex:
|
||||
// Regex.
|
||||
params = append(params, &config_parser.Param{
|
||||
Key: consts.RoutingDomain_Regex,
|
||||
Key: string(consts.RoutingDomainKey_Regex),
|
||||
Val: item.Value,
|
||||
})
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package sniffing
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package sniffing
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package quicutils
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package quicutils
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package quicutils
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package quicutils
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package quicutils
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package sniffing
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package sniffing
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package sniffing
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package sniffing
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package sniffing
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package sniffing
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package sniffing
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package config
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, mzz2017 <mzz@tuta.io>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package config
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package config
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package config
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, mzz2017 <mzz@tuta.io>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package control
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, mzz2017 <mzz@tuta.io>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package control
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2022, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package control
|
||||
@ -48,6 +48,12 @@ func (r _bpfPortRange) Encode() (b [16]byte) {
|
||||
return b
|
||||
}
|
||||
|
||||
func ParsePortRange(b []byte) (portStart, portEnd uint16) {
|
||||
portStart = binary.LittleEndian.Uint16(b[:2])
|
||||
portEnd = binary.LittleEndian.Uint16(b[2:])
|
||||
return portStart, portEnd
|
||||
}
|
||||
|
||||
func (o *bpfObjects) newLpmMap(keys []_bpfLpmKey, values []uint32) (m *ebpf.Map, err error) {
|
||||
m, err = ebpf.NewMap(&ebpf.MapSpec{
|
||||
Type: ebpf.LPMTrie,
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, mzz2017 <mzz@tuta.io>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package control
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2022, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package control
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2022, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package control
|
||||
@ -43,16 +43,14 @@ type ControlPlane struct {
|
||||
// TODO: add mutex?
|
||||
outbounds []*outbound.DialerGroup
|
||||
|
||||
SimulatedLpmTries [][]netip.Prefix
|
||||
SimulatedDomainSet []DomainSet
|
||||
Fallback string
|
||||
|
||||
// mutex protects the dnsCache.
|
||||
dnsCacheMu sync.Mutex
|
||||
dnsCache map[string]*dnsCache
|
||||
dnsUpstream DnsUpstreamRaw
|
||||
|
||||
dialMode consts.DialMode
|
||||
|
||||
routingMatcher *RoutingMatcher
|
||||
}
|
||||
|
||||
func NewControlPlane(
|
||||
@ -294,28 +292,30 @@ func NewControlPlane(
|
||||
if err = routing.ApplyMatcherBuilder(log, builder, rules, routingA.Fallback); err != nil {
|
||||
return nil, fmt.Errorf("ApplyMatcherBuilder: %w", err)
|
||||
}
|
||||
if err = builder.Build(); err != nil {
|
||||
return nil, fmt.Errorf("RoutingMatcherBuilder.Build: %w", err)
|
||||
if err = builder.BuildKernspace(); err != nil {
|
||||
return nil, fmt.Errorf("RoutingMatcherBuilder.BuildKernspace: %w", err)
|
||||
}
|
||||
routingMatcher, err := builder.BuildUserspace()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("RoutingMatcherBuilder.BuildKernspace: %w", err)
|
||||
}
|
||||
|
||||
dialMode, err := consts.ParseDialMode(global.DialMode)
|
||||
|
||||
c = &ControlPlane{
|
||||
log: log,
|
||||
core: core,
|
||||
deferFuncs: nil,
|
||||
listenIp: "0.0.0.0",
|
||||
outbounds: outbounds,
|
||||
SimulatedLpmTries: builder.SimulatedLpmTries,
|
||||
SimulatedDomainSet: builder.SimulatedDomainSet,
|
||||
Fallback: routingA.Fallback,
|
||||
dnsCacheMu: sync.Mutex{},
|
||||
dnsCache: make(map[string]*dnsCache),
|
||||
log: log,
|
||||
core: core,
|
||||
deferFuncs: nil,
|
||||
listenIp: "0.0.0.0",
|
||||
outbounds: outbounds,
|
||||
dnsCacheMu: sync.Mutex{},
|
||||
dnsCache: make(map[string]*dnsCache),
|
||||
dnsUpstream: DnsUpstreamRaw{
|
||||
Raw: global.DnsUpstream,
|
||||
FinishInitCallback: nil,
|
||||
},
|
||||
dialMode: dialMode,
|
||||
dialMode: dialMode,
|
||||
routingMatcher: routingMatcher,
|
||||
}
|
||||
|
||||
/// DNS upstream
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, mzz2017 <mzz@tuta.io>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package control
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package control
|
||||
@ -13,7 +13,6 @@ import (
|
||||
"github.com/mohae/deepcopy"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/v2rayA/dae/common"
|
||||
"github.com/v2rayA/dae/common/consts"
|
||||
"golang.org/x/net/dns/dnsmessage"
|
||||
"hash/fnv"
|
||||
"math/rand"
|
||||
@ -28,7 +27,7 @@ var (
|
||||
)
|
||||
|
||||
type dnsCache struct {
|
||||
DomainBitmap [consts.MaxMatchSetLen / 32]uint32
|
||||
DomainBitmap []uint32
|
||||
Answers []dnsmessage.Resource
|
||||
Deadline time.Time
|
||||
}
|
||||
@ -95,8 +94,12 @@ func (c *ControlPlane) BatchUpdateDomainRouting(cache *dnsCache) error {
|
||||
ip6 := ip.As16()
|
||||
keys = append(keys, common.Ipv6ByteSliceToUint32Array(ip6[:]))
|
||||
vals = append(vals, bpfDomainRouting{
|
||||
Bitmap: cache.DomainBitmap,
|
||||
Bitmap: [3]uint32{},
|
||||
})
|
||||
if len(cache.DomainBitmap) != len(vals[len(vals)-1].Bitmap) {
|
||||
return fmt.Errorf("domain bitmap length not sync with kern program")
|
||||
}
|
||||
copy(vals[len(vals)-1].Bitmap[:], cache.DomainBitmap)
|
||||
}
|
||||
if _, err := BpfMapBatchUpdate(c.core.bpf.DomainRoutingMap, keys, vals, &ebpf.BatchOptions{
|
||||
ElemFlags: uint64(ebpf.UpdateAny),
|
||||
@ -341,7 +344,7 @@ func (c *ControlPlane) UpdateDnsCache(host string, typ dnsmessage.Type, answers
|
||||
cache.Answers = answers
|
||||
} else {
|
||||
cache = &dnsCache{
|
||||
DomainBitmap: c.MatchDomainBitmap(strings.TrimSuffix(fqdn, ".")),
|
||||
DomainBitmap: c.routingMatcher.domainMatcher.MatchDomainBitmap(fqdn),
|
||||
Answers: answers,
|
||||
Deadline: deadline,
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, mzz2017 <mzz@tuta.io>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package control
|
||||
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package control
|
||||
|
||||
import (
|
||||
"github.com/v2rayA/dae/common/consts"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (c *ControlPlane) MatchDomainBitmap(domain string) (bitmap [consts.MaxMatchSetLen / 32]uint32) {
|
||||
// TODO: high performance implementation.
|
||||
for _, s := range c.SimulatedDomainSet {
|
||||
for _, d := range s.Domains {
|
||||
var hit bool
|
||||
switch s.Key {
|
||||
case consts.RoutingDomain_Suffix:
|
||||
if domain == d || strings.HasSuffix(domain, "."+d) {
|
||||
hit = true
|
||||
}
|
||||
case consts.RoutingDomain_Full:
|
||||
if strings.EqualFold(domain, d) {
|
||||
hit = true
|
||||
}
|
||||
case consts.RoutingDomain_Keyword:
|
||||
if strings.Contains(strings.ToLower(domain), strings.ToLower(d)) {
|
||||
hit = true
|
||||
}
|
||||
case consts.RoutingDomain_Regex:
|
||||
// FIXME: too slow
|
||||
for _, d := range s.Domains {
|
||||
if regexp.MustCompile(d).MatchString(strings.ToLower(domain)) {
|
||||
hit = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if hit {
|
||||
bitmap[s.RuleIndex/32] |= 1 << (s.RuleIndex % 32)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return bitmap
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
// +build ignore
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2022, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
#include <asm-generic/errno-base.h>
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2022, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package control
|
||||
@ -8,28 +8,24 @@ package control
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"github.com/Asphaltt/lpmtrie"
|
||||
"github.com/cilium/ebpf"
|
||||
"github.com/v2rayA/dae/common"
|
||||
"github.com/v2rayA/dae/common/consts"
|
||||
"github.com/v2rayA/dae/component/routing"
|
||||
"github.com/v2rayA/dae/component/routing/domain_matcher"
|
||||
"github.com/v2rayA/dae/pkg/config_parser"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type DomainSet struct {
|
||||
Key string
|
||||
RuleIndex int
|
||||
Domains []string
|
||||
}
|
||||
|
||||
type RoutingMatcherBuilder struct {
|
||||
*routing.DefaultMatcherBuilder
|
||||
outboundName2Id map[string]uint8
|
||||
bpf *bpfObjects
|
||||
rules []bpfMatchSet
|
||||
SimulatedLpmTries [][]netip.Prefix
|
||||
SimulatedDomainSet []DomainSet
|
||||
simulatedLpmTries [][]netip.Prefix
|
||||
simulatedDomainSet []routing.DomainSet
|
||||
Fallback string
|
||||
|
||||
err error
|
||||
@ -62,17 +58,17 @@ func (b *RoutingMatcherBuilder) AddDomain(f *config_parser.Function, key string,
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
switch key {
|
||||
case consts.RoutingDomain_Regex,
|
||||
consts.RoutingDomain_Full,
|
||||
consts.RoutingDomain_Keyword,
|
||||
consts.RoutingDomain_Suffix:
|
||||
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, DomainSet{
|
||||
Key: key,
|
||||
b.simulatedDomainSet = append(b.simulatedDomainSet, routing.DomainSet{
|
||||
Key: consts.RoutingDomainKey(key),
|
||||
RuleIndex: len(b.rules),
|
||||
Domains: values,
|
||||
})
|
||||
@ -94,8 +90,8 @@ func (b *RoutingMatcherBuilder) AddSourceMac(f *config_parser.Function, macAddrs
|
||||
prefix := netip.PrefixFrom(netip.AddrFrom16(addr16), 128)
|
||||
values = append(values, prefix)
|
||||
}
|
||||
lpmTrieIndex := len(b.SimulatedLpmTries)
|
||||
b.SimulatedLpmTries = append(b.SimulatedLpmTries, values)
|
||||
lpmTrieIndex := len(b.simulatedLpmTries)
|
||||
b.simulatedLpmTries = append(b.simulatedLpmTries, values)
|
||||
set := bpfMatchSet{
|
||||
Value: [16]byte{},
|
||||
Type: uint8(consts.MatchType_Mac),
|
||||
@ -111,8 +107,8 @@ func (b *RoutingMatcherBuilder) AddIp(f *config_parser.Function, values []netip.
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
lpmTrieIndex := len(b.SimulatedLpmTries)
|
||||
b.SimulatedLpmTries = append(b.SimulatedLpmTries, values)
|
||||
lpmTrieIndex := len(b.simulatedLpmTries)
|
||||
b.simulatedLpmTries = append(b.simulatedLpmTries, values)
|
||||
set := bpfMatchSet{
|
||||
Value: [16]byte{},
|
||||
Type: uint8(consts.MatchType_IpSet),
|
||||
@ -145,8 +141,8 @@ func (b *RoutingMatcherBuilder) AddSourceIp(f *config_parser.Function, values []
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
lpmTrieIndex := len(b.SimulatedLpmTries)
|
||||
b.SimulatedLpmTries = append(b.SimulatedLpmTries, values)
|
||||
lpmTrieIndex := len(b.simulatedLpmTries)
|
||||
b.simulatedLpmTries = append(b.simulatedLpmTries, values)
|
||||
set := bpfMatchSet{
|
||||
Value: [16]byte{},
|
||||
Type: uint8(consts.MatchType_SourceIpSet),
|
||||
@ -226,12 +222,12 @@ func (b *RoutingMatcherBuilder) AddFallback(outbound string) {
|
||||
})
|
||||
}
|
||||
|
||||
func (b *RoutingMatcherBuilder) Build() (err error) {
|
||||
func (b *RoutingMatcherBuilder) BuildKernspace() (err error) {
|
||||
if b.err != nil {
|
||||
return b.err
|
||||
}
|
||||
// Update lpm_array_map.
|
||||
for i, cidrs := range b.SimulatedLpmTries {
|
||||
for i, cidrs := range b.simulatedLpmTries {
|
||||
var keys []_bpfLpmKey
|
||||
var values []uint32
|
||||
for _, cidr := range cidrs {
|
||||
@ -264,3 +260,40 @@ func (b *RoutingMatcherBuilder) Build() (err error) {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *RoutingMatcherBuilder) BuildUserspace() (matcher *RoutingMatcher, err error) {
|
||||
if b.err != nil {
|
||||
return nil, b.err
|
||||
}
|
||||
var m RoutingMatcher
|
||||
// Update lpms.
|
||||
m.lpms = make([]lpmtrie.LpmTrie, len(b.simulatedLpmTries))
|
||||
for i, cidrs := range b.simulatedLpmTries {
|
||||
lpm, err := lpmtrie.New(128)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, cidr := range cidrs {
|
||||
lpm.Update(cidrToLpmTrieKey(cidr), 1)
|
||||
}
|
||||
m.lpms[i] = lpm
|
||||
}
|
||||
// Build domainMatcher
|
||||
m.domainMatcher = domain_matcher.NewAhocorasick(consts.MaxMatchSetLen)
|
||||
for _, domains := range b.simulatedDomainSet {
|
||||
m.domainMatcher.AddSet(domains.RuleIndex, domains.Domains, domains.Key)
|
||||
}
|
||||
if err = m.domainMatcher.Build(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Write routings.
|
||||
// Fallback rule MUST be the last.
|
||||
if b.rules[len(b.rules)-1].Type != uint8(consts.MatchType_Fallback) {
|
||||
b.err = fmt.Errorf("fallback rule MUST be the last")
|
||||
return nil, b.err
|
||||
}
|
||||
m.matches = b.rules
|
||||
|
||||
return &m, nil
|
||||
}
|
||||
|
150
control/routing_matcher_userspace.go
Normal file
150
control/routing_matcher_userspace.go
Normal file
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) 2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package control
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"github.com/Asphaltt/lpmtrie"
|
||||
"github.com/v2rayA/dae/common/consts"
|
||||
"github.com/v2rayA/dae/component/routing"
|
||||
"net"
|
||||
"net/netip"
|
||||
)
|
||||
|
||||
type RoutingMatcher struct {
|
||||
lpms []lpmtrie.LpmTrie
|
||||
domainMatcher routing.DomainMatcher // All domain matchSets use one DomainMatcher.
|
||||
|
||||
matches []bpfMatchSet
|
||||
}
|
||||
|
||||
// Match is modified from kern/tproxy.c; please keep sync.
|
||||
func (m *RoutingMatcher) Match(
|
||||
sourceAddr []byte,
|
||||
destAddr []byte,
|
||||
sourcePort uint16,
|
||||
destPort uint16,
|
||||
ipVersion consts.IpVersionType,
|
||||
l4proto consts.L4ProtoType,
|
||||
domain string,
|
||||
processName string,
|
||||
mac []byte,
|
||||
) (outboundIndex consts.OutboundIndex, err error) {
|
||||
if len(sourceAddr) != net.IPv6len || len(destAddr) != net.IPv6len || len(mac) != net.IPv6len {
|
||||
return 0, fmt.Errorf("bad address length")
|
||||
}
|
||||
lpmKeys := make([]*lpmtrie.Key, consts.MatchType_Mac+1)
|
||||
lpmKeys[consts.MatchType_IpSet] = &lpmtrie.Key{
|
||||
PrefixLen: 128,
|
||||
Data: destAddr,
|
||||
}
|
||||
lpmKeys[consts.MatchType_SourceIpSet] = &lpmtrie.Key{
|
||||
PrefixLen: 128,
|
||||
Data: sourceAddr,
|
||||
}
|
||||
lpmKeys[consts.MatchType_Mac] = &lpmtrie.Key{
|
||||
PrefixLen: 128,
|
||||
Data: mac,
|
||||
}
|
||||
var domainMatchBitmap []uint32
|
||||
if domain != "" {
|
||||
domainMatchBitmap = m.domainMatcher.MatchDomainBitmap(domain)
|
||||
}
|
||||
|
||||
goodSubrule := false
|
||||
badRule := false
|
||||
for i, match := range m.matches {
|
||||
if badRule || goodSubrule {
|
||||
goto beforeNextLoop
|
||||
}
|
||||
switch consts.MatchType(match.Type) {
|
||||
case consts.MatchType_IpSet, consts.MatchType_SourceIpSet, consts.MatchType_Mac:
|
||||
lpmIndex := int(binary.LittleEndian.Uint16(match.Value[:]))
|
||||
_, hit := m.lpms[lpmIndex].Lookup(*lpmKeys[int(match.Type)])
|
||||
if hit {
|
||||
goodSubrule = true
|
||||
}
|
||||
case consts.MatchType_DomainSet:
|
||||
if domainMatchBitmap != nil && (domainMatchBitmap[i/32]>>(i%32))&1 > 0 {
|
||||
goodSubrule = true
|
||||
}
|
||||
case consts.MatchType_Port:
|
||||
portStart, portEnd := ParsePortRange(match.Value[:])
|
||||
if destPort >= portStart &&
|
||||
destPort <= portEnd {
|
||||
goodSubrule = true
|
||||
}
|
||||
case consts.MatchType_SourcePort:
|
||||
portStart, portEnd := ParsePortRange(match.Value[:])
|
||||
if sourcePort >= portStart &&
|
||||
sourcePort <= portEnd {
|
||||
goodSubrule = true
|
||||
}
|
||||
case consts.MatchType_IpVersion:
|
||||
// LittleEndian
|
||||
if ipVersion&consts.IpVersionType(match.Value[0]) > 0 {
|
||||
goodSubrule = true
|
||||
}
|
||||
case consts.MatchType_L4Proto:
|
||||
// LittleEndian
|
||||
if l4proto&consts.L4ProtoType(match.Value[0]) > 0 {
|
||||
goodSubrule = true
|
||||
}
|
||||
case consts.MatchType_ProcessName:
|
||||
if processName != "" && string(match.Value[:]) == processName {
|
||||
goodSubrule = true
|
||||
}
|
||||
case consts.MatchType_Fallback:
|
||||
goodSubrule = true
|
||||
default:
|
||||
return 0, fmt.Errorf("unknown match type: %v", match.Type)
|
||||
}
|
||||
beforeNextLoop:
|
||||
outbound := consts.OutboundIndex(match.Outbound)
|
||||
if outbound != consts.OutboundLogicalOr {
|
||||
// This match_set reaches the end of subrule.
|
||||
// We are now at end of rule, or next match_set belongs to another
|
||||
// subrule.
|
||||
|
||||
if goodSubrule == match.Not {
|
||||
// This subrule does not hit.
|
||||
badRule = true
|
||||
}
|
||||
|
||||
// Reset goodSubrule.
|
||||
goodSubrule = false
|
||||
}
|
||||
|
||||
if outbound&consts.OutboundLogicalMask !=
|
||||
consts.OutboundLogicalMask {
|
||||
// Tail of a rule (line).
|
||||
// Decide whether to hit.
|
||||
if !badRule {
|
||||
if outbound == consts.OutboundDirect && destPort == 53 &&
|
||||
l4proto == consts.L4ProtoType_UDP {
|
||||
// DNS packet should go through control plane.
|
||||
return consts.OutboundControlPlaneDirect, nil
|
||||
}
|
||||
return outbound, nil
|
||||
}
|
||||
badRule = false
|
||||
}
|
||||
}
|
||||
return 0, fmt.Errorf("no match set hit")
|
||||
}
|
||||
|
||||
func cidrToLpmTrieKey(prefix netip.Prefix) lpmtrie.Key {
|
||||
bits := prefix.Bits()
|
||||
if prefix.Addr().Is4() {
|
||||
bits += 96
|
||||
}
|
||||
ip := prefix.Addr().As16()
|
||||
return lpmtrie.Key{
|
||||
PrefixLen: bits,
|
||||
Data: ip[:],
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2022, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package control
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, mzz2017 <mzz@tuta.io>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package control
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2022, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package control
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2022, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package control
|
||||
|
2
go.mod
2
go.mod
@ -3,9 +3,11 @@ module github.com/v2rayA/dae
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/Asphaltt/lpmtrie v0.0.0-20220205153150-3d814250b8ab
|
||||
github.com/adrg/xdg v0.4.0
|
||||
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12
|
||||
github.com/cilium/ebpf v0.10.0
|
||||
github.com/cloudflare/ahocorasick v0.0.0-20210425175752-730270c3e184
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
||||
|
4
go.sum
4
go.sum
@ -1,9 +1,13 @@
|
||||
github.com/Asphaltt/lpmtrie v0.0.0-20220205153150-3d814250b8ab h1:hzN25CB5VzeKk3/c1fi1oT03N+5365nVOMPAxixkADY=
|
||||
github.com/Asphaltt/lpmtrie v0.0.0-20220205153150-3d814250b8ab/go.mod h1:TdNTLzn3VVXKfmHAULK5gY+h/A1gLQ8NnwLB6cSN54g=
|
||||
github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
|
||||
github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E=
|
||||
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12 h1:npHgfD4Tl2WJS3AJaMUi5ynGDPUBfkg3U3fCzDyXZ+4=
|
||||
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
|
||||
github.com/cilium/ebpf v0.10.0 h1:nk5HPMeoBXtOzbkZBWym+ZWq1GIiHUsBFXxwewXAHLQ=
|
||||
github.com/cilium/ebpf v0.10.0/go.mod h1:DPiVdY/kT534dgc9ERmvP8mWA+9gvwgKfRvk4nNWnoE=
|
||||
github.com/cloudflare/ahocorasick v0.0.0-20210425175752-730270c3e184 h1:8yL+85JpbwrIc6m+7N1iYrjn/22z68jwrTIBOJHNe4k=
|
||||
github.com/cloudflare/ahocorasick v0.0.0-20210425175752-730270c3e184/go.mod h1:tGWUZLZp9ajsxUOnHmFFLnqnlKXsCn6GReG4jAD59H0=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
|
2
main.go
2
main.go
@ -2,7 +2,7 @@
|
||||
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2022, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package main
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package config_parser
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package config_parser
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2022, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package config_parser
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package config_parser
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2022, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package config_parser
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
// Modified from https://github.com/v2fly/v2ray-core/blob/42b166760b2ba8d984e514b830fcd44e23728e43/infra/conf/geodata/memconservative
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
// Modified from https://github.com/v2fly/v2ray-core/blob/42b166760b2ba8d984e514b830fcd44e23728e43/infra/conf/geodata/memconservative
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Copyright (c) since 2023, v2rayA Organization <team@v2raya.org>
|
||||
* Copyright (c) 2022-2023, v2rayA Organization <team@v2raya.org>
|
||||
*/
|
||||
|
||||
package logger
|
||||
|
Loading…
Reference in New Issue
Block a user