From 633f1749479245379f50761ce579fd077ae7c192 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Wed, 16 May 2007 21:36:27 +0000 Subject: [PATCH] improved natpmp, upnp and lsd --- include/libtorrent/upnp.hpp | 2 ++ src/lsd.cpp | 35 +++++++---------------------------- src/natpmp.cpp | 29 +++++++++++++++++------------ src/upnp.cpp | 24 ++++++++++++++++++------ 4 files changed, 44 insertions(+), 46 deletions(-) diff --git a/include/libtorrent/upnp.hpp b/include/libtorrent/upnp.hpp index aac11931f..6133ceca1 100644 --- a/include/libtorrent/upnp.hpp +++ b/include/libtorrent/upnp.hpp @@ -51,6 +51,8 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { +bool is_local(address const& a); + // int: external tcp port // int: external udp port // std::string: error message diff --git a/src/lsd.cpp b/src/lsd.cpp index 5fa0402dd..5c881501c 100644 --- a/src/lsd.cpp +++ b/src/lsd.cpp @@ -72,36 +72,11 @@ lsd::~lsd() {} void lsd::rebind(address const& listen_interface) { - address_v4 local_ip; - if (listen_interface.is_v4() && listen_interface != address_v4::from_string("0.0.0.0")) + address_v4 local_ip = address_v4::any(); + if (listen_interface.is_v4() && listen_interface != address_v4::any()) { local_ip = listen_interface.to_v4(); } - else - { - // make a best guess of the interface we're using and its IP - udp::resolver r(m_socket.io_service()); - udp::resolver::iterator i = r.resolve(udp::resolver::query(asio::ip::host_name(), "0")); - for (;i != udp::resolver_iterator(); ++i) - { - // ignore the loopback - if (i->endpoint().address() == address_v4((127 << 24) + 1)) continue; - // ignore non-IPv4 addresses - if (i->endpoint().address().is_v4()) break; - } - - if (i == udp::resolver_iterator()) - { - #if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) - m_log << "local host name did not resolve to an IPv4 address. " - "disabling local service discovery" << std::endl; - #endif - m_disabled = true; - return; - } - - local_ip = i->endpoint().address().to_v4(); - } try { @@ -123,8 +98,12 @@ void lsd::rebind(address const& listen_interface) #endif m_socket.set_option(join_group(lsd_multicast_address)); - m_socket.set_option(outbound_interface(address_v4())); + m_socket.set_option(outbound_interface(local_ip)); +#ifdef NDEBUG m_socket.set_option(enable_loopback(false)); +#else + m_socket.set_option(enable_loopback(true)); +#endif m_socket.set_option(hops(255)); } catch (std::exception& e) diff --git a/src/natpmp.cpp b/src/natpmp.cpp index 22102b016..d3ac9c95b 100644 --- a/src/natpmp.cpp +++ b/src/natpmp.cpp @@ -42,6 +42,11 @@ using namespace libtorrent; enum { num_mappings = 2 }; +namespace libtorrent +{ + bool is_local(address const& a); +} + natpmp::natpmp(io_service& ios, address const& listen_interface, portmap_callback_t const& cb) : m_callback(cb) , m_currently_mapping(-1) @@ -62,8 +67,8 @@ natpmp::natpmp(io_service& ios, address const& listen_interface, portmap_callbac void natpmp::rebind(address const& listen_interface) try { - address_v4 local; - if (listen_interface.is_v4() && listen_interface != address_v4::from_string("0.0.0.0")) + address_v4 local = address_v4::any(); + if (listen_interface.is_v4() && listen_interface != address_v4::any()) { local = listen_interface.to_v4(); } @@ -76,30 +81,27 @@ void natpmp::rebind(address const& listen_interface) try { // ignore the loopback if (i->endpoint().address() == address_v4((127 << 24) + 1)) continue; + // ignore addresses that are not on a local network + if (!is_local(i->endpoint().address())) continue; // ignore non-IPv4 addresses if (i->endpoint().address().is_v4()) break; } if (i == udp::resolver_iterator()) { - throw std::runtime_error("local host name did not resolve to an " - "IPv4 address. disabling NAT-PMP"); + throw std::runtime_error("local host is probably not on a NATed " + "network. disabling NAT-PMP"); } local = i->endpoint().address().to_v4(); } - m_socket.open(udp::v4()); - m_socket.bind(udp::endpoint(local, 0)); - #if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) m_log << time_now_string() << " local ip: " << local.to_string() << std::endl; #endif - if ((local.to_ulong() & 0xff000000) != 0x0a000000 - && (local.to_ulong() & 0xfff00000) != 0xac100000 - && (local.to_ulong() & 0xffff0000) != 0xc0a80000) + if (!is_local(local)) { // the local address seems to be an external // internet address. Assume it is not behind a NAT @@ -108,13 +110,13 @@ void natpmp::rebind(address const& listen_interface) try m_disabled = false; + // assume the router is located on the local + // network as x.x.x.1 udp::endpoint nat_endpoint( address_v4((local.to_ulong() & 0xffffff00) | 1), 5351); if (nat_endpoint == m_nat_endpoint) return; - // assume the router is located on the local - // network as x.x.x.1 // TODO: find a better way to figure out the router IP m_nat_endpoint = nat_endpoint; @@ -122,6 +124,9 @@ void natpmp::rebind(address const& listen_interface) try m_log << "assuming router is at: " << m_nat_endpoint.address().to_string() << std::endl; #endif + m_socket.open(udp::v4()); + m_socket.bind(udp::endpoint(address_v4::any(), 0)); + for (int i = 0; i < num_mappings; ++i) { if (m_mappings[i].local_port == 0) diff --git a/src/upnp.cpp b/src/upnp.cpp index 8b13ccbd2..8155bb26a 100644 --- a/src/upnp.cpp +++ b/src/upnp.cpp @@ -52,6 +52,18 @@ using namespace libtorrent; address_v4 upnp::upnp_multicast_address; udp::endpoint upnp::upnp_multicast_endpoint; +namespace libtorrent +{ + bool is_local(address const& a) + { + if (a.is_v6()) return false; + address_v4 a4 = a.to_v4(); + return ((a4.to_ulong() & 0xff000000) == 0x0a000000 + || (a4.to_ulong() & 0xfff00000) == 0xac100000 + || (a4.to_ulong() & 0xffff0000) == 0xc0a80000); + } +} + upnp::upnp(io_service& ios, connection_queue& cc , address const& listen_interface, std::string const& user_agent , portmap_callback_t const& cb) @@ -84,7 +96,7 @@ upnp::~upnp() void upnp::rebind(address const& listen_interface) try { - if (listen_interface.is_v4() && listen_interface != address_v4::from_string("0.0.0.0")) + if (listen_interface.is_v4() && listen_interface != address_v4::any()) { m_local_ip = listen_interface.to_v4(); } @@ -97,14 +109,16 @@ void upnp::rebind(address const& listen_interface) try { // ignore the loopback if (i->endpoint().address() == address_v4((127 << 24) + 1)) continue; + // ignore addresses that are not on a local network + if (!is_local(i->endpoint().address())) continue; // ignore non-IPv4 addresses if (i->endpoint().address().is_v4()) break; } if (i == udp::resolver_iterator()) { - throw std::runtime_error("local host name did not resolve to an " - "IPv4 address. disabling UPnP"); + throw std::runtime_error("local host is probably not on a NATed " + "network. disabling UPnP"); } m_local_ip = i->endpoint().address().to_v4(); @@ -115,9 +129,7 @@ void upnp::rebind(address const& listen_interface) try << " local ip: " << m_local_ip.to_string() << std::endl; #endif - if ((m_local_ip.to_ulong() & 0xff000000) != 0x0a000000 - && (m_local_ip.to_ulong() & 0xfff00000) != 0xac100000 - && (m_local_ip.to_ulong() & 0xffff0000) != 0xc0a80000) + if (!is_local(m_local_ip)) { // the local address seems to be an external // internet address. Assume it is not behind a NAT