sniffer.go 3.4 KB

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