proper default gateway discovery
This commit is contained in:
parent
9ade71a5fb
commit
f36e6a6c4f
|
@ -21,8 +21,6 @@ int main()
|
||||||
if (is_local(i->interface_address)) std::cout << "local ";
|
if (is_local(i->interface_address)) std::cout << "local ";
|
||||||
if (is_loopback(i->interface_address)) std::cout << "loopback ";
|
if (is_loopback(i->interface_address)) std::cout << "loopback ";
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
std::cout << " router: " << router_for_interface(i->interface_address, ec);
|
|
||||||
std::cout << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
address local = guess_local_address(ios);
|
address local = guess_local_address(ios);
|
||||||
|
|
|
@ -55,9 +55,11 @@ namespace libtorrent
|
||||||
|
|
||||||
// returns true if the specified address is on the same
|
// returns true if the specified address is on the same
|
||||||
// local network as us
|
// local network as us
|
||||||
bool in_local_network(asio::io_service& ios, address const& addr, asio::error_code& ec);
|
bool in_local_network(asio::io_service& ios, address const& addr
|
||||||
|
, asio::error_code& ec);
|
||||||
|
|
||||||
address router_for_interface(address const interface, asio::error_code& ec);
|
address get_default_gateway(asio::io_service& ios, address const& addr
|
||||||
|
, asio::error_code& ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
146
src/enum_net.cpp
146
src/enum_net.cpp
|
@ -30,10 +30,12 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined __linux__ || defined BSD
|
#if defined __linux__ || (defined __APPLE__ && __MACH__) || defined __FreeBSD__ || defined __NetBSD__ \
|
||||||
|
|| defined __OpenBSD__ || defined __bsdi__ || defined __DragonFly__
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
|
#include <net/route.h>
|
||||||
#elif defined WIN32
|
#elif defined WIN32
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
@ -67,6 +69,14 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
return address();
|
return address();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool verify_sockaddr(sockaddr_in* sin)
|
||||||
|
{
|
||||||
|
return (sin->sin_len == sizeof(sockaddr_in)
|
||||||
|
&& sin->sin_family == AF_INET)
|
||||||
|
|| (sin->sin_len == sizeof(sockaddr_in6)
|
||||||
|
&& sin->sin_family == AF_INET6);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool in_subnet(address const& addr, ip_interface const& iface)
|
bool in_subnet(address const& addr, ip_interface const& iface)
|
||||||
|
@ -213,15 +223,117 @@ namespace libtorrent
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
address router_for_interface(address const interface, asio::error_code& ec)
|
address get_default_gateway(asio::io_service& ios, address const& interface, asio::error_code& ec)
|
||||||
{
|
{
|
||||||
#ifdef WIN32
|
|
||||||
|
#if defined __linux__ || (defined __APPLE__ && __MACH__) || defined __FreeBSD__ || defined __NetBSD__ \
|
||||||
|
|| defined __OpenBSD__ || defined __bsdi__ || defined __DragonFly__
|
||||||
|
|
||||||
|
struct rt_msg
|
||||||
|
{
|
||||||
|
rt_msghdr m_rtm;
|
||||||
|
char buf[512];
|
||||||
|
};
|
||||||
|
|
||||||
|
rt_msg m;
|
||||||
|
int len = sizeof(rt_msg);
|
||||||
|
bzero(&m, len);
|
||||||
|
m.m_rtm.rtm_type = RTM_GET;
|
||||||
|
m.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY;
|
||||||
|
m.m_rtm.rtm_version = RTM_VERSION;
|
||||||
|
m.m_rtm.rtm_addrs = RTA_DST | RTA_GATEWAY;
|
||||||
|
m.m_rtm.rtm_seq = 0;
|
||||||
|
m.m_rtm.rtm_msglen = len;
|
||||||
|
|
||||||
|
int s = socket(PF_ROUTE, SOCK_RAW, AF_INET);
|
||||||
|
if (s == -1)
|
||||||
|
{
|
||||||
|
ec = asio::error_code(errno, asio::error::system_category);
|
||||||
|
return address_v4::any();
|
||||||
|
}
|
||||||
|
|
||||||
|
int n = write(s, &m, len);
|
||||||
|
if (n == -1)
|
||||||
|
{
|
||||||
|
ec = asio::error_code(errno, asio::error::system_category);
|
||||||
|
close(s);
|
||||||
|
return address_v4::any();
|
||||||
|
}
|
||||||
|
else if (n != len)
|
||||||
|
{
|
||||||
|
ec = asio::error::operation_not_supported;
|
||||||
|
close(s);
|
||||||
|
return address_v4::any();
|
||||||
|
}
|
||||||
|
bzero(&m, len);
|
||||||
|
|
||||||
|
n = read(s, &m, len);
|
||||||
|
if (n == -1)
|
||||||
|
{
|
||||||
|
ec = asio::error_code(errno, asio::error::system_category);
|
||||||
|
close(s);
|
||||||
|
return address_v4::any();
|
||||||
|
}
|
||||||
|
close(s);
|
||||||
|
|
||||||
|
TORRENT_ASSERT(m.m_rtm.rtm_seq == 0);
|
||||||
|
TORRENT_ASSERT(m.m_rtm.rtm_pid == getpid());
|
||||||
|
if (m.m_rtm.rtm_errno)
|
||||||
|
{
|
||||||
|
ec = asio::error_code(m.m_rtm.rtm_errno, asio::error::system_category);
|
||||||
|
return address_v4::any();
|
||||||
|
}
|
||||||
|
if (m.m_rtm.rtm_flags & RTF_UP == 0
|
||||||
|
|| m.m_rtm.rtm_flags & RTF_GATEWAY == 0)
|
||||||
|
{
|
||||||
|
ec = asio::error::operation_not_supported;
|
||||||
|
return address_v4::any();
|
||||||
|
}
|
||||||
|
if (m.m_rtm.rtm_addrs & RTA_DST == 0
|
||||||
|
|| m.m_rtm.rtm_addrs & RTA_GATEWAY == 0)
|
||||||
|
{
|
||||||
|
ec = asio::error::operation_not_supported;
|
||||||
|
return address_v4::any();
|
||||||
|
}
|
||||||
|
if (m.m_rtm.rtm_msglen > len)
|
||||||
|
{
|
||||||
|
ec = asio::error::operation_not_supported;
|
||||||
|
return address_v4::any();
|
||||||
|
}
|
||||||
|
int min_len = sizeof(rt_msghdr) + 2 * sizeof(struct sockaddr_in);
|
||||||
|
if (m.m_rtm.rtm_msglen < min_len)
|
||||||
|
{
|
||||||
|
ec = asio::error::operation_not_supported;
|
||||||
|
return address_v4::any();
|
||||||
|
}
|
||||||
|
|
||||||
|
// default route
|
||||||
|
char* p = m.buf;
|
||||||
|
sockaddr_in* sin = (sockaddr_in*)p;
|
||||||
|
if (!verify_sockaddr(sin))
|
||||||
|
{
|
||||||
|
ec = asio::error::operation_not_supported;
|
||||||
|
return address_v4::any();
|
||||||
|
}
|
||||||
|
|
||||||
|
// default gateway
|
||||||
|
p += sin->sin_len;
|
||||||
|
sin = (sockaddr_in*)p;
|
||||||
|
if (!verify_sockaddr(sin))
|
||||||
|
{
|
||||||
|
ec = asio::error::operation_not_supported;
|
||||||
|
return address_v4::any();
|
||||||
|
}
|
||||||
|
|
||||||
|
return sockaddr_to_address((sockaddr*)sin);
|
||||||
|
|
||||||
|
#elif defined WIN32
|
||||||
|
|
||||||
// Load Iphlpapi library
|
// Load Iphlpapi library
|
||||||
HMODULE iphlp = LoadLibraryA("Iphlpapi.dll");
|
HMODULE iphlp = LoadLibraryA("Iphlpapi.dll");
|
||||||
if (!iphlp)
|
if (!iphlp)
|
||||||
{
|
{
|
||||||
ec = asio::error::fault;
|
ec = asio::error::operation_not_supported;
|
||||||
return address_v4::any();
|
return address_v4::any();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,7 +343,7 @@ namespace libtorrent
|
||||||
if (!GetAdaptersInfo)
|
if (!GetAdaptersInfo)
|
||||||
{
|
{
|
||||||
FreeLibrary(iphlp);
|
FreeLibrary(iphlp);
|
||||||
ec = asio::error::fault;
|
ec = asio::error::operation_not_supported;
|
||||||
return address_v4::any();
|
return address_v4::any();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,7 +352,7 @@ namespace libtorrent
|
||||||
if (GetAdaptersInfo(adapter_info, &out_buf_size) != ERROR_BUFFER_OVERFLOW)
|
if (GetAdaptersInfo(adapter_info, &out_buf_size) != ERROR_BUFFER_OVERFLOW)
|
||||||
{
|
{
|
||||||
FreeLibrary(iphlp);
|
FreeLibrary(iphlp);
|
||||||
ec = asio::error::fault;
|
ec = asio::error::operation_not_supported;
|
||||||
return address_v4::any();
|
return address_v4::any();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,22 +360,29 @@ namespace libtorrent
|
||||||
if (!adapter_info)
|
if (!adapter_info)
|
||||||
{
|
{
|
||||||
FreeLibrary(iphlp);
|
FreeLibrary(iphlp);
|
||||||
ec = asio::error::fault;
|
ec = asio::error::no_memory;
|
||||||
return address_v4::any();
|
return address_v4::any();
|
||||||
}
|
}
|
||||||
|
|
||||||
address ret;
|
address ret;
|
||||||
if (GetAdaptersInfo(adapter_info, &out_buf_size) == NO_ERROR)
|
if (GetAdaptersInfo(adapter_info, &out_buf_size) == NO_ERROR)
|
||||||
{
|
{
|
||||||
PIP_ADAPTER_INFO adapter = adapter_info;
|
|
||||||
while (adapter != 0)
|
for (PIP_ADAPTER_INFO adapter = adapter_info;
|
||||||
|
adapter != 0; adapter = adapter->Next)
|
||||||
{
|
{
|
||||||
if (interface == address::from_string(adapter->IpAddressList.IpAddress.String, ec))
|
address iface = address::from_string(adapter->IpAddressList.IpAddress.String, ec);
|
||||||
|
if (ec)
|
||||||
|
{
|
||||||
|
ec = asio::error_code();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (is_loopback(iface) || is_any(iface)) continue;
|
||||||
|
if (interface == address() || interface == iface)
|
||||||
{
|
{
|
||||||
ret = address::from_string(adapter->GatewayList.IpAddress.String, ec);
|
ret = address::from_string(adapter->GatewayList.IpAddress.String, ec);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
adapter = adapter->Next;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,10 +393,11 @@ namespace libtorrent
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
// TODO: temporary implementation
|
address interface = guess_local_address(ios);
|
||||||
|
|
||||||
if (!interface.is_v4())
|
if (!interface.is_v4())
|
||||||
{
|
{
|
||||||
ec = asio::error::fault;
|
ec = asio::error::operation_not_supported;
|
||||||
return address_v4::any();
|
return address_v4::any();
|
||||||
}
|
}
|
||||||
return address_v4((interface.to_v4().to_ulong() & 0xffffff00) | 1);
|
return address_v4((interface.to_v4().to_ulong() & 0xffffff00) | 1);
|
||||||
|
|
|
@ -45,13 +45,6 @@ using namespace libtorrent;
|
||||||
|
|
||||||
enum { num_mappings = 2 };
|
enum { num_mappings = 2 };
|
||||||
|
|
||||||
namespace libtorrent
|
|
||||||
{
|
|
||||||
// defined in upnp.cpp
|
|
||||||
bool is_local(address const& a);
|
|
||||||
address guess_local_address(asio::io_service&);
|
|
||||||
}
|
|
||||||
|
|
||||||
natpmp::natpmp(io_service& ios, address const& listen_interface, portmap_callback_t const& cb)
|
natpmp::natpmp(io_service& ios, address const& listen_interface, portmap_callback_t const& cb)
|
||||||
: m_callback(cb)
|
: m_callback(cb)
|
||||||
, m_currently_mapping(-1)
|
, m_currently_mapping(-1)
|
||||||
|
@ -72,51 +65,27 @@ natpmp::natpmp(io_service& ios, address const& listen_interface, portmap_callbac
|
||||||
|
|
||||||
void natpmp::rebind(address const& listen_interface)
|
void natpmp::rebind(address const& listen_interface)
|
||||||
{
|
{
|
||||||
address local = address_v4::any();
|
asio::error_code ec;
|
||||||
if (listen_interface != address_v4::any())
|
address gateway = get_default_gateway(m_socket.get_io_service(), listen_interface, ec);
|
||||||
|
if (ec)
|
||||||
{
|
{
|
||||||
local = listen_interface;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
local = guess_local_address(m_socket.io_service());
|
|
||||||
|
|
||||||
if (local == address_v4::any())
|
|
||||||
{
|
|
||||||
disable("local host is probably not on a NATed "
|
|
||||||
"network. disabling NAT-PMP");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||||
m_log << time_now_string()
|
m_log << time_now_string() << " failed to find default router: "
|
||||||
<< " local ip: " << local.to_string() << std::endl;
|
<< ec.message() << std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
disable("failed to find default router");
|
||||||
if (!is_local(local))
|
|
||||||
{
|
|
||||||
// the local address seems to be an external
|
|
||||||
// internet address. Assume it is not behind a NAT
|
|
||||||
disable("local IP is not on a local network");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_disabled = false;
|
m_disabled = false;
|
||||||
|
|
||||||
asio::error_code ec;
|
udp::endpoint nat_endpoint(gateway, 5351);
|
||||||
udp::endpoint nat_endpoint(router_for_interface(local, ec), 5351);
|
|
||||||
if (ec)
|
|
||||||
{
|
|
||||||
disable("cannot retrieve router address");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nat_endpoint == m_nat_endpoint) return;
|
if (nat_endpoint == m_nat_endpoint) return;
|
||||||
m_nat_endpoint = nat_endpoint;
|
m_nat_endpoint = nat_endpoint;
|
||||||
|
|
||||||
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
|
||||||
m_log << "assuming router is at: " << m_nat_endpoint.address().to_string() << std::endl;
|
m_log << time_now_string() << " found router at: "
|
||||||
|
<< m_nat_endpoint.address() << std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_socket.open(udp::v4(), ec);
|
m_socket.open(udp::v4(), ec);
|
||||||
|
|
Loading…
Reference in New Issue