mirror of
https://github.com/go-i2p/go-i2p-bt.git
synced 2025-07-01 12:13:36 -04:00
207 lines
4.8 KiB
Go
207 lines
4.8 KiB
Go
// Copyright 2020 xgfone, 2023 idk
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package httptracker
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"errors"
|
|
"net"
|
|
"strings"
|
|
|
|
"github.com/go-i2p/i2pkeys"
|
|
"github.com/go-i2p/go-i2p-bt/bencode"
|
|
"github.com/go-i2p/go-i2p-bt/metainfo"
|
|
)
|
|
|
|
var errInvalidPeer = errors.New("invalid peer information format")
|
|
|
|
// Peer is a tracker peer.
|
|
type Peer struct {
|
|
// ID is the peer's self-selected ID.
|
|
ID string `bencode:"peer id"` // BEP 3
|
|
|
|
// IP is the IP address or dns name.
|
|
IP string `bencode:"ip"` // BEP 3
|
|
Port uint16 `bencode:"port"` // BEP 3
|
|
}
|
|
|
|
// Addresses returns the list of the addresses that the peer listens on.
|
|
func (p Peer) Addresses() (addrs []metainfo.Address, err error) {
|
|
if strings.HasSuffix(p.IP, ".i2p") {
|
|
var netAddr net.Addr
|
|
if netAddr, err = i2pkeys.NewI2PAddrFromString(strings.TrimSuffix(p.IP, ".i2p")); err != nil {
|
|
return
|
|
} else {
|
|
return []metainfo.Address{{IP: netAddr, Port: p.Port}}, nil
|
|
}
|
|
|
|
}
|
|
if ip := net.ParseIP(p.IP); len(ip) != 0 {
|
|
return []metainfo.Address{{IP: &net.IPAddr{IP: ip}, Port: p.Port}}, nil
|
|
}
|
|
|
|
ips, err := net.LookupIP(p.IP)
|
|
if _len := len(ips); err == nil && len(ips) != 0 {
|
|
addrs = make([]metainfo.Address, _len)
|
|
for i, ip := range ips {
|
|
addrs[i] = metainfo.Address{IP: &net.IPAddr{IP: ip}, Port: p.Port}
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// Peers is a set of the peers.
|
|
type Peers []Peer
|
|
|
|
// UnmarshalBencode implements the interface bencode.Unmarshaler.
|
|
func (ps *Peers) UnmarshalBencode(b []byte) (err error) {
|
|
var v interface{}
|
|
if err = bencode.DecodeBytes(b, &v); err != nil {
|
|
return
|
|
}
|
|
|
|
switch vs := v.(type) {
|
|
case string: // BEP 23
|
|
_len := len(vs)
|
|
if _len%6 != 0 {
|
|
return metainfo.ErrInvalidAddr
|
|
}
|
|
|
|
peers := make(Peers, 0, _len/6)
|
|
for i := 0; i < _len; i += 6 {
|
|
var addr metainfo.Address
|
|
addrBytes := []byte(vs[i : i+6])
|
|
if err = addr.UnmarshalBinary(addrBytes); err != nil {
|
|
return
|
|
}
|
|
peers = append(peers, Peer{IP: addr.IP.String(), Port: addr.Port})
|
|
|
|
}
|
|
|
|
*ps = peers
|
|
case []interface{}: // BEP 3
|
|
peers := make(Peers, len(vs))
|
|
for i, p := range vs {
|
|
|
|
m, ok := p.(map[string]interface{})
|
|
if !ok {
|
|
return errInvalidPeer
|
|
}
|
|
|
|
pid, ok := m["peer id"].(string)
|
|
if !ok {
|
|
return errInvalidPeer
|
|
}
|
|
|
|
ip, ok := m["ip"].(string)
|
|
if !ok {
|
|
return errInvalidPeer
|
|
}
|
|
|
|
port, ok := m["port"].(int64)
|
|
if !ok {
|
|
return errInvalidPeer
|
|
}
|
|
|
|
peers[i] = Peer{ID: pid, IP: ip, Port: uint16(port)}
|
|
}
|
|
*ps = peers
|
|
default:
|
|
return errInvalidPeer
|
|
}
|
|
return
|
|
}
|
|
|
|
// MarshalBencode implements the interface bencode.Marshaler.
|
|
func (ps Peers) MarshalBencode() (b []byte, err error) {
|
|
for _, p := range ps {
|
|
if p.ID == "" {
|
|
return ps.marshalCompactBencode() // BEP 23
|
|
}
|
|
}
|
|
|
|
// BEP 3
|
|
buf := bytes.NewBuffer(make([]byte, 0, 64*len(ps)))
|
|
buf.WriteByte('l')
|
|
for _, p := range ps {
|
|
if err = bencode.NewEncoder(buf).Encode(p); err != nil {
|
|
return
|
|
}
|
|
}
|
|
buf.WriteByte('e')
|
|
b = buf.Bytes()
|
|
return
|
|
}
|
|
|
|
func (ps Peers) marshalCompactBencode() (b []byte, err error) {
|
|
buf := bytes.NewBuffer(make([]byte, 0, 6*len(ps)))
|
|
for _, peer := range ps {
|
|
ip := net.ParseIP(peer.IP).To4()
|
|
if len(ip) == 0 {
|
|
return nil, errInvalidPeer
|
|
}
|
|
buf.Write(ip[:])
|
|
binary.Write(buf, binary.BigEndian, peer.Port)
|
|
}
|
|
return bencode.EncodeBytes(buf.Bytes())
|
|
}
|
|
|
|
// Peers6 is a set of the peers for IPv6 in the compact case.
|
|
//
|
|
// BEP 7
|
|
type Peers6 []Peer
|
|
|
|
// UnmarshalBencode implements the interface bencode.Unmarshaler.
|
|
func (ps *Peers6) UnmarshalBencode(b []byte) (err error) {
|
|
var s string
|
|
if err = bencode.DecodeBytes(b, &s); err != nil {
|
|
return
|
|
}
|
|
|
|
_len := len(s)
|
|
if _len%18 != 0 {
|
|
return metainfo.ErrInvalidAddr
|
|
}
|
|
|
|
peers := make(Peers6, 0, _len/18)
|
|
for i := 0; i < _len; i += 18 {
|
|
var addr metainfo.Address
|
|
if err = addr.UnmarshalBinary([]byte(s[i : i+18])); err != nil {
|
|
return
|
|
}
|
|
peers = append(peers, Peer{IP: addr.IP.String(), Port: addr.Port})
|
|
}
|
|
|
|
*ps = peers
|
|
return
|
|
}
|
|
|
|
// MarshalBencode implements the interface bencode.Marshaler.
|
|
func (ps Peers6) MarshalBencode() (b []byte, err error) {
|
|
buf := bytes.NewBuffer(make([]byte, 0, 18*len(ps)))
|
|
for _, peer := range ps {
|
|
ip := net.ParseIP(peer.IP).To16()
|
|
if len(ip) == 0 {
|
|
return nil, errInvalidPeer
|
|
}
|
|
|
|
buf.Write(ip[:])
|
|
binary.Write(buf, binary.BigEndian, peer.Port)
|
|
}
|
|
return bencode.EncodeBytes(buf.Bytes())
|
|
}
|