mirror of
https://github.com/go-i2p/go-i2p.git
synced 2025-06-07 18:24:25 -04:00
380 lines
11 KiB
Go
380 lines
11 KiB
Go
// Package router_info implements the I2P RouterInfo common data structure
|
|
package router_info
|
|
|
|
import (
|
|
"errors"
|
|
"strconv"
|
|
"strings"
|
|
|
|
. "github.com/go-i2p/go-i2p/lib/common/data"
|
|
. "github.com/go-i2p/go-i2p/lib/common/router_address"
|
|
. "github.com/go-i2p/go-i2p/lib/common/router_identity"
|
|
. "github.com/go-i2p/go-i2p/lib/common/signature"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
const ROUTER_INFO_MIN_SIZE = 439
|
|
|
|
var MIN_GOOD_VERSION = 59
|
|
const MAX_GOOD_VERSION = 99
|
|
|
|
/*
|
|
[RouterInfo]
|
|
Accurate for version 0.9.49
|
|
|
|
Description
|
|
Defines all of the data that a router wants to public for the network to see. The
|
|
RouterInfo is one of two structures stored in the network database (the other being
|
|
LeaseSet), and is keyed under the SHA256 of the contained RouterIdentity.
|
|
|
|
Contents
|
|
RouterIdentity followed by the Date, when the entry was published
|
|
|
|
+----+----+----+----+----+----+----+----+
|
|
| router_ident |
|
|
+ +
|
|
| |
|
|
~ ~
|
|
~ ~
|
|
| |
|
|
+----+----+----+----+----+----+----+----+
|
|
| published |
|
|
+----+----+----+----+----+----+----+----+
|
|
|size| RouterAddress 0 |
|
|
+----+ +
|
|
| |
|
|
~ ~
|
|
~ ~
|
|
| |
|
|
+----+----+----+----+----+----+----+----+
|
|
| RouterAddress 1 |
|
|
+ +
|
|
| |
|
|
~ ~
|
|
~ ~
|
|
| |
|
|
+----+----+----+----+----+----+----+----+
|
|
| RouterAddress ($size-1) |
|
|
+ +
|
|
| |
|
|
~ ~
|
|
~ ~
|
|
| |
|
|
+----+----+----+----+-//-+----+----+----+
|
|
|psiz| options |
|
|
+----+----+----+----+-//-+----+----+----+
|
|
| signature |
|
|
+ +
|
|
| |
|
|
+ +
|
|
| |
|
|
+ +
|
|
| |
|
|
+ +
|
|
| |
|
|
+----+----+----+----+----+----+----+----+
|
|
|
|
router_ident :: RouterIdentity
|
|
length -> >= 387 bytes
|
|
|
|
published :: Date
|
|
length -> 8 bytes
|
|
|
|
size :: Integer
|
|
length -> 1 byte
|
|
The number of RouterAddresses to follow, 0-255
|
|
|
|
addresses :: [RouterAddress]
|
|
length -> varies
|
|
|
|
peer_size :: Integer
|
|
length -> 1 byte
|
|
The number of peer Hashes to follow, 0-255, unused, always zero
|
|
value -> 0
|
|
|
|
options :: Mapping
|
|
|
|
signature :: Signature
|
|
length -> 40 bytes
|
|
*/
|
|
|
|
// RouterInfo is the represenation of an I2P RouterInfo.
|
|
//
|
|
// https://geti2p.net/spec/common-structures#routerinfo
|
|
type RouterInfo struct {
|
|
router_identity *RouterIdentity
|
|
published *Date
|
|
size *Integer
|
|
addresses []*RouterAddress
|
|
peer_size *Integer
|
|
options *Mapping
|
|
signature *Signature
|
|
}
|
|
|
|
// Bytes returns the RouterInfo as a []byte suitable for writing to a stream.
|
|
func (router_info RouterInfo) Bytes() ([]byte, error) {
|
|
var err error
|
|
var bytes []byte
|
|
bytes = append(bytes, router_info.router_identity.KeysAndCert.Bytes()...)
|
|
bytes = append(bytes, router_info.published.Bytes()...)
|
|
bytes = append(bytes, router_info.size.Bytes()...)
|
|
for _, router_address := range router_info.addresses {
|
|
bytes = append(bytes, router_address.Bytes()...)
|
|
}
|
|
bytes = append(bytes, router_info.peer_size.Bytes()...)
|
|
bytes = append(bytes, router_info.options.Data()...)
|
|
//bytes = append(bytes, []byte(*router_info.signature)...)
|
|
|
|
return bytes, err
|
|
}
|
|
|
|
// RouterIdentity returns the router identity as *RouterIdentity.
|
|
func (router_info *RouterInfo) RouterIdentity() *RouterIdentity {
|
|
return router_info.router_identity
|
|
}
|
|
|
|
// IndentHash returns the identity hash (sha256 sum) for this RouterInfo.
|
|
func (router_info *RouterInfo) IdentHash() Hash {
|
|
ri := router_info.RouterIdentity()
|
|
h := HashData(ri.KeysAndCert.Certificate().Data())
|
|
return h
|
|
}
|
|
|
|
// Published returns the date this RouterInfo was published as an I2P Date.
|
|
func (router_info *RouterInfo) Published() *Date {
|
|
return router_info.published
|
|
}
|
|
|
|
// RouterAddressCount returns the count of RouterAddress in this RouterInfo as a Go integer.
|
|
func (router_info *RouterInfo) RouterAddressCount() int {
|
|
return router_info.size.Int()
|
|
}
|
|
|
|
// RouterAddresses returns all RouterAddresses for this RouterInfo as []*RouterAddress.
|
|
func (router_info *RouterInfo) RouterAddresses() []*RouterAddress {
|
|
return router_info.addresses
|
|
}
|
|
|
|
// PeerSize returns the peer size as a Go integer.
|
|
func (router_info *RouterInfo) PeerSize() int {
|
|
// Peer size is unused:
|
|
// https://geti2p.net/spec/common-structures#routeraddress
|
|
return 0
|
|
}
|
|
|
|
// Options returns the options for this RouterInfo as an I2P Mapping.
|
|
func (router_info RouterInfo) Options() (mapping Mapping) {
|
|
return *router_info.options
|
|
}
|
|
|
|
//
|
|
// Return the signature of this router info
|
|
//
|
|
|
|
// Signature returns the signature for this RouterInfo as an I2P Signature.
|
|
func (router_info RouterInfo) Signature() (signature Signature) {
|
|
return *router_info.signature
|
|
}
|
|
|
|
//
|
|
// Used during parsing to determine where in the RouterInfo the Mapping data begins.
|
|
//
|
|
/*func (router_info RouterInfo) optionsLocation() (location int) {
|
|
data, remainder, err := ReadRouterIdentity(router_info)
|
|
if err != nil {
|
|
return
|
|
}
|
|
location += len(data)
|
|
|
|
remainder_len := len(remainder)
|
|
if remainder_len < 9 {
|
|
log.WithFields(log.Fields{
|
|
"at": "(RouterInfo) optionsLocation",
|
|
"data_len": remainder_len,
|
|
"required_len": 9,
|
|
"reason": "not enough data",
|
|
}).Error("error parsing router info")
|
|
err = errors.New("error parsing router addresses: not enough data")
|
|
return
|
|
}
|
|
location += 9
|
|
|
|
remaining := remainder[9:]
|
|
var router_address RouterAddress
|
|
var router_addresses []RouterAddress
|
|
addr_count, cerr := router_info.RouterAddressCount()
|
|
if cerr != nil {
|
|
err = cerr
|
|
return
|
|
}
|
|
for i := 0; i < addr_count; i++ {
|
|
router_address, remaining, err = ReadRouterAddress(remaining)
|
|
if err == nil {
|
|
location += len(router_address)
|
|
router_addresses = append(router_addresses, router_address)
|
|
}
|
|
}
|
|
location += 1
|
|
return
|
|
}*/
|
|
|
|
//
|
|
// Used during parsing to determine the size of the options in the RouterInfo.
|
|
//
|
|
/*func (router_info RouterInfo) optionsSize() (size int) {
|
|
head := router_info.optionsLocation()
|
|
s := Integer(router_info[head : head+2])
|
|
size = s.Int() + 2
|
|
return
|
|
}*/
|
|
|
|
// ReadRouterInfo returns RouterInfo from a []byte.
|
|
// The remaining bytes after the specified length are also returned.
|
|
// Returns a list of errors that occurred during parsing.
|
|
func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error) {
|
|
identity, remainder, err := NewRouterIdentity(bytes)
|
|
info.router_identity = identity
|
|
if err != nil {
|
|
log.WithFields(log.Fields{
|
|
"at": "(RouterInfo) ReadRouterInfo",
|
|
"data_len": len(bytes),
|
|
"required_len": ROUTER_INFO_MIN_SIZE,
|
|
"reason": "not enough data",
|
|
}).Error("error parsing router info")
|
|
err = errors.New("error parsing router info: not enough data")
|
|
}
|
|
date, remainder, err := NewDate(remainder)
|
|
info.published = date
|
|
if err != nil {
|
|
log.WithFields(log.Fields{
|
|
"at": "(RouterInfo) ReadRouterInfo",
|
|
"data_len": len(remainder),
|
|
"required_len": DATE_SIZE,
|
|
"reason": "not enough data",
|
|
}).Error("error parsing router info")
|
|
err = errors.New("error parsing router info: not enough data")
|
|
}
|
|
size, remainder, err := NewInteger(remainder, 1)
|
|
if err != nil {
|
|
log.WithFields(log.Fields{
|
|
"at": "(RouterInfo) ReadRouterInfo",
|
|
"data_len": len(remainder),
|
|
"required_len": size.Int(),
|
|
"reason": "read error",
|
|
}).Error("error parsing router info size")
|
|
}
|
|
info.size = size
|
|
if err != nil {
|
|
log.WithFields(log.Fields{
|
|
"at": "(RouterInfo) ReadRouterInfo",
|
|
"data_len": len(remainder),
|
|
"required_len": size.Int(),
|
|
"reason": "not enough data",
|
|
}).Error("error parsing router info")
|
|
err = errors.New("error parsing router info: not enough data")
|
|
}
|
|
for i := 0; i < size.Int(); i++ {
|
|
address, more, err := NewRouterAddress(remainder)
|
|
remainder = more
|
|
if err != nil {
|
|
log.WithFields(log.Fields{
|
|
"at": "(RouterInfo) ReadRouterInfo",
|
|
"data_len": len(remainder),
|
|
//"required_len": ROUTER_ADDRESS_SIZE,
|
|
"reason": "not enough data",
|
|
}).Error("error parsing router address")
|
|
err = errors.New("error parsing router info: not enough data")
|
|
}
|
|
info.addresses = append(info.addresses, address)
|
|
}
|
|
info.peer_size, remainder, err = NewInteger(remainder, 1)
|
|
var errs []error
|
|
info.options, remainder, errs = NewMapping(remainder)
|
|
if len(errs) != 0 {
|
|
log.WithFields(log.Fields{
|
|
"at": "(RouterInfo) ReadRouterInfo",
|
|
"data_len": len(remainder),
|
|
//"required_len": MAPPING_SIZE,
|
|
"reason": "not enough data",
|
|
}).Error("error parsing router info")
|
|
estring := ""
|
|
for _, e := range errs {
|
|
estring += e.Error() + " "
|
|
}
|
|
err = errors.New("error parsing router info: " + estring)
|
|
}
|
|
if err != nil {
|
|
log.WithFields(log.Fields{
|
|
"at": "(RouterInfo) ReadRouterInfo",
|
|
"data_len": len(remainder),
|
|
//"required_len": MAPPING_SIZE,
|
|
"reason": "not enough data",
|
|
}).Error("error parsing router info")
|
|
err = errors.New("error parsing router info: not enough data")
|
|
}
|
|
return
|
|
}
|
|
|
|
func (router_info *RouterInfo) RouterCapabilities() string {
|
|
str, err := ToI2PString("caps")
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return string(router_info.options.Values().Get(str))
|
|
}
|
|
|
|
func (router_info *RouterInfo) RouterVersion() string {
|
|
str, err := ToI2PString("router.version")
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return string(router_info.options.Values().Get(str))
|
|
}
|
|
|
|
func (router_info *RouterInfo) GoodVersion() bool {
|
|
version := router_info.RouterVersion()
|
|
v := strings.Split(version, ".")
|
|
if len(v) != 3 {
|
|
return false
|
|
}
|
|
if v[0] == "0" {
|
|
if v[1] == "9" {
|
|
val, _ := strconv.Atoi(v[2])
|
|
if val >= MIN_GOOD_VERSION && val <= MAX_GOOD_VERSION {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (router_info *RouterInfo) UnCongested() bool {
|
|
caps := router_info.RouterCapabilities()
|
|
if strings.Contains(caps, "K") {
|
|
return false
|
|
}
|
|
if strings.Contains(caps, "G") {
|
|
return false
|
|
}
|
|
if strings.Contains(caps, "E") {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (router_info *RouterInfo) Reachable() bool {
|
|
caps := router_info.RouterCapabilities()
|
|
if strings.Contains(caps, "U") {
|
|
return false
|
|
}
|
|
return strings.Contains(caps, "R")
|
|
}
|
|
|
|
// NewRouterInfo creates a new *RouterInfo from []byte using ReadRouterInfo.
|
|
// Returns a pointer to RouterInfo unlike ReadRouterInfo.
|
|
func NewRouterInfo(data []byte) (router_info *RouterInfo, remainder []byte, err error) {
|
|
routerInfo, remainder, err := ReadRouterInfo(data)
|
|
router_info = &routerInfo
|
|
return
|
|
}
|