router_test.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. package conf_test
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "os"
  6. "path/filepath"
  7. "testing"
  8. "time"
  9. _ "unsafe"
  10. "github.com/xtls/xray-core/app/router"
  11. "github.com/xtls/xray-core/common"
  12. "github.com/xtls/xray-core/common/net"
  13. "github.com/xtls/xray-core/common/platform"
  14. "github.com/xtls/xray-core/common/platform/filesystem"
  15. "github.com/xtls/xray-core/common/serial"
  16. . "github.com/xtls/xray-core/infra/conf"
  17. "google.golang.org/protobuf/proto"
  18. )
  19. func getAssetPath(file string) (string, error) {
  20. path := platform.GetAssetLocation(file)
  21. _, err := os.Stat(path)
  22. if os.IsNotExist(err) {
  23. path := filepath.Join("..", "..", "resources", file)
  24. _, err := os.Stat(path)
  25. if os.IsNotExist(err) {
  26. return "", fmt.Errorf("can't find %s in standard asset locations or {project_root}/resources", file)
  27. }
  28. if err != nil {
  29. return "", fmt.Errorf("can't stat %s: %v", path, err)
  30. }
  31. return path, nil
  32. }
  33. if err != nil {
  34. return "", fmt.Errorf("can't stat %s: %v", path, err)
  35. }
  36. return path, nil
  37. }
  38. func TestToCidrList(t *testing.T) {
  39. tempDir, err := os.MkdirTemp("", "test-")
  40. if err != nil {
  41. t.Fatalf("can't create temp dir: %v", err)
  42. }
  43. defer os.RemoveAll(tempDir)
  44. geoipPath, err := getAssetPath("geoip.dat")
  45. if err != nil {
  46. t.Fatal(err)
  47. }
  48. common.Must(filesystem.CopyFile(filepath.Join(tempDir, "geoip.dat"), geoipPath))
  49. common.Must(filesystem.CopyFile(filepath.Join(tempDir, "geoiptestrouter.dat"), geoipPath))
  50. os.Setenv("xray.location.asset", tempDir)
  51. defer os.Unsetenv("xray.location.asset")
  52. ips := StringList([]string{
  53. "geoip:us",
  54. "geoip:cn",
  55. "geoip:!cn",
  56. "ext:geoiptestrouter.dat:!cn",
  57. "ext:geoiptestrouter.dat:ca",
  58. "ext-ip:geoiptestrouter.dat:!cn",
  59. "ext-ip:geoiptestrouter.dat:!ca",
  60. })
  61. _, err = ToCidrList(ips)
  62. if err != nil {
  63. t.Fatalf("Failed to parse geoip list, got %s", err)
  64. }
  65. }
  66. func TestRouterConfig(t *testing.T) {
  67. createParser := func() func(string) (proto.Message, error) {
  68. return func(s string) (proto.Message, error) {
  69. config := new(RouterConfig)
  70. if err := json.Unmarshal([]byte(s), config); err != nil {
  71. return nil, err
  72. }
  73. return config.Build()
  74. }
  75. }
  76. runMultiTestCase(t, []TestCase{
  77. {
  78. Input: `{
  79. "domainStrategy": "AsIs",
  80. "rules": [
  81. {
  82. "type": "field",
  83. "domain": [
  84. "baidu.com",
  85. "qq.com"
  86. ],
  87. "outboundTag": "direct"
  88. },
  89. {
  90. "type": "field",
  91. "ip": [
  92. "10.0.0.0/8",
  93. "::1/128"
  94. ],
  95. "outboundTag": "test"
  96. },{
  97. "type": "field",
  98. "port": "53, 443, 1000-2000",
  99. "outboundTag": "test"
  100. },{
  101. "type": "field",
  102. "port": 123,
  103. "outboundTag": "test"
  104. }
  105. ],
  106. "balancers": [
  107. {
  108. "tag": "b1",
  109. "selector": ["test"],
  110. "fallbackTag": "fall"
  111. },
  112. {
  113. "tag": "b2",
  114. "selector": ["test"],
  115. "strategy": {
  116. "type": "leastload",
  117. "settings": {
  118. "healthCheck": {
  119. "interval": "5m0s",
  120. "sampling": 2,
  121. "timeout": "5s",
  122. "destination": "dest",
  123. "connectivity": "conn"
  124. },
  125. "costs": [
  126. {
  127. "regexp": true,
  128. "match": "\\d+(\\.\\d+)",
  129. "value": 5
  130. }
  131. ],
  132. "baselines": ["400ms", "600ms"],
  133. "expected": 6,
  134. "maxRTT": "1000ms",
  135. "tolerance": 0.5
  136. }
  137. },
  138. "fallbackTag": "fall"
  139. }
  140. ]
  141. }`,
  142. Parser: createParser(),
  143. Output: &router.Config{
  144. DomainStrategy: router.Config_AsIs,
  145. BalancingRule: []*router.BalancingRule{
  146. {
  147. Tag: "b1",
  148. OutboundSelector: []string{"test"},
  149. Strategy: "random",
  150. FallbackTag: "fall",
  151. },
  152. {
  153. Tag: "b2",
  154. OutboundSelector: []string{"test"},
  155. Strategy: "leastload",
  156. StrategySettings: serial.ToTypedMessage(&router.StrategyLeastLoadConfig{
  157. Costs: []*router.StrategyWeight{
  158. {
  159. Regexp: true,
  160. Match: "\\d+(\\.\\d+)",
  161. Value: 5,
  162. },
  163. },
  164. Baselines: []int64{
  165. int64(time.Duration(400) * time.Millisecond),
  166. int64(time.Duration(600) * time.Millisecond),
  167. },
  168. Expected: 6,
  169. MaxRTT: int64(time.Duration(1000) * time.Millisecond),
  170. Tolerance: 0.5,
  171. }),
  172. FallbackTag: "fall",
  173. },
  174. },
  175. Rule: []*router.RoutingRule{
  176. {
  177. Domain: []*router.Domain{
  178. {
  179. Type: router.Domain_Plain,
  180. Value: "baidu.com",
  181. },
  182. {
  183. Type: router.Domain_Plain,
  184. Value: "qq.com",
  185. },
  186. },
  187. TargetTag: &router.RoutingRule_Tag{
  188. Tag: "direct",
  189. },
  190. },
  191. {
  192. Geoip: []*router.GeoIP{
  193. {
  194. Cidr: []*router.CIDR{
  195. {
  196. Ip: []byte{10, 0, 0, 0},
  197. Prefix: 8,
  198. },
  199. {
  200. Ip: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  201. Prefix: 128,
  202. },
  203. },
  204. },
  205. },
  206. TargetTag: &router.RoutingRule_Tag{
  207. Tag: "test",
  208. },
  209. },
  210. {
  211. PortList: &net.PortList{
  212. Range: []*net.PortRange{
  213. {From: 53, To: 53},
  214. {From: 443, To: 443},
  215. {From: 1000, To: 2000},
  216. },
  217. },
  218. TargetTag: &router.RoutingRule_Tag{
  219. Tag: "test",
  220. },
  221. },
  222. {
  223. PortList: &net.PortList{
  224. Range: []*net.PortRange{
  225. {From: 123, To: 123},
  226. },
  227. },
  228. TargetTag: &router.RoutingRule_Tag{
  229. Tag: "test",
  230. },
  231. },
  232. },
  233. },
  234. },
  235. {
  236. Input: `{
  237. "domainStrategy": "IPIfNonMatch",
  238. "rules": [
  239. {
  240. "type": "field",
  241. "domain": [
  242. "baidu.com",
  243. "qq.com"
  244. ],
  245. "outboundTag": "direct"
  246. },
  247. {
  248. "type": "field",
  249. "ip": [
  250. "10.0.0.0/8",
  251. "::1/128"
  252. ],
  253. "outboundTag": "test"
  254. }
  255. ]
  256. }`,
  257. Parser: createParser(),
  258. Output: &router.Config{
  259. DomainStrategy: router.Config_IpIfNonMatch,
  260. Rule: []*router.RoutingRule{
  261. {
  262. Domain: []*router.Domain{
  263. {
  264. Type: router.Domain_Plain,
  265. Value: "baidu.com",
  266. },
  267. {
  268. Type: router.Domain_Plain,
  269. Value: "qq.com",
  270. },
  271. },
  272. TargetTag: &router.RoutingRule_Tag{
  273. Tag: "direct",
  274. },
  275. },
  276. {
  277. Geoip: []*router.GeoIP{
  278. {
  279. Cidr: []*router.CIDR{
  280. {
  281. Ip: []byte{10, 0, 0, 0},
  282. Prefix: 8,
  283. },
  284. {
  285. Ip: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  286. Prefix: 128,
  287. },
  288. },
  289. },
  290. },
  291. TargetTag: &router.RoutingRule_Tag{
  292. Tag: "test",
  293. },
  294. },
  295. },
  296. },
  297. },
  298. })
  299. }