func (dht *IpfsDHT) handleFindPeer(ctx context.Context, p peer.ID, pmes *pb.Message) (*pb.Message, error) { defer log.EventBegin(ctx, "handleFindPeer", p).Done() resp := pb.NewMessage(pmes.GetType(), "", pmes.GetClusterLevel()) var closest []peer.ID // if looking for self... special case where we send it on CloserPeers. if peer.ID(pmes.GetKey()) == dht.self { closest = []peer.ID{dht.self} } else { closest = dht.betterPeersToQuery(pmes, p, CloserPeerCount) } if closest == nil { log.Infof("%s handleFindPeer %s: could not find anything.", dht.self, p) return resp, nil } var withAddresses []peer.PeerInfo closestinfos := peer.PeerInfos(dht.peerstore, closest) for _, pi := range closestinfos { if len(pi.Addrs) > 0 { withAddresses = append(withAddresses, pi) log.Debugf("handleFindPeer: sending back '%s'", pi.ID) } } resp.CloserPeers = pb.PeerInfosToPBPeers(dht.host.Network(), withAddresses) return resp, nil }
func ReadHeader(r io.Reader) (src, dst peer.ID, err error) { mhr := mh.NewReader(r) s, err := mhr.ReadMultihash() if err != nil { return "", "", err } d, err := mhr.ReadMultihash() if err != nil { return "", "", err } return peer.ID(s), peer.ID(d), nil }
func (dht *IpfsDHT) closerPeersSingle(ctx context.Context, key key.Key, p peer.ID) ([]peer.ID, error) { pmes, err := dht.findPeerSingle(ctx, p, peer.ID(key)) if err != nil { return nil, err } var out []peer.ID for _, pbp := range pmes.GetCloserPeers() { pid := peer.ID(pbp.GetId()) if pid != dht.self { // dont add self dht.peerstore.AddAddrs(pid, pbp.Addresses(), peer.TempAddrTTL) out = append(out, pid) } } return out, nil }
// RandPeerID generates random "valid" peer IDs. it does not NEED to generate // keys because it is as if we lost the key right away. fine to read randomness // and hash it. to generate proper keys and corresponding PeerID, use: // sk, pk, _ := testutil.RandKeyPair() // id, _ := peer.IDFromPublicKey(pk) func RandPeerID() (peer.ID, error) { buf := make([]byte, 16) if _, err := io.ReadFull(u.NewTimeSeededRand(), buf); err != nil { return "", err } h := u.Hash(buf) return peer.ID(h), nil }
// ID returns the ID of a given Conn. func ID(c Conn) string { l := fmt.Sprintf("%s/%s", c.LocalMultiaddr(), c.LocalPeer().Pretty()) r := fmt.Sprintf("%s/%s", c.RemoteMultiaddr(), c.RemotePeer().Pretty()) lh := u.Hash([]byte(l)) rh := u.Hash([]byte(r)) ch := u.XOR(lh, rh) return peer.ID(ch).Pretty() }
func GetGraphJson(dinfo []*DiagInfo) []byte { out := make(map[string]interface{}) names := make(map[string]int) var nodes []*node for _, di := range dinfo { names[di.ID] = len(nodes) val := di.BwIn + di.BwOut + 10 // include the routing table key, for proper routing table display rtk := peer.ID(rtable.ConvertPeerID(peer.ID(di.ID))).Pretty() nodes = append(nodes, &node{Name: di.ID, Value: val, RtKey: rtk}) } var links []*link linkexists := make([][]bool, len(nodes)) for i := range linkexists { linkexists[i] = make([]bool, len(nodes)) } for _, di := range dinfo { myid := names[di.ID] for _, con := range di.Connections { thisid := names[con.ID] if !linkexists[thisid][myid] { links = append(links, &link{ Source: myid, Target: thisid, Value: 3, }) linkexists[myid][thisid] = true } } } out["nodes"] = nodes out["links"] = links b, err := json.Marshal(out) if err != nil { panic(err) } return b }
func storeProvidersToPeerstore(ps peer.Peerstore, p peer.ID, providers []*dhtpb.Message_Peer) { for _, provider := range providers { providerID := peer.ID(provider.GetId()) if providerID != p { log.Errorf("provider message came from third-party %s", p) continue } for _, maddr := range provider.Addresses() { // as a router, we want to store addresses for peers who have provided ps.AddAddr(p, maddr, peer.AddressTTL) } } }
func GetPublicKey(r IpfsRouting, ctx context.Context, pkhash []byte) (ci.PubKey, error) { if dht, ok := r.(PubKeyFetcher); ok { // If we have a DHT as our routing system, use optimized fetcher return dht.GetPublicKey(ctx, peer.ID(pkhash)) } else { key := key.Key("/pk/" + string(pkhash)) pkval, err := r.GetValue(ctx, key) if err != nil { return nil, err } // get PublicKey from node.Data return ci.UnmarshalPublicKey(pkval) } }
func verify(ps peer.Peerstore, r *dhtpb.Record) error { v := make(record.Validator) v["pk"] = record.PublicKeyValidator p := peer.ID(r.GetAuthor()) pk := ps.PubKey(p) if pk == nil { return fmt.Errorf("do not have public key for %s", p) } if err := record.CheckRecordSig(r, pk); err != nil { return err } if err := v.VerifyRecord(r); err != nil { return err } return nil }
// verifyRecordLocally attempts to verify a record. if we do not have the public // key, we fail. we do not search the dht. func (dht *IpfsDHT) verifyRecordLocally(r *pb.Record) error { if len(r.Signature) > 0 { // First, validate the signature p := peer.ID(r.GetAuthor()) pk := dht.peerstore.PubKey(p) if pk == nil { return fmt.Errorf("do not have public key for %s", p) } if err := record.CheckRecordSig(r, pk); err != nil { return err } } return dht.Validator.VerifyRecord(r) }
// verifyRecordOnline verifies a record, searching the DHT for the public key // if necessary. The reason there is a distinction in the functions is that // retrieving arbitrary public keys from the DHT as a result of passively // receiving records (e.g. through a PUT_VALUE or ADD_PROVIDER) can cause a // massive amplification attack on the dht. Use with care. func (dht *IpfsDHT) verifyRecordOnline(ctx context.Context, r *pb.Record) error { if len(r.Signature) > 0 { // get the public key, search for it if necessary. p := peer.ID(r.GetAuthor()) pk, err := dht.GetPublicKey(ctx, p) if err != nil { return err } err = record.CheckRecordSig(r, pk) if err != nil { return err } } return dht.Validator.VerifyRecord(r) }
func (n *IpfsNode) loadID() error { if n.Identity != "" { return errors.New("identity already loaded") } cfg, err := n.Repo.Config() if err != nil { return err } cid := cfg.Identity.PeerID if cid == "" { return errors.New("Identity was not set in config (was ipfs init run?)") } if len(cid) == 0 { return errors.New("No peer ID in config! (was ipfs init run?)") } n.Identity = peer.ID(b58.Decode(cid)) return nil }
func (s *Server) handleMessage( ctx context.Context, p peer.ID, req *dhtpb.Message) (peer.ID, *dhtpb.Message) { defer log.EventBegin(ctx, "routingMessageReceived", req, p).Done() var response = dhtpb.NewMessage(req.GetType(), req.GetKey(), req.GetClusterLevel()) switch req.GetType() { case dhtpb.Message_GET_VALUE: rawRecord, err := getRoutingRecord(s.routingBackend, key.Key(req.GetKey())) if err != nil { return "", nil } response.Record = rawRecord return p, response case dhtpb.Message_PUT_VALUE: // FIXME: verify complains that the peer's ID is not present in the // peerstore. Mocknet problem? // if err := verify(s.peerstore, req.GetRecord()); err != nil { // log.Event(ctx, "validationFailed", req, p) // return "", nil // } putRoutingRecord(s.routingBackend, key.Key(req.GetKey()), req.GetRecord()) return p, req case dhtpb.Message_FIND_NODE: p := s.peerstore.PeerInfo(peer.ID(req.GetKey())) pri := []dhtpb.PeerRoutingInfo{ { PeerInfo: p, // Connectedness: TODO }, } response.CloserPeers = dhtpb.PeerRoutingInfosToPBPeers(pri) return p.ID, response case dhtpb.Message_ADD_PROVIDER: for _, provider := range req.GetProviderPeers() { providerID := peer.ID(provider.GetId()) if providerID == p { store := []*dhtpb.Message_Peer{provider} storeProvidersToPeerstore(s.peerstore, p, store) if err := putRoutingProviders(s.routingBackend, key.Key(req.GetKey()), store); err != nil { return "", nil } } else { log.Event(ctx, "addProviderBadRequest", p, req) } } return "", nil case dhtpb.Message_GET_PROVIDERS: providers, err := getRoutingProviders(s.routingBackend, key.Key(req.GetKey())) if err != nil { return "", nil } response.ProviderPeers = providers return p, response case dhtpb.Message_PING: return p, req default: } return "", nil }
return } if len(req.Arguments()) == 0 { output, err := printSelf(node) if err != nil { res.SetError(err, cmds.ErrNormal) return } res.SetOutput(output) return } pid := req.Arguments()[0] id := peer.ID(b58.Decode(pid)) if len(id) == 0 { res.SetError(cmds.ClientError("Invalid peer id"), cmds.ErrClient) return } // TODO handle offline mode with polymorphism instead of conditionals if !node.OnlineMode() { res.SetError(errors.New(offlineIdErrorMessage), cmds.ErrClient) return } p, err := node.Routing.FindPeer(req.Context(), id) if err == kb.ErrLookupFailure { res.SetError(errors.New(offlineIdErrorMessage), cmds.ErrClient) return
func (dht *IpfsDHT) checkLocalDatastore(k key.Key) (*pb.Record, error) { log.Debugf("%s handleGetValue looking into ds", dht.self) dskey := k.DsKey() iVal, err := dht.datastore.Get(dskey) log.Debugf("%s handleGetValue looking into ds GOT %v", dht.self, iVal) if err == ds.ErrNotFound { return nil, nil } // if we got an unexpected error, bail. if err != nil { return nil, err } // if we have the value, send it back log.Debugf("%s handleGetValue success!", dht.self) byts, ok := iVal.([]byte) if !ok { return nil, fmt.Errorf("datastore had non byte-slice value for %v", dskey) } rec := new(pb.Record) err = proto.Unmarshal(byts, rec) if err != nil { log.Debug("Failed to unmarshal dht record from datastore") return nil, err } // if its our record, dont bother checking the times on it if peer.ID(rec.GetAuthor()) == dht.self { return rec, nil } var recordIsBad bool recvtime, err := u.ParseRFC3339(rec.GetTimeReceived()) if err != nil { log.Info("either no receive time set on record, or it was invalid: ", err) recordIsBad = true } if time.Now().Sub(recvtime) > MaxRecordAge { log.Debug("old record found, tossing.") recordIsBad = true } // NOTE: we do not verify the record here beyond checking these timestamps. // we put the burden of checking the records on the requester as checking a record // may be computationally expensive if recordIsBad { err := dht.datastore.Delete(dskey) if err != nil { log.Error("Failed to delete bad record from datastore: ", err) } return nil, nil // can treat this as not having the record at all } return rec, nil }
// runBootstrap builds up list of peers by requesting random peer IDs func (dht *IpfsDHT) runBootstrap(ctx context.Context, cfg BootstrapConfig) error { bslog := func(msg string) { log.Debugf("DHT %s dhtRunBootstrap %s -- routing table size: %d", dht.self, msg, dht.routingTable.Size()) } bslog("start") defer bslog("end") defer log.EventBegin(ctx, "dhtRunBootstrap").Done() var merr u.MultiErr randomID := func() peer.ID { // 16 random bytes is not a valid peer id. it may be fine becuase // the dht will rehash to its own keyspace anyway. id := make([]byte, 16) rand.Read(id) id = u.Hash(id) return peer.ID(id) } // bootstrap sequentially, as results will compound ctx, cancel := context.WithTimeout(ctx, cfg.Timeout) defer cancel() runQuery := func(ctx context.Context, id peer.ID) { p, err := dht.FindPeer(ctx, id) if err == routing.ErrNotFound { // this isn't an error. this is precisely what we expect. } else if err != nil { merr = append(merr, err) } else { // woah, actually found a peer with that ID? this shouldn't happen normally // (as the ID we use is not a real ID). this is an odd error worth logging. err := fmt.Errorf("Bootstrap peer error: Actually FOUND peer. (%s, %s)", id, p) log.Warningf("%s", err) merr = append(merr, err) } } sequential := true if sequential { // these should be parallel normally. but can make them sequential for debugging. // note that the core/bootstrap context deadline should be extended too for that. for i := 0; i < cfg.Queries; i++ { id := randomID() log.Debugf("Bootstrapping query (%d/%d) to random ID: %s", i+1, cfg.Queries, id) runQuery(ctx, id) } } else { // note on parallelism here: the context is passed in to the queries, so they // **should** exit when it exceeds, making this function exit on ctx cancel. // normally, we should be selecting on ctx.Done() here too, but this gets // complicated to do with WaitGroup, and doesnt wait for the children to exit. var wg sync.WaitGroup for i := 0; i < cfg.Queries; i++ { wg.Add(1) go func() { defer wg.Done() id := randomID() log.Debugf("Bootstrapping query (%d/%d) to random ID: %s", i+1, cfg.Queries, id) runQuery(ctx, id) }() } wg.Wait() } if len(merr) > 0 { return merr } return nil }
// PBPeerToPeer turns a *Message_Peer into its peer.PeerInfo counterpart func PBPeerToPeerInfo(pbp *Message_Peer) peer.PeerInfo { return peer.PeerInfo{ ID: peer.ID(pbp.GetId()), Addrs: pbp.Addresses(), } }