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