All peerstore records encode/decode tests pass
This commit is contained in:
@@ -5,21 +5,23 @@ import (
|
||||
"github.com/indra-labs/indra/pkg/crypto"
|
||||
"github.com/indra-labs/indra/pkg/crypto/nonce"
|
||||
"github.com/indra-labs/indra/pkg/crypto/sha256"
|
||||
"github.com/indra-labs/indra/pkg/engine/coding"
|
||||
"github.com/indra-labs/indra/pkg/engine/magic"
|
||||
"github.com/indra-labs/indra/pkg/engine/sess"
|
||||
"github.com/indra-labs/indra/pkg/engine/sessions"
|
||||
"github.com/indra-labs/indra/pkg/util/qu"
|
||||
"github.com/indra-labs/indra/pkg/util/slice"
|
||||
"github.com/indra-labs/indra/pkg/util/splice"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
"net/netip"
|
||||
"time"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
const (
|
||||
AddressAdMagic = "adad"
|
||||
AddressAdLen = nonce.IDLen +
|
||||
AddressAdLen = magic.Len +
|
||||
nonce.IDLen +
|
||||
crypto.PubKeyLen +
|
||||
splice.AddrLen + 1 +
|
||||
slice.Uint64Len +
|
||||
crypto.SigLen
|
||||
)
|
||||
|
||||
@@ -28,80 +30,143 @@ const (
|
||||
// address. This means hidden service introducers for values over zero.
|
||||
// Hidden services have no value in the zero index, which is "<hash>/address/0".
|
||||
type AddressAd struct {
|
||||
ID nonce.ID // To ensure no repeating message
|
||||
Multiaddr multiaddr.Multiaddr // We only use a netip.AddrPort though.
|
||||
Index byte // This is the index in the slice from Peer.
|
||||
Expiry time.Time // zero for relay's public address (32 bit).
|
||||
Sig crypto.SigBytes
|
||||
ID nonce.ID // To ensure no repeating message
|
||||
Key *crypto.Pub
|
||||
Addr multiaddr.Multiaddr
|
||||
Sig crypto.SigBytes
|
||||
}
|
||||
|
||||
func (x *AddressAd) Account(res *sess.Data, sm *sess.Manager, s *sessions.Data,
|
||||
last bool) (skip bool, sd *sessions.Data) {
|
||||
|
||||
return false, nil
|
||||
func AddKeyToMultiaddr(in multiaddr.Multiaddr, pub *crypto.Pub) (ma multiaddr.Multiaddr) {
|
||||
var pid peer.ID
|
||||
var e error
|
||||
if pid, e = peer.IDFromPublicKey(pub); fails(e) {
|
||||
return
|
||||
}
|
||||
var k multiaddr.Multiaddr
|
||||
if k, e = multiaddr.NewMultiaddr("/p2p/" + pid.String()); fails(e) {
|
||||
return
|
||||
}
|
||||
ma = in.Encapsulate(k)
|
||||
return
|
||||
}
|
||||
|
||||
func (x *AddressAd) Decode(s *splice.Splice) (e error) {
|
||||
var addr *netip.AddrPort
|
||||
s.ReadID(&x.ID).ReadAddrPort(&addr).ReadByte(&x.Index).ReadTime(&x.Expiry)
|
||||
if e = magic.TooShort(s.Remaining(), AddressAdLen-magic.Len,
|
||||
PeerMagic); fails(e) {
|
||||
|
||||
return
|
||||
}
|
||||
addr := &netip.AddrPort{}
|
||||
s.ReadID(&x.ID).
|
||||
ReadPubkey(&x.Key).
|
||||
ReadAddrPort(&addr).
|
||||
ReadSignature(&x.Sig)
|
||||
//cid.Parse(x.Key.ToBytes())
|
||||
var ap multiaddr.Multiaddr
|
||||
proto := "ip4"
|
||||
if addr.Addr().Is6() {
|
||||
proto = "ip6"
|
||||
}
|
||||
if ap, e = multiaddr.NewMultiaddr(
|
||||
"/" + proto + "/" + addr.Addr().String() +
|
||||
"/tcp/" + fmt.Sprint(addr.Port()),
|
||||
); fails(e) {
|
||||
return
|
||||
}
|
||||
x.Addr = AddKeyToMultiaddr(ap, x.Key)
|
||||
return
|
||||
}
|
||||
|
||||
func (x *AddressAd) Encode(s *splice.Splice) (e error) {
|
||||
x.Splice(s.Magic(AddressAdMagic))
|
||||
log.T.S("encoding", reflect.TypeOf(x),
|
||||
x.ID, x.Sig,
|
||||
)
|
||||
x.Splice(s)
|
||||
return
|
||||
}
|
||||
|
||||
func (x *AddressAd) GetOnion() interface{} { return nil }
|
||||
func (x *AddressAd) Gossip(sm *sess.Manager, c qu.C) {}
|
||||
func (x *AddressAd) Handle(s *splice.Splice, p Onion, ni Ngin) (e error) { return nil }
|
||||
func (x *AddressAd) Len() int { return AddressAdLen }
|
||||
func (x *AddressAd) Magic() string { return "" }
|
||||
func (x *AddressAd) GetOnion() interface{} { return x }
|
||||
|
||||
func (x *AddressAd) Sign(prv *crypto.Prv) (e error) {
|
||||
s := splice.New(x.Len())
|
||||
if e = x.Encode(s); fails(e) {
|
||||
return
|
||||
}
|
||||
var b []byte
|
||||
if b, e = prv.Sign(s.GetUntil(s.GetCursor())); fails(e) {
|
||||
return
|
||||
}
|
||||
if len(b) != crypto.SigLen {
|
||||
return fmt.Errorf("signature incorrect length, got %d expected %d",
|
||||
len(b), crypto.SigLen)
|
||||
}
|
||||
copy(x.Sig[:], b)
|
||||
return nil
|
||||
func (x *AddressAd) Gossip(sm *sess.Manager, c qu.C) {
|
||||
log.D.F("propagating peer info for %s",
|
||||
x.Key.ToBased32Abbreviated())
|
||||
Gossip(x, sm, c)
|
||||
log.T.Ln("finished broadcasting peer info")
|
||||
}
|
||||
|
||||
func (x *AddressAd) Len() int { return AddressAdLen }
|
||||
|
||||
func (x *AddressAd) Magic() string { return AddressAdMagic }
|
||||
|
||||
func (x *AddressAd) Splice(s *splice.Splice) {
|
||||
x.SpliceWithoutSig(s)
|
||||
s.Signature(x.Sig)
|
||||
}
|
||||
|
||||
func (x *AddressAd) SpliceWithoutSig(s *splice.Splice) {
|
||||
var e error
|
||||
var ip, port string
|
||||
if ip, e = x.Multiaddr.ValueForProtocol(multiaddr.P_IP4); fails(e) {
|
||||
var ap netip.AddrPort
|
||||
if ap, e = MultiaddrToAddrPort(x.Addr); fails(e) {
|
||||
return
|
||||
}
|
||||
if ip == "" {
|
||||
if ip, e = x.Multiaddr.ValueForProtocol(multiaddr.P_IP6); fails(e) {
|
||||
s.Magic(AddressAdMagic).
|
||||
ID(x.ID).
|
||||
Pubkey(x.Key).
|
||||
AddrPort(&ap)
|
||||
}
|
||||
|
||||
func (x *AddressAd) Validate() bool {
|
||||
s := splice.New(AddressAdLen - magic.Len)
|
||||
x.SpliceWithoutSig(s)
|
||||
hash := sha256.Single(s.GetUntil(s.GetCursor()))
|
||||
key, e := x.Sig.Recover(hash)
|
||||
if fails(e) {
|
||||
return false
|
||||
}
|
||||
if key.Equals(x.Key) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func MultiaddrToAddrPort(ma multiaddr.Multiaddr) (ap netip.AddrPort, e error) {
|
||||
var addrStr string
|
||||
if addrStr, e = ma.ValueForProtocol(multiaddr.P_IP4); fails(e) {
|
||||
if addrStr, e = ma.ValueForProtocol(multiaddr.P_IP6); fails(e) {
|
||||
return
|
||||
}
|
||||
}
|
||||
// There is really no alternative to TCP so, TCP it is.
|
||||
if port, e = x.Multiaddr.ValueForProtocol(multiaddr.P_TCP); fails(e) {
|
||||
var portStr string
|
||||
if portStr, e = ma.ValueForProtocol(multiaddr.P_TCP); fails(e) {
|
||||
return
|
||||
}
|
||||
var addr netip.AddrPort
|
||||
if addr, e = netip.ParseAddrPort(ip + ":" + port); fails(e) {
|
||||
}
|
||||
s.ID(x.ID).AddrPort(&addr).Byte(x.Index).Time(x.Expiry)
|
||||
}
|
||||
|
||||
func (x *AddressAd) Validate(s *splice.Splice) (pub *crypto.Pub) {
|
||||
h := sha256.Single(s.GetRange(0, nonce.IDLen+splice.AddrLen+1+
|
||||
slice.Uint64Len))
|
||||
var e error
|
||||
if pub, e = x.Sig.Recover(h); fails(e) {
|
||||
if ap, e = netip.ParseAddrPort(addrStr + ":" + portStr); fails(e) {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (x *AddressAd) Wrap(inner Onion) {}
|
||||
func NewAddressAd(id nonce.ID, key *crypto.Prv,
|
||||
ma multiaddr.Multiaddr) (peerAd *AddressAd) {
|
||||
|
||||
pub := crypto.DerivePub(key)
|
||||
ma = AddKeyToMultiaddr(ma, pub)
|
||||
log.D.Ln("ma", ma)
|
||||
peerAd = &AddressAd{
|
||||
ID: id,
|
||||
Key: pub,
|
||||
Addr: ma,
|
||||
}
|
||||
s := splice.New(IntroLen - magic.Len)
|
||||
peerAd.SpliceWithoutSig(s)
|
||||
hash := sha256.Single(s.GetUntil(s.GetCursor()))
|
||||
var e error
|
||||
if peerAd.Sig, e = crypto.Sign(key, hash); fails(e) {
|
||||
return nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func addrGen() coding.Codec { return &AddressAd{} }
|
||||
|
||||
func init() { Register(AddressAdMagic, addrGen) }
|
||||
|
||||
62
pkg/engine/onions/adaddress_test.go
Normal file
62
pkg/engine/onions/adaddress_test.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package onions
|
||||
|
||||
import (
|
||||
"github.com/indra-labs/indra/pkg/crypto"
|
||||
"github.com/indra-labs/indra/pkg/crypto/nonce"
|
||||
"github.com/indra-labs/indra/pkg/engine/coding"
|
||||
log2 "github.com/indra-labs/indra/pkg/proc/log"
|
||||
"github.com/indra-labs/indra/pkg/util/splice"
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAdAddress(t *testing.T) {
|
||||
log2.SetLogLevel(log2.Trace)
|
||||
var e error
|
||||
pr, _, _ := crypto.NewSigner()
|
||||
id := nonce.NewID()
|
||||
var ma multiaddr.Multiaddr
|
||||
if ma, e = multiaddr.NewMultiaddr("/ip4/127.0.0.1/tcp/4242"); fails(e) {
|
||||
t.FailNow()
|
||||
}
|
||||
aa := NewAddressAd(id, pr, ma)
|
||||
log.D.S("ad", aa)
|
||||
s := splice.New(aa.Len())
|
||||
if e = aa.Encode(s); fails(e) {
|
||||
t.FailNow()
|
||||
}
|
||||
s.SetCursor(0)
|
||||
var onc coding.Codec
|
||||
if onc = Recognise(s); onc == nil {
|
||||
t.Error("did not unwrap")
|
||||
t.FailNow()
|
||||
}
|
||||
if e = onc.Decode(s); fails(e) {
|
||||
t.Error("did not decode")
|
||||
t.FailNow()
|
||||
}
|
||||
log.D.S(onc)
|
||||
var ad *AddressAd
|
||||
var ok bool
|
||||
if ad, ok = onc.(*AddressAd); !ok {
|
||||
t.Error("did not unwrap expected type")
|
||||
t.FailNow()
|
||||
}
|
||||
if ad.ID != aa.ID {
|
||||
t.Errorf("ID did not decode correctly")
|
||||
t.FailNow()
|
||||
}
|
||||
if ad.Addr.String() != aa.Addr.String() {
|
||||
t.Errorf("address did not decode correctly")
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if !ad.Key.Equals(crypto.DerivePub(pr)) {
|
||||
t.Errorf("public key did not decode correctly")
|
||||
t.FailNow()
|
||||
}
|
||||
if !ad.Validate() {
|
||||
t.Errorf("received ad did not validate")
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/indra-labs/indra/pkg/engine/coding"
|
||||
"github.com/indra-labs/indra/pkg/engine/magic"
|
||||
"github.com/indra-labs/indra/pkg/engine/sess"
|
||||
"github.com/indra-labs/indra/pkg/engine/sessions"
|
||||
"github.com/indra-labs/indra/pkg/util/qu"
|
||||
"github.com/indra-labs/indra/pkg/util/slice"
|
||||
"github.com/indra-labs/indra/pkg/util/splice"
|
||||
@@ -39,16 +38,7 @@ type IntroAd struct {
|
||||
Sig crypto.SigBytes
|
||||
}
|
||||
|
||||
func (x *IntroAd) Account(
|
||||
res *sess.Data,
|
||||
sm *sess.Manager,
|
||||
s *sessions.Data,
|
||||
last bool,
|
||||
) (skip bool, sd *sessions.Data) {
|
||||
|
||||
res.ID = x.ID
|
||||
return
|
||||
}
|
||||
var _ coding.Codec = &IntroAd{}
|
||||
|
||||
func (x *IntroAd) Decode(s *splice.Splice) (e error) {
|
||||
if e = magic.TooShort(s.Remaining(), IntroLen-magic.Len,
|
||||
@@ -84,41 +74,7 @@ func (x *IntroAd) Gossip(sm *sess.Manager, c qu.C) {
|
||||
x.Key.ToBased32Abbreviated())
|
||||
}
|
||||
|
||||
func (x *IntroAd) Handle(s *splice.Splice, p Onion, ng Ngin) (e error) {
|
||||
log.D.Ln("handling intro")
|
||||
ng.GetHidden().Lock()
|
||||
valid := x.Validate()
|
||||
if valid {
|
||||
|
||||
// Add to our current peer state advertisements.
|
||||
_ = valid
|
||||
|
||||
log.D.Ln(ng.Mgr().GetLocalNodeAddressString(), "validated intro", x.ID)
|
||||
kb := x.Key.ToBytes()
|
||||
if _, ok := ng.GetHidden().KnownIntros[x.Key.ToBytes()]; ok {
|
||||
log.D.Ln(ng.Mgr().GetLocalNodeAddressString(), "already have intro")
|
||||
ng.Pending().ProcessAndDelete(x.ID, &kb, s.GetAll())
|
||||
ng.GetHidden().Unlock()
|
||||
return
|
||||
}
|
||||
log.D.F("%s storing intro for %s %s",
|
||||
ng.Mgr().GetLocalNodeAddressString(), x.Key.ToBased32Abbreviated(),
|
||||
x.ID)
|
||||
ng.GetHidden().KnownIntros[x.Key.ToBytes()] = x
|
||||
var ok bool
|
||||
if ok, e = ng.Pending().ProcessAndDelete(x.ID, &kb,
|
||||
s.GetAll()); ok || !fails(e) {
|
||||
|
||||
ng.GetHidden().Unlock()
|
||||
log.D.Ln("deleted pending response", x.ID)
|
||||
return
|
||||
}
|
||||
}
|
||||
ng.GetHidden().Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
func (x *IntroAd) Len() int { return IntroLen }
|
||||
func (x *IntroAd) Len() int { return IntroLen }
|
||||
|
||||
func (x *IntroAd) Magic() string { return IntroMagic }
|
||||
|
||||
@@ -145,8 +101,6 @@ func (x *IntroAd) Validate() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *IntroAd) Wrap(inner Onion) {}
|
||||
|
||||
func IntroSplice(
|
||||
s *splice.Splice,
|
||||
id nonce.ID,
|
||||
@@ -196,6 +150,6 @@ func NewIntroAd(
|
||||
return
|
||||
}
|
||||
|
||||
func init() { Register(IntroMagic, introGen) }
|
||||
func init() { Register(IntroMagic, introGen) }
|
||||
|
||||
func introGen() coding.Codec { return &IntroAd{} }
|
||||
|
||||
@@ -1,133 +1,114 @@
|
||||
package onions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/indra-labs/indra/pkg/crypto"
|
||||
"github.com/indra-labs/indra/pkg/crypto/nonce"
|
||||
"github.com/indra-labs/indra/pkg/crypto/sha256"
|
||||
"github.com/indra-labs/indra/pkg/engine/coding"
|
||||
"github.com/indra-labs/indra/pkg/engine/magic"
|
||||
"github.com/indra-labs/indra/pkg/engine/sess"
|
||||
"github.com/indra-labs/indra/pkg/engine/sessions"
|
||||
"github.com/indra-labs/indra/pkg/util/qu"
|
||||
"github.com/indra-labs/indra/pkg/util/slice"
|
||||
"github.com/indra-labs/indra/pkg/util/splice"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
const (
|
||||
PeerAdMagic = "prad"
|
||||
PeerAdLen = magic.Len +
|
||||
PeerMagic = "peer"
|
||||
PeerLen = magic.Len +
|
||||
nonce.IDLen +
|
||||
crypto.PubKeyLen +
|
||||
crypto.PubKeyLen + 1 +
|
||||
slice.Uint32Len +
|
||||
crypto.SigLen
|
||||
)
|
||||
|
||||
var _ Ad = &PeerAd{}
|
||||
|
||||
// PeerAd is the root identity document for an Indra peer. It is indexed by the
|
||||
// Identity field, its public key. The slices found below it are derived via
|
||||
// concatenation of strings with the keys and hashing to generate a derived
|
||||
// field index, used to search the DHT for matches.
|
||||
//
|
||||
// The data stored for Peer must be signed with the key claimed by the Identity.
|
||||
// For hidden services the address fields are signed in the DHT by the hidden
|
||||
// service from their introduction solicitation, and the index from the current
|
||||
// set is given by the hidden service.
|
||||
type PeerAd struct {
|
||||
nonce.ID // To ensure no repeating message
|
||||
Identity *crypto.Pub // Must match signature.
|
||||
RelayRate uint32 // Zero means not relaying.
|
||||
ID nonce.ID // This ensures never a repeated signed message.
|
||||
Key *crypto.Pub // Identity key.
|
||||
RelayRate uint32
|
||||
Sig crypto.SigBytes
|
||||
}
|
||||
|
||||
func NewPeerAd(
|
||||
id nonce.ID,
|
||||
key *crypto.Prv,
|
||||
relayRate uint32,
|
||||
) (pa *PeerAd) {
|
||||
func NewPeer(id nonce.ID, key *crypto.Prv,
|
||||
relayRate uint32) (peerAd *PeerAd) {
|
||||
|
||||
pa = &PeerAd{
|
||||
ID: id,
|
||||
Identity: crypto.DerivePub(key),
|
||||
RelayRate: relayRate,
|
||||
}
|
||||
pk := crypto.DerivePub(key)
|
||||
s := splice.New(IntroLen - magic.Len)
|
||||
s.ID(id).
|
||||
Pubkey(pk).
|
||||
Uint32(relayRate)
|
||||
hash := sha256.Single(s.GetUntil(s.GetCursor()))
|
||||
var e error
|
||||
if e = pa.Sign(key); fails(e) {
|
||||
return
|
||||
var sign crypto.SigBytes
|
||||
if sign, e = crypto.Sign(key, hash); fails(e) {
|
||||
return nil
|
||||
}
|
||||
peerAd = &PeerAd{
|
||||
ID: id,
|
||||
Key: pk,
|
||||
RelayRate: relayRate,
|
||||
Sig: sign,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (x *PeerAd) Account(res *sess.Data, sm *sess.Manager, s *sessions.Data, last bool) (skip bool, sd *sessions.Data) {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (x *PeerAd) Decode(s *splice.Splice) (e error) {
|
||||
if e = magic.TooShort(s.Remaining(), PeerLen-magic.Len,
|
||||
PeerMagic); fails(e) {
|
||||
|
||||
return
|
||||
}
|
||||
s.ReadID(&x.ID).
|
||||
ReadPubkey(&x.Identity).
|
||||
ReadPubkey(&x.Key).
|
||||
ReadUint32(&x.RelayRate).
|
||||
ReadSignature(&x.Sig)
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
func (x *PeerAd) Encode(s *splice.Splice) (e error) {
|
||||
s.Magic(PeerAdMagic)
|
||||
x.Splice(s)
|
||||
return nil
|
||||
log.T.S("encoding", reflect.TypeOf(x),
|
||||
x.ID, x.Sig,
|
||||
)
|
||||
x.Splice(s.Magic(PeerMagic))
|
||||
return
|
||||
}
|
||||
|
||||
func (x *PeerAd) GetOnion() interface{} { return nil }
|
||||
func (x *PeerAd) Gossip(sm *sess.Manager, c qu.C) {}
|
||||
func (x *PeerAd) Handle(s *splice.Splice, p Onion, ni Ngin) (e error) {
|
||||
return nil
|
||||
}
|
||||
func (x *PeerAd) Len() int { return PeerAdLen }
|
||||
func (x *PeerAd) Magic() string { return PeerAdMagic }
|
||||
func (x *PeerAd) GetOnion() interface{} { return x }
|
||||
|
||||
func (x *PeerAd) Sign(prv *crypto.Prv) (e error) {
|
||||
s := splice.New(x.Len())
|
||||
if e = x.Encode(s); fails(e) {
|
||||
return
|
||||
}
|
||||
var b []byte
|
||||
if b, e = prv.Sign(s.GetUntil(s.GetCursor())); fails(e) {
|
||||
return
|
||||
}
|
||||
if len(b) != crypto.SigLen {
|
||||
return fmt.Errorf("signature incorrect length, got %d expected %d",
|
||||
len(b), crypto.SigLen)
|
||||
}
|
||||
copy(x.Sig[:], b)
|
||||
return nil
|
||||
func (x *PeerAd) Gossip(sm *sess.Manager, c qu.C) {
|
||||
log.D.F("propagating peer info for %s",
|
||||
x.Key.ToBased32Abbreviated())
|
||||
Gossip(x, sm, c)
|
||||
log.T.Ln("finished broadcasting peer info")
|
||||
}
|
||||
|
||||
func (x *PeerAd) Len() int { return PeerLen }
|
||||
|
||||
func (x *PeerAd) Magic() string { return PeerMagic }
|
||||
|
||||
func (x *PeerAd) Splice(s *splice.Splice) {
|
||||
s.ID(x.ID).
|
||||
Pubkey(x.Identity).
|
||||
Pubkey(x.Key).
|
||||
Uint32(x.RelayRate).
|
||||
Signature(x.Sig)
|
||||
}
|
||||
|
||||
func (x *PeerAd) SpliceNoSig(s *splice.Splice) {
|
||||
func (x *PeerAd) Validate() bool {
|
||||
s := splice.New(PeerLen - magic.Len)
|
||||
s.ID(x.ID).
|
||||
Pubkey(x.Identity).
|
||||
Uint32(x.RelayRate).
|
||||
Signature(x.Sig)
|
||||
}
|
||||
|
||||
func (x *PeerAd) Validate() (valid bool) {
|
||||
s := splice.New(x.Len())
|
||||
x.SpliceNoSig(s)
|
||||
h := sha256.Single(s.GetUntil(s.GetCursor()))
|
||||
var e error
|
||||
var pk *crypto.Pub
|
||||
if pk, e = x.Sig.Recover(h); fails(e) {
|
||||
Pubkey(x.Key).
|
||||
Uint32(x.RelayRate)
|
||||
hash := sha256.Single(s.GetUntil(s.GetCursor()))
|
||||
key, e := x.Sig.Recover(hash)
|
||||
if fails(e) {
|
||||
return false
|
||||
}
|
||||
return pk != nil
|
||||
if key.Equals(x.Key) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *PeerAd) Wrap(inner Onion) {}
|
||||
func init() { Register(PeerAdMagic, peerAdGen) }
|
||||
func peerAdGen() coding.Codec { return &PeerAd{} }
|
||||
func init() { Register(PeerMagic, peerGen) }
|
||||
|
||||
func peerGen() coding.Codec { return &PeerAd{} }
|
||||
|
||||
@@ -9,39 +9,41 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestOnionSkins_PeerAd(t *testing.T) {
|
||||
func TestPeerAd(t *testing.T) {
|
||||
log2.SetLogLevel(log2.Trace)
|
||||
var e error
|
||||
pr, _, _ := crypto.NewSigner()
|
||||
pr, ks, _ := crypto.NewSigner()
|
||||
id := nonce.NewID()
|
||||
peerAd := NewPeerAd(id, pr, 20000)
|
||||
s := splice.New(peerAd.Len())
|
||||
if e = peerAd.Encode(s); fails(e) {
|
||||
t.FailNow()
|
||||
// in := NewPeer(id, pr, time.Now().Add(time.Hour))
|
||||
var prvs crypto.Privs
|
||||
for i := range prvs {
|
||||
prvs[i] = ks.Next()
|
||||
}
|
||||
var pubs crypto.Pubs
|
||||
for i := range pubs {
|
||||
pubs[i] = crypto.DerivePub(prvs[i])
|
||||
}
|
||||
pa := NewPeer(id, pr, 20000)
|
||||
s := splice.New(pa.Len())
|
||||
if e = pa.Encode(s); fails(e) {
|
||||
t.Fatalf("did not encode")
|
||||
}
|
||||
log.D.S(s.GetAll().ToBytes())
|
||||
s.SetCursor(0)
|
||||
var onc coding.Codec
|
||||
if onc = Recognise(s); onc == nil {
|
||||
t.Error("did not unwrap")
|
||||
t.FailNow()
|
||||
t.Fatalf("did not unwrap")
|
||||
}
|
||||
if e = onc.Decode(s); fails(e) {
|
||||
t.Error("did not decode")
|
||||
t.FailNow()
|
||||
t.Fatalf("did not decode")
|
||||
}
|
||||
log.D.S(onc)
|
||||
var pa *PeerAd
|
||||
var peer *PeerAd
|
||||
var ok bool
|
||||
if pa, ok = onc.(*PeerAd); !ok {
|
||||
t.Error("did not unwrap expected type")
|
||||
t.FailNow()
|
||||
if peer, ok = onc.(*PeerAd); !ok {
|
||||
t.Fatal("did not unwrap expected type")
|
||||
}
|
||||
if pa.RelayRate != peerAd.RelayRate {
|
||||
t.Errorf("relay rate did not decode correctly")
|
||||
t.FailNow()
|
||||
}
|
||||
if !pa.Validate() {
|
||||
t.Errorf("received intro did not validate")
|
||||
t.FailNow()
|
||||
if !peer.Validate() {
|
||||
t.Fatalf("received PeerAd did not validate")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/indra-labs/indra/pkg/engine/coding"
|
||||
"github.com/indra-labs/indra/pkg/engine/magic"
|
||||
"github.com/indra-labs/indra/pkg/engine/sess"
|
||||
"github.com/indra-labs/indra/pkg/engine/sessions"
|
||||
"github.com/indra-labs/indra/pkg/util/qu"
|
||||
"github.com/indra-labs/indra/pkg/util/slice"
|
||||
"github.com/indra-labs/indra/pkg/util/splice"
|
||||
@@ -26,7 +25,7 @@ const (
|
||||
|
||||
// ServiceAd stores a specification for the fee rate and the service port, which
|
||||
// must be a well known port to match with a type of service, eg 80 for web, 53
|
||||
// for DNS, etc. These are also attached to the Peer entry via concatenating
|
||||
// for DNS, etc. These are also attached to the PeerAd entry via concatenating
|
||||
// "/service/N" where N is the index of the entry. A zero value at an index
|
||||
// signals to stop scanning for more subsequent values.
|
||||
type ServiceAd struct {
|
||||
@@ -37,6 +36,8 @@ type ServiceAd struct {
|
||||
Sig crypto.SigBytes
|
||||
}
|
||||
|
||||
var _ coding.Codec = &ServiceAd{}
|
||||
|
||||
func NewServiceAd(
|
||||
id nonce.ID,
|
||||
key *crypto.Prv,
|
||||
@@ -63,16 +64,6 @@ func NewServiceAd(
|
||||
return
|
||||
}
|
||||
|
||||
func (x *ServiceAd) Account(
|
||||
res *sess.Data,
|
||||
sm *sess.Manager,
|
||||
s *sessions.Data,
|
||||
last bool,
|
||||
) (skip bool, sd *sessions.Data) {
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (x *ServiceAd) Decode(s *splice.Splice) (e error) {
|
||||
s.ReadID(&x.ID).
|
||||
ReadPubkey(&x.Key).
|
||||
@@ -92,10 +83,6 @@ func (x *ServiceAd) GetOnion() interface{} { return nil }
|
||||
func (x *ServiceAd) Gossip(sm *sess.Manager, c qu.C) {
|
||||
}
|
||||
|
||||
func (x *ServiceAd) Handle(s *splice.Splice, p Onion, ni Ngin) (e error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ServiceAd) Len() int { return ServiceAdLen }
|
||||
|
||||
func (x *ServiceAd) Magic() string { return "" }
|
||||
@@ -140,8 +127,6 @@ func (x *ServiceAd) Validate() (valid bool) {
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *ServiceAd) Wrap(inner Onion) {}
|
||||
|
||||
func ServiceSplice(
|
||||
s *splice.Splice,
|
||||
id nonce.ID,
|
||||
|
||||
@@ -32,7 +32,7 @@ type Onion interface {
|
||||
last bool) (skip bool, sd *sessions.Data)
|
||||
}
|
||||
type Ad interface {
|
||||
Onion
|
||||
coding.Codec
|
||||
Splice(s *splice.Splice)
|
||||
Validate() bool
|
||||
Gossip(sm *sess.Manager, c qu.C)
|
||||
|
||||
@@ -83,9 +83,9 @@ func (x *IntroQuery) Handle(s *splice.Splice, p Onion, ng Ngin) (e error) {
|
||||
return
|
||||
}
|
||||
ng.GetHidden().Unlock()
|
||||
iqr := Encode(il)
|
||||
e = il.Encode(s)
|
||||
rb := FormatReply(GetRoutingHeaderFromCursor(s), x.Ciphers, x.Nonces,
|
||||
iqr.GetAll())
|
||||
s.GetAll())
|
||||
switch on1 := p.(type) {
|
||||
case *Crypt:
|
||||
sess := ng.Mgr().FindSessionByHeader(on1.ToPriv)
|
||||
|
||||
@@ -222,17 +222,6 @@ func (o Skins) HiddenService(in *IntroAd, point *ExitPoint) Skins {
|
||||
})
|
||||
}
|
||||
|
||||
func (o Skins) Intro(id nonce.ID, key *crypto.Prv, ap *netip.AddrPort,
|
||||
expires time.Time) (sk Skins) {
|
||||
return append(o, NewIntroAd(id, key, ap, 0, 0, expires))
|
||||
}
|
||||
|
||||
func (o Skins) PeerAd(id nonce.ID, key *crypto.Prv, ap *netip.AddrPort,
|
||||
relayRate uint32, port uint16, expires time.Time) (sk Skins) {
|
||||
|
||||
return append(o, NewPeerAd(id, key, relayRate))
|
||||
}
|
||||
|
||||
func (o Skins) IntroQuery(id nonce.ID, hsk *crypto.Pub, exit *ExitPoint) Skins {
|
||||
return append(o, &IntroQuery{
|
||||
ID: id,
|
||||
@@ -328,10 +317,6 @@ func (o Skins) Message(msg *Message, ks *crypto.KeySet) Skins {
|
||||
msg)
|
||||
}
|
||||
|
||||
func (o Skins) Peer(id nonce.ID, key *crypto.Prv, relayRate uint32, expires time.Time) (sk Skins) {
|
||||
return append(o, NewPeer(id, key, expires, relayRate))
|
||||
}
|
||||
|
||||
// Ping is a message which checks the liveness of relays by ensuring they are
|
||||
// correctly relaying messages.
|
||||
//
|
||||
|
||||
@@ -1,187 +0,0 @@
|
||||
package onions
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/gookit/color"
|
||||
|
||||
"github.com/indra-labs/indra/pkg/crypto"
|
||||
"github.com/indra-labs/indra/pkg/crypto/nonce"
|
||||
"github.com/indra-labs/indra/pkg/crypto/sha256"
|
||||
"github.com/indra-labs/indra/pkg/engine/coding"
|
||||
"github.com/indra-labs/indra/pkg/engine/magic"
|
||||
"github.com/indra-labs/indra/pkg/engine/node"
|
||||
"github.com/indra-labs/indra/pkg/engine/sess"
|
||||
"github.com/indra-labs/indra/pkg/engine/sessions"
|
||||
"github.com/indra-labs/indra/pkg/util/qu"
|
||||
"github.com/indra-labs/indra/pkg/util/slice"
|
||||
"github.com/indra-labs/indra/pkg/util/splice"
|
||||
)
|
||||
|
||||
const (
|
||||
PeerMagic = "peer"
|
||||
PeerLen = magic.Len +
|
||||
nonce.IDLen +
|
||||
crypto.PubKeyLen + 1 +
|
||||
splice.AddrLen +
|
||||
slice.Uint32Len +
|
||||
slice.Uint64Len +
|
||||
crypto.SigLen
|
||||
)
|
||||
|
||||
type Peer struct {
|
||||
ID nonce.ID // This ensures never a repeated signed message.
|
||||
Key *crypto.Pub // Identity key.
|
||||
AddrPort *netip.AddrPort
|
||||
RelayRate uint32
|
||||
Expiry time.Time
|
||||
Sig crypto.SigBytes
|
||||
}
|
||||
|
||||
func NewPeer(id nonce.ID, key *crypto.Prv, expires time.Time,
|
||||
relayRate uint32) (in *Peer) {
|
||||
|
||||
pk := crypto.DerivePub(key)
|
||||
s := splice.New(IntroLen - magic.Len)
|
||||
s.ID(id).
|
||||
Pubkey(pk).
|
||||
Uint32(relayRate).
|
||||
Uint64(uint64(expires.UnixNano()))
|
||||
hash := sha256.Single(s.GetUntil(s.GetCursor()))
|
||||
var e error
|
||||
var sign crypto.SigBytes
|
||||
if sign, e = crypto.Sign(key, hash); fails(e) {
|
||||
return nil
|
||||
}
|
||||
in = &Peer{
|
||||
ID: id,
|
||||
Key: pk,
|
||||
RelayRate: relayRate,
|
||||
Expiry: expires,
|
||||
Sig: sign,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (x *Peer) Account(res *sess.Data, sm *sess.Manager,
|
||||
s *sessions.Data, last bool) (skip bool, sd *sessions.Data) {
|
||||
|
||||
res.ID = x.ID
|
||||
return
|
||||
}
|
||||
|
||||
func (x *Peer) Decode(s *splice.Splice) (e error) {
|
||||
if e = magic.TooShort(s.Remaining(), PeerLen-magic.Len,
|
||||
PeerMagic); fails(e) {
|
||||
|
||||
return
|
||||
}
|
||||
s.ReadID(&x.ID).
|
||||
ReadPubkey(&x.Key).
|
||||
ReadUint32(&x.RelayRate).
|
||||
ReadTime(&x.Expiry).
|
||||
ReadSignature(&x.Sig)
|
||||
return
|
||||
}
|
||||
|
||||
func (x *Peer) Encode(s *splice.Splice) (e error) {
|
||||
log.T.S("encoding", reflect.TypeOf(x),
|
||||
x.ID, x.Expiry, x.Sig,
|
||||
)
|
||||
x.Splice(s.Magic(PeerMagic))
|
||||
return
|
||||
}
|
||||
|
||||
func (x *Peer) GetOnion() interface{} { return x }
|
||||
|
||||
func (x *Peer) Gossip(sm *sess.Manager, c qu.C) {
|
||||
log.D.F("propagating peer info for %s",
|
||||
x.Key.ToBased32Abbreviated())
|
||||
Gossip(x, sm, c)
|
||||
log.T.Ln("finished broadcasting peer info")
|
||||
}
|
||||
|
||||
func (x *Peer) Handle(s *splice.Splice, p Onion, ng Ngin) (e error) {
|
||||
ng.GetHidden().Lock()
|
||||
valid := x.Validate()
|
||||
if valid {
|
||||
log.T.Ln(ng.Mgr().GetLocalNodeAddressString(), "validated intro", x.ID)
|
||||
kb := x.Key.ToBytes()
|
||||
if _, ok := ng.GetHidden().KnownIntros[x.Key.ToBytes()]; ok {
|
||||
log.D.Ln(ng.Mgr().GetLocalNodeAddressString(), "already have intro")
|
||||
ng.Pending().ProcessAndDelete(x.ID, &kb, s.GetAll())
|
||||
ng.GetHidden().Unlock()
|
||||
return
|
||||
}
|
||||
log.D.F("%s storing intro for %s %s",
|
||||
ng.Mgr().GetLocalNodeAddressString(), x.Key.ToBased32Abbreviated(),
|
||||
x.ID)
|
||||
// ng.GetHidden().KnownIntros[x.Key.ToBytes()] = x
|
||||
var ok bool
|
||||
if ok, e = ng.Pending().ProcessAndDelete(x.ID, &kb,
|
||||
s.GetAll()); ok || fails(e) {
|
||||
|
||||
ng.GetHidden().Unlock()
|
||||
log.D.Ln("deleted pending response", x.ID)
|
||||
return
|
||||
}
|
||||
log.D.F("%s sending out intro to %s to all known peers",
|
||||
ng.Mgr().GetLocalNodeAddressString(), x.Key.ToBased32Abbreviated())
|
||||
sender := ng.Mgr().FindNodeByIdentity(x.Key)
|
||||
nn := make(map[nonce.ID]*node.Node)
|
||||
ng.Mgr().ForEachNode(func(n *node.Node) bool {
|
||||
if n.ID != sender.ID {
|
||||
nn[n.ID] = n
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
counter := 0
|
||||
for i := range nn {
|
||||
log.T.F("sending intro to %s",
|
||||
color.Yellow.Sprint(nn[i].AddrPort.String()))
|
||||
nn[i].Transport.Send(s.GetAll())
|
||||
counter++
|
||||
if counter < 2 {
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
ng.GetHidden().Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
func (x *Peer) Len() int { return PeerLen }
|
||||
func (x *Peer) Magic() string { return PeerMagic }
|
||||
|
||||
func (x *Peer) Splice(s *splice.Splice) {
|
||||
s.ID(x.ID).
|
||||
Pubkey(x.Key).
|
||||
Uint32(x.RelayRate).
|
||||
Uint64(uint64(x.Expiry.UnixNano())).
|
||||
Signature(x.Sig)
|
||||
}
|
||||
|
||||
func (x *Peer) Validate() bool {
|
||||
s := splice.New(PeerLen - magic.Len)
|
||||
s.ID(x.ID).
|
||||
Pubkey(x.Key).
|
||||
Uint32(x.RelayRate).
|
||||
Uint64(uint64(x.Expiry.UnixNano()))
|
||||
hash := sha256.Single(s.GetUntil(s.GetCursor()))
|
||||
key, e := x.Sig.Recover(hash)
|
||||
if fails(e) {
|
||||
return false
|
||||
}
|
||||
if key.Equals(x.Key) && x.Expiry.After(time.Now()) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *Peer) Wrap(inner Onion) {}
|
||||
func init() { Register(PeerMagic, peerGen) }
|
||||
func peerGen() coding.Codec { return &Peer{} }
|
||||
@@ -1,54 +0,0 @@
|
||||
package onions
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/indra-labs/indra/pkg/crypto"
|
||||
"github.com/indra-labs/indra/pkg/crypto/nonce"
|
||||
"github.com/indra-labs/indra/pkg/engine/coding"
|
||||
log2 "github.com/indra-labs/indra/pkg/proc/log"
|
||||
)
|
||||
|
||||
func TestOnionSkins_Peer(t *testing.T) {
|
||||
log2.SetLogLevel(log2.Debug)
|
||||
var e error
|
||||
pr, ks, _ := crypto.NewSigner()
|
||||
id := nonce.NewID()
|
||||
// in := NewPeer(id, pr, time.Now().Add(time.Hour))
|
||||
var prvs crypto.Privs
|
||||
for i := range prvs {
|
||||
prvs[i] = ks.Next()
|
||||
}
|
||||
var pubs crypto.Pubs
|
||||
for i := range pubs {
|
||||
pubs[i] = crypto.DerivePub(prvs[i])
|
||||
}
|
||||
on1 := Skins{}.
|
||||
Peer(id, pr, 20000, time.Now().Add(time.Hour))
|
||||
on1 = append(on1, &End{})
|
||||
on := on1.Assemble()
|
||||
s := Encode(on)
|
||||
log.D.S(s.GetAll().ToBytes())
|
||||
s.SetCursor(0)
|
||||
var onc coding.Codec
|
||||
if onc = Recognise(s); onc == nil {
|
||||
t.Error("did not unwrap")
|
||||
t.FailNow()
|
||||
}
|
||||
if e = onc.Decode(s); fails(e) {
|
||||
t.Error("did not decode")
|
||||
t.FailNow()
|
||||
}
|
||||
log.D.S(onc)
|
||||
var peer *Peer
|
||||
var ok bool
|
||||
if peer, ok = onc.(*Peer); !ok {
|
||||
t.Error("did not unwrap expected type")
|
||||
t.FailNow()
|
||||
}
|
||||
if !peer.Validate() {
|
||||
t.Errorf("received Peer did not validate")
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user