diff --git a/ChangeLog b/ChangeLog index fb9ede116..bebf071fe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -39,6 +39,7 @@ * fix uTP edge case where udp socket buffer fills up * fix nagle implementation in uTP + * make lt_tex more robust against bugs and malicious behavior * HTTP chunked encoding fix * expose file_granularity flag to python bindings * fix DHT memory error diff --git a/include/libtorrent/escape_string.hpp b/include/libtorrent/escape_string.hpp index 7980b831f..4fb1bfa19 100644 --- a/include/libtorrent/escape_string.hpp +++ b/include/libtorrent/escape_string.hpp @@ -53,6 +53,8 @@ namespace libtorrent // it will be encoded TORRENT_EXTRA_EXPORT std::string maybe_url_encode(std::string const& url); + // returns true if the given string (not null terminated) contains + // characters that would need to be escaped if used in a URL TORRENT_EXTRA_EXPORT bool need_encoding(char const* str, int len); // encodes a string using the base64 scheme diff --git a/include/libtorrent/parse_url.hpp b/include/libtorrent/parse_url.hpp index eb11230c6..3e625768b 100644 --- a/include/libtorrent/parse_url.hpp +++ b/include/libtorrent/parse_url.hpp @@ -50,6 +50,7 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { + // returns protocol, auth, hostname, port, path TORRENT_EXTRA_EXPORT boost::tuple parse_url_components(std::string url, error_code& ec); diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index 67c1ee9c1..0de431257 100644 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -741,7 +741,11 @@ namespace libtorrent { return m_trackers; } void replace_trackers(std::vector const& urls); - void add_tracker(announce_entry const& url); + + // returns true if the tracker was added, and false if it was already + // in the tracker list (in which case the source was added to the + // entry in the list) + bool add_tracker(announce_entry const& url); torrent_handle get_handle(); diff --git a/src/lt_trackers.cpp b/src/lt_trackers.cpp index 1cd96af2b..09140d8b2 100644 --- a/src/lt_trackers.cpp +++ b/src/lt_trackers.cpp @@ -57,6 +57,8 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/extensions.hpp" #include "libtorrent/extensions/ut_metadata.hpp" #include "libtorrent/alert_types.hpp" +#include "libtorrent/escape_string.hpp" +#include "libtorrent/parse_url.hpp" #ifdef TORRENT_STATS #include "libtorrent/aux_/session_impl.hpp" #endif @@ -78,6 +80,7 @@ namespace libtorrent { namespace : m_torrent(t) , m_updates(0) , m_2_minutes(110) + , m_num_trackers(0) { m_old_trackers = t.trackers(); update_list_hash(); @@ -133,6 +136,9 @@ namespace libtorrent { namespace std::vector const& trackers() const { return m_old_trackers; } + void increment_tracker_counter() { m_num_trackers++; } + int num_tex_trackers() const { return m_num_trackers; } + private: torrent& m_torrent; std::vector m_old_trackers; @@ -140,6 +146,7 @@ namespace libtorrent { namespace int m_2_minutes; std::vector m_lt_trackers_msg; sha1_hash m_list_hash; + int m_num_trackers; }; @@ -203,12 +210,6 @@ namespace libtorrent { namespace lazy_entry const* added = msg.dict_find_list("added"); -#ifdef TORRENT_VERBOSE_LOGGING - std::stringstream log_line; - log_line << time_now_string() << " <== LT_TEX [ " - "added: "; -#endif - // invalid tex message if (added == 0) { @@ -218,14 +219,66 @@ namespace libtorrent { namespace return true; } +#ifdef TORRENT_VERBOSE_LOGGING + std::stringstream log_line; +#endif + if (m_tp.num_tex_trackers() >= 50) + { +#ifdef TORRENT_VERBOSE_LOGGING + log_line << time_now_string() << " <== LT_TEX [ " + "we already have " << m_tp.num_tex_trackers() << " trackers " + "from tex, don't add any more"; + (*m_pc.m_logger) << log_line.str(); +#endif + return true; + } + +#ifdef TORRENT_VERBOSE_LOGGING + log_line << time_now_string() << " <== LT_TEX [ " + "added: "; +#endif + for (int i = 0; i < added->list_size(); ++i) { announce_entry e(added->list_string_value_at(i)); if (e.url.empty()) continue; - e.fail_limit = 3; + + // ignore urls with binary data in them + if (need_encoding(e.url.c_str(), e.url.size())) continue; + + // ignore invalid URLs + error_code ec; + std::string protocol; + std::string auth; + std::string hostname; + int port; + std::string path; + boost::tie(protocol, auth, hostname, port, path) + = parse_url_components(e.url, ec); + if (ec) continue; + + // ignore unknown protocols + if (protocol != "udp" && protocol != "http" && protocol != "https") + continue; + + // ignore invalid ports + if (port == 0) + continue; + + if (m_tp.num_tex_trackers() >= 50) + { +#ifdef TORRENT_VERBOSE_LOGGING + log_line << "**reached-limit** "; +#endif + break; + } + + e.fail_limit = 1; e.send_stats = false; e.source = announce_entry::source_tex; - m_torrent.add_tracker(e); + if (m_torrent.add_tracker(e)) + m_tp.increment_tracker_counter(); + #ifdef TORRENT_VERBOSE_LOGGING log_line << e.url << " "; #endif diff --git a/src/parse_url.cpp b/src/parse_url.cpp index f4419088f..0155ff191 100644 --- a/src/parse_url.cpp +++ b/src/parse_url.cpp @@ -112,6 +112,12 @@ namespace libtorrent { hostname.assign(start, port_pos); ++port_pos; + for (std::string::iterator i = port_pos; i < end; ++i) + { + if (is_digit(*i)) continue; + ec = errors::invalid_port; + goto exit; + } port = std::atoi(std::string(port_pos, end).c_str()); } else diff --git a/src/storage.cpp b/src/storage.cpp index 4267db0f7..046bd5750 100644 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -1221,7 +1221,10 @@ ret: return -1; } - if (m_allocate_files && (op.mode & file::rw_mask) != file::read_only) + // if the file has priority 0, don't allocate it + int file_index = files().file_index(*file_iter); + if (m_allocate_files && (op.mode & file::rw_mask) != file::read_only + && (m_file_priority.size() < file_index || m_file_priority[file_index] > 0)) { TORRENT_ASSERT(m_file_created.size() == files().num_files()); if (m_file_created[file_index] == false) @@ -1420,6 +1423,12 @@ ret: bool lock_files = m_settings ? settings().lock_files : false; if (lock_files) mode |= file::lock_file; if (!m_allocate_files) mode |= file::sparse; + + // files with priority 0 should always be sparse + int file_index = fe - files().begin(); + if (m_file_priority.size() > file_index && m_file_priority[file_index] == 0) + mode |= file::sparse; + if (m_settings && settings().no_atime_storage) mode |= file::no_atime; return m_pool.open_file(const_cast(this), m_save_path, file_index, files(), mode, ec); diff --git a/src/torrent.cpp b/src/torrent.cpp index cafbc5fae..85ac08065 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -4268,14 +4268,14 @@ namespace libtorrent } } - void torrent::add_tracker(announce_entry const& url) + bool torrent::add_tracker(announce_entry const& url) { std::vector::iterator k = std::find_if(m_trackers.begin() , m_trackers.end(), boost::bind(&announce_entry::url, _1) == url.url); if (k != m_trackers.end()) { k->source |= url.source; - return; + return false; } k = std::upper_bound(m_trackers.begin(), m_trackers.end(), url , boost::bind(&announce_entry::tier, _1) < boost::bind(&announce_entry::tier, _2)); @@ -4283,6 +4283,7 @@ namespace libtorrent k = m_trackers.insert(k, url); if (k->source == 0) k->source = announce_entry::source_client; if (!m_trackers.empty()) announce_with_tracker(); + return true; } bool torrent::choke_peer(peer_connection& c)