123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- package dispatcher
- import (
- "context"
- "github.com/xtls/xray-core/common"
- "github.com/xtls/xray-core/common/errors"
- "github.com/xtls/xray-core/common/net"
- "github.com/xtls/xray-core/common/protocol/bittorrent"
- "github.com/xtls/xray-core/common/protocol/http"
- "github.com/xtls/xray-core/common/protocol/quic"
- "github.com/xtls/xray-core/common/protocol/tls"
- )
- type SniffResult interface {
- Protocol() string
- Domain() string
- }
- type protocolSniffer func(context.Context, []byte) (SniffResult, error)
- type protocolSnifferWithMetadata struct {
- protocolSniffer protocolSniffer
- // A Metadata sniffer will be invoked on connection establishment only, with nil body,
- // for both TCP and UDP connections
- // It will not be shown as a traffic type for routing unless there is no other successful sniffing.
- metadataSniffer bool
- network net.Network
- }
- type Sniffer struct {
- sniffer []protocolSnifferWithMetadata
- }
- func NewSniffer(ctx context.Context) *Sniffer {
- ret := &Sniffer{
- sniffer: []protocolSnifferWithMetadata{
- {func(c context.Context, b []byte) (SniffResult, error) { return http.SniffHTTP(b, c) }, false, net.Network_TCP},
- {func(c context.Context, b []byte) (SniffResult, error) { return tls.SniffTLS(b) }, false, net.Network_TCP},
- {func(c context.Context, b []byte) (SniffResult, error) { return bittorrent.SniffBittorrent(b) }, false, net.Network_TCP},
- {func(c context.Context, b []byte) (SniffResult, error) { return quic.SniffQUIC(b) }, false, net.Network_UDP},
- {func(c context.Context, b []byte) (SniffResult, error) { return bittorrent.SniffUTP(b) }, false, net.Network_UDP},
- },
- }
- if sniffer, err := newFakeDNSSniffer(ctx); err == nil {
- others := ret.sniffer
- ret.sniffer = append(ret.sniffer, sniffer)
- fakeDNSThenOthers, err := newFakeDNSThenOthers(ctx, sniffer, others)
- if err == nil {
- ret.sniffer = append([]protocolSnifferWithMetadata{fakeDNSThenOthers}, ret.sniffer...)
- }
- }
- return ret
- }
- var errUnknownContent = errors.New("unknown content")
- func (s *Sniffer) Sniff(c context.Context, payload []byte, network net.Network) (SniffResult, error) {
- var pendingSniffer []protocolSnifferWithMetadata
- for _, si := range s.sniffer {
- s := si.protocolSniffer
- if si.metadataSniffer || si.network != network {
- continue
- }
- result, err := s(c, payload)
- if err == common.ErrNoClue {
- pendingSniffer = append(pendingSniffer, si)
- continue
- }
- if err == nil && result != nil {
- return result, nil
- }
- }
- if len(pendingSniffer) > 0 {
- s.sniffer = pendingSniffer
- return nil, common.ErrNoClue
- }
- return nil, errUnknownContent
- }
- func (s *Sniffer) SniffMetadata(c context.Context) (SniffResult, error) {
- var pendingSniffer []protocolSnifferWithMetadata
- for _, si := range s.sniffer {
- s := si.protocolSniffer
- if !si.metadataSniffer {
- pendingSniffer = append(pendingSniffer, si)
- continue
- }
- result, err := s(c, nil)
- if err == common.ErrNoClue {
- pendingSniffer = append(pendingSniffer, si)
- continue
- }
- if err == nil && result != nil {
- return result, nil
- }
- }
- if len(pendingSniffer) > 0 {
- s.sniffer = pendingSniffer
- return nil, common.ErrNoClue
- }
- return nil, errUnknownContent
- }
- func CompositeResult(domainResult SniffResult, protocolResult SniffResult) SniffResult {
- return &compositeResult{domainResult: domainResult, protocolResult: protocolResult}
- }
- type compositeResult struct {
- domainResult SniffResult
- protocolResult SniffResult
- }
- func (c compositeResult) Protocol() string {
- return c.protocolResult.Protocol()
- }
- func (c compositeResult) Domain() string {
- return c.domainResult.Domain()
- }
- func (c compositeResult) ProtocolForDomainResult() string {
- return c.domainResult.Protocol()
- }
- type SnifferResultComposite interface {
- ProtocolForDomainResult() string
- }
- type SnifferIsProtoSubsetOf interface {
- IsProtoSubsetOf(protocolName string) bool
- }
|