mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-07-02 17:58:46 +00:00
DNS: Avoid panic on domain too long (#6207)
Fixes https://github.com/XTLS/Xray-core/issues/6204
This commit is contained in:
@@ -127,15 +127,20 @@ func genEDNS0Options(clientIP net.IP, padding int) *dnsmessage.Resource {
|
|||||||
return opt
|
return opt
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildReqMsgs(domain string, option dns_feature.IPOption, reqIDGen func() uint16, reqOpts *dnsmessage.Resource) []*dnsRequest {
|
func buildReqMsgs(domain string, option dns_feature.IPOption, reqIDGen func() uint16, reqOpts *dnsmessage.Resource) ([]*dnsRequest, error) {
|
||||||
|
name, err := dnsmessage.NewName(domain)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
qA := dnsmessage.Question{
|
qA := dnsmessage.Question{
|
||||||
Name: dnsmessage.MustNewName(domain),
|
Name: name,
|
||||||
Type: dnsmessage.TypeA,
|
Type: dnsmessage.TypeA,
|
||||||
Class: dnsmessage.ClassINET,
|
Class: dnsmessage.ClassINET,
|
||||||
}
|
}
|
||||||
|
|
||||||
qAAAA := dnsmessage.Question{
|
qAAAA := dnsmessage.Question{
|
||||||
Name: dnsmessage.MustNewName(domain),
|
Name: name,
|
||||||
Type: dnsmessage.TypeAAAA,
|
Type: dnsmessage.TypeAAAA,
|
||||||
Class: dnsmessage.ClassINET,
|
Class: dnsmessage.ClassINET,
|
||||||
}
|
}
|
||||||
@@ -175,7 +180,7 @@ func buildReqMsgs(domain string, option dns_feature.IPOption, reqIDGen func() ui
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return reqs
|
return reqs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseResponse parses DNS answers from the returned payload
|
// parseResponse parses DNS answers from the returned payload
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package dns
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -131,10 +132,15 @@ func Test_buildReqMsgs(t *testing.T) {
|
|||||||
IPv6Enable: false,
|
IPv6Enable: false,
|
||||||
FakeEnable: false,
|
FakeEnable: false,
|
||||||
}, nil}, 0},
|
}, nil}, 0},
|
||||||
|
{"name too long", args{strings.Repeat("a", 256), dns_feature.IPOption{
|
||||||
|
IPv4Enable: true,
|
||||||
|
IPv6Enable: true,
|
||||||
|
FakeEnable: false,
|
||||||
|
}, nil}, 0},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
if got := buildReqMsgs(tt.args.domain, tt.args.option, stubID, tt.args.reqOpts); !(len(got) == tt.want) {
|
if got, _ := buildReqMsgs(tt.args.domain, tt.args.option, stubID, tt.args.reqOpts); !(len(got) == tt.want) {
|
||||||
t.Errorf("buildReqMsgs() = %v, want %v", got, tt.want)
|
t.Errorf("buildReqMsgs() = %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -137,14 +137,32 @@ func (s *DoHNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- er
|
|||||||
if s.Name()+"." == "DOH//"+fqdn {
|
if s.Name()+"." == "DOH//"+fqdn {
|
||||||
errors.LogError(ctx, s.Name(), " tries to resolve itself! Use IP or set \"hosts\" instead")
|
errors.LogError(ctx, s.Name(), " tries to resolve itself! Use IP or set \"hosts\" instead")
|
||||||
if noResponseErrCh != nil {
|
if noResponseErrCh != nil {
|
||||||
noResponseErrCh <- errors.New("tries to resolve itself!", s.Name())
|
err := errors.New("tries to resolve itself!", s.Name())
|
||||||
|
if option.IPv4Enable {
|
||||||
|
noResponseErrCh <- err
|
||||||
|
}
|
||||||
|
if option.IPv6Enable {
|
||||||
|
noResponseErrCh <- err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// As we don't want our traffic pattern looks like DoH, we use Random-Length Padding instead of Block-Length Padding recommended in RFC 8467
|
// As we don't want our traffic pattern looks like DoH, we use Random-Length Padding instead of Block-Length Padding recommended in RFC 8467
|
||||||
// Although DoH server like 1.1.1.1 will pad the response to Block-Length 468, at least it is better than no padding for response at all
|
// Although DoH server like 1.1.1.1 will pad the response to Block-Length 468, at least it is better than no padding for response at all
|
||||||
reqs := buildReqMsgs(fqdn, option, s.newReqID, genEDNS0Options(s.clientIP, int(crypto.RandBetween(100, 300))))
|
reqs, err := buildReqMsgs(fqdn, option, s.newReqID, genEDNS0Options(s.clientIP, int(crypto.RandBetween(100, 300))))
|
||||||
|
if err != nil {
|
||||||
|
errors.LogErrorInner(ctx, err, "failed to build dns query for ", fqdn)
|
||||||
|
if noResponseErrCh != nil {
|
||||||
|
if option.IPv4Enable {
|
||||||
|
noResponseErrCh <- err
|
||||||
|
}
|
||||||
|
if option.IPv6Enable {
|
||||||
|
noResponseErrCh <- err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var deadline time.Time
|
var deadline time.Time
|
||||||
if d, ok := ctx.Deadline(); ok {
|
if d, ok := ctx.Deadline(); ok {
|
||||||
|
|||||||
@@ -78,7 +78,19 @@ func (s *QUICNameServer) getCacheController() *CacheController { return s.cacheC
|
|||||||
func (s *QUICNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, fqdn string, option dns_feature.IPOption) {
|
func (s *QUICNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, fqdn string, option dns_feature.IPOption) {
|
||||||
errors.LogInfo(ctx, s.Name(), " querying: ", fqdn)
|
errors.LogInfo(ctx, s.Name(), " querying: ", fqdn)
|
||||||
|
|
||||||
reqs := buildReqMsgs(fqdn, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
reqs, err := buildReqMsgs(fqdn, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
||||||
|
if err != nil {
|
||||||
|
errors.LogErrorInner(ctx, err, "failed to build dns query for ", fqdn)
|
||||||
|
if noResponseErrCh != nil {
|
||||||
|
if option.IPv4Enable {
|
||||||
|
noResponseErrCh <- err
|
||||||
|
}
|
||||||
|
if option.IPv6Enable {
|
||||||
|
noResponseErrCh <- err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var deadline time.Time
|
var deadline time.Time
|
||||||
if d, ok := ctx.Deadline(); ok {
|
if d, ok := ctx.Deadline(); ok {
|
||||||
|
|||||||
@@ -113,7 +113,19 @@ func (s *TCPNameServer) getCacheController() *CacheController {
|
|||||||
func (s *TCPNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, fqdn string, option dns_feature.IPOption) {
|
func (s *TCPNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, fqdn string, option dns_feature.IPOption) {
|
||||||
errors.LogInfo(ctx, s.Name(), " querying DNS for: ", fqdn)
|
errors.LogInfo(ctx, s.Name(), " querying DNS for: ", fqdn)
|
||||||
|
|
||||||
reqs := buildReqMsgs(fqdn, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
reqs, err := buildReqMsgs(fqdn, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
||||||
|
if err != nil {
|
||||||
|
errors.LogErrorInner(ctx, err, "failed to build dns query for ", fqdn)
|
||||||
|
if noResponseErrCh != nil {
|
||||||
|
if option.IPv4Enable {
|
||||||
|
noResponseErrCh <- err
|
||||||
|
}
|
||||||
|
if option.IPv6Enable {
|
||||||
|
noResponseErrCh <- err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var deadline time.Time
|
var deadline time.Time
|
||||||
if d, ok := ctx.Deadline(); ok {
|
if d, ok := ctx.Deadline(); ok {
|
||||||
|
|||||||
@@ -161,7 +161,19 @@ func (s *ClassicNameServer) getCacheController() *CacheController {
|
|||||||
func (s *ClassicNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, fqdn string, option dns_feature.IPOption) {
|
func (s *ClassicNameServer) sendQuery(ctx context.Context, noResponseErrCh chan<- error, fqdn string, option dns_feature.IPOption) {
|
||||||
errors.LogInfo(ctx, s.Name(), " querying DNS for: ", fqdn)
|
errors.LogInfo(ctx, s.Name(), " querying DNS for: ", fqdn)
|
||||||
|
|
||||||
reqs := buildReqMsgs(fqdn, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
reqs, err := buildReqMsgs(fqdn, option, s.newReqID, genEDNS0Options(s.clientIP, 0))
|
||||||
|
if err != nil {
|
||||||
|
errors.LogErrorInner(ctx, err, "failed to build dns query for ", fqdn)
|
||||||
|
if noResponseErrCh != nil {
|
||||||
|
if option.IPv4Enable {
|
||||||
|
noResponseErrCh <- err
|
||||||
|
}
|
||||||
|
if option.IPv6Enable {
|
||||||
|
noResponseErrCh <- err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
for _, req := range reqs {
|
for _, req := range reqs {
|
||||||
udpReq := &udpDnsRequest{
|
udpReq := &udpDnsRequest{
|
||||||
|
|||||||
Reference in New Issue
Block a user