bittorrent.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. package bittorrent
  2. import (
  3. "encoding/binary"
  4. "errors"
  5. "math"
  6. "time"
  7. "github.com/xtls/xray-core/common"
  8. "github.com/xtls/xray-core/common/buf"
  9. )
  10. type SniffHeader struct{}
  11. func (h *SniffHeader) Protocol() string {
  12. return "bittorrent"
  13. }
  14. func (h *SniffHeader) Domain() string {
  15. return ""
  16. }
  17. var errNotBittorrent = errors.New("not bittorrent header")
  18. func SniffBittorrent(b []byte) (*SniffHeader, error) {
  19. if len(b) < 20 {
  20. return nil, common.ErrNoClue
  21. }
  22. if b[0] == 19 && string(b[1:20]) == "BitTorrent protocol" {
  23. return &SniffHeader{}, nil
  24. }
  25. return nil, errNotBittorrent
  26. }
  27. func SniffUTP(b []byte) (*SniffHeader, error) {
  28. if len(b) < 20 {
  29. return nil, common.ErrNoClue
  30. }
  31. buffer := buf.FromBytes(b)
  32. var typeAndVersion uint8
  33. if binary.Read(buffer, binary.BigEndian, &typeAndVersion) != nil {
  34. return nil, common.ErrNoClue
  35. } else if b[0]>>4&0xF > 4 || b[0]&0xF != 1 {
  36. return nil, errNotBittorrent
  37. }
  38. var extension uint8
  39. if binary.Read(buffer, binary.BigEndian, &extension) != nil {
  40. return nil, common.ErrNoClue
  41. } else if extension != 0 && extension != 1 {
  42. return nil, errNotBittorrent
  43. }
  44. for extension != 0 {
  45. if extension != 1 {
  46. return nil, errNotBittorrent
  47. }
  48. if binary.Read(buffer, binary.BigEndian, &extension) != nil {
  49. return nil, common.ErrNoClue
  50. }
  51. var length uint8
  52. if err := binary.Read(buffer, binary.BigEndian, &length); err != nil {
  53. return nil, common.ErrNoClue
  54. }
  55. if common.Error2(buffer.ReadBytes(int32(length))) != nil {
  56. return nil, common.ErrNoClue
  57. }
  58. }
  59. if common.Error2(buffer.ReadBytes(2)) != nil {
  60. return nil, common.ErrNoClue
  61. }
  62. var timestamp uint32
  63. if err := binary.Read(buffer, binary.BigEndian, &timestamp); err != nil {
  64. return nil, common.ErrNoClue
  65. }
  66. if math.Abs(float64(time.Now().UnixMicro()-int64(timestamp))) > float64(24*time.Hour) {
  67. return nil, errNotBittorrent
  68. }
  69. return &SniffHeader{}, nil
  70. }