Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
08faa82
Add concurrency control and pipelining for DNS handling
Feb 3, 2026
8d1ea12
fix: validate DNS payload length and handle nil options in DnsController
Feb 3, 2026
058e72f
control: optimize DNS concurrency and connection lifecycle
Feb 13, 2026
be5b6e9
refactor: improve UDP task queue management and enhance test coverage
Feb 14, 2026
d7f6b0c
feat(sniffing): add IsLikelyQuicInitialPacket function for quick QUIC…
Feb 15, 2026
c0d7803
fix: enhance connection handling and add tests for timeout scenarios
Feb 15, 2026
e6e24df
feat(dns): implement DNS forwarder fallback mechanism and add tests f…
Feb 15, 2026
0341673
chore: remove deprecated configuration file and clean up unused settings
Feb 15, 2026
138be60
chore: update changelog with unreleased features, bug fixes, and tests
Feb 15, 2026
fd3d0fa
Merge branch 'main' into optimize/code-quality-fixes
olicesx Feb 15, 2026
c7460ed
feat(pool): enhance concurrency handling with create mutex management
Feb 15, 2026
e8c5b16
fix(dns): address PR936 review feedback on response safety and cache …
Feb 15, 2026
a248f8d
control: shard udp pools and switch ttl to janitor
Feb 16, 2026
1041fa9
control/dns: bypass singleflight on cache hit and reduce hot-path ove…
Feb 16, 2026
0ee51f3
optimize geodata expansion cache and reduce DNS rule retention
Feb 16, 2026
72c13f9
feat: wire local outbound with ss2022 protocol support
Feb 16, 2026
5a114fd
fix: update outbound module reference to new repository location
Feb 16, 2026
9e3abaa
refactor: comment out SS2022 protocol import and replace directive fo…
Feb 16, 2026
688b271
fix(dns,ci): remove invalid kernel-test input and harden dns hot paths
Feb 16, 2026
e70ba5d
feat(ss2022): finalize outbound pin and add matrix coverage
Feb 16, 2026
81f0007
fix(test): stabilize full regression and config marshal round-trip
Feb 16, 2026
08b66be
fix(dns): tolerate stale UDP DNS responses
Feb 16, 2026
489c3d3
fix(control): restore serialized UDP task scheduling
Feb 16, 2026
736b65a
fix(dns): remove singleflight cache bypass path
Feb 16, 2026
15017dc
perf(control): streamline UdpTaskPool hot path
Feb 16, 2026
28c95c9
perf(control): optimize IPv4 hash and DNS cache hot path
Feb 16, 2026
b92e099
perf(dns): reduce unnecessary wait in dual-stack preference path
Feb 17, 2026
4144718
perf(dns): trim avoidable waiting in hot paths
Feb 17, 2026
1d327fb
fix(dialer): preserve alive state when health check is skipped
Feb 17, 2026
e738ce9
test(dialer): cover skip-check avalanche prevention semantics
Feb 17, 2026
b2ed4d3
test(dialer): harden anti-cascade health-check coverage
Feb 17, 2026
ed4ad1d
perf(control): deduplicate real-domain probes in dial target selection
Feb 17, 2026
05d3a60
perf(control,dns): implement P0/P1 no-regret optimizations
Feb 17, 2026
e9815c1
perf(control): reduce domain-probe blocking on web request path
Feb 17, 2026
f0a1de5
perf(control): avoid first-hit page stall with async domain probe warmup
Feb 17, 2026
d78b85b
perf(dns): add non-blocking cache janitors and idle forwarder eviction
Feb 17, 2026
99b8230
feat(control): implement non-blocking task queue with overflow handli…
Feb 17, 2026
a795323
refactor(control): optimize memory alignment and improve task queue m…
Feb 17, 2026
5d3d838
perf(dns): add qtype string cache to reduce allocations in DNS query …
Feb 17, 2026
a3bf927
chore: update outbound to latest commit with ss/ss2022 optimizations
Feb 17, 2026
bef4d10
refactor(control): optimize DNS parameters for improved performance a…
Feb 18, 2026
7b4ecfd
refactor(control): enhance dialSend function to accept responseWriter…
Feb 18, 2026
e4405e8
refactor(control): enhance Close methods to prevent memory leaks and …
Feb 18, 2026
593afbb
feat(control): implement dead flag for UdpEndpoint to manage endpoint…
Feb 18, 2026
a4cc8a5
refactor(control): optimize DNS cache with pre-packed responses for i…
Feb 18, 2026
5c3df8e
refactor(control): optimize DNS cache performance with atomic deadlin…
Feb 18, 2026
760f564
refactor: replace context.TODO() with proper context propagation
Feb 19, 2026
02c4b6d
refactor(control): improve context handling for connection lifecycle …
Feb 19, 2026
0f8a44d
refactor(control): enhance routing tuple handling for UDP and TCP con…
Feb 19, 2026
03b7dc3
Refactor code structure for improved readability and maintainability
Feb 19, 2026
7b0d825
refactor(control): optimize cache handling and add latency testing fo…
Feb 19, 2026
8828b24
fix(dns): improve cache hit logging for CI compatibility
Feb 19, 2026
b9aa600
refactor(control): remove async route updater and optimize BPF update…
Feb 20, 2026
617603f
Enhance DNS Cache Tests: Update TTL Refresh Logic and Add Memory Leak…
Feb 20, 2026
bccfc50
fix: prevent UdpTaskPool convoy goroutine leak
Feb 20, 2026
61920ae
fix: prevent UdpTaskPool convoy goroutine leak
Feb 20, 2026
ee0b86e
feat(bpf): optimize UDP timeout with DNS-specific 17s expiry
Feb 20, 2026
542b282
perf(dns): optimize cache with Copy-on-Write for lock-free reads
Feb 20, 2026
3aa924c
fix(dns): reorder request handling to prioritize reject rules over cache
Feb 20, 2026
106014b
fix(dns): enhance debug logging for cache hits with destination address
Feb 20, 2026
fc49453
feat(cache): implement optimistic caching to improve hit rate and red…
Feb 20, 2026
a48be8c
feat(dns): add optimistic cache TTL and max cache size configuration …
Feb 21, 2026
1649a9d
Merge branch 'main' into optimize/code-quality-fixes
MarksonHon Feb 21, 2026
8d71000
chore: update outbound dependency with performance optimizations
Feb 21, 2026
4452b25
feat(tests): add performance benchmarks for cache eviction and sortin…
Feb 21, 2026
7a65922
perf: integrate UDP cipher cache and TCP splice optimizations
Feb 21, 2026
0bc2b50
fix: correct outbound dependency pseudo-version timestamp
Feb 21, 2026
2d73b9c
chore: update outbound dependency with trojan password hash cache opt…
Feb 21, 2026
de65f12
chore: update outbound dependency to complete optimizations branch
Feb 21, 2026
7a0b778
chore: update artifact upload name to include .zip extension and remo…
Feb 21, 2026
67444aa
perf(udp): increase task queue length from 128 to 4096
Feb 22, 2026
510e0a9
perf(bpf): comprehensive eBPF optimizations (P0, P1, Plan A, Plan B)
Feb 22, 2026
288c867
style(bpf): fix code style issues in tproxy.c
Feb 22, 2026
7bce071
fix(udp): demote normal UdpEndpoint EOF exits from Warn to Debug
MaurUppi Feb 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/kernel-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ jobs:
test-name: dae-test
image-version: ${{ matrix.kernel }}
host-mount: ./
dns-resolver: '1.1.1.1'
install-dependencies: 'true'
cmd: |
chmod +x /host/dae/dae
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/seed-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ jobs:
- name: Upload files to Artifacts
uses: actions/upload-artifact@v4
with:
name: dae-${{ steps.get_filename.outputs.ASSET_NAME }}
name: dae-${{ steps.get_filename.outputs.ASSET_NAME }}.zip
path: build/*

- name: Report result
Expand Down
16 changes: 16 additions & 0 deletions CHANGELOGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ curl --silent "https://api.github.com/repos/daeuniverse/dae/releases" | jq -r '.

<!-- BEGIN NEW TOC ENTRY -->

- [Unreleased](#unreleased)
- [v1.1.0rc1 (Pre-release)](#v110rc1-pre-release)
- [v1.0.0 (Latest)](#v100-latest)
- [v0.9.0)](#v090)
Expand Down Expand Up @@ -48,6 +49,21 @@ curl --silent "https://api.github.com/repos/daeuniverse/dae/releases" | jq -r '.
- [v0.1.0](#v010)
<!-- BEGIN NEW CHANGELOGS -->

### Unreleased

#### Features

- feat(dns): add robust DNS forward fallback path for `tcp+udp` upstream (UDP-first with TCP fallback on request failure).

#### Bug Fixes

- fix(dns): report DNS forward failures to dialer health feedback path to improve failover quality.
- fix(control): harden DNS/UDP connection lifecycle handling in high-concurrency paths.

#### Others

- test(control): add regression tests for DNS fallback, timeout cleanup, and pool concurrency safety.

### v1.1.0rc1 (Pre-release)

> Release date: 2025/11/03
Expand Down
26 changes: 12 additions & 14 deletions common/bitlist/bitlist_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ func TestBitList6(t *testing.T) {
if v := bm.Get(13); v != 0b110010 {
t.Fatal(fmt.Errorf("expect 0b%08b, got 0b%08b", 0b110010, v))
}
capBeforeTighten := bm.b.Cap()
bm.Tighten()
if bm.b.Cap() != 11 {
t.Fatal("failed to tighten", bm.b.Cap())
if bm.b.Cap() != bm.b.Len() || bm.b.Cap() > capBeforeTighten {
t.Fatal("failed to tighten", bm.b.Cap(), bm.b.Len(), capBeforeTighten)
}
if v := bm.Get(13); v != 0b110010 {
t.Fatal(fmt.Errorf("expect 0b%08b, got 0b%08b", 0b110010, v))
Expand All @@ -35,12 +36,10 @@ func TestBitList6(t *testing.T) {
if v := bm.Get(14); v != 0b110010 {
t.Fatal(fmt.Errorf("expect 0b%08b, got 0b%08b", 0b110010, v))
}
if bm.b.Cap() != 32 {
t.Fatal("unexpected grow behavior", bm.b.Cap())
}
capBeforeTighten = bm.b.Cap()
bm.Tighten()
if bm.b.Cap() != 12 {
t.Fatal("failed to tighten", bm.b.Cap())
if bm.b.Cap() != bm.b.Len() || bm.b.Cap() > capBeforeTighten {
t.Fatal("failed to tighten", bm.b.Cap(), bm.b.Len(), capBeforeTighten)
}
}

Expand All @@ -58,9 +57,10 @@ func TestBitList19(t *testing.T) {
if v := bm.Get(13); v != 0b1110010110010110010 {
t.Fatal(fmt.Errorf("expect 0b%019b, got 0b%019b", 0b1110010110010110010, v))
}
capBeforeTighten := bm.b.Cap()
bm.Tighten()
if bm.b.Cap() != 34 {
t.Fatal("failed to tighten", bm.b.Cap())
if bm.b.Cap() != bm.b.Len() || bm.b.Cap() > capBeforeTighten {
t.Fatal("failed to tighten", bm.b.Cap(), bm.b.Len(), capBeforeTighten)
}
if v := bm.Get(13); v != 0b1110010110010110010 {
t.Fatal(fmt.Errorf("expect 0b%019b, got 0b%019b", 0b1110010110010110010, v))
Expand All @@ -69,12 +69,10 @@ func TestBitList19(t *testing.T) {
if v := bm.Get(14); v != 0b1110010110010110010 {
t.Fatal(fmt.Errorf("expect 0b%019b, got 0b%019b", 0b1110010110010110010, v))
}
if bm.b.Cap() != 128 {
t.Fatal("unexpected grow behavior", bm.b.Cap())
}
capBeforeTighten = bm.b.Cap()
bm.Tighten()
if bm.b.Cap() != 36 {
t.Fatal("failed to tighten", bm.b.Cap())
if bm.b.Cap() != bm.b.Len() || bm.b.Cap() > capBeforeTighten {
t.Fatal("failed to tighten", bm.b.Cap(), bm.b.Len(), capBeforeTighten)
}
bm.Set(1, 0b0000000000000000000)
if v := bm.Get(1); v != 0b0000000000000000000 {
Expand Down
34 changes: 27 additions & 7 deletions common/consts/dialer.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,38 +8,55 @@ package consts
import (
"net/netip"
"time"
)

"golang.org/x/sys/unix"
// IP protocol numbers from IANA protocol numbers registry.
const (
// IPPROTO_TCP is the IP protocol number for TCP (RFC 793).
IPPROTO_TCP = 6
// IPPROTO_UDP is the IP protocol number for UDP (RFC 768).
IPPROTO_UDP = 17
)

// DialerSelectionPolicy defines the strategy for selecting a dialer from a group.
type DialerSelectionPolicy string

const (
DialerSelectionPolicy_Random DialerSelectionPolicy = "random"
DialerSelectionPolicy_Fixed DialerSelectionPolicy = "fixed"
DialerSelectionPolicy_MinAverage10Latencies DialerSelectionPolicy = "min_avg10"
// DialerSelectionPolicy_Random selects a dialer randomly.
DialerSelectionPolicy_Random DialerSelectionPolicy = "random"
// DialerSelectionPolicy_Fixed always selects the first dialer.
DialerSelectionPolicy_Fixed DialerSelectionPolicy = "fixed"
// DialerSelectionPolicy_MinAverage10Latencies selects the dialer with minimum average latency of last 10 checks.
DialerSelectionPolicy_MinAverage10Latencies DialerSelectionPolicy = "min_avg10"
// DialerSelectionPolicy_MinMovingAverageLatencies selects the dialer with minimum moving average latency.
DialerSelectionPolicy_MinMovingAverageLatencies DialerSelectionPolicy = "min_moving_avg"
DialerSelectionPolicy_MinLastLatency DialerSelectionPolicy = "min"
// DialerSelectionPolicy_MinLastLatency selects the dialer with minimum last latency.
DialerSelectionPolicy_MinLastLatency DialerSelectionPolicy = "min"
)

const (
// UdpCheckLookupHost is the default host used for UDP connectivity checks.
UdpCheckLookupHost = "connectivitycheck.gstatic.com."
// DefaultDialTimeout is the default timeout for dialing.
DefaultDialTimeout = 8 * time.Second
)

// L4ProtoStr represents a layer 4 protocol as a string.
type L4ProtoStr string

const (
// L4ProtoStr_TCP represents the TCP protocol.
L4ProtoStr_TCP L4ProtoStr = "tcp"
// L4ProtoStr_UDP represents the UDP protocol.
L4ProtoStr_UDP L4ProtoStr = "udp"
)

func (l L4ProtoStr) ToL4Proto() uint8 {
switch l {
case L4ProtoStr_TCP:
return unix.IPPROTO_TCP
return IPPROTO_TCP
case L4ProtoStr_UDP:
return unix.IPPROTO_IDP
return IPPROTO_UDP
}
panic("unsupported l4proto")
}
Expand All @@ -54,10 +71,13 @@ func (l L4ProtoStr) ToL4ProtoType() L4ProtoType {
panic("unsupported l4proto: " + l)
}

// IpVersionStr represents an IP version as a string.
type IpVersionStr string

const (
// IpVersionStr_4 represents IPv4.
IpVersionStr_4 IpVersionStr = "4"
// IpVersionStr_6 represents IPv6.
IpVersionStr_6 IpVersionStr = "6"
)

Expand Down
39 changes: 39 additions & 0 deletions common/consts/dialer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package consts

import (
"testing"
)

func TestL4ProtoStr_ToL4Proto(t *testing.T) {
tests := []struct {
name string
l L4ProtoStr
want uint8
}{
{"TCP", L4ProtoStr_TCP, IPPROTO_TCP},
{"UDP", L4ProtoStr_UDP, IPPROTO_UDP},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.l.ToL4Proto(); got != tt.want {
t.Errorf("L4ProtoStr.ToL4Proto() = %v, want %v", got, tt.want)
}
})
}
}

func TestL4ProtoStr_ToL4ProtoType(t *testing.T) {
// Just verify it doesn't panic for known types
defer func() {
if r := recover(); r != nil {
t.Errorf("The code panicked: %v", r)
}
}()

if got := L4ProtoStr_TCP.ToL4ProtoType(); got != L4ProtoType_TCP {
t.Errorf("Expected TCP, got %v", got)
}
if got := L4ProtoStr_UDP.ToL4ProtoType(); got != L4ProtoType_UDP {
t.Errorf("Expected UDP, got %v", got)
}
}
3 changes: 3 additions & 0 deletions common/netutils/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,9 @@ func ResolveSOA(ctx context.Context, d netproxy.Dialer, dns netip.AddrPort, host
}

func resolve(ctx context.Context, d netproxy.Dialer, dns netip.AddrPort, host string, typ uint16, network string) (ans []dnsmessage.RR, err error) {
if d == nil {
return nil, fmt.Errorf("nil dialer")
}
ctx, cancel := context.WithCancel(ctx)
defer cancel()
fqdn := dnsmessage.CanonicalName(host)
Expand Down
5 changes: 3 additions & 2 deletions common/netutils/ip46_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ import (
func TestResolveIp46(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
direct.InitDirectDialers("223.5.5.5:53")
ip46, err4, err6 := ResolveIp46(ctx, direct.SymmetricDirect, netip.MustParseAddrPort("223.5.5.5:53"), "ipv6.google.com", "udp", false)
if err4 != nil || err6 != nil {
t.Fatal(err4, err6)
if err4 != nil && err6 != nil {
t.Skipf("network unavailable or DNS blocked in test environment: err4=%v err6=%v", err4, err6)
}
if !ip46.Ip4.IsValid() && !ip46.Ip6.IsValid() {
t.Fatal("No record")
Expand Down
11 changes: 7 additions & 4 deletions common/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,17 +427,20 @@ func AddrToDnsType(addr netip.Addr) uint16 {
}
}

// Htons converts the unsigned short integer hostshort from host byte order to network byte order.
// Htons converts the unsigned short integer from host byte order to network byte order (big-endian).
// This is used when communicating with eBPF programs which expect network byte order.
func Htons(i uint16) uint16 {
b := make([]byte, 2)
binary.BigEndian.PutUint16(b, i)
return *(*uint16)(unsafe.Pointer(&b[0]))
}

// Ntohs converts the unsigned short integer hostshort from host byte order to network byte order.
// Ntohs converts the unsigned short integer from network byte order (big-endian) to host byte order.
// This is used when reading values from eBPF programs which are in network byte order.
func Ntohs(i uint16) uint16 {
bytes := *(*[2]byte)(unsafe.Pointer(&i))
return binary.BigEndian.Uint16(bytes[:])
b := make([]byte, 2)
internal.NativeEndian.PutUint16(b, i)
return binary.BigEndian.Uint16(b)
}

func GetDefaultIfnames() (defaultIfs []string, err error) {
Expand Down
34 changes: 17 additions & 17 deletions component/dns/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ var ErrBadUpstreamFormat = fmt.Errorf("bad upstream format")
type Dns struct {
log *logrus.Logger
upstream []*UpstreamResolver
upstream2IndexMu sync.Mutex
upstream2Index map[*Upstream]int
upstream2Index sync.Map
reqMatcher *RequestMatcher
respMatcher *ResponseMatcher
}
Expand All @@ -41,10 +40,8 @@ type NewOption struct {
func New(dns *config.Dns, opt *NewOption) (s *Dns, err error) {
s = &Dns{
log: opt.Logger,
upstream2Index: map[*Upstream]int{
nil: int(consts.DnsRequestOutboundIndex_AsIs),
},
}
s.upstream2Index.Store((*Upstream)(nil), int(consts.DnsRequestOutboundIndex_AsIs))
// Parse upstream.
upstreamName2Id := map[string]uint8{}
for i, upstreamRaw := range dns.Upstream {
Expand Down Expand Up @@ -73,9 +70,7 @@ func New(dns *config.Dns, opt *NewOption) (s *Dns, err error) {
}
}

s.upstream2IndexMu.Lock()
s.upstream2Index[upstream] = i
s.upstream2IndexMu.Unlock()
s.upstream2Index.Store(upstream, i)
return nil
}
}(i),
Expand All @@ -87,22 +82,25 @@ func New(dns *config.Dns, opt *NewOption) (s *Dns, err error) {
s.upstream = append(s.upstream, r)
}
// Optimize routings.
if dns.Routing.Request.Rules, err = routing.ApplyRulesOptimizers(dns.Routing.Request.Rules,
requestRules, err := routing.ApplyRulesOptimizers(dns.Routing.Request.Rules,
&routing.DatReaderOptimizer{Logger: opt.Logger, LocationFinder: opt.LocationFinder},
&routing.MergeAndSortRulesOptimizer{},
&routing.DeduplicateParamsOptimizer{},
); err != nil {
)
if err != nil {
return nil, err
}
if dns.Routing.Response.Rules, err = routing.ApplyRulesOptimizers(dns.Routing.Response.Rules,

responseRules, err := routing.ApplyRulesOptimizers(dns.Routing.Response.Rules,
&routing.DatReaderOptimizer{Logger: opt.Logger, LocationFinder: opt.LocationFinder},
&routing.MergeAndSortRulesOptimizer{},
&routing.DeduplicateParamsOptimizer{},
); err != nil {
)
if err != nil {
return nil, err
}
// Parse request routing.
reqMatcherBuilder, err := NewRequestMatcherBuilder(opt.Logger, dns.Routing.Request.Rules, upstreamName2Id, dns.Routing.Request.Fallback)
reqMatcherBuilder, err := NewRequestMatcherBuilder(opt.Logger, requestRules, upstreamName2Id, dns.Routing.Request.Fallback)
if err != nil {
return nil, fmt.Errorf("failed to build DNS request routing: %w", err)
}
Expand All @@ -111,7 +109,7 @@ func New(dns *config.Dns, opt *NewOption) (s *Dns, err error) {
return nil, fmt.Errorf("failed to build DNS request routing: %w", err)
}
// Parse response routing.
respMatcherBuilder, err := NewResponseMatcherBuilder(opt.Logger, dns.Routing.Response.Rules, upstreamName2Id, dns.Routing.Response.Fallback)
respMatcherBuilder, err := NewResponseMatcherBuilder(opt.Logger, responseRules, upstreamName2Id, dns.Routing.Response.Fallback)
if err != nil {
return nil, fmt.Errorf("failed to build DNS response routing: %w", err)
}
Expand Down Expand Up @@ -207,9 +205,11 @@ func (s *Dns) ResponseSelect(msg *dnsmessage.Msg, fromUpstream *Upstream) (upstr
}
}

s.upstream2IndexMu.Lock()
from := s.upstream2Index[fromUpstream]
s.upstream2IndexMu.Unlock()
fromValue, ok := s.upstream2Index.Load(fromUpstream)
if !ok {
fromValue = int(consts.DnsRequestOutboundIndex_AsIs)
}
from := fromValue.(int)
// Route.
upstreamIndex, err = s.respMatcher.Match(qname, qtype, ips, consts.DnsRequestOutboundIndex(from))
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion component/dns/upstream.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ func (u *UpstreamResolver) GetUpstream() (_ *Upstream, err error) {
u.init = true
}
}()
ctx, cancel := context.WithTimeout(context.TODO(), 10*time.Second)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if u.upstream, err = NewUpstream(ctx, u.Raw, u.Network); err != nil {
return nil, fmt.Errorf("failed to init dns upstream: %w", err)
Expand Down
3 changes: 2 additions & 1 deletion component/outbound/dialer/alive_dialer_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ func (a *AliveDialerSet) NotifyLatencyChange(dialer *Dialer, alive bool) {

if hasLatency {
bakOldBestDialer := a.minLatency.dialer
bakOldMinSortingLatency := a.minLatency.sortingLatency
// Calc minLatency.
a.dialerToLatency[dialer] = rawLatency
sortingLatency = a.SortingLatency(dialer)
Expand All @@ -222,7 +223,7 @@ func (a *AliveDialerSet) NotifyLatencyChange(dialer *Dialer, alive bool) {
a.minLatency.dialer = dialer
} else if a.minLatency.dialer == dialer {
a.minLatency.sortingLatency = sortingLatency
if !alive || sortingLatency > a.minLatency.sortingLatency {
if !alive || sortingLatency > bakOldMinSortingLatency {
// Latency increases.
if !alive {
a.minLatency.dialer = nil
Expand Down
Loading