sniffer.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  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. ret.sniffer = append(ret.sniffer, sniffer)
  35. }
  36. return ret
  37. }
  38. var errUnknownContent = newError("unknown content")
  39. func (s *Sniffer) Sniff(c context.Context, payload []byte) (SniffResult, error) {
  40. var pendingSniffer []protocolSnifferWithMetadata
  41. for _, si := range s.sniffer {
  42. s := si.protocolSniffer
  43. if si.metadataSniffer {
  44. continue
  45. }
  46. result, err := s(c, payload)
  47. if err == common.ErrNoClue {
  48. pendingSniffer = append(pendingSniffer, si)
  49. continue
  50. }
  51. if err == nil && result != nil {
  52. return result, nil
  53. }
  54. }
  55. if len(pendingSniffer) > 0 {
  56. s.sniffer = pendingSniffer
  57. return nil, common.ErrNoClue
  58. }
  59. return nil, errUnknownContent
  60. }
  61. func (s *Sniffer) SniffMetadata(c context.Context) (SniffResult, error) {
  62. var pendingSniffer []protocolSnifferWithMetadata
  63. for _, si := range s.sniffer {
  64. s := si.protocolSniffer
  65. if !si.metadataSniffer {
  66. pendingSniffer = append(pendingSniffer, si)
  67. continue
  68. }
  69. result, err := s(c, nil)
  70. if err == common.ErrNoClue {
  71. pendingSniffer = append(pendingSniffer, si)
  72. continue
  73. }
  74. if err == nil && result != nil {
  75. return result, nil
  76. }
  77. }
  78. if len(pendingSniffer) > 0 {
  79. s.sniffer = pendingSniffer
  80. return nil, common.ErrNoClue
  81. }
  82. return nil, errUnknownContent
  83. }
  84. func CompositeResult(domainResult SniffResult, protocolResult SniffResult) SniffResult {
  85. return &compositeResult{domainResult: domainResult, protocolResult: protocolResult}
  86. }
  87. type compositeResult struct {
  88. domainResult SniffResult
  89. protocolResult SniffResult
  90. }
  91. func (c compositeResult) Protocol() string {
  92. return c.protocolResult.Protocol()
  93. }
  94. func (c compositeResult) Domain() string {
  95. return c.domainResult.Domain()
  96. }
  97. func (c compositeResult) ProtocolForDomainResult() string {
  98. return c.domainResult.Protocol()
  99. }
  100. type SnifferResultComposite interface {
  101. ProtocolForDomainResult() string
  102. }