|
@@ -2,14 +2,16 @@ package maskcompat
|
|
|
|
|
|
|
|
import (
|
|
import (
|
|
|
"encoding/json"
|
|
"encoding/json"
|
|
|
|
|
+ "slices"
|
|
|
"testing"
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/xtls/xray-core/infra/conf"
|
|
"github.com/xtls/xray-core/infra/conf"
|
|
|
|
|
+ "github.com/xtls/xray-core/transport/internet/finalmask/xdns"
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
-// buildXdnsSettings runs an xdns mask's settings through conf.XDNS, the loader
|
|
|
|
|
-// the core calls at startup, so the test's verdict is the core's verdict.
|
|
|
|
|
-func buildXdnsSettings(t *testing.T, settings any) error {
|
|
|
|
|
|
|
+// coreXdnsView runs an xdns mask's settings through conf.XDNS, the loader the core
|
|
|
|
|
+// calls at startup, and returns the domain names and resolvers the core would use.
|
|
|
|
|
+func coreXdnsView(t *testing.T, settings any) (domains, resolvers []string, err error) {
|
|
|
t.Helper()
|
|
t.Helper()
|
|
|
raw, err := json.Marshal(settings)
|
|
raw, err := json.Marshal(settings)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
@@ -17,42 +19,75 @@ func buildXdnsSettings(t *testing.T, settings any) error {
|
|
|
}
|
|
}
|
|
|
var mask conf.XDNS
|
|
var mask conf.XDNS
|
|
|
if err := json.Unmarshal(raw, &mask); err != nil {
|
|
if err := json.Unmarshal(raw, &mask); err != nil {
|
|
|
- return err
|
|
|
|
|
|
|
+ return nil, nil, err
|
|
|
}
|
|
}
|
|
|
- _, err = mask.Build()
|
|
|
|
|
- return err
|
|
|
|
|
|
|
+ built, err := mask.Build()
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ config := built.(*xdns.Config)
|
|
|
|
|
+ for _, domain := range config.Domains {
|
|
|
|
|
+ domains = append(domains, domain.Name)
|
|
|
|
|
+ }
|
|
|
|
|
+ for _, resolver := range config.Resolvers {
|
|
|
|
|
+ resolvers = append(resolvers, resolver.Type+"://"+resolver.Addr)
|
|
|
|
|
+ }
|
|
|
|
|
+ return domains, resolvers, nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func TestUpgradeLegacyXdns(t *testing.T) {
|
|
func TestUpgradeLegacyXdns(t *testing.T) {
|
|
|
tests := []struct {
|
|
tests := []struct {
|
|
|
- name string
|
|
|
|
|
- mask string
|
|
|
|
|
- want string
|
|
|
|
|
|
|
+ name string
|
|
|
|
|
+ mask string
|
|
|
|
|
+ want string
|
|
|
|
|
+ wantDomains []string
|
|
|
|
|
+ wantResolvers []string
|
|
|
}{
|
|
}{
|
|
|
{
|
|
{
|
|
|
- name: "bare server domain becomes TXT with the legacy EDNS0 size",
|
|
|
|
|
- mask: `{"type":"xdns","settings":{"domains":["t.example.com"]}}`,
|
|
|
|
|
- want: `{"domains":[{"edns0":1232,"name":"t.example.com","types":[16]}]}`,
|
|
|
|
|
|
|
+ name: "bare server domain becomes TXT with the legacy EDNS0 size",
|
|
|
|
|
+ mask: `{"type":"xdns","settings":{"domains":["t.example.com"]}}`,
|
|
|
|
|
+ want: `{"domains":[{"edns0":1232,"names":["t.example.com"],"types":[16]}]}`,
|
|
|
|
|
+ wantDomains: []string{"t.example.com"},
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ name: "method suffixes map to their record types",
|
|
|
|
|
+ mask: `{"type":"xdns","settings":{"domains":["a.example.com:a","q.example.com:AAAA","t.example.com:txt"]}}`,
|
|
|
|
|
+ want: `{"domains":[{"edns0":1232,"names":["a.example.com"],"types":[1]},{"edns0":1232,"names":["q.example.com"],"types":[28]},{"edns0":1232,"names":["t.example.com"],"types":[16]}]}`,
|
|
|
|
|
+ wantDomains: []string{"a.example.com", "q.example.com", "t.example.com"},
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ name: "client resolver splits into its domain and a udp resolver",
|
|
|
|
|
+ mask: `{"type":"XDNS","settings":{"resolvers":["t.example.com:a+udp://8.8.8.8:53"]}}`,
|
|
|
|
|
+ want: `{"domains":[{"edns0":1232,"names":["t.example.com"],"types":[1]}],"resolvers":[{"addrs":["udp://8.8.8.8:53"]}]}`,
|
|
|
|
|
+ wantDomains: []string{"t.example.com"},
|
|
|
|
|
+ wantResolvers: []string{"udp://8.8.8.8:53"},
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
|
- name: "method suffixes map to their record types",
|
|
|
|
|
- mask: `{"type":"xdns","settings":{"domains":["a.example.com:a","q.example.com:AAAA","t.example.com:txt"]}}`,
|
|
|
|
|
- want: `{"domains":[{"edns0":1232,"name":"a.example.com","types":[1]},{"edns0":1232,"name":"q.example.com","types":[28]},{"edns0":1232,"name":"t.example.com","types":[16]}]}`,
|
|
|
|
|
|
|
+ name: "a resolver for an already listed domain adds no duplicate",
|
|
|
|
|
+ mask: `{"type":"xdns","settings":{"domains":["t.example.com"],"resolvers":["T.example.com+udp://1.1.1.1:53"]}}`,
|
|
|
|
|
+ want: `{"domains":[{"edns0":1232,"names":["t.example.com"],"types":[16]}],"resolvers":[{"addrs":["udp://1.1.1.1:53"]}]}`,
|
|
|
|
|
+ wantDomains: []string{"t.example.com"},
|
|
|
|
|
+ wantResolvers: []string{"udp://1.1.1.1:53"},
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
|
- name: "client resolver splits into its domain and a udp resolver",
|
|
|
|
|
- mask: `{"type":"XDNS","settings":{"resolvers":["t.example.com:a+udp://8.8.8.8:53"]}}`,
|
|
|
|
|
- want: `{"domains":[{"edns0":1232,"name":"t.example.com","types":[1]}],"resolvers":[{"settings":{"addr":"8.8.8.8:53"},"type":"udp"}]}`,
|
|
|
|
|
|
|
+ name: "string entries the old core refused are dropped",
|
|
|
|
|
+ mask: `{"type":"xdns","settings":{"domains":["t.example.com","m.example.com:mx"],"resolvers":["1.1.1.1:53"]}}`,
|
|
|
|
|
+ want: `{"domains":[{"edns0":1232,"names":["t.example.com"],"types":[16]}]}`,
|
|
|
|
|
+ wantDomains: []string{"t.example.com"},
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
|
- name: "a resolver for an already listed domain adds no duplicate",
|
|
|
|
|
- mask: `{"type":"xdns","settings":{"domains":["t.example.com"],"resolvers":["T.example.com+udp://1.1.1.1:53"]}}`,
|
|
|
|
|
- want: `{"domains":[{"edns0":1232,"name":"t.example.com","types":[16]}],"resolvers":[{"settings":{"addr":"1.1.1.1:53"},"type":"udp"}]}`,
|
|
|
|
|
|
|
+ name: "26.9.30 domain and resolver objects move to names and addrs",
|
|
|
|
|
+ mask: `{"type":"xdns","settings":{"domains":[{"name":"t.example.com","types":[16,28],"edns0":1232,"lenLimit":200}],"resolvers":[{"type":"tcp","settings":{"addr":"8.8.8.8:53"}},{"type":"udp","settings":{"addr":"1.1.1.1:5353"}}],"extraPoll":1}}`,
|
|
|
|
|
+ want: `{"domains":[{"edns0":1232,"lenLimit":200,"names":["t.example.com"],"types":[16,28]}],"extraPoll":1,"resolvers":[{"addrs":["tcp://8.8.8.8:53"]},{"addrs":["udp://1.1.1.1:5353"]}]}`,
|
|
|
|
|
+ wantDomains: []string{"t.example.com"},
|
|
|
|
|
+ wantResolvers: []string{"tcp://8.8.8.8:53", "udp://1.1.1.1:5353"},
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
|
- name: "entries the old core refused are dropped",
|
|
|
|
|
- mask: `{"type":"xdns","settings":{"domains":["t.example.com","m.example.com:mx"],"resolvers":["1.1.1.1:53"]}}`,
|
|
|
|
|
- want: `{"domains":[{"edns0":1232,"name":"t.example.com","types":[16]}]}`,
|
|
|
|
|
|
|
+ name: "26.9.30 resolvers the old loader refused are dropped",
|
|
|
|
|
+ mask: `{"type":"xdns","settings":{"domains":[{"name":"t.example.com"}],"resolvers":[{"type":"doh","settings":{"addr":"dns.example.com"}},{"type":"udp","settings":{}},{"type":"udp","settings":{"addr":"9.9.9.9:53"}}]}}`,
|
|
|
|
|
+ want: `{"domains":[{"names":["t.example.com"]}],"resolvers":[{"addrs":["udp://9.9.9.9:53"]}]}`,
|
|
|
|
|
+ wantDomains: []string{"t.example.com"},
|
|
|
|
|
+ wantResolvers: []string{"udp://9.9.9.9:53"},
|
|
|
},
|
|
},
|
|
|
}
|
|
}
|
|
|
for _, tc := range tests {
|
|
for _, tc := range tests {
|
|
@@ -61,8 +96,9 @@ func TestUpgradeLegacyXdns(t *testing.T) {
|
|
|
if err := json.Unmarshal([]byte(tc.mask), &mask); err != nil {
|
|
if err := json.Unmarshal([]byte(tc.mask), &mask); err != nil {
|
|
|
t.Fatalf("unmarshal mask: %v", err)
|
|
t.Fatalf("unmarshal mask: %v", err)
|
|
|
}
|
|
}
|
|
|
- if err := buildXdnsSettings(t, mask["settings"]); err == nil {
|
|
|
|
|
- t.Fatal("the core accepted the legacy string shape; the upgrade is no longer needed")
|
|
|
|
|
|
|
+ domains, resolvers, err := coreXdnsView(t, mask["settings"])
|
|
|
|
|
+ if err == nil && slices.Equal(domains, tc.wantDomains) && slices.Equal(resolvers, tc.wantResolvers) {
|
|
|
|
|
+ t.Fatal("the core already serves the legacy shape as intended; the upgrade is no longer needed")
|
|
|
}
|
|
}
|
|
|
finalmask := map[string]any{"udp": []any{mask}}
|
|
finalmask := map[string]any{"udp": []any{mask}}
|
|
|
if !UpgradeLegacyXdns(finalmask) {
|
|
if !UpgradeLegacyXdns(finalmask) {
|
|
@@ -75,21 +111,25 @@ func TestUpgradeLegacyXdns(t *testing.T) {
|
|
|
if string(got) != tc.want {
|
|
if string(got) != tc.want {
|
|
|
t.Fatalf("upgraded settings\n got: %s\nwant: %s", got, tc.want)
|
|
t.Fatalf("upgraded settings\n got: %s\nwant: %s", got, tc.want)
|
|
|
}
|
|
}
|
|
|
- if err := buildXdnsSettings(t, mask["settings"]); err != nil {
|
|
|
|
|
|
|
+ domains, resolvers, err = coreXdnsView(t, mask["settings"])
|
|
|
|
|
+ if err != nil {
|
|
|
t.Fatalf("the core refuses the upgraded settings: %v", err)
|
|
t.Fatalf("the core refuses the upgraded settings: %v", err)
|
|
|
}
|
|
}
|
|
|
|
|
+ if !slices.Equal(domains, tc.wantDomains) || !slices.Equal(resolvers, tc.wantResolvers) {
|
|
|
|
|
+ t.Fatalf("the core serves domains %v resolvers %v, want %v %v", domains, resolvers, tc.wantDomains, tc.wantResolvers)
|
|
|
|
|
+ }
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func TestUpgradeLegacyXdnsLeavesCurrentShapeAlone(t *testing.T) {
|
|
func TestUpgradeLegacyXdnsLeavesCurrentShapeAlone(t *testing.T) {
|
|
|
- const current = `{"udp":[{"type":"xdns","settings":{"domains":[{"name":"t.example.com","types":[16,28],"edns0":1232}],"resolvers":[{"type":"tcp","settings":{"addr":"8.8.8.8:53"}}],"extraPoll":2}},{"type":"salamander","settings":{"password":"x"}}]}`
|
|
|
|
|
|
|
+ const current = `{"udp":[{"type":"xdns","settings":{"domains":[{"names":["t.example.com","u.example.com"],"types":[16,28],"edns0":1232}],"resolvers":[{"addrs":["tcp://8.8.8.8:53","1.1.1.1"]}],"extraPoll":2}},{"type":"salamander","settings":{"password":"x"}}]}`
|
|
|
var finalmask map[string]any
|
|
var finalmask map[string]any
|
|
|
if err := json.Unmarshal([]byte(current), &finalmask); err != nil {
|
|
if err := json.Unmarshal([]byte(current), &finalmask); err != nil {
|
|
|
t.Fatalf("unmarshal finalmask: %v", err)
|
|
t.Fatalf("unmarshal finalmask: %v", err)
|
|
|
}
|
|
}
|
|
|
if UpgradeLegacyXdns(finalmask) {
|
|
if UpgradeLegacyXdns(finalmask) {
|
|
|
- t.Fatal("UpgradeLegacyXdns rewrote a mask that is already in the object shape")
|
|
|
|
|
|
|
+ t.Fatal("UpgradeLegacyXdns rewrote a mask that is already in the names/addrs shape")
|
|
|
}
|
|
}
|
|
|
var want map[string]any
|
|
var want map[string]any
|
|
|
_ = json.Unmarshal([]byte(current), &want)
|
|
_ = json.Unmarshal([]byte(current), &want)
|