mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-04-30 01:08:33 +00:00
Add Fake DNS support (#309)
Co-authored-by: Xiaokang Wang <xiaokangwang@outlook.com> Co-authored-by: loyalsoldier <10487845+Loyalsoldier@users.noreply.github.com> Co-authored-by: kslr <kslrwang@gmail.com>
This commit is contained in:
parent
db32ce6fd9
commit
f50eff5ebb
43 changed files with 1351 additions and 301 deletions
|
@ -15,6 +15,7 @@ import (
|
|||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/core"
|
||||
"github.com/xtls/xray-core/features/dns"
|
||||
"github.com/xtls/xray-core/features/outbound"
|
||||
"github.com/xtls/xray-core/features/policy"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
|
@ -175,17 +176,28 @@ func (d *DefaultDispatcher) getLink(ctx context.Context) (*transport.Link, *tran
|
|||
return inboundLink, outboundLink
|
||||
}
|
||||
|
||||
func shouldOverride(result SniffResult, request session.SniffingRequest) bool {
|
||||
func shouldOverride(ctx context.Context, result SniffResult, request session.SniffingRequest, destination net.Destination) bool {
|
||||
domain := result.Domain()
|
||||
for _, d := range request.ExcludeForDomain {
|
||||
if domain == d {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
protocol := result.Protocol()
|
||||
var fakeDNSEngine dns.FakeDNSEngine
|
||||
core.RequireFeatures(ctx, func(fdns dns.FakeDNSEngine) {
|
||||
fakeDNSEngine = fdns
|
||||
})
|
||||
protocolString := result.Protocol()
|
||||
if resComp, ok := result.(SnifferResultComposite); ok {
|
||||
protocolString = resComp.ProtocolForDomainResult()
|
||||
}
|
||||
for _, p := range request.OverrideDestinationForProtocol {
|
||||
if strings.HasPrefix(protocol, p) {
|
||||
if strings.HasPrefix(protocolString, p) {
|
||||
return true
|
||||
}
|
||||
if fakeDNSEngine != nil && protocolString != "bittorrent" && p == "fakedns" &&
|
||||
fakeDNSEngine.GetFakeIPRange().Contains(destination.Address.IP()) {
|
||||
newError("Using sniffer ", protocolString, " since the fake DNS missed").WriteToLog(session.ExportIDToError(ctx))
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -210,19 +222,33 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
|
|||
ctx = session.ContextWithContent(ctx, content)
|
||||
}
|
||||
sniffingRequest := content.SniffingRequest
|
||||
if destination.Network != net.Network_TCP || !sniffingRequest.Enabled {
|
||||
switch {
|
||||
case !sniffingRequest.Enabled:
|
||||
go d.routedDispatch(ctx, outbound, destination)
|
||||
} else {
|
||||
case destination.Network != net.Network_TCP:
|
||||
// Only metadata sniff will be used for non tcp connection
|
||||
result, err := sniffer(ctx, nil, true)
|
||||
if err == nil {
|
||||
content.Protocol = result.Protocol()
|
||||
if shouldOverride(ctx, result, sniffingRequest, destination) {
|
||||
domain := result.Domain()
|
||||
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
|
||||
destination.Address = net.ParseAddress(domain)
|
||||
ob.Target = destination
|
||||
}
|
||||
}
|
||||
go d.routedDispatch(ctx, outbound, destination)
|
||||
default:
|
||||
go func() {
|
||||
cReader := &cachedReader{
|
||||
reader: outbound.Reader.(*pipe.Reader),
|
||||
}
|
||||
outbound.Reader = cReader
|
||||
result, err := sniffer(ctx, cReader)
|
||||
result, err := sniffer(ctx, cReader, sniffingRequest.MetadataOnly)
|
||||
if err == nil {
|
||||
content.Protocol = result.Protocol()
|
||||
}
|
||||
if err == nil && shouldOverride(result, sniffingRequest) {
|
||||
if err == nil && shouldOverride(ctx, result, sniffingRequest, destination) {
|
||||
domain := result.Domain()
|
||||
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
|
||||
destination.Address = net.ParseAddress(domain)
|
||||
|
@ -234,34 +260,50 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
|
|||
return inbound, nil
|
||||
}
|
||||
|
||||
func sniffer(ctx context.Context, cReader *cachedReader) (SniffResult, error) {
|
||||
func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool) (SniffResult, error) {
|
||||
payload := buf.New()
|
||||
defer payload.Release()
|
||||
|
||||
sniffer := NewSniffer()
|
||||
totalAttempt := 0
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
totalAttempt++
|
||||
if totalAttempt > 2 {
|
||||
return nil, errSniffingTimeout
|
||||
}
|
||||
sniffer := NewSniffer(ctx)
|
||||
|
||||
cReader.Cache(payload)
|
||||
if !payload.IsEmpty() {
|
||||
result, err := sniffer.Sniff(payload.Bytes())
|
||||
if err != common.ErrNoClue {
|
||||
return result, err
|
||||
metaresult, metadataErr := sniffer.SniffMetadata(ctx)
|
||||
|
||||
if metadataOnly {
|
||||
return metaresult, metadataErr
|
||||
}
|
||||
|
||||
contentResult, contentErr := func() (SniffResult, error) {
|
||||
totalAttempt := 0
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
totalAttempt++
|
||||
if totalAttempt > 2 {
|
||||
return nil, errSniffingTimeout
|
||||
}
|
||||
|
||||
cReader.Cache(payload)
|
||||
if !payload.IsEmpty() {
|
||||
result, err := sniffer.Sniff(ctx, payload.Bytes())
|
||||
if err != common.ErrNoClue {
|
||||
return result, err
|
||||
}
|
||||
}
|
||||
if payload.IsFull() {
|
||||
return nil, errUnknownContent
|
||||
}
|
||||
}
|
||||
if payload.IsFull() {
|
||||
return nil, errUnknownContent
|
||||
}
|
||||
}
|
||||
}()
|
||||
if contentErr != nil && metadataErr == nil {
|
||||
return metaresult, nil
|
||||
}
|
||||
if contentErr == nil && metadataErr == nil {
|
||||
return CompositeResult(metaresult, contentResult), nil
|
||||
}
|
||||
return contentResult, contentErr
|
||||
}
|
||||
|
||||
func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.Link, destination net.Destination) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue