80 lines
1.9 KiB
Go
80 lines
1.9 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"encoding/hex"
|
|
"net"
|
|
"time"
|
|
)
|
|
|
|
type TrackerMeta struct {
|
|
Seeders int
|
|
Leechers int
|
|
Completed int
|
|
}
|
|
|
|
func udpScrape(host string, infoHashes [][]byte) map[string]TrackerMeta {
|
|
out := map[string]TrackerMeta{}
|
|
if len(infoHashes) == 0 {
|
|
return out
|
|
}
|
|
addr, err := net.ResolveUDPAddr("udp", host)
|
|
if err != nil {
|
|
return out
|
|
}
|
|
conn, err := net.DialUDP("udp", nil, addr)
|
|
if err != nil {
|
|
return out
|
|
}
|
|
defer conn.Close()
|
|
_ = conn.SetDeadline(time.Now().Add(6 * time.Second))
|
|
transID := uint32(time.Now().UnixNano() & 0x7fffffff)
|
|
var req bytes.Buffer
|
|
_ = binary.Write(&req, binary.BigEndian, uint64(0x41727101980))
|
|
_ = binary.Write(&req, binary.BigEndian, uint32(0))
|
|
_ = binary.Write(&req, binary.BigEndian, transID)
|
|
if _, err := conn.Write(req.Bytes()); err != nil {
|
|
return out
|
|
}
|
|
resp := make([]byte, 16)
|
|
n, err := conn.Read(resp)
|
|
if err != nil || n < 16 || binary.BigEndian.Uint32(resp[4:8]) != transID {
|
|
return out
|
|
}
|
|
connID := resp[8:16]
|
|
if len(infoHashes) > 70 {
|
|
infoHashes = infoHashes[:70]
|
|
}
|
|
var sc bytes.Buffer
|
|
sc.Write(connID)
|
|
_ = binary.Write(&sc, binary.BigEndian, uint32(2))
|
|
_ = binary.Write(&sc, binary.BigEndian, transID+1)
|
|
for _, h := range infoHashes {
|
|
if len(h) == 20 {
|
|
sc.Write(h)
|
|
}
|
|
}
|
|
if _, err := conn.Write(sc.Bytes()); err != nil {
|
|
return out
|
|
}
|
|
buf := make([]byte, 8+12*74)
|
|
_ = conn.SetDeadline(time.Now().Add(6 * time.Second))
|
|
n, err = conn.Read(buf)
|
|
if err != nil || n < 8 {
|
|
return out
|
|
}
|
|
off := 8
|
|
for i, h := range infoHashes {
|
|
if off+12 > n {
|
|
break
|
|
}
|
|
_ = i
|
|
seeders := int(binary.BigEndian.Uint32(buf[off : off+4]))
|
|
done := int(binary.BigEndian.Uint32(buf[off+4 : off+8]))
|
|
leech := int(binary.BigEndian.Uint32(buf[off+8 : off+12]))
|
|
out[hex.EncodeToString(h)] = TrackerMeta{Seeders: seeders, Leechers: leech, Completed: done}
|
|
off += 12
|
|
}
|
|
return out
|
|
}
|