optimize: remove rush-answer detector because it does always work in all districts

This commit is contained in:
mzz2017 2023-03-29 18:14:06 +08:00
parent f915b47a9a
commit 12febe94cf
7 changed files with 57 additions and 31 deletions

View File

@ -10,6 +10,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/mzz2017/softwind/netproxy" "github.com/mzz2017/softwind/netproxy"
"github.com/sirupsen/logrus"
"golang.org/x/net/dns/dnsmessage" "golang.org/x/net/dns/dnsmessage"
"net/netip" "net/netip"
"sync" "sync"
@ -21,6 +22,17 @@ type Ip46 struct {
} }
func ResolveIp46(ctx context.Context, dialer netproxy.Dialer, dns netip.AddrPort, host string, tcp bool, race bool) (ipv46 *Ip46, err error) { func ResolveIp46(ctx context.Context, dialer netproxy.Dialer, dns netip.AddrPort, host string, tcp bool, race bool) (ipv46 *Ip46, err error) {
var log *logrus.Logger
if _log := ctx.Value("logger"); _log != nil {
log = _log.(*logrus.Logger)
defer func() {
if err == nil {
log.Tracef("ResolveIp46 %v using %v: A(%v) AAAA(%v)", host, systemDns, ipv46.Ip4, ipv46.Ip6)
} else {
log.Tracef("ResolveIp46 %v using %v: %v", host, systemDns, err)
}
}()
}
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(2) wg.Add(2)
var err4, err6 error var err4, err6 error

View File

@ -7,9 +7,9 @@ package dialer
import ( import (
"fmt" "fmt"
"github.com/daeuniverse/dae/common/consts"
"github.com/mzz2017/softwind/pkg/fastrand" "github.com/mzz2017/softwind/pkg/fastrand"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/daeuniverse/dae/common/consts"
"strings" "strings"
"sync" "sync"
"time" "time"
@ -138,10 +138,8 @@ func (a *AliveDialerSet) NotifyLatencyChange(dialer *Dialer, alive bool) {
// Dialer: not alive -> alive. // Dialer: not alive -> alive.
if index == -NotAlive { if index == -NotAlive {
a.log.WithFields(logrus.Fields{ a.log.WithFields(logrus.Fields{
"dialer": dialer.property.Name, "group": a.dialerGroupName,
"group": a.dialerGroupName, }).Infof("[NOT ALIVE --%v-> ALIVE] %v", a.CheckTyp.String(), dialer.property.Name)
"network": a.CheckTyp.StringWithoutDns(),
}).Infoln("NOT ALIVE -> ALIVE:")
} }
a.dialerToIndex[dialer] = len(a.inorderedAliveDialerSet) a.dialerToIndex[dialer] = len(a.inorderedAliveDialerSet)
a.inorderedAliveDialerSet = append(a.inorderedAliveDialerSet, dialer) a.inorderedAliveDialerSet = append(a.inorderedAliveDialerSet, dialer)
@ -151,10 +149,8 @@ func (a *AliveDialerSet) NotifyLatencyChange(dialer *Dialer, alive bool) {
if index >= 0 { if index >= 0 {
// Dialer: alive -> not alive. // Dialer: alive -> not alive.
a.log.WithFields(logrus.Fields{ a.log.WithFields(logrus.Fields{
"dialer": dialer.property.Name, "group": a.dialerGroupName,
"group": a.dialerGroupName, }).Infof("[ALIVE --%v-> NOT ALIVE] %v", a.CheckTyp.String(), dialer.property.Name)
"network": a.CheckTyp.StringWithoutDns(),
}).Infoln("ALIVE -> NOT ALIVE:")
// Remove the dialer from inorderedAliveDialerSet. // Remove the dialer from inorderedAliveDialerSet.
if index >= len(a.inorderedAliveDialerSet) { if index >= len(a.inorderedAliveDialerSet) {
a.log.Panicf("index:%v >= len(a.inorderedAliveDialerSet):%v", index, len(a.inorderedAliveDialerSet)) a.log.Panicf("index:%v >= len(a.inorderedAliveDialerSet):%v", index, len(a.inorderedAliveDialerSet))

View File

@ -167,6 +167,7 @@ func ParseCheckDnsOption(ctx context.Context, dnsHostPort string) (opt *CheckDns
type TcpCheckOptionRaw struct { type TcpCheckOptionRaw struct {
opt *TcpCheckOption opt *TcpCheckOption
mu sync.Mutex mu sync.Mutex
Log *logrus.Logger
Raw string Raw string
} }
@ -176,6 +177,7 @@ func (c *TcpCheckOptionRaw) Option() (opt *TcpCheckOption, err error) {
if c.opt == nil { if c.opt == nil {
ctx, cancel := context.WithTimeout(context.TODO(), 10*time.Second) ctx, cancel := context.WithTimeout(context.TODO(), 10*time.Second)
defer cancel() defer cancel()
ctx = context.WithValue(ctx, "logger", c.Log)
tcpCheckOption, err := ParseTcpCheckOption(ctx, c.Raw) tcpCheckOption, err := ParseTcpCheckOption(ctx, c.Raw)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to parse tcp_check_url: %w", err) return nil, fmt.Errorf("failed to parse tcp_check_url: %w", err)
@ -238,6 +240,7 @@ func (d *Dialer) aliveBackground() {
if !opt.Ip4.IsValid() { if !opt.Ip4.IsValid() {
d.Log.WithFields(logrus.Fields{ d.Log.WithFields(logrus.Fields{
"link": d.TcpCheckOptionRaw.Raw, "link": d.TcpCheckOptionRaw.Raw,
"dialer": d.property.Name,
"network": typ.String(), "network": typ.String(),
}).Debugln("Skip check due to no DNS record.") }).Debugln("Skip check due to no DNS record.")
return false, nil return false, nil
@ -259,6 +262,7 @@ func (d *Dialer) aliveBackground() {
if !opt.Ip6.IsValid() { if !opt.Ip6.IsValid() {
d.Log.WithFields(logrus.Fields{ d.Log.WithFields(logrus.Fields{
"link": d.TcpCheckOptionRaw.Raw, "link": d.TcpCheckOptionRaw.Raw,
"dialer": d.property.Name,
"network": typ.String(), "network": typ.String(),
}).Debugln("Skip check due to no DNS record.") }).Debugln("Skip check due to no DNS record.")
return false, nil return false, nil
@ -280,6 +284,7 @@ func (d *Dialer) aliveBackground() {
if !opt.Ip4.IsValid() { if !opt.Ip4.IsValid() {
d.Log.WithFields(logrus.Fields{ d.Log.WithFields(logrus.Fields{
"link": d.CheckDnsOptionRaw.Raw, "link": d.CheckDnsOptionRaw.Raw,
"dialer": d.property.Name,
"network": typ.String(), "network": typ.String(),
}).Debugln("Skip check due to no DNS record.") }).Debugln("Skip check due to no DNS record.")
return false, nil return false, nil
@ -301,6 +306,7 @@ func (d *Dialer) aliveBackground() {
if !opt.Ip6.IsValid() { if !opt.Ip6.IsValid() {
d.Log.WithFields(logrus.Fields{ d.Log.WithFields(logrus.Fields{
"link": d.CheckDnsOptionRaw.Raw, "link": d.CheckDnsOptionRaw.Raw,
"dialer": d.property.Name,
"network": typ.String(), "network": typ.String(),
}).Debugln("Skip check due to no DNS record.") }).Debugln("Skip check due to no DNS record.")
return false, nil return false, nil
@ -523,9 +529,16 @@ func (d *Dialer) HttpCheck(ctx context.Context, u *netutils.URL, ip netip.Addr)
defer resp.Body.Close() defer resp.Body.Close()
// Judge the status code. // Judge the status code.
if page := path.Base(req.URL.Path); strings.HasPrefix(page, "generate_") { if page := path.Base(req.URL.Path); strings.HasPrefix(page, "generate_") {
return strconv.Itoa(resp.StatusCode) == strings.TrimPrefix(page, "generate_"), nil if strconv.Itoa(resp.StatusCode) != strings.TrimPrefix(page, "generate_") {
return false, fmt.Errorf("unexpected status code: %v", resp.StatusCode)
}
return true, nil
} else {
if resp.StatusCode < 200 || resp.StatusCode >= 500 {
return false, fmt.Errorf("bad status code: %v", resp.StatusCode)
}
return true, nil
} }
return resp.StatusCode >= 200 && resp.StatusCode < 500, nil
} }
func (d *Dialer) DnsCheck(ctx context.Context, dns netip.AddrPort, tcp bool) (ok bool, err error) { func (d *Dialer) DnsCheck(ctx context.Context, dns netip.AddrPort, tcp bool) (ok bool, err error) {

View File

@ -6,10 +6,10 @@
package outbound package outbound
import ( import (
"github.com/mzz2017/softwind/pkg/fastrand"
"github.com/daeuniverse/dae/common/consts" "github.com/daeuniverse/dae/common/consts"
"github.com/daeuniverse/dae/component/outbound/dialer" "github.com/daeuniverse/dae/component/outbound/dialer"
"github.com/daeuniverse/dae/pkg/logger" "github.com/daeuniverse/dae/pkg/logger"
"github.com/mzz2017/softwind/pkg/fastrand"
"testing" "testing"
"time" "time"
) )
@ -43,7 +43,7 @@ func TestDialerGroup_Select_Fixed(t *testing.T) {
g := NewDialerGroup(option, "test-group", dialers, DialerSelectionPolicy{ g := NewDialerGroup(option, "test-group", dialers, DialerSelectionPolicy{
Policy: consts.DialerSelectionPolicy_Fixed, Policy: consts.DialerSelectionPolicy_Fixed,
FixedIndex: fixedIndex, FixedIndex: fixedIndex,
}, func(alive bool, networkType *dialer.NetworkType) {}) }, func(alive bool, networkType *dialer.NetworkType, isInit bool) {})
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
d, _, err := g.Select(TestNetworkType) d, _, err := g.Select(TestNetworkType)
if err != nil { if err != nil {
@ -90,7 +90,7 @@ func TestDialerGroup_Select_MinLastLatency(t *testing.T) {
} }
g := NewDialerGroup(option, "test-group", dialers, DialerSelectionPolicy{ g := NewDialerGroup(option, "test-group", dialers, DialerSelectionPolicy{
Policy: consts.DialerSelectionPolicy_MinLastLatency, Policy: consts.DialerSelectionPolicy_MinLastLatency,
}, func(alive bool, networkType *dialer.NetworkType) {}) }, func(alive bool, networkType *dialer.NetworkType, isInit bool) {})
// Test 1000 times. // Test 1000 times.
for i := 0; i < 1000; i++ { for i := 0; i < 1000; i++ {
@ -155,7 +155,7 @@ func TestDialerGroup_Select_Random(t *testing.T) {
} }
g := NewDialerGroup(option, "test-group", dialers, DialerSelectionPolicy{ g := NewDialerGroup(option, "test-group", dialers, DialerSelectionPolicy{
Policy: consts.DialerSelectionPolicy_Random, Policy: consts.DialerSelectionPolicy_Random,
}, func(alive bool, networkType *dialer.NetworkType) {}) }, func(alive bool, networkType *dialer.NetworkType, isInit bool) {})
count := make([]int, len(dialers)) count := make([]int, len(dialers))
for i := 0; i < 100; i++ { for i := 0; i < 100; i++ {
d, _, err := g.Select(TestNetworkType) d, _, err := g.Select(TestNetworkType)
@ -195,7 +195,7 @@ func TestDialerGroup_SetAlive(t *testing.T) {
} }
g := NewDialerGroup(option, "test-group", dialers, DialerSelectionPolicy{ g := NewDialerGroup(option, "test-group", dialers, DialerSelectionPolicy{
Policy: consts.DialerSelectionPolicy_Random, Policy: consts.DialerSelectionPolicy_Random,
}, func(alive bool, networkType *dialer.NetworkType) {}) }, func(alive bool, networkType *dialer.NetworkType, isInit bool) {})
zeroTarget := 3 zeroTarget := 3
g.MustGetAliveDialerSet(TestNetworkType).NotifyLatencyChange(dialers[zeroTarget], false) g.MustGetAliveDialerSet(TestNetworkType).NotifyLatencyChange(dialers[zeroTarget], false)
count := make([]int, len(dialers)) count := make([]int, len(dialers))

View File

@ -6,8 +6,8 @@
package domain_matcher package domain_matcher
import ( import (
"github.com/sirupsen/logrus"
"github.com/daeuniverse/dae/common/consts" "github.com/daeuniverse/dae/common/consts"
"github.com/sirupsen/logrus"
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
"math/rand" "math/rand"
"testing" "testing"
@ -21,7 +21,7 @@ func TestAhocorasickSlimtrie(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
bf := NewBruteforce(consts.MaxMatchSetLen) bf := NewBruteforce(consts.MaxMatchSetLen)
actrie := NewAhocorasickSlimtrie(consts.MaxMatchSetLen) actrie := NewAhocorasickSlimtrie(logrus.StandardLogger(), consts.MaxMatchSetLen)
for _, domains := range simulatedDomainSet { for _, domains := range simulatedDomainSet {
bf.AddSet(domains.RuleIndex, domains.Domains, domains.Key) bf.AddSet(domains.RuleIndex, domains.Domains, domains.Key)
actrie.AddSet(domains.RuleIndex, domains.Domains, domains.Key) actrie.AddSet(domains.RuleIndex, domains.Domains, domains.Key)

View File

@ -220,7 +220,7 @@ func NewControlPlane(
} }
option := &dialer.GlobalOption{ option := &dialer.GlobalOption{
Log: log, Log: log,
TcpCheckOptionRaw: dialer.TcpCheckOptionRaw{Raw: global.TcpCheckUrl}, TcpCheckOptionRaw: dialer.TcpCheckOptionRaw{Raw: global.TcpCheckUrl, Log: log},
CheckDnsOptionRaw: dialer.CheckDnsOptionRaw{Raw: global.UdpCheckDns}, CheckDnsOptionRaw: dialer.CheckDnsOptionRaw{Raw: global.UdpCheckDns},
CheckInterval: global.CheckInterval, CheckInterval: global.CheckInterval,
CheckTolerance: global.CheckTolerance, CheckTolerance: global.CheckTolerance,

View File

@ -312,10 +312,11 @@ func (c *DnsController) Handle_(dnsMessage *dnsmessage.Message, req *udpRequest)
return nil return nil
} }
// Make sure there is additional record OPT in the request to filter DNS rush-answer in the response process. //// NOTICE: Rush-answer detector was removed because it does not always work in all districts.
// Because rush-answer has no resp OPT. We can distinguish them from multiple responses. //// Make sure there is additional record OPT in the request to filter DNS rush-answer in the response process.
// Note that additional record OPT may not be supported by home router either. //// Because rush-answer has no resp OPT. We can distinguish them from multiple responses.
_, _ = EnsureAdditionalOpt(dnsMessage, true) //// Note that additional record OPT may not be supported by home router either.
//_, _ = EnsureAdditionalOpt(dnsMessage, true)
// Route request. // Route request.
upstream, err := c.routing.RequestSelect(dnsMessage) upstream, err := c.routing.RequestSelect(dnsMessage)
@ -382,13 +383,17 @@ func (c *DnsController) dialSend(req *udpRequest, data []byte, id uint16, upstre
// dnsRespHandler caches dns response and check rush answers. // dnsRespHandler caches dns response and check rush answers.
dnsRespHandler := c.DnsRespHandlerFactory(func(from netip.AddrPort) bool { dnsRespHandler := c.DnsRespHandlerFactory(func(from netip.AddrPort) bool {
// We only validate rush-ans when outbound is direct and pkt does not send to a home device. //// NOTICE: Rush-answer detector was removed because it does not always work in all districts.
// Because additional record OPT may not be supported by home router. //// We only validate rush-ans when outbound is direct and pkt does not send to a home device.
// So se should trust home devices even if they make rush-answer (or looks like). //// Because additional record OPT may not be supported by home router.
return dialArgument.bestDialer.Property().Name == "direct" && //// So se should trust home devices even if they make rush-answer (or looks like).
!from.Addr().IsPrivate() && //return dialArgument.bestDialer.Property().Name == "direct" &&
!from.Addr().IsLoopback() && // !from.Addr().IsPrivate() &&
!from.Addr().IsUnspecified() // !from.Addr().IsLoopback() &&
// !from.Addr().IsUnspecified()
// Do not validate rush-answer.
return false
}) })
// Dial and send. // Dial and send.
var respMsg *dnsmessage.Message var respMsg *dnsmessage.Message
@ -456,12 +461,12 @@ func (c *DnsController) dialSend(req *udpRequest, data []byte, id uint16, upstre
if err != nil { if err != nil {
return fmt.Errorf("failed to read from: %v (dialer: %v): %w", dialArgument.bestTarget, dialArgument.bestDialer.Property().Name, err) return fmt.Errorf("failed to read from: %v (dialer: %v): %w", dialArgument.bestTarget, dialArgument.bestDialer.Property().Name, err)
} }
cancelDnsReqCtx()
respMsg, err = dnsRespHandler(respBuf[:n], dialArgument.bestTarget) respMsg, err = dnsRespHandler(respBuf[:n], dialArgument.bestTarget)
if err != nil { if err != nil {
return err return err
} }
if respMsg != nil { if respMsg != nil {
cancelDnsReqCtx()
break break
} }
} }