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
|
package channeldb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/btcsuite/go-socks/socks"
|
"github.com/lightningnetwork/lnd/tor"
|
||||||
)
|
)
|
||||||
|
|
||||||
// addressType specifies the network protocol and version that should be used
|
// 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 denotes a version 2 Tor onion service address.
|
||||||
v2OnionAddr addressType = 2
|
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
|
v3OnionAddr addressType = 3
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// encodeTCPAddr serializes a TCP address into its compact raw bytes
|
||||||
|
// representation.
|
||||||
func encodeTCPAddr(w io.Writer, addr *net.TCPAddr) error {
|
func encodeTCPAddr(w io.Writer, addr *net.TCPAddr) error {
|
||||||
var scratch [16]byte
|
var (
|
||||||
|
addrType byte
|
||||||
|
ip []byte
|
||||||
|
)
|
||||||
|
|
||||||
if addr.IP.To4() != nil {
|
if addr.IP.To4() != nil {
|
||||||
scratch[0] = uint8(tcp4Addr)
|
addrType = byte(tcp4Addr)
|
||||||
if _, err := w.Write(scratch[:1]); err != nil {
|
ip = addr.IP.To4()
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
copy(scratch[:4], addr.IP.To4())
|
|
||||||
if _, err := w.Write(scratch[:4]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
scratch[0] = uint8(tcp6Addr)
|
addrType = byte(tcp6Addr)
|
||||||
if _, err := w.Write(scratch[:1]); err != nil {
|
ip = addr.IP.To16()
|
||||||
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([]byte{addrType}); err != nil {
|
||||||
if _, err := w.Write(scratch[:2]); 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
|
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
|
// deserializeAddr reads the serialized raw representation of an address and
|
||||||
// deserializes it into the actual address, to avoid performing address
|
// deserializes it into the actual address. This allows us to avoid address
|
||||||
// resolution in the database module
|
// resolution within the channeldb package.
|
||||||
func deserializeAddr(r io.Reader) (net.Addr, error) {
|
func deserializeAddr(r io.Reader) (net.Addr, error) {
|
||||||
var scratch [8]byte
|
var addrType [1]byte
|
||||||
var address net.Addr
|
if _, err := r.Read(addrType[:]); err != nil {
|
||||||
|
|
||||||
if _, err := r.Read(scratch[:1]); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(roasbeef): also add onion addrs
|
var address net.Addr
|
||||||
switch addressType(scratch[0]) {
|
switch addressType(addrType[0]) {
|
||||||
case tcp4Addr:
|
case tcp4Addr:
|
||||||
addr := &net.TCPAddr{}
|
|
||||||
var ip [4]byte
|
var ip [4]byte
|
||||||
if _, err := r.Read(ip[:]); err != nil {
|
if _, err := r.Read(ip[:]); err != nil {
|
||||||
return nil, err
|
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
|
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:
|
case tcp6Addr:
|
||||||
addr := &net.TCPAddr{}
|
|
||||||
var ip [16]byte
|
var ip [16]byte
|
||||||
if _, err := r.Read(ip[:]); err != nil {
|
if _, err := r.Read(ip[:]); err != nil {
|
||||||
return nil, err
|
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
|
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:
|
default:
|
||||||
return nil, ErrUnknownAddressType
|
return nil, ErrUnknownAddressType
|
||||||
}
|
}
|
||||||
@ -103,34 +184,14 @@ func deserializeAddr(r io.Reader) (net.Addr, error) {
|
|||||||
return address, nil
|
return address, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// serializeAddr serializes an address into a raw byte representation so it
|
// serializeAddr serializes an address into its raw bytes representation so that
|
||||||
// can be deserialized without requiring address resolution
|
// it can be deserialized without requiring address resolution.
|
||||||
func serializeAddr(w io.Writer, address net.Addr) error {
|
func serializeAddr(w io.Writer, address net.Addr) error {
|
||||||
|
|
||||||
switch addr := address.(type) {
|
switch addr := address.(type) {
|
||||||
case *net.TCPAddr:
|
case *net.TCPAddr:
|
||||||
return encodeTCPAddr(w, addr)
|
return encodeTCPAddr(w, addr)
|
||||||
|
case *tor.OnionAddr:
|
||||||
// If this is a proxied address (due to the connection being
|
return encodeOnionAddr(w, addr)
|
||||||
// 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
|
return nil
|
||||||
|
Loading…
Reference in New Issue
Block a user