udphop.go 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. package maskcompat
  2. import (
  3. "maps"
  4. "slices"
  5. "strings"
  6. )
  7. // UpgradeLegacyUDPHop moves the quicParams.udpHop xray-core 26.9.9 ignores into an intervalRemote
  8. // "udphop" mask, rewriting only finalmask's own keys: a merged finalmask shares quicParams and udp.
  9. func UpgradeLegacyUDPHop(finalmask any) bool {
  10. fm, _ := finalmask.(map[string]any)
  11. quicParams, _ := fm["quicParams"].(map[string]any)
  12. legacy, found := quicParams["udpHop"]
  13. if !found {
  14. return false
  15. }
  16. restQuic := maps.Clone(quicParams)
  17. delete(restQuic, "udpHop")
  18. if len(restQuic) == 0 {
  19. delete(fm, "quicParams")
  20. } else {
  21. fm["quicParams"] = restQuic
  22. }
  23. hop, _ := legacy.(map[string]any)
  24. ports := hop["ports"]
  25. if isEmptyHopValue(ports) || hasUDPHopMask(fm) {
  26. return true
  27. }
  28. settings := map[string]any{"mode": "intervalRemote", "remotePorts": ports}
  29. if interval := hop["interval"]; !isEmptyHopValue(interval) {
  30. settings["interval"] = interval
  31. }
  32. masks, _ := fm["udp"].([]any)
  33. fm["udp"] = append(slices.Clip(masks), map[string]any{"type": "udphop", "settings": settings})
  34. return true
  35. }
  36. func hasUDPHopMask(fm map[string]any) bool {
  37. masks, _ := fm["udp"].([]any)
  38. for _, entry := range masks {
  39. mask, _ := entry.(map[string]any)
  40. if maskType, _ := mask["type"].(string); strings.EqualFold(maskType, "udphop") {
  41. return true
  42. }
  43. }
  44. return false
  45. }
  46. func isEmptyHopValue(value any) bool {
  47. switch v := value.(type) {
  48. case nil:
  49. return true
  50. case string:
  51. return strings.TrimSpace(v) == ""
  52. case float64:
  53. return v == 0
  54. }
  55. return false
  56. }