mirror of
https://github.com/daeuniverse/dae.git
synced 2025-07-20 04:38:40 +07:00
feat: support independent tcp4, tcp6, udp4, udp6 connectivity check
This commit is contained in:
@ -12,6 +12,8 @@ import (
|
||||
"github.com/v2rayA/dae/component/outbound/dialer"
|
||||
"golang.org/x/net/proxy"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type DialerGroup struct {
|
||||
@ -24,7 +26,10 @@ type DialerGroup struct {
|
||||
Dialers []*dialer.Dialer
|
||||
|
||||
registeredAliveDialerSet bool
|
||||
AliveDialerSet *dialer.AliveDialerSet
|
||||
AliveTcp4DialerSet *dialer.AliveDialerSet
|
||||
AliveTcp6DialerSet *dialer.AliveDialerSet
|
||||
AliveUdp4DialerSet *dialer.AliveDialerSet
|
||||
AliveUdp6DialerSet *dialer.AliveDialerSet
|
||||
|
||||
selectionPolicy *DialerSelectionPolicy
|
||||
}
|
||||
@ -32,7 +37,10 @@ type DialerGroup struct {
|
||||
func NewDialerGroup(option *dialer.GlobalOption, name string, dialers []*dialer.Dialer, p DialerSelectionPolicy) *DialerGroup {
|
||||
log := option.Log
|
||||
var registeredAliveDialerSet bool
|
||||
a := dialer.NewAliveDialerSet(log, name, p.Policy, dialers, true)
|
||||
aliveTcp4DialerSet := dialer.NewAliveDialerSet(log, name, consts.L4ProtoStr_TCP, consts.IpVersionStr_4, p.Policy, dialers, true)
|
||||
aliveTcp6DialerSet := dialer.NewAliveDialerSet(log, name, consts.L4ProtoStr_TCP, consts.IpVersionStr_6, p.Policy, dialers, true)
|
||||
aliveUdp4DialerSet := dialer.NewAliveDialerSet(log, name, consts.L4ProtoStr_UDP, consts.IpVersionStr_4, p.Policy, dialers, true)
|
||||
aliveUdp6DialerSet := dialer.NewAliveDialerSet(log, name, consts.L4ProtoStr_UDP, consts.IpVersionStr_6, p.Policy, dialers, true)
|
||||
|
||||
switch p.Policy {
|
||||
case consts.DialerSelectionPolicy_Random,
|
||||
@ -40,7 +48,10 @@ func NewDialerGroup(option *dialer.GlobalOption, name string, dialers []*dialer.
|
||||
consts.DialerSelectionPolicy_MinAverage10Latencies:
|
||||
// Need to know the alive state or latency.
|
||||
for _, d := range dialers {
|
||||
d.RegisterAliveDialerSet(a)
|
||||
d.RegisterAliveDialerSet(aliveTcp4DialerSet, consts.L4ProtoStr_TCP, consts.IpVersionStr_4)
|
||||
d.RegisterAliveDialerSet(aliveTcp6DialerSet, consts.L4ProtoStr_TCP, consts.IpVersionStr_6)
|
||||
d.RegisterAliveDialerSet(aliveUdp4DialerSet, consts.L4ProtoStr_UDP, consts.IpVersionStr_4)
|
||||
d.RegisterAliveDialerSet(aliveUdp6DialerSet, consts.L4ProtoStr_UDP, consts.IpVersionStr_6)
|
||||
}
|
||||
registeredAliveDialerSet = true
|
||||
|
||||
@ -56,7 +67,10 @@ func NewDialerGroup(option *dialer.GlobalOption, name string, dialers []*dialer.
|
||||
Name: name,
|
||||
Dialers: dialers,
|
||||
block: dialer.NewBlockDialer(option),
|
||||
AliveDialerSet: a,
|
||||
AliveTcp4DialerSet: aliveTcp4DialerSet,
|
||||
AliveTcp6DialerSet: aliveTcp6DialerSet,
|
||||
AliveUdp4DialerSet: aliveUdp4DialerSet,
|
||||
AliveUdp6DialerSet: aliveUdp6DialerSet,
|
||||
registeredAliveDialerSet: registeredAliveDialerSet,
|
||||
selectionPolicy: &p,
|
||||
}
|
||||
@ -65,7 +79,10 @@ func NewDialerGroup(option *dialer.GlobalOption, name string, dialers []*dialer.
|
||||
func (g *DialerGroup) Close() error {
|
||||
if g.registeredAliveDialerSet {
|
||||
for _, d := range g.Dialers {
|
||||
d.UnregisterAliveDialerSet(g.AliveDialerSet)
|
||||
d.UnregisterAliveDialerSet(g.AliveTcp4DialerSet, consts.L4ProtoStr_TCP, consts.IpVersionStr_4)
|
||||
d.UnregisterAliveDialerSet(g.AliveTcp6DialerSet, consts.L4ProtoStr_TCP, consts.IpVersionStr_6)
|
||||
d.UnregisterAliveDialerSet(g.AliveUdp4DialerSet, consts.L4ProtoStr_UDP, consts.IpVersionStr_4)
|
||||
d.UnregisterAliveDialerSet(g.AliveUdp6DialerSet, consts.L4ProtoStr_UDP, consts.IpVersionStr_6)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@ -77,17 +94,39 @@ func (g *DialerGroup) SetSelectionPolicy(policy DialerSelectionPolicy) {
|
||||
}
|
||||
|
||||
// Select selects a dialer from group according to selectionPolicy.
|
||||
func (g *DialerGroup) Select() (*dialer.Dialer, error) {
|
||||
func (g *DialerGroup) Select(l4proto consts.L4ProtoStr, ipversion consts.IpVersionStr) (*dialer.Dialer, error) {
|
||||
if len(g.Dialers) == 0 {
|
||||
return nil, fmt.Errorf("no dialer in this group")
|
||||
}
|
||||
var a *dialer.AliveDialerSet
|
||||
switch l4proto {
|
||||
case consts.L4ProtoStr_TCP:
|
||||
switch ipversion {
|
||||
case consts.IpVersionStr_4:
|
||||
a = g.AliveTcp4DialerSet
|
||||
case consts.IpVersionStr_6:
|
||||
a = g.AliveTcp6DialerSet
|
||||
}
|
||||
case consts.L4ProtoStr_UDP:
|
||||
switch ipversion {
|
||||
case consts.IpVersionStr_4:
|
||||
a = g.AliveUdp4DialerSet
|
||||
case consts.IpVersionStr_6:
|
||||
a = g.AliveUdp6DialerSet
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("DialerGroup.Select: unexpected l4proto type: %v", l4proto)
|
||||
}
|
||||
|
||||
switch g.selectionPolicy.Policy {
|
||||
case consts.DialerSelectionPolicy_Random:
|
||||
d := g.AliveDialerSet.GetRand()
|
||||
d := a.GetRand()
|
||||
if d == nil {
|
||||
// No alive dialer.
|
||||
g.log.Warnf("No alive dialer in DialerGroup %v, use \"block\".", g.Name)
|
||||
g.log.WithFields(logrus.Fields{
|
||||
"l4proto": l4proto,
|
||||
"group": g.Name,
|
||||
}).Warnf("No alive dialer in DialerGroup, use \"block\".")
|
||||
return g.block, nil
|
||||
}
|
||||
return d, nil
|
||||
@ -99,10 +138,13 @@ func (g *DialerGroup) Select() (*dialer.Dialer, error) {
|
||||
return g.Dialers[g.selectionPolicy.FixedIndex], nil
|
||||
|
||||
case consts.DialerSelectionPolicy_MinLastLatency, consts.DialerSelectionPolicy_MinAverage10Latencies:
|
||||
d := g.AliveDialerSet.GetMinLatency()
|
||||
d := a.GetMinLatency()
|
||||
if d == nil {
|
||||
// No alive dialer.
|
||||
g.log.Warnf("No alive dialer in DialerGroup %v, use \"block\".", g.Name)
|
||||
g.log.WithFields(logrus.Fields{
|
||||
"l4proto": l4proto,
|
||||
"group": g.Name,
|
||||
}).Warnf("No alive dialer in DialerGroup, use \"block\".")
|
||||
return g.block, nil
|
||||
}
|
||||
return d, nil
|
||||
@ -113,7 +155,20 @@ func (g *DialerGroup) Select() (*dialer.Dialer, error) {
|
||||
}
|
||||
|
||||
func (g *DialerGroup) Dial(network string, addr string) (c net.Conn, err error) {
|
||||
d, err := g.Select()
|
||||
var d proxy.Dialer
|
||||
ipAddr, err := netip.ParseAddr(addr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("DialerGroup.Dial only supports ip as addr")
|
||||
}
|
||||
ipversion := consts.IpVersionFromAddr(ipAddr)
|
||||
switch {
|
||||
case strings.HasPrefix(network, "tcp"):
|
||||
d, err = g.Select(consts.L4ProtoStr_TCP, ipversion)
|
||||
case strings.HasPrefix(network, "udp"):
|
||||
d, err = g.Select(consts.L4ProtoStr_UDP, ipversion)
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected network: %v", network)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
Reference in New Issue
Block a user