sniff.go 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. package sniff
  2. import (
  3. "bytes"
  4. "context"
  5. "errors"
  6. "io"
  7. "net"
  8. "time"
  9. "github.com/sagernet/sing-box/adapter"
  10. C "github.com/sagernet/sing-box/constant"
  11. "github.com/sagernet/sing/common"
  12. "github.com/sagernet/sing/common/buf"
  13. E "github.com/sagernet/sing/common/exceptions"
  14. )
  15. type (
  16. StreamSniffer = func(ctx context.Context, metadata *adapter.InboundContext, reader io.Reader) error
  17. PacketSniffer = func(ctx context.Context, metadata *adapter.InboundContext, packet []byte) error
  18. )
  19. var ErrNeedMoreData = E.New("need more data")
  20. func Skip(metadata *adapter.InboundContext) bool {
  21. // skip server first protocols
  22. switch metadata.Destination.Port {
  23. case 25, 465, 587:
  24. // SMTP
  25. return true
  26. case 143, 993:
  27. // IMAP
  28. return true
  29. case 110, 995:
  30. // POP3
  31. return true
  32. }
  33. return false
  34. }
  35. func PeekStream(ctx context.Context, metadata *adapter.InboundContext, conn net.Conn, buffers []*buf.Buffer, buffer *buf.Buffer, timeout time.Duration, sniffers ...StreamSniffer) error {
  36. if timeout == 0 {
  37. timeout = C.ReadPayloadTimeout
  38. }
  39. deadline := time.Now().Add(timeout)
  40. var sniffError error
  41. for i := 0; ; i++ {
  42. err := conn.SetReadDeadline(deadline)
  43. if err != nil {
  44. return E.Cause(err, "set read deadline")
  45. }
  46. _, err = buffer.ReadOnceFrom(conn)
  47. _ = conn.SetReadDeadline(time.Time{})
  48. if err != nil {
  49. if i > 0 {
  50. break
  51. }
  52. return E.Cause(err, "read payload")
  53. }
  54. sniffError = nil
  55. for _, sniffer := range sniffers {
  56. reader := io.MultiReader(common.Map(append(buffers, buffer), func(it *buf.Buffer) io.Reader {
  57. return bytes.NewReader(it.Bytes())
  58. })...)
  59. err = sniffer(ctx, metadata, reader)
  60. if err == nil {
  61. return nil
  62. }
  63. sniffError = E.Errors(sniffError, err)
  64. }
  65. if !errors.Is(sniffError, ErrNeedMoreData) {
  66. break
  67. }
  68. }
  69. return sniffError
  70. }
  71. func PeekPacket(ctx context.Context, metadata *adapter.InboundContext, packet []byte, sniffers ...PacketSniffer) error {
  72. var sniffError []error
  73. for _, sniffer := range sniffers {
  74. err := sniffer(ctx, metadata, packet)
  75. if err == nil {
  76. return nil
  77. }
  78. sniffError = append(sniffError, err)
  79. }
  80. return E.Errors(sniffError...)
  81. }