github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/routing/dht/records.go (about)

     1  package dht
     2  
     3  import (
     4  	"fmt"
     5  
     6  	ctxfrac "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-context/frac"
     7  	"github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
     8  	ci "github.com/ipfs/go-ipfs/p2p/crypto"
     9  	peer "github.com/ipfs/go-ipfs/p2p/peer"
    10  	routing "github.com/ipfs/go-ipfs/routing"
    11  	pb "github.com/ipfs/go-ipfs/routing/dht/pb"
    12  	record "github.com/ipfs/go-ipfs/routing/record"
    13  )
    14  
    15  func (dht *IpfsDHT) GetPublicKey(ctx context.Context, p peer.ID) (ci.PubKey, error) {
    16  	log.Debugf("getPublicKey for: %s", p)
    17  
    18  	// check locally.
    19  	pk := dht.peerstore.PubKey(p)
    20  	if pk != nil {
    21  		return pk, nil
    22  	}
    23  
    24  	// ok, try the node itself. if they're overwhelmed or slow we can move on.
    25  	ctxT, cancelFunc := ctxfrac.WithDeadlineFraction(ctx, 0.3)
    26  	defer cancelFunc()
    27  	if pk, err := dht.getPublicKeyFromNode(ctx, p); err == nil {
    28  		err := dht.peerstore.AddPubKey(p, pk)
    29  		if err != nil {
    30  			return pk, err
    31  		}
    32  		return pk, nil
    33  	}
    34  
    35  	// last ditch effort: let's try the dht.
    36  	log.Debugf("pk for %s not in peerstore, and peer failed. trying dht.", p)
    37  	pkkey := routing.KeyForPublicKey(p)
    38  
    39  	val, err := dht.GetValue(ctxT, pkkey)
    40  	if err != nil {
    41  		log.Warning("Failed to find requested public key.")
    42  		return nil, err
    43  	}
    44  
    45  	pk, err = ci.UnmarshalPublicKey(val)
    46  	if err != nil {
    47  		log.Debugf("Failed to unmarshal public key: %s", err)
    48  		return nil, err
    49  	}
    50  
    51  	return pk, dht.peerstore.AddPubKey(p, pk)
    52  }
    53  
    54  func (dht *IpfsDHT) getPublicKeyFromNode(ctx context.Context, p peer.ID) (ci.PubKey, error) {
    55  
    56  	// check locally, just in case...
    57  	pk := dht.peerstore.PubKey(p)
    58  	if pk != nil {
    59  		return pk, nil
    60  	}
    61  
    62  	pkkey := routing.KeyForPublicKey(p)
    63  	pmes, err := dht.getValueSingle(ctx, p, pkkey)
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  
    68  	// node doesn't have key :(
    69  	record := pmes.GetRecord()
    70  	if record == nil {
    71  		return nil, fmt.Errorf("node not responding with its public key: %s", p)
    72  	}
    73  
    74  	// Success! We were given the value. we don't need to check
    75  	// validity because a) we can't. b) we know the hash of the
    76  	// key we're looking for.
    77  	val := record.GetValue()
    78  	log.Debug("dht got a value from other peer.")
    79  
    80  	pk, err = ci.UnmarshalPublicKey(val)
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  
    85  	id, err := peer.IDFromPublicKey(pk)
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  	if id != p {
    90  		return nil, fmt.Errorf("public key does not match id: %s", p)
    91  	}
    92  
    93  	// ok! it's valid. we got it!
    94  	log.Debugf("dht got public key from node itself.")
    95  	return pk, nil
    96  }
    97  
    98  // verifyRecordLocally attempts to verify a record. if we do not have the public
    99  // key, we fail. we do not search the dht.
   100  func (dht *IpfsDHT) verifyRecordLocally(r *pb.Record) error {
   101  
   102  	if len(r.Signature) > 0 {
   103  		// First, validate the signature
   104  		p := peer.ID(r.GetAuthor())
   105  		pk := dht.peerstore.PubKey(p)
   106  		if pk == nil {
   107  			return fmt.Errorf("do not have public key for %s", p)
   108  		}
   109  
   110  		if err := record.CheckRecordSig(r, pk); err != nil {
   111  			return err
   112  		}
   113  	}
   114  
   115  	return dht.Validator.VerifyRecord(r)
   116  }
   117  
   118  // verifyRecordOnline verifies a record, searching the DHT for the public key
   119  // if necessary. The reason there is a distinction in the functions is that
   120  // retrieving arbitrary public keys from the DHT as a result of passively
   121  // receiving records (e.g. through a PUT_VALUE or ADD_PROVIDER) can cause a
   122  // massive amplification attack on the dht. Use with care.
   123  func (dht *IpfsDHT) verifyRecordOnline(ctx context.Context, r *pb.Record) error {
   124  
   125  	if len(r.Signature) > 0 {
   126  		// get the public key, search for it if necessary.
   127  		p := peer.ID(r.GetAuthor())
   128  		pk, err := dht.GetPublicKey(ctx, p)
   129  		if err != nil {
   130  			return err
   131  		}
   132  
   133  		err = record.CheckRecordSig(r, pk)
   134  		if err != nil {
   135  			return err
   136  		}
   137  	}
   138  
   139  	return dht.Validator.VerifyRecord(r)
   140  }