forked from premiere/premiere-libtorrent
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_loopback(i->interface_address)) std::cout << "loopback ";
|
||||
std::cout << std::endl;
|
||||
std::cout << " router: " << router_for_interface(i->interface_address, ec);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
address local = guess_local_address(ios);
|
||||
|
|
|
@ -55,9 +55,11 @@ namespace libtorrent
|
|||
|
||||
// returns true if the specified address is on the same
|
||||
// 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
|
||||
|
|
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 <netinet/in.h>
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
#elif defined WIN32
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
@ -67,6 +69,14 @@ namespace libtorrent
|
|||
}
|
||||
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)
|
||||
|
@ -213,15 +223,117 @@ namespace libtorrent
|
|||
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
|
||||
HMODULE iphlp = LoadLibraryA("Iphlpapi.dll");
|
||||
if (!iphlp)
|
||||
{
|
||||
ec = asio::error::fault;
|
||||
ec = asio::error::operation_not_supported;
|
||||
return address_v4::any();
|
||||
}
|
||||
|
||||
|
@ -231,7 +343,7 @@ namespace libtorrent
|
|||
if (!GetAdaptersInfo)
|
||||
{
|
||||
FreeLibrary(iphlp);
|
||||
ec = asio::error::fault;
|
||||
ec = asio::error::operation_not_supported;
|
||||
return address_v4::any();
|
||||
}
|
||||
|
||||
|
@ -240,7 +352,7 @@ namespace libtorrent
|
|||
if (GetAdaptersInfo(adapter_info, &out_buf_size) != ERROR_BUFFER_OVERFLOW)
|
||||
{
|
||||
FreeLibrary(iphlp);
|
||||
ec = asio::error::fault;
|
||||
ec = asio::error::operation_not_supported;
|
||||
return address_v4::any();
|
||||
}
|
||||
|
||||
|
@ -248,22 +360,29 @@ namespace libtorrent
|
|||
if (!adapter_info)
|
||||
{
|
||||
FreeLibrary(iphlp);
|
||||
ec = asio::error::fault;
|
||||
ec = asio::error::no_memory;
|
||||
return address_v4::any();
|
||||
}
|
||||
|
||||
address ret;
|
||||
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);
|
||||
break;
|
||||
}
|
||||
adapter = adapter->Next;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -274,10 +393,11 @@ namespace libtorrent
|
|||
return ret;
|
||||
|
||||
#else
|
||||
// TODO: temporary implementation
|
||||
address interface = guess_local_address(ios);
|
||||
|
||||
if (!interface.is_v4())
|
||||
{
|
||||
ec = asio::error::fault;
|
||||
ec = asio::error::operation_not_supported;
|
||||
return address_v4::any();
|
||||
}
|
||||
return address_v4((interface.to_v4().to_ulong() & 0xffffff00) | 1);
|
||||
|
|
|
@ -45,13 +45,6 @@ using namespace libtorrent;
|
|||
|
||||
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)
|
||||
: m_callback(cb)
|
||||
, 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)
|
||||
{
|
||||
address local = address_v4::any();
|
||||
if (listen_interface != address_v4::any())
|
||||
asio::error_code ec;
|
||||
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)
|
||||
m_log << time_now_string()
|
||||
<< " local ip: " << local.to_string() << std::endl;
|
||||
m_log << time_now_string() << " failed to find default router: "
|
||||
<< ec.message() << std::endl;
|
||||
#endif
|
||||
|
||||
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");
|
||||
disable("failed to find default router");
|
||||
return;
|
||||
}
|
||||
|
||||
m_disabled = false;
|
||||
|
||||
asio::error_code ec;
|
||||
udp::endpoint nat_endpoint(router_for_interface(local, ec), 5351);
|
||||
if (ec)
|
||||
{
|
||||
disable("cannot retrieve router address");
|
||||
return;
|
||||
}
|
||||
|
||||
udp::endpoint nat_endpoint(gateway, 5351);
|
||||
if (nat_endpoint == m_nat_endpoint) return;
|
||||
m_nat_endpoint = nat_endpoint;
|
||||
|
||||
#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
|
||||
|
||||
m_socket.open(udp::v4(), ec);
|
||||
|
|
Loading…
Reference in New Issue