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