Files
sing-box/protocol/cloudflare/features.go
2026-03-31 15:32:56 +08:00

60 lines
1.3 KiB
Go

//go:build with_cloudflared
package cloudflare
import (
"context"
"encoding/json"
"hash/fnv"
"net"
"time"
)
const (
featureSelectorHostname = "cfd-features.argotunnel.com"
featureLookupTimeout = 10 * time.Second
)
type cloudflaredFeaturesRecord struct {
DatagramV3Percentage uint32 `json:"dv3_2"`
}
var lookupCloudflaredFeatures = func(ctx context.Context) ([]byte, error) {
lookupCtx, cancel := context.WithTimeout(ctx, featureLookupTimeout)
defer cancel()
records, err := net.DefaultResolver.LookupTXT(lookupCtx, featureSelectorHostname)
if err != nil || len(records) == 0 {
return nil, err
}
return []byte(records[0]), nil
}
func resolveDatagramVersion(ctx context.Context, accountTag string, configured string) string {
if configured != "" {
return configured
}
record, err := lookupCloudflaredFeatures(ctx)
if err != nil {
return "v2"
}
var features cloudflaredFeaturesRecord
if err := json.Unmarshal(record, &features); err != nil {
return "v2"
}
if accountEnabled(accountTag, features.DatagramV3Percentage) {
return "v3"
}
return "v2"
}
func accountEnabled(accountTag string, percentage uint32) bool {
if percentage == 0 {
return false
}
hasher := fnv.New32a()
_, _ = hasher.Write([]byte(accountTag))
return percentage > hasher.Sum32()%100
}