diff --git a/include/opendht/dhtrunner.h b/include/opendht/dhtrunner.h
index fd3346c0c329e5f703da2db1f452ed101aa1a24f..fb78f1af208caa0aef3de9942047b62fb30cb14b 100644
--- a/include/opendht/dhtrunner.h
+++ b/include/opendht/dhtrunner.h
@@ -202,7 +202,7 @@ public:
      * Insert known nodes to the routing table, without necessarly ping them.
      * Usefull to restart a node and get things running fast without putting load on the network.
      */
-    void bootstrap(const std::vector<std::pair<sockaddr_storage, socklen_t>>& nodes, DoneCallbackSimple&& cb={});
+    void bootstrap(const std::vector<SockAddr>& nodes, DoneCallbackSimple&& cb={});
     void bootstrap(const SockAddr& addr, DoneCallbackSimple&& cb={});
 
     /**
@@ -329,7 +329,7 @@ public:
      * @param threaded: If false, loop() must be called periodically. Otherwise a thread is launched.
      * @param cb: Optional callback to receive general state information.
      */
-    void run(const sockaddr_in* local4, const sockaddr_in6* local6, Config config);
+    void run(const SockAddr& local4, const SockAddr& local6, Config config);
 
     /**
      * Same as @run(sockaddr_in, sockaddr_in6, Identity, bool, StatusCallback), but with string IP addresses and service (port).
@@ -373,10 +373,10 @@ private:
      */
     void tryBootstrapContinuously();
 
-    void doRun(const sockaddr_in* sin4, const sockaddr_in6* sin6, SecureDhtConfig config);
+    void doRun(const SockAddr& sin4, const SockAddr& sin6, SecureDhtConfig config);
     time_point loop_();
 
-    static std::vector<std::pair<sockaddr_storage, socklen_t>> getAddrInfo(const std::string& host, const std::string& service);
+    static std::vector<SockAddr> getAddrInfo(const std::string& host, const std::string& service);
 
     NodeStatus getStatus() const {
         return std::max(status4, status6);
diff --git a/src/dhtrunner.cpp b/src/dhtrunner.cpp
index 66b4ebbd2fe011d4f1a91aaaccd743df4c2302f1..e2850580cde548d7c8596829c84d9b53ba0bde9f 100644
--- a/src/dhtrunner.cpp
+++ b/src/dhtrunner.cpp
@@ -58,15 +58,13 @@ DhtRunner::~DhtRunner()
 void
 DhtRunner::run(in_port_t port, DhtRunner::Config config)
 {
-    sockaddr_in sin4;
-    std::fill_n((uint8_t*)&sin4, sizeof(sin4), 0);
-    sin4.sin_family = AF_INET;
-    sin4.sin_port = htons(port);
-    sockaddr_in6 sin6;
-    std::fill_n((uint8_t*)&sin6, sizeof(sin6), 0);
-    sin6.sin6_family = AF_INET6;
-    sin6.sin6_port = htons(port);
-    run(&sin4, &sin6, config);
+    SockAddr sin4;
+    sin4.setFamily(AF_INET);
+    sin4.setPort(port);
+    SockAddr sin6;
+    sin6.setFamily(AF_INET6);
+    sin6.setPort(port);
+    run(sin4, sin6, config);
 }
 
 void
@@ -74,12 +72,12 @@ DhtRunner::run(const char* ip4, const char* ip6, const char* service, DhtRunner:
 {
     auto res4 = getAddrInfo(ip4, service);
     auto res6 = getAddrInfo(ip6, service);
-    run(res4.empty() ? nullptr : (sockaddr_in*) &res4.front().first,
-        res6.empty() ? nullptr : (sockaddr_in6*)&res6.front().first, config);
+    run(res4.empty() ? SockAddr() : res4.front(),
+        res6.empty() ? SockAddr() : res6.front(), config);
 }
 
 void
-DhtRunner::run(const sockaddr_in* local4, const sockaddr_in6* local6, DhtRunner::Config config)
+DhtRunner::run(const SockAddr& local4, const SockAddr& local6, DhtRunner::Config config)
 {
     if (running)
         return;
@@ -375,8 +373,34 @@ DhtRunner::loop_()
     return wakeup;
 }
 
+
+int bindSocket(const SockAddr& addr, SockAddr& bound)
+{
+    bool is_ipv6 = addr.getFamily() == AF_INET6;
+    int sock = socket(is_ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0);
+    if (sock >= 0) {
+        int set = 1;
+#ifdef SO_NOSIGPIPE
+        setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(set));
+#endif
+        if (is_ipv6)
+            setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&set, sizeof(set));
+        int rc = bind(sock, addr.get(), addr.getLength());
+        if(rc < 0)
+            throw DhtException("Can't bind socket on " + addr.toString() + " " + strerror(rc));
+        sockaddr_storage ss;
+        socklen_t ss_len = sizeof(ss);
+        getsockname(sock, (sockaddr*)&ss, &ss_len);
+        bound = {ss, ss_len};
+        return sock;
+    } else {
+        throw DhtException(std::string("Can't open socket: ") + strerror(sock));
+    }
+    return -1;
+}
+
 void
-DhtRunner::doRun(const sockaddr_in* sin4, const sockaddr_in6* sin6, SecureDht::Config config)
+DhtRunner::doRun(const SockAddr& sin4, const SockAddr& sin6, SecureDht::Config config)
 {
     dht_.reset();
 
@@ -384,40 +408,19 @@ DhtRunner::doRun(const sockaddr_in* sin4, const sockaddr_in6* sin6, SecureDht::C
         s6 = -1;
 
     bound4 = {};
-    if (sin4) {
-        s4 = socket(PF_INET, SOCK_DGRAM, 0);
-        if(s4 >= 0) {
-            int rc = bind(s4, (sockaddr*)sin4, sizeof(sockaddr_in));
-            if(rc < 0)
-                throw DhtException("Can't bind IPv4 socket on " + dht::print_addr((sockaddr*)sin4, sizeof(sockaddr_in)));
-            sockaddr_storage ss;
-            socklen_t ss_len = sizeof(ss);
-            getsockname(s4, (sockaddr*)&ss, &ss_len);
-            bound4 = {ss, ss_len};
-        }
-    }
+    if (sin4)
+        s4 = bindSocket(sin4, bound4);
 
 #if 1
     bound6 = {};
-    if (sin6) {
-        s6 = socket(PF_INET6, SOCK_DGRAM, 0);
-        if(s6 >= 0) {
-            int val = 1;
-            int rc = setsockopt(s6, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&val, sizeof(val));
-            if(rc < 0)
-                throw DhtException("Can't set IPV6_V6ONLY");
-
-            rc = bind(s6, (sockaddr*)sin6, sizeof(sockaddr_in6));
-            if(rc < 0)
-                throw DhtException("Can't bind IPv6 socket on " + dht::print_addr((sockaddr*)sin6, sizeof(sockaddr_in6)));
-            sockaddr_storage ss;
-            socklen_t ss_len = sizeof(ss);
-            getsockname(s6, (sockaddr*)&ss, &ss_len);
-            bound6 = {ss, ss_len};
-        }
-    }
+    if (sin6)
+        s6 = bindSocket(sin6, bound6);
 #endif
 
+    std::cerr << "s4: " << s4 << " bound on " << bound4.toString() << std::endl;
+    std::cerr << "s6: " << s6 << " bound on " << bound6.toString() << std::endl;
+
+
     dht_ = std::unique_ptr<SecureDht>(new SecureDht {s4, s6, config});
 
     rcv_thread = std::thread([this,s4,s6]() {
@@ -490,7 +493,8 @@ DhtRunner::get(const std::string& key, GetCallback vcb, DoneCallbackSimple dcb,
 {
     get(InfoHash::get(key), vcb, dcb, f, w);
 }
-void DhtRunner::query(const InfoHash& hash, QueryCallback cb, DoneCallback done_cb, Query q) {
+void
+DhtRunner::query(const InfoHash& hash, QueryCallback cb, DoneCallback done_cb, Query q) {
     {
         std::lock_guard<std::mutex> lck(storage_mtx);
         pending_ops.emplace([=](SecureDht& dht) mutable {
@@ -695,10 +699,10 @@ DhtRunner::tryBootstrapContinuously()
     });
 }
 
-std::vector<std::pair<sockaddr_storage, socklen_t>>
+std::vector<SockAddr>
 DhtRunner::getAddrInfo(const std::string& host, const std::string& service)
 {
-    std::vector<std::pair<sockaddr_storage, socklen_t>> ips {};
+    std::vector<SockAddr> ips {};
     if (host.empty())
         return ips;
 
@@ -712,8 +716,7 @@ DhtRunner::getAddrInfo(const std::string& host, const std::string& service)
 
     addrinfo* infop = info;
     while (infop) {
-        ips.emplace_back(sockaddr_storage(), infop->ai_addrlen);
-        std::copy_n((uint8_t*)infop->ai_addr, infop->ai_addrlen, (uint8_t*)&ips.back().first);
+        ips.emplace_back(infop->ai_addr, infop->ai_addrlen);
         infop = infop->ai_next;
     }
     freeaddrinfo(info);
@@ -737,13 +740,13 @@ DhtRunner::clearBootstrap()
 }
 
 void
-DhtRunner::bootstrap(const std::vector<std::pair<sockaddr_storage, socklen_t>>& nodes, DoneCallbackSimple&& cb)
+DhtRunner::bootstrap(const std::vector<SockAddr>& nodes, DoneCallbackSimple&& cb)
 {
     std::lock_guard<std::mutex> lck(storage_mtx);
     pending_ops_prio.emplace([=](SecureDht& dht) mutable {
         auto rem = cb ? std::make_shared<std::pair<size_t, bool>>(nodes.size(), false) : nullptr;
-        for (auto& node : nodes)
-            dht.pingNode((sockaddr*)&node.first, node.second, cb ? [rem,cb](bool ok) {
+        for (const auto& node : nodes)
+            dht.pingNode(node.get(), node.getLength(), cb ? [rem,cb](bool ok) {
                 auto& r = *rem;
                 r.first--;
                 r.second |= ok;