mirror of
https://github.com/daeuniverse/dae.git
synced 2024-12-23 01:14:46 +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
|
# 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,
|
# The development version of clang is distributed as the 'clang' binary,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package main
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package main
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package cmd
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package assets
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package consts
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package consts
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package consts
|
||||||
@ -41,10 +41,10 @@ const (
|
|||||||
DisableL4ChecksumPolicy_SetZero
|
DisableL4ChecksumPolicy_SetZero
|
||||||
)
|
)
|
||||||
|
|
||||||
type RoutingType uint8
|
type MatchType uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
MatchType_DomainSet RoutingType = iota
|
MatchType_DomainSet MatchType = iota
|
||||||
MatchType_IpSet
|
MatchType_IpSet
|
||||||
MatchType_SourceIpSet
|
MatchType_SourceIpSet
|
||||||
MatchType_Port
|
MatchType_Port
|
||||||
@ -65,6 +65,7 @@ const (
|
|||||||
OutboundControlPlaneDirect OutboundIndex = 0xFD
|
OutboundControlPlaneDirect OutboundIndex = 0xFD
|
||||||
OutboundLogicalOr OutboundIndex = 0xFE
|
OutboundLogicalOr OutboundIndex = 0xFE
|
||||||
OutboundLogicalAnd OutboundIndex = 0xFF
|
OutboundLogicalAnd OutboundIndex = 0xFF
|
||||||
|
OutboundLogicalMask OutboundIndex = 0xFE
|
||||||
|
|
||||||
OutboundMax = OutboundLogicalAnd
|
OutboundMax = OutboundLogicalAnd
|
||||||
OutboundUserDefinedMax = OutboundMustDirect - 1
|
OutboundUserDefinedMax = OutboundMustDirect - 1
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package consts
|
||||||
|
|
||||||
|
type RoutingDomainKey string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
RoutingDomain_Full = "full"
|
RoutingDomainKey_Full RoutingDomainKey = "full"
|
||||||
RoutingDomain_Keyword = "keyword"
|
RoutingDomainKey_Keyword RoutingDomainKey = "keyword"
|
||||||
RoutingDomain_Suffix = "suffix"
|
RoutingDomainKey_Suffix RoutingDomainKey = "suffix"
|
||||||
RoutingDomain_Regex = "regex"
|
RoutingDomainKey_Regex RoutingDomainKey = "regex"
|
||||||
|
|
||||||
Function_Domain = "domain"
|
Function_Domain = "domain"
|
||||||
Function_Ip = "ip"
|
Function_Ip = "ip"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package common
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package netutils
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package netutils
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package netutils
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package netutils
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package common
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package dialer
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package dialer
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package dialer
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package dialer
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package dialer
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package dialer
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package outbound
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package outbound
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package outbound
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package outbound
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
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
|
* 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
|
package routing
|
||||||
@ -19,6 +19,12 @@ var FakeOutbound_MUST_DIRECT = consts.OutboundMustDirect.String()
|
|||||||
var FakeOutbound_AND = consts.OutboundLogicalAnd.String()
|
var FakeOutbound_AND = consts.OutboundLogicalAnd.String()
|
||||||
var FakeOutbound_OR = consts.OutboundLogicalOr.String()
|
var FakeOutbound_OR = consts.OutboundLogicalOr.String()
|
||||||
|
|
||||||
|
type DomainSet struct {
|
||||||
|
Key consts.RoutingDomainKey
|
||||||
|
RuleIndex int
|
||||||
|
Domains []string
|
||||||
|
}
|
||||||
|
|
||||||
type MatcherBuilder interface {
|
type MatcherBuilder interface {
|
||||||
AddDomain(f *config_parser.Function, key string, values []string, outbound string)
|
AddDomain(f *config_parser.Function, key string, values []string, outbound string)
|
||||||
AddIp(f *config_parser.Function, values []netip.Prefix, outbound string)
|
AddIp(f *config_parser.Function, values []netip.Prefix, outbound string)
|
||||||
@ -32,7 +38,6 @@ type MatcherBuilder interface {
|
|||||||
AddFallback(outbound string)
|
AddFallback(outbound string)
|
||||||
AddAnyBefore(f *config_parser.Function, key string, values []string, outbound string)
|
AddAnyBefore(f *config_parser.Function, key string, values []string, outbound string)
|
||||||
AddAnyAfter(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) {
|
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) 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
|
* 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
|
package routing
|
||||||
@ -49,9 +49,9 @@ func (o *RefineFunctionParamKeyOptimizer) Optimize(rules []*config_parser.Routin
|
|||||||
// Rewrite to authoritative key name.
|
// Rewrite to authoritative key name.
|
||||||
switch param.Key {
|
switch param.Key {
|
||||||
case "", "domain":
|
case "", "domain":
|
||||||
param.Key = consts.RoutingDomain_Suffix
|
param.Key = string(consts.RoutingDomainKey_Suffix)
|
||||||
case "contains":
|
case "contains":
|
||||||
param.Key = consts.RoutingDomain_Keyword
|
param.Key = string(consts.RoutingDomainKey_Keyword)
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -169,25 +169,25 @@ func (o *DatReaderOptimizer) loadGeoSite(filename string, code string) (params [
|
|||||||
case geodata.Domain_Full:
|
case geodata.Domain_Full:
|
||||||
// Full.
|
// Full.
|
||||||
params = append(params, &config_parser.Param{
|
params = append(params, &config_parser.Param{
|
||||||
Key: consts.RoutingDomain_Full,
|
Key: string(consts.RoutingDomainKey_Full),
|
||||||
Val: item.Value,
|
Val: item.Value,
|
||||||
})
|
})
|
||||||
case geodata.Domain_RootDomain:
|
case geodata.Domain_RootDomain:
|
||||||
// Suffix.
|
// Suffix.
|
||||||
params = append(params, &config_parser.Param{
|
params = append(params, &config_parser.Param{
|
||||||
Key: consts.RoutingDomain_Suffix,
|
Key: string(consts.RoutingDomainKey_Suffix),
|
||||||
Val: item.Value,
|
Val: item.Value,
|
||||||
})
|
})
|
||||||
case geodata.Domain_Plain:
|
case geodata.Domain_Plain:
|
||||||
// Keyword.
|
// Keyword.
|
||||||
params = append(params, &config_parser.Param{
|
params = append(params, &config_parser.Param{
|
||||||
Key: consts.RoutingDomain_Keyword,
|
Key: string(consts.RoutingDomainKey_Keyword),
|
||||||
Val: item.Value,
|
Val: item.Value,
|
||||||
})
|
})
|
||||||
case geodata.Domain_Regex:
|
case geodata.Domain_Regex:
|
||||||
// Regex.
|
// Regex.
|
||||||
params = append(params, &config_parser.Param{
|
params = append(params, &config_parser.Param{
|
||||||
Key: consts.RoutingDomain_Regex,
|
Key: string(consts.RoutingDomainKey_Regex),
|
||||||
Val: item.Value,
|
Val: item.Value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package sniffing
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package sniffing
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package quicutils
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package quicutils
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package quicutils
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package quicutils
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package quicutils
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package sniffing
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package sniffing
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package sniffing
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package sniffing
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package sniffing
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package sniffing
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package sniffing
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package config
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package config
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package config
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package config
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package control
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package control
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package control
|
||||||
@ -48,6 +48,12 @@ func (r _bpfPortRange) Encode() (b [16]byte) {
|
|||||||
return b
|
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) {
|
func (o *bpfObjects) newLpmMap(keys []_bpfLpmKey, values []uint32) (m *ebpf.Map, err error) {
|
||||||
m, err = ebpf.NewMap(&ebpf.MapSpec{
|
m, err = ebpf.NewMap(&ebpf.MapSpec{
|
||||||
Type: ebpf.LPMTrie,
|
Type: ebpf.LPMTrie,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package control
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package control
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package control
|
||||||
@ -43,16 +43,14 @@ type ControlPlane struct {
|
|||||||
// TODO: add mutex?
|
// TODO: add mutex?
|
||||||
outbounds []*outbound.DialerGroup
|
outbounds []*outbound.DialerGroup
|
||||||
|
|
||||||
SimulatedLpmTries [][]netip.Prefix
|
|
||||||
SimulatedDomainSet []DomainSet
|
|
||||||
Fallback string
|
|
||||||
|
|
||||||
// mutex protects the dnsCache.
|
// mutex protects the dnsCache.
|
||||||
dnsCacheMu sync.Mutex
|
dnsCacheMu sync.Mutex
|
||||||
dnsCache map[string]*dnsCache
|
dnsCache map[string]*dnsCache
|
||||||
dnsUpstream DnsUpstreamRaw
|
dnsUpstream DnsUpstreamRaw
|
||||||
|
|
||||||
dialMode consts.DialMode
|
dialMode consts.DialMode
|
||||||
|
|
||||||
|
routingMatcher *RoutingMatcher
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewControlPlane(
|
func NewControlPlane(
|
||||||
@ -294,28 +292,30 @@ func NewControlPlane(
|
|||||||
if err = routing.ApplyMatcherBuilder(log, builder, rules, routingA.Fallback); err != nil {
|
if err = routing.ApplyMatcherBuilder(log, builder, rules, routingA.Fallback); err != nil {
|
||||||
return nil, fmt.Errorf("ApplyMatcherBuilder: %w", err)
|
return nil, fmt.Errorf("ApplyMatcherBuilder: %w", err)
|
||||||
}
|
}
|
||||||
if err = builder.Build(); err != nil {
|
if err = builder.BuildKernspace(); err != nil {
|
||||||
return nil, fmt.Errorf("RoutingMatcherBuilder.Build: %w", err)
|
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)
|
dialMode, err := consts.ParseDialMode(global.DialMode)
|
||||||
|
|
||||||
c = &ControlPlane{
|
c = &ControlPlane{
|
||||||
log: log,
|
log: log,
|
||||||
core: core,
|
core: core,
|
||||||
deferFuncs: nil,
|
deferFuncs: nil,
|
||||||
listenIp: "0.0.0.0",
|
listenIp: "0.0.0.0",
|
||||||
outbounds: outbounds,
|
outbounds: outbounds,
|
||||||
SimulatedLpmTries: builder.SimulatedLpmTries,
|
dnsCacheMu: sync.Mutex{},
|
||||||
SimulatedDomainSet: builder.SimulatedDomainSet,
|
dnsCache: make(map[string]*dnsCache),
|
||||||
Fallback: routingA.Fallback,
|
|
||||||
dnsCacheMu: sync.Mutex{},
|
|
||||||
dnsCache: make(map[string]*dnsCache),
|
|
||||||
dnsUpstream: DnsUpstreamRaw{
|
dnsUpstream: DnsUpstreamRaw{
|
||||||
Raw: global.DnsUpstream,
|
Raw: global.DnsUpstream,
|
||||||
FinishInitCallback: nil,
|
FinishInitCallback: nil,
|
||||||
},
|
},
|
||||||
dialMode: dialMode,
|
dialMode: dialMode,
|
||||||
|
routingMatcher: routingMatcher,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// DNS upstream
|
/// DNS upstream
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package control
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package control
|
||||||
@ -13,7 +13,6 @@ import (
|
|||||||
"github.com/mohae/deepcopy"
|
"github.com/mohae/deepcopy"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/v2rayA/dae/common"
|
"github.com/v2rayA/dae/common"
|
||||||
"github.com/v2rayA/dae/common/consts"
|
|
||||||
"golang.org/x/net/dns/dnsmessage"
|
"golang.org/x/net/dns/dnsmessage"
|
||||||
"hash/fnv"
|
"hash/fnv"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
@ -28,7 +27,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type dnsCache struct {
|
type dnsCache struct {
|
||||||
DomainBitmap [consts.MaxMatchSetLen / 32]uint32
|
DomainBitmap []uint32
|
||||||
Answers []dnsmessage.Resource
|
Answers []dnsmessage.Resource
|
||||||
Deadline time.Time
|
Deadline time.Time
|
||||||
}
|
}
|
||||||
@ -95,8 +94,12 @@ func (c *ControlPlane) BatchUpdateDomainRouting(cache *dnsCache) error {
|
|||||||
ip6 := ip.As16()
|
ip6 := ip.As16()
|
||||||
keys = append(keys, common.Ipv6ByteSliceToUint32Array(ip6[:]))
|
keys = append(keys, common.Ipv6ByteSliceToUint32Array(ip6[:]))
|
||||||
vals = append(vals, bpfDomainRouting{
|
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{
|
if _, err := BpfMapBatchUpdate(c.core.bpf.DomainRoutingMap, keys, vals, &ebpf.BatchOptions{
|
||||||
ElemFlags: uint64(ebpf.UpdateAny),
|
ElemFlags: uint64(ebpf.UpdateAny),
|
||||||
@ -341,7 +344,7 @@ func (c *ControlPlane) UpdateDnsCache(host string, typ dnsmessage.Type, answers
|
|||||||
cache.Answers = answers
|
cache.Answers = answers
|
||||||
} else {
|
} else {
|
||||||
cache = &dnsCache{
|
cache = &dnsCache{
|
||||||
DomainBitmap: c.MatchDomainBitmap(strings.TrimSuffix(fqdn, ".")),
|
DomainBitmap: c.routingMatcher.domainMatcher.MatchDomainBitmap(fqdn),
|
||||||
Answers: answers,
|
Answers: answers,
|
||||||
Deadline: deadline,
|
Deadline: deadline,
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
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
|
// +build ignore
|
||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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>
|
#include <asm-generic/errno-base.h>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package control
|
||||||
@ -8,28 +8,24 @@ package control
|
|||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/Asphaltt/lpmtrie"
|
||||||
"github.com/cilium/ebpf"
|
"github.com/cilium/ebpf"
|
||||||
"github.com/v2rayA/dae/common"
|
"github.com/v2rayA/dae/common"
|
||||||
"github.com/v2rayA/dae/common/consts"
|
"github.com/v2rayA/dae/common/consts"
|
||||||
"github.com/v2rayA/dae/component/routing"
|
"github.com/v2rayA/dae/component/routing"
|
||||||
|
"github.com/v2rayA/dae/component/routing/domain_matcher"
|
||||||
"github.com/v2rayA/dae/pkg/config_parser"
|
"github.com/v2rayA/dae/pkg/config_parser"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DomainSet struct {
|
|
||||||
Key string
|
|
||||||
RuleIndex int
|
|
||||||
Domains []string
|
|
||||||
}
|
|
||||||
|
|
||||||
type RoutingMatcherBuilder struct {
|
type RoutingMatcherBuilder struct {
|
||||||
*routing.DefaultMatcherBuilder
|
*routing.DefaultMatcherBuilder
|
||||||
outboundName2Id map[string]uint8
|
outboundName2Id map[string]uint8
|
||||||
bpf *bpfObjects
|
bpf *bpfObjects
|
||||||
rules []bpfMatchSet
|
rules []bpfMatchSet
|
||||||
SimulatedLpmTries [][]netip.Prefix
|
simulatedLpmTries [][]netip.Prefix
|
||||||
SimulatedDomainSet []DomainSet
|
simulatedDomainSet []routing.DomainSet
|
||||||
Fallback string
|
Fallback string
|
||||||
|
|
||||||
err error
|
err error
|
||||||
@ -62,17 +58,17 @@ func (b *RoutingMatcherBuilder) AddDomain(f *config_parser.Function, key string,
|
|||||||
if b.err != nil {
|
if b.err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch key {
|
switch consts.RoutingDomainKey(key) {
|
||||||
case consts.RoutingDomain_Regex,
|
case consts.RoutingDomainKey_Regex,
|
||||||
consts.RoutingDomain_Full,
|
consts.RoutingDomainKey_Full,
|
||||||
consts.RoutingDomain_Keyword,
|
consts.RoutingDomainKey_Keyword,
|
||||||
consts.RoutingDomain_Suffix:
|
consts.RoutingDomainKey_Suffix:
|
||||||
default:
|
default:
|
||||||
b.err = fmt.Errorf("AddDomain: unsupported key: %v", key)
|
b.err = fmt.Errorf("AddDomain: unsupported key: %v", key)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
b.SimulatedDomainSet = append(b.SimulatedDomainSet, DomainSet{
|
b.simulatedDomainSet = append(b.simulatedDomainSet, routing.DomainSet{
|
||||||
Key: key,
|
Key: consts.RoutingDomainKey(key),
|
||||||
RuleIndex: len(b.rules),
|
RuleIndex: len(b.rules),
|
||||||
Domains: values,
|
Domains: values,
|
||||||
})
|
})
|
||||||
@ -94,8 +90,8 @@ func (b *RoutingMatcherBuilder) AddSourceMac(f *config_parser.Function, macAddrs
|
|||||||
prefix := netip.PrefixFrom(netip.AddrFrom16(addr16), 128)
|
prefix := netip.PrefixFrom(netip.AddrFrom16(addr16), 128)
|
||||||
values = append(values, prefix)
|
values = append(values, prefix)
|
||||||
}
|
}
|
||||||
lpmTrieIndex := len(b.SimulatedLpmTries)
|
lpmTrieIndex := len(b.simulatedLpmTries)
|
||||||
b.SimulatedLpmTries = append(b.SimulatedLpmTries, values)
|
b.simulatedLpmTries = append(b.simulatedLpmTries, values)
|
||||||
set := bpfMatchSet{
|
set := bpfMatchSet{
|
||||||
Value: [16]byte{},
|
Value: [16]byte{},
|
||||||
Type: uint8(consts.MatchType_Mac),
|
Type: uint8(consts.MatchType_Mac),
|
||||||
@ -111,8 +107,8 @@ func (b *RoutingMatcherBuilder) AddIp(f *config_parser.Function, values []netip.
|
|||||||
if b.err != nil {
|
if b.err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
lpmTrieIndex := len(b.SimulatedLpmTries)
|
lpmTrieIndex := len(b.simulatedLpmTries)
|
||||||
b.SimulatedLpmTries = append(b.SimulatedLpmTries, values)
|
b.simulatedLpmTries = append(b.simulatedLpmTries, values)
|
||||||
set := bpfMatchSet{
|
set := bpfMatchSet{
|
||||||
Value: [16]byte{},
|
Value: [16]byte{},
|
||||||
Type: uint8(consts.MatchType_IpSet),
|
Type: uint8(consts.MatchType_IpSet),
|
||||||
@ -145,8 +141,8 @@ func (b *RoutingMatcherBuilder) AddSourceIp(f *config_parser.Function, values []
|
|||||||
if b.err != nil {
|
if b.err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
lpmTrieIndex := len(b.SimulatedLpmTries)
|
lpmTrieIndex := len(b.simulatedLpmTries)
|
||||||
b.SimulatedLpmTries = append(b.SimulatedLpmTries, values)
|
b.simulatedLpmTries = append(b.simulatedLpmTries, values)
|
||||||
set := bpfMatchSet{
|
set := bpfMatchSet{
|
||||||
Value: [16]byte{},
|
Value: [16]byte{},
|
||||||
Type: uint8(consts.MatchType_SourceIpSet),
|
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 {
|
if b.err != nil {
|
||||||
return b.err
|
return b.err
|
||||||
}
|
}
|
||||||
// Update lpm_array_map.
|
// Update lpm_array_map.
|
||||||
for i, cidrs := range b.SimulatedLpmTries {
|
for i, cidrs := range b.simulatedLpmTries {
|
||||||
var keys []_bpfLpmKey
|
var keys []_bpfLpmKey
|
||||||
var values []uint32
|
var values []uint32
|
||||||
for _, cidr := range cidrs {
|
for _, cidr := range cidrs {
|
||||||
@ -264,3 +260,40 @@ func (b *RoutingMatcherBuilder) Build() (err error) {
|
|||||||
}
|
}
|
||||||
return nil
|
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
|
* 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
|
package control
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package control
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package control
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package control
|
||||||
|
2
go.mod
2
go.mod
@ -3,9 +3,11 @@ module github.com/v2rayA/dae
|
|||||||
go 1.18
|
go 1.18
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/Asphaltt/lpmtrie v0.0.0-20220205153150-3d814250b8ab
|
||||||
github.com/adrg/xdg v0.4.0
|
github.com/adrg/xdg v0.4.0
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12
|
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12
|
||||||
github.com/cilium/ebpf v0.10.0
|
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/gorilla/websocket v1.5.0
|
||||||
github.com/json-iterator/go v1.1.12
|
github.com/json-iterator/go v1.1.12
|
||||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
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 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
|
||||||
github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E=
|
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 h1:npHgfD4Tl2WJS3AJaMUi5ynGDPUBfkg3U3fCzDyXZ+4=
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
|
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 h1:nk5HPMeoBXtOzbkZBWym+ZWq1GIiHUsBFXxwewXAHLQ=
|
||||||
github.com/cilium/ebpf v0.10.0/go.mod h1:DPiVdY/kT534dgc9ERmvP8mWA+9gvwgKfRvk4nNWnoE=
|
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/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.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
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
|
* 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
|
package main
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package config_parser
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package config_parser
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package config_parser
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package config_parser
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
package config_parser
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* 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
|
// 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
|
* 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
|
// 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
|
* 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
|
package logger
|
||||||
|
Loading…
Reference in New Issue
Block a user