github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/app/dispatcher/sniffer.go (about)

     1  package dispatcher
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/v2fly/v2ray-core/v5/common"
     7  	"github.com/v2fly/v2ray-core/v5/common/net"
     8  	"github.com/v2fly/v2ray-core/v5/common/protocol/bittorrent"
     9  	"github.com/v2fly/v2ray-core/v5/common/protocol/http"
    10  	"github.com/v2fly/v2ray-core/v5/common/protocol/quic"
    11  	"github.com/v2fly/v2ray-core/v5/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 quic.SniffQUIC(b) }, false, net.Network_UDP},
    40  			{func(c context.Context, b []byte) (SniffResult, error) { return bittorrent.SniffBittorrent(b) }, false, net.Network_TCP},
    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 {
    62  			continue
    63  		}
    64  		if si.network != network {
    65  			continue
    66  		}
    67  		result, err := s(c, payload)
    68  		if err == common.ErrNoClue {
    69  			pendingSniffer = append(pendingSniffer, si)
    70  			continue
    71  		}
    72  
    73  		if err == nil && result != nil {
    74  			return result, nil
    75  		}
    76  	}
    77  
    78  	if len(pendingSniffer) > 0 {
    79  		s.sniffer = pendingSniffer
    80  		return nil, common.ErrNoClue
    81  	}
    82  
    83  	return nil, errUnknownContent
    84  }
    85  
    86  func (s *Sniffer) SniffMetadata(c context.Context) (SniffResult, error) {
    87  	var pendingSniffer []protocolSnifferWithMetadata
    88  	for _, si := range s.sniffer {
    89  		s := si.protocolSniffer
    90  		if !si.metadataSniffer {
    91  			pendingSniffer = append(pendingSniffer, si)
    92  			continue
    93  		}
    94  		result, err := s(c, nil)
    95  		if err == common.ErrNoClue {
    96  			pendingSniffer = append(pendingSniffer, si)
    97  			continue
    98  		}
    99  
   100  		if err == nil && result != nil {
   101  			return result, nil
   102  		}
   103  	}
   104  
   105  	if len(pendingSniffer) > 0 {
   106  		s.sniffer = pendingSniffer
   107  		return nil, common.ErrNoClue
   108  	}
   109  
   110  	return nil, errUnknownContent
   111  }
   112  
   113  func CompositeResult(domainResult SniffResult, protocolResult SniffResult) SniffResult {
   114  	return &compositeResult{domainResult: domainResult, protocolResult: protocolResult}
   115  }
   116  
   117  type compositeResult struct {
   118  	domainResult   SniffResult
   119  	protocolResult SniffResult
   120  }
   121  
   122  func (c compositeResult) Protocol() string {
   123  	return c.protocolResult.Protocol()
   124  }
   125  
   126  func (c compositeResult) Domain() string {
   127  	return c.domainResult.Domain()
   128  }
   129  
   130  func (c compositeResult) ProtocolForDomainResult() string {
   131  	return c.domainResult.Protocol()
   132  }
   133  
   134  type SnifferResultComposite interface {
   135  	ProtocolForDomainResult() string
   136  }
   137  
   138  type SnifferIsProtoSubsetOf interface {
   139  	IsProtoSubsetOf(protocolName string) bool
   140  }