simplify natpmp gateway and local address discovery
This commit is contained in:
parent
d7a60442bd
commit
a477a53b80
|
@ -41,6 +41,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <sys/socket.h> // for SO_BINDTODEVICE
|
||||
#endif
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include "libtorrent/aux_/disable_warnings_pop.hpp"
|
||||
|
||||
#include "libtorrent/io_service_fwd.hpp"
|
||||
|
@ -94,6 +96,9 @@ namespace libtorrent {
|
|||
TORRENT_EXTRA_EXPORT bool in_local_network(std::vector<ip_interface> const& net
|
||||
, address const& addr);
|
||||
|
||||
TORRENT_EXTRA_EXPORT boost::optional<ip_route> get_default_route(io_service& ios
|
||||
, string_view device, bool v6, error_code& ec);
|
||||
|
||||
// returns the first default gateway found if device is empty
|
||||
TORRENT_EXTRA_EXPORT address get_default_gateway(io_service& ios
|
||||
, string_view device, bool v6, error_code& ec);
|
||||
|
|
|
@ -45,6 +45,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/aux_/disable_warnings_push.hpp"
|
||||
|
||||
#include <boost/asio/ip/host_name.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#if TORRENT_USE_IFCONF
|
||||
#include <sys/ioctl.h>
|
||||
|
@ -844,10 +845,10 @@ int _System __libsocket_sysctl(int* mib, u_int namelen, void *oldp, size_t *oldl
|
|||
return ret;
|
||||
}
|
||||
|
||||
address get_default_gateway(io_service& ios
|
||||
, string_view device, bool v6, error_code& ec)
|
||||
boost::optional<ip_route> get_default_route(io_service& ios
|
||||
, string_view const device, bool const v6, error_code& ec)
|
||||
{
|
||||
std::vector<ip_route> ret = enum_routes(ios, ec);
|
||||
std::vector<ip_route> const ret = enum_routes(ios, ec);
|
||||
auto const i = std::find_if(ret.begin(), ret.end()
|
||||
, [device,v6](ip_route const& r)
|
||||
{
|
||||
|
@ -855,8 +856,15 @@ int _System __libsocket_sysctl(int* mib, u_int namelen, void *oldp, size_t *oldl
|
|||
&& r.destination.is_v6() == v6
|
||||
&& (device.empty() || r.name == device);
|
||||
});
|
||||
if (i == ret.end()) return address();
|
||||
return i->gateway;
|
||||
if (i == ret.end()) return boost::none;
|
||||
return *i;
|
||||
}
|
||||
|
||||
address get_default_gateway(io_service& ios
|
||||
, string_view const device, bool const v6, error_code& ec)
|
||||
{
|
||||
auto const default_route = get_default_route(ios, device, v6, ec);
|
||||
return default_route ? default_route->gateway : address();
|
||||
}
|
||||
|
||||
std::vector<ip_route> enum_routes(io_service& ios, error_code& ec)
|
||||
|
|
|
@ -156,24 +156,58 @@ void natpmp::start(address local_address, std::string device)
|
|||
// if necessary
|
||||
m_version = version_pcp;
|
||||
|
||||
// we really want a device name to get the right default gateway
|
||||
// try to find one even if the listen socket isn't bound to a device
|
||||
if (device.empty())
|
||||
{
|
||||
device = device_for_address(local_address, m_socket.get_io_service(), ec);
|
||||
// if this fails fall back to using the first default gateway in the
|
||||
// routing table
|
||||
ec.clear();
|
||||
}
|
||||
|
||||
auto const route = get_default_route(m_socket.get_io_service()
|
||||
, device, local_address.is_v6(), ec);
|
||||
|
||||
if (!route)
|
||||
{
|
||||
#ifndef TORRENT_DISABLE_LOGGING
|
||||
if (should_log())
|
||||
{
|
||||
log("failed to find default route for \"%s\" %s: %s"
|
||||
, device.c_str(), local_address.to_string().c_str()
|
||||
, convert_from_native(ec.message()).c_str());
|
||||
}
|
||||
#endif
|
||||
disable(ec);
|
||||
return;
|
||||
}
|
||||
|
||||
if (device.empty()) device = route->name;
|
||||
|
||||
TORRENT_ASSERT(!device.empty());
|
||||
|
||||
// PCP requires reporting the source address at the application
|
||||
// layer so the socket MUST be bound to a specific address
|
||||
// if the caller didn't specify one then get the first suitable
|
||||
// address from the OS
|
||||
if (local_address.is_unspecified())
|
||||
{
|
||||
for (auto const& a : enum_net_interfaces(m_socket.get_io_service(), ec))
|
||||
{
|
||||
if (a.interface_address.is_loopback()) continue;
|
||||
if (a.interface_address.is_v4() != local_address.is_v4()) continue;
|
||||
if (a.interface_address.is_v6() && is_local(a.interface_address)) continue;
|
||||
if (!device.empty() && a.name != device) continue;
|
||||
local_address = a.interface_address;
|
||||
device = a.name;
|
||||
break;
|
||||
}
|
||||
std::vector<ip_interface> const net = enum_net_interfaces(
|
||||
m_socket.get_io_service(), ec);
|
||||
|
||||
if (local_address.is_unspecified())
|
||||
auto const it = std::find_if(net.begin(), net.end(), [&](ip_interface const& i)
|
||||
{
|
||||
return i.interface_address.is_v4() == local_address.is_v4()
|
||||
&& (i.interface_address.is_v4() || !is_local(i.interface_address))
|
||||
&& i.name == device;
|
||||
});
|
||||
|
||||
if (it != net.end())
|
||||
{
|
||||
local_address = it->interface_address;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if we can't get a specific address to bind to we'll have
|
||||
// to fall back to NAT-PMP
|
||||
|
@ -198,34 +232,9 @@ void natpmp::start(address local_address, std::string device)
|
|||
}
|
||||
}
|
||||
|
||||
// we really want a device name to get the right default gateway
|
||||
// try to find one even if the listen socket isn't bound to a device
|
||||
if (device.empty())
|
||||
{
|
||||
device = device_for_address(local_address, m_socket.get_io_service(), ec);
|
||||
// if this fails fall back to using the first default gateway in the
|
||||
// routing table
|
||||
ec.clear();
|
||||
}
|
||||
|
||||
address const gateway = get_default_gateway(m_socket.get_io_service()
|
||||
, device, local_address.is_v6(), ec);
|
||||
if (ec || gateway.is_unspecified())
|
||||
{
|
||||
#ifndef TORRENT_DISABLE_LOGGING
|
||||
if (should_log())
|
||||
{
|
||||
log("failed to find default route for %s: %s"
|
||||
, local_address.to_string().c_str(), convert_from_native(ec.message()).c_str());
|
||||
}
|
||||
#endif
|
||||
disable(ec);
|
||||
return;
|
||||
}
|
||||
|
||||
m_disabled = false;
|
||||
|
||||
udp::endpoint nat_endpoint(gateway, 5351);
|
||||
udp::endpoint const nat_endpoint(route->gateway, 5351);
|
||||
if (nat_endpoint == m_nat_endpoint) return;
|
||||
m_nat_endpoint = nat_endpoint;
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ int main()
|
|||
|
||||
for (auto const& i : net)
|
||||
{
|
||||
address iface_def_gw = get_default_gateway(ios, i.name, i.interface_address.is_v6(), ec);
|
||||
address const iface_def_gw = get_default_gateway(ios, i.name, i.interface_address.is_v6(), ec);
|
||||
std::printf("%-34s%-45s%-20s%s%s%-20s%-34s%s %s\n"
|
||||
, i.interface_address.to_string(ec).c_str()
|
||||
, i.netmask.to_string(ec).c_str()
|
||||
|
|
Loading…
Reference in New Issue