2014-11-09 23:45:16 -08:00
|
|
|
package dht
|
|
|
|
|
|
|
|
import (
|
2016-09-30 10:24:03 -07:00
|
|
|
"context"
|
2014-12-19 12:19:56 -08:00
|
|
|
"fmt"
|
2014-11-09 23:45:16 -08:00
|
|
|
|
2019-05-26 23:33:15 +01:00
|
|
|
"github.com/libp2p/go-libp2p-core/peer"
|
|
|
|
"github.com/libp2p/go-libp2p-core/routing"
|
|
|
|
|
|
|
|
ci "github.com/libp2p/go-libp2p-core/crypto"
|
2014-11-09 23:45:16 -08:00
|
|
|
)
|
|
|
|
|
2018-02-27 17:28:13 -05:00
|
|
|
type pubkrs struct {
|
|
|
|
pubk ci.PubKey
|
|
|
|
err error
|
|
|
|
}
|
|
|
|
|
2015-03-30 10:48:29 -07:00
|
|
|
func (dht *IpfsDHT) GetPublicKey(ctx context.Context, p peer.ID) (ci.PubKey, error) {
|
2019-02-01 17:46:46 +11:00
|
|
|
logger.Debugf("getPublicKey for: %s", p)
|
2014-12-19 12:19:56 -08:00
|
|
|
|
2018-04-16 14:25:00 +09:00
|
|
|
// Check locally. Will also try to extract the public key from the peer
|
|
|
|
// ID itself if possible (if inlined).
|
2018-04-16 14:04:03 +09:00
|
|
|
pk := dht.peerstore.PubKey(p)
|
2014-12-19 12:19:56 -08:00
|
|
|
if pk != nil {
|
|
|
|
return pk, nil
|
|
|
|
}
|
|
|
|
|
2018-02-27 17:28:13 -05:00
|
|
|
// Try getting the public key both directly from the node it identifies
|
|
|
|
// and from the DHT, in parallel
|
2018-03-07 00:13:34 -05:00
|
|
|
ctx, cancel := context.WithCancel(ctx)
|
|
|
|
defer cancel()
|
2018-02-27 17:28:13 -05:00
|
|
|
resp := make(chan pubkrs, 2)
|
|
|
|
go func() {
|
|
|
|
pubk, err := dht.getPublicKeyFromNode(ctx, p)
|
|
|
|
resp <- pubkrs{pubk, err}
|
|
|
|
}()
|
|
|
|
|
2018-03-07 00:13:34 -05:00
|
|
|
// Note that the number of open connections is capped by the dial
|
|
|
|
// limiter, so there is a chance that getPublicKeyFromDHT(), which
|
|
|
|
// potentially opens a lot of connections, will block
|
|
|
|
// getPublicKeyFromNode() from getting a connection.
|
|
|
|
// Currently this doesn't seem to cause an issue so leaving as is
|
|
|
|
// for now.
|
2018-02-27 17:28:13 -05:00
|
|
|
go func() {
|
|
|
|
pubk, err := dht.getPublicKeyFromDHT(ctx, p)
|
|
|
|
resp <- pubkrs{pubk, err}
|
|
|
|
}()
|
|
|
|
|
|
|
|
// Wait for one of the two go routines to return
|
|
|
|
// a public key (or for both to error out)
|
|
|
|
var err error
|
|
|
|
for i := 0; i < 2; i++ {
|
2018-03-07 00:13:34 -05:00
|
|
|
r := <-resp
|
|
|
|
if r.err == nil {
|
|
|
|
// Found the public key
|
|
|
|
err := dht.peerstore.AddPubKey(p, r.pubk)
|
|
|
|
if err != nil {
|
2019-02-01 17:46:46 +11:00
|
|
|
logger.Warningf("Failed to add public key to peerstore for %v", p)
|
2018-02-27 17:28:13 -05:00
|
|
|
}
|
2018-03-07 00:13:34 -05:00
|
|
|
return r.pubk, nil
|
2015-03-30 07:53:14 -07:00
|
|
|
}
|
2018-03-07 00:13:34 -05:00
|
|
|
err = r.err
|
2014-11-11 16:28:20 -08:00
|
|
|
}
|
|
|
|
|
2018-02-27 17:28:13 -05:00
|
|
|
// Both go routines failed to find a public key
|
|
|
|
return nil, err
|
|
|
|
}
|
2014-12-19 12:19:56 -08:00
|
|
|
|
2018-02-27 17:28:13 -05:00
|
|
|
func (dht *IpfsDHT) getPublicKeyFromDHT(ctx context.Context, p peer.ID) (ci.PubKey, error) {
|
|
|
|
// Only retrieve one value, because the public key is immutable
|
|
|
|
// so there's no need to retrieve multiple versions
|
|
|
|
pkkey := routing.KeyForPublicKey(p)
|
2018-05-03 14:19:53 -07:00
|
|
|
val, err := dht.GetValue(ctx, pkkey, Quorum(1))
|
2014-11-11 16:28:20 -08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-05-03 14:19:53 -07:00
|
|
|
pubk, err := ci.UnmarshalPublicKey(val)
|
2014-11-11 16:28:20 -08:00
|
|
|
if err != nil {
|
2019-02-01 17:46:46 +11:00
|
|
|
logger.Errorf("Could not unmarshall public key retrieved from DHT for %v", p)
|
2014-11-11 16:28:20 -08:00
|
|
|
return nil, err
|
|
|
|
}
|
2015-03-30 07:53:14 -07:00
|
|
|
|
2018-03-07 00:13:34 -05:00
|
|
|
// Note: No need to check that public key hash matches peer ID
|
|
|
|
// because this is done by GetValues()
|
2019-02-01 17:46:46 +11:00
|
|
|
logger.Debugf("Got public key for %s from DHT", p)
|
2018-03-07 00:13:34 -05:00
|
|
|
return pubk, nil
|
2014-11-11 16:28:20 -08:00
|
|
|
}
|
|
|
|
|
2014-12-19 12:19:56 -08:00
|
|
|
func (dht *IpfsDHT) getPublicKeyFromNode(ctx context.Context, p peer.ID) (ci.PubKey, error) {
|
|
|
|
// check locally, just in case...
|
|
|
|
pk := dht.peerstore.PubKey(p)
|
|
|
|
if pk != nil {
|
|
|
|
return pk, nil
|
|
|
|
}
|
|
|
|
|
2018-02-27 17:28:13 -05:00
|
|
|
// Get the key from the node itself
|
2015-03-31 14:41:53 -07:00
|
|
|
pkkey := routing.KeyForPublicKey(p)
|
2014-12-19 12:19:56 -08:00
|
|
|
pmes, err := dht.getValueSingle(ctx, p, pkkey)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// node doesn't have key :(
|
|
|
|
record := pmes.GetRecord()
|
|
|
|
if record == nil {
|
2018-03-07 00:13:34 -05:00
|
|
|
return nil, fmt.Errorf("node %v not responding with its public key", p)
|
2014-12-19 12:19:56 -08:00
|
|
|
}
|
|
|
|
|
2018-03-07 00:13:34 -05:00
|
|
|
pubk, err := ci.UnmarshalPublicKey(record.GetValue())
|
2014-12-19 12:19:56 -08:00
|
|
|
if err != nil {
|
2019-02-01 17:46:46 +11:00
|
|
|
logger.Errorf("Could not unmarshall public key for %v", p)
|
2014-12-19 12:19:56 -08:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-02-27 17:28:13 -05:00
|
|
|
// Make sure the public key matches the peer ID
|
|
|
|
id, err := peer.IDFromPublicKey(pubk)
|
2014-12-19 12:19:56 -08:00
|
|
|
if err != nil {
|
2019-02-01 17:46:46 +11:00
|
|
|
logger.Errorf("Could not extract peer id from public key for %v", p)
|
2014-12-19 12:19:56 -08:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if id != p {
|
2018-02-27 17:28:13 -05:00
|
|
|
return nil, fmt.Errorf("public key %v does not match peer %v", id, p)
|
2014-12-19 12:19:56 -08:00
|
|
|
}
|
|
|
|
|
2019-02-01 17:46:46 +11:00
|
|
|
logger.Debugf("Got public key from node %v itself", p)
|
2018-02-27 17:28:13 -05:00
|
|
|
return pubk, nil
|
2014-12-19 12:19:56 -08:00
|
|
|
}
|