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 }