diff --git a/rak/socket_address.h b/rak/socket_address.h
index 25fdb37..d38533e 100644
--- a/rak/socket_address.h
+++ b/rak/socket_address.h
@@ -145,7 +145,7 @@ private:
   };
 };
 
-// Remeber to set the AF_INET.
+// Remember to set the AF_INET.
 
 class socket_address_inet {
 public:
@@ -184,6 +184,10 @@ public:
 
   const sockaddr*     c_sockaddr() const                      { return reinterpret_cast<const sockaddr*>(&m_sockaddr); }
   const sockaddr_in*  c_sockaddr_inet() const                 { return &m_sockaddr; }
+  
+#ifdef RAK_USE_INET6
+  socket_address_inet6 to_mapped_address() const;
+#endif
 
   bool                operator == (const socket_address_inet& rhs) const;
   bool                operator < (const socket_address_inet& rhs) const;
@@ -192,6 +196,52 @@ private:
   struct sockaddr_in  m_sockaddr;
 };
 
+#ifdef RAK_USE_INET6
+// Remember to set the AF_INET6.
+
+class socket_address_inet6 {
+public:
+  bool                is_any() const                          { return is_port_any() && is_address_any(); }
+  bool                is_valid() const                        { return !is_port_any() && !is_address_any(); }
+  bool                is_port_any() const                     { return port() == 0; }
+  bool                is_address_any() const                  { return std::memcmp(&m_sockaddr.sin6_addr, &in6addr_any, sizeof(in6_addr)) == 0; }
+
+  void                clear()                                 { std::memset(this, 0, sizeof(socket_address_inet6)); set_family(); }
+
+  uint16_t            port() const                            { return ntohs(m_sockaddr.sin6_port); }
+  uint16_t            port_n() const                          { return m_sockaddr.sin6_port; }
+  void                set_port(uint16_t p)                    { m_sockaddr.sin6_port = htons(p); }
+  void                set_port_n(uint16_t p)                  { m_sockaddr.sin6_port = p; }
+
+  in6_addr            address() const                         { return m_sockaddr.sin6_addr; }
+  std::string         address_str() const;
+  bool                address_c_str(char* buf, socklen_t size) const;
+
+  void                set_address(in6_addr a)                 { m_sockaddr.sin6_addr = a; }
+  bool                set_address_str(const std::string& a)   { return set_address_c_str(a.c_str()); }
+  bool                set_address_c_str(const char* a);
+
+  void                set_address_any()                       { set_port(0); set_address(in6addr_any); }
+
+  sa_family_t         family() const                          { return m_sockaddr.sin6_family; }
+  void                set_family()                            { m_sockaddr.sin6_family = AF_INET6; }
+
+  sockaddr*           c_sockaddr()                            { return reinterpret_cast<sockaddr*>(&m_sockaddr); }
+  sockaddr_in6*       c_sockaddr_inet6()                      { return &m_sockaddr; }
+
+  const sockaddr*     c_sockaddr() const                      { return reinterpret_cast<const sockaddr*>(&m_sockaddr); }
+  const sockaddr_in6* c_sockaddr_inet6() const                { return &m_sockaddr; }
+
+  socket_address      normalize_address() const;
+
+  bool                operator == (const socket_address_inet6& rhs) const;
+  bool                operator < (const socket_address_inet6& rhs) const;
+
+private:
+  struct sockaddr_in6 m_sockaddr;
+};
+#endif
+
 // Unique key for the address, excluding port numbers etc.
 class socket_address_key {
 public:
@@ -241,8 +291,10 @@ socket_address::is_valid() const {
   switch (family()) {
   case af_inet:
     return sa_inet()->is_valid();
-//   case af_inet6:
-//     return sa_inet6().is_valid();
+#ifdef RAK_USE_INET6
+  case af_inet6:
+    return sa_inet6()->is_valid();
+#endif
   default:
     return false;
   }
@@ -253,6 +305,10 @@ socket_address::is_bindable() const {
   switch (family()) {
   case af_inet:
     return !sa_inet()->is_address_any();
+#ifdef RAK_USE_INET6
+  case af_inet6:
+    return !sa_inet6()->is_address_any();
+#endif
   default:
     return false;
   }
@@ -263,6 +319,10 @@ socket_address::is_address_any() const {
   switch (family()) {
   case af_inet:
     return sa_inet()->is_address_any();
+#ifdef RAK_USE_INET6
+  case af_inet6:
+    return sa_inet6()->is_address_any();
+#endif
   default:
     return true;
   }
@@ -273,6 +333,10 @@ socket_address::port() const {
   switch (family()) {
   case af_inet:
     return sa_inet()->port();
+#ifdef RAK_USE_INET6
+  case af_inet6:
+    return sa_inet6()->port();
+#endif
   default:
     return 0;
   }
@@ -283,6 +347,10 @@ socket_address::set_port(uint16_t p) {
   switch (family()) {
   case af_inet:
     return sa_inet()->set_port(p);
+#ifdef RAK_USE_INET6
+  case af_inet6:
+    return sa_inet6()->set_port(p);
+#endif
   default:
     break;
   }
@@ -293,6 +361,10 @@ socket_address::address_str() const {
   switch (family()) {
   case af_inet:
     return sa_inet()->address_str();
+#ifdef RAK_USE_INET6
+  case af_inet6:
+    return sa_inet6()->address_str();
+#endif
   default:
     return std::string();
   }
@@ -303,6 +375,10 @@ socket_address::address_c_str(char* buf, socklen_t size) const {
   switch (family()) {
   case af_inet:
     return sa_inet()->address_c_str(buf, size);
+#ifdef RAK_USE_INET6
+  case af_inet6:
+    return sa_inet6()->address_c_str(buf, size);
+#endif
   default:
     return false;
   }
@@ -314,6 +390,12 @@ socket_address::set_address_c_str(const char* a) {
     sa_inet()->set_family();
     return true;
 
+#ifdef RAK_USE_INET6
+  } else if (sa_inet6()->set_address_c_str(a)) {
+    sa_inet6()->set_family();
+    return true;
+#endif
+
   } else {
     return false;
   }
@@ -325,6 +407,10 @@ socket_address::length() const {
   switch(family()) {
   case af_inet:
     return sizeof(sockaddr_in);
+#ifdef RAK_USE_INET6
+  case af_inet6:
+    return sizeof(sockaddr_in6);
+#endif
   default:
     return 0;
   }      
@@ -349,8 +435,10 @@ socket_address::operator == (const socket_address& rhs) const {
   switch (family()) {
   case af_inet:
     return *sa_inet() == *rhs.sa_inet();
-//   case af_inet6:
-//     return *sa_inet6() == *rhs.sa_inet6();
+#ifdef RAK_USE_INET6
+  case af_inet6:
+    return *sa_inet6() == *rhs.sa_inet6();
+#endif
   default:
     throw std::logic_error("socket_address::operator == (rhs) invalid type comparison.");
   }
@@ -364,8 +452,10 @@ socket_address::operator < (const socket_address& rhs) const {
   switch (family()) {
   case af_inet:
     return *sa_inet() < *rhs.sa_inet();
-//   case af_inet6:
-//     return *sa_inet6() < *rhs.sa_inet6();
+#ifdef RAK_USE_INET6
+  case af_inet6:
+    return *sa_inet6() < *rhs.sa_inet6();
+#endif
   default:
     throw std::logic_error("socket_address::operator < (rhs) invalid type comparison.");
   }
@@ -391,6 +481,23 @@ socket_address_inet::set_address_c_str(const char* a) {
   return inet_pton(AF_INET, a, &m_sockaddr.sin_addr);
 }
 
+#ifdef RAK_USE_INET6
+inline socket_address_inet6
+socket_address_inet::to_mapped_address() const {
+  uint32_t addr32[4];
+  addr32[0] = 0;
+  addr32[1] = 0;
+  addr32[2] = htonl(0xffff);
+  addr32[3] = m_sockaddr.sin_addr.s_addr;
+  
+  socket_address_inet6 sa;
+  sa.clear();
+  sa.set_address(*reinterpret_cast<in6_addr *>(addr32));
+  sa.set_port_n(m_sockaddr.sin_port);
+  return sa;
+}
+#endif
+
 inline bool
 socket_address_inet::operator == (const socket_address_inet& rhs) const {
   return
@@ -406,6 +513,59 @@ socket_address_inet::operator < (const socket_address_inet& rhs) const {
      m_sockaddr.sin_port < rhs.m_sockaddr.sin_port);
 }
 
+#ifdef RAK_USE_INET6
+
+inline std::string
+socket_address_inet6::address_str() const {
+  char buf[INET6_ADDRSTRLEN];
+
+  if (!address_c_str(buf, INET6_ADDRSTRLEN))
+    return std::string();
+
+  return std::string(buf);
+}
+
+inline bool
+socket_address_inet6::address_c_str(char* buf, socklen_t size) const {
+  return inet_ntop(family(), &m_sockaddr.sin6_addr, buf, size);
+}
+
+inline bool
+socket_address_inet6::set_address_c_str(const char* a) {
+  return inet_pton(AF_INET6, a, &m_sockaddr.sin6_addr);
+}
+
+inline socket_address
+socket_address_inet6::normalize_address() const {
+  const uint32_t *addr32 = reinterpret_cast<const uint32_t *>(m_sockaddr.sin6_addr.s6_addr);
+  if (addr32[0] == 0 && addr32[1] == 0 && addr32[2] == htonl(0xffff)) {
+    socket_address addr4;
+    addr4.sa_inet()->set_family();
+    addr4.sa_inet()->set_address_n(addr32[3]);
+    addr4.sa_inet()->set_port_n(m_sockaddr.sin6_port);
+    return addr4;
+  }
+  return *reinterpret_cast<const socket_address*>(this);
+}
+
+inline bool
+socket_address_inet6::operator == (const socket_address_inet6& rhs) const {
+  return
+    memcmp(&m_sockaddr.sin6_addr, &rhs.m_sockaddr.sin6_addr, sizeof(in6_addr)) == 0 &&
+    m_sockaddr.sin6_port == rhs.m_sockaddr.sin6_port;
+}
+
+inline bool
+socket_address_inet6::operator < (const socket_address_inet6& rhs) const {
+  int addr_comp = memcmp(&m_sockaddr.sin6_addr, &rhs.m_sockaddr.sin6_addr, sizeof(in6_addr));
+  return
+    addr_comp < 0 ||
+    (addr_comp == 0 ||
+     m_sockaddr.sin6_port < rhs.m_sockaddr.sin6_port);
+}
+
+#endif
+
 }
 
 #endif
diff --git a/src/dht/dht_node.cc b/src/dht/dht_node.cc
index 9d51a28..e0eb306 100644
--- a/src/dht/dht_node.cc
+++ b/src/dht/dht_node.cc
@@ -55,8 +55,15 @@ DhtNode::DhtNode(const HashString& id, const rak::socket_address* sa) :
   m_recentlyInactive(0),
   m_bucket(NULL) {
 
+#ifdef RAK_USE_INET6
+  if (sa->family() != rak::socket_address::af_inet &&
+      (sa->family() != rak::socket_address::af_inet6 || 
+       !sa->sa_inet6()->is_any()))
+    throw resource_error("Address not af_inet or in6addr_any");
+#else
   if (sa->family() != rak::socket_address::af_inet)
     throw resource_error("Address not af_inet");
+#endif
 }
 
 DhtNode::DhtNode(const SimpleString& id, const Object& cache) :
@@ -85,8 +92,20 @@ DhtNode::store_compact(char* buffer) const {
 
 Object*
 DhtNode::store_cache(Object* container) const {
-  container->insert_key("i", m_socketAddress.sa_inet()->address_h());
-  container->insert_key("p", m_socketAddress.sa_inet()->port());
+#ifdef RAK_USE_INET6
+  if (m_socketAddress.family() == rak::socket_address::af_inet6) {
+    // Currently, all we support is in6addr_any (checked in the constructor),
+    // which is effectively equivalent to this. Note that we need to specify
+    // int64_t explicitly here because a zero constant is special in C++ and
+    // thus we need an explicit match.
+    container->insert_key("i", int64_t(0));
+    container->insert_key("p", m_socketAddress.sa_inet6()->port());
+  } else 
+#endif
+  {
+    container->insert_key("i", m_socketAddress.sa_inet()->address_h());
+    container->insert_key("p", m_socketAddress.sa_inet()->port());
+  }
   container->insert_key("t", m_lastSeen);
   return container;
 }
diff --git a/src/dht/dht_server.cc b/src/dht/dht_server.cc
index 256b92b..8c8b380 100644
--- a/src/dht/dht_server.cc
+++ b/src/dht/dht_server.cc
@@ -692,6 +692,16 @@ DhtServer::event_read() {
       if (read < 0)
         break;
 
+#ifdef RAK_USE_INET6
+      // We can currently only process mapped-IPv4 addresses, not real IPv6.
+      // Translate them to an af_inet socket_address.
+      if (sa.family() == rak::socket_address::af_inet6)
+        sa = sa.sa_inet6()->normalize_address();
+#endif
+
+      if (sa.family() != rak::socket_address::af_inet)
+        continue;
+
       total += read;
 
       // If it's not a valid bencode dictionary at all, it's probably not a DHT
diff --git a/src/download/download_info.h b/src/download/download_info.h
index 68fb178..2e27ba3 100644
--- a/src/download/download_info.h
+++ b/src/download/download_info.h
@@ -216,6 +216,28 @@ struct SocketAddressCompact {
   const char*         c_str() const { return reinterpret_cast<const char*>(this); }
 } __attribute__ ((packed));
 
+#ifdef RAK_USE_INET6
+struct SocketAddressCompact6 {
+  SocketAddressCompact6() {}
+  SocketAddressCompact6(in6_addr a, uint16_t p) : addr(a), port(p) {}
+  SocketAddressCompact6(const rak::socket_address_inet6* sa) : addr(sa->address()), port(sa->port_n()) {}
+
+  operator rak::socket_address () const {
+    rak::socket_address sa;
+    sa.sa_inet6()->clear();
+    sa.sa_inet6()->set_port_n(port);
+    sa.sa_inet6()->set_address(addr);
+
+    return sa;
+  }
+
+  in6_addr addr;
+  uint16_t port;
+
+  const char*         c_str() const { return reinterpret_cast<const char*>(this); }
+} __attribute__ ((packed));
+#endif
+
 }
 
 #endif
diff --git a/src/net/Makefile.am b/src/net/Makefile.am
index e07f382..3df0f6d 100644
--- a/src/net/Makefile.am
+++ b/src/net/Makefile.am
@@ -4,6 +4,8 @@ libsub_net_la_SOURCES = \
 	address_list.cc \
 	address_list.h \
 	data_buffer.h \
+	local_addr.cc \
+	local_addr.h \
 	listen.cc \
 	listen.h \
 	protocol_buffer.h \
diff --git a/src/net/Makefile.in b/src/net/Makefile.in
index 1920403..cdbe398 100644
--- a/src/net/Makefile.in
+++ b/src/net/Makefile.in
@@ -54,9 +54,9 @@ CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
 LTLIBRARIES = $(noinst_LTLIBRARIES)
 libsub_net_la_LIBADD =
-am_libsub_net_la_OBJECTS = address_list.lo listen.lo socket_base.lo \
-	socket_datagram.lo socket_fd.lo socket_set.lo socket_stream.lo \
-	throttle_internal.lo throttle_list.lo
+am_libsub_net_la_OBJECTS = address_list.lo local_addr.lo listen.lo \
+	socket_base.lo socket_datagram.lo socket_fd.lo socket_set.lo \
+	socket_stream.lo throttle_internal.lo throttle_list.lo
 libsub_net_la_OBJECTS = $(am_libsub_net_la_OBJECTS)
 DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
 depcomp = $(SHELL) $(top_srcdir)/depcomp
@@ -216,6 +216,8 @@ libsub_net_la_SOURCES = \
 	address_list.cc \
 	address_list.h \
 	data_buffer.h \
+	local_addr.cc \
+	local_addr.h \
 	listen.cc \
 	listen.h \
 	protocol_buffer.h \
@@ -290,6 +292,7 @@ distclean-compile:
 
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/address_list.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/listen.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/local_addr.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket_base.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket_datagram.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket_fd.Plo@am__quote@
diff --git a/src/net/address_list.cc b/src/net/address_list.cc
index e5cf3cb..68a0b22 100644
--- a/src/net/address_list.cc
+++ b/src/net/address_list.cc
@@ -70,16 +70,6 @@ AddressList::parse_address_normal(const Object::list_type& b) {
 }
 
 void
-AddressList::parse_address_compact(SimpleString s) {
-  if (sizeof(const SocketAddressCompact) != 6)
-    throw internal_error("ConnectionList::AddressList::parse_address_compact(...) bad struct size.");
-
-  std::copy(reinterpret_cast<const SocketAddressCompact*>(s.c_str()),
-	    reinterpret_cast<const SocketAddressCompact*>(s.c_str() + s.size() - s.size() % sizeof(SocketAddressCompact)),
-	    std::back_inserter(*this));
-}
-
-void
 AddressList::parse_address_bencode(SimpleString s) {
   if (sizeof(const SocketAddressCompact) != 6)
     throw internal_error("AddressList::parse_address_bencode(...) bad struct size.");
@@ -93,4 +83,26 @@ AddressList::parse_address_bencode(SimpleString s) {
   }
 }
 
+void
+AddressList::parse_address_compact(SimpleString s) {
+  if (sizeof(const SocketAddressCompact) != 6)
+    throw internal_error("ConnectionList::AddressList::parse_address_compact(...) bad struct size.");
+
+  std::copy(reinterpret_cast<const SocketAddressCompact*>(s.c_str()),
+	    reinterpret_cast<const SocketAddressCompact*>(s.c_str() + s.size() - s.size() % sizeof(SocketAddressCompact)),
+	    std::back_inserter(*this));
+}
+
+#ifdef RAK_USE_INET6
+void
+AddressList::parse_address_compact_ipv6(const std::string& s) {
+  if (sizeof(const SocketAddressCompact6) != 18)
+    throw internal_error("ConnectionList::AddressList::parse_address_compact_ipv6(...) bad struct size.");
+
+  std::copy(reinterpret_cast<const SocketAddressCompact6*>(s.c_str()),
+            reinterpret_cast<const SocketAddressCompact6*>(s.c_str() + s.size() - s.size() % sizeof(SocketAddressCompact6)),
+            std::back_inserter(*this));
+}
+#endif
+
 }
diff --git a/src/net/address_list.h b/src/net/address_list.h
index 10dbac4..d264d95 100644
--- a/src/net/address_list.h
+++ b/src/net/address_list.h
@@ -50,8 +50,11 @@ class AddressList : public std::list<rak::socket_address> {
 public:
   // Parse normal or compact list of addresses and add to AddressList
   void                        parse_address_normal(const Object::list_type& b);
-  void                        parse_address_compact(SimpleString s);
   void                        parse_address_bencode(SimpleString s);
+  void                        parse_address_compact(SimpleString s);
+#ifdef RAK_USE_INET6
+  void                        parse_address_compact_ipv6(const std::string& s);
+#endif
 
 private:
   static rak::socket_address  parse_address(const Object& b);
diff --git a/src/net/local_addr.cc b/src/net/local_addr.cc
new file mode 100644
index 0000000..fae3f85
--- /dev/null
+++ b/src/net/local_addr.cc
@@ -0,0 +1,336 @@
+// libTorrent - BitTorrent library
+// Copyright (C) 2005-2007, Jari Sundell
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//
+// In addition, as a special exception, the copyright holders give
+// permission to link the code of portions of this program with the
+// OpenSSL library under certain conditions as described in each
+// individual source file, and distribute linked combinations
+// including the two.
+//
+// You must obey the GNU General Public License in all respects for
+// all of the code used other than OpenSSL.  If you modify file(s)
+// with this exception, you may extend this exception to your version
+// of the file(s), but you are not obligated to do so.  If you do not
+// wish to do so, delete this exception statement from your version.
+// If you delete this exception statement from all source files in the
+// program, then also delete it here.
+//
+// Contact:  Jari Sundell <jaris@ifi.uio.no>
+//
+//           Skomakerveien 33
+//           3185 Skoppum, NORWAY
+
+#include "config.h"
+
+#include <stdio.h>
+#include <ifaddrs.h>
+#include <rak/socket_address.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#ifdef __linux__
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#endif
+
+#include "torrent/exceptions.h"
+#include "socket_fd.h"
+#include "local_addr.h"
+
+namespace torrent {
+namespace {
+
+// IPv4 priority, from highest to lowest:
+//
+//   1. Everything else (global address)
+//   2. Private address space (10.0.0.0/8, 172.16.0.0/16, 192.168.0.0/24)
+//   3. Empty/INADDR_ANY (0.0.0.0)
+//   4. Link-local address (169.254.0.0/16)
+//   5. Localhost (127.0.0.0/8)
+int get_priority_ipv4(const in_addr& addr) {
+  if ((addr.s_addr & htonl(0xff000000U)) == htonl(0x7f000000U)) {
+    return 5;
+  }
+  if (addr.s_addr == htonl(0)) {
+    return 4;
+  }
+  if ((addr.s_addr & htonl(0xffff0000U)) == htonl(0xa9fe0000U)) {
+    return 3;
+  }
+  if ((addr.s_addr & htonl(0xff000000U)) == htonl(0x0a000000U) ||
+      (addr.s_addr & htonl(0xffff0000U)) == htonl(0xac100000U) ||
+      (addr.s_addr & htonl(0xffff0000U)) == htonl(0xc0a80000U)) {
+    return 2;
+  }
+  return 1;
+}
+
+#ifdef RAK_USE_INET6
+// IPv6 priority, from highest to lowest:
+//
+//  1. Global address (2000::/16 not in 6to4 or Teredo)
+//  2. 6to4 (2002::/16)
+//  3. Teredo (2001::/32)
+//  4. Empty/INADDR_ANY (::)
+//  5. Everything else (link-local, ULA, etc.)
+int get_priority_ipv6(const in6_addr& addr) {
+  const uint32_t *addr32 = reinterpret_cast<const uint32_t *>(addr.s6_addr);
+  if (addr32[0] == htonl(0) &&
+      addr32[1] == htonl(0) &&
+      addr32[2] == htonl(0) &&
+      addr32[3] == htonl(0)) {
+    return 4;
+  }
+  if (addr32[0] == htonl(0x20010000)) {
+    return 3;
+  }
+  if ((addr32[0] & htonl(0xffff0000)) == htonl(0x20020000)) {
+    return 2;
+  }
+  if ((addr32[0] & htonl(0xe0000000)) == htonl(0x20000000)) {
+    return 1;
+  }
+  return 5;
+}
+#endif
+
+int get_priority(const rak::socket_address& addr) {
+  switch (addr.family()) {
+  case AF_INET:
+    return get_priority_ipv4(addr.c_sockaddr_inet()->sin_addr);
+#ifdef RAK_USE_INET6
+  case AF_INET6:
+    return get_priority_ipv6(addr.c_sockaddr_inet6()->sin6_addr);
+#endif
+  default:
+    throw torrent::internal_error("Unknown address family given to compare");
+  }
+}
+
+}
+
+#ifdef __linux__
+
+// Linux-specific implementation that understands how to filter away
+// understands how to filter away secondary addresses.
+bool get_local_address(sa_family_t family, rak::socket_address *address) {
+  ifaddrs *ifaddrs;
+  if (getifaddrs(&ifaddrs)) {
+    return false;
+  }
+
+  rak::socket_address best_addr;
+  switch (family) {
+  case AF_INET:
+    best_addr.sa_inet()->clear();
+    break;
+#ifdef RAK_USE_INET6
+  case AF_INET6:
+    best_addr.sa_inet6()->clear();
+    break;
+#endif
+  default:
+    throw torrent::internal_error("Unknown address family given to get_local_address");
+  }
+
+  // The bottom bit of the priority is used to hold if the address is 
+  // a secondary address (e.g. with IPv6 privacy extensions) or not;
+  // secondary addresses have lower priority (higher number).
+  int best_addr_pri = get_priority(best_addr) * 2;
+
+  // Get all the addresses via Linux' netlink interface.
+  int fd = ::socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+  if (fd == -1) {
+    return false;
+  }
+
+  struct sockaddr_nl nladdr;
+  memset(&nladdr, 0, sizeof(nladdr));
+  nladdr.nl_family = AF_NETLINK;
+  if (::bind(fd, (sockaddr *)&nladdr, sizeof(nladdr))) {
+    ::close(fd);
+    return false;
+  }
+
+  const int seq_no = 1;
+  struct {
+    nlmsghdr nh;
+    rtgenmsg g;
+  } req;
+  memset(&req, 0, sizeof(req));
+
+  req.nh.nlmsg_len = sizeof(req);
+  req.nh.nlmsg_type = RTM_GETADDR;
+  req.nh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
+  req.nh.nlmsg_pid = getpid();
+  req.nh.nlmsg_seq = seq_no;
+  req.g.rtgen_family = AF_UNSPEC;
+
+  int ret;
+  do {
+    ret = ::sendto(fd, &req, sizeof(req), 0, (sockaddr *)&nladdr, sizeof(nladdr));
+  } while (ret == -1 && errno == EINTR);
+
+  if (ret == -1) {
+    ::close(fd);
+    return false;
+  }
+
+  bool done = false;
+  do {
+    char buf[4096];
+    socklen_t len = sizeof(nladdr);
+    do {
+      ret = ::recvfrom(fd, buf, sizeof(buf), 0, (sockaddr *)&nladdr, &len);
+    } while (ret == -1 && errno == EINTR);
+
+    if (ret < 0) {
+      ::close(fd);
+      return false;
+    }
+
+    for (const nlmsghdr *nlmsg = (const nlmsghdr *)buf;
+         NLMSG_OK(nlmsg, ret);
+         nlmsg = NLMSG_NEXT(nlmsg, ret)) {
+      if (nlmsg->nlmsg_seq != seq_no)
+        continue;
+      if (nlmsg->nlmsg_type == NLMSG_DONE) {
+        done = true;
+        break;
+      }
+      if (nlmsg->nlmsg_type == NLMSG_ERROR) {
+        ::close(fd);
+        return false;
+      }
+      if (nlmsg->nlmsg_type != RTM_NEWADDR)
+        continue;
+
+      const ifaddrmsg *ifa = (const ifaddrmsg *)NLMSG_DATA(nlmsg);
+
+      if (ifa->ifa_family != family)
+        continue; 
+
+#ifdef IFA_F_OPTIMISTIC
+      if ((ifa->ifa_flags & IFA_F_OPTIMISTIC) != 0)
+        continue;
+#endif
+#ifdef IFA_F_DADFAILED
+      if ((ifa->ifa_flags & IFA_F_DADFAILED) != 0)
+        continue;
+#endif
+#ifdef IFA_F_DEPRECATED
+      if ((ifa->ifa_flags & IFA_F_DEPRECATED) != 0)
+        continue;
+#endif
+#ifdef IFA_F_TENTATIVE
+      if ((ifa->ifa_flags & IFA_F_TENTATIVE) != 0)
+        continue;
+#endif
+  
+      // Since there can be point-to-point links on the machine, we need to keep
+      // track of the addresses we've seen for this interface; if we see both
+      // IFA_LOCAL and IFA_ADDRESS for an interface, keep only the IFA_LOCAL.
+      rak::socket_address this_addr;
+      bool seen_addr = false;
+      int plen = IFA_PAYLOAD(nlmsg);
+      for (const rtattr *rta = IFA_RTA(ifa);
+           RTA_OK(rta, plen);
+	   rta = RTA_NEXT(rta, plen)) {
+        if (rta->rta_type != IFA_LOCAL &&
+            rta->rta_type != IFA_ADDRESS) {
+          continue;
+        }
+        if (rta->rta_type == IFA_ADDRESS && seen_addr) {
+          continue;
+        }
+        seen_addr = true;
+        switch (ifa->ifa_family) {
+        case AF_INET:
+          this_addr.sa_inet()->clear();
+          this_addr.sa_inet()->set_address(*(const in_addr *)RTA_DATA(rta));
+          break;
+#ifdef RAK_USE_INET6
+        case AF_INET6:
+          this_addr.sa_inet6()->clear();
+          this_addr.sa_inet6()->set_address(*(const in6_addr *)RTA_DATA(rta));
+          break;
+#endif
+        }
+      }
+      if (!seen_addr)
+        continue;
+       
+      int this_addr_pri = get_priority(this_addr) * 2;
+      if ((ifa->ifa_flags & IFA_F_SECONDARY) == IFA_F_SECONDARY) {
+        ++this_addr_pri;
+      }
+
+      if (this_addr_pri < best_addr_pri) {
+        best_addr = this_addr;
+        best_addr_pri = this_addr_pri;
+      }
+    }
+  } while (!done);
+
+  ::close(fd);
+  if (!best_addr.is_address_any()) {
+    *address = best_addr;
+    return true;
+  } else {
+    return false;
+  } 
+}
+
+#else
+
+// Generic POSIX variant.
+bool get_local_address(sa_family_t family, rak::socket_address *address) {
+  SocketFd sock;
+  if (!sock.open_datagram()) {
+    return false;
+  }
+
+  rak::socket_address dummy_dest;
+  dummy_dest.clear();
+
+  switch (family) {
+  case rak::socket_address::af_inet:
+    dummy_dest.set_address_c_str("4.0.0.0"); 
+    break;
+#ifdef RAK_USE_INET6
+  case rak::socket_address::af_inet6:
+    dummy_dest.set_address_c_str("2001:700::"); 
+    break;
+#endif
+  default:
+    throw internal_error("Unknown address family");
+  }
+  dummy_dest.set_port(80);
+
+  if (!sock.connect(dummy_dest)) {
+    sock.close();
+    return false;
+  }
+
+  bool ret = sock.getsockname(address);
+  sock.close();
+  return ret;
+}
+
+#endif
+
+}
diff --git a/src/net/local_addr.h b/src/net/local_addr.h
new file mode 100644
index 0000000..43bc820
--- /dev/null
+++ b/src/net/local_addr.h
@@ -0,0 +1,64 @@
+// libTorrent - BitTorrent library
+// Copyright (C) 2005-2007, Jari Sundell
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//
+// In addition, as a special exception, the copyright holders give
+// permission to link the code of portions of this program with the
+// OpenSSL library under certain conditions as described in each
+// individual source file, and distribute linked combinations
+// including the two.
+//
+// You must obey the GNU General Public License in all respects for
+// all of the code used other than OpenSSL.  If you modify file(s)
+// with this exception, you may extend this exception to your version
+// of the file(s), but you are not obligated to do so.  If you do not
+// wish to do so, delete this exception statement from your version.
+// If you delete this exception statement from all source files in the
+// program, then also delete it here.
+//
+// Contact:  Jari Sundell <jaris@ifi.uio.no>
+//
+//           Skomakerveien 33
+//           3185 Skoppum, NORWAY
+
+// A routine to get a local IP address that can be presented to a tracker.
+// (Does not use UPnP etc., so will not understand NAT.)
+// On a machine with multiple network cards, address selection can be a
+// complex process, and in general what's selected is a source/destination
+// address pair. However, this routine will give an approximation that will
+// be good enough for most purposes and users.
+
+#ifndef LIBTORRENT_NET_LOCAL_ADDR_H
+#define LIBTORRENT_NET_LOCAL_ADDR_H
+
+#include <unistd.h>
+
+namespace rak {
+  class socket_address;
+}
+
+namespace torrent {
+
+// Note: family must currently be rak::af_inet or rak::af_inet6
+// (rak::af_unspec won't do); anything else will throw an exception.
+// Returns false if no address of the given family could be found,
+// either because there are none, or because something went wrong in
+// the process (e.g., no free file descriptors).
+bool get_local_address(sa_family_t family, rak::socket_address *address);
+
+}
+
+#endif /* LIBTORRENT_NET_LOCAL_ADDR_H */
diff --git a/src/net/socket_datagram.cc b/src/net/socket_datagram.cc
index b983289..69992e3 100644
--- a/src/net/socket_datagram.cc
+++ b/src/net/socket_datagram.cc
@@ -73,7 +73,13 @@ SocketDatagram::write_datagram(const void* buffer, unsigned int length, rak::soc
   int r;
 
   if (sa != NULL) {
-    r = ::sendto(m_fileDesc, buffer, length, 0, sa->sa_inet()->c_sockaddr(), sizeof(rak::socket_address_inet));
+#ifdef RAK_USE_INET6
+    if (m_ipv6_socket && sa->family() == rak::socket_address::pf_inet) {
+      rak::socket_address_inet6 sa_mapped = sa->sa_inet()->to_mapped_address();
+      r = ::sendto(m_fileDesc, buffer, length, 0, sa_mapped.c_sockaddr(), sizeof(rak::socket_address_inet6));
+    } else
+#endif
+    r = ::sendto(m_fileDesc, buffer, length, 0, sa->c_sockaddr(), sa->length());
   } else {
     r = ::send(m_fileDesc, buffer, length, 0);
   }
diff --git a/src/net/socket_fd.cc b/src/net/socket_fd.cc
index c349d21..20e2403 100644
--- a/src/net/socket_fd.cc
+++ b/src/net/socket_fd.cc
@@ -70,6 +70,11 @@ SocketFd::set_priority(priority_type p) {
   check_valid();
   int opt = p;
 
+#ifdef RAK_USE_INET6
+  if (m_ipv6_socket)
+    return setsockopt(m_fd, IPPROTO_IPV6, IPV6_TCLASS, &opt, sizeof(opt)) == 0;
+  else
+#endif
   return setsockopt(m_fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) == 0;
 }
 
@@ -112,12 +117,36 @@ SocketFd::get_error() const {
 
 bool
 SocketFd::open_stream() {
+#ifdef RAK_USE_INET6
+  m_fd = socket(rak::socket_address::pf_inet6, SOCK_STREAM, IPPROTO_TCP);
+  if (m_fd == -1) {
+    m_ipv6_socket = false;
+    return (m_fd = socket(rak::socket_address::pf_inet, SOCK_STREAM, IPPROTO_TCP)) != -1;
+  }
+  m_ipv6_socket = true;
+
+  int zero = 0;
+  return setsockopt(m_fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)) != -1;
+#else
   return (m_fd = socket(rak::socket_address::pf_inet, SOCK_STREAM, IPPROTO_TCP)) != -1;
+#endif
 }
 
 bool
 SocketFd::open_datagram() {
+#ifdef RAK_USE_INET6
+  m_fd = socket(rak::socket_address::pf_inet6, SOCK_DGRAM, 0);
+  if (m_fd == -1) {
+    m_ipv6_socket = false;
+    return (m_fd = socket(rak::socket_address::pf_inet, SOCK_DGRAM, 0)) != -1;
+  }
+  m_ipv6_socket = true;
+
+  int zero = 0;
+  return setsockopt(m_fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)) != -1;
+#else
   return (m_fd = socket(rak::socket_address::pf_inet, SOCK_DGRAM, 0)) != -1;
+#endif
 }
 
 bool
@@ -135,6 +164,12 @@ bool
 SocketFd::bind(const rak::socket_address& sa) {
   check_valid();
 
+#ifdef RAK_USE_INET6
+  if (m_ipv6_socket && sa.family() == rak::socket_address::pf_inet) {
+    rak::socket_address_inet6 sa_mapped = sa.sa_inet()->to_mapped_address();
+    return !::bind(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped));
+  }
+#endif
   return !::bind(m_fd, sa.c_sockaddr(), sa.length());
 }
 
@@ -142,6 +177,12 @@ bool
 SocketFd::bind(const rak::socket_address& sa, unsigned int length) {
   check_valid();
 
+#ifdef RAK_USE_INET6
+  if (m_ipv6_socket && sa.family() == rak::socket_address::pf_inet) {
+    rak::socket_address_inet6 sa_mapped = sa.sa_inet()->to_mapped_address();
+    return !::bind(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped));
+  }
+#endif
   return !::bind(m_fd, sa.c_sockaddr(), length);
 }
 
@@ -149,10 +190,34 @@ bool
 SocketFd::connect(const rak::socket_address& sa) {
   check_valid();
 
+#ifdef RAK_USE_INET6
+  if (m_ipv6_socket && sa.family() == rak::socket_address::pf_inet) {
+    rak::socket_address_inet6 sa_mapped = sa.sa_inet()->to_mapped_address();
+    return !::connect(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped)) || errno == EINPROGRESS;
+  }
+#endif
   return !::connect(m_fd, sa.c_sockaddr(), sa.length()) || errno == EINPROGRESS;
 }
 
 bool
+SocketFd::getsockname(rak::socket_address *sa) {
+  check_valid();
+
+  socklen_t len = sizeof(rak::socket_address);
+  if (::getsockname(m_fd, sa->c_sockaddr(), &len)) {
+    return false;
+  }
+
+#ifdef RAK_USE_INET6
+  if (m_ipv6_socket && sa->family() == rak::socket_address::af_inet6) {
+    *sa = sa->sa_inet6()->normalize_address();
+  }
+#endif
+
+  return true;
+}
+
+bool
 SocketFd::listen(int size) {
   check_valid();
 
@@ -164,7 +229,18 @@ SocketFd::accept(rak::socket_address* sa) {
   check_valid();
   socklen_t len = sizeof(rak::socket_address);
 
+#ifdef RAK_USE_INET6
+  if (sa == NULL) {
+    return SocketFd(::accept(m_fd, NULL, &len));
+  }
+  int fd = ::accept(m_fd, sa->c_sockaddr(), &len);
+  if (fd != -1 && m_ipv6_socket && sa->family() == rak::socket_address::af_inet6) {
+    *sa = sa->sa_inet6()->normalize_address();
+  }
+  return SocketFd(fd);
+#else
   return SocketFd(::accept(m_fd, sa != NULL ? sa->c_sockaddr() : NULL, &len));
+#endif
 }
 
 // unsigned int
diff --git a/src/net/socket_fd.h b/src/net/socket_fd.h
index a208ad6..d39c413 100644
--- a/src/net/socket_fd.h
+++ b/src/net/socket_fd.h
@@ -77,6 +77,7 @@ public:
   bool                bind(const rak::socket_address& sa);
   bool                bind(const rak::socket_address& sa, unsigned int length);
   bool                connect(const rak::socket_address& sa);
+  bool                getsockname(rak::socket_address* sa);
 
   bool                listen(int size);
   SocketFd            accept(rak::socket_address* sa);
@@ -88,6 +89,9 @@ private:
   inline void         check_valid() const;
 
   int                 m_fd;
+#ifdef RAK_USE_INET6
+  bool                m_ipv6_socket;
+#endif
 };
 
 }
diff --git a/src/torrent/connection_manager.cc b/src/torrent/connection_manager.cc
index 64c4197..152a0a1 100644
--- a/src/torrent/connection_manager.cc
+++ b/src/torrent/connection_manager.cc
@@ -78,13 +78,18 @@ ConnectionManager::ConnectionManager() :
   m_slotResolver(&resolve_host) {
 
   m_bindAddress = (new rak::socket_address())->c_sockaddr();
-  rak::socket_address::cast_from(m_bindAddress)->sa_inet()->clear();
-
   m_localAddress = (new rak::socket_address())->c_sockaddr();
-  rak::socket_address::cast_from(m_localAddress)->sa_inet()->clear();
-
   m_proxyAddress = (new rak::socket_address())->c_sockaddr();
+
+#ifdef RAK_USE_INET6
+  rak::socket_address::cast_from(m_bindAddress)->sa_inet6()->clear();
+  rak::socket_address::cast_from(m_localAddress)->sa_inet6()->clear();
+  rak::socket_address::cast_from(m_proxyAddress)->sa_inet6()->clear();
+#else
+  rak::socket_address::cast_from(m_bindAddress)->sa_inet()->clear();
+  rak::socket_address::cast_from(m_localAddress)->sa_inet()->clear();
   rak::socket_address::cast_from(m_proxyAddress)->sa_inet()->clear();
+#endif
 }
 
 ConnectionManager::~ConnectionManager() {
@@ -123,8 +128,10 @@ void
 ConnectionManager::set_bind_address(const sockaddr* sa) {
   const rak::socket_address* rsa = rak::socket_address::cast_from(sa);
 
+#ifndef RAK_USE_INET6
   if (rsa->family() != rak::socket_address::af_inet)
     throw input_error("Tried to set a bind address that is not an af_inet address.");
+#endif
 
   rak::socket_address::cast_from(m_bindAddress)->copy(*rsa, rsa->length());
 }
@@ -133,8 +140,10 @@ void
 ConnectionManager::set_local_address(const sockaddr* sa) {
   const rak::socket_address* rsa = rak::socket_address::cast_from(sa);
 
+#ifndef RAK_USE_INET6
   if (rsa->family() != rak::socket_address::af_inet)
     throw input_error("Tried to set a local address that is not an af_inet address.");
+#endif
 
   rak::socket_address::cast_from(m_localAddress)->copy(*rsa, rsa->length());
 }
@@ -143,8 +152,10 @@ void
 ConnectionManager::set_proxy_address(const sockaddr* sa) {
   const rak::socket_address* rsa = rak::socket_address::cast_from(sa);
 
+#ifndef RAK_USE_INET6
   if (rsa->family() != rak::socket_address::af_inet)
     throw input_error("Tried to set a proxy address that is not an af_inet address.");
+#endif
 
   rak::socket_address::cast_from(m_proxyAddress)->copy(*rsa, rsa->length());
 }
diff --git a/src/torrent/event.h b/src/torrent/event.h
index 335e6d6..2d6e36c 100644
--- a/src/torrent/event.h
+++ b/src/torrent/event.h
@@ -57,6 +57,10 @@ public:
 
 protected:
   int                 m_fileDesc;
+
+#ifdef RAK_USE_INET6
+  bool                m_ipv6_socket;
+#endif
 };
 
 }
diff --git a/src/torrent/peer/peer_list.cc b/src/torrent/peer/peer_list.cc
index 187ba5b..cef840b 100644
--- a/src/torrent/peer/peer_list.cc
+++ b/src/torrent/peer/peer_list.cc
@@ -65,15 +65,23 @@ socket_address_less(const sockaddr* s1, const sockaddr* s2) {
     // humans.
     return sa1->sa_inet()->address_h() < sa2->sa_inet()->address_h();
 
+#ifdef RAK_USE_INET6
+  else {
+    const in6_addr addr1 = sa1->sa_inet6()->address();
+    const in6_addr addr2 = sa2->sa_inet6()->address();
+    return memcmp(&addr1, &addr2, sizeof(in6_addr)) < 0;
+  }
+#else
   else
-    // When we implement INET6 handling, embed the ipv4 address in
-    // the ipv6 address.
     throw internal_error("socket_address_key(...) tried to compare an invalid family type.");
+#endif
+
 }
 
 inline bool
 socket_address_key::is_comparable(const sockaddr* sa) {
-  return rak::socket_address::cast_from(sa)->family() == rak::socket_address::af_inet;
+  return rak::socket_address::cast_from(sa)->family() == rak::socket_address::af_inet ||
+    rak::socket_address::cast_from(sa)->family() == rak::socket_address::af_inet6;
 }
 
 struct peer_list_equal_port : public std::binary_function<PeerList::reference, uint16_t, bool> {
diff --git a/src/tracker/tracker_http.cc b/src/tracker/tracker_http.cc
index d23cae6..493dd0d 100644
--- a/src/tracker/tracker_http.cc
+++ b/src/tracker/tracker_http.cc
@@ -43,6 +43,7 @@
 
 #include "download/download_info.h"
 #include "net/address_list.h"
+#include "net/local_addr.h"
 #include "torrent/connection_manager.h"
 #include "torrent/exceptions.h"
 #include "torrent/http.h"
@@ -114,9 +115,16 @@ TrackerHttp::send_state(int state) {
 
   const rak::socket_address* localAddress = rak::socket_address::cast_from(manager->connection_manager()->local_address());
 
-  if (localAddress->family() == rak::socket_address::af_inet &&
-      !localAddress->sa_inet()->is_address_any())
+  if (!localAddress->is_address_any())
     s << "&ip=" << localAddress->address_str();
+  
+#ifdef RAK_USE_INET6
+  if (localAddress->is_address_any() || localAddress->family() != rak::socket_address::pf_inet6) {
+    rak::socket_address local_v6;
+    if (get_local_address(rak::socket_address::af_inet6, &local_v6))
+      s << "&ipv6=" << rak::copy_escape_html(local_v6.address_str());
+  }
+#endif
 
   if (info->is_compact())
     s << "&compact=1";
@@ -220,18 +228,34 @@ TrackerHttp::receive_done() {
 
   AddressList l;
 
-  try {
-    // Due to some trackers sending the wrong type when no peers are
-    // available, don't bork on it.
-    if (b.get_key("peers").is_string())
-      l.parse_address_compact(b.get_key_string("peers"));
+  if (!b.has_key("peers")
+#ifdef RAK_USE_INET6
+      && !b.has_key("peers6")
+#endif
+  ) {
+    return receive_failed("No peers returned");
+  }
+
+  if (b.has_key("peers")) {
+    try {
+      // Due to some trackers sending the wrong type when no peers are
+      // available, don't bork on it.
+      if (b.get_key("peers").is_string())
+        l.parse_address_compact(b.get_key_string("peers"));
+
+      else if (b.get_key("peers").is_list())
+        l.parse_address_normal(b.get_key_list("peers"));
 
-    else if (b.get_key("peers").is_list())
-      l.parse_address_normal(b.get_key_list("peers"));
+    } catch (bencode_error& e) {
+      return receive_failed(e.what());
+    }
+  }
 
-  } catch (bencode_error& e) {
-    return receive_failed(e.what());
+#ifdef RAK_USE_INET6
+  if (b.has_key("peers6")) {
+    l.parse_address_compact_ipv6(b.get_key_string("peers6"));
   }
+#endif
 
   close();
   m_parent->receive_success(this, &l);
diff --git a/src/tracker/tracker_udp.cc b/src/tracker/tracker_udp.cc
index dacf21b..63442a3 100644
--- a/src/tracker/tracker_udp.cc
+++ b/src/tracker/tracker_udp.cc
@@ -271,11 +271,18 @@ TrackerUdp::prepare_announce_input() {
 
   const rak::socket_address* localAddress = rak::socket_address::cast_from(manager->connection_manager()->local_address());
 
-  // This code assumes we're have a inet address.
+#ifdef RAK_USE_INET6
+  uint32_t local_addr = 0;
+  if (localAddress->family() == rak::socket_address::af_inet)
+    local_addr = localAddress->sa_inet()->address_n();
+#else
   if (localAddress->family() != rak::socket_address::af_inet)
     throw internal_error("TrackerUdp::prepare_announce_input() info->local_address() not of family AF_INET.");
+  
+  uint32_t local_addr = localAddress->sa_inet()->address_n();
+#endif
 
-  m_writeBuffer->write_32_n(localAddress->sa_inet()->address_n());
+  m_writeBuffer->write_32_n(local_addr);
   m_writeBuffer->write_32(m_parent->key());
   m_writeBuffer->write_32(m_parent->numwant());
   m_writeBuffer->write_16(manager->connection_manager()->listen_port());
