Skip to content

Commit 3847a73

Browse files
author
drovosek229
committed
DNS hosts: Support returning RCode (XTLS#4681)
1 parent e273b91 commit 3847a73

4 files changed

Lines changed: 76 additions & 18 deletions

File tree

app/dns/dns.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,12 @@ func (s *DNS) LookupIP(domain string, option dns.IPOption) ([]net.IP, uint32, er
204204
}
205205

206206
// Static host lookup
207-
switch addrs := s.hosts.Lookup(domain, option); {
207+
switch addrs, err := s.hosts.Lookup(domain, option); {
208+
case err != nil:
209+
if go_errors.Is(err, dns.ErrEmptyResponse) {
210+
return nil, 0, dns.ErrEmptyResponse
211+
}
212+
return nil, 0, errors.New("returning nil for domain ", domain).Base(err)
208213
case addrs == nil: // Domain not recorded in static host
209214
break
210215
case len(addrs) == 0: // Domain recorded, but no valid IP returned (e.g. IPv4 address with only IPv6 enabled)

app/dns/hosts.go

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package dns
22

33
import (
44
"context"
5+
"strconv"
6+
57
"github.com/xtls/xray-core/common/errors"
68
"github.com/xtls/xray-core/common/net"
79
"github.com/xtls/xray-core/common/strmatcher"
@@ -31,7 +33,15 @@ func NewStaticHosts(hosts []*Config_HostMapping) (*StaticHosts, error) {
3133
ips := make([]net.Address, 0, len(mapping.Ip)+1)
3234
switch {
3335
case len(mapping.ProxiedDomain) > 0:
34-
ips = append(ips, net.DomainAddress(mapping.ProxiedDomain))
36+
if mapping.ProxiedDomain[0] == '#' {
37+
rcode, err := strconv.Atoi(mapping.ProxiedDomain[1:])
38+
if err != nil {
39+
return nil, err
40+
}
41+
ips = append(ips, dns.RCodeError(rcode))
42+
} else {
43+
ips = append(ips, net.DomainAddress(mapping.ProxiedDomain))
44+
}
3545
case len(mapping.Ip) > 0:
3646
for _, ip := range mapping.Ip {
3747
addr := net.IPAddress(ip)
@@ -58,38 +68,51 @@ func filterIP(ips []net.Address, option dns.IPOption) []net.Address {
5868
return filtered
5969
}
6070

61-
func (h *StaticHosts) lookupInternal(domain string) []net.Address {
71+
func (h *StaticHosts) lookupInternal(domain string) ([]net.Address, error) {
6272
ips := make([]net.Address, 0)
6373
found := false
6474
for _, id := range h.matchers.Match(domain) {
75+
for _, v := range h.ips[id] {
76+
if err, ok := v.(dns.RCodeError); ok {
77+
if uint16(err) == 0 {
78+
return nil, dns.ErrEmptyResponse
79+
}
80+
return nil, err
81+
}
82+
}
6583
ips = append(ips, h.ips[id]...)
6684
found = true
6785
}
6886
if !found {
69-
return nil
87+
return nil, nil
7088
}
71-
return ips
89+
return ips, nil
7290
}
7391

74-
func (h *StaticHosts) lookup(domain string, option dns.IPOption, maxDepth int) []net.Address {
75-
switch addrs := h.lookupInternal(domain); {
92+
func (h *StaticHosts) lookup(domain string, option dns.IPOption, maxDepth int) ([]net.Address, error) {
93+
switch addrs, err := h.lookupInternal(domain); {
94+
case err != nil:
95+
return nil, err
7696
case len(addrs) == 0: // Not recorded in static hosts, return nil
77-
return addrs
97+
return addrs, nil
7898
case len(addrs) == 1 && addrs[0].Family().IsDomain(): // Try to unwrap domain
7999
errors.LogDebug(context.Background(), "found replaced domain: ", domain, " -> ", addrs[0].Domain(), ". Try to unwrap it")
80100
if maxDepth > 0 {
81-
unwrapped := h.lookup(addrs[0].Domain(), option, maxDepth-1)
101+
unwrapped, err := h.lookup(addrs[0].Domain(), option, maxDepth-1)
102+
if err != nil {
103+
return nil, err
104+
}
82105
if unwrapped != nil {
83-
return unwrapped
106+
return unwrapped, nil
84107
}
85108
}
86-
return addrs
109+
return addrs, nil
87110
default: // IP record found, return a non-nil IP array
88-
return filterIP(addrs, option)
111+
return filterIP(addrs, option), nil
89112
}
90113
}
91114

92115
// Lookup returns IP addresses or proxied domain for the given domain, if exists in this StaticHosts.
93-
func (h *StaticHosts) Lookup(domain string, option dns.IPOption) []net.Address {
116+
func (h *StaticHosts) Lookup(domain string, option dns.IPOption) ([]net.Address, error) {
94117
return h.lookup(domain, option, 5)
95118
}

app/dns/hosts_test.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ import (
1212

1313
func TestStaticHosts(t *testing.T) {
1414
pb := []*Config_HostMapping{
15+
{
16+
Type: DomainMatchingType_Subdomain,
17+
Domain: "lan",
18+
ProxiedDomain: "#3",
19+
},
1520
{
1621
Type: DomainMatchingType_Full,
1722
Domain: "example.com",
@@ -54,7 +59,14 @@ func TestStaticHosts(t *testing.T) {
5459
common.Must(err)
5560

5661
{
57-
ips := hosts.Lookup("example.com", dns.IPOption{
62+
_, err := hosts.Lookup("example.com.lan", dns.IPOption{})
63+
if dns.RCodeFromError(err) != 3 {
64+
t.Error(err)
65+
}
66+
}
67+
68+
{
69+
ips, _ := hosts.Lookup("example.com", dns.IPOption{
5870
IPv4Enable: true,
5971
IPv6Enable: true,
6072
})
@@ -67,7 +79,7 @@ func TestStaticHosts(t *testing.T) {
6779
}
6880

6981
{
70-
domain := hosts.Lookup("proxy.xray.com", dns.IPOption{
82+
domain, _ := hosts.Lookup("proxy.xray.com", dns.IPOption{
7183
IPv4Enable: true,
7284
IPv6Enable: false,
7385
})
@@ -80,7 +92,7 @@ func TestStaticHosts(t *testing.T) {
8092
}
8193

8294
{
83-
domain := hosts.Lookup("proxy2.xray.com", dns.IPOption{
95+
domain, _ := hosts.Lookup("proxy2.xray.com", dns.IPOption{
8496
IPv4Enable: true,
8597
IPv6Enable: false,
8698
})
@@ -93,7 +105,7 @@ func TestStaticHosts(t *testing.T) {
93105
}
94106

95107
{
96-
ips := hosts.Lookup("www.example.cn", dns.IPOption{
108+
ips, _ := hosts.Lookup("www.example.cn", dns.IPOption{
97109
IPv4Enable: true,
98110
IPv6Enable: true,
99111
})
@@ -106,7 +118,7 @@ func TestStaticHosts(t *testing.T) {
106118
}
107119

108120
{
109-
ips := hosts.Lookup("baidu.com", dns.IPOption{
121+
ips, _ := hosts.Lookup("baidu.com", dns.IPOption{
110122
IPv4Enable: false,
111123
IPv6Enable: true,
112124
})

features/dns/client.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,24 @@ func (e RCodeError) Error() string {
4242
return serial.Concat("rcode: ", uint16(e))
4343
}
4444

45+
func (RCodeError) IP() net.IP {
46+
panic("Calling IP() on a RCodeError.")
47+
}
48+
49+
func (RCodeError) Domain() string {
50+
panic("Calling Domain() on a RCodeError.")
51+
}
52+
53+
func (RCodeError) Family() net.AddressFamily {
54+
panic("Calling Family() on a RCodeError.")
55+
}
56+
57+
func (e RCodeError) String() string {
58+
return e.Error()
59+
}
60+
61+
var _ net.Address = (*RCodeError)(nil)
62+
4563
func RCodeFromError(err error) uint16 {
4664
if err == nil {
4765
return 0

0 commit comments

Comments
 (0)