channeldb: implement serialization of onion addresses
Co-Authored-By: Eugene <crypt-iq@users.noreply.github.com>
This commit is contained in:
parent
e5987a1ef1
commit
3738e68ae2
@ -1,10 +1,12 @@
|
||||
package channeldb
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
|
||||
"github.com/btcsuite/go-socks/socks"
|
||||
"github.com/lightningnetwork/lnd/tor"
|
||||
)
|
||||
|
||||
// addressType specifies the network protocol and version that should be used
|
||||
@ -21,38 +23,75 @@ const (
|
||||
// v2OnionAddr denotes a version 2 Tor onion service address.
|
||||
v2OnionAddr addressType = 2
|
||||
|
||||
// v3OnionAddr denotes a version 3 Tor (prop224) onion service addresses.
|
||||
// v3OnionAddr denotes a version 3 Tor (prop224) onion service address.
|
||||
v3OnionAddr addressType = 3
|
||||
)
|
||||
|
||||
// encodeTCPAddr serializes a TCP address into its compact raw bytes
|
||||
// representation.
|
||||
func encodeTCPAddr(w io.Writer, addr *net.TCPAddr) error {
|
||||
var scratch [16]byte
|
||||
var (
|
||||
addrType byte
|
||||
ip []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
|
||||
}
|
||||
|
||||
addrType = byte(tcp4Addr)
|
||||
ip = addr.IP.To4()
|
||||
} 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
|
||||
}
|
||||
addrType = byte(tcp6Addr)
|
||||
ip = addr.IP.To16()
|
||||
}
|
||||
|
||||
byteOrder.PutUint16(scratch[:2], uint16(addr.Port))
|
||||
if _, err := w.Write(scratch[:2]); err != nil {
|
||||
if _, err := w.Write([]byte{addrType}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := w.Write(ip); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var port [2]byte
|
||||
byteOrder.PutUint16(port[:], uint16(addr.Port))
|
||||
if _, err := w.Write(port[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// encodeOnionAddr serializes an onion address into its compact raw bytes
|
||||
// representation.
|
||||
func encodeOnionAddr(w io.Writer, addr *tor.OnionAddr) error {
|
||||
var suffixIndex int
|
||||
switch len(addr.OnionService) {
|
||||
case tor.V2Len:
|
||||
if _, err := w.Write([]byte{byte(v2OnionAddr)}); err != nil {
|
||||
return err
|
||||
}
|
||||
suffixIndex = tor.V2Len - tor.OnionSuffixLen
|
||||
case tor.V3Len:
|
||||
if _, err := w.Write([]byte{byte(v3OnionAddr)}); err != nil {
|
||||
return err
|
||||
}
|
||||
suffixIndex = tor.V3Len - tor.OnionSuffixLen
|
||||
default:
|
||||
return errors.New("unknown onion service length")
|
||||
}
|
||||
|
||||
host, err := tor.Base32Encoding.DecodeString(
|
||||
addr.OnionService[:suffixIndex],
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write(host); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var port [2]byte
|
||||
byteOrder.PutUint16(port[:], uint16(addr.Port))
|
||||
if _, err := w.Write(port[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -60,42 +99,84 @@ func encodeTCPAddr(w io.Writer, addr *net.TCPAddr) error {
|
||||
}
|
||||
|
||||
// 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
|
||||
// deserializes it into the actual address. This allows us to avoid address
|
||||
// resolution within the channeldb package.
|
||||
func deserializeAddr(r io.Reader) (net.Addr, error) {
|
||||
var scratch [8]byte
|
||||
var address net.Addr
|
||||
|
||||
if _, err := r.Read(scratch[:1]); err != nil {
|
||||
var addrType [1]byte
|
||||
if _, err := r.Read(addrType[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO(roasbeef): also add onion addrs
|
||||
switch addressType(scratch[0]) {
|
||||
var address net.Addr
|
||||
switch addressType(addrType[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 {
|
||||
|
||||
var port [2]byte
|
||||
if _, err := r.Read(port[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addr.Port = int(byteOrder.Uint16(scratch[:2]))
|
||||
address = addr
|
||||
|
||||
address = &net.TCPAddr{
|
||||
IP: net.IP(ip[:]),
|
||||
Port: int(binary.BigEndian.Uint16(port[:])),
|
||||
}
|
||||
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 {
|
||||
|
||||
var port [2]byte
|
||||
if _, err := r.Read(port[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addr.Port = int(byteOrder.Uint16(scratch[:2]))
|
||||
address = addr
|
||||
|
||||
address = &net.TCPAddr{
|
||||
IP: net.IP(ip[:]),
|
||||
Port: int(binary.BigEndian.Uint16(port[:])),
|
||||
}
|
||||
case v2OnionAddr:
|
||||
var h [tor.V2DecodedLen]byte
|
||||
if _, err := r.Read(h[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var p [2]byte
|
||||
if _, err := r.Read(p[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
onionService := tor.Base32Encoding.EncodeToString(h[:])
|
||||
onionService += tor.OnionSuffix
|
||||
port := int(binary.BigEndian.Uint16(p[:]))
|
||||
|
||||
address = &tor.OnionAddr{
|
||||
OnionService: onionService,
|
||||
Port: port,
|
||||
}
|
||||
case v3OnionAddr:
|
||||
var h [tor.V3DecodedLen]byte
|
||||
if _, err := r.Read(h[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var p [2]byte
|
||||
if _, err := r.Read(p[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
onionService := tor.Base32Encoding.EncodeToString(h[:])
|
||||
onionService += tor.OnionSuffix
|
||||
port := int(binary.BigEndian.Uint16(p[:]))
|
||||
|
||||
address = &tor.OnionAddr{
|
||||
OnionService: onionService,
|
||||
Port: port,
|
||||
}
|
||||
default:
|
||||
return nil, ErrUnknownAddressType
|
||||
}
|
||||
@ -103,34 +184,14 @@ func deserializeAddr(r io.Reader) (net.Addr, error) {
|
||||
return address, nil
|
||||
}
|
||||
|
||||
// serializeAddr serializes an address into a raw byte representation so it
|
||||
// can be deserialized without requiring address resolution
|
||||
// serializeAddr serializes an address into its raw bytes representation so that
|
||||
// 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)
|
||||
case *tor.OnionAddr:
|
||||
return encodeOnionAddr(w, addr)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
Loading…
Reference in New Issue
Block a user