Compare commits

...

5 Commits

Author SHA1 Message Date
dependabot[bot]
85291651f9 build(deps): bump go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp
Bumps [go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp](https://github.com/open-telemetry/opentelemetry-go) from 1.31.0 to 1.43.0.
- [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.31.0...v1.43.0)

---
updated-dependencies:
- dependency-name: go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp
  dependency-version: 1.43.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-11 04:13:52 +00:00
世界
ebd31ca363 Add optimistic DNS cache 2026-04-11 12:10:52 +08:00
世界
6ba7a6f001 Fix tailscale error 2026-04-11 11:48:54 +08:00
世界
b7e1a14974 Fix darwin cgo DNS again 2026-04-10 23:17:56 +08:00
世界
a5c0112f0c Update naiveproxy to v147.0.7727.49-1 2026-04-10 20:59:59 +08:00
38 changed files with 1692 additions and 698 deletions

View File

@@ -1 +1 @@
ea7cd33752aed62603775af3df946c1b83f4b0b3
335e5bef5d88fc4474c9a70b865561f45a67de83

View File

@@ -3,6 +3,7 @@ package adapter
import (
"context"
"net/netip"
"time"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
@@ -31,12 +32,13 @@ type DNSClient interface {
}
type DNSQueryOptions struct {
Transport DNSTransport
Strategy C.DomainStrategy
LookupStrategy C.DomainStrategy
DisableCache bool
RewriteTTL *uint32
ClientSubnet netip.Prefix
Transport DNSTransport
Strategy C.DomainStrategy
LookupStrategy C.DomainStrategy
DisableCache bool
DisableOptimisticCache bool
RewriteTTL *uint32
ClientSubnet netip.Prefix
}
func DNSQueryOptionsFrom(ctx context.Context, options *option.DomainResolveOptions) (*DNSQueryOptions, error) {
@@ -49,11 +51,12 @@ func DNSQueryOptionsFrom(ctx context.Context, options *option.DomainResolveOptio
return nil, E.New("domain resolver not found: " + options.Server)
}
return &DNSQueryOptions{
Transport: transport,
Strategy: C.DomainStrategy(options.Strategy),
DisableCache: options.DisableCache,
RewriteTTL: options.RewriteTTL,
ClientSubnet: options.ClientSubnet.Build(netip.Prefix{}),
Transport: transport,
Strategy: C.DomainStrategy(options.Strategy),
DisableCache: options.DisableCache,
DisableOptimisticCache: options.DisableOptimisticCache,
RewriteTTL: options.RewriteTTL,
ClientSubnet: options.ClientSubnet.Build(netip.Prefix{}),
}, nil
}
@@ -63,6 +66,13 @@ type RDRCStore interface {
SaveRDRCAsync(transportName string, qName string, qType uint16, logger logger.Logger)
}
type DNSCacheStore interface {
LoadDNSCache(transportName string, qName string, qType uint16) (rawMessage []byte, expireAt time.Time, loaded bool)
SaveDNSCache(transportName string, qName string, qType uint16, rawMessage []byte, expireAt time.Time) error
SaveDNSCacheAsync(transportName string, qName string, qType uint16, rawMessage []byte, expireAt time.Time, logger logger.Logger)
ClearDNSCache() error
}
type DNSTransport interface {
Lifecycle
Type() string

View File

@@ -47,6 +47,12 @@ type CacheFile interface {
StoreRDRC() bool
RDRCStore
StoreDNS() bool
DNSCacheStore
SetDisableExpire(disableExpire bool)
SetOptimisticTimeout(timeout time.Duration)
LoadMode() string
StoreMode(mode string) error
LoadSelected(group string) string

7
box.go
View File

@@ -196,7 +196,10 @@ func New(options Options) (*Box, error) {
service.MustRegister[adapter.DNSTransportManager](ctx, dnsTransportManager)
service.MustRegister[adapter.ServiceManager](ctx, serviceManager)
service.MustRegister[adapter.CertificateProviderManager](ctx, certificateProviderManager)
dnsRouter := dns.NewRouter(ctx, logFactory, dnsOptions)
dnsRouter, err := dns.NewRouter(ctx, logFactory, dnsOptions)
if err != nil {
return nil, E.Cause(err, "initialize DNS router")
}
service.MustRegister[adapter.DNSRouter](ctx, dnsRouter)
service.MustRegister[adapter.DNSRuleSetUpdateValidator](ctx, dnsRouter)
networkManager, err := route.NewNetworkManager(ctx, logFactory.NewLogger("network"), routeOptions, dnsOptions)
@@ -372,7 +375,7 @@ func New(options Options) (*Box, error) {
}
}
if needCacheFile {
cacheFile := cachefile.New(ctx, common.PtrValueOrDefault(experimentalOptions.CacheFile))
cacheFile := cachefile.New(ctx, logFactory.NewLogger("cache-file"), common.PtrValueOrDefault(experimentalOptions.CacheFile))
service.MustRegister[adapter.CacheFile](ctx, cacheFile)
internalServices = append(internalServices, cacheFile)
}

View File

@@ -87,11 +87,12 @@ func NewWithOptions(options Options) (N.Dialer, error) {
}
server = dialOptions.DomainResolver.Server
dnsQueryOptions = adapter.DNSQueryOptions{
Transport: transport,
Strategy: strategy,
DisableCache: dialOptions.DomainResolver.DisableCache,
RewriteTTL: dialOptions.DomainResolver.RewriteTTL,
ClientSubnet: dialOptions.DomainResolver.ClientSubnet.Build(netip.Prefix{}),
Transport: transport,
Strategy: strategy,
DisableCache: dialOptions.DomainResolver.DisableCache,
DisableOptimisticCache: dialOptions.DomainResolver.DisableOptimisticCache,
RewriteTTL: dialOptions.DomainResolver.RewriteTTL,
ClientSubnet: dialOptions.DomainResolver.ClientSubnet.Build(netip.Prefix{}),
}
resolveFallbackDelay = time.Duration(dialOptions.FallbackDelay)
} else if options.DirectResolver {

View File

@@ -9,6 +9,8 @@ import (
"net/netip"
"time"
"github.com/sagernet/sing/common/bufio"
"github.com/sagernet/sing/common/bufio/deadline"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
@@ -431,6 +433,9 @@ func Run(options Options) (*Result, error) {
defer func() {
_ = packetConn.Close()
}()
if deadline.NeedAdditionalReadDeadline(packetConn) {
packetConn = deadline.NewPacketConn(bufio.NewPacketConn(packetConn))
}
select {
case <-ctx.Done():

View File

@@ -30,59 +30,63 @@ var (
var _ adapter.DNSClient = (*Client)(nil)
type Client struct {
timeout time.Duration
disableCache bool
disableExpire bool
independentCache bool
clientSubnet netip.Prefix
rdrc adapter.RDRCStore
initRDRCFunc func() adapter.RDRCStore
logger logger.ContextLogger
cache freelru.Cache[dns.Question, *dns.Msg]
cacheLock compatible.Map[dns.Question, chan struct{}]
transportCache freelru.Cache[transportCacheKey, *dns.Msg]
transportCacheLock compatible.Map[dns.Question, chan struct{}]
ctx context.Context
timeout time.Duration
disableCache bool
disableExpire bool
optimisticTimeout time.Duration
cacheCapacity uint32
clientSubnet netip.Prefix
rdrc adapter.RDRCStore
initRDRCFunc func() adapter.RDRCStore
dnsCache adapter.DNSCacheStore
initDNSCacheFunc func() adapter.DNSCacheStore
logger logger.ContextLogger
cache freelru.Cache[dnsCacheKey, *dns.Msg]
cacheLock compatible.Map[dnsCacheKey, chan struct{}]
backgroundRefresh compatible.Map[dnsCacheKey, struct{}]
}
type ClientOptions struct {
Timeout time.Duration
DisableCache bool
DisableExpire bool
IndependentCache bool
CacheCapacity uint32
ClientSubnet netip.Prefix
RDRC func() adapter.RDRCStore
Logger logger.ContextLogger
Context context.Context
Timeout time.Duration
DisableCache bool
DisableExpire bool
OptimisticTimeout time.Duration
CacheCapacity uint32
ClientSubnet netip.Prefix
RDRC func() adapter.RDRCStore
DNSCache func() adapter.DNSCacheStore
Logger logger.ContextLogger
}
func NewClient(options ClientOptions) *Client {
client := &Client{
timeout: options.Timeout,
disableCache: options.DisableCache,
disableExpire: options.DisableExpire,
independentCache: options.IndependentCache,
clientSubnet: options.ClientSubnet,
initRDRCFunc: options.RDRC,
logger: options.Logger,
}
if client.timeout == 0 {
client.timeout = C.DNSTimeout
}
cacheCapacity := options.CacheCapacity
if cacheCapacity < 1024 {
cacheCapacity = 1024
}
if !client.disableCache {
if !client.independentCache {
client.cache = common.Must1(freelru.NewSharded[dns.Question, *dns.Msg](cacheCapacity, maphash.NewHasher[dns.Question]().Hash32))
} else {
client.transportCache = common.Must1(freelru.NewSharded[transportCacheKey, *dns.Msg](cacheCapacity, maphash.NewHasher[transportCacheKey]().Hash32))
}
client := &Client{
ctx: options.Context,
timeout: options.Timeout,
disableCache: options.DisableCache,
disableExpire: options.DisableExpire,
optimisticTimeout: options.OptimisticTimeout,
cacheCapacity: cacheCapacity,
clientSubnet: options.ClientSubnet,
initRDRCFunc: options.RDRC,
initDNSCacheFunc: options.DNSCache,
logger: options.Logger,
}
if client.timeout == 0 {
client.timeout = C.DNSTimeout
}
if !client.disableCache && client.initDNSCacheFunc == nil {
client.initializeMemoryCache()
}
return client
}
type transportCacheKey struct {
type dnsCacheKey struct {
dns.Question
transportTag string
}
@@ -91,6 +95,19 @@ func (c *Client) Start() {
if c.initRDRCFunc != nil {
c.rdrc = c.initRDRCFunc()
}
if c.initDNSCacheFunc != nil {
c.dnsCache = c.initDNSCacheFunc()
}
if c.dnsCache == nil {
c.initializeMemoryCache()
}
}
func (c *Client) initializeMemoryCache() {
if c.disableCache || c.cache != nil {
return
}
c.cache = common.Must1(freelru.NewSharded[dnsCacheKey, *dns.Msg](c.cacheCapacity, maphash.NewHasher[dnsCacheKey]().Hash32))
}
func extractNegativeTTL(response *dns.Msg) (uint32, bool) {
@@ -107,6 +124,37 @@ func extractNegativeTTL(response *dns.Msg) (uint32, bool) {
return 0, false
}
func computeTimeToLive(response *dns.Msg) uint32 {
var timeToLive uint32
if len(response.Answer) == 0 {
if soaTTL, hasSOA := extractNegativeTTL(response); hasSOA {
return soaTTL
}
}
for _, recordList := range [][]dns.RR{response.Answer, response.Ns, response.Extra} {
for _, record := range recordList {
if record.Header().Rrtype == dns.TypeOPT {
continue
}
if timeToLive == 0 || record.Header().Ttl > 0 && record.Header().Ttl < timeToLive {
timeToLive = record.Header().Ttl
}
}
}
return timeToLive
}
func normalizeTTL(response *dns.Msg, timeToLive uint32) {
for _, recordList := range [][]dns.RR{response.Answer, response.Ns, response.Extra} {
for _, record := range recordList {
if record.Header().Rrtype == dns.TypeOPT {
continue
}
record.Header().Ttl = timeToLive
}
}
}
func (c *Client) Exchange(ctx context.Context, transport adapter.DNSTransport, message *dns.Msg, options adapter.DNSQueryOptions, responseChecker func(response *dns.Msg) bool) (*dns.Msg, error) {
if len(message.Question) == 0 {
if c.logger != nil {
@@ -121,13 +169,7 @@ func (c *Client) Exchange(ctx context.Context, transport adapter.DNSTransport, m
}
return FixedResponseStatus(message, dns.RcodeSuccess), nil
}
clientSubnet := options.ClientSubnet
if !clientSubnet.IsValid() {
clientSubnet = c.clientSubnet
}
if clientSubnet.IsValid() {
message = SetClientSubnet(message, clientSubnet)
}
message = c.prepareExchangeMessage(message, options)
isSimpleRequest := len(message.Question) == 1 &&
len(message.Ns) == 0 &&
@@ -139,40 +181,32 @@ func (c *Client) Exchange(ctx context.Context, transport adapter.DNSTransport, m
!options.ClientSubnet.IsValid()
disableCache := !isSimpleRequest || c.disableCache || options.DisableCache
if !disableCache {
if c.cache != nil {
cond, loaded := c.cacheLock.LoadOrStore(question, make(chan struct{}))
if loaded {
select {
case <-cond:
case <-ctx.Done():
return nil, ctx.Err()
}
} else {
defer func() {
c.cacheLock.Delete(question)
close(cond)
}()
}
} else if c.transportCache != nil {
cond, loaded := c.transportCacheLock.LoadOrStore(question, make(chan struct{}))
if loaded {
select {
case <-cond:
case <-ctx.Done():
return nil, ctx.Err()
}
} else {
defer func() {
c.transportCacheLock.Delete(question)
close(cond)
}()
cacheKey := dnsCacheKey{Question: question, transportTag: transport.Tag()}
cond, loaded := c.cacheLock.LoadOrStore(cacheKey, make(chan struct{}))
if loaded {
select {
case <-cond:
case <-ctx.Done():
return nil, ctx.Err()
}
} else {
defer func() {
c.cacheLock.Delete(cacheKey)
close(cond)
}()
}
response, ttl := c.loadResponse(question, transport)
response, ttl, isStale := c.loadResponse(question, transport)
if response != nil {
logCachedResponse(c.logger, ctx, response, ttl)
response.Id = message.Id
return response, nil
if isStale && !options.DisableOptimisticCache {
c.backgroundRefreshDNS(transport, question, message.Copy(), options, responseChecker)
logOptimisticResponse(c.logger, ctx, response)
response.Id = message.Id
return response, nil
} else if !isStale {
logCachedResponse(c.logger, ctx, response, ttl)
response.Id = message.Id
return response, nil
}
}
}
@@ -188,52 +222,10 @@ func (c *Client) Exchange(ctx context.Context, transport adapter.DNSTransport, m
return nil, ErrResponseRejectedCached
}
}
ctx, cancel := context.WithTimeout(ctx, c.timeout)
response, err := transport.Exchange(ctx, message)
cancel()
response, err := c.exchangeToTransport(ctx, transport, message)
if err != nil {
var rcodeError RcodeError
if errors.As(err, &rcodeError) {
response = FixedResponseStatus(message, int(rcodeError))
} else {
return nil, err
}
return nil, err
}
/*if question.Qtype == dns.TypeA || question.Qtype == dns.TypeAAAA {
validResponse := response
loop:
for {
var (
addresses int
queryCNAME string
)
for _, rawRR := range validResponse.Answer {
switch rr := rawRR.(type) {
case *dns.A:
break loop
case *dns.AAAA:
break loop
case *dns.CNAME:
queryCNAME = rr.Target
}
}
if queryCNAME == "" {
break
}
exMessage := *message
exMessage.Question = []dns.Question{{
Name: queryCNAME,
Qtype: question.Qtype,
}}
validResponse, err = c.Exchange(ctx, transport, &exMessage, options, responseChecker)
if err != nil {
return nil, err
}
}
if validResponse != response {
response.Answer = append(response.Answer, validResponse.Answer...)
}
}*/
disableCache = disableCache || (response.Rcode != dns.RcodeSuccess && response.Rcode != dns.RcodeNameError)
if responseChecker != nil {
var rejected bool
@@ -250,54 +242,7 @@ func (c *Client) Exchange(ctx context.Context, transport adapter.DNSTransport, m
return response, ErrResponseRejected
}
}
if question.Qtype == dns.TypeHTTPS {
if options.Strategy == C.DomainStrategyIPv4Only || options.Strategy == C.DomainStrategyIPv6Only {
for _, rr := range response.Answer {
https, isHTTPS := rr.(*dns.HTTPS)
if !isHTTPS {
continue
}
content := https.SVCB
content.Value = common.Filter(content.Value, func(it dns.SVCBKeyValue) bool {
if options.Strategy == C.DomainStrategyIPv4Only {
return it.Key() != dns.SVCB_IPV6HINT
} else {
return it.Key() != dns.SVCB_IPV4HINT
}
})
https.SVCB = content
}
}
}
var timeToLive uint32
if len(response.Answer) == 0 {
if soaTTL, hasSOA := extractNegativeTTL(response); hasSOA {
timeToLive = soaTTL
}
}
if timeToLive == 0 {
for _, recordList := range [][]dns.RR{response.Answer, response.Ns, response.Extra} {
for _, record := range recordList {
if record.Header().Rrtype == dns.TypeOPT {
continue
}
if timeToLive == 0 || record.Header().Ttl > 0 && record.Header().Ttl < timeToLive {
timeToLive = record.Header().Ttl
}
}
}
}
if options.RewriteTTL != nil {
timeToLive = *options.RewriteTTL
}
for _, recordList := range [][]dns.RR{response.Answer, response.Ns, response.Extra} {
for _, record := range recordList {
if record.Header().Rrtype == dns.TypeOPT {
continue
}
record.Header().Ttl = timeToLive
}
}
timeToLive := applyResponseOptions(question, response, options)
if !disableCache {
c.storeCache(transport, question, response, timeToLive)
}
@@ -363,8 +308,12 @@ func (c *Client) Lookup(ctx context.Context, transport adapter.DNSTransport, dom
func (c *Client) ClearCache() {
if c.cache != nil {
c.cache.Purge()
} else if c.transportCache != nil {
c.transportCache.Purge()
}
if c.dnsCache != nil {
err := c.dnsCache.ClearDNSCache()
if err != nil && c.logger != nil {
c.logger.Warn("clear DNS cache: ", err)
}
}
}
@@ -380,24 +329,22 @@ func (c *Client) storeCache(transport adapter.DNSTransport, question dns.Questio
if timeToLive == 0 {
return
}
if c.dnsCache != nil {
packed, err := message.Pack()
if err == nil {
expireAt := time.Now().Add(time.Second * time.Duration(timeToLive))
c.dnsCache.SaveDNSCacheAsync(transport.Tag(), question.Name, question.Qtype, packed, expireAt, c.logger)
}
return
}
if c.cache == nil {
return
}
key := dnsCacheKey{Question: question, transportTag: transport.Tag()}
if c.disableExpire {
if !c.independentCache {
c.cache.Add(question, message.Copy())
} else {
c.transportCache.Add(transportCacheKey{
Question: question,
transportTag: transport.Tag(),
}, message.Copy())
}
c.cache.Add(key, message.Copy())
} else {
if !c.independentCache {
c.cache.AddWithLifetime(question, message.Copy(), time.Second*time.Duration(timeToLive))
} else {
c.transportCache.AddWithLifetime(transportCacheKey{
Question: question,
transportTag: transport.Tag(),
}, message.Copy(), time.Second*time.Duration(timeToLive))
}
c.cache.AddWithLifetime(key, message.Copy(), time.Second*time.Duration(timeToLive))
}
}
@@ -407,19 +354,19 @@ func (c *Client) lookupToExchange(ctx context.Context, transport adapter.DNSTran
Qtype: qType,
Qclass: dns.ClassINET,
}
disableCache := c.disableCache || options.DisableCache
if !disableCache {
cachedAddresses, err := c.questionCache(question, transport)
if err != ErrNotCached {
return cachedAddresses, err
}
}
message := dns.Msg{
MsgHdr: dns.MsgHdr{
RecursionDesired: true,
},
Question: []dns.Question{question},
}
disableCache := c.disableCache || options.DisableCache
if !disableCache {
cachedAddresses, err := c.questionCache(ctx, transport, &message, options, responseChecker)
if err != ErrNotCached {
return cachedAddresses, err
}
}
response, err := c.Exchange(ctx, transport, &message, options, responseChecker)
if err != nil {
return nil, err
@@ -430,98 +377,177 @@ func (c *Client) lookupToExchange(ctx context.Context, transport adapter.DNSTran
return MessageToAddresses(response), nil
}
func (c *Client) questionCache(question dns.Question, transport adapter.DNSTransport) ([]netip.Addr, error) {
response, _ := c.loadResponse(question, transport)
func (c *Client) questionCache(ctx context.Context, transport adapter.DNSTransport, message *dns.Msg, options adapter.DNSQueryOptions, responseChecker func(response *dns.Msg) bool) ([]netip.Addr, error) {
question := message.Question[0]
response, _, isStale := c.loadResponse(question, transport)
if response == nil {
return nil, ErrNotCached
}
if isStale {
if options.DisableOptimisticCache {
return nil, ErrNotCached
}
c.backgroundRefreshDNS(transport, question, c.prepareExchangeMessage(message.Copy(), options), options, responseChecker)
logOptimisticResponse(c.logger, ctx, response)
}
if response.Rcode != dns.RcodeSuccess {
return nil, RcodeError(response.Rcode)
}
return MessageToAddresses(response), nil
}
func (c *Client) loadResponse(question dns.Question, transport adapter.DNSTransport) (*dns.Msg, int) {
var (
response *dns.Msg
loaded bool
)
if c.disableExpire {
if !c.independentCache {
response, loaded = c.cache.Get(question)
} else {
response, loaded = c.transportCache.Get(transportCacheKey{
Question: question,
transportTag: transport.Tag(),
})
}
if !loaded {
return nil, 0
}
return response.Copy(), 0
} else {
var expireAt time.Time
if !c.independentCache {
response, expireAt, loaded = c.cache.GetWithLifetime(question)
} else {
response, expireAt, loaded = c.transportCache.GetWithLifetime(transportCacheKey{
Question: question,
transportTag: transport.Tag(),
})
}
if !loaded {
return nil, 0
}
timeNow := time.Now()
if timeNow.After(expireAt) {
if !c.independentCache {
c.cache.Remove(question)
} else {
c.transportCache.Remove(transportCacheKey{
Question: question,
transportTag: transport.Tag(),
})
}
return nil, 0
}
var originTTL int
for _, recordList := range [][]dns.RR{response.Answer, response.Ns, response.Extra} {
for _, record := range recordList {
if record.Header().Rrtype == dns.TypeOPT {
continue
}
if originTTL == 0 || record.Header().Ttl > 0 && int(record.Header().Ttl) < originTTL {
originTTL = int(record.Header().Ttl)
}
}
}
nowTTL := int(expireAt.Sub(timeNow).Seconds())
if nowTTL < 0 {
nowTTL = 0
}
response = response.Copy()
if originTTL > 0 {
duration := uint32(originTTL - nowTTL)
for _, recordList := range [][]dns.RR{response.Answer, response.Ns, response.Extra} {
for _, record := range recordList {
if record.Header().Rrtype == dns.TypeOPT {
continue
}
record.Header().Ttl = record.Header().Ttl - duration
}
}
} else {
for _, recordList := range [][]dns.RR{response.Answer, response.Ns, response.Extra} {
for _, record := range recordList {
if record.Header().Rrtype == dns.TypeOPT {
continue
}
record.Header().Ttl = uint32(nowTTL)
}
}
}
return response, nowTTL
func (c *Client) loadResponse(question dns.Question, transport adapter.DNSTransport) (*dns.Msg, int, bool) {
if c.dnsCache != nil {
return c.loadPersistentResponse(question, transport)
}
if c.cache == nil {
return nil, 0, false
}
key := dnsCacheKey{Question: question, transportTag: transport.Tag()}
if c.disableExpire {
response, loaded := c.cache.Get(key)
if !loaded {
return nil, 0, false
}
return response.Copy(), 0, false
}
response, expireAt, loaded := c.cache.GetWithLifetimeNoExpire(key)
if !loaded {
return nil, 0, false
}
timeNow := time.Now()
if timeNow.After(expireAt) {
if c.optimisticTimeout > 0 && timeNow.Before(expireAt.Add(c.optimisticTimeout)) {
response = response.Copy()
normalizeTTL(response, 1)
return response, 0, true
}
c.cache.Remove(key)
return nil, 0, false
}
nowTTL := int(expireAt.Sub(timeNow).Seconds())
if nowTTL < 0 {
nowTTL = 0
}
response = response.Copy()
normalizeTTL(response, uint32(nowTTL))
return response, nowTTL, false
}
func (c *Client) loadPersistentResponse(question dns.Question, transport adapter.DNSTransport) (*dns.Msg, int, bool) {
rawMessage, expireAt, loaded := c.dnsCache.LoadDNSCache(transport.Tag(), question.Name, question.Qtype)
if !loaded {
return nil, 0, false
}
response := new(dns.Msg)
err := response.Unpack(rawMessage)
if err != nil {
return nil, 0, false
}
if c.disableExpire {
return response, 0, false
}
timeNow := time.Now()
if timeNow.After(expireAt) {
if c.optimisticTimeout > 0 && timeNow.Before(expireAt.Add(c.optimisticTimeout)) {
normalizeTTL(response, 1)
return response, 0, true
}
return nil, 0, false
}
nowTTL := int(expireAt.Sub(timeNow).Seconds())
if nowTTL < 0 {
nowTTL = 0
}
normalizeTTL(response, uint32(nowTTL))
return response, nowTTL, false
}
func applyResponseOptions(question dns.Question, response *dns.Msg, options adapter.DNSQueryOptions) uint32 {
if question.Qtype == dns.TypeHTTPS && (options.Strategy == C.DomainStrategyIPv4Only || options.Strategy == C.DomainStrategyIPv6Only) {
for _, rr := range response.Answer {
https, isHTTPS := rr.(*dns.HTTPS)
if !isHTTPS {
continue
}
content := https.SVCB
content.Value = common.Filter(content.Value, func(it dns.SVCBKeyValue) bool {
if options.Strategy == C.DomainStrategyIPv4Only {
return it.Key() != dns.SVCB_IPV6HINT
}
return it.Key() != dns.SVCB_IPV4HINT
})
https.SVCB = content
}
}
timeToLive := computeTimeToLive(response)
if options.RewriteTTL != nil {
timeToLive = *options.RewriteTTL
}
normalizeTTL(response, timeToLive)
return timeToLive
}
func (c *Client) backgroundRefreshDNS(transport adapter.DNSTransport, question dns.Question, message *dns.Msg, options adapter.DNSQueryOptions, responseChecker func(response *dns.Msg) bool) {
key := dnsCacheKey{Question: question, transportTag: transport.Tag()}
_, loaded := c.backgroundRefresh.LoadOrStore(key, struct{}{})
if loaded {
return
}
go func() {
defer c.backgroundRefresh.Delete(key)
ctx := contextWithTransportTag(c.ctx, transport.Tag())
response, err := c.exchangeToTransport(ctx, transport, message)
if err != nil {
if c.logger != nil {
c.logger.Debug("optimistic refresh failed for ", FqdnToDomain(question.Name), ": ", err)
}
return
}
if responseChecker != nil {
var rejected bool
if response.Rcode != dns.RcodeSuccess && response.Rcode != dns.RcodeNameError {
rejected = true
} else {
rejected = !responseChecker(response)
}
if rejected {
if c.rdrc != nil {
c.rdrc.SaveRDRCAsync(transport.Tag(), question.Name, question.Qtype, c.logger)
}
return
}
} else if response.Rcode != dns.RcodeSuccess && response.Rcode != dns.RcodeNameError {
return
}
timeToLive := applyResponseOptions(question, response, options)
c.storeCache(transport, question, response, timeToLive)
}()
}
func (c *Client) prepareExchangeMessage(message *dns.Msg, options adapter.DNSQueryOptions) *dns.Msg {
clientSubnet := options.ClientSubnet
if !clientSubnet.IsValid() {
clientSubnet = c.clientSubnet
}
if clientSubnet.IsValid() {
message = SetClientSubnet(message, clientSubnet)
}
return message
}
func (c *Client) exchangeToTransport(ctx context.Context, transport adapter.DNSTransport, message *dns.Msg) (*dns.Msg, error) {
ctx, cancel := context.WithTimeout(ctx, c.timeout)
defer cancel()
response, err := transport.Exchange(ctx, message)
if err == nil {
return response, nil
}
var rcodeError RcodeError
if errors.As(err, &rcodeError) {
return FixedResponseStatus(message, int(rcodeError)), nil
}
return nil, err
}
func MessageToAddresses(response *dns.Msg) []netip.Addr {

View File

@@ -22,6 +22,19 @@ func logCachedResponse(logger logger.ContextLogger, ctx context.Context, respons
}
}
func logOptimisticResponse(logger logger.ContextLogger, ctx context.Context, response *dns.Msg) {
if logger == nil || len(response.Question) == 0 {
return
}
domain := FqdnToDomain(response.Question[0].Name)
logger.DebugContext(ctx, "optimistic ", domain, " ", dns.RcodeToString[response.Rcode])
for _, recordList := range [][]dns.RR{response.Answer, response.Ns, response.Extra} {
for _, record := range recordList {
logger.InfoContext(ctx, "optimistic ", dns.Type(record.Header().Rrtype).String(), " ", FormatQuestion(record.String()))
}
}
}
func logExchangedResponse(logger logger.ContextLogger, ctx context.Context, response *dns.Msg, ttl uint32) {
if logger == nil || len(response.Question) == 0 {
return

View File

@@ -51,7 +51,7 @@ type Router struct {
closing bool
}
func NewRouter(ctx context.Context, logFactory log.Factory, options option.DNSOptions) *Router {
func NewRouter(ctx context.Context, logFactory log.Factory, options option.DNSOptions) (*Router, error) {
router := &Router{
ctx: ctx,
logger: logFactory.NewLogger("dns"),
@@ -61,12 +61,30 @@ func NewRouter(ctx context.Context, logFactory log.Factory, options option.DNSOp
rules: make([]adapter.DNSRule, 0, len(options.Rules)),
defaultDomainStrategy: C.DomainStrategy(options.Strategy),
}
if options.DNSClientOptions.IndependentCache {
deprecated.Report(ctx, deprecated.OptionIndependentDNSCache)
}
var optimisticTimeout time.Duration
optimisticOptions := common.PtrValueOrDefault(options.DNSClientOptions.Optimistic)
if optimisticOptions.Enabled {
if options.DNSClientOptions.DisableCache {
return nil, E.New("`optimistic` is conflict with `disable_cache`")
}
if options.DNSClientOptions.DisableExpire {
return nil, E.New("`optimistic` is conflict with `disable_expire`")
}
optimisticTimeout = time.Duration(optimisticOptions.Timeout)
if optimisticTimeout == 0 {
optimisticTimeout = 3 * 24 * time.Hour
}
}
router.client = NewClient(ClientOptions{
DisableCache: options.DNSClientOptions.DisableCache,
DisableExpire: options.DNSClientOptions.DisableExpire,
IndependentCache: options.DNSClientOptions.IndependentCache,
CacheCapacity: options.DNSClientOptions.CacheCapacity,
ClientSubnet: options.DNSClientOptions.ClientSubnet.Build(netip.Prefix{}),
Context: ctx,
DisableCache: options.DNSClientOptions.DisableCache,
DisableExpire: options.DNSClientOptions.DisableExpire,
OptimisticTimeout: optimisticTimeout,
CacheCapacity: options.DNSClientOptions.CacheCapacity,
ClientSubnet: options.DNSClientOptions.ClientSubnet.Build(netip.Prefix{}),
RDRC: func() adapter.RDRCStore {
cacheFile := service.FromContext[adapter.CacheFile](ctx)
if cacheFile == nil {
@@ -77,12 +95,24 @@ func NewRouter(ctx context.Context, logFactory log.Factory, options option.DNSOp
}
return cacheFile
},
DNSCache: func() adapter.DNSCacheStore {
cacheFile := service.FromContext[adapter.CacheFile](ctx)
if cacheFile == nil {
return nil
}
if !cacheFile.StoreDNS() {
return nil
}
cacheFile.SetDisableExpire(options.DNSClientOptions.DisableExpire)
cacheFile.SetOptimisticTimeout(optimisticTimeout)
return cacheFile
},
Logger: router.logger,
})
if options.ReverseMapping {
router.dnsReverseMapping = common.Must1(freelru.NewSharded[netip.Addr, string](1024, maphash.NewHasher[netip.Addr]().Hash32))
}
return router
return router, nil
}
func (r *Router) Initialize(rules []option.DNSRule) error {
@@ -319,6 +349,9 @@ func (r *Router) applyDNSRouteOptions(options *adapter.DNSQueryOptions, routeOpt
if routeOptions.DisableCache {
options.DisableCache = true
}
if routeOptions.DisableOptimisticCache {
options.DisableOptimisticCache = true
}
if routeOptions.RewriteTTL != nil {
options.RewriteTTL = routeOptions.RewriteTTL
}
@@ -907,7 +940,9 @@ func dnsRuleModeRequirementsInRule(router adapter.Router, rule option.DNSRule, m
return dnsRuleModeRequirementsInDefaultRule(router, rule.DefaultOptions, metadataOverrides)
case C.RuleTypeLogical:
flags := dnsRuleModeFlags{
disabled: dnsRuleActionType(rule) == C.RuleActionTypeEvaluate || dnsRuleActionType(rule) == C.RuleActionTypeRespond,
disabled: dnsRuleActionType(rule) == C.RuleActionTypeEvaluate ||
dnsRuleActionType(rule) == C.RuleActionTypeRespond ||
dnsRuleActionDisablesLegacyDNSMode(rule.LogicalOptions.DNSRuleAction),
neededFromStrategy: dnsRuleActionHasStrategy(rule.LogicalOptions.DNSRuleAction),
}
flags.needed = flags.neededFromStrategy
@@ -926,7 +961,7 @@ func dnsRuleModeRequirementsInRule(router adapter.Router, rule option.DNSRule, m
func dnsRuleModeRequirementsInDefaultRule(router adapter.Router, rule option.DefaultDNSRule, metadataOverrides map[string]adapter.RuleSetMetadata) (dnsRuleModeFlags, error) {
flags := dnsRuleModeFlags{
disabled: defaultRuleDisablesLegacyDNSMode(rule),
disabled: defaultRuleDisablesLegacyDNSMode(rule) || dnsRuleActionDisablesLegacyDNSMode(rule.DNSRuleAction),
neededFromStrategy: dnsRuleActionHasStrategy(rule.DNSRuleAction),
}
flags.needed = defaultRuleNeedsLegacyDNSModeFromAddressFilter(rule) || flags.neededFromStrategy
@@ -1063,6 +1098,17 @@ func validateLegacyDNSModeDisabledDefaultRule(rule option.DefaultDNSRule) (bool,
return rule.MatchResponse || rule.Action == C.RuleActionTypeRespond, nil
}
func dnsRuleActionDisablesLegacyDNSMode(action option.DNSRuleAction) bool {
switch action.Action {
case "", C.RuleActionTypeRoute, C.RuleActionTypeEvaluate:
return action.RouteOptions.DisableOptimisticCache
case C.RuleActionTypeRouteOptions:
return action.RouteOptionsOptions.DisableOptimisticCache
default:
return false
}
}
func dnsRuleActionHasStrategy(action option.DNSRuleAction) bool {
switch action.Action {
case "", C.RuleActionTypeRoute, C.RuleActionTypeEvaluate:

View File

@@ -4,8 +4,24 @@ package local
/*
#include <stdlib.h>
#include <dns.h>
#include <resolv.h>
#include <netdb.h>
static void *cgo_dns_open_super() {
return (void *)dns_open(NULL);
}
static void cgo_dns_close(void *opaque) {
if (opaque != NULL) dns_free((dns_handle_t)opaque);
}
static int cgo_dns_search(void *opaque, const char *name, int class, int type,
unsigned char *answer, int anslen) {
dns_handle_t handle = (dns_handle_t)opaque;
struct sockaddr_storage from;
uint32_t fromlen = sizeof(from);
return dns_search(handle, name, class, type, (char *)answer, anslen, (struct sockaddr *)&from, &fromlen);
}
static void *cgo_res_init() {
res_state state = calloc(1, sizeof(struct __res_state));
@@ -52,7 +68,59 @@ import (
mDNS "github.com/miekg/dns"
)
func resolvSearch(name string, class, qtype int, timeoutSeconds int) (*mDNS.Msg, error) {
const (
darwinResolverHostNotFound = 1
darwinResolverTryAgain = 2
darwinResolverNoRecovery = 3
darwinResolverNoData = 4
darwinResolverMaxPacketSize = 65535
)
var errDarwinNeedLargerBuffer = errors.New("darwin resolver response truncated")
func darwinLookupSystemDNS(name string, class, qtype, timeoutSeconds int) (*mDNS.Msg, error) {
response, err := darwinSearchWithSystemRouting(name, class, qtype)
if err == nil {
return response, nil
}
fallbackResponse, fallbackErr := darwinSearchWithResolv(name, class, qtype, timeoutSeconds)
if fallbackErr == nil || fallbackResponse != nil {
return fallbackResponse, fallbackErr
}
return nil, E.Errors(
E.Cause(err, "dns_search"),
E.Cause(fallbackErr, "res_nsearch"),
)
}
func darwinSearchWithSystemRouting(name string, class, qtype int) (*mDNS.Msg, error) {
handle := C.cgo_dns_open_super()
if handle == nil {
return nil, E.New("dns_open failed")
}
defer C.cgo_dns_close(handle)
cName := C.CString(name)
defer C.free(unsafe.Pointer(cName))
bufSize := 1232
for {
answer := make([]byte, bufSize)
n := C.cgo_dns_search(handle, cName, C.int(class), C.int(qtype),
(*C.uchar)(unsafe.Pointer(&answer[0])), C.int(len(answer)))
if n <= 0 {
return nil, E.New("dns_search failed for ", name)
}
if int(n) > bufSize {
bufSize = int(n)
continue
}
return unpackDarwinResolverMessage(answer[:int(n)], "dns_search")
}
}
func darwinSearchWithResolv(name string, class, qtype int, timeoutSeconds int) (*mDNS.Msg, error) {
state := C.cgo_res_init()
if state == nil {
return nil, E.New("res_ninit failed")
@@ -61,6 +129,7 @@ func resolvSearch(name string, class, qtype int, timeoutSeconds int) (*mDNS.Msg,
cName := C.CString(name)
defer C.free(unsafe.Pointer(cName))
bufSize := 1232
for {
answer := make([]byte, bufSize)
@@ -74,37 +143,55 @@ func resolvSearch(name string, class, qtype int, timeoutSeconds int) (*mDNS.Msg,
bufSize = int(n)
continue
}
var response mDNS.Msg
err := response.Unpack(answer[:int(n)])
if err != nil {
return nil, E.Cause(err, "unpack res_nsearch response")
return unpackDarwinResolverMessage(answer[:int(n)], "res_nsearch")
}
response, err := handleDarwinResolvFailure(name, answer, int(hErrno))
if err == nil {
return response, nil
}
if errors.Is(err, errDarwinNeedLargerBuffer) && bufSize < darwinResolverMaxPacketSize {
bufSize *= 2
if bufSize > darwinResolverMaxPacketSize {
bufSize = darwinResolverMaxPacketSize
}
return &response, nil
continue
}
var response mDNS.Msg
_ = response.Unpack(answer[:bufSize])
if response.Response {
if response.Truncated && bufSize < 65535 {
bufSize *= 2
if bufSize > 65535 {
bufSize = 65535
}
continue
}
return &response, nil
}
switch hErrno {
case C.HOST_NOT_FOUND:
return nil, dns.RcodeNameError
case C.TRY_AGAIN:
return nil, dns.RcodeNameError
case C.NO_RECOVERY:
return nil, dns.RcodeServerFailure
case C.NO_DATA:
return nil, dns.RcodeSuccess
default:
return nil, E.New("res_nsearch: unknown error ", int(hErrno), " for ", name)
return nil, err
}
}
func unpackDarwinResolverMessage(packet []byte, source string) (*mDNS.Msg, error) {
var response mDNS.Msg
err := response.Unpack(packet)
if err != nil {
return nil, E.Cause(err, "unpack ", source, " response")
}
return &response, nil
}
func handleDarwinResolvFailure(name string, answer []byte, hErrno int) (*mDNS.Msg, error) {
response, err := unpackDarwinResolverMessage(answer, "res_nsearch failure")
if err == nil && response.Response {
if response.Truncated && len(answer) < darwinResolverMaxPacketSize {
return nil, errDarwinNeedLargerBuffer
}
return response, nil
}
return nil, darwinResolverHErrno(name, hErrno)
}
func darwinResolverHErrno(name string, hErrno int) error {
switch hErrno {
case darwinResolverHostNotFound:
return dns.RcodeNameError
case darwinResolverTryAgain:
return dns.RcodeServerFailure
case darwinResolverNoRecovery:
return dns.RcodeServerFailure
case darwinResolverNoData:
return dns.RcodeSuccess
default:
return E.New("res_nsearch: unknown error ", hErrno, " for ", name)
}
}
@@ -141,7 +228,7 @@ func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg,
}
resultCh := make(chan resolvResult, 1)
go func() {
response, err := resolvSearch(name, int(question.Qclass), int(question.Qtype), timeoutSeconds)
response, err := darwinLookupSystemDNS(name, int(question.Qclass), int(question.Qtype), timeoutSeconds)
resultCh <- resolvResult{response, err}
}()
var result resolvResult

View File

@@ -2,6 +2,11 @@
icon: material/alert-decagram
---
!!! quote "Changes in sing-box 1.14.0"
:material-delete-clock: [independent_cache](#independent_cache)
:material-plus: [optimistic](#optimistic)
!!! quote "Changes in sing-box 1.12.0"
:material-decagram: [servers](#servers)
@@ -25,6 +30,7 @@ icon: material/alert-decagram
"disable_expire": false,
"independent_cache": false,
"cache_capacity": 0,
"optimistic": false, // or {}
"reverse_mapping": false,
"client_subnet": "",
"fakeip": {}
@@ -57,12 +63,20 @@ One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.
Disable dns cache.
Conflict with `optimistic`.
#### disable_expire
Disable dns cache expire.
Conflict with `optimistic`.
#### independent_cache
!!! failure "Deprecated in sing-box 1.14.0"
`independent_cache` is deprecated and will be removed in sing-box 1.14.0, check [Migration](/migration/#migrate-independent-dns-cache).
Make each DNS server's cache independent for special purposes. If enabled, will slightly degrade performance.
#### cache_capacity
@@ -73,6 +87,34 @@ LRU cache capacity.
Value less than 1024 will be ignored.
#### optimistic
!!! question "Since sing-box 1.14.0"
Enable optimistic DNS caching. When a cached DNS entry has expired but is still within the timeout window,
the stale response is returned immediately while a background refresh is triggered.
Conflict with `disable_cache` and `disable_expire`.
Accepts a boolean or an object. When set to `true`, the default timeout of `3d` is used.
```json
{
"enabled": true,
"timeout": "3d"
}
```
##### enabled
Enable optimistic DNS caching.
##### timeout
The maximum time an expired cache entry can be served optimistically.
`3d` is used by default.
#### reverse_mapping
Stores a reverse mapping of IP addresses after responding to a DNS query in order to provide domain names when routing.

View File

@@ -2,6 +2,11 @@
icon: material/alert-decagram
---
!!! quote "sing-box 1.14.0 中的更改"
:material-delete-clock: [independent_cache](#independent_cache)
:material-plus: [optimistic](#optimistic)
!!! quote "sing-box 1.12.0 中的更改"
:material-decagram: [servers](#servers)
@@ -25,6 +30,7 @@ icon: material/alert-decagram
"disable_expire": false,
"independent_cache": false,
"cache_capacity": 0,
"optimistic": false, // or {}
"reverse_mapping": false,
"client_subnet": "",
"fakeip": {}
@@ -56,12 +62,20 @@ icon: material/alert-decagram
禁用 DNS 缓存。
`optimistic` 冲突。
#### disable_expire
禁用 DNS 缓存过期。
`optimistic` 冲突。
#### independent_cache
!!! failure "已在 sing-box 1.14.0 废弃"
`independent_cache` 已在 sing-box 1.14.0 废弃,且将在 sing-box 1.16.0 中被移除,参阅[迁移指南](/zh/migration/#迁移-independent-dns-cache)。
使每个 DNS 服务器的缓存独立,以满足特殊目的。如果启用,将轻微降低性能。
#### cache_capacity
@@ -72,6 +86,34 @@ LRU 缓存容量。
小于 1024 的值将被忽略。
#### optimistic
!!! question "自 sing-box 1.14.0 起"
启用乐观 DNS 缓存。当缓存的 DNS 条目已过期但仍在超时窗口内时,
立即返回过期的响应,同时在后台触发刷新。
`disable_cache``disable_expire` 冲突。
接受布尔值或对象。当设置为 `true` 时,使用默认超时 `3d`
```json
{
"enabled": true,
"timeout": "3d"
}
```
##### enabled
启用乐观 DNS 缓存。
##### timeout
过期缓存条目可被乐观提供的最长时间。
默认使用 `3d`
#### reverse_mapping
在响应 DNS 查询后存储 IP 地址的反向映射以为路由目的提供域名。

View File

@@ -6,7 +6,8 @@ icon: material/new-box
:material-delete-clock: [strategy](#strategy)
:material-plus: [evaluate](#evaluate)
:material-plus: [respond](#respond)
:material-plus: [respond](#respond)
:material-plus: [disable_optimistic_cache](#disable_optimistic_cache)
!!! quote "Changes in sing-box 1.12.0"
@@ -23,6 +24,7 @@ icon: material/new-box
"server": "",
"strategy": "",
"disable_cache": false,
"disable_optimistic_cache": false,
"rewrite_ttl": null,
"client_subnet": null
}
@@ -52,6 +54,12 @@ One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.
Disable cache and save cache in this query.
#### disable_optimistic_cache
!!! question "Since sing-box 1.14.0"
Disable optimistic DNS caching in this query.
#### rewrite_ttl
Rewrite TTL in DNS responses.
@@ -73,6 +81,7 @@ Will override `dns.client_subnet`.
"action": "evaluate",
"server": "",
"disable_cache": false,
"disable_optimistic_cache": false,
"rewrite_ttl": null,
"client_subnet": null
}
@@ -97,6 +106,12 @@ Tag of target server.
Disable cache and save cache in this query.
#### disable_optimistic_cache
!!! question "Since sing-box 1.14.0"
Disable optimistic DNS caching in this query.
#### rewrite_ttl
Rewrite TTL in DNS responses.
@@ -131,6 +146,7 @@ Only allowed after a preceding top-level `evaluate` rule. If the action is reach
{
"action": "route-options",
"disable_cache": false,
"disable_optimistic_cache": false,
"rewrite_ttl": null,
"client_subnet": null
}

View File

@@ -6,7 +6,8 @@ icon: material/new-box
:material-delete-clock: [strategy](#strategy)
:material-plus: [evaluate](#evaluate)
:material-plus: [respond](#respond)
:material-plus: [respond](#respond)
:material-plus: [disable_optimistic_cache](#disable_optimistic_cache)
!!! quote "sing-box 1.12.0 中的更改"
@@ -23,6 +24,7 @@ icon: material/new-box
"server": "",
"strategy": "",
"disable_cache": false,
"disable_optimistic_cache": false,
"rewrite_ttl": null,
"client_subnet": null
}
@@ -52,6 +54,12 @@ icon: material/new-box
在此查询中禁用缓存。
#### disable_optimistic_cache
!!! question "自 sing-box 1.14.0 起"
在此查询中禁用乐观 DNS 缓存。
#### rewrite_ttl
重写 DNS 回应中的 TTL。
@@ -73,6 +81,7 @@ icon: material/new-box
"action": "evaluate",
"server": "",
"disable_cache": false,
"disable_optimistic_cache": false,
"rewrite_ttl": null,
"client_subnet": null
}
@@ -95,6 +104,12 @@ icon: material/new-box
在此查询中禁用缓存。
#### disable_optimistic_cache
!!! question "自 sing-box 1.14.0 起"
在此查询中禁用乐观 DNS 缓存。
#### rewrite_ttl
重写 DNS 回应中的 TTL。
@@ -129,6 +144,7 @@ icon: material/new-box
{
"action": "route-options",
"disable_cache": false,
"disable_optimistic_cache": false,
"rewrite_ttl": null,
"client_subnet": null
}

View File

@@ -1,5 +1,10 @@
!!! question "Since sing-box 1.8.0"
!!! quote "Changes in sing-box 1.14.0"
:material-delete-clock: [store_rdrc](#store_rdrc)
:material-plus: [store_dns](#store_dns)
!!! quote "Changes in sing-box 1.9.0"
:material-plus: [store_rdrc](#store_rdrc)
@@ -14,7 +19,8 @@
"cache_id": "",
"store_fakeip": false,
"store_rdrc": false,
"rdrc_timeout": ""
"rdrc_timeout": "",
"store_dns": false
}
```
@@ -42,6 +48,10 @@ Store fakeip in the cache file
#### store_rdrc
!!! failure "Deprecated in sing-box 1.14.0"
`store_rdrc` is deprecated and will be removed in sing-box 1.16.0, check [Migration](/migration/#migrate-store-rdrc).
Store rejected DNS response cache in the cache file
The check results of [Legacy Address Filter Fields](/configuration/dns/rule/#legacy-address-filter-fields)
@@ -52,3 +62,9 @@ will be cached until expiration.
Timeout of rejected DNS response cache.
`7d` is used by default.
#### store_dns
!!! question "Since sing-box 1.14.0"
Store DNS cache in the cache file.

View File

@@ -1,5 +1,10 @@
!!! question "自 sing-box 1.8.0 起"
!!! quote "sing-box 1.14.0 中的更改"
:material-delete-clock: [store_rdrc](#store_rdrc)
:material-plus: [store_dns](#store_dns)
!!! quote "sing-box 1.9.0 中的更改"
:material-plus: [store_rdrc](#store_rdrc)
@@ -14,7 +19,8 @@
"cache_id": "",
"store_fakeip": false,
"store_rdrc": false,
"rdrc_timeout": ""
"rdrc_timeout": "",
"store_dns": false
}
```
@@ -40,6 +46,10 @@
#### store_rdrc
!!! failure "已在 sing-box 1.14.0 废弃"
`store_rdrc` 已在 sing-box 1.14.0 废弃,且将在 sing-box 1.16.0 中被移除,参阅[迁移指南](/zh/migration/#迁移-store_rdrc)。
将拒绝的 DNS 响应缓存存储在缓存文件中。
[旧版地址筛选字段](/zh/configuration/dns/rule/#旧版地址筛选字段) 的检查结果将被缓存至过期。
@@ -49,3 +59,9 @@
拒绝的 DNS 响应缓存超时。
默认使用 `7d`
#### store_dns
!!! question "自 sing-box 1.14.0 起"
将 DNS 缓存存储在缓存文件中。

View File

@@ -7,6 +7,10 @@ icon: material/new-box
:material-plus: [bypass](#bypass)
:material-alert: [reject](#reject)
!!! quote "Changes in sing-box 1.14.0"
:material-plus: [resolve.disable_optimistic_cache](#disable_optimistic_cache)
!!! quote "Changes in sing-box 1.12.0"
:material-plus: [tls_fragment](#tls_fragment)
@@ -279,6 +283,7 @@ Timeout for sniffing.
"server": "",
"strategy": "",
"disable_cache": false,
"disable_optimistic_cache": false,
"rewrite_ttl": null,
"client_subnet": null
}
@@ -302,6 +307,12 @@ DNS resolution strategy, available values are: `prefer_ipv4`, `prefer_ipv6`, `ip
Disable cache and save cache in this query.
#### disable_optimistic_cache
!!! question "Since sing-box 1.14.0"
Disable optimistic DNS caching in this query.
#### rewrite_ttl
!!! question "Since sing-box 1.12.0"

View File

@@ -7,6 +7,10 @@ icon: material/new-box
:material-plus: [bypass](#bypass)
:material-alert: [reject](#reject)
!!! quote "sing-box 1.14.0 中的更改"
:material-plus: [resolve.disable_optimistic_cache](#disable_optimistic_cache)
!!! quote "sing-box 1.12.0 中的更改"
:material-plus: [tls_fragment](#tls_fragment)
@@ -268,6 +272,7 @@ UDP 连接超时时间。
"server": "",
"strategy": "",
"disable_cache": false,
"disable_optimistic_cache": false,
"rewrite_ttl": null,
"client_subnet": null
}
@@ -291,6 +296,12 @@ DNS 解析策略,可用值有:`prefer_ipv4`、`prefer_ipv6`、`ipv4_only`、
在此查询中禁用缓存。
#### disable_optimistic_cache
!!! question "自 sing-box 1.14.0 起"
在此查询中禁用乐观 DNS 缓存。
#### rewrite_ttl
!!! question "自 sing-box 1.12.0 起"

View File

@@ -27,6 +27,21 @@ check [Migration](../migration/#migrate-address-filter-fields-to-response-matchi
Old fields will be removed in sing-box 1.16.0.
#### `independent_cache` DNS option
`independent_cache` DNS option is deprecated.
The DNS cache now always keys by transport, making this option unnecessary,
check [Migration](../migration/#migrate-independent-dns-cache).
Old fields will be removed in sing-box 1.16.0.
#### `store_rdrc` cache file option
`store_rdrc` cache file option is deprecated,
check [Migration](../migration/#migrate-store-rdrc).
Old fields will be removed in sing-box 1.16.0.
#### Legacy Address Filter Fields in DNS rules
Legacy Address Filter Fields (`ip_cidr`, `ip_is_private` without `match_response`)

View File

@@ -27,6 +27,21 @@ TLS 中的内联 ACME 选项(`tls.acme`)已废弃,
旧字段将在 sing-box 1.16.0 中被移除。
#### `independent_cache` DNS 选项
`independent_cache` DNS 选项已废弃。
DNS 缓存现在始终按传输分离,使此选项不再需要,
参阅[迁移指南](/zh/migration/#迁移-independent-dns-cache)。
旧字段将在 sing-box 1.16.0 中被移除。
#### `store_rdrc` 缓存文件选项
`store_rdrc` 缓存文件选项已废弃,
参阅[迁移指南](/zh/migration/#迁移-store_rdrc)。
旧字段将在 sing-box 1.16.0 中被移除。
#### 旧版地址筛选字段 (DNS 规则)
旧版地址筛选字段(不使用 `match_response``ip_cidr``ip_is_private`)已废弃,

View File

@@ -137,6 +137,68 @@ to fetch a DNS response, then match against it explicitly with `match_response`.
}
```
### Migrate independent DNS cache
The DNS cache now always keys by transport name, making `independent_cache` unnecessary.
Simply remove the field.
!!! info "References"
[DNS](/configuration/dns/)
=== ":material-card-remove: Deprecated"
```json
{
"dns": {
"independent_cache": true
}
}
```
=== ":material-card-multiple: New"
```json
{
"dns": {}
}
```
### Migrate store_rdrc
`store_rdrc` is deprecated and can be replaced by `store_dns`,
which persists the full DNS cache to the cache file.
!!! info "References"
[Cache File](/configuration/experimental/cache-file/)
=== ":material-card-remove: Deprecated"
```json
{
"experimental": {
"cache_file": {
"enabled": true,
"store_rdrc": true
}
}
}
```
=== ":material-card-multiple: New"
```json
{
"experimental": {
"cache_file": {
"enabled": true,
"store_dns": true
}
}
}
```
### ip_version and query_type behavior changes in DNS rules
In sing-box 1.14.0, the behavior of

View File

@@ -137,6 +137,68 @@ sing-box 1.14.0 新增字段参阅 [ACME](/zh/configuration/shared/certificate-p
}
```
### 迁移 independent DNS cache
DNS 缓存现在始终按传输名称分离,使 `independent_cache` 不再需要。
直接移除该字段即可。
!!! info "参考"
[DNS](/zh/configuration/dns/)
=== ":material-card-remove: 弃用的"
```json
{
"dns": {
"independent_cache": true
}
}
```
=== ":material-card-multiple: 新的"
```json
{
"dns": {}
}
```
### 迁移 store_rdrc
`store_rdrc` 已废弃,且可以被 `store_dns` 替代,
后者将完整的 DNS 缓存持久化到缓存文件中。
!!! info "参考"
[缓存文件](/zh/configuration/experimental/cache-file/)
=== ":material-card-remove: 弃用的"
```json
{
"experimental": {
"cache_file": {
"enabled": true,
"store_rdrc": true
}
}
}
```
=== ":material-card-multiple: 新的"
```json
{
"experimental": {
"cache_file": {
"enabled": true,
"store_dns": true
}
}
}
```
### DNS 规则中的 ip_version 和 query_type 行为更改
在 sing-box 1.14.0 中DNS 规则中的

View File

@@ -12,9 +12,11 @@ import (
"github.com/sagernet/bbolt"
bboltErrors "github.com/sagernet/bbolt/errors"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/experimental/deprecated"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
"github.com/sagernet/sing/service/filemanager"
)
@@ -30,6 +32,7 @@ var (
string(bucketMode),
string(bucketRuleSet),
string(bucketRDRC),
string(bucketDNSCache),
}
cacheIDDefault = []byte("default")
@@ -38,30 +41,43 @@ var (
var _ adapter.CacheFile = (*CacheFile)(nil)
type CacheFile struct {
ctx context.Context
path string
cacheID []byte
storeFakeIP bool
storeRDRC bool
rdrcTimeout time.Duration
DB *bbolt.DB
resetAccess sync.Mutex
saveMetadataTimer *time.Timer
saveFakeIPAccess sync.RWMutex
saveDomain map[netip.Addr]string
saveAddress4 map[string]netip.Addr
saveAddress6 map[string]netip.Addr
saveRDRCAccess sync.RWMutex
saveRDRC map[saveRDRCCacheKey]bool
ctx context.Context
logger logger.Logger
path string
cacheID []byte
storeFakeIP bool
storeRDRC bool
storeDNS bool
disableExpire bool
rdrcTimeout time.Duration
optimisticTimeout time.Duration
DB *bbolt.DB
resetAccess sync.Mutex
saveMetadataTimer *time.Timer
saveFakeIPAccess sync.RWMutex
saveDomain map[netip.Addr]string
saveAddress4 map[string]netip.Addr
saveAddress6 map[string]netip.Addr
saveRDRCAccess sync.RWMutex
saveRDRC map[saveCacheKey]bool
saveDNSCacheAccess sync.RWMutex
saveDNSCache map[saveCacheKey]saveDNSCacheEntry
}
type saveRDRCCacheKey struct {
type saveCacheKey struct {
TransportName string
QuestionName string
QType uint16
}
func New(ctx context.Context, options option.CacheFileOptions) *CacheFile {
type saveDNSCacheEntry struct {
rawMessage []byte
expireAt time.Time
sequence uint64
saving bool
}
func New(ctx context.Context, logger logger.Logger, options option.CacheFileOptions) *CacheFile {
var path string
if options.Path != "" {
path = options.Path
@@ -72,6 +88,9 @@ func New(ctx context.Context, options option.CacheFileOptions) *CacheFile {
if options.CacheID != "" {
cacheIDBytes = append([]byte{0}, []byte(options.CacheID)...)
}
if options.StoreRDRC {
deprecated.Report(ctx, deprecated.OptionStoreRDRC)
}
var rdrcTimeout time.Duration
if options.StoreRDRC {
if options.RDRCTimeout > 0 {
@@ -82,15 +101,18 @@ func New(ctx context.Context, options option.CacheFileOptions) *CacheFile {
}
return &CacheFile{
ctx: ctx,
logger: logger,
path: filemanager.BasePath(ctx, path),
cacheID: cacheIDBytes,
storeFakeIP: options.StoreFakeIP,
storeRDRC: options.StoreRDRC,
storeDNS: options.StoreDNS,
rdrcTimeout: rdrcTimeout,
saveDomain: make(map[netip.Addr]string),
saveAddress4: make(map[string]netip.Addr),
saveAddress6: make(map[string]netip.Addr),
saveRDRC: make(map[saveRDRCCacheKey]bool),
saveRDRC: make(map[saveCacheKey]bool),
saveDNSCache: make(map[saveCacheKey]saveDNSCacheEntry),
}
}
@@ -102,10 +124,44 @@ func (c *CacheFile) Dependencies() []string {
return nil
}
func (c *CacheFile) SetOptimisticTimeout(timeout time.Duration) {
c.optimisticTimeout = timeout
}
func (c *CacheFile) SetDisableExpire(disableExpire bool) {
c.disableExpire = disableExpire
}
func (c *CacheFile) Start(stage adapter.StartStage) error {
if stage != adapter.StartStateInitialize {
return nil
switch stage {
case adapter.StartStateInitialize:
return c.start()
case adapter.StartStateStart:
c.startCacheCleanup()
}
return nil
}
func (c *CacheFile) startCacheCleanup() {
if c.storeDNS {
c.clearRDRC()
c.cleanupDNSCache()
interval := c.optimisticTimeout / 2
if interval <= 0 {
interval = time.Hour
}
go c.loopCacheCleanup(interval, c.cleanupDNSCache)
} else if c.storeRDRC {
c.cleanupRDRC()
interval := c.rdrcTimeout / 2
if interval <= 0 {
interval = time.Hour
}
go c.loopCacheCleanup(interval, c.cleanupRDRC)
}
}
func (c *CacheFile) start() error {
const fileMode = 0o666
options := bbolt.Options{Timeout: time.Second}
var (

View File

@@ -0,0 +1,299 @@
package cachefile
import (
"encoding/binary"
"time"
"github.com/sagernet/bbolt"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/logger"
)
var bucketDNSCache = []byte("dns_cache")
func (c *CacheFile) StoreDNS() bool {
return c.storeDNS
}
func (c *CacheFile) LoadDNSCache(transportName string, qName string, qType uint16) (rawMessage []byte, expireAt time.Time, loaded bool) {
c.saveDNSCacheAccess.RLock()
entry, cached := c.saveDNSCache[saveCacheKey{transportName, qName, qType}]
c.saveDNSCacheAccess.RUnlock()
if cached {
return entry.rawMessage, entry.expireAt, true
}
key := buf.Get(2 + len(qName))
binary.BigEndian.PutUint16(key, qType)
copy(key[2:], qName)
defer buf.Put(key)
err := c.view(func(tx *bbolt.Tx) error {
bucket := c.bucket(tx, bucketDNSCache)
if bucket == nil {
return nil
}
bucket = bucket.Bucket([]byte(transportName))
if bucket == nil {
return nil
}
content := bucket.Get(key)
if len(content) < 8 {
return nil
}
expireAt = time.Unix(int64(binary.BigEndian.Uint64(content[:8])), 0)
rawMessage = make([]byte, len(content)-8)
copy(rawMessage, content[8:])
loaded = true
return nil
})
if err != nil {
return nil, time.Time{}, false
}
return
}
func (c *CacheFile) SaveDNSCache(transportName string, qName string, qType uint16, rawMessage []byte, expireAt time.Time) error {
return c.batch(func(tx *bbolt.Tx) error {
bucket, err := c.createBucket(tx, bucketDNSCache)
if err != nil {
return err
}
bucket, err = bucket.CreateBucketIfNotExists([]byte(transportName))
if err != nil {
return err
}
key := buf.Get(2 + len(qName))
binary.BigEndian.PutUint16(key, qType)
copy(key[2:], qName)
defer buf.Put(key)
value := buf.Get(8 + len(rawMessage))
defer buf.Put(value)
binary.BigEndian.PutUint64(value[:8], uint64(expireAt.Unix()))
copy(value[8:], rawMessage)
return bucket.Put(key, value)
})
}
func (c *CacheFile) SaveDNSCacheAsync(transportName string, qName string, qType uint16, rawMessage []byte, expireAt time.Time, logger logger.Logger) {
saveKey := saveCacheKey{transportName, qName, qType}
if !c.queueDNSCacheSave(saveKey, rawMessage, expireAt) {
return
}
go c.flushPendingDNSCache(saveKey, logger)
}
func (c *CacheFile) queueDNSCacheSave(saveKey saveCacheKey, rawMessage []byte, expireAt time.Time) bool {
c.saveDNSCacheAccess.Lock()
defer c.saveDNSCacheAccess.Unlock()
entry := c.saveDNSCache[saveKey]
entry.rawMessage = append([]byte(nil), rawMessage...)
entry.expireAt = expireAt
entry.sequence++
startFlush := !entry.saving
entry.saving = true
c.saveDNSCache[saveKey] = entry
return startFlush
}
func (c *CacheFile) flushPendingDNSCache(saveKey saveCacheKey, logger logger.Logger) {
c.flushPendingDNSCacheWith(saveKey, logger, func(entry saveDNSCacheEntry) error {
return c.SaveDNSCache(saveKey.TransportName, saveKey.QuestionName, saveKey.QType, entry.rawMessage, entry.expireAt)
})
}
func (c *CacheFile) flushPendingDNSCacheWith(saveKey saveCacheKey, logger logger.Logger, save func(saveDNSCacheEntry) error) {
for {
c.saveDNSCacheAccess.RLock()
entry, loaded := c.saveDNSCache[saveKey]
c.saveDNSCacheAccess.RUnlock()
if !loaded {
return
}
err := save(entry)
if err != nil {
logger.Warn("save DNS cache: ", err)
}
c.saveDNSCacheAccess.Lock()
currentEntry, loaded := c.saveDNSCache[saveKey]
if !loaded {
c.saveDNSCacheAccess.Unlock()
return
}
if currentEntry.sequence != entry.sequence {
c.saveDNSCacheAccess.Unlock()
continue
}
delete(c.saveDNSCache, saveKey)
c.saveDNSCacheAccess.Unlock()
return
}
}
func (c *CacheFile) ClearDNSCache() error {
c.saveDNSCacheAccess.Lock()
clear(c.saveDNSCache)
c.saveDNSCacheAccess.Unlock()
return c.batch(func(tx *bbolt.Tx) error {
if c.cacheID == nil {
bucket := tx.Bucket(bucketDNSCache)
if bucket == nil {
return nil
}
return tx.DeleteBucket(bucketDNSCache)
}
bucket := tx.Bucket(c.cacheID)
if bucket == nil || bucket.Bucket(bucketDNSCache) == nil {
return nil
}
return bucket.DeleteBucket(bucketDNSCache)
})
}
func (c *CacheFile) loopCacheCleanup(interval time.Duration, cleanupFunc func()) {
ticker := time.NewTicker(interval)
defer ticker.Stop()
for {
select {
case <-c.ctx.Done():
return
case <-ticker.C:
cleanupFunc()
}
}
}
func (c *CacheFile) cleanupDNSCache() {
now := time.Now()
err := c.batch(func(tx *bbolt.Tx) error {
bucket := c.bucket(tx, bucketDNSCache)
if bucket == nil {
return nil
}
var emptyTransports [][]byte
err := bucket.ForEachBucket(func(transportName []byte) error {
transportBucket := bucket.Bucket(transportName)
if transportBucket == nil {
return nil
}
var expiredKeys [][]byte
err := transportBucket.ForEach(func(key, value []byte) error {
if len(value) < 8 {
expiredKeys = append(expiredKeys, append([]byte(nil), key...))
return nil
}
if c.disableExpire {
return nil
}
expireAt := time.Unix(int64(binary.BigEndian.Uint64(value[:8])), 0)
if now.After(expireAt.Add(c.optimisticTimeout)) {
expiredKeys = append(expiredKeys, append([]byte(nil), key...))
}
return nil
})
if err != nil {
return err
}
for _, key := range expiredKeys {
err = transportBucket.Delete(key)
if err != nil {
return err
}
}
first, _ := transportBucket.Cursor().First()
if first == nil {
emptyTransports = append(emptyTransports, append([]byte(nil), transportName...))
}
return nil
})
if err != nil {
return err
}
for _, name := range emptyTransports {
err = bucket.DeleteBucket(name)
if err != nil {
return err
}
}
return nil
})
if err != nil {
c.logger.Warn("cleanup DNS cache: ", err)
}
}
func (c *CacheFile) clearRDRC() {
c.saveRDRCAccess.Lock()
clear(c.saveRDRC)
c.saveRDRCAccess.Unlock()
err := c.batch(func(tx *bbolt.Tx) error {
if c.cacheID == nil {
if tx.Bucket(bucketRDRC) == nil {
return nil
}
return tx.DeleteBucket(bucketRDRC)
}
bucket := tx.Bucket(c.cacheID)
if bucket == nil || bucket.Bucket(bucketRDRC) == nil {
return nil
}
return bucket.DeleteBucket(bucketRDRC)
})
if err != nil {
c.logger.Warn("clear RDRC: ", err)
}
}
func (c *CacheFile) cleanupRDRC() {
now := time.Now()
err := c.batch(func(tx *bbolt.Tx) error {
bucket := c.bucket(tx, bucketRDRC)
if bucket == nil {
return nil
}
var emptyTransports [][]byte
err := bucket.ForEachBucket(func(transportName []byte) error {
transportBucket := bucket.Bucket(transportName)
if transportBucket == nil {
return nil
}
var expiredKeys [][]byte
err := transportBucket.ForEach(func(key, value []byte) error {
if len(value) < 8 {
expiredKeys = append(expiredKeys, append([]byte(nil), key...))
return nil
}
expiresAt := time.Unix(int64(binary.BigEndian.Uint64(value)), 0)
if now.After(expiresAt) {
expiredKeys = append(expiredKeys, append([]byte(nil), key...))
}
return nil
})
if err != nil {
return err
}
for _, key := range expiredKeys {
err = transportBucket.Delete(key)
if err != nil {
return err
}
}
first, _ := transportBucket.Cursor().First()
if first == nil {
emptyTransports = append(emptyTransports, append([]byte(nil), transportName...))
}
return nil
})
if err != nil {
return err
}
for _, name := range emptyTransports {
err = bucket.DeleteBucket(name)
if err != nil {
return err
}
}
return nil
})
if err != nil {
c.logger.Warn("cleanup RDRC: ", err)
}
}

View File

@@ -21,7 +21,7 @@ func (c *CacheFile) RDRCTimeout() time.Duration {
func (c *CacheFile) LoadRDRC(transportName string, qName string, qType uint16) (rejected bool) {
c.saveRDRCAccess.RLock()
rejected, cached := c.saveRDRC[saveRDRCCacheKey{transportName, qName, qType}]
rejected, cached := c.saveRDRC[saveCacheKey{transportName, qName, qType}]
c.saveRDRCAccess.RUnlock()
if cached {
return
@@ -93,7 +93,7 @@ func (c *CacheFile) SaveRDRC(transportName string, qName string, qType uint16) e
}
func (c *CacheFile) SaveRDRCAsync(transportName string, qName string, qType uint16, logger logger.Logger) {
saveKey := saveRDRCCacheKey{transportName, qName, qType}
saveKey := saveCacheKey{transportName, qName, qType}
c.saveRDRCAccess.Lock()
c.saveRDRC[saveKey] = true
c.saveRDRCAccess.Unlock()

View File

@@ -120,6 +120,24 @@ var OptionLegacyDNSRuleStrategy = Note{
MigrationLink: "https://sing-box.sagernet.org/migration/#migrate-dns-rule-action-strategy-to-rule-items",
}
var OptionIndependentDNSCache = Note{
Name: "independent-dns-cache",
Description: "`independent_cache` DNS option",
DeprecatedVersion: "1.14.0",
ScheduledVersion: "1.16.0",
EnvName: "INDEPENDENT_DNS_CACHE",
MigrationLink: "https://sing-box.sagernet.org/migration/#migrate-independent-dns-cache",
}
var OptionStoreRDRC = Note{
Name: "store-rdrc",
Description: "`store_rdrc` cache file option",
DeprecatedVersion: "1.14.0",
ScheduledVersion: "1.16.0",
EnvName: "STORE_RDRC",
MigrationLink: "https://sing-box.sagernet.org/migration/#migrate-store-rdrc",
}
var Options = []Note{
OptionOutboundDNSRuleItem,
OptionMissingDomainResolver,
@@ -128,4 +146,6 @@ var Options = []Note{
OptionRuleSetIPCIDRAcceptEmpty,
OptionLegacyDNSAddressFilter,
OptionLegacyDNSRuleStrategy,
OptionIndependentDNSCache,
OptionStoreRDRC,
}

View File

@@ -769,7 +769,7 @@ func (c *CommandClient) SubscribeTailscaleStatus(handler TailscaleStatusHandler)
for {
event, recvErr := stream.Recv()
if recvErr != nil {
if status.Code(recvErr) == codes.NotFound {
if status.Code(recvErr) == codes.NotFound || status.Code(recvErr) == codes.Unavailable {
return nil
}
recvErr = E.Cause(recvErr, "tailscale status recv")

62
go.mod
View File

@@ -31,8 +31,8 @@ require (
github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a
github.com/sagernet/cors v1.2.1
github.com/sagernet/cronet-go v0.0.0-20260309100020-c128886ff3fc
github.com/sagernet/cronet-go/all v0.0.0-20260309100020-c128886ff3fc
github.com/sagernet/cronet-go v0.0.0-20260410123506-30af64155529
github.com/sagernet/cronet-go/all v0.0.0-20260410123506-30af64155529
github.com/sagernet/fswatch v0.1.1
github.com/sagernet/gomobile v0.1.12
github.com/sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1
@@ -109,35 +109,35 @@ require (
github.com/prometheus-community/pro-bing v0.4.0 // indirect
github.com/quic-go/qpack v0.6.0 // indirect
github.com/safchain/ethtool v0.3.0 // indirect
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260309101654-0cbdcfddded9 // indirect
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect
github.com/sagernet/nftables v0.3.0-beta.4 // indirect
github.com/spf13/pflag v1.0.9 // indirect

124
go.sum
View File

@@ -168,68 +168,68 @@ github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkk
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM=
github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ=
github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI=
github.com/sagernet/cronet-go v0.0.0-20260309100020-c128886ff3fc h1:YK7PwJT0irRAEui9ASdXSxcE2BOVQipWMF/A1Ogt+7c=
github.com/sagernet/cronet-go v0.0.0-20260309100020-c128886ff3fc/go.mod h1:hwFHBEjjthyEquDULbr4c4ucMedp8Drb6Jvm2kt/0Bw=
github.com/sagernet/cronet-go/all v0.0.0-20260309100020-c128886ff3fc h1:EJPHOqk23IuBsTjXK9OXqkNxPbKOBWKRmviQoCcriAs=
github.com/sagernet/cronet-go/all v0.0.0-20260309100020-c128886ff3fc/go.mod h1:8aty0RW96DrJSMWXO6bRPMBJEjuqq5JWiOIi4bCRzFA=
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260309101654-0cbdcfddded9 h1:Qi0IKBpoPP3qZqIXuOKMsT2dv+l/MLWMyBHDMLRw2EA=
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:XXDwdjX/T8xftoeJxQmbBoYXZp8MAPFR2CwbFuTpEtw=
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260309101654-0cbdcfddded9 h1:p+wCMjOhj46SpSD/AJeTGgkCcbyA76FyH631XZatyU8=
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:iNiUGoLtnr8/JTuVNj7XJbmpOAp2C6+B81KDrPxwaZM=
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260309101654-0cbdcfddded9 h1:Y7lWrZwEhC/HX8Pb5C92CrQihuaE7hrHmWB2ykst3iQ=
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:19ILNUOGIzRdOqa2mq+iY0JoHxuieB7/lnjYeaA2vEc=
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260309101654-0cbdcfddded9 h1:3Ggy5wiyjA6t+aVVPnXlSEIVj9zkxd4ybH3NsvsNefs=
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:JxzGyQf94Cr6sBShKqODGDyRUlESfJK/Njcz9Lz6qMQ=
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260309101654-0cbdcfddded9 h1:DuFTCnZloblY+7olXiZoRdueWfxi34EV5UheTFKM2rA=
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:KN+9T9TBycGOLzmKU4QdcHAJEj6Nlx48ifnlTvvHMvs=
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260309101654-0cbdcfddded9 h1:x/6T2gjpLw9yNdCVR6xBlzMUzED9fxNFNt6U6A6SOh8=
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:kojvtUc29KKnk8hs2QIANynVR59921SnGWA9kXohHc0=
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260309101654-0cbdcfddded9 h1:Lx9PExM70rg8aNxPm0JPeSr5SWC3yFiCz4wIq86ugx8=
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:hkQzRE5GDbaH1/ioqYh0Taho4L6i0yLRCVEZ5xHz5M0=
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260309101654-0cbdcfddded9 h1:BTEpw7/vKR9BNBsHebfpiGHDCPpjVJ3vLIbHNU3VUfM=
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:tzVJFTOm66UxLxy6K0ZN5Ic2PC79e+sKKnt+V9puEa4=
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260309101654-0cbdcfddded9 h1:hdEph9nQXRnKwc/lIDwo15rmzbC6znXF5jJWHPN1Fiw=
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:M/pN6m3j0HFU6/y83n0HU6GLYys3tYdr/xTE8hVEGMo=
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260309101654-0cbdcfddded9 h1:Iq++oYV7dtRJHTpu8yclHJdn+1oj2t1e84/YpdXYWW8=
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:cGh5hO6eljCo6KMQ/Cel8Xgq4+etL0awZLRBDVG1EZQ=
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260309101654-0cbdcfddded9 h1:Y43fuLL8cgwRHpEKwxh0O3vYp7g/SZGvbkJj3cQ6USA=
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:JFE0/cxaKkx0wqPMZU7MgaplQlU0zudv82dROJjClKU=
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260309101654-0cbdcfddded9 h1:bX2GJmF0VCC+tBrVAa49YEsmJ4A9dLmwoA6DJUxRtCY=
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:vU8VftFeSt7fURCa3JXD6+k6ss1YAX+idQjPvHmJ2tI=
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260309101654-0cbdcfddded9 h1:gQTR/2azUCInE0r3kmesZT9xu+x801+BmtDY0d0Tw9Y=
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:vCe4OUuL+XOUge9v3MyTD45BnuAXiH+DkjN9quDXJzQ=
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260309101654-0cbdcfddded9 h1:X4mP3jlYvxgrKpZLOKMmc/O8T5/zP83/23pgfQOc3tY=
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:w9amBWrvjtohQzBGCKJ7LCh22LhTIJs4sE7cYaKQzM0=
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260309101654-0cbdcfddded9 h1:c6xj2nXr/65EDiRFddUKQIBQ/b/lAPoH8WFYlgadaPc=
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:TqlsFtcYS/etTeck46kHBeT8Le0Igw1Q/AV88UnMS3s=
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260309101654-0cbdcfddded9 h1:ahbl7yjOvGVVNUwk9TcQk+xejVfoYAYFRlhWnby0/YM=
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:B6Qd0vys8sv9OKVRN6J9RqDzYRGE938Fb2zrYdBDyTQ=
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260309101654-0cbdcfddded9 h1:JC5Zv5+J85da6g5G56VhdaK53fmo6Os2q/wWi5QlxOw=
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:3tXMMFY7AHugOVBZ5Al7cL7JKsnFOe5bMVr0hZPk3ow=
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260309101654-0cbdcfddded9 h1:4bt7Go588BoM4VjNYMxx0MrvbwlFQn3DdRDCM7BmkRo=
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:Wt5uFdU3tnmm8YzobYewwdF7Mt6SucRQg6xeTNWC3Tk=
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260309101654-0cbdcfddded9 h1:E1z0BeLUh8EZfCjIyS9BrfCocZrt+0KPS0bzop3Sxf4=
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:lyIF6wKBLwWa5ZXaAKbAoewewl+yCHo2iYev39Mbj4E=
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260309101654-0cbdcfddded9 h1:d8ejxRHO7Vi9JqR/6DxR7RyI/swA2JfDWATR4T7otBw=
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:H46PnSTTZNcZokLLiDeMDaHiS1l14PH3tzWi0eykjD8=
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260309101654-0cbdcfddded9 h1:iUDVEVu3RxL5ArPIY72BesbuX5zQ1la/ZFwKpQcGc5c=
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:RBhSUDAKWq7fswtV4nQUQhuaTLcX3ettR7teA7/yf2w=
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260309101654-0cbdcfddded9 h1:xB6ikOC/R3n3hjy68EJ0sbZhH4vwEhd6JM9jZ1U2SVY=
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:wRzoIOGG4xbpp3Gh3triLKwMwYriScXzFtunLYhY4w0=
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260309101654-0cbdcfddded9 h1:mBOuLCPOOMMq8N1+dUM5FqZclqga1+u6fAbPqQcbIhc=
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:LNiZXmWil1OPwKCheqQjtakZlJuKGFz+iv2eGF76Hhs=
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260309101654-0cbdcfddded9 h1:cwPyDfj+ZNFE7kvcWbayQJyeC/KQA16HTXOxgHphL0w=
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:YFDGKTkpkJGc5+hnX/RYosZyTWg9h+68VB55fYRRLYc=
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260309101654-0cbdcfddded9 h1:Zk9zG8kt3mXAboclUXQlvvxKQuhnI8u5NdDEl8uotNY=
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:aaX0YGl8nhGmfRWI8bc3BtDjY8Vzx6O0cS/e1uqxDq4=
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260309101654-0cbdcfddded9 h1:Lu05srGqddQRMnl1MZtGAReln2yJljeGx9b1IadlMJ8=
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:EdzMKA96xITc42QEI+ct4SwqX8Dn3ltKK8wzdkLWpSc=
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260309101654-0cbdcfddded9 h1:Tk9bDywUmOtc0iMjjCVIwMlAQNsxCy+bK+bTNA0OaBE=
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:qix4kv1TTAJ5tY4lJ9vjhe9EY4mM+B7H5giOhbxDVcc=
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260309101654-0cbdcfddded9 h1:tQqDQw3tEHdQpt7NTdAwF3UvZ3CjNIj/IJKMRFmm388=
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:lm9w/oCCRyBiUa3G8lDQTT8x/ONUvgVR2iV9fVzUZB8=
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260309101654-0cbdcfddded9 h1:biUIbI2YxUrcQikEfS/bwPA8NsHp/WO+VZUG4morUmE=
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:n34YyLgapgjWdKa0IoeczjAFCwD3/dxbsH5sucKw0bw=
github.com/sagernet/cronet-go v0.0.0-20260410123506-30af64155529 h1:tG9OIgS2yHlPAV3JdeUxsRB5v/G+SLKJpxqzpp6k8Oo=
github.com/sagernet/cronet-go v0.0.0-20260410123506-30af64155529/go.mod h1:hwFHBEjjthyEquDULbr4c4ucMedp8Drb6Jvm2kt/0Bw=
github.com/sagernet/cronet-go/all v0.0.0-20260410123506-30af64155529 h1:lVtf0GEzHsM7kB8pOgLMXDtiHRdLd9YHJxiFJYA+UtY=
github.com/sagernet/cronet-go/all v0.0.0-20260410123506-30af64155529/go.mod h1:9ojC4hR6aYIFjEJYlWDdVsirXLugrOW+ww6n4qoU4rk=
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260410122836-cce5e03076fc h1:kIrWkB7LXP+ff8d93ZgRJxY3CMMDCQ3UpJXXCtCN7g4=
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:XXDwdjX/T8xftoeJxQmbBoYXZp8MAPFR2CwbFuTpEtw=
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260410122836-cce5e03076fc h1:zlNxXRb10o8dBzKyoKQjECHVFJKK/E6WZELxAbO+1xs=
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:iNiUGoLtnr8/JTuVNj7XJbmpOAp2C6+B81KDrPxwaZM=
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260410122836-cce5e03076fc h1:bVQhCxXgckcDAgbFewjgHrqaANbnjzl7LdqOWnjlNeI=
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260410122836-cce5e03076fc/go.mod h1:19ILNUOGIzRdOqa2mq+iY0JoHxuieB7/lnjYeaA2vEc=
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260410122836-cce5e03076fc h1:ANWZXcqJEK6xYPSRkaUvHJHfCzcTVEYyfkzztE9d/e0=
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:JxzGyQf94Cr6sBShKqODGDyRUlESfJK/Njcz9Lz6qMQ=
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260410122836-cce5e03076fc h1:OkwOWNnQKFOZPhCH3JTJBy2nGVLDMiQsJQi7//uPOaI=
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:KN+9T9TBycGOLzmKU4QdcHAJEj6Nlx48ifnlTvvHMvs=
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260410122836-cce5e03076fc h1:ZtCNLhBZSCsHcFQjTA9UiZBL8e2a//HJITCCsn/m8/g=
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:kojvtUc29KKnk8hs2QIANynVR59921SnGWA9kXohHc0=
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260410122836-cce5e03076fc h1:E2gNT2Hy363eGs72OXEgav63RbvNF7Ptm/71OOG5Ibs=
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260410122836-cce5e03076fc/go.mod h1:hkQzRE5GDbaH1/ioqYh0Taho4L6i0yLRCVEZ5xHz5M0=
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260410122836-cce5e03076fc h1:aZaOSYcELkqhtEnRzeKSC65TzctvdUQjXTSr3CaEhfo=
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:tzVJFTOm66UxLxy6K0ZN5Ic2PC79e+sKKnt+V9puEa4=
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260410122836-cce5e03076fc h1:vnwtUyYifqFN9mywy+aBFUFpQkcy2IfioGuGvsNDhf0=
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260410122836-cce5e03076fc/go.mod h1:M/pN6m3j0HFU6/y83n0HU6GLYys3tYdr/xTE8hVEGMo=
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260410122836-cce5e03076fc h1:w1CclLzyKS38gzD+q3jm60Hr86BhAQ1xiDZ0n8m0nY0=
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:cGh5hO6eljCo6KMQ/Cel8Xgq4+etL0awZLRBDVG1EZQ=
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260410122836-cce5e03076fc h1:Q/gk7S02kQ0bvUDFrNwpKJKVJdjl7kJWzWZKljgi+5w=
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260410122836-cce5e03076fc/go.mod h1:JFE0/cxaKkx0wqPMZU7MgaplQlU0zudv82dROJjClKU=
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260410122836-cce5e03076fc h1:Ai172rUVUzkuHFkNfLldvRG2dI1ClGScI7FtUZWLots=
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:vU8VftFeSt7fURCa3JXD6+k6ss1YAX+idQjPvHmJ2tI=
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260410122836-cce5e03076fc h1:1o6xtlAe1HzwESswMnQoHu1r1n+cLdGAFfPpX+bHO8M=
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260410122836-cce5e03076fc/go.mod h1:vCe4OUuL+XOUge9v3MyTD45BnuAXiH+DkjN9quDXJzQ=
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260410122836-cce5e03076fc h1:Sti8C+dQouIBjURJwmEMKztLHSYWsCen40gwgHgwzSM=
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260410122836-cce5e03076fc/go.mod h1:w9amBWrvjtohQzBGCKJ7LCh22LhTIJs4sE7cYaKQzM0=
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260410122836-cce5e03076fc h1:KdClWyb0mkhRSbMgwz14n6Ibo5EKZkrgTWFYIm9BI+0=
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:TqlsFtcYS/etTeck46kHBeT8Le0Igw1Q/AV88UnMS3s=
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260410122836-cce5e03076fc h1:cO3NyWvhWEEzoSgT8JZwCsR/3P8exvfGVm/K4ZEyNEQ=
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260410122836-cce5e03076fc/go.mod h1:B6Qd0vys8sv9OKVRN6J9RqDzYRGE938Fb2zrYdBDyTQ=
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260410122836-cce5e03076fc h1:ZZ/TroXsTbefE7RaZf6TLYBhiniSQkiXZNU75yizot4=
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260410122836-cce5e03076fc/go.mod h1:3tXMMFY7AHugOVBZ5Al7cL7JKsnFOe5bMVr0hZPk3ow=
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260410122836-cce5e03076fc h1:A9IcfsvbWk2MEnT+DAtD72FOA6X9AdZ/UohFmF651XE=
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:Wt5uFdU3tnmm8YzobYewwdF7Mt6SucRQg6xeTNWC3Tk=
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260410122836-cce5e03076fc h1:/5x0yFE0Qs8jX5/H8cnZwaMiu6ZxCVHvHJQa2GIcw80=
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260410122836-cce5e03076fc/go.mod h1:lyIF6wKBLwWa5ZXaAKbAoewewl+yCHo2iYev39Mbj4E=
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260410122836-cce5e03076fc h1:9+/b5fc+/Nk8J+UnxSC9oQOUFJIauxv1v1M/PxCcEeo=
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260410122836-cce5e03076fc/go.mod h1:H46PnSTTZNcZokLLiDeMDaHiS1l14PH3tzWi0eykjD8=
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260410122836-cce5e03076fc h1:7T4XbPCZt4ZNVtovgfVKq+cgZMRl6O2nmBVr9dprSR8=
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260410122836-cce5e03076fc/go.mod h1:RBhSUDAKWq7fswtV4nQUQhuaTLcX3ettR7teA7/yf2w=
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260410122836-cce5e03076fc h1:75W3nWXJNuGFt57/Gdyl5b2kO1o0lLX+7BNyI33H4eE=
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260410122836-cce5e03076fc/go.mod h1:wRzoIOGG4xbpp3Gh3triLKwMwYriScXzFtunLYhY4w0=
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260410122836-cce5e03076fc h1:qFIm4mvWQjMoTA5qtc6rwzlnfNOVvgnGnyzDkuxHx/w=
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:LNiZXmWil1OPwKCheqQjtakZlJuKGFz+iv2eGF76Hhs=
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260410122836-cce5e03076fc h1:jN/F8+FuGClq/VniawnvnEfjFJ6r8CC6e1ExJnnz6+w=
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260410122836-cce5e03076fc/go.mod h1:YFDGKTkpkJGc5+hnX/RYosZyTWg9h+68VB55fYRRLYc=
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260410122836-cce5e03076fc h1:P9EjLKcKbnb+nBBd2xu0dmLX+FwZxr8Z09MgiFZDGDI=
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260410122836-cce5e03076fc/go.mod h1:aaX0YGl8nhGmfRWI8bc3BtDjY8Vzx6O0cS/e1uqxDq4=
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260410122836-cce5e03076fc h1:k8QhIShmy781KH5arAeYuLx/aJhIXsOJSy6NLsndtWA=
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:EdzMKA96xITc42QEI+ct4SwqX8Dn3ltKK8wzdkLWpSc=
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260410122836-cce5e03076fc h1:xSo4RX7nrAcZangMn4YZ/23AReudgXUKcr+cq8xtt1A=
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260410122836-cce5e03076fc/go.mod h1:qix4kv1TTAJ5tY4lJ9vjhe9EY4mM+B7H5giOhbxDVcc=
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260410122836-cce5e03076fc h1:zCCXtvnPSX5Jmv9wMCh/kXAtOMmqd/HuRsM/m60CoaI=
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:lm9w/oCCRyBiUa3G8lDQTT8x/ONUvgVR2iV9fVzUZB8=
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260410122836-cce5e03076fc h1:5f1Gl0sqSZvt8wTcr0MXpn5L1qExJeatcx+1fPoYsus=
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:n34YyLgapgjWdKa0IoeczjAFCwD3/dxbsH5sucKw0bw=
github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs=
github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o=
github.com/sagernet/gomobile v0.1.12 h1:XwzjZaclFF96deLqwAgK8gU3w0M2A8qxgDmhV+A0wjg=

View File

@@ -52,9 +52,32 @@ type DNSClientOptions struct {
DisableExpire bool `json:"disable_expire,omitempty"`
IndependentCache bool `json:"independent_cache,omitempty"`
CacheCapacity uint32 `json:"cache_capacity,omitempty"`
Optimistic *OptimisticDNSOptions `json:"optimistic,omitempty"`
ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
}
type _OptimisticDNSOptions struct {
Enabled bool `json:"enabled,omitempty"`
Timeout badoption.Duration `json:"timeout,omitempty"`
}
type OptimisticDNSOptions _OptimisticDNSOptions
func (o OptimisticDNSOptions) MarshalJSON() ([]byte, error) {
if o.Timeout == 0 {
return json.Marshal(o.Enabled)
}
return json.Marshal((_OptimisticDNSOptions)(o))
}
func (o *OptimisticDNSOptions) UnmarshalJSON(bytes []byte) error {
err := json.Unmarshal(bytes, &o.Enabled)
if err == nil {
return nil
}
return json.UnmarshalDisallowUnknownFields(bytes, (*_OptimisticDNSOptions)(o))
}
type DNSTransportOptionsRegistry interface {
CreateOptions(transportType string) (any, bool)
}

View File

@@ -16,6 +16,7 @@ type CacheFileOptions struct {
StoreFakeIP bool `json:"store_fakeip,omitempty"`
StoreRDRC bool `json:"store_rdrc,omitempty"`
RDRCTimeout badoption.Duration `json:"rdrc_timeout,omitempty"`
StoreDNS bool `json:"store_dns,omitempty"`
}
type ClashAPIOptions struct {

View File

@@ -93,11 +93,12 @@ type DialerOptions struct {
}
type _DomainResolveOptions struct {
Server string `json:"server"`
Strategy DomainStrategy `json:"strategy,omitempty"`
DisableCache bool `json:"disable_cache,omitempty"`
RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"`
ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
Server string `json:"server"`
Strategy DomainStrategy `json:"strategy,omitempty"`
DisableCache bool `json:"disable_cache,omitempty"`
DisableOptimisticCache bool `json:"disable_optimistic_cache,omitempty"`
RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"`
ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
}
type DomainResolveOptions _DomainResolveOptions
@@ -107,6 +108,7 @@ func (o DomainResolveOptions) MarshalJSON() ([]byte, error) {
return []byte("{}"), nil
} else if o.Strategy == DomainStrategy(C.DomainStrategyAsIS) &&
!o.DisableCache &&
!o.DisableOptimisticCache &&
o.RewriteTTL == nil &&
o.ClientSubnet == nil {
return json.Marshal(o.Server)

View File

@@ -201,18 +201,20 @@ func (r *RouteOptionsActionOptions) UnmarshalJSON(data []byte) error {
}
type DNSRouteActionOptions struct {
Server string `json:"server,omitempty"`
Strategy DomainStrategy `json:"strategy,omitempty"`
DisableCache bool `json:"disable_cache,omitempty"`
RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"`
ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
Server string `json:"server,omitempty"`
Strategy DomainStrategy `json:"strategy,omitempty"`
DisableCache bool `json:"disable_cache,omitempty"`
DisableOptimisticCache bool `json:"disable_optimistic_cache,omitempty"`
RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"`
ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
}
type _DNSRouteOptionsActionOptions struct {
Strategy DomainStrategy `json:"strategy,omitempty"`
DisableCache bool `json:"disable_cache,omitempty"`
RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"`
ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
Strategy DomainStrategy `json:"strategy,omitempty"`
DisableCache bool `json:"disable_cache,omitempty"`
DisableOptimisticCache bool `json:"disable_optimistic_cache,omitempty"`
RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"`
ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
}
type DNSRouteOptionsActionOptions _DNSRouteOptionsActionOptions
@@ -321,11 +323,12 @@ type RouteActionSniff struct {
}
type RouteActionResolve struct {
Server string `json:"server,omitempty"`
Strategy DomainStrategy `json:"strategy,omitempty"`
DisableCache bool `json:"disable_cache,omitempty"`
RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"`
ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
Server string `json:"server,omitempty"`
Strategy DomainStrategy `json:"strategy,omitempty"`
DisableCache bool `json:"disable_cache,omitempty"`
DisableOptimisticCache bool `json:"disable_optimistic_cache,omitempty"`
RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"`
ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
}
type DNSRouteActionPredefined struct {

View File

@@ -78,10 +78,11 @@ func NewNetworkManager(ctx context.Context, logger logger.ContextLogger, options
RoutingMark: uint32(options.DefaultMark),
DomainResolver: defaultDomainResolver.Server,
DomainResolveOptions: adapter.DNSQueryOptions{
Strategy: C.DomainStrategy(defaultDomainResolver.Strategy),
DisableCache: defaultDomainResolver.DisableCache,
RewriteTTL: defaultDomainResolver.RewriteTTL,
ClientSubnet: defaultDomainResolver.ClientSubnet.Build(netip.Prefix{}),
Strategy: C.DomainStrategy(defaultDomainResolver.Strategy),
DisableCache: defaultDomainResolver.DisableCache,
DisableOptimisticCache: defaultDomainResolver.DisableOptimisticCache,
RewriteTTL: defaultDomainResolver.RewriteTTL,
ClientSubnet: defaultDomainResolver.ClientSubnet.Build(netip.Prefix{}),
},
NetworkStrategy: (*C.NetworkStrategy)(options.DefaultNetworkStrategy),
NetworkType: common.Map(options.DefaultNetworkType, option.InterfaceType.Build),

View File

@@ -219,7 +219,6 @@ func (r *Router) routePacketConnection(ctx context.Context, conn N.PacketConn, m
/*if deadline.NeedAdditionalReadDeadline(conn) {
conn = deadline.NewPacketConn(bufio.NewNetPacketConn(conn))
}*/
selectedRule, _, _, packetBuffers, err := r.matchRule(ctx, &metadata, false, false, nil, conn)
if err != nil {
return err
@@ -816,11 +815,12 @@ func (r *Router) actionResolve(ctx context.Context, metadata *adapter.InboundCon
}
}
addresses, err := r.dns.Lookup(adapter.WithContext(ctx, metadata), metadata.Destination.Fqdn, adapter.DNSQueryOptions{
Transport: transport,
Strategy: action.Strategy,
DisableCache: action.DisableCache,
RewriteTTL: action.RewriteTTL,
ClientSubnet: action.ClientSubnet,
Transport: transport,
Strategy: action.Strategy,
DisableCache: action.DisableCache,
DisableOptimisticCache: action.DisableOptimisticCache,
RewriteTTL: action.RewriteTTL,
ClientSubnet: action.ClientSubnet,
})
if err != nil {
return err

View File

@@ -107,11 +107,12 @@ func NewRuleAction(ctx context.Context, logger logger.ContextLogger, action opti
return sniffAction, sniffAction.build()
case C.RuleActionTypeResolve:
return &RuleActionResolve{
Server: action.ResolveOptions.Server,
Strategy: C.DomainStrategy(action.ResolveOptions.Strategy),
DisableCache: action.ResolveOptions.DisableCache,
RewriteTTL: action.ResolveOptions.RewriteTTL,
ClientSubnet: action.ResolveOptions.ClientSubnet.Build(netip.Prefix{}),
Server: action.ResolveOptions.Server,
Strategy: C.DomainStrategy(action.ResolveOptions.Strategy),
DisableCache: action.ResolveOptions.DisableCache,
DisableOptimisticCache: action.ResolveOptions.DisableOptimisticCache,
RewriteTTL: action.ResolveOptions.RewriteTTL,
ClientSubnet: action.ResolveOptions.ClientSubnet.Build(netip.Prefix{}),
}, nil
default:
panic(F.ToString("unknown rule action: ", action.Action))
@@ -126,30 +127,33 @@ func NewDNSRuleAction(logger logger.ContextLogger, action option.DNSRuleAction)
return &RuleActionDNSRoute{
Server: action.RouteOptions.Server,
RuleActionDNSRouteOptions: RuleActionDNSRouteOptions{
Strategy: C.DomainStrategy(action.RouteOptions.Strategy),
DisableCache: action.RouteOptions.DisableCache,
RewriteTTL: action.RouteOptions.RewriteTTL,
ClientSubnet: netip.Prefix(common.PtrValueOrDefault(action.RouteOptions.ClientSubnet)),
Strategy: C.DomainStrategy(action.RouteOptions.Strategy),
DisableCache: action.RouteOptions.DisableCache,
DisableOptimisticCache: action.RouteOptions.DisableOptimisticCache,
RewriteTTL: action.RouteOptions.RewriteTTL,
ClientSubnet: netip.Prefix(common.PtrValueOrDefault(action.RouteOptions.ClientSubnet)),
},
}
case C.RuleActionTypeEvaluate:
return &RuleActionEvaluate{
Server: action.RouteOptions.Server,
RuleActionDNSRouteOptions: RuleActionDNSRouteOptions{
Strategy: C.DomainStrategy(action.RouteOptions.Strategy),
DisableCache: action.RouteOptions.DisableCache,
RewriteTTL: action.RouteOptions.RewriteTTL,
ClientSubnet: netip.Prefix(common.PtrValueOrDefault(action.RouteOptions.ClientSubnet)),
Strategy: C.DomainStrategy(action.RouteOptions.Strategy),
DisableCache: action.RouteOptions.DisableCache,
DisableOptimisticCache: action.RouteOptions.DisableOptimisticCache,
RewriteTTL: action.RouteOptions.RewriteTTL,
ClientSubnet: netip.Prefix(common.PtrValueOrDefault(action.RouteOptions.ClientSubnet)),
},
}
case C.RuleActionTypeRespond:
return &RuleActionRespond{}
case C.RuleActionTypeRouteOptions:
return &RuleActionDNSRouteOptions{
Strategy: C.DomainStrategy(action.RouteOptionsOptions.Strategy),
DisableCache: action.RouteOptionsOptions.DisableCache,
RewriteTTL: action.RouteOptionsOptions.RewriteTTL,
ClientSubnet: netip.Prefix(common.PtrValueOrDefault(action.RouteOptionsOptions.ClientSubnet)),
Strategy: C.DomainStrategy(action.RouteOptionsOptions.Strategy),
DisableCache: action.RouteOptionsOptions.DisableCache,
DisableOptimisticCache: action.RouteOptionsOptions.DisableOptimisticCache,
RewriteTTL: action.RouteOptionsOptions.RewriteTTL,
ClientSubnet: netip.Prefix(common.PtrValueOrDefault(action.RouteOptionsOptions.ClientSubnet)),
}
case C.RuleActionTypeReject:
return &RuleActionReject{
@@ -310,6 +314,9 @@ func formatDNSRouteAction(action string, server string, options RuleActionDNSRou
if options.DisableCache {
descriptions = append(descriptions, "disable-cache")
}
if options.DisableOptimisticCache {
descriptions = append(descriptions, "disable-optimistic-cache")
}
if options.RewriteTTL != nil {
descriptions = append(descriptions, F.ToString("rewrite-ttl=", *options.RewriteTTL))
}
@@ -320,10 +327,11 @@ func formatDNSRouteAction(action string, server string, options RuleActionDNSRou
}
type RuleActionDNSRouteOptions struct {
Strategy C.DomainStrategy
DisableCache bool
RewriteTTL *uint32
ClientSubnet netip.Prefix
Strategy C.DomainStrategy
DisableCache bool
DisableOptimisticCache bool
RewriteTTL *uint32
ClientSubnet netip.Prefix
}
func (r *RuleActionDNSRouteOptions) Type() string {
@@ -335,6 +343,9 @@ func (r *RuleActionDNSRouteOptions) String() string {
if r.DisableCache {
descriptions = append(descriptions, "disable-cache")
}
if r.DisableOptimisticCache {
descriptions = append(descriptions, "disable-optimistic-cache")
}
if r.RewriteTTL != nil {
descriptions = append(descriptions, F.ToString("rewrite-ttl=", *r.RewriteTTL))
}
@@ -510,11 +521,12 @@ func (r *RuleActionSniff) String() string {
}
type RuleActionResolve struct {
Server string
Strategy C.DomainStrategy
DisableCache bool
RewriteTTL *uint32
ClientSubnet netip.Prefix
Server string
Strategy C.DomainStrategy
DisableCache bool
DisableOptimisticCache bool
RewriteTTL *uint32
ClientSubnet netip.Prefix
}
func (r *RuleActionResolve) Type() string {
@@ -532,6 +544,9 @@ func (r *RuleActionResolve) String() string {
if r.DisableCache {
options = append(options, "disable_cache")
}
if r.DisableOptimisticCache {
options = append(options, "disable_optimistic_cache")
}
if r.RewriteTTL != nil {
options = append(options, F.ToString("rewrite_ttl=", *r.RewriteTTL))
}

View File

@@ -1,6 +1,6 @@
module test
go 1.24.7
go 1.25.0
require github.com/sagernet/sing-box v0.0.0
@@ -10,15 +10,15 @@ require (
github.com/docker/docker v27.3.1+incompatible
github.com/docker/go-connections v0.5.0
github.com/gofrs/uuid/v5 v5.4.0
github.com/sagernet/quic-go v0.59.0-sing-box-mod.2
github.com/sagernet/sing v0.8.0-beta.16
github.com/sagernet/sing-quic v0.6.0-beta.11
github.com/sagernet/quic-go v0.59.0-sing-box-mod.4
github.com/sagernet/sing v0.8.5-0.20260404181712-947827ec3849
github.com/sagernet/sing-quic v0.6.2-0.20260330152607-bf674c163212
github.com/sagernet/sing-shadowsocks v0.2.8
github.com/sagernet/sing-shadowsocks2 v0.2.1
github.com/spyzhov/ajson v0.9.4
github.com/stretchr/testify v1.11.1
go.uber.org/goleak v1.3.0
golang.org/x/net v0.48.0
golang.org/x/net v0.52.0
)
require (
@@ -28,16 +28,18 @@ require (
github.com/akutz/memconn v0.1.0 // indirect
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect
github.com/andybalholm/brotli v1.1.0 // indirect
github.com/anthropics/anthropic-sdk-go v1.19.0 // indirect
github.com/anthropics/anthropic-sdk-go v1.26.0 // indirect
github.com/anytls/sing-anytls v0.0.11 // indirect
github.com/caddyserver/certmagic v0.25.0 // indirect
github.com/caddyserver/zerossl v0.1.3 // indirect
github.com/caddyserver/certmagic v0.25.2 // indirect
github.com/caddyserver/zerossl v0.1.5 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/coder/websocket v1.8.14 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 // indirect
github.com/coreos/go-oidc/v3 v3.17.0 // indirect
github.com/cretz/bine v0.2.0 // indirect
github.com/database64128/netx-go v0.1.1 // indirect
github.com/database64128/tfo-go/v2 v2.3.1 // indirect
github.com/database64128/tfo-go/v2 v2.3.2 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa // indirect
github.com/distribution/reference v0.5.0 // indirect
@@ -48,15 +50,16 @@ require (
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/gaissmai/bart v0.18.0 // indirect
github.com/go-chi/chi/v5 v5.2.3 // indirect
github.com/go-chi/chi/v5 v5.2.5 // indirect
github.com/go-chi/render v1.0.3 // indirect
github.com/go-jose/go-jose/v4 v4.1.3 // indirect
github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/godbus/dbus/v5 v5.2.1 // indirect
github.com/godbus/dbus/v5 v5.2.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/btree v1.1.3 // indirect
@@ -65,26 +68,26 @@ require (
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/yamux v0.1.2 // indirect
github.com/hdevalence/ed25519consensus v0.2.0 // indirect
github.com/insomniacslk/dhcp v0.0.0-20251020182700-175e84fbb167 // indirect
github.com/insomniacslk/dhcp v0.0.0-20260220084031-5adc3eb26f91 // indirect
github.com/jsimonetti/rtnetlink v1.4.0 // indirect
github.com/keybase/go-keychain v0.0.1 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/libdns/acmedns v0.5.0 // indirect
github.com/libdns/alidns v1.0.6-beta.3 // indirect
github.com/libdns/alidns v1.0.6 // indirect
github.com/libdns/cloudflare v0.2.2 // indirect
github.com/libdns/libdns v1.1.1 // indirect
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 // indirect
github.com/mdlayher/netlink v1.9.0 // indirect
github.com/mdlayher/socket v0.5.1 // indirect
github.com/metacubex/utls v1.8.4 // indirect
github.com/mholt/acmez/v3 v3.1.4 // indirect
github.com/miekg/dns v1.1.69 // indirect
github.com/mholt/acmez/v3 v3.1.6 // indirect
github.com/miekg/dns v1.1.72 // indirect
github.com/mitchellh/go-ps v1.0.0 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/term v0.5.0 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/openai/openai-go/v3 v3.15.0 // indirect
github.com/openai/openai-go/v3 v3.26.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/pierrec/lz4/v4 v4.1.21 // indirect
@@ -96,41 +99,49 @@ require (
github.com/safchain/ethtool v0.3.0 // indirect
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a // indirect
github.com/sagernet/cors v1.2.1 // indirect
github.com/sagernet/cronet-go v0.0.0-20260117110918-dc1cda1fe287 // indirect
github.com/sagernet/cronet-go/all v0.0.0-20260117110918-dc1cda1fe287 // indirect
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260117110516-f21660bef13f // indirect
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260117110516-f21660bef13f // indirect
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260117110516-f21660bef13f // indirect
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260117110516-f21660bef13f // indirect
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260117110516-f21660bef13f // indirect
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260117110516-f21660bef13f // indirect
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260117110516-f21660bef13f // indirect
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260117110516-f21660bef13f // indirect
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260117110516-f21660bef13f // indirect
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260117110516-f21660bef13f // indirect
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260117110516-f21660bef13f // indirect
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260117110516-f21660bef13f // indirect
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260117110516-f21660bef13f // indirect
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260117110516-f21660bef13f // indirect
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260117110516-f21660bef13f // indirect
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260117110516-f21660bef13f // indirect
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260117110516-f21660bef13f // indirect
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260117110516-f21660bef13f // indirect
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260117110516-f21660bef13f // indirect
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260117110516-f21660bef13f // indirect
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260117110516-f21660bef13f // indirect
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260117110516-f21660bef13f // indirect
github.com/sagernet/cronet-go v0.0.0-20260410123506-30af64155529 // indirect
github.com/sagernet/cronet-go/all v0.0.0-20260410123506-30af64155529 // indirect
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260410122836-cce5e03076fc // indirect
github.com/sagernet/fswatch v0.1.1 // indirect
github.com/sagernet/gvisor v0.0.0-20250822052253-5558536cf237 // indirect
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect
github.com/sagernet/nftables v0.3.0-beta.4 // indirect
github.com/sagernet/sing-cloudflared v0.0.0-20260407120610-7715dc2523fa // indirect
github.com/sagernet/sing-mux v0.3.4 // indirect
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 // indirect
github.com/sagernet/sing-tun v0.8.0-beta.17 // indirect
github.com/sagernet/sing-tun v0.8.8-0.20260410061515-018f5eaae695 // indirect
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1 // indirect
github.com/sagernet/smux v1.5.50-sing-box-mod.1 // indirect
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.6 // indirect
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20250917110311-16510ac47288 // indirect
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.7 // indirect
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20260224074747-506b7631853c // indirect
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 // indirect
github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e // indirect
github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // indirect
@@ -149,31 +160,33 @@ require (
github.com/zeebo/blake3 v0.2.4 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 // indirect
go.opentelemetry.io/otel v1.38.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0 // indirect
go.opentelemetry.io/otel/metric v1.38.0 // indirect
go.opentelemetry.io/otel/trace v1.38.0 // indirect
go.opentelemetry.io/otel v1.43.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 // indirect
go.opentelemetry.io/otel/metric v1.43.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.43.0 // indirect
go.opentelemetry.io/otel/trace v1.43.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.1 // indirect
go.uber.org/zap/exp v0.3.0 // indirect
go4.org/mem v0.0.0-20240501181205-ae6ca9944745 // indirect
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
golang.org/x/crypto v0.46.0 // indirect
golang.org/x/crypto v0.49.0 // indirect
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect
golang.org/x/mod v0.31.0 // indirect
golang.org/x/oauth2 v0.32.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.39.0 // indirect
golang.org/x/term v0.38.0 // indirect
golang.org/x/text v0.32.0 // indirect
golang.org/x/mod v0.33.0 // indirect
golang.org/x/oauth2 v0.35.0 // indirect
golang.org/x/sync v0.20.0 // indirect
golang.org/x/sys v0.42.0 // indirect
golang.org/x/term v0.41.0 // indirect
golang.org/x/text v0.35.0 // indirect
golang.org/x/time v0.11.0 // indirect
golang.org/x/tools v0.40.0 // indirect
golang.org/x/tools v0.42.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
golang.zx2c4.com/wireguard/windows v0.5.3 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect
google.golang.org/grpc v1.77.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect
google.golang.org/grpc v1.80.0 // indirect
google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gotest.tools/v3 v3.5.1 // indirect
lukechampine.com/blake3 v1.3.0 // indirect
zombiezen.com/go/capnproto2 v2.18.2+incompatible // indirect
)

View File

@@ -1,3 +1,5 @@
code.pfad.fr/check v1.1.0 h1:GWvjdzhSEgHvEHe2uJujDcpmZoySKuHQNrZMfzfO0bE=
code.pfad.fr/check v1.1.0/go.mod h1:NiUH13DtYsb7xp5wll0U4SXx7KhXQVCtRgdC96IPfoM=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
@@ -12,16 +14,18 @@ github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7V
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/anthropics/anthropic-sdk-go v1.19.0 h1:mO6E+ffSzLRvR/YUH9KJC0uGw0uV8GjISIuzem//3KE=
github.com/anthropics/anthropic-sdk-go v1.19.0/go.mod h1:WTz31rIUHUHqai2UslPpw5CwXrQP3geYBioRV4WOLvE=
github.com/anthropics/anthropic-sdk-go v1.26.0 h1:oUTzFaUpAevfuELAP1sjL6CQJ9HHAfT7CoSYSac11PY=
github.com/anthropics/anthropic-sdk-go v1.26.0/go.mod h1:qUKmaW+uuPB64iy1l+4kOSvaLqPXnHTTBKH6RVZ7q5Q=
github.com/anytls/sing-anytls v0.0.11 h1:w8e9Uj1oP3m4zxkyZDewPk0EcQbvVxb7Nn+rapEx4fc=
github.com/anytls/sing-anytls v0.0.11/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8=
github.com/caddyserver/certmagic v0.25.0 h1:VMleO/XA48gEWes5l+Fh6tRWo9bHkhwAEhx63i+F5ic=
github.com/caddyserver/certmagic v0.25.0/go.mod h1:m9yB7Mud24OQbPHOiipAoyKPn9pKHhpSJxXR1jydBxA=
github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA=
github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/caddyserver/certmagic v0.25.2 h1:D7xcS7ggX/WEY54x0czj7ioTkmDWKIgxtIi2OcQclUc=
github.com/caddyserver/certmagic v0.25.2/go.mod h1:llW/CvsNmza8S6hmsuggsZeiX+uS27dkqY27wDIuBWg=
github.com/caddyserver/zerossl v0.1.5 h1:dkvOjBAEEtY6LIGAHei7sw2UgqSD6TrWweXpV7lvEvE=
github.com/caddyserver/zerossl v0.1.5/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4=
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cilium/ebpf v0.15.0 h1:7NxJhNiBT3NG8pZJ3c+yfrVdHY8ScgKD27sScgjLMMk=
github.com/cilium/ebpf v0.15.0/go.mod h1:DHp1WyrLeiBh19Cf/tfiSMhqheEiK8fXFZ4No0P1Hso=
github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g=
@@ -30,12 +34,14 @@ github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 h1:8h5+bWd7R6AYUslN6c6iuZWTKsKxUFDlpnmilO6R2n0=
github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
github.com/coreos/go-oidc/v3 v3.17.0 h1:hWBGaQfbi0iVviX4ibC7bk8OKT5qNr4klBaCHVNvehc=
github.com/coreos/go-oidc/v3 v3.17.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8=
github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo=
github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI=
github.com/database64128/netx-go v0.1.1 h1:dT5LG7Gs7zFZBthFBbzWE6K8wAHjSNAaK7wCYZT7NzM=
github.com/database64128/netx-go v0.1.1/go.mod h1:LNlYVipaYkQArRFDNNJ02VkNV+My9A5XR/IGS7sIBQc=
github.com/database64128/tfo-go/v2 v2.3.1 h1:EGE+ELd5/AQ0X6YBlQ9RgKs8+kciNhgN3d8lRvfEJQw=
github.com/database64128/tfo-go/v2 v2.3.1/go.mod h1:k9wcpg/8i5zenspBkc9jUEYehpZZccBnCElzOJB++bU=
github.com/database64128/tfo-go/v2 v2.3.2 h1:UhZMKiMq3swZGUiETkLBDzQnZBPSAeBMClpJGlnJ5Fw=
github.com/database64128/tfo-go/v2 v2.3.2/go.mod h1:GC3uB5oa4beGpCUbRb2ZOWP73bJJFmMyAVgQSO7r724=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -43,6 +49,8 @@ github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa h1:h8TfIT1xc8FWbww
github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa/go.mod h1:Nx87SkVqTKd8UtT+xu7sM/l+LgXs6c0aHrlKusR+2EQ=
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI=
github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
@@ -63,10 +71,12 @@ github.com/gaissmai/bart v0.18.0 h1:jQLBT/RduJu0pv/tLwXE+xKPgtWJejbxuXAR+wLJafo=
github.com/gaissmai/bart v0.18.0/go.mod h1:JJzMAhNF5Rjo4SF4jWBrANuJfqY+FvsFhW7t1UZJ+XY=
github.com/github/fakeca v0.1.0 h1:Km/MVOFvclqxPM9dZBC4+QE564nU4gz4iZ0D9pMw28I=
github.com/github/fakeca v0.1.0/go.mod h1:+bormgoGMMuamOscx7N91aOuUST7wdaJ2rNjeohylyo=
github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE=
github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug=
github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0=
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs=
github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced h1:Q311OHjMh/u5E2TITc++WlTP5We0xNseRMkHDyvhW7I=
github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@@ -80,8 +90,8 @@ github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/godbus/dbus/v5 v5.2.1 h1:I4wwMdWSkmI57ewd+elNGwLRf2/dtSaFz1DujfWYvOk=
github.com/godbus/dbus/v5 v5.2.1/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c=
github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ=
github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c=
github.com/gofrs/uuid/v5 v5.4.0 h1:EfbpCTjqMuGyq5ZJwxqzn3Cbr2d0rUZU7v5ycAk/e/0=
github.com/gofrs/uuid/v5 v5.4.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
@@ -98,14 +108,14 @@ github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 h1:wG8RYIyctLhdF
github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806/go.mod h1:Beg6V6zZ3oEn0JuiUQ4wqwuyqqzasOltcoXPtgLbFp4=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c=
github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8=
github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns=
github.com/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N3iBb1Tb4rdcU=
github.com/hdevalence/ed25519consensus v0.2.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo=
github.com/insomniacslk/dhcp v0.0.0-20251020182700-175e84fbb167 h1:MEufgJohwIjFi2n3eJv4c/8UdRLQVUwPwSWQPoER+eU=
github.com/insomniacslk/dhcp v0.0.0-20251020182700-175e84fbb167/go.mod h1:qfvBmyDNp+/liLEYWRvqny/PEz9hGe2Dz833eXILSmo=
github.com/insomniacslk/dhcp v0.0.0-20260220084031-5adc3eb26f91 h1:u9i04mGE3iliBh0EFuWaKsmcwrLacqGmq1G3XoaM7gY=
github.com/insomniacslk/dhcp v0.0.0-20260220084031-5adc3eb26f91/go.mod h1:qfvBmyDNp+/liLEYWRvqny/PEz9hGe2Dz833eXILSmo=
github.com/jsimonetti/rtnetlink v1.4.0 h1:Z1BF0fRgcETPEa0Kt0MRk3yV5+kF1FWTni6KUFKrq2I=
github.com/jsimonetti/rtnetlink v1.4.0/go.mod h1:5W1jDvWdnthFJ7fxYX1GMK07BUpI4oskfOqvPteYS6E=
github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU=
@@ -120,26 +130,32 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/letsencrypt/challtestsrv v1.4.2 h1:0ON3ldMhZyWlfVNYYpFuWRTmZNnyfiL9Hh5YzC3JVwU=
github.com/letsencrypt/challtestsrv v1.4.2/go.mod h1:GhqMqcSoeGpYd5zX5TgwA6er/1MbWzx/o7yuuVya+Wk=
github.com/letsencrypt/pebble/v2 v2.10.0 h1:Wq6gYXlsY6ubqI3hhxsTzdyotvfdjFBxuwYqCLCnj/U=
github.com/letsencrypt/pebble/v2 v2.10.0/go.mod h1:Sk8cmUIPcIdv2nINo+9PB4L+ZBhzY+F9A1a/h/xmWiQ=
github.com/libdns/acmedns v0.5.0 h1:5pRtmUj4Lb/QkNJSl1xgOGBUJTWW7RjpNaIhjpDXjPE=
github.com/libdns/acmedns v0.5.0/go.mod h1:X7UAFP1Ep9NpTwWpVlrZzJLR7epynAy0wrIxSPFgKjQ=
github.com/libdns/alidns v1.0.6-beta.3 h1:KAmb7FQ1tRzKsaAUGa7ZpGKAMRANwg7+1c7tUbSELq8=
github.com/libdns/alidns v1.0.6-beta.3/go.mod h1:RECwyQ88e9VqQVtSrvX76o1ux3gQUKGzMgxICi+u7Ec=
github.com/libdns/alidns v1.0.6 h1:/Ii428ty6WHFJmE24rZxq2taq++gh7rf9jhgLfp8PmM=
github.com/libdns/alidns v1.0.6/go.mod h1:RECwyQ88e9VqQVtSrvX76o1ux3gQUKGzMgxICi+u7Ec=
github.com/libdns/cloudflare v0.2.2 h1:XWHv+C1dDcApqazlh08Q6pjytYLgR2a+Y3xrXFu0vsI=
github.com/libdns/cloudflare v0.2.2/go.mod h1:w9uTmRCDlAoafAsTPnn2nJ0XHK/eaUMh86DUk8BWi60=
github.com/libdns/libdns v1.1.1 h1:wPrHrXILoSHKWJKGd0EiAVmiJbFShguILTg9leS/P/U=
github.com/libdns/libdns v1.1.1/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 h1:A1Cq6Ysb0GM0tpKMbdCXCIfBclan4oHk1Jb+Hrejirg=
github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42/go.mod h1:BB4YCPDOzfy7FniQ/lxuYQ3dgmM2cZumHbK8RpTjN2o=
github.com/mdlayher/netlink v1.9.0 h1:G8+GLq2x3v4D4MVIqDdNUhTUC7TKiCy/6MDkmItfKco=
github.com/mdlayher/netlink v1.9.0/go.mod h1:YBnl5BXsCoRuwBjKKlZ+aYmEoq0r12FDA/3JC+94KDg=
github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
github.com/metacubex/utls v1.8.4 h1:HmL9nUApDdWSkgUyodfwF6hSjtiwCGGdyhaSpEejKpg=
github.com/metacubex/utls v1.8.4/go.mod h1:kncGGVhFaoGn5M3pFe3SXhZCzsbCJayNOH4UEqTKTko=
github.com/mholt/acmez/v3 v3.1.4 h1:DyzZe/RnAzT3rpZj/2Ii5xZpiEvvYk3cQEN/RmqxwFQ=
github.com/mholt/acmez/v3 v3.1.4/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ=
github.com/miekg/dns v1.1.69 h1:Kb7Y/1Jo+SG+a2GtfoFUfDkG//csdRPwRLkCsxDG9Sc=
github.com/miekg/dns v1.1.69/go.mod h1:7OyjD9nEba5OkqQ/hB4fy3PIoxafSZJtducccIelz3g=
github.com/mholt/acmez/v3 v3.1.6 h1:eGVQNObP0pBN4sxqrXeg7MYqTOWyoiYpQqITVWlrevk=
github.com/mholt/acmez/v3 v3.1.6/go.mod h1:5nTPosTGosLxF3+LU4ygbgMRFDhbAVpqMI4+a4aHLBY=
github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI=
github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs=
github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
@@ -150,12 +166,14 @@ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/openai/openai-go/v3 v3.15.0 h1:hk99rM7YPz+M99/5B/zOQcVwFRLLMdprVGx1vaZ8XMo=
github.com/openai/openai-go/v3 v3.15.0/go.mod h1:cdufnVK14cWcT9qA1rRtrXx4FTRsgbDPW7Ia7SS5cZo=
github.com/openai/openai-go/v3 v3.26.0 h1:bRt6H/ozMNt/dDkN4gobnLqaEGrRGBzmbVs0xxJEnQE=
github.com/openai/openai-go/v3 v3.26.0/go.mod h1:cdufnVK14cWcT9qA1rRtrXx4FTRsgbDPW7Ia7SS5cZo=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM=
github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pires/go-proxyproto v0.8.1 h1:9KEixbdJfhrbtjpz/ZwCdWDD2Xem0NZ38qMYaASJgp0=
@@ -177,54 +195,68 @@ github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkk
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM=
github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ=
github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI=
github.com/sagernet/cronet-go v0.0.0-20260117110918-dc1cda1fe287 h1:0BYNmr0ptjsII948U0oBFmrbo4qEaCFcrE2JPRg3Zlk=
github.com/sagernet/cronet-go v0.0.0-20260117110918-dc1cda1fe287/go.mod h1:hwFHBEjjthyEquDULbr4c4ucMedp8Drb6Jvm2kt/0Bw=
github.com/sagernet/cronet-go/all v0.0.0-20260117110918-dc1cda1fe287 h1:ghxhYSBQpzkakqWqJDvXr/Zmxe0WjTjKuALEGbjGiGY=
github.com/sagernet/cronet-go/all v0.0.0-20260117110918-dc1cda1fe287/go.mod h1:M+4ZjPhLJXIvoxcQsbDofmc19Wrig59hZ+hLvj6S3To=
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260117110516-f21660bef13f h1:8jZbZ4KBTdcXDFLwUBNQt5Xci6ZuAKh255S8TwuBCaM=
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260117110516-f21660bef13f/go.mod h1:XXDwdjX/T8xftoeJxQmbBoYXZp8MAPFR2CwbFuTpEtw=
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260117110516-f21660bef13f h1:tG0hCx+0u5zca7qQ7AMkcv4DCrBG/DKW1ggs/P+BRRI=
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:iNiUGoLtnr8/JTuVNj7XJbmpOAp2C6+B81KDrPxwaZM=
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260117110516-f21660bef13f h1:ZXp5hKJIA7iJ52ZShJCKMQEPLpp/7dDIVZmPGV9Il40=
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260117110516-f21660bef13f/go.mod h1:19ILNUOGIzRdOqa2mq+iY0JoHxuieB7/lnjYeaA2vEc=
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260117110516-f21660bef13f h1:gL7H8HS8s38adz4/HZtRHh79qMwsbLTRRPz4GQ9LcWI=
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:JxzGyQf94Cr6sBShKqODGDyRUlESfJK/Njcz9Lz6qMQ=
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260117110516-f21660bef13f h1:Dchgc0pAY5Jwb5lzUlE+1nhHIzqLx+YOurXLHgvWd/0=
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:KN+9T9TBycGOLzmKU4QdcHAJEj6Nlx48ifnlTvvHMvs=
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260117110516-f21660bef13f h1:+MOLSQoduuKDxF410i1LcSPaQGaiP0eZb0INvMlmjM4=
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:kojvtUc29KKnk8hs2QIANynVR59921SnGWA9kXohHc0=
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260117110516-f21660bef13f h1:lIZna05Vn6n8k21p8OpSUnhwGm+E57PrMjiI4ZUfMSg=
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260117110516-f21660bef13f/go.mod h1:hkQzRE5GDbaH1/ioqYh0Taho4L6i0yLRCVEZ5xHz5M0=
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260117110516-f21660bef13f h1:B2aFQ5CRHI20t8YsEizvtguS5W2QfK7D5XV/NzTIxPE=
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:tzVJFTOm66UxLxy6K0ZN5Ic2PC79e+sKKnt+V9puEa4=
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260117110516-f21660bef13f h1:qpSwJ1rFGYCfJDenNCZoWYjoG7N+xEa6ke+E7/JO1i4=
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260117110516-f21660bef13f/go.mod h1:M/pN6m3j0HFU6/y83n0HU6GLYys3tYdr/xTE8hVEGMo=
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260117110516-f21660bef13f h1:cx7Ipg0tSvTDjS4maMEYz4vuzz93BMPAysmZ1YLrz80=
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260117110516-f21660bef13f/go.mod h1:cGh5hO6eljCo6KMQ/Cel8Xgq4+etL0awZLRBDVG1EZQ=
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260117110516-f21660bef13f h1:4jOHuUiBxD8pJEpBBVQfJqyLmxjpd3t4MLRzU7YLFyg=
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260117110516-f21660bef13f/go.mod h1:JFE0/cxaKkx0wqPMZU7MgaplQlU0zudv82dROJjClKU=
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260117110516-f21660bef13f h1:OpXBa2WlRU+Mam9oRe9Nn4/zf7gQ+qiBTNK8A5RwbfQ=
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:vU8VftFeSt7fURCa3JXD6+k6ss1YAX+idQjPvHmJ2tI=
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260117110516-f21660bef13f h1:nJpGFi+6hI85tl4zoyNFEnFEQ5+xEV5gyvsUoMvd8g0=
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260117110516-f21660bef13f/go.mod h1:vCe4OUuL+XOUge9v3MyTD45BnuAXiH+DkjN9quDXJzQ=
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260117110516-f21660bef13f h1:SEy2rpmgOJgrqcEryJI/RSnqUWIsEsp0cfYoA8y21jc=
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260117110516-f21660bef13f/go.mod h1:w9amBWrvjtohQzBGCKJ7LCh22LhTIJs4sE7cYaKQzM0=
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260117110516-f21660bef13f h1:EW2TuFMLm0iBGqRZtuGwIZdeYmDtDsDmRcRRJQOMxUo=
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:TqlsFtcYS/etTeck46kHBeT8Le0Igw1Q/AV88UnMS3s=
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260117110516-f21660bef13f h1:3U5woxrNCkzfv1+UX+mVoWh1228AE1qAiMG02F9oFbY=
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260117110516-f21660bef13f/go.mod h1:B6Qd0vys8sv9OKVRN6J9RqDzYRGE938Fb2zrYdBDyTQ=
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260117110516-f21660bef13f h1:YwFTfuWG3mmctroeDYtFZ6LHjGsedVO+5wInYbbUuUY=
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260117110516-f21660bef13f/go.mod h1:3tXMMFY7AHugOVBZ5Al7cL7JKsnFOe5bMVr0hZPk3ow=
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260117110516-f21660bef13f h1:r4V0ddPCRLgGu0VdgR3aUsO9NjpmyjAf+h+3oTD9D6E=
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260117110516-f21660bef13f/go.mod h1:aaX0YGl8nhGmfRWI8bc3BtDjY8Vzx6O0cS/e1uqxDq4=
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260117110516-f21660bef13f h1:B8yf4gFvEYUnwWmtVK9sdwUsflYZ387MhYmlOP2ohFQ=
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:EdzMKA96xITc42QEI+ct4SwqX8Dn3ltKK8wzdkLWpSc=
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260117110516-f21660bef13f h1:9YyaMg4rO1/jIgrxmNb0LKH+X7frSYWfX2pFgW5JUVM=
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260117110516-f21660bef13f/go.mod h1:qix4kv1TTAJ5tY4lJ9vjhe9EY4mM+B7H5giOhbxDVcc=
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260117110516-f21660bef13f h1:B0fnGu0sh9yT/9JDN5u/GqThGoOzNN/daOAuGWFLXEk=
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:lm9w/oCCRyBiUa3G8lDQTT8x/ONUvgVR2iV9fVzUZB8=
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260117110516-f21660bef13f h1:lxPcIXKSSI5JDhc7rx/6yufISWM4vtBS2FY9PavWQTs=
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:n34YyLgapgjWdKa0IoeczjAFCwD3/dxbsH5sucKw0bw=
github.com/sagernet/cronet-go v0.0.0-20260410123506-30af64155529 h1:tG9OIgS2yHlPAV3JdeUxsRB5v/G+SLKJpxqzpp6k8Oo=
github.com/sagernet/cronet-go v0.0.0-20260410123506-30af64155529/go.mod h1:hwFHBEjjthyEquDULbr4c4ucMedp8Drb6Jvm2kt/0Bw=
github.com/sagernet/cronet-go/all v0.0.0-20260410123506-30af64155529 h1:lVtf0GEzHsM7kB8pOgLMXDtiHRdLd9YHJxiFJYA+UtY=
github.com/sagernet/cronet-go/all v0.0.0-20260410123506-30af64155529/go.mod h1:9ojC4hR6aYIFjEJYlWDdVsirXLugrOW+ww6n4qoU4rk=
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260410122836-cce5e03076fc h1:kIrWkB7LXP+ff8d93ZgRJxY3CMMDCQ3UpJXXCtCN7g4=
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:XXDwdjX/T8xftoeJxQmbBoYXZp8MAPFR2CwbFuTpEtw=
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260410122836-cce5e03076fc h1:zlNxXRb10o8dBzKyoKQjECHVFJKK/E6WZELxAbO+1xs=
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:iNiUGoLtnr8/JTuVNj7XJbmpOAp2C6+B81KDrPxwaZM=
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260410122836-cce5e03076fc h1:bVQhCxXgckcDAgbFewjgHrqaANbnjzl7LdqOWnjlNeI=
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260410122836-cce5e03076fc/go.mod h1:19ILNUOGIzRdOqa2mq+iY0JoHxuieB7/lnjYeaA2vEc=
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260410122836-cce5e03076fc h1:ANWZXcqJEK6xYPSRkaUvHJHfCzcTVEYyfkzztE9d/e0=
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:JxzGyQf94Cr6sBShKqODGDyRUlESfJK/Njcz9Lz6qMQ=
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260410122836-cce5e03076fc h1:OkwOWNnQKFOZPhCH3JTJBy2nGVLDMiQsJQi7//uPOaI=
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:KN+9T9TBycGOLzmKU4QdcHAJEj6Nlx48ifnlTvvHMvs=
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260410122836-cce5e03076fc h1:ZtCNLhBZSCsHcFQjTA9UiZBL8e2a//HJITCCsn/m8/g=
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:kojvtUc29KKnk8hs2QIANynVR59921SnGWA9kXohHc0=
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260410122836-cce5e03076fc h1:E2gNT2Hy363eGs72OXEgav63RbvNF7Ptm/71OOG5Ibs=
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260410122836-cce5e03076fc/go.mod h1:hkQzRE5GDbaH1/ioqYh0Taho4L6i0yLRCVEZ5xHz5M0=
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260410122836-cce5e03076fc h1:aZaOSYcELkqhtEnRzeKSC65TzctvdUQjXTSr3CaEhfo=
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:tzVJFTOm66UxLxy6K0ZN5Ic2PC79e+sKKnt+V9puEa4=
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260410122836-cce5e03076fc h1:vnwtUyYifqFN9mywy+aBFUFpQkcy2IfioGuGvsNDhf0=
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260410122836-cce5e03076fc/go.mod h1:M/pN6m3j0HFU6/y83n0HU6GLYys3tYdr/xTE8hVEGMo=
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260410122836-cce5e03076fc h1:w1CclLzyKS38gzD+q3jm60Hr86BhAQ1xiDZ0n8m0nY0=
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:cGh5hO6eljCo6KMQ/Cel8Xgq4+etL0awZLRBDVG1EZQ=
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260410122836-cce5e03076fc h1:Q/gk7S02kQ0bvUDFrNwpKJKVJdjl7kJWzWZKljgi+5w=
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260410122836-cce5e03076fc/go.mod h1:JFE0/cxaKkx0wqPMZU7MgaplQlU0zudv82dROJjClKU=
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260410122836-cce5e03076fc h1:Ai172rUVUzkuHFkNfLldvRG2dI1ClGScI7FtUZWLots=
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:vU8VftFeSt7fURCa3JXD6+k6ss1YAX+idQjPvHmJ2tI=
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260410122836-cce5e03076fc h1:1o6xtlAe1HzwESswMnQoHu1r1n+cLdGAFfPpX+bHO8M=
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260410122836-cce5e03076fc/go.mod h1:vCe4OUuL+XOUge9v3MyTD45BnuAXiH+DkjN9quDXJzQ=
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260410122836-cce5e03076fc h1:Sti8C+dQouIBjURJwmEMKztLHSYWsCen40gwgHgwzSM=
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260410122836-cce5e03076fc/go.mod h1:w9amBWrvjtohQzBGCKJ7LCh22LhTIJs4sE7cYaKQzM0=
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260410122836-cce5e03076fc h1:KdClWyb0mkhRSbMgwz14n6Ibo5EKZkrgTWFYIm9BI+0=
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:TqlsFtcYS/etTeck46kHBeT8Le0Igw1Q/AV88UnMS3s=
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260410122836-cce5e03076fc h1:cO3NyWvhWEEzoSgT8JZwCsR/3P8exvfGVm/K4ZEyNEQ=
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260410122836-cce5e03076fc/go.mod h1:B6Qd0vys8sv9OKVRN6J9RqDzYRGE938Fb2zrYdBDyTQ=
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260410122836-cce5e03076fc h1:ZZ/TroXsTbefE7RaZf6TLYBhiniSQkiXZNU75yizot4=
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260410122836-cce5e03076fc/go.mod h1:3tXMMFY7AHugOVBZ5Al7cL7JKsnFOe5bMVr0hZPk3ow=
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260410122836-cce5e03076fc h1:A9IcfsvbWk2MEnT+DAtD72FOA6X9AdZ/UohFmF651XE=
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:Wt5uFdU3tnmm8YzobYewwdF7Mt6SucRQg6xeTNWC3Tk=
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260410122836-cce5e03076fc h1:/5x0yFE0Qs8jX5/H8cnZwaMiu6ZxCVHvHJQa2GIcw80=
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260410122836-cce5e03076fc/go.mod h1:lyIF6wKBLwWa5ZXaAKbAoewewl+yCHo2iYev39Mbj4E=
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260410122836-cce5e03076fc h1:9+/b5fc+/Nk8J+UnxSC9oQOUFJIauxv1v1M/PxCcEeo=
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260410122836-cce5e03076fc/go.mod h1:H46PnSTTZNcZokLLiDeMDaHiS1l14PH3tzWi0eykjD8=
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260410122836-cce5e03076fc h1:7T4XbPCZt4ZNVtovgfVKq+cgZMRl6O2nmBVr9dprSR8=
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260410122836-cce5e03076fc/go.mod h1:RBhSUDAKWq7fswtV4nQUQhuaTLcX3ettR7teA7/yf2w=
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260410122836-cce5e03076fc h1:75W3nWXJNuGFt57/Gdyl5b2kO1o0lLX+7BNyI33H4eE=
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260410122836-cce5e03076fc/go.mod h1:wRzoIOGG4xbpp3Gh3triLKwMwYriScXzFtunLYhY4w0=
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260410122836-cce5e03076fc h1:qFIm4mvWQjMoTA5qtc6rwzlnfNOVvgnGnyzDkuxHx/w=
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:LNiZXmWil1OPwKCheqQjtakZlJuKGFz+iv2eGF76Hhs=
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260410122836-cce5e03076fc h1:jN/F8+FuGClq/VniawnvnEfjFJ6r8CC6e1ExJnnz6+w=
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260410122836-cce5e03076fc/go.mod h1:YFDGKTkpkJGc5+hnX/RYosZyTWg9h+68VB55fYRRLYc=
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260410122836-cce5e03076fc h1:P9EjLKcKbnb+nBBd2xu0dmLX+FwZxr8Z09MgiFZDGDI=
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260410122836-cce5e03076fc/go.mod h1:aaX0YGl8nhGmfRWI8bc3BtDjY8Vzx6O0cS/e1uqxDq4=
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260410122836-cce5e03076fc h1:k8QhIShmy781KH5arAeYuLx/aJhIXsOJSy6NLsndtWA=
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:EdzMKA96xITc42QEI+ct4SwqX8Dn3ltKK8wzdkLWpSc=
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260410122836-cce5e03076fc h1:xSo4RX7nrAcZangMn4YZ/23AReudgXUKcr+cq8xtt1A=
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260410122836-cce5e03076fc/go.mod h1:qix4kv1TTAJ5tY4lJ9vjhe9EY4mM+B7H5giOhbxDVcc=
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260410122836-cce5e03076fc h1:zCCXtvnPSX5Jmv9wMCh/kXAtOMmqd/HuRsM/m60CoaI=
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:lm9w/oCCRyBiUa3G8lDQTT8x/ONUvgVR2iV9fVzUZB8=
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260410122836-cce5e03076fc h1:5f1Gl0sqSZvt8wTcr0MXpn5L1qExJeatcx+1fPoYsus=
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260410122836-cce5e03076fc/go.mod h1:n34YyLgapgjWdKa0IoeczjAFCwD3/dxbsH5sucKw0bw=
github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs=
github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o=
github.com/sagernet/gvisor v0.0.0-20250822052253-5558536cf237 h1:SUPFNB+vSP4RBPrSEgNII+HkfqC8hKMpYLodom4o4EU=
@@ -233,30 +265,32 @@ github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZN
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I=
github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8=
github.com/sagernet/quic-go v0.59.0-sing-box-mod.2 h1:hJUL+HtxEOjxsa0CsucbBVqI/AMS4k52NwNU637zmdw=
github.com/sagernet/quic-go v0.59.0-sing-box-mod.2/go.mod h1:OqILvS182CyOol5zNNo6bguvOGgXzV459+chpRaUC+4=
github.com/sagernet/sing v0.8.0-beta.16 h1:Fe+6E9VHYky9Mx4cf0ugbZPWDcXRflpAu7JQ5bWXvaA=
github.com/sagernet/sing v0.8.0-beta.16/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/quic-go v0.59.0-sing-box-mod.4 h1:6qvrUW79S+CrPwWz6cMePXohgjHoKxLo3c+MDhNwc3o=
github.com/sagernet/quic-go v0.59.0-sing-box-mod.4/go.mod h1:OqILvS182CyOol5zNNo6bguvOGgXzV459+chpRaUC+4=
github.com/sagernet/sing v0.8.5-0.20260404181712-947827ec3849 h1:P8jaGN561IbHBxjlU8IGrFK65n1vDOrHo8FOMgHfn14=
github.com/sagernet/sing v0.8.5-0.20260404181712-947827ec3849/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing-cloudflared v0.0.0-20260407120610-7715dc2523fa h1:165HiOfgfofJIirEp1NGSmsoJAi+++WhR29IhtAu4A4=
github.com/sagernet/sing-cloudflared v0.0.0-20260407120610-7715dc2523fa/go.mod h1:bH2NKX+NpDTY1Zkxfboxw6MXB/ZywaNLmrDJYgKMJ2Y=
github.com/sagernet/sing-mux v0.3.4 h1:ZQplKl8MNXutjzbMVtWvWG31fohhgOfCuUZR4dVQ8+s=
github.com/sagernet/sing-mux v0.3.4/go.mod h1:QvlKMyNBNrQoyX4x+gq028uPbLM2XeRpWtDsWBJbFSk=
github.com/sagernet/sing-quic v0.6.0-beta.11 h1:eUusxITKKRedhWC2ScUYFUvD96h/QfbKLaS3N6/7in4=
github.com/sagernet/sing-quic v0.6.0-beta.11/go.mod h1:K5bWvITOm4vE10fwLfrWpw27bCoVJ+tfQ79tOWg+Ko8=
github.com/sagernet/sing-quic v0.6.2-0.20260330152607-bf674c163212 h1:7mFOUqy+DyOj7qKGd1X54UMXbnbJiiMileK/tn17xYc=
github.com/sagernet/sing-quic v0.6.2-0.20260330152607-bf674c163212/go.mod h1:K5bWvITOm4vE10fwLfrWpw27bCoVJ+tfQ79tOWg+Ko8=
github.com/sagernet/sing-shadowsocks v0.2.8 h1:PURj5PRoAkqeHh2ZW205RWzN9E9RtKCVCzByXruQWfE=
github.com/sagernet/sing-shadowsocks v0.2.8/go.mod h1:lo7TWEMDcN5/h5B8S0ew+r78ZODn6SwVaFhvB6H+PTI=
github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnqqs2gQ2/Qioo=
github.com/sagernet/sing-shadowsocks2 v0.2.1/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 h1:tK+75l64tm9WvEFrYRE1t0YxoFdWQqw/h7Uhzj0vJ+w=
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA=
github.com/sagernet/sing-tun v0.8.0-beta.17 h1:6DdbNXeTFYj8Tb4FCh8Mp2boA3rVY6VNqzTOObj7Xis=
github.com/sagernet/sing-tun v0.8.0-beta.17/go.mod h1:+HAK/y9GZljdT0KYKMYDR8MjjqnqDDQZYp5ZZQoRzS8=
github.com/sagernet/sing-tun v0.8.8-0.20260410061515-018f5eaae695 h1:2maqN3XuorEo5faXHIyYZQZ1/ybim4hImfCEWZwdPbk=
github.com/sagernet/sing-tun v0.8.8-0.20260410061515-018f5eaae695/go.mod h1:pLCo4o+LacXEzz0bhwhJkKBjLlKOGPBNOAZ97ZVZWzs=
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1 h1:aSwUNYUkVyVvdmBSufR8/nRFonwJeKSIROxHcm5br9o=
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1/go.mod h1:P11scgTxMxVVQ8dlM27yNm3Cro40mD0+gHbnqrNGDuY=
github.com/sagernet/smux v1.5.50-sing-box-mod.1 h1:XkJcivBC9V4wBjiGXIXZ229aZCU1hzcbp6kSkkyQ478=
github.com/sagernet/smux v1.5.50-sing-box-mod.1/go.mod h1:NjhsCEWedJm7eFLyhuBgIEzwfhRmytrUoiLluxs5Sk8=
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.6 h1:eYz/OpMqWCvO2++iw3dEuzrlfC2xv78GdlGvprIM6O8=
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.6/go.mod h1:m87GAn4UcesHQF3leaPFEINZETO5za1LGn1GJdNDgNc=
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20250917110311-16510ac47288 h1:E2tZFeg9mGYGQ7E7BbxMv1cU35HxwgRm6tPKI2Pp7DA=
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20250917110311-16510ac47288/go.mod h1:WUxgxUDZoCF2sxVmW+STSxatP02Qn3FcafTiI2BLtE0=
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.7 h1:8zc1Aph1+ElqF9/7aSPkO0o4vTd+AfQC+CO324mLWGg=
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.7/go.mod h1:m87GAn4UcesHQF3leaPFEINZETO5za1LGn1GJdNDgNc=
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20260224074747-506b7631853c h1:f9cXNB+IOOPnR8DOLMTpr42jf7naxh5Un5Y09BBf5Cg=
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20260224074747-506b7631853c/go.mod h1:WUxgxUDZoCF2sxVmW+STSxatP02Qn3FcafTiI2BLtE0=
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc=
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854/go.mod h1:LtfoSK3+NG57tvnVEHgcuBW9ujgE8enPSgzgwStwCAA=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
@@ -293,6 +327,8 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
github.com/tinylib/msgp v1.6.3 h1:bCSxiTz386UTgyT1i0MSCvdbWjVW+8sG3PjkGsZQt4s=
github.com/tinylib/msgp v1.6.3/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA=
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8RaCKgVpHZnecvArXvPXcFkM=
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA=
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
@@ -312,22 +348,22 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0 h1:K0XaT3DwHAcV4nKLzcQvwAgSyisUghWoY20I7huthMk=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0/go.mod h1:B5Ki776z/MBnVha1Nzwp5arlzBbE3+1jk+pGmaP5HME=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0 h1:lUsI2TYsQw2r1IASwoROaCnjdj2cvC2+Jbxvk6nHnWU=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0/go.mod h1:2HpZxxQurfGxJlJDblybejHB6RX6pmExPNe517hREw4=
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I=
go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJKlCZufyRzPzlQhUIWVmfltrXuGyfjREgGP3UUjc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak=
go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM=
go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY=
go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg=
go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg=
go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw=
go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A=
go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A=
go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0=
go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g=
go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
@@ -344,32 +380,32 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0=
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU=
golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w=
golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI=
golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg=
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY=
golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ=
golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -379,24 +415,24 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -405,19 +441,21 @@ golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeu
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE=
golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 h1:mepRgnBZa07I4TRuomDE4sTIYieg/osKmzIf4USdWS4=
google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM=
google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig=
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 h1:VPWxll4HlMw1Vs/qXtN7BvhZqsS9cdAittCNvVENElA=
google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:7QBABkRtR8z+TEnmXTqIqwJLlzrZKVfAUm7tY3yGv0M=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 h1:m8qni9SQFH0tJc1X0vmnpw/0t+AImlSvp30sEupozUg=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM=
google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
@@ -427,3 +465,5 @@ lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE=
lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k=
software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI=
zombiezen.com/go/capnproto2 v2.18.2+incompatible h1:v3BD1zbruvffn7zjJUU5Pn8nZAB11bhZSQC4W+YnnKo=
zombiezen.com/go/capnproto2 v2.18.2+incompatible/go.mod h1:XO5Pr2SbXgqZwn0m0Ru54QBqpOf4K5AYBO+8LAOBQEQ=