Skip to content

Commit 61336ab

Browse files
nnemirovskyLjhAUMEM
authored andcommitted
XDNS finalmask: Support resolvers (client) and domains (server) instead of domain (XTLS#5872)
XTLS#5872 (comment) Example: XTLS#5872 (comment) --------- Co-authored-by: LjhAUMEM <llnu14702@gmail.com>
1 parent e74ced3 commit 61336ab

10 files changed

Lines changed: 268 additions & 114 deletions

File tree

infra/conf/transport_internet.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1662,16 +1662,30 @@ func (c *Sudoku) Build() (proto.Message, error) {
16621662
}
16631663

16641664
type Xdns struct {
1665-
Domain string `json:"domain"`
1665+
Domain json.RawMessage `json:"domain"`
1666+
1667+
Domains []string `json:"domains"`
1668+
Resolvers []string `json:"resolvers"`
16661669
}
16671670

16681671
func (c *Xdns) Build() (proto.Message, error) {
1669-
if c.Domain == "" {
1670-
return nil, errors.New("empty domain")
1672+
if c.Domain != nil {
1673+
return nil, errors.PrintRemovedFeatureError("domain", "domains(server) & resolvers(client)")
1674+
}
1675+
1676+
if len(c.Domains) == 0 && len(c.Resolvers) == 0 {
1677+
return nil, errors.New("empty domains & empty resolvers")
1678+
}
1679+
1680+
for _, r := range c.Resolvers {
1681+
if !strings.Contains(r, "+udp://") {
1682+
return nil, errors.New("invalid resolver ", r)
1683+
}
16711684
}
16721685

16731686
return &xdns.Config{
1674-
Domain: c.Domain,
1687+
Domains: c.Domains,
1688+
Resolvers: c.Resolvers,
16751689
}, nil
16761690
}
16771691

transport/internet/finalmask/xdns/client.go

Lines changed: 176 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ import (
99
go_errors "errors"
1010
"io"
1111
"net"
12+
"strconv"
13+
"strings"
1214
"sync"
15+
"sync/atomic"
1316
"time"
1417

1518
"github.com/xtls/xray-core/common"
@@ -34,10 +37,14 @@ type packet struct {
3437
}
3538

3639
type xdnsConnClient struct {
37-
net.PacketConn
40+
conn net.PacketConn
41+
resolverConns []net.PacketConn
42+
resolverAddrs []*net.UDPAddr
43+
resolverIdx uint32
44+
resolverSend []atomic.Uint32
3845

3946
clientID []byte
40-
domain Name
47+
domains []Name
4148

4249
pollChan chan struct{}
4350
readQueue chan *packet
@@ -48,16 +55,66 @@ type xdnsConnClient struct {
4855
}
4956

5057
func NewConnClient(c *Config, raw net.PacketConn) (net.PacketConn, error) {
51-
domain, err := ParseName(c.Domain)
52-
if err != nil {
53-
return nil, err
58+
if len(c.Resolvers) == 0 {
59+
return nil, errors.New("empty resolvers")
60+
}
61+
62+
var domains []Name
63+
var servers []string
64+
for _, rs := range c.Resolvers {
65+
parts := strings.Split(rs, "+udp://")
66+
if len(parts) != 2 {
67+
return nil, errors.New("invalid resolvers")
68+
}
69+
domain, err := ParseName(parts[0])
70+
if err != nil {
71+
return nil, err
72+
}
73+
domains = append(domains, domain)
74+
servers = append(servers, parts[1])
75+
}
76+
77+
var resolverConns []net.PacketConn
78+
var resolverAddrs []*net.UDPAddr
79+
var resolverSend []atomic.Uint32
80+
for _, rs := range servers {
81+
h, p, err := net.SplitHostPort(rs)
82+
if err != nil {
83+
return nil, err
84+
}
85+
ip := net.ParseIP(h)
86+
if ip == nil {
87+
return nil, errors.New("invalid ip address")
88+
}
89+
port, _ := strconv.Atoi(p)
90+
if port == 0 {
91+
return nil, errors.New("invalid port")
92+
}
93+
var uc net.PacketConn
94+
if ip.To4() != nil {
95+
uc, err = net.ListenPacket("udp4", ":0")
96+
} else {
97+
uc, err = net.ListenPacket("udp6", ":0")
98+
}
99+
if err != nil {
100+
for _, rc := range resolverConns {
101+
rc.Close()
102+
}
103+
return nil, errors.New("failed to create resolver socket: ", err)
104+
}
105+
resolverConns = append(resolverConns, uc)
106+
resolverAddrs = append(resolverAddrs, &net.UDPAddr{IP: ip, Port: port})
54107
}
108+
resolverSend = make([]atomic.Uint32, len(resolverConns))
55109

56110
conn := &xdnsConnClient{
57-
PacketConn: raw,
111+
conn: raw,
112+
resolverConns: resolverConns,
113+
resolverAddrs: resolverAddrs,
114+
resolverSend: resolverSend,
58115

59116
clientID: make([]byte, 8),
60-
domain: domain,
117+
domains: domains,
61118

62119
pollChan: make(chan struct{}, pollLimit),
63120
readQueue: make(chan *packet, 256),
@@ -73,58 +130,70 @@ func NewConnClient(c *Config, raw net.PacketConn) (net.PacketConn, error) {
73130
}
74131

75132
func (c *xdnsConnClient) recvLoop() {
76-
var buf [finalmask.UDPSize]byte
77-
78-
for {
79-
if c.closed {
80-
break
81-
}
82-
83-
n, addr, err := c.PacketConn.ReadFrom(buf[:])
84-
if err != nil || n == 0 {
85-
if go_errors.Is(err, net.ErrClosed) || go_errors.Is(err, io.EOF) {
86-
break
87-
}
88-
continue
89-
}
90-
91-
resp, err := MessageFromWireFormat(buf[:n])
92-
if err != nil {
93-
errors.LogDebug(context.Background(), addr, " xdns from wireformat err ", err)
94-
continue
95-
}
96-
97-
payload := dnsResponsePayload(&resp, c.domain)
98-
99-
r := bytes.NewReader(payload)
100-
anyPacket := false
101-
for {
102-
p, err := nextPacket(r)
103-
if err != nil {
104-
break
133+
var wg sync.WaitGroup
134+
135+
for i, rc := range c.resolverConns {
136+
wg.Add(1)
137+
go func() {
138+
defer wg.Done()
139+
140+
var buf [finalmask.UDPSize]byte
141+
142+
for {
143+
if c.closed {
144+
break
145+
}
146+
147+
n, addr, err := rc.ReadFrom(buf[:])
148+
if err != nil {
149+
if go_errors.Is(err, net.ErrClosed) {
150+
break
151+
}
152+
continue
153+
}
154+
155+
resp, err := MessageFromWireFormat(buf[:n])
156+
if err != nil {
157+
errors.LogDebug(context.Background(), addr, " xdns from wireformat err ", err)
158+
continue
159+
}
160+
161+
payload := dnsResponsePayload(&resp, c.domains)
162+
163+
r := bytes.NewReader(payload)
164+
anyPacket := false
165+
for {
166+
p, err := nextPacket(r)
167+
if err != nil {
168+
break
169+
}
170+
anyPacket = true
171+
172+
buf := make([]byte, len(p))
173+
copy(buf, p)
174+
select {
175+
case c.readQueue <- &packet{
176+
p: buf,
177+
addr: addr,
178+
}:
179+
default:
180+
errors.LogDebug(context.Background(), addr, " mask read err queue full")
181+
}
182+
}
183+
184+
if anyPacket {
185+
c.resolverSend[i].Store(0)
186+
select {
187+
case c.pollChan <- struct{}{}:
188+
default:
189+
}
190+
}
105191
}
106-
anyPacket = true
107-
108-
buf := make([]byte, len(p))
109-
copy(buf, p)
110-
select {
111-
case c.readQueue <- &packet{
112-
p: buf,
113-
addr: addr,
114-
}:
115-
default:
116-
errors.LogDebug(context.Background(), addr, " mask read err queue full")
117-
}
118-
}
119-
120-
if anyPacket {
121-
select {
122-
case c.pollChan <- struct{}{}:
123-
default:
124-
}
125-
}
192+
}()
126193
}
127194

195+
wg.Wait()
196+
128197
errors.LogDebug(context.Background(), "xdns closed")
129198

130199
close(c.pollChan)
@@ -138,8 +207,6 @@ func (c *xdnsConnClient) recvLoop() {
138207
}
139208

140209
func (c *xdnsConnClient) sendLoop() {
141-
var addr net.Addr
142-
143210
pollDelay := initPollDelay
144211
pollTimer := time.NewTimer(pollDelay)
145212
for {
@@ -158,17 +225,14 @@ func (c *xdnsConnClient) sendLoop() {
158225
}
159226

160227
if p != nil {
161-
addr = p.addr
162-
163228
select {
164229
case <-c.pollChan:
165230
default:
166231
}
167-
} else if addr != nil {
168-
encoded, _ := encode(nil, c.clientID, c.domain)
232+
} else {
233+
encoded, _ := encode(nil, c.clientID, c.domains[c.resolverIdx])
169234
p = &packet{
170-
p: encoded,
171-
addr: addr,
235+
p: encoded,
172236
}
173237
}
174238

@@ -189,10 +253,16 @@ func (c *xdnsConnClient) sendLoop() {
189253
return
190254
}
191255

192-
if p != nil {
193-
_, err := c.PacketConn.WriteTo(p.p, p.addr)
194-
if go_errors.Is(err, net.ErrClosed) || go_errors.Is(err, io.ErrClosedPipe) {
195-
c.closed = true
256+
cur := c.resolverIdx
257+
curSend := c.resolverSend[c.resolverIdx].Add(1)
258+
_, _ = c.resolverConns[c.resolverIdx].WriteTo(p.p, c.resolverAddrs[c.resolverIdx])
259+
for {
260+
c.resolverIdx += 1
261+
c.resolverIdx %= uint32(len(c.resolverConns))
262+
if c.resolverIdx == cur {
263+
break
264+
}
265+
if c.resolverSend[c.resolverIdx].Load() < curSend {
196266
break
197267
}
198268
}
@@ -220,7 +290,7 @@ func (c *xdnsConnClient) WriteTo(p []byte, addr net.Addr) (n int, err error) {
220290
return 0, io.ErrClosedPipe
221291
}
222292

223-
encoded, err := encode(p, c.clientID, c.domain)
293+
encoded, err := encode(p, c.clientID, c.domains[c.resolverIdx%uint32(len(c.resolverConns))])
224294
if err != nil {
225295
errors.LogDebug(context.Background(), addr, " xdns wireformat err ", err, " ", len(p))
226296
return 0, nil
@@ -240,7 +310,35 @@ func (c *xdnsConnClient) WriteTo(p []byte, addr net.Addr) (n int, err error) {
240310

241311
func (c *xdnsConnClient) Close() error {
242312
c.closed = true
243-
return c.PacketConn.Close()
313+
for _, rc := range c.resolverConns {
314+
rc.Close()
315+
}
316+
return c.conn.Close()
317+
}
318+
319+
func (c *xdnsConnClient) LocalAddr() net.Addr {
320+
return c.conn.LocalAddr()
321+
}
322+
323+
func (c *xdnsConnClient) SetDeadline(t time.Time) error {
324+
for _, rc := range c.resolverConns {
325+
rc.SetDeadline(t)
326+
}
327+
return c.conn.SetDeadline(t)
328+
}
329+
330+
func (c *xdnsConnClient) SetReadDeadline(t time.Time) error {
331+
for _, rc := range c.resolverConns {
332+
rc.SetReadDeadline(t)
333+
}
334+
return c.conn.SetReadDeadline(t)
335+
}
336+
337+
func (c *xdnsConnClient) SetWriteDeadline(t time.Time) error {
338+
for _, rc := range c.resolverConns {
339+
rc.SetWriteDeadline(t)
340+
}
341+
return c.conn.SetWriteDeadline(t)
244342
}
245343

246344
func encode(p []byte, clientID []byte, domain Name) ([]byte, error) {
@@ -332,7 +430,7 @@ func nextPacket(r *bytes.Reader) ([]byte, error) {
332430
return p, err
333431
}
334432

335-
func dnsResponsePayload(resp *Message, domain Name) []byte {
433+
func dnsResponsePayload(resp *Message, domains []Name) []byte {
336434
if resp.Flags&0x8000 != 0x8000 {
337435
return nil
338436
}
@@ -345,7 +443,13 @@ func dnsResponsePayload(resp *Message, domain Name) []byte {
345443
}
346444
answer := resp.Answer[0]
347445

348-
_, ok := answer.Name.TrimSuffix(domain)
446+
var ok bool
447+
for _, domain := range domains {
448+
_, ok = answer.Name.TrimSuffix(domain)
449+
if ok {
450+
break
451+
}
452+
}
349453
if !ok {
350454
return nil
351455
}

0 commit comments

Comments
 (0)