diff -Nur libtorrent-0.12.6.orig/rak/socket_address.h libtorrent-0.12.6/rak/socket_address.h
--- libtorrent-0.12.6.orig/rak/socket_address.h	2009-11-12 09:03:59.000000000 +0100
+++ libtorrent-0.12.6/rak/socket_address.h	2009-12-26 14:44:34.000000000 +0100
@@ -145,7 +145,7 @@
   };
 };
 
-// Remeber to set the AF_INET.
+// Remember to set the AF_INET.
 
 class socket_address_inet {
 public:
@@ -192,6 +192,50 @@
   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; }
+
+  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 +285,10 @@
   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 +299,10 @@
   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 +313,10 @@
   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 +327,10 @@
   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 +341,10 @@
   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 +355,10 @@
   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 +369,10 @@
   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 +384,10 @@
     sa_inet()->set_family();
     return true;
 
+  } else if (sa_inet6()->set_address_c_str(a)) {
+    sa_inet6()->set_family();
+    return true;
+
   } else {
     return false;
   }
@@ -325,6 +399,10 @@
   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 +427,10 @@
   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 +444,10 @@
   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.");
   }
@@ -406,6 +488,46 @@
      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 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 -Nur libtorrent-0.12.6.orig/src/download/download_info.h libtorrent-0.12.6/src/download/download_info.h
--- libtorrent-0.12.6.orig/src/download/download_info.h	2009-11-12 09:03:54.000000000 +0100
+++ libtorrent-0.12.6/src/download/download_info.h	2009-12-27 02:07:43.000000000 +0100
@@ -206,6 +206,28 @@
   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 -Nur libtorrent-0.12.6.orig/src/net/address_list.cc libtorrent-0.12.6/src/net/address_list.cc
--- libtorrent-0.12.6.orig/src/net/address_list.cc	2009-11-12 09:03:52.000000000 +0100
+++ libtorrent-0.12.6/src/net/address_list.cc	2009-12-27 02:11:51.000000000 +0100
@@ -79,4 +79,16 @@
 	    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(SocketAddressCompact)),
+	    std::back_inserter(*this));
+}
+#endif
+
 }
diff -Nur libtorrent-0.12.6.orig/src/net/address_list.h libtorrent-0.12.6/src/net/address_list.h
--- libtorrent-0.12.6.orig/src/net/address_list.h	2009-11-12 09:03:52.000000000 +0100
+++ libtorrent-0.12.6/src/net/address_list.h	2009-12-27 02:08:49.000000000 +0100
@@ -50,6 +50,9 @@
   // Parse normal or compact list of addresses and add to AddressList
   void                        parse_address_normal(const Object::list_type& b);
   void                        parse_address_compact(const std::string& 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 -Nur libtorrent-0.12.6.orig/src/net/local_addr.cc libtorrent-0.12.6/src/net/local_addr.cc
--- libtorrent-0.12.6.orig/src/net/local_addr.cc	1970-01-01 01:00:00.000000000 +0100
+++ libtorrent-0.12.6/src/net/local_addr.cc	2009-12-26 23:54:44.000000000 +0100
@@ -0,0 +1,319 @@
+// 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) {
+  if (addr.s6_addr32[0] == htonl(0) &&
+      addr.s6_addr32[1] == htonl(0) &&
+      addr.s6_addr32[2] == htonl(0) &&
+      addr.s6_addr32[3] == htonl(0)) {
+    return 4;
+  }
+  if (addr.s6_addr32[0] == htonl(0x20010000)) {
+    return 3;
+  }
+  if ((addr.s6_addr32[0] & htonl(0xffff0000)) == htonl(0x20020000)) {
+    return 2;
+  }
+  if ((addr.s6_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; 
+      if ((ifa->ifa_flags & (IFA_F_OPTIMISTIC|IFA_F_DADFAILED|IFA_F_DEPRECATED|IFA_F_TENTATIVE)) != 0)
+        continue;
+  
+      // 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);
+
+  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 -Nur libtorrent-0.12.6.orig/src/net/local_addr.h libtorrent-0.12.6/src/net/local_addr.h
--- libtorrent-0.12.6.orig/src/net/local_addr.h	1970-01-01 01:00:00.000000000 +0100
+++ libtorrent-0.12.6/src/net/local_addr.h	2009-12-26 17:54:26.000000000 +0100
@@ -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 -Nur libtorrent-0.12.6.orig/src/net/Makefile.am libtorrent-0.12.6/src/net/Makefile.am
--- libtorrent-0.12.6.orig/src/net/Makefile.am	2009-11-12 09:03:52.000000000 +0100
+++ libtorrent-0.12.6/src/net/Makefile.am	2009-12-25 21:15:46.000000000 +0100
@@ -4,6 +4,8 @@
 	address_list.cc \
 	address_list.h \
 	data_buffer.h \
+	local_addr.cc \
+	local_addr.h \
 	listen.cc \
 	listen.h \
 	protocol_buffer.h \
diff -Nur libtorrent-0.12.6.orig/src/net/Makefile.in libtorrent-0.12.6/src/net/Makefile.in
--- libtorrent-0.12.6.orig/src/net/Makefile.in	2009-11-30 16:12:18.000000000 +0100
+++ libtorrent-0.12.6/src/net/Makefile.in	2009-12-26 17:10:38.000000000 +0100
@@ -54,9 +54,9 @@
 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 @@
 	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 @@
 
 @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 -Nur libtorrent-0.12.6.orig/src/net/socket_fd.cc libtorrent-0.12.6/src/net/socket_fd.cc
--- libtorrent-0.12.6.orig/src/net/socket_fd.cc	2009-11-12 09:03:52.000000000 +0100
+++ libtorrent-0.12.6/src/net/socket_fd.cc	2009-12-26 16:50:59.000000000 +0100
@@ -52,6 +52,26 @@
 
 namespace torrent {
 
+#ifdef RAK_USE_INET6
+namespace { 
+
+rak::socket_address normalize_ipv6_address(const rak::socket_address& addr6) {
+  const sockaddr_in6 *addr = (sockaddr_in6 *)addr6.c_sockaddr();
+  if (addr->sin6_addr.s6_addr32[0] == 0 &&
+      addr->sin6_addr.s6_addr32[1] == 0 &&
+      addr->sin6_addr.s6_addr32[2] == htonl(0xffff)) {
+    rak::socket_address addr4;
+    addr4.sa_inet()->set_family();
+    addr4.sa_inet()->set_address_n(addr->sin6_addr.s6_addr32[3]);
+    addr4.sa_inet()->set_port_n(addr->sin6_port);
+    return addr4;
+  }
+  return addr6;
+}
+
+}
+#endif
+
 inline void
 SocketFd::check_valid() const {
   if (!is_valid())
@@ -112,12 +132,36 @@
 
 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
@@ -149,10 +193,41 @@
 SocketFd::connect(const rak::socket_address& sa) {
   check_valid();
 
+#ifdef RAK_USE_INET6
+  if (m_ipv6_socket && sa.family() == rak::socket_address::pf_inet) {
+    sockaddr_in6 mapped_addr;
+    memset(&mapped_addr, 0, sizeof(mapped_addr));
+    mapped_addr.sin6_family = AF_INET6;
+    mapped_addr.sin6_addr.s6_addr32[0] = 0;
+    mapped_addr.sin6_addr.s6_addr32[1] = 0;
+    mapped_addr.sin6_addr.s6_addr32[2] = htonl(0xffff);
+    mapped_addr.sin6_addr.s6_addr32[3] = sa.sa_inet()->address_n();
+    mapped_addr.sin6_port = sa.sa_inet()->port_n();
+    return !::connect(m_fd, (sockaddr *)&mapped_addr, sizeof(mapped_addr)) || 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 = normalize_ipv6_address(*sa);
+  }
+#endif
+
+  return true;
+}
+
+bool
 SocketFd::listen(int size) {
   check_valid();
 
@@ -164,7 +239,18 @@
   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 = normalize_ipv6_address(*sa);
+  }
+  return SocketFd(fd);
+#else
   return SocketFd(::accept(m_fd, sa != NULL ? sa->c_sockaddr() : NULL, &len));
+#endif
 }
 
 // unsigned int
diff -Nur libtorrent-0.12.6.orig/src/net/socket_fd.h libtorrent-0.12.6/src/net/socket_fd.h
--- libtorrent-0.12.6.orig/src/net/socket_fd.h	2009-11-12 09:03:52.000000000 +0100
+++ libtorrent-0.12.6/src/net/socket_fd.h	2009-12-25 20:42:52.000000000 +0100
@@ -77,6 +77,7 @@
   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 @@
   inline void         check_valid() const;
 
   int                 m_fd;
+#ifdef RAK_USE_INET6
+  bool                m_ipv6_socket;
+#endif
 };
 
 }
diff -Nur libtorrent-0.12.6.orig/src/torrent/connection_manager.cc libtorrent-0.12.6/src/torrent/connection_manager.cc
--- libtorrent-0.12.6.orig/src/torrent/connection_manager.cc	2009-11-12 09:03:58.000000000 +0100
+++ libtorrent-0.12.6/src/torrent/connection_manager.cc	2009-12-26 00:47:03.000000000 +0100
@@ -78,13 +78,18 @@
   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 @@
 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 @@
 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 @@
 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 -Nur libtorrent-0.12.6.orig/src/torrent/event.h libtorrent-0.12.6/src/torrent/event.h
--- libtorrent-0.12.6.orig/src/torrent/event.h	2009-11-12 09:03:58.000000000 +0100
+++ libtorrent-0.12.6/src/torrent/event.h	2009-12-26 14:34:30.000000000 +0100
@@ -57,6 +57,12 @@
 
 protected:
   int                 m_fileDesc;
+
+#ifdef RAK_USE_INET6
+  // Since Event and SocketFd are casted back and forth to each other,
+  // we need a bool here to make them the same size and layout.
+  bool                m_dummyBool;
+#endif
 };
 
 }
diff -Nur libtorrent-0.12.6.orig/src/torrent/peer/peer_list.cc libtorrent-0.12.6/src/torrent/peer/peer_list.cc
--- libtorrent-0.12.6.orig/src/torrent/peer/peer_list.cc	2009-11-12 09:03:56.000000000 +0100
+++ libtorrent-0.12.6/src/torrent/peer/peer_list.cc	2009-12-25 17:06:29.000000000 +0100
@@ -65,15 +65,17 @@
     // humans.
     return sa1->sa_inet()->address_h() < sa2->sa_inet()->address_h();
 
-  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.");
+  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;
+  }
 }
 
 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 -Nur libtorrent-0.12.6.orig/src/tracker/tracker_http.cc libtorrent-0.12.6/src/tracker/tracker_http.cc
--- libtorrent-0.12.6.orig/src/tracker/tracker_http.cc	2009-11-12 09:03:55.000000000 +0100
+++ libtorrent-0.12.6/src/tracker/tracker_http.cc	2009-12-27 02:09:34.000000000 +0100
@@ -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 @@
 
   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 @@
 
   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");
+  }
 
-    else if (b.get_key("peers").is_list())
-      l.parse_address_normal(b.get_key_list("peers"));
+  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"));
+
+    } 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 -Nur libtorrent-0.12.6.orig/src/tracker/tracker_udp.cc libtorrent-0.12.6/src/tracker/tracker_udp.cc
--- libtorrent-0.12.6.orig/src/tracker/tracker_udp.cc	2009-11-12 09:03:55.000000000 +0100
+++ libtorrent-0.12.6/src/tracker/tracker_udp.cc	2009-12-26 17:10:24.000000000 +0100
@@ -271,11 +271,18 @@
 
   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());

