sniffer.go 3.3 KB

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