feat: allow group override global node connectivity check (#623)

Co-authored-by: mzz2017 <2017@duck.com>
This commit is contained in:
神楽坂·喵
2024-09-08 22:13:06 +08:00
committed by GitHub
parent c8856614c5
commit 9f04adfe16
6 changed files with 115 additions and 14 deletions

View File

@ -19,6 +19,7 @@ import (
"strings" "strings"
"sync" "sync"
"time" "time"
"unsafe"
"github.com/daeuniverse/dae/common" "github.com/daeuniverse/dae/common"
@ -452,6 +453,18 @@ func (d *Dialer) aliveBackground() {
} }
} }
}() }()
var unused int
for _, opt := range CheckOpts {
if len(d.mustGetCollection(opt.networkType).AliveDialerSetSet) == 0 {
unused++
}
}
if unused == len(CheckOpts) {
d.Log.WithField("dialer", d.Property().Name).
WithField("p", unsafe.Pointer(d)).
Traceln("cleaned up due to unused")
return
}
var wg sync.WaitGroup var wg sync.WaitGroup
for range d.checkCh { for range d.checkCh {
for _, opt := range CheckOpts { for _, opt := range CheckOpts {

View File

@ -10,7 +10,10 @@ import (
"fmt" "fmt"
"sync" "sync"
"time" "time"
"unsafe"
"github.com/daeuniverse/dae/common"
"github.com/daeuniverse/dae/config"
D "github.com/daeuniverse/outbound/dialer" D "github.com/daeuniverse/outbound/dialer"
"github.com/daeuniverse/outbound/netproxy" "github.com/daeuniverse/outbound/netproxy"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -60,6 +63,21 @@ type Property struct {
type AliveDialerSetSet map[*AliveDialerSet]int type AliveDialerSetSet map[*AliveDialerSet]int
func NewGlobalOption(global *config.Global, log *logrus.Logger) *GlobalOption {
return &GlobalOption{
ExtraOption: D.ExtraOption{
AllowInsecure: global.AllowInsecure,
TlsImplementation: global.TlsImplementation,
UtlsImitate: global.UtlsImitate},
Log: log,
TcpCheckOptionRaw: TcpCheckOptionRaw{Raw: global.TcpCheckUrl, Log: log, ResolverNetwork: common.MagicNetwork("udp", global.SoMarkFromDae, global.Mptcp), Method: global.TcpCheckHttpMethod},
CheckDnsOptionRaw: CheckDnsOptionRaw{Raw: global.UdpCheckDns, ResolverNetwork: common.MagicNetwork("udp", global.SoMarkFromDae, global.Mptcp), Somark: global.SoMarkFromDae},
CheckInterval: global.CheckInterval,
CheckTolerance: global.CheckTolerance,
CheckDnsTcp: true,
}
}
// NewDialer is for register in general. // NewDialer is for register in general.
func NewDialer(dialer netproxy.Dialer, option *GlobalOption, iOption InstanceOption, property *Property) *Dialer { func NewDialer(dialer netproxy.Dialer, option *GlobalOption, iOption InstanceOption, property *Property) *Dialer {
var collections [6]*collection var collections [6]*collection
@ -80,9 +98,16 @@ func NewDialer(dialer netproxy.Dialer, option *GlobalOption, iOption InstanceOpt
ctx: ctx, ctx: ctx,
cancel: cancel, cancel: cancel,
} }
option.Log.WithField("dialer", d.Property().Name).
WithField("p", unsafe.Pointer(d)).
Traceln("NewDialer")
return d return d
} }
func (d *Dialer) Clone() *Dialer {
return NewDialer(d.Dialer, d.GlobalOption, d.InstanceOption, d.property)
}
func (d *Dialer) Close() error { func (d *Dialer) Close() error {
d.cancel() d.cancel()
d.tickerMu.Lock() d.tickerMu.Lock()

View File

@ -89,6 +89,12 @@ type Group struct {
Filter [][]*config_parser.Function `mapstructure:"filter" repeatable:""` Filter [][]*config_parser.Function `mapstructure:"filter" repeatable:""`
FilterAnnotation [][]*config_parser.Param `mapstructure:"_"` FilterAnnotation [][]*config_parser.Param `mapstructure:"_"`
Policy FunctionListOrString `mapstructure:"policy" required:""` Policy FunctionListOrString `mapstructure:"policy" required:""`
TcpCheckUrl []string `mapstructure:"tcp_check_url"`
TcpCheckHttpMethod string `mapstructure:"tcp_check_http_method"`
UdpCheckDns []string `mapstructure:"udp_check_dns"`
CheckInterval time.Duration `mapstructure:"check_interval"`
CheckTolerance time.Duration `mapstructure:"check_tolerance"`
} }
type DnsRequestRouting struct { type DnsRequestRouting struct {

View File

@ -85,4 +85,9 @@ min: Select node by the latency of last check.
min_avg10: Select node by the average of latencies of last 10 checks. min_avg10: Select node by the average of latencies of last 10 checks.
min_moving_avg: Select node by the moving average of latencies of checks, which means more recent latencies have higher weight. min_moving_avg: Select node by the moving average of latencies of checks, which means more recent latencies have higher weight.
`, `,
"tcp_check_url": "Override global config.",
"tcp_check_http_method": "Override global config.",
"udp_check_dns": "Override global config.",
"check_interval": "Override global config.",
"check_tolerance": "Override global config.",
} }

View File

@ -33,7 +33,6 @@ import (
"github.com/daeuniverse/dae/config" "github.com/daeuniverse/dae/config"
"github.com/daeuniverse/dae/pkg/config_parser" "github.com/daeuniverse/dae/pkg/config_parser"
internal "github.com/daeuniverse/dae/pkg/ebpf_internal" internal "github.com/daeuniverse/dae/pkg/ebpf_internal"
D "github.com/daeuniverse/outbound/dialer"
"github.com/daeuniverse/outbound/pool" "github.com/daeuniverse/outbound/pool"
"github.com/daeuniverse/outbound/protocol/direct" "github.com/daeuniverse/outbound/protocol/direct"
"github.com/daeuniverse/outbound/transport/grpc" "github.com/daeuniverse/outbound/transport/grpc"
@ -256,18 +255,7 @@ func NewControlPlane(
if global.AllowInsecure { if global.AllowInsecure {
log.Warnln("AllowInsecure is enabled, but it is not recommended. Please make sure you have to turn it on.") log.Warnln("AllowInsecure is enabled, but it is not recommended. Please make sure you have to turn it on.")
} }
option := &dialer.GlobalOption{ option := dialer.NewGlobalOption(global, log)
ExtraOption: D.ExtraOption{
AllowInsecure: global.AllowInsecure,
TlsImplementation: global.TlsImplementation,
UtlsImitate: global.UtlsImitate},
Log: log,
TcpCheckOptionRaw: dialer.TcpCheckOptionRaw{Raw: global.TcpCheckUrl, Log: log, ResolverNetwork: common.MagicNetwork("udp", global.SoMarkFromDae, global.Mptcp), Method: global.TcpCheckHttpMethod},
CheckDnsOptionRaw: dialer.CheckDnsOptionRaw{Raw: global.UdpCheckDns, ResolverNetwork: common.MagicNetwork("udp", global.SoMarkFromDae, global.Mptcp), Somark: global.SoMarkFromDae},
CheckInterval: global.CheckInterval,
CheckTolerance: global.CheckTolerance,
CheckDnsTcp: true,
}
// Dial mode. // Dial mode.
dialMode, err := consts.ParseDialMode(global.DialMode) dialMode, err := consts.ParseDialMode(global.DialMode)
@ -323,8 +311,22 @@ func NewControlPlane(
if len(dialers) == 0 { if len(dialers) == 0 {
log.Infoln("\t<Empty>") log.Infoln("\t<Empty>")
} }
groupOption, err := ParseGroupOverrideOption(group, *global, log)
finalOption := option
if err == nil && groupOption != nil {
newDialers := make([]*dialer.Dialer, 0)
for _, d := range dialers {
newDialer := d.Clone()
deferFuncs = append(deferFuncs, newDialer.Close)
newDialer.GlobalOption = groupOption
newDialers = append(newDialers, newDialer)
}
log.Infof(`Group "%v"'s check option has been override.`, group.Name)
dialers = newDialers
finalOption = groupOption
}
// Create dialer group and append it to outbounds. // Create dialer group and append it to outbounds.
dialerGroup := outbound.NewDialerGroup(option, group.Name, dialers, annos, *policy, dialerGroup := outbound.NewDialerGroup(finalOption, group.Name, dialers, annos, *policy,
core.outboundAliveChangeCallback(uint8(len(outbounds)), disableKernelAliveCallback)) core.outboundAliveChangeCallback(uint8(len(outbounds)), disableKernelAliveCallback))
outbounds = append(outbounds, dialerGroup) outbounds = append(outbounds, dialerGroup)
} }
@ -515,6 +517,36 @@ func ParseFixedDomainTtl(ks []config.KeyableString) (map[string]int, error) {
return m, nil return m, nil
} }
func ParseGroupOverrideOption(group config.Group, global config.Global, log *logrus.Logger) (*dialer.GlobalOption, error) {
result := global
changed := false
if group.TcpCheckUrl != nil {
result.TcpCheckUrl = group.TcpCheckUrl
changed = true
}
if group.TcpCheckHttpMethod != "" {
result.TcpCheckHttpMethod = group.TcpCheckHttpMethod
changed = true
}
if group.UdpCheckDns != nil {
result.UdpCheckDns = group.UdpCheckDns
changed = true
}
if group.CheckInterval != 0 {
result.CheckInterval = group.CheckInterval
changed = true
}
if group.CheckTolerance != 0 {
result.CheckTolerance = group.CheckTolerance
changed = true
}
if changed {
option := dialer.NewGlobalOption(&result, log)
return option, nil
}
return nil, nil
}
// EjectBpf will resect bpf from destroying life-cycle of control plane. // EjectBpf will resect bpf from destroying life-cycle of control plane.
func (c *ControlPlane) EjectBpf() *bpfObjects { func (c *ControlPlane) EjectBpf() *bpfObjects {
return c.core.EjectBpf() return c.core.EjectBpf()

View File

@ -40,6 +40,7 @@ global {
auto_config_kernel_parameter: true auto_config_kernel_parameter: true
##### Node connectivity check. ##### Node connectivity check.
# These options, as defaults, are effective when no definition is given in the group.
# Host of URL should have both IPv4 and IPv6 if you have double stack in local. # Host of URL should have both IPv4 and IPv6 if you have double stack in local.
# First is URL, others are IP addresses if given. # First is URL, others are IP addresses if given.
@ -213,6 +214,24 @@ group {
# Select the node with min average of the last 10 latencies from the group for every connection. # Select the node with min average of the last 10 latencies from the group for every connection.
policy: min_avg10 policy: min_avg10
} }
steam {
# Filter nodes from the global node pool defined by the subscription and node section above.
filter: subtag(my_sub) && !name(keyword: 'ExpireAt:')
# Select the node with min moving average of latencies from the group for every connection.
policy: min_moving_avg
# Override tcp_check_url in global.
tcp_check_url: 'http://test.steampowered.com'
# Override tcp_check_http_method in global
#tcp_check_http_method: HEAD
# Override udp_check_dns in global
#udp_check_dns: 'dns.google.com:53,8.8.8.8,2001:4860:4860::8888'
# Override check_interval in global
#check_interval: 30s
# Override check_tolerance in global
#check_tolerance: 50ms
}
} }
# See https://github.com/daeuniverse/dae/blob/main/docs/en/configuration/routing.md for full examples. # See https://github.com/daeuniverse/dae/blob/main/docs/en/configuration/routing.md for full examples.
@ -239,5 +258,6 @@ routing {
dip(geoip:cn) -> direct dip(geoip:cn) -> direct
domain(geosite:cn) -> direct domain(geosite:cn) -> direct
fallback: my_group fallback: my_group
} }