mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-05-12 15:18:41 +00:00
Merge branch 'dns' into features-looutbound
This commit is contained in:
commit
ab3b0f843d
71 changed files with 2447 additions and 1156 deletions
|
@ -11,10 +11,12 @@ import (
|
|||
)
|
||||
|
||||
type NameServerConfig struct {
|
||||
Address *Address
|
||||
Port uint16
|
||||
Domains []string
|
||||
ExpectIPs StringList
|
||||
Address *Address
|
||||
ClientIP *Address
|
||||
Port uint16
|
||||
SkipFallback bool
|
||||
Domains []string
|
||||
ExpectIPs StringList
|
||||
}
|
||||
|
||||
func (c *NameServerConfig) UnmarshalJSON(data []byte) error {
|
||||
|
@ -25,14 +27,18 @@ func (c *NameServerConfig) UnmarshalJSON(data []byte) error {
|
|||
}
|
||||
|
||||
var advanced struct {
|
||||
Address *Address `json:"address"`
|
||||
Port uint16 `json:"port"`
|
||||
Domains []string `json:"domains"`
|
||||
ExpectIPs StringList `json:"expectIps"`
|
||||
Address *Address `json:"address"`
|
||||
ClientIP *Address `json:"clientIp"`
|
||||
Port uint16 `json:"port"`
|
||||
SkipFallback bool `json:"skipFallback"`
|
||||
Domains []string `json:"domains"`
|
||||
ExpectIPs StringList `json:"expectIps"`
|
||||
}
|
||||
if err := json.Unmarshal(data, &advanced); err == nil {
|
||||
c.Address = advanced.Address
|
||||
c.ClientIP = advanced.ClientIP
|
||||
c.Port = advanced.Port
|
||||
c.SkipFallback = advanced.SkipFallback
|
||||
c.Domains = advanced.Domains
|
||||
c.ExpectIPs = advanced.ExpectIPs
|
||||
return nil
|
||||
|
@ -87,12 +93,21 @@ func (c *NameServerConfig) Build() (*dns.NameServer, error) {
|
|||
return nil, newError("invalid IP rule: ", c.ExpectIPs).Base(err)
|
||||
}
|
||||
|
||||
var myClientIP []byte
|
||||
if c.ClientIP != nil {
|
||||
if !c.ClientIP.Family().IsIP() {
|
||||
return nil, newError("not an IP address:", c.ClientIP.String())
|
||||
}
|
||||
myClientIP = []byte(c.ClientIP.IP())
|
||||
}
|
||||
return &dns.NameServer{
|
||||
Address: &net.Endpoint{
|
||||
Network: net.Network_UDP,
|
||||
Address: c.Address.Build(),
|
||||
Port: uint32(c.Port),
|
||||
},
|
||||
ClientIp: myClientIP,
|
||||
SkipFallback: c.SkipFallback,
|
||||
PrioritizedDomain: domains,
|
||||
Geoip: geoipList,
|
||||
OriginalRules: originalRules,
|
||||
|
@ -108,28 +123,72 @@ var typeMap = map[router.Domain_Type]dns.DomainMatchingType{
|
|||
|
||||
// DNSConfig is a JSON serializable object for dns.Config.
|
||||
type DNSConfig struct {
|
||||
Servers []*NameServerConfig `json:"servers"`
|
||||
Hosts map[string]*Address `json:"hosts"`
|
||||
ClientIP *Address `json:"clientIp"`
|
||||
Tag string `json:"tag"`
|
||||
Servers []*NameServerConfig `json:"servers"`
|
||||
Hosts map[string]*HostAddress `json:"hosts"`
|
||||
ClientIP *Address `json:"clientIp"`
|
||||
Tag string `json:"tag"`
|
||||
QueryStrategy string `json:"queryStrategy"`
|
||||
CacheStrategy string `json:"cacheStrategy"`
|
||||
DisableCache bool `json:"disableCache"`
|
||||
DisableFallback bool `json:"disableFallback"`
|
||||
}
|
||||
|
||||
func getHostMapping(addr *Address) *dns.Config_HostMapping {
|
||||
if addr.Family().IsIP() {
|
||||
return &dns.Config_HostMapping{
|
||||
Ip: [][]byte{[]byte(addr.IP())},
|
||||
type HostAddress struct {
|
||||
addr *Address
|
||||
addrs []*Address
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
|
||||
func (h *HostAddress) UnmarshalJSON(data []byte) error {
|
||||
addr := new(Address)
|
||||
var addrs []*Address
|
||||
switch {
|
||||
case json.Unmarshal(data, &addr) == nil:
|
||||
h.addr = addr
|
||||
case json.Unmarshal(data, &addrs) == nil:
|
||||
h.addrs = addrs
|
||||
default:
|
||||
return newError("invalid address")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getHostMapping(ha *HostAddress) *dns.Config_HostMapping {
|
||||
if ha.addr != nil {
|
||||
if ha.addr.Family().IsDomain() {
|
||||
return &dns.Config_HostMapping{
|
||||
ProxiedDomain: ha.addr.Domain(),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return &dns.Config_HostMapping{
|
||||
ProxiedDomain: addr.Domain(),
|
||||
Ip: [][]byte{ha.addr.IP()},
|
||||
}
|
||||
}
|
||||
|
||||
ips := make([][]byte, 0, len(ha.addrs))
|
||||
for _, addr := range ha.addrs {
|
||||
if addr.Family().IsDomain() {
|
||||
return &dns.Config_HostMapping{
|
||||
ProxiedDomain: addr.Domain(),
|
||||
}
|
||||
}
|
||||
ips = append(ips, []byte(addr.IP()))
|
||||
}
|
||||
return &dns.Config_HostMapping{
|
||||
Ip: ips,
|
||||
}
|
||||
}
|
||||
|
||||
// Build implements Buildable
|
||||
func (c *DNSConfig) Build() (*dns.Config, error) {
|
||||
config := &dns.Config{
|
||||
Tag: c.Tag,
|
||||
Tag: c.Tag,
|
||||
CacheStrategy: dns.CacheStrategy_Cache_ALL,
|
||||
DisableFallback: c.DisableFallback,
|
||||
}
|
||||
|
||||
if c.DisableCache {
|
||||
config.CacheStrategy = dns.CacheStrategy_Cache_DISABLE
|
||||
}
|
||||
|
||||
if c.ClientIP != nil {
|
||||
|
@ -139,6 +198,25 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
|
|||
config.ClientIp = []byte(c.ClientIP.IP())
|
||||
}
|
||||
|
||||
config.QueryStrategy = dns.QueryStrategy_USE_IP
|
||||
switch strings.ToLower(c.QueryStrategy) {
|
||||
case "useip", "use_ip", "use-ip":
|
||||
config.QueryStrategy = dns.QueryStrategy_USE_IP
|
||||
case "useip4", "useipv4", "use_ip4", "use_ipv4", "use_ip_v4", "use-ip4", "use-ipv4", "use-ip-v4":
|
||||
config.QueryStrategy = dns.QueryStrategy_USE_IP4
|
||||
case "useip6", "useipv6", "use_ip6", "use_ipv6", "use_ip_v6", "use-ip6", "use-ipv6", "use-ip-v6":
|
||||
config.QueryStrategy = dns.QueryStrategy_USE_IP6
|
||||
}
|
||||
|
||||
switch strings.ToLower(c.CacheStrategy) {
|
||||
case "noerror":
|
||||
config.CacheStrategy = dns.CacheStrategy_Cache_NOERROR
|
||||
case "all":
|
||||
config.CacheStrategy = dns.CacheStrategy_Cache_ALL
|
||||
case "disable", "none":
|
||||
config.CacheStrategy = dns.CacheStrategy_Cache_DISABLE
|
||||
}
|
||||
|
||||
for _, server := range c.Servers {
|
||||
ns, err := server.Build()
|
||||
if err != nil {
|
||||
|
|
|
@ -67,17 +67,23 @@ func TestDNSConfigParsing(t *testing.T) {
|
|||
Input: `{
|
||||
"servers": [{
|
||||
"address": "8.8.8.8",
|
||||
"clientIp": "10.0.0.1",
|
||||
"port": 5353,
|
||||
"skipFallback": true,
|
||||
"domains": ["domain:example.com"]
|
||||
}],
|
||||
"hosts": {
|
||||
"example.com": "127.0.0.1",
|
||||
"xtls.github.io": ["1.2.3.4", "5.6.7.8"],
|
||||
"domain:example.com": "google.com",
|
||||
"geosite:test": "10.0.0.1",
|
||||
"keyword:google": "8.8.8.8",
|
||||
"geosite:test": ["127.0.0.1", "127.0.0.2"],
|
||||
"keyword:google": ["8.8.8.8", "8.8.4.4"],
|
||||
"regexp:.*\\.com": "8.8.4.4"
|
||||
},
|
||||
"clientIp": "10.0.0.1"
|
||||
"clientIp": "10.0.0.1",
|
||||
"queryStrategy": "UseIPv4",
|
||||
"cacheStrategy": "disable",
|
||||
"disableFallback": true
|
||||
}`,
|
||||
Parser: parserCreator(),
|
||||
Output: &dns.Config{
|
||||
|
@ -92,6 +98,8 @@ func TestDNSConfigParsing(t *testing.T) {
|
|||
Network: net.Network_UDP,
|
||||
Port: 5353,
|
||||
},
|
||||
ClientIp: []byte{10, 0, 0, 1},
|
||||
SkipFallback: true,
|
||||
PrioritizedDomain: []*dns.NameServer_PriorityDomain{
|
||||
{
|
||||
Type: dns.DomainMatchingType_Subdomain,
|
||||
|
@ -120,20 +128,28 @@ func TestDNSConfigParsing(t *testing.T) {
|
|||
{
|
||||
Type: dns.DomainMatchingType_Full,
|
||||
Domain: "example.com",
|
||||
Ip: [][]byte{{10, 0, 0, 1}},
|
||||
Ip: [][]byte{{127, 0, 0, 1}, {127, 0, 0, 2}},
|
||||
},
|
||||
{
|
||||
Type: dns.DomainMatchingType_Keyword,
|
||||
Domain: "google",
|
||||
Ip: [][]byte{{8, 8, 8, 8}},
|
||||
Ip: [][]byte{{8, 8, 8, 8}, {8, 8, 4, 4}},
|
||||
},
|
||||
{
|
||||
Type: dns.DomainMatchingType_Regex,
|
||||
Domain: ".*\\.com",
|
||||
Ip: [][]byte{{8, 8, 4, 4}},
|
||||
},
|
||||
{
|
||||
Type: dns.DomainMatchingType_Full,
|
||||
Domain: "xtls.github.io",
|
||||
Ip: [][]byte{{1, 2, 3, 4}, {5, 6, 7, 8}},
|
||||
},
|
||||
},
|
||||
ClientIp: []byte{10, 0, 0, 1},
|
||||
ClientIp: []byte{10, 0, 0, 1},
|
||||
QueryStrategy: dns.QueryStrategy_USE_IP4,
|
||||
CacheStrategy: dns.CacheStrategy_Cache_DISABLE,
|
||||
DisableFallback: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
@ -22,11 +22,11 @@ func (c *FreedomConfig) Build() (proto.Message, error) {
|
|||
config := new(freedom.Config)
|
||||
config.DomainStrategy = freedom.Config_AS_IS
|
||||
switch strings.ToLower(c.DomainStrategy) {
|
||||
case "useip", "use_ip":
|
||||
case "useip", "use_ip", "use-ip":
|
||||
config.DomainStrategy = freedom.Config_USE_IP
|
||||
case "useip4", "useipv4", "use_ipv4", "use_ip_v4", "use_ip4":
|
||||
case "useip4", "useipv4", "use_ip4", "use_ipv4", "use_ip_v4", "use-ip4", "use-ipv4", "use-ip-v4":
|
||||
config.DomainStrategy = freedom.Config_USE_IP4
|
||||
case "useip6", "useipv6", "use_ipv6", "use_ip_v6", "use_ip6":
|
||||
case "useip6", "useipv6", "use_ip6", "use_ipv6", "use_ip_v6", "use-ip6", "use-ipv6", "use-ip-v6":
|
||||
config.DomainStrategy = freedom.Config_USE_IP6
|
||||
}
|
||||
|
||||
|
|
|
@ -321,6 +321,7 @@ type TLSConfig struct {
|
|||
MaxVersion string `json:"maxVersion"`
|
||||
CipherSuites string `json:"cipherSuites"`
|
||||
PreferServerCipherSuites bool `json:"preferServerCipherSuites"`
|
||||
Fingerprint string `json:"fingerprint"`
|
||||
}
|
||||
|
||||
// Build implements Buildable.
|
||||
|
@ -348,6 +349,7 @@ func (c *TLSConfig) Build() (proto.Message, error) {
|
|||
config.MaxVersion = c.MaxVersion
|
||||
config.CipherSuites = c.CipherSuites
|
||||
config.PreferServerCipherSuites = c.PreferServerCipherSuites
|
||||
config.Fingerprint = strings.ToLower(c.Fingerprint)
|
||||
return config, nil
|
||||
}
|
||||
|
||||
|
@ -476,22 +478,19 @@ type SocketConfig struct {
|
|||
|
||||
// Build implements Buildable.
|
||||
func (c *SocketConfig) Build() (*internet.SocketConfig, error) {
|
||||
tfo := int32(-1)
|
||||
tfo := int32(0) // don't invoke setsockopt() for TFO
|
||||
if c.TFO != nil {
|
||||
switch v := c.TFO.(type) {
|
||||
case bool:
|
||||
if v {
|
||||
tfo = 256
|
||||
} else {
|
||||
tfo = 0
|
||||
tfo = -1 // TFO need to be disabled
|
||||
}
|
||||
case float64:
|
||||
if v < 0 {
|
||||
return nil, newError("tcpFastOpen: only boolean and non-negative integer value is acceptable")
|
||||
}
|
||||
tfo = int32(math.Min(v, math.MaxInt32))
|
||||
default:
|
||||
return nil, newError("tcpFastOpen: only boolean and non-negative integer value is acceptable")
|
||||
return nil, newError("tcpFastOpen: only boolean and integer value is acceptable")
|
||||
}
|
||||
}
|
||||
var tproxy internet.SocketConfig_TProxyMode
|
||||
|
|
|
@ -31,6 +31,13 @@ func TestSocketConfig(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// test "tcpFastOpen": true, queue length 256 is expected. other parameters are tested here too
|
||||
expectedOutput := &internet.SocketConfig{
|
||||
Mark: 1,
|
||||
Tfo: 256,
|
||||
DomainStrategy: internet.DomainStrategy_USE_IP,
|
||||
DialerProxy: "tag",
|
||||
}
|
||||
runMultiTestCase(t, []TestCase{
|
||||
{
|
||||
Input: `{
|
||||
|
@ -40,38 +47,118 @@ func TestSocketConfig(t *testing.T) {
|
|||
"dialerProxy": "tag"
|
||||
}`,
|
||||
Parser: createParser(),
|
||||
Output: &internet.SocketConfig{
|
||||
Mark: 1,
|
||||
Tfo: 256,
|
||||
DomainStrategy: internet.DomainStrategy_USE_IP,
|
||||
DialerProxy: "tag",
|
||||
},
|
||||
Output: expectedOutput,
|
||||
},
|
||||
})
|
||||
if expectedOutput.ParseTFOValue() != 256 {
|
||||
t.Fatalf("unexpected parsed TFO value, which should be 256")
|
||||
}
|
||||
|
||||
// test "tcpFastOpen": false, disabled TFO is expected
|
||||
expectedOutput = &internet.SocketConfig{
|
||||
Mark: 0,
|
||||
Tfo: -1,
|
||||
}
|
||||
runMultiTestCase(t, []TestCase{
|
||||
{
|
||||
Input: `{
|
||||
"tcpFastOpen": false
|
||||
}`,
|
||||
Parser: createParser(),
|
||||
Output: &internet.SocketConfig{
|
||||
Mark: 0,
|
||||
Tfo: 0,
|
||||
},
|
||||
Output: expectedOutput,
|
||||
},
|
||||
})
|
||||
if expectedOutput.ParseTFOValue() != 0 {
|
||||
t.Fatalf("unexpected parsed TFO value, which should be 0")
|
||||
}
|
||||
|
||||
// test "tcpFastOpen": 65535, queue length 65535 is expected
|
||||
expectedOutput = &internet.SocketConfig{
|
||||
Mark: 0,
|
||||
Tfo: 65535,
|
||||
}
|
||||
runMultiTestCase(t, []TestCase{
|
||||
{
|
||||
Input: `{
|
||||
"tcpFastOpen": 65535
|
||||
}`,
|
||||
Parser: createParser(),
|
||||
Output: &internet.SocketConfig{
|
||||
Mark: 0,
|
||||
Tfo: 65535,
|
||||
},
|
||||
Output: expectedOutput,
|
||||
},
|
||||
})
|
||||
if expectedOutput.ParseTFOValue() != 65535 {
|
||||
t.Fatalf("unexpected parsed TFO value, which should be 65535")
|
||||
}
|
||||
|
||||
// test "tcpFastOpen": -65535, disable TFO is expected
|
||||
expectedOutput = &internet.SocketConfig{
|
||||
Mark: 0,
|
||||
Tfo: -65535,
|
||||
}
|
||||
runMultiTestCase(t, []TestCase{
|
||||
{
|
||||
Input: `{
|
||||
"tcpFastOpen": -65535
|
||||
}`,
|
||||
Parser: createParser(),
|
||||
Output: expectedOutput,
|
||||
},
|
||||
})
|
||||
if expectedOutput.ParseTFOValue() != 0 {
|
||||
t.Fatalf("unexpected parsed TFO value, which should be 0")
|
||||
}
|
||||
|
||||
// test "tcpFastOpen": 0, no operation is expected
|
||||
expectedOutput = &internet.SocketConfig{
|
||||
Mark: 0,
|
||||
Tfo: 0,
|
||||
}
|
||||
runMultiTestCase(t, []TestCase{
|
||||
{
|
||||
Input: `{
|
||||
"tcpFastOpen": 0
|
||||
}`,
|
||||
Parser: createParser(),
|
||||
Output: expectedOutput,
|
||||
},
|
||||
})
|
||||
if expectedOutput.ParseTFOValue() != -1 {
|
||||
t.Fatalf("unexpected parsed TFO value, which should be -1")
|
||||
}
|
||||
|
||||
// test omit "tcpFastOpen", no operation is expected
|
||||
expectedOutput = &internet.SocketConfig{
|
||||
Mark: 0,
|
||||
Tfo: 0,
|
||||
}
|
||||
runMultiTestCase(t, []TestCase{
|
||||
{
|
||||
Input: `{}`,
|
||||
Parser: createParser(),
|
||||
Output: expectedOutput,
|
||||
},
|
||||
})
|
||||
if expectedOutput.ParseTFOValue() != -1 {
|
||||
t.Fatalf("unexpected parsed TFO value, which should be -1")
|
||||
}
|
||||
|
||||
// test "tcpFastOpen": null, no operation is expected
|
||||
expectedOutput = &internet.SocketConfig{
|
||||
Mark: 0,
|
||||
Tfo: 0,
|
||||
}
|
||||
runMultiTestCase(t, []TestCase{
|
||||
{
|
||||
Input: `{
|
||||
"tcpFastOpen": null
|
||||
}`,
|
||||
Parser: createParser(),
|
||||
Output: expectedOutput,
|
||||
},
|
||||
})
|
||||
if expectedOutput.ParseTFOValue() != -1 {
|
||||
t.Fatalf("unexpected parsed TFO value, which should be -1")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransportConfig(t *testing.T) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue