github.com/xmplusdev/xray-core@v1.8.10/app/dispatcher/sniffer.go (about)

     1  package dispatcher
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/xmplusdev/xray-core/common"
     7  	"github.com/xmplusdev/xray-core/common/net"
     8  	"github.com/xmplusdev/xray-core/common/protocol/bittorrent"
     9  	"github.com/xmplusdev/xray-core/common/protocol/http"
    10  	"github.com/xmplusdev/xray-core/common/protocol/quic"
    11  	"github.com/xmplusdev/xray-core/common/protocol/tls"
    12  )
    13  
    14  type SniffResult interface {
    15  	Protocol() string
    16  	Domain() string
    17  }
    18  
    19  type protocolSniffer func(context.Context, []byte) (SniffResult, error)
    20  
    21  type protocolSnifferWithMetadata struct {
    22  	protocolSniffer protocolSniffer
    23  	// A Metadata sniffer will be invoked on connection establishment only, with nil body,
    24  	// for both TCP and UDP connections
    25  	// It will not be shown as a traffic type for routing unless there is no other successful sniffing.
    26  	metadataSniffer bool
    27  	network         net.Network
    28  }
    29  
    30  type Sniffer struct {
    31  	sniffer []protocolSnifferWithMetadata
    32  }
    33  
    34  func NewSniffer(ctx context.Context) *Sniffer {
    35  	ret := &Sniffer{
    36  		sniffer: []protocolSnifferWithMetadata{
    37  			{func(c context.Context, b []byte) (SniffResult, error) { return http.SniffHTTP(b) }, false, net.Network_TCP},
    38  			{func(c context.Context, b []byte) (SniffResult, error) { return tls.SniffTLS(b) }, false, net.Network_TCP},
    39  			{func(c context.Context, b []byte) (SniffResult, error) { return bittorrent.SniffBittorrent(b) }, false, net.Network_TCP},
    40  			{func(c context.Context, b []byte) (SniffResult, error) { return quic.SniffQUIC(b) }, false, net.Network_UDP},
    41  			{func(c context.Context, b []byte) (SniffResult, error) { return bittorrent.SniffUTP(b) }, false, net.Network_UDP},
    42  		},
    43  	}
    44  	if sniffer, err := newFakeDNSSniffer(ctx); err == nil {
    45  		others := ret.sniffer
    46  		ret.sniffer = append(ret.sniffer, sniffer)
    47  		fakeDNSThenOthers, err := newFakeDNSThenOthers(ctx, sniffer, others)
    48  		if err == nil {
    49  			ret.sniffer = append([]protocolSnifferWithMetadata{fakeDNSThenOthers}, ret.sniffer...)
    50  		}
    51  	}
    52  	return ret
    53  }
    54  
    55  var errUnknownContent = newError("unknown content")
    56  
    57  func (s *Sniffer) Sniff(c context.Context, payload []byte, network net.Network) (SniffResult, error) {
    58  	var pendingSniffer []protocolSnifferWithMetadata
    59  	for _, si := range s.sniffer {
    60  		s := si.protocolSniffer
    61  		if si.metadataSniffer || si.network != network {
    62  			continue
    63  		}
    64  		result, err := s(c, payload)
    65  		if err == common.ErrNoClue {
    66  			pendingSniffer = append(pendingSniffer, si)
    67  			continue
    68  		}
    69  
    70  		if err == nil && result != nil {
    71  			return result, nil
    72  		}
    73  	}
    74  
    75  	if len(pendingSniffer) > 0 {
    76  		s.sniffer = pendingSniffer
    77  		return nil, common.ErrNoClue
    78  	}
    79  
    80  	return nil, errUnknownContent
    81  }
    82  
    83  func (s *Sniffer) SniffMetadata(c context.Context) (SniffResult, error) {
    84  	var pendingSniffer []protocolSnifferWithMetadata
    85  	for _, si := range s.sniffer {
    86  		s := si.protocolSniffer
    87  		if !si.metadataSniffer {
    88  			pendingSniffer = append(pendingSniffer, si)
    89  			continue
    90  		}
    91  		result, err := s(c, nil)
    92  		if err == common.ErrNoClue {
    93  			pendingSniffer = append(pendingSniffer, si)
    94  			continue
    95  		}
    96  
    97  		if err == nil && result != nil {
    98  			return result, nil
    99  		}
   100  	}
   101  
   102  	if len(pendingSniffer) > 0 {
   103  		s.sniffer = pendingSniffer
   104  		return nil, common.ErrNoClue
   105  	}
   106  
   107  	return nil, errUnknownContent
   108  }
   109  
   110  func CompositeResult(domainResult SniffResult, protocolResult SniffResult) SniffResult {
   111  	return &compositeResult{domainResult: domainResult, protocolResult: protocolResult}
   112  }
   113  
   114  type compositeResult struct {
   115  	domainResult   SniffResult
   116  	protocolResult SniffResult
   117  }
   118  
   119  func (c compositeResult) Protocol() string {
   120  	return c.protocolResult.Protocol()
   121  }
   122  
   123  func (c compositeResult) Domain() string {
   124  	return c.domainResult.Domain()
   125  }
   126  
   127  func (c compositeResult) ProtocolForDomainResult() string {
   128  	return c.domainResult.Protocol()
   129  }
   130  
   131  type SnifferResultComposite interface {
   132  	ProtocolForDomainResult() string
   133  }
   134  
   135  type SnifferIsProtoSubsetOf interface {
   136  	IsProtoSubsetOf(protocolName string) bool
   137  }