github.com/Asutorufa/yuhaiin@v0.3.6-0.20240502055049-7984da7023a0/pkg/net/sniffy/bittorrent/bittorrent.go (about)

     1  package bittorrent
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"errors"
     7  	"io"
     8  	"math"
     9  	"time"
    10  )
    11  
    12  type SniffHeader struct{}
    13  
    14  func (h *SniffHeader) Protocol() string {
    15  	return "bittorrent"
    16  }
    17  
    18  func (h *SniffHeader) Domain() string {
    19  	return ""
    20  }
    21  
    22  var errNotBittorrent = errors.New("not bittorrent header")
    23  var ErrNoClue = errors.New("no rule")
    24  
    25  func SniffBittorrent(b []byte) (*SniffHeader, error) {
    26  	if len(b) < 20 {
    27  		return nil, 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, ErrNoClue
    40  	}
    41  
    42  	buffer := bytes.NewBuffer(b)
    43  
    44  	var typeAndVersion uint8
    45  
    46  	if binary.Read(buffer, binary.BigEndian, &typeAndVersion) != nil {
    47  		return nil, 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, 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, ErrNoClue
    66  		}
    67  
    68  		var length uint8
    69  		if err := binary.Read(buffer, binary.BigEndian, &length); err != nil {
    70  			return nil, ErrNoClue
    71  		}
    72  		if ReadBytes(buffer, int(length)) != nil {
    73  			return nil, ErrNoClue
    74  		}
    75  	}
    76  
    77  	if ReadBytes(buffer, 2) != nil {
    78  		return nil, ErrNoClue
    79  	}
    80  
    81  	var timestamp uint32
    82  	if err := binary.Read(buffer, binary.BigEndian, &timestamp); err != nil {
    83  		return nil, 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  }
    91  
    92  func ReadBytes(buf *bytes.Buffer, n int) error {
    93  	if buf.Len() < n {
    94  		return io.EOF
    95  	}
    96  
    97  	buf.Next(n)
    98  	return nil
    99  }