diff --git a/include/opendht/dhtrunner.h b/include/opendht/dhtrunner.h
index 42cd6817946d0aca8c2438136e2160a943a36d55..30a44c7225950a6bf79f5db45776ff08321e28a8 100644
--- a/include/opendht/dhtrunner.h
+++ b/include/opendht/dhtrunner.h
@@ -77,6 +77,7 @@ public:
     void putEncrypted(InfoHash hash, InfoHash to, Value&& value, Dht::DoneCallback cb=nullptr);
     void putEncrypted(const std::string& key, InfoHash to, Value&& value, Dht::DoneCallback cb=nullptr);
 
+    void bootstrap(const char* host, const char* service);
     void bootstrap(const std::vector<std::pair<sockaddr_storage, socklen_t>>& nodes);
     void bootstrap(const std::vector<Dht::NodeExport>& nodes);
 
diff --git a/src/dht.cpp b/src/dht.cpp
index d6957aebec495ee09b1f7371ae948736a9982399..59c96aac9880d263457e6b8974a77571766e98d3 100644
--- a/src/dht.cpp
+++ b/src/dht.cpp
@@ -2460,7 +2460,7 @@ Dht::insertNode(const InfoHash& id, const sockaddr *sa, socklen_t salen)
 int
 Dht::pingNode(const sockaddr *sa, socklen_t salen)
 {
-    DHT_DEBUG("Sending ping.");
+    DHT_DEBUG("Sending ping to %s", print_addr(sa, salen).c_str());
     return sendPing(sa, salen, TransId {TransPrefix::PING});
 }
 
diff --git a/src/dhtrunner.cpp b/src/dhtrunner.cpp
index 1374b7bea24c9f37d98dc2203b9f4b5e46569264..ac94f5cd8d36411e3e2f593ff7c73317e16b5a59 100644
--- a/src/dhtrunner.cpp
+++ b/src/dhtrunner.cpp
@@ -335,6 +335,29 @@ DhtRunner::putEncrypted(const std::string& key, InfoHash to, Value&& value, Dht:
     putEncrypted(InfoHash::get(key), to, std::forward<Value>(value), cb);
 }
 
+void
+DhtRunner::bootstrap(const char* host, const char* service)
+{
+    std::vector<std::pair<sockaddr_storage, socklen_t>> bootstrap_nodes {};
+
+    addrinfo hints;
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_socktype = SOCK_DGRAM;
+    addrinfo* info = nullptr;
+    int rc = getaddrinfo(host, service, &hints, &info);
+    if(rc != 0)
+        throw std::invalid_argument(std::string("Error: `") + host + ":" + service + "`: " + gai_strerror(rc));
+
+    addrinfo* infop = info;
+    while (infop) {
+        bootstrap_nodes.emplace_back(sockaddr_storage(), infop->ai_addrlen);
+        std::copy_n((uint8_t*)infop->ai_addr, infop->ai_addrlen, (uint8_t*)&bootstrap_nodes.back().first);
+        infop = infop->ai_next;
+    }
+    freeaddrinfo(info);
+    bootstrap(bootstrap_nodes);
+}
+
 void
 DhtRunner::bootstrap(const std::vector<std::pair<sockaddr_storage, socklen_t>>& nodes)
 {
diff --git a/tools/dhtchat.cpp b/tools/dhtchat.cpp
index bf8605a687f6dab0171e0eaac4e2ec47d65911f5..c54d5596e47b74cb29f42df31a470cbb23bd39b9 100644
--- a/tools/dhtchat.cpp
+++ b/tools/dhtchat.cpp
@@ -114,31 +114,6 @@ main(int argc, char **argv)
     if (!port)
         port = 4222;
 
-    std::vector<std::pair<sockaddr_storage, socklen_t>> bootstrap_nodes {};
-    while (i < argc) {
-        addrinfo hints;
-        memset(&hints, 0, sizeof(hints));
-        addrinfo *info = nullptr, *infop = nullptr;
-        hints.ai_socktype = SOCK_DGRAM;
-        int rc = getaddrinfo(argv[i], argv[i + 1], &hints, &info);
-        if(rc != 0)
-            throw std::invalid_argument(std::string("getaddrinfo: ") + gai_strerror(rc));
-
-        i++;
-        if(i >= argc)
-            break;
-
-        infop = info;
-        while (infop) {
-            sockaddr_storage tmp;
-            std::copy_n((uint8_t*)infop->ai_addr, infop->ai_addrlen, (uint8_t*)&tmp);
-            bootstrap_nodes.emplace_back(tmp, infop->ai_addrlen);
-            infop = infop->ai_next;
-        }
-        freeaddrinfo(info);
-        i++;
-    }
-
     int rc = gnutls_global_init();
     if (rc != GNUTLS_E_SUCCESS)
         throw std::runtime_error(std::string("Error initializing GnuTLS: ")+gnutls_strerror(rc));
@@ -155,7 +130,11 @@ main(int argc, char **argv)
         [](char const* m, va_list args){ printLog(std::cout, m, args); }
     );
 */
-    dht.bootstrap(bootstrap_nodes);
+
+    while (i+1 < argc) {
+        dht.bootstrap(argv[i], argv[i + 1]);
+        i += 2;
+    }
 
     std::cout << "OpenDht node " << dht.getRoutingId() << " running on port " <<  port<<  std::endl;
     std::cout << "Public key ID " << dht.getId() << std::endl;
diff --git a/tools/dhtnode.cpp b/tools/dhtnode.cpp
index 2a6444d175fd311ea8c6fe49fcba651edf1bb058..3b891f630299f824a7891631a773cb956f4498ff 100644
--- a/tools/dhtnode.cpp
+++ b/tools/dhtnode.cpp
@@ -99,31 +99,6 @@ main(int argc, char **argv)
     if (!port)
         port = 4222;
 
-    std::vector<std::pair<sockaddr_storage, socklen_t>> bootstrap_nodes {};
-    while (i < argc) {
-        addrinfo hints;
-        memset(&hints, 0, sizeof(hints));
-        addrinfo *info = nullptr, *infop = nullptr;
-        hints.ai_socktype = SOCK_DGRAM;
-        int rc = getaddrinfo(argv[i], argv[i + 1], &hints, &info);
-        if(rc != 0)
-            throw std::invalid_argument(std::string("getaddrinfo: ") + gai_strerror(rc));
-
-        i++;
-        if(i >= argc)
-            break;
-
-        infop = info;
-        while (infop) {
-            sockaddr_storage tmp;
-            std::copy_n((uint8_t*)infop->ai_addr, infop->ai_addrlen, (uint8_t*)&tmp);
-            bootstrap_nodes.emplace_back(tmp, infop->ai_addrlen);
-            infop = infop->ai_next;
-        }
-        freeaddrinfo(info);
-        i++;
-    }
-
     int rc = gnutls_global_init();
     if (rc != GNUTLS_E_SUCCESS)
         throw std::runtime_error(std::string("Error initializing GnuTLS: ")+gnutls_strerror(rc));
@@ -135,7 +110,10 @@ main(int argc, char **argv)
     dht.run(port, crt_tmp, true, [](dht::Dht::Status /* ipv4 */, dht::Dht::Status /* ipv6 */) {
     });
 
-    dht.bootstrap(bootstrap_nodes);
+    while (i+1 < argc) {
+        dht.bootstrap(argv[i], argv[i + 1]);
+        i += 2;
+    }
 
     std::cout << "OpenDht node " << dht.getRoutingId() << " running on port " <<  port<<  std::endl;
     std::cout << "Public key ID " << dht.getId() << std::endl;