xdns_finalmask_migration_test.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. package database
  2. import (
  3. "encoding/json"
  4. "testing"
  5. "github.com/mhsanaei/3x-ui/v3/internal/database/model"
  6. )
  7. // legacyXdnsFinalmask is the 26.9.30 object shape the previous seeder left in panel DBs;
  8. // xray-core 26.10.10 reads neither its "name" nor its typed resolver.
  9. const legacyXdnsFinalmask = `{"udp":[{"type":"xdns","settings":{"domains":[{"name":"t.example.com","types":[16],"edns0":1232}],"resolvers":[{"type":"udp","settings":{"addr":"8.8.8.8:53"}}]}}]}`
  10. // assertXdnsUpgraded fails unless the finalmask's xdns mask uses the names/addrs lists,
  11. // the only shape xray-core 26.10.10 reads.
  12. func assertXdnsUpgraded(t *testing.T, where string, finalmask any) {
  13. t.Helper()
  14. fm, _ := finalmask.(map[string]any)
  15. udp, _ := fm["udp"].([]any)
  16. if len(udp) != 1 {
  17. t.Fatalf("%s: udp masks = %v, want one", where, fm["udp"])
  18. }
  19. mask, _ := udp[0].(map[string]any)
  20. settings, _ := mask["settings"].(map[string]any)
  21. got, err := json.Marshal(settings)
  22. if err != nil {
  23. t.Fatalf("%s: marshal xdns settings: %v", where, err)
  24. }
  25. const want = `{"domains":[{"edns0":1232,"names":["t.example.com"],"types":[16]}],"resolvers":[{"addrs":["udp://8.8.8.8:53"]}]}`
  26. if string(got) != want {
  27. t.Fatalf("%s: xdns settings\n got: %s\nwant: %s", where, got, want)
  28. }
  29. }
  30. func TestXdnsFinalmaskSeederUpgradesEveryStoredMask(t *testing.T) {
  31. initMigrateDB(t)
  32. ib := seedInboundWithStream(t, "xdns-in", 5353,
  33. `{"network":"kcp","security":"none","finalmask":`+legacyXdnsFinalmask+`}`)
  34. host := &model.Host{InboundId: ib.Id, Remark: "h", Address: "cdn.example.com", Port: 53, FinalMask: legacyXdnsFinalmask}
  35. if err := GetDB().Create(host).Error; err != nil {
  36. t.Fatalf("create host: %v", err)
  37. }
  38. seedTemplate(t, `{"outbounds":[{"protocol":"vless","tag":"dns-tunnel","settings":{},"streamSettings":{"network":"kcp","finalmask":`+legacyXdnsFinalmask+`}}]}`)
  39. if err := GetDB().Create(&model.Setting{Key: "subJsonFinalMask", Value: legacyXdnsFinalmask}).Error; err != nil {
  40. t.Fatalf("seed subJsonFinalMask: %v", err)
  41. }
  42. sub := &model.OutboundSubscription{
  43. Remark: "donor", Url: "https://donor.example.com/sub",
  44. LastFetchedOutbounds: `[{"protocol":"vless","tag":"sub-1","settings":{},"streamSettings":{"network":"kcp","finalmask":` + legacyXdnsFinalmask + `}}]`,
  45. }
  46. if err := GetDB().Create(sub).Error; err != nil {
  47. t.Fatalf("create outbound subscription: %v", err)
  48. }
  49. if err := GetDB().Where("seeder_name = ?", "XdnsFinalmaskNamesAddrsFix").
  50. Delete(&model.HistoryOfSeeders{}).Error; err != nil {
  51. t.Fatalf("clear seeder history: %v", err)
  52. }
  53. if err := runSeeders(false); err != nil {
  54. t.Fatalf("runSeeders: %v", err)
  55. }
  56. var stored model.Inbound
  57. if err := GetDB().First(&stored, ib.Id).Error; err != nil {
  58. t.Fatalf("reload inbound: %v", err)
  59. }
  60. var stream map[string]any
  61. if err := json.Unmarshal([]byte(stored.StreamSettings), &stream); err != nil {
  62. t.Fatalf("inbound stream is not JSON: %v", err)
  63. }
  64. assertXdnsUpgraded(t, "inbound stream", stream["finalmask"])
  65. var storedHost model.Host
  66. if err := GetDB().First(&storedHost, host.Id).Error; err != nil {
  67. t.Fatalf("reload host: %v", err)
  68. }
  69. var hostMask any
  70. if err := json.Unmarshal([]byte(storedHost.FinalMask), &hostMask); err != nil {
  71. t.Fatalf("host finalMask is not JSON: %v", err)
  72. }
  73. assertXdnsUpgraded(t, "host finalMask", hostMask)
  74. var template struct {
  75. Outbounds []struct {
  76. StreamSettings struct {
  77. Finalmask any `json:"finalmask"`
  78. } `json:"streamSettings"`
  79. } `json:"outbounds"`
  80. }
  81. if err := json.Unmarshal([]byte(storedTemplate(t)), &template); err != nil || len(template.Outbounds) != 1 {
  82. t.Fatalf("stored template unreadable (%v)", err)
  83. }
  84. assertXdnsUpgraded(t, "template outbound", template.Outbounds[0].StreamSettings.Finalmask)
  85. var subMask model.Setting
  86. if err := GetDB().Where("key = ?", "subJsonFinalMask").First(&subMask).Error; err != nil {
  87. t.Fatalf("reload subJsonFinalMask: %v", err)
  88. }
  89. var subFinalmask any
  90. if err := json.Unmarshal([]byte(subMask.Value), &subFinalmask); err != nil {
  91. t.Fatalf("subJsonFinalMask is not JSON: %v", err)
  92. }
  93. assertXdnsUpgraded(t, "subJsonFinalMask", subFinalmask)
  94. var storedSub model.OutboundSubscription
  95. if err := GetDB().First(&storedSub, sub.Id).Error; err != nil {
  96. t.Fatalf("reload outbound subscription: %v", err)
  97. }
  98. var cached []struct {
  99. StreamSettings struct {
  100. Finalmask any `json:"finalmask"`
  101. } `json:"streamSettings"`
  102. }
  103. if err := json.Unmarshal([]byte(storedSub.LastFetchedOutbounds), &cached); err != nil || len(cached) != 1 {
  104. t.Fatalf("cached subscription outbounds unreadable (%v)", err)
  105. }
  106. assertXdnsUpgraded(t, "cached subscription outbound", cached[0].StreamSettings.Finalmask)
  107. }