138 lines
3.1 KiB
Go
138 lines
3.1 KiB
Go
package channeldb
|
|
|
|
import (
|
|
"io"
|
|
"net"
|
|
|
|
"github.com/btcsuite/go-socks/socks"
|
|
)
|
|
|
|
// addressType specifies the network protocol and version that should be used
|
|
// when connecting to a node at a particular address.
|
|
type addressType uint8
|
|
|
|
const (
|
|
// tcp4Addr denotes an IPv4 TCP address.
|
|
tcp4Addr addressType = 0
|
|
|
|
// tcp6Addr denotes an IPv6 TCP address.
|
|
tcp6Addr addressType = 1
|
|
|
|
// v2OnionAddr denotes a version 2 Tor onion service address.
|
|
v2OnionAddr addressType = 2
|
|
|
|
// v3OnionAddr denotes a version 3 Tor (prop224) onion service addresses.
|
|
v3OnionAddr addressType = 3
|
|
)
|
|
|
|
func encodeTCPAddr(w io.Writer, addr *net.TCPAddr) error {
|
|
var scratch [16]byte
|
|
|
|
if addr.IP.To4() != nil {
|
|
scratch[0] = uint8(tcp4Addr)
|
|
if _, err := w.Write(scratch[:1]); err != nil {
|
|
return err
|
|
}
|
|
|
|
copy(scratch[:4], addr.IP.To4())
|
|
if _, err := w.Write(scratch[:4]); err != nil {
|
|
return err
|
|
}
|
|
|
|
} else {
|
|
scratch[0] = uint8(tcp6Addr)
|
|
if _, err := w.Write(scratch[:1]); err != nil {
|
|
return err
|
|
}
|
|
|
|
copy(scratch[:], addr.IP.To16())
|
|
if _, err := w.Write(scratch[:]); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
byteOrder.PutUint16(scratch[:2], uint16(addr.Port))
|
|
if _, err := w.Write(scratch[:2]); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// deserializeAddr reads the serialized raw representation of an address and
|
|
// deserializes it into the actual address, to avoid performing address
|
|
// resolution in the database module
|
|
func deserializeAddr(r io.Reader) (net.Addr, error) {
|
|
var scratch [8]byte
|
|
var address net.Addr
|
|
|
|
if _, err := r.Read(scratch[:1]); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// TODO(roasbeef): also add onion addrs
|
|
switch addressType(scratch[0]) {
|
|
case tcp4Addr:
|
|
addr := &net.TCPAddr{}
|
|
var ip [4]byte
|
|
if _, err := r.Read(ip[:]); err != nil {
|
|
return nil, err
|
|
}
|
|
addr.IP = (net.IP)(ip[:])
|
|
if _, err := r.Read(scratch[:2]); err != nil {
|
|
return nil, err
|
|
}
|
|
addr.Port = int(byteOrder.Uint16(scratch[:2]))
|
|
address = addr
|
|
case tcp6Addr:
|
|
addr := &net.TCPAddr{}
|
|
var ip [16]byte
|
|
if _, err := r.Read(ip[:]); err != nil {
|
|
return nil, err
|
|
}
|
|
addr.IP = (net.IP)(ip[:])
|
|
if _, err := r.Read(scratch[:2]); err != nil {
|
|
return nil, err
|
|
}
|
|
addr.Port = int(byteOrder.Uint16(scratch[:2]))
|
|
address = addr
|
|
default:
|
|
return nil, ErrUnknownAddressType
|
|
}
|
|
|
|
return address, nil
|
|
}
|
|
|
|
// serializeAddr serializes an address into a raw byte representation so it
|
|
// can be deserialized without requiring address resolution
|
|
func serializeAddr(w io.Writer, address net.Addr) error {
|
|
|
|
switch addr := address.(type) {
|
|
case *net.TCPAddr:
|
|
return encodeTCPAddr(w, addr)
|
|
|
|
// If this is a proxied address (due to the connection being
|
|
// established over a SOCKs proxy, then we'll convert it into its
|
|
// corresponding TCP address.
|
|
case *socks.ProxiedAddr:
|
|
// If we can't parse the host as an IP (though we should be
|
|
// able to at this point), then we'll skip this address all
|
|
// together.
|
|
//
|
|
// TODO(roasbeef): would be nice to be able to store hosts
|
|
// though...
|
|
ip := net.ParseIP(addr.Host)
|
|
if ip == nil {
|
|
return nil
|
|
}
|
|
|
|
tcpAddr := &net.TCPAddr{
|
|
IP: ip,
|
|
Port: addr.Port,
|
|
}
|
|
return encodeTCPAddr(w, tcpAddr)
|
|
}
|
|
|
|
return nil
|
|
}
|