diff --git a/include/opendht/dht.h b/include/opendht/dht.h
index db3b4d994dd9967956d07299f6174c3fd0fdd72a..f01e2c088da1a9240c9c84ddb61f5c6980466fab 100644
--- a/include/opendht/dht.h
+++ b/include/opendht/dht.h
@@ -121,7 +121,7 @@ public:
         insertNode(n.id, SockAddr(n.ss, n.sslen));
     }
 
-    void pingNode(const sockaddr*, socklen_t);
+    void pingNode(const sockaddr*, socklen_t, DoneCallbackSimple&& cb={});
 
     time_point periodic(const uint8_t *buf, size_t buflen, const SockAddr&);
     time_point periodic(const uint8_t *buf, size_t buflen, const sockaddr* from, socklen_t fromlen) {
diff --git a/include/opendht/dhtrunner.h b/include/opendht/dhtrunner.h
index 42fd7f7153562ea80258e27694ed2bb917e967ed..6def61d585c013f83b2fd7cc84de7732e97acdb1 100644
--- a/include/opendht/dhtrunner.h
+++ b/include/opendht/dhtrunner.h
@@ -197,8 +197,8 @@ public:
     }
     void putEncrypted(const std::string& key, InfoHash to, Value&& value, DoneCallback cb={});
 
-    void bootstrap(const char* host, const char* service);
-    void bootstrap(const std::vector<std::pair<sockaddr_storage, socklen_t>>& nodes);
+    void bootstrap(const char* host, const char* service, DoneCallbackSimple&& cb={});
+    void bootstrap(const std::vector<std::pair<sockaddr_storage, socklen_t>>& nodes, DoneCallbackSimple&& cb={});
     void bootstrap(const std::vector<NodeExport>& nodes);
 
     /**
diff --git a/src/dht.cpp b/src/dht.cpp
index 352cc878e5cb333bc609a4102f6bc9f71db32db6..19477f06c7efe3446f5a1947df2379fd78889611 100644
--- a/src/dht.cpp
+++ b/src/dht.cpp
@@ -2990,17 +2990,22 @@ Dht::insertNode(const InfoHash& id, const SockAddr& addr)
 }
 
 void
-Dht::pingNode(const sockaddr* sa, socklen_t salen)
+Dht::pingNode(const sockaddr* sa, socklen_t salen, DoneCallbackSimple&& cb)
 {
     scheduler.syncTime();
     DHT_LOG.DEBUG("Sending ping to %s", print_addr(sa, salen).c_str());
     auto& count = sa->sa_family == AF_INET ? pending_pings4 : pending_pings6;
     count++;
-    network_engine.sendPing(sa, salen, [&](const Request&, NetworkEngine::RequestAnswer&&) {
+    network_engine.sendPing(sa, salen, [&count,cb](const Request&, NetworkEngine::RequestAnswer&&) {
         count--;
-    }, [&](const Request&, bool last){
-        if (last)
+        if (cb)
+            cb(true);
+    }, [&count,cb](const Request&, bool last){
+        if (last) {
             count--;
+            if (cb)
+                cb(false);
+        }
     });
 }
 
diff --git a/src/dhtrunner.cpp b/src/dhtrunner.cpp
index fd96c16ab7a9c3c6ece214d5bae52eeaa6e75bfe..ee1a07f43a7f6506ec693e5659b6df75047bcf31 100644
--- a/src/dhtrunner.cpp
+++ b/src/dhtrunner.cpp
@@ -597,18 +597,25 @@ DhtRunner::getAddrInfo(const char* host, const char* service)
 }
 
 void
-DhtRunner::bootstrap(const char* host, const char* service)
+DhtRunner::bootstrap(const char* host, const char* service, DoneCallbackSimple&& cb)
 {
-    bootstrap(getAddrInfo(host, service));
+    bootstrap(getAddrInfo(host, service), std::forward<DoneCallbackSimple>(cb));
 }
 
 void
-DhtRunner::bootstrap(const std::vector<std::pair<sockaddr_storage, socklen_t>>& nodes)
+DhtRunner::bootstrap(const std::vector<std::pair<sockaddr_storage, socklen_t>>& nodes, DoneCallbackSimple&& cb)
 {
     std::lock_guard<std::mutex> lck(storage_mtx);
-    pending_ops_prio.emplace([=](SecureDht& dht) {
+    pending_ops_prio.emplace([=](SecureDht& dht) mutable {
+        auto rem = std::make_shared<std::pair<size_t, bool>>(nodes.size(), false);
         for (auto& node : nodes)
-            dht.pingNode((sockaddr*)&node.first, node.second);
+            dht.pingNode((sockaddr*)&node.first, node.second, [rem,cb](bool ok) {
+                auto& r = *rem;
+                r.first--;
+                r.second |= ok;
+                if (not r.first)
+                    cb(r.second);
+            });
     });
     cv.notify_all();
 }