mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-10-12 18:45:49 +00:00
infra/conf: reject conflicting routing and DNS options when script is configured
This commit is contained in:
@@ -272,6 +272,17 @@ func (m *HostsWrapper) Build() ([]*dns.Config_HostMapping, error) {
|
||||
|
||||
// Build implements Buildable
|
||||
func (c *DNSConfig) Build() (*dns.Config, error) {
|
||||
if c.Script != "" {
|
||||
if c.DisableFallback || c.DisableFallbackIfMatch || c.EnableParallelQuery {
|
||||
return nil, errors.New("DNS script cannot be used with disableFallback, disableFallbackIfMatch or enableParallelQuery")
|
||||
}
|
||||
for i, server := range c.Servers {
|
||||
if len(server.Domains) > 0 || server.SkipFallback || server.FinalQuery {
|
||||
return nil, errors.New("DNS script cannot be used with domains, skipFallback or finalQuery in server ", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
config := &dns.Config{
|
||||
Tag: c.Tag,
|
||||
DisableCache: c.DisableCache,
|
||||
|
||||
+41
-2
@@ -2,6 +2,7 @@ package conf_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
@@ -28,7 +29,6 @@ func TestDNSConfigParsing(t *testing.T) {
|
||||
testCases := []TestCase{
|
||||
{
|
||||
Input: `{
|
||||
"script": "base64:%",
|
||||
"servers": [{
|
||||
"address": "8.8.8.8",
|
||||
"port": 5353,
|
||||
@@ -53,7 +53,6 @@ func TestDNSConfigParsing(t *testing.T) {
|
||||
}`,
|
||||
Parser: parserCreator(),
|
||||
Output: &dns.Config{
|
||||
Script: "base64:%",
|
||||
NameServer: []*dns.NameServer{
|
||||
{
|
||||
Address: &net.Endpoint{
|
||||
@@ -138,3 +137,43 @@ func TestDNSNameServerID(t *testing.T) {
|
||||
t.Fatalf("nameserver IDs = %v, want primary", built.NameServer)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDNSScriptConfig(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
input string
|
||||
wantError string
|
||||
}{
|
||||
{name: "script only", input: `{"script":"base64:%"}`},
|
||||
{name: "compatible fields", input: `{"script":"base64:%","servers":["1.1.1.1",{"id":"primary","address":"8.8.8.8","expectedIPs":["8.8.8.8"],"queryStrategy":"UseIPv4","disableCache":true}],"hosts":{"example.com":"127.0.0.1"},"disableCache":true}`},
|
||||
{name: "disabled options", input: `{"script":"base64:%","disableFallback":false,"disableFallbackIfMatch":false,"enableParallelQuery":false,"servers":[{"address":"1.1.1.1","domains":[],"skipFallback":false,"finalQuery":false}]}`},
|
||||
{name: "domains", input: `{"script":"base64:%","servers":[{"address":"1.1.1.1","domains":["domain:example.com"]}]}`, wantError: "domains"},
|
||||
{name: "skip fallback", input: `{"script":"base64:%","servers":[{"address":"1.1.1.1","skipFallback":true}]}`, wantError: "skipFallback"},
|
||||
{name: "final query", input: `{"script":"base64:%","servers":[{"address":"1.1.1.1","finalQuery":true}]}`, wantError: "finalQuery"},
|
||||
{name: "later server", input: `{"script":"base64:%","servers":["1.1.1.1",{"address":"8.8.8.8","finalQuery":true}]}`, wantError: "server 1"},
|
||||
{name: "disable fallback", input: `{"script":"base64:%","disableFallback":true}`, wantError: "disableFallback"},
|
||||
{name: "disable fallback if match", input: `{"script":"base64:%","disableFallbackIfMatch":true}`, wantError: "disableFallbackIfMatch"},
|
||||
{name: "parallel query", input: `{"script":"base64:%","enableParallelQuery":true}`, wantError: "enableParallelQuery"},
|
||||
{name: "empty script", input: `{"script":"","disableFallback":true,"disableFallbackIfMatch":true,"enableParallelQuery":true,"servers":[{"address":"1.1.1.1","domains":["example.com"],"skipFallback":true,"finalQuery":true}]}`},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
var config DNSConfig
|
||||
if err := json.Unmarshal([]byte(test.input), &config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
built, err := config.Build()
|
||||
if test.wantError != "" {
|
||||
if built != nil || err == nil || !strings.Contains(err.Error(), "DNS script cannot be used with ") || !strings.Contains(err.Error(), test.wantError) {
|
||||
t.Fatalf("Build() = %v, %v; want nil config and script conflict error mentioning %s", built, err, test.wantError)
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if built.Script != config.Script || len(built.NameServer) != len(config.Servers) {
|
||||
t.Fatalf("Build() did not preserve script or servers: %v", built)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,6 +94,9 @@ func (c *RouterConfig) getDomainStrategy() router.Config_DomainStrategy {
|
||||
func (c *RouterConfig) Build() (*router.Config, error) {
|
||||
config := new(router.Config)
|
||||
|
||||
if c.Script != "" && (c.DomainStrategy != nil || len(c.RuleList) > 0) {
|
||||
return nil, errors.New("routing script cannot be used with domainStrategy or rules")
|
||||
}
|
||||
config.Script = c.Script
|
||||
|
||||
config.DomainStrategy = c.getDomainStrategy()
|
||||
|
||||
@@ -2,6 +2,7 @@ package conf_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
_ "unsafe"
|
||||
@@ -29,7 +30,6 @@ func TestRouterConfig(t *testing.T) {
|
||||
runMultiTestCase(t, []TestCase{
|
||||
{
|
||||
Input: `{
|
||||
"script": "missing.lua",
|
||||
"domainStrategy": "AsIs",
|
||||
"rules": [
|
||||
{
|
||||
@@ -91,7 +91,6 @@ func TestRouterConfig(t *testing.T) {
|
||||
}`,
|
||||
Parser: createParser(),
|
||||
Output: &router.Config{
|
||||
Script: "missing.lua",
|
||||
DomainStrategy: router.Config_AsIs,
|
||||
BalancingRule: []*router.BalancingRule{
|
||||
{
|
||||
@@ -238,3 +237,40 @@ func TestRouterConfig(t *testing.T) {
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestRouterScriptConfig(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
input string
|
||||
wantError bool
|
||||
}{
|
||||
{name: "script only", input: `{"script":"missing.lua"}`},
|
||||
{name: "empty rules", input: `{"script":"missing.lua","rules":[]}`},
|
||||
{name: "balancers", input: `{"script":"missing.lua","balancers":[{"tag":"b1","selector":["direct"]}]}`},
|
||||
{name: "default domain strategy", input: `{"script":"missing.lua","domainStrategy":"AsIs"}`, wantError: true},
|
||||
{name: "IP domain strategy", input: `{"script":"missing.lua","domainStrategy":"IPIfNonMatch"}`, wantError: true},
|
||||
{name: "empty domain strategy", input: `{"script":"missing.lua","domainStrategy":""}`, wantError: true},
|
||||
{name: "rules", input: `{"script":"missing.lua","rules":[{"outboundTag":"direct","domain":["example.com"]}]}`, wantError: true},
|
||||
{name: "empty script", input: `{"script":"","domainStrategy":"IPOnDemand","rules":[{"outboundTag":"direct","domain":["example.com"]}]}`},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
var config RouterConfig
|
||||
if err := json.Unmarshal([]byte(test.input), &config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
built, err := config.Build()
|
||||
if test.wantError {
|
||||
if built != nil || err == nil || !strings.Contains(err.Error(), "routing script cannot be used with domainStrategy or rules") {
|
||||
t.Fatalf("Build() = %v, %v; want nil config and script conflict error", built, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if built.Script != config.Script || len(built.Rule) != len(config.RuleList) || len(built.BalancingRule) != len(config.Balancers) {
|
||||
t.Fatalf("Build() did not preserve script, rules or balancers: %v", built)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user