sniffer.go 3.3 KB

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