handle DHT error responses correctly

This commit is contained in:
Arvid Norberg 2014-01-03 08:02:53 +00:00
parent 926cb44953
commit db6a22d5c1
4 changed files with 42 additions and 20 deletions

View File

@ -1,3 +1,4 @@
* handle DHT error responses correctly
* allow force_announce to only affect a single tracker * allow force_announce to only affect a single tracker
* add moving_storage field to torrent_status * add moving_storage field to torrent_status
* expose UPnP and NAT-PMP mapping in session object * expose UPnP and NAT-PMP mapping in session object

View File

@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE.
#define RPC_MANAGER_HPP #define RPC_MANAGER_HPP
#include <vector> #include <vector>
#include <deque>
#include <map> #include <map>
#include <boost/cstdint.hpp> #include <boost/cstdint.hpp>
#include <boost/pool/pool.hpp> #include <boost/pool/pool.hpp>
@ -107,7 +108,7 @@ private:
mutable boost::pool<> m_pool_allocator; mutable boost::pool<> m_pool_allocator;
typedef std::list<observer_ptr> transactions_t; typedef std::deque<observer_ptr> transactions_t;
transactions_t m_transactions; transactions_t m_transactions;
udp_socket_interface* m_sock; udp_socket_interface* m_sock;

View File

@ -218,9 +218,11 @@ void node_impl::incoming(msg const& m)
lazy_entry const* y_ent = m.message.dict_find_string("y"); lazy_entry const* y_ent = m.message.dict_find_string("y");
if (!y_ent || y_ent->string_length() == 0) if (!y_ent || y_ent->string_length() == 0)
{ {
entry e; // don't respond to this obviously broken messages. We don't
incoming_error(e, "missing 'y' entry"); // want to open up a magnification opportunity
m_sock->send_packet(e, m.addr, 0); // entry e;
// incoming_error(e, "missing 'y' entry");
// m_sock->send_packet(e, m.addr, 0);
return; return;
} }
@ -282,6 +284,8 @@ void node_impl::incoming(msg const& m)
TORRENT_LOG(node) << "INCOMING ERROR: " << err->list_string_value_at(1); TORRENT_LOG(node) << "INCOMING ERROR: " << err->list_string_value_at(1);
} }
#endif #endif
node_id id;
m_rpc.incoming(m, &id, m_settings);
break; break;
} }
} }

View File

@ -255,7 +255,7 @@ void rpc_manager::unreachable(udp::endpoint const& ep)
observer_ptr const& o = *i; observer_ptr const& o = *i;
if (o->target_ep() != ep) { ++i; continue; } if (o->target_ep() != ep) { ++i; continue; }
observer_ptr ptr = *i; observer_ptr ptr = *i;
m_transactions.erase(i++); i = m_transactions.erase(i);
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(rpc) << " found transaction [ tid: " << ptr->transaction_id() << " ]"; TORRENT_LOG(rpc) << " found transaction [ tid: " << ptr->transaction_id() << " ]";
#endif #endif
@ -273,13 +273,15 @@ bool rpc_manager::incoming(msg const& m, node_id* id, libtorrent::dht_settings c
if (m_destructing) return false; if (m_destructing) return false;
// we only deal with replies, not queries // we only deal with replies and errors, not queries
TORRENT_ASSERT(m.message.dict_find_string_value("y") == "r"); TORRENT_ASSERT(m.message.dict_find_string_value("y") == "r"
|| m.message.dict_find_string_value("y") == "e");
// if we don't have the transaction id in our // if we don't have the transaction id in our
// request list, ignore the packet // request list, ignore the packet
std::string transaction_id = m.message.dict_find_string_value("t"); std::string transaction_id = m.message.dict_find_string_value("t");
if (transaction_id.empty()) return false;
std::string::const_iterator i = transaction_id.begin(); std::string::const_iterator i = transaction_id.begin();
int tid = transaction_id.size() != 2 ? -1 : io::read_uint16(i); int tid = transaction_id.size() != 2 ? -1 : io::read_uint16(i);
@ -287,25 +289,34 @@ bool rpc_manager::incoming(msg const& m, node_id* id, libtorrent::dht_settings c
observer_ptr o; observer_ptr o;
for (transactions_t::iterator i = m_transactions.begin() for (transactions_t::iterator i = m_transactions.begin()
, end(m_transactions.end()); i != end; ++i) , end(m_transactions.end()); i != end;)
{ {
TORRENT_ASSERT(*i); TORRENT_ASSERT(*i);
if ((*i)->transaction_id() != tid) continue; if ((*i)->transaction_id() != tid
if (m.addr.address() != (*i)->target_addr()) continue; || m.addr.address() != (*i)->target_addr())
{
++i;
continue;
}
o = *i; o = *i;
m_transactions.erase(i); i = m_transactions.erase(i);
break; break;
} }
if (!o) if (!o)
{ {
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(rpc) << "Reply with invalid transaction id size: " TORRENT_LOG(rpc) << "Reply with unknown transaction id size: "
<< transaction_id.size() << " from " << m.addr; << transaction_id.size() << " from " << m.addr;
#endif #endif
entry e; // this isn't necessarily because the other end is doing
incoming_error(e, "invalid transaction id"); // something wrong. This can also happen when we restart
m_sock->send_packet(e, m.addr, 0); // the node, and we prematurely abort all outstanding
// requests. Also, this opens up a potential magnification
// attack.
// entry e;
// incoming_error(e, "invalid transaction id");
// m_sock->send_packet(e, m.addr, 0);
return false; return false;
} }
@ -320,10 +331,15 @@ bool rpc_manager::incoming(msg const& m, node_id* id, libtorrent::dht_settings c
lazy_entry const* ret_ent = m.message.dict_find_dict("r"); lazy_entry const* ret_ent = m.message.dict_find_dict("r");
if (ret_ent == 0) if (ret_ent == 0)
{ {
// it may be an error
ret_ent = m.message.dict_find_dict("e");
o->timeout(); o->timeout();
if (ret_ent == NULL)
{
entry e; entry e;
incoming_error(e, "missing 'r' key"); incoming_error(e, "missing 'r' key");
m_sock->send_packet(e, m.addr, 0); m_sock->send_packet(e, m.addr, 0);
}
return false; return false;
} }
@ -365,7 +381,7 @@ time_duration rpc_manager::tick()
INVARIANT_CHECK; INVARIANT_CHECK;
const static int short_timeout = 1; const static int short_timeout = 1;
const static int timeout = 8; const static int timeout = 15;
// look for observers that have timed out // look for observers that have timed out
@ -405,7 +421,7 @@ time_duration rpc_manager::tick()
TORRENT_LOG(rpc) << "[" << o->m_algorithm.get() << "] Timing out transaction id: " TORRENT_LOG(rpc) << "[" << o->m_algorithm.get() << "] Timing out transaction id: "
<< (*i)->transaction_id() << " from " << o->target_ep(); << (*i)->transaction_id() << " from " << o->target_ep();
#endif #endif
m_transactions.erase(i++); i = m_transactions.erase(i);
timeouts.push_back(o); timeouts.push_back(o);
} }