| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- package maskcompat
- import (
- "slices"
- "strings"
- )
- // legacyXdnsEDNS0 is the EDNS0 payload the pre-26.9.30 xdns always negotiated;
- // the object shape makes it opt-in and caps every answer at 512 bytes without it.
- const legacyXdnsEDNS0 = 1232
- var legacyXdnsRecordTypes = map[string]int{"": 16, "txt": 16, "a": 1, "aaaa": 28}
- // UpgradeLegacyXdns rewrites xdns masks into the names/addrs lists xray-core 26.10.10
- // (#7090) parses: it ignores 26.9.30's name/type+settings keys and fails the string lists.
- func UpgradeLegacyXdns(finalmask any) bool {
- fm, _ := finalmask.(map[string]any)
- masks, _ := fm["udp"].([]any)
- changed := false
- for _, entry := range masks {
- mask, _ := entry.(map[string]any)
- if maskType, _ := mask["type"].(string); !strings.EqualFold(maskType, "xdns") {
- continue
- }
- if settings, ok := mask["settings"].(map[string]any); ok && upgradeLegacyXdnsSettings(settings) {
- changed = true
- }
- }
- return changed
- }
- // upgradeLegacyXdnsSettings maps a bare name to TXT, the type legacy clients queried by
- // default, and drops entries the old core refused instead of keeping them to fail again.
- func upgradeLegacyXdnsSettings(settings map[string]any) bool {
- rawDomains, _ := settings["domains"].([]any)
- rawResolvers, _ := settings["resolvers"].([]any)
- if !slices.ContainsFunc(rawDomains, isLegacyXdnsDomain) && !slices.ContainsFunc(rawResolvers, isLegacyXdnsResolver) {
- return false
- }
- domains := make([]any, 0, len(rawDomains))
- listed := map[string]bool{}
- addDomain := func(domain map[string]any) {
- names, _ := domain["names"].([]any)
- for _, name := range names {
- if s, ok := name.(string); ok {
- listed[strings.ToLower(s)] = true
- }
- }
- domains = append(domains, domain)
- }
- addLegacyDomain := func(domain map[string]any) {
- if name, _ := domain["names"].([]any)[0].(string); !listed[strings.ToLower(name)] {
- addDomain(domain)
- }
- }
- for _, entry := range rawDomains {
- switch value := entry.(type) {
- case map[string]any:
- addDomain(upgradeXdnsDomainObject(value))
- case string:
- if domain, ok := legacyXdnsDomain(value); ok {
- addLegacyDomain(domain)
- }
- }
- }
- resolvers := make([]any, 0, len(rawResolvers))
- for _, entry := range rawResolvers {
- switch value := entry.(type) {
- case string:
- head, addr, found := strings.Cut(value, "+udp://")
- addr = strings.TrimSpace(addr)
- domain, valid := legacyXdnsDomain(head)
- if !found || addr == "" || !valid {
- continue
- }
- addLegacyDomain(domain)
- resolvers = append(resolvers, map[string]any{"addrs": []any{"udp://" + addr}})
- case map[string]any:
- if !isLegacyXdnsResolver(value) {
- resolvers = append(resolvers, value)
- } else if addr, ok := legacyXdnsResolverAddr(value); ok {
- resolvers = append(resolvers, map[string]any{"addrs": []any{addr}})
- }
- default:
- resolvers = append(resolvers, entry)
- }
- }
- settings["domains"] = domains
- if len(resolvers) > 0 {
- settings["resolvers"] = resolvers
- } else {
- delete(settings, "resolvers")
- }
- return true
- }
- // upgradeXdnsDomainObject folds a 26.9.30 domain's single "name" into the "names" list.
- func upgradeXdnsDomainObject(domain map[string]any) map[string]any {
- raw, legacy := domain["name"]
- if !legacy {
- return domain
- }
- delete(domain, "name")
- name, _ := raw.(string)
- name = strings.TrimSpace(name)
- names, _ := domain["names"].([]any)
- if name != "" && !slices.Contains(names, any(name)) {
- names = append([]any{name}, names...)
- }
- if names == nil {
- names = []any{}
- }
- domain["names"] = names
- return domain
- }
- // legacyXdnsResolverAddr turns a 26.9.30 {type, settings:{addr}} resolver into the URL
- // the addrs list takes; that loader refused every type but udp and tcp.
- func legacyXdnsResolverAddr(resolver map[string]any) (string, bool) {
- kind, _ := resolver["type"].(string)
- kind = strings.ToLower(strings.TrimSpace(kind))
- settings, _ := resolver["settings"].(map[string]any)
- addr, _ := settings["addr"].(string)
- addr = strings.TrimSpace(addr)
- if (kind != "udp" && kind != "tcp") || addr == "" {
- return "", false
- }
- return kind + "://" + addr, true
- }
- // legacyXdnsDomain parses the "name[:txt|a|aaaa]" spec both legacy lists used.
- func legacyXdnsDomain(spec string) (map[string]any, bool) {
- name, method := strings.TrimSpace(spec), ""
- if i := strings.LastIndex(name, ":"); i >= 0 {
- name, method = name[:i], strings.ToLower(name[i+1:])
- }
- name = strings.Trim(name, ".")
- recordType, known := legacyXdnsRecordTypes[method]
- if name == "" || !known {
- return nil, false
- }
- return map[string]any{"names": []any{name}, "types": []any{recordType}, "edns0": legacyXdnsEDNS0}, true
- }
- func isLegacyXdnsDomain(value any) bool {
- switch domain := value.(type) {
- case string:
- return true
- case map[string]any:
- _, legacy := domain["name"]
- return legacy
- }
- return false
- }
- func isLegacyXdnsResolver(value any) bool {
- switch resolver := value.(type) {
- case string:
- return true
- case map[string]any:
- _, current := resolver["addrs"]
- return !current
- }
- return false
- }
|