bind upnp requests to correct local address

This commit is contained in:
arvidn 2017-05-07 20:43:55 -04:00 committed by Arvid Norberg
parent f8bda070be
commit ff63557f58
7 changed files with 43 additions and 40 deletions

View File

@ -1,3 +1,4 @@
* bind upnp requests to correct local address
* save resume data when removing web seeds * save resume data when removing web seeds
* fix proxying of https connections * fix proxying of https connections
* fix race condition in disk I/O storage class * fix race condition in disk I/O storage class

View File

@ -104,7 +104,7 @@ struct TORRENT_EXTRA_EXPORT http_connection
std::string m_sendbuffer; std::string m_sendbuffer;
void get(std::string const& url, time_duration timeout = seconds(30) void get(std::string const& url, time_duration timeout = seconds(30)
, int prio = 0, aux::proxy_settings const* ps = 0, int handle_redirects = 5 , int prio = 0, aux::proxy_settings const* ps = NULL, int handle_redirects = 5
, std::string const& user_agent = std::string() , std::string const& user_agent = std::string()
, address const& bind_addr = address_v4::any() , address const& bind_addr = address_v4::any()
, int resolve_flags = 0, std::string const& auth_ = std::string() , int resolve_flags = 0, std::string const& auth_ = std::string()
@ -114,7 +114,7 @@ struct TORRENT_EXTRA_EXPORT http_connection
); );
void start(std::string const& hostname, int port void start(std::string const& hostname, int port
, time_duration timeout, int prio = 0, aux::proxy_settings const* ps = 0 , time_duration timeout, int prio = 0, aux::proxy_settings const* ps = NULL
, bool ssl = false, int handle_redirect = 5 , bool ssl = false, int handle_redirect = 5
, address const& bind_addr = address_v4::any() , address const& bind_addr = address_v4::any()
, int resolve_flags = 0 , int resolve_flags = 0

View File

@ -75,7 +75,7 @@ public:
void close(); void close();
private: private:
boost::shared_ptr<natpmp> self() { return shared_from_this(); } boost::shared_ptr<natpmp> self() { return shared_from_this(); }
void update_mapping(int i, mutex::scoped_lock& l); void update_mapping(int i, mutex::scoped_lock& l);

View File

@ -187,13 +187,13 @@ public:
// portmap_alert_ respectively. If The mapping fails immediately, the return value // portmap_alert_ respectively. If The mapping fails immediately, the return value
// is -1, which means failure. There will not be any error alert notification for // is -1, which means failure. There will not be any error alert notification for
// mappings that fail with a -1 return value. // mappings that fail with a -1 return value.
int add_mapping(protocol_type p, int external_port, int local_port); int add_mapping(protocol_type p, int external_port, tcp::endpoint local_ep);
// This function removes a port mapping. ``mapping_index`` is the index that refers // This function removes a port mapping. ``mapping_index`` is the index that refers
// to the mapping you want to remove, which was returned from add_mapping(). // to the mapping you want to remove, which was returned from add_mapping().
void delete_mapping(int mapping_index); void delete_mapping(int mapping_index);
bool get_mapping(int mapping_index, int& local_port, int& external_port, int& protocol) const; bool get_mapping(int mapping_index, tcp::endpoint& local_ep, int& external_port, int& protocol) const;
void discover_device(); void discover_device();
void close(); void close();
@ -261,11 +261,10 @@ private:
global_mapping_t() global_mapping_t()
: protocol(none) : protocol(none)
, external_port(0) , external_port(0)
, local_port(0)
{} {}
int protocol; int protocol;
int external_port; int external_port;
int local_port; tcp::endpoint local_ep;
}; };
struct mapping_t struct mapping_t
@ -273,7 +272,6 @@ private:
enum action_t { action_none, action_add, action_delete }; enum action_t { action_none, action_add, action_delete };
mapping_t() mapping_t()
: action(action_none) : action(action_none)
, local_port(0)
, external_port(0) , external_port(0)
, protocol(none) , protocol(none)
, failcount(0) , failcount(0)
@ -282,11 +280,11 @@ private:
// the time the port mapping will expire // the time the port mapping will expire
time_point expires; time_point expires;
int action; // the local port for this mapping. The port is set
// the local port for this mapping. If this is set
// to 0, the mapping is not in use // to 0, the mapping is not in use
int local_port; tcp::endpoint local_ep;
int action;
// the external (on the NAT router) port // the external (on the NAT router) port
// for the mapping. This is the port we // for the mapping. This is the port we

View File

@ -2250,7 +2250,8 @@ retry:
if ((mask & 2) && m_upnp) if ((mask & 2) && m_upnp)
{ {
if (m_tcp_mapping[1] != -1) m_upnp->delete_mapping(m_tcp_mapping[1]); if (m_tcp_mapping[1] != -1) m_upnp->delete_mapping(m_tcp_mapping[1]);
m_tcp_mapping[1] = m_upnp->add_mapping(upnp::tcp, tcp_port, tcp_port); m_tcp_mapping[1] = m_upnp->add_mapping(upnp::tcp, tcp_port
, tcp::endpoint(m_listen_interface.address(), tcp_port));
#ifdef TORRENT_USE_OPENSSL #ifdef TORRENT_USE_OPENSSL
if (m_ssl_tcp_mapping[1] != -1) if (m_ssl_tcp_mapping[1] != -1)
{ {
@ -2258,7 +2259,7 @@ retry:
m_ssl_tcp_mapping[1] = -1; m_ssl_tcp_mapping[1] = -1;
} }
if (ssl_port > 0) m_ssl_tcp_mapping[1] = m_upnp->add_mapping(upnp::tcp if (ssl_port > 0) m_ssl_tcp_mapping[1] = m_upnp->add_mapping(upnp::tcp
, ssl_port, ssl_port); , ssl_port, tcp::endpoint(m_listen_interface.address(), ssl_port));
#endif #endif
} }
} }
@ -5994,7 +5995,8 @@ retry:
void session_impl::maybe_update_udp_mapping(int const nat, bool const ssl void session_impl::maybe_update_udp_mapping(int const nat, bool const ssl
, int const local_port, int const external_port) , int const local_port, int const external_port)
{ {
int local, external, protocol; int external, protocol;
tcp::endpoint local_ep;
#ifdef TORRENT_USE_OPENSSL #ifdef TORRENT_USE_OPENSSL
int* mapping = ssl ? m_ssl_udp_mapping : m_udp_mapping; int* mapping = ssl ? m_ssl_udp_mapping : m_udp_mapping;
#else #else
@ -6003,6 +6005,7 @@ retry:
#endif #endif
if (nat == 0 && m_natpmp) if (nat == 0 && m_natpmp)
{ {
int local = 0;
if (mapping[nat] != -1) if (mapping[nat] != -1)
{ {
if (m_natpmp->get_mapping(mapping[nat], local, external, protocol)) if (m_natpmp->get_mapping(mapping[nat], local, external, protocol))
@ -6014,23 +6017,24 @@ retry:
m_natpmp->delete_mapping(mapping[nat]); m_natpmp->delete_mapping(mapping[nat]);
} }
mapping[nat] = m_natpmp->add_mapping(natpmp::udp mapping[nat] = m_natpmp->add_mapping(natpmp::udp
, local_port, external_port); , external_port, local_port);
return; return;
} }
else if (nat == 1 && m_upnp) else if (nat == 1 && m_upnp)
{ {
if (mapping[nat] != -1) if (mapping[nat] != -1)
{ {
if (m_upnp->get_mapping(mapping[nat], local, external, protocol)) if (m_upnp->get_mapping(mapping[nat], local_ep, external, protocol))
{ {
// we already have a mapping. If it's the same, don't do anything // we already have a mapping. If it's the same, don't do anything
if (local == local_port && external == external_port && protocol == natpmp::udp) if (local_ep.port() == local_port && external == external_port && protocol == natpmp::udp)
return; return;
} }
m_upnp->delete_mapping(mapping[nat]); m_upnp->delete_mapping(mapping[nat]);
} }
local_ep.port(local_port);
mapping[nat] = m_upnp->add_mapping(upnp::udp mapping[nat] = m_upnp->add_mapping(upnp::udp
, local_port, external_port); , external_port, local_ep);
return; return;
} }
} }
@ -6786,13 +6790,13 @@ retry:
if (m_udp_socket.is_open()) if (m_udp_socket.is_open())
{ {
m_udp_mapping[1] = m_upnp->add_mapping(upnp::udp m_udp_mapping[1] = m_upnp->add_mapping(upnp::udp
, m_listen_interface.port(), m_listen_interface.port()); , m_listen_interface.port(), m_listen_interface);
} }
#ifdef TORRENT_USE_OPENSSL #ifdef TORRENT_USE_OPENSSL
if (m_ssl_udp_socket.is_open() && ssl_port > 0) if (m_ssl_udp_socket.is_open() && ssl_port > 0)
{ {
m_ssl_udp_mapping[1] = m_upnp->add_mapping(upnp::udp m_ssl_udp_mapping[1] = m_upnp->add_mapping(upnp::udp
, ssl_port, ssl_port); , ssl_port, tcp::endpoint(m_listen_interface.address(), ssl_port));
} }
#endif #endif
return m_upnp.get(); return m_upnp.get();
@ -6803,9 +6807,9 @@ retry:
{ {
int ret = 0; int ret = 0;
if (m_upnp) ret = m_upnp->add_mapping(static_cast<upnp::protocol_type>(t), external_port if (m_upnp) ret = m_upnp->add_mapping(static_cast<upnp::protocol_type>(t), external_port
, local_port); , tcp::endpoint(m_listen_interface.address(), local_port));
if (m_natpmp) ret = m_natpmp->add_mapping(static_cast<natpmp::protocol_type>(t), external_port if (m_natpmp) ret = m_natpmp->add_mapping(static_cast<natpmp::protocol_type>(t)
, local_port); , external_port, local_port);
return ret; return ret;
} }

View File

@ -166,7 +166,7 @@ void upnp::discover_device_impl(mutex::scoped_lock& l)
} }
// returns a reference to a mapping or -1 on failure // returns a reference to a mapping or -1 on failure
int upnp::add_mapping(upnp::protocol_type p, int external_port, int local_port) int upnp::add_mapping(upnp::protocol_type p, int external_port, tcp::endpoint local_ep)
{ {
// external port 0 means _every_ port // external port 0 means _every_ port
TORRENT_ASSERT(external_port != 0); TORRENT_ASSERT(external_port != 0);
@ -175,8 +175,8 @@ int upnp::add_mapping(upnp::protocol_type p, int external_port, int local_port)
char msg[500]; char msg[500];
snprintf(msg, sizeof(msg), "adding port map: [ protocol: %s ext_port: %u " snprintf(msg, sizeof(msg), "adding port map: [ protocol: %s ext_port: %u "
"local_port: %u ] %s", (p == tcp?"tcp":"udp"), external_port "local_ep: %s ] %s", (p == tcp?"tcp":"udp"), external_port
, local_port, m_disabled ? "DISABLED": ""); , print_endpoint(local_ep).c_str(), m_disabled ? "DISABLED": "");
log(msg, l); log(msg, l);
if (m_disabled) return -1; if (m_disabled) return -1;
@ -192,7 +192,7 @@ int upnp::add_mapping(upnp::protocol_type p, int external_port, int local_port)
mapping_it->protocol = p; mapping_it->protocol = p;
mapping_it->external_port = external_port; mapping_it->external_port = external_port;
mapping_it->local_port = local_port; mapping_it->local_ep = local_ep;
int mapping_index = mapping_it - m_mappings.begin(); int mapping_index = mapping_it - m_mappings.begin();
@ -209,7 +209,7 @@ int upnp::add_mapping(upnp::protocol_type p, int external_port, int local_port)
m.action = mapping_t::action_add; m.action = mapping_t::action_add;
m.protocol = p; m.protocol = p;
m.external_port = external_port; m.external_port = external_port;
m.local_port = local_port; m.local_ep = local_ep;
if (!d.service_namespace.empty()) update_map(d, mapping_index, l); if (!d.service_namespace.empty()) update_map(d, mapping_index, l);
} }
@ -227,8 +227,8 @@ void upnp::delete_mapping(int mapping)
char msg[500]; char msg[500];
snprintf(msg, sizeof(msg), "deleting port map: [ protocol: %s ext_port: %u " snprintf(msg, sizeof(msg), "deleting port map: [ protocol: %s ext_port: %u "
"local_port: %u ]", (m.protocol == tcp?"tcp":"udp"), m.external_port "local_ep: %s ]", (m.protocol == tcp?"tcp":"udp"), m.external_port
, m.local_port); , print_endpoint(m.local_ep).c_str());
log(msg, l); log(msg, l);
if (m.protocol == none) return; if (m.protocol == none) return;
@ -246,13 +246,13 @@ void upnp::delete_mapping(int mapping)
} }
} }
bool upnp::get_mapping(int index, int& local_port, int& external_port, int& protocol) const bool upnp::get_mapping(int index, tcp::endpoint& local_ep, int& external_port, int& protocol) const
{ {
TORRENT_ASSERT(index < int(m_mappings.size()) && index >= 0); TORRENT_ASSERT(index < int(m_mappings.size()) && index >= 0);
if (index >= int(m_mappings.size()) || index < 0) return false; if (index >= int(m_mappings.size()) || index < 0) return false;
global_mapping_t const& m = m_mappings[index]; global_mapping_t const& m = m_mappings[index];
if (m.protocol == none) return false; if (m.protocol == none) return false;
local_port = m.local_port; local_ep = m.local_ep;
external_port = m.external_port; external_port = m.external_port;
protocol = m.protocol; protocol = m.protocol;
return true; return true;
@ -537,7 +537,7 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer
{ {
mapping_t m; mapping_t m;
m.action = mapping_t::action_add; m.action = mapping_t::action_add;
m.local_port = j->local_port; m.local_ep = j->local_ep;
m.external_port = j->external_port; m.external_port = j->external_port;
m.protocol = j->protocol; m.protocol = j->protocol;
d.mapping.push_back(m); d.mapping.push_back(m);
@ -700,9 +700,9 @@ void upnp::create_port_mapping(http_connection& c, rootdevice& d, int i)
"</u:%s></s:Body></s:Envelope>" "</u:%s></s:Body></s:Envelope>"
, soap_action, d.service_namespace.c_str(), d.mapping[i].external_port , soap_action, d.service_namespace.c_str(), d.mapping[i].external_port
, (d.mapping[i].protocol == udp ? "UDP" : "TCP") , (d.mapping[i].protocol == udp ? "UDP" : "TCP")
, d.mapping[i].local_port , d.mapping[i].local_ep.port()
, local_endpoint.c_str() , local_endpoint.c_str()
, m_user_agent.c_str(), local_endpoint.c_str(), d.mapping[i].local_port , m_user_agent.c_str(), local_endpoint.c_str(), d.mapping[i].local_ep.port()
, d.lease_duration, soap_action); , d.lease_duration, soap_action);
post(d, soap, soap_action, l); post(d, soap, soap_action, l);
@ -772,7 +772,7 @@ void upnp::update_map(rootdevice& d, int i, mutex::scoped_lock& l)
, boost::bind(&upnp::create_port_mapping, self(), _1, boost::ref(d), i))); , boost::bind(&upnp::create_port_mapping, self(), _1, boost::ref(d), i)));
d.upnp_connection->start(d.hostname, d.port d.upnp_connection->start(d.hostname, d.port
, seconds(10), 1); , seconds(10), 1, NULL, false, 5, m.local_ep.address());
} }
else if (m.action == mapping_t::action_delete) else if (m.action == mapping_t::action_delete)
{ {
@ -783,7 +783,7 @@ void upnp::update_map(rootdevice& d, int i, mutex::scoped_lock& l)
, boost::ref(d), i, _5), true, default_max_bottled_buffer_size , boost::ref(d), i, _5), true, default_max_bottled_buffer_size
, boost::bind(&upnp::delete_port_mapping, self(), boost::ref(d), i))); , boost::bind(&upnp::delete_port_mapping, self(), boost::ref(d), i)));
d.upnp_connection->start(d.hostname, d.port d.upnp_connection->start(d.hostname, d.port
, seconds(10), 1); , seconds(10), 1, NULL, false, 5, m.local_ep.address());
} }
m.action = mapping_t::action_none; m.action = mapping_t::action_none;

View File

@ -182,8 +182,8 @@ void run_upnp_test(char const* root_filename, char const* router_model, char con
std::cerr << "router: " << upnp_handler->router_model() << std::endl; std::cerr << "router: " << upnp_handler->router_model() << std::endl;
TEST_EQUAL(upnp_handler->router_model(), router_model); TEST_EQUAL(upnp_handler->router_model(), router_model);
int mapping1 = upnp_handler->add_mapping(upnp::tcp, 500, 500); int mapping1 = upnp_handler->add_mapping(upnp::tcp, 500, ep("127.0.0.1", 500));
int mapping2 = upnp_handler->add_mapping(upnp::udp, 501, 501); int mapping2 = upnp_handler->add_mapping(upnp::udp, 501, ep("127.0.0.1", 501));
for (int i = 0; i < 40; ++i) for (int i = 0; i < 40; ++i)
{ {