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, &timestamp); 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  }