mirror of
https://github.com/SagerNet/sing-box.git
synced 2026-04-14 04:38:28 +10:00
60 lines
1.3 KiB
Go
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
|
|
}
|