diff --git a/bindings/python/src/alert.cpp b/bindings/python/src/alert.cpp index 12f391613..b18ce7e85 100644 --- a/bindings/python/src/alert.cpp +++ b/bindings/python/src/alert.cpp @@ -58,72 +58,60 @@ void bind_alert() } class_, noncopyable>( - "torrent_alert", no_init - ) + "torrent_alert", no_init) .def_readonly("handle", &torrent_alert::handle) ; class_, noncopyable>( - "tracker_alert", no_init - ) + "tracker_alert", no_init) .def_readonly("url", &tracker_alert::url) ; class_, noncopyable>( - "read_piece_alert", 0, no_init - ) + "read_piece_alert", 0, no_init) .add_property("buffer", get_buffer) .def_readonly("piece", &read_piece_alert::piece) .def_readonly("size", &read_piece_alert::size) ; class_, noncopyable>( - "peer_alert", no_init - ) + "peer_alert", no_init) .def_readonly("ip", &peer_alert::ip) .def_readonly("pid", &peer_alert::pid) ; class_, noncopyable>( - "tracker_error_alert", no_init - ) + "tracker_error_alert", no_init) .def_readonly("msg", &tracker_error_alert::msg) .def_readonly("times_in_row", &tracker_error_alert::times_in_row) .def_readonly("status_code", &tracker_error_alert::status_code) ; class_, noncopyable>( - "tracker_warning_alert", no_init - ); + "tracker_warning_alert", no_init); class_, noncopyable>( - "tracker_reply_alert", no_init - ) + "tracker_reply_alert", no_init) .def_readonly("num_peers", &tracker_reply_alert::num_peers) ; class_, noncopyable>( - "tracker_announce_alert", no_init - ) + "tracker_announce_alert", no_init) .def_readonly("event", &tracker_announce_alert::event) ; class_, noncopyable>( - "hash_failed_alert", no_init - ) + "hash_failed_alert", no_init) .def_readonly("piece_index", &hash_failed_alert::piece_index) ; class_, noncopyable>( - "peer_ban_alert", no_init - ); + "peer_ban_alert", no_init); class_, noncopyable>( - "peer_error_alert", no_init - ); + "peer_error_alert", no_init); class_, noncopyable>( - "invalid_request_alert", no_init - ) + "invalid_request_alert", no_init) .def_readonly("request", &invalid_request_alert::request) ; @@ -135,66 +123,55 @@ void bind_alert() ; class_, noncopyable>( - "torrent_finished_alert", no_init - ); + "torrent_finished_alert", no_init); class_, noncopyable>( - "piece_finished_alert", no_init - ) + "piece_finished_alert", no_init) .def_readonly("piece_index", &piece_finished_alert::piece_index) ; class_, noncopyable>( - "block_finished_alert", no_init - ) + "block_finished_alert", no_init) .def_readonly("block_index", &block_finished_alert::block_index) .def_readonly("piece_index", &block_finished_alert::piece_index) ; class_, noncopyable>( - "block_downloading_alert", no_init - ) + "block_downloading_alert", no_init) .def_readonly("peer_speedmsg", &block_downloading_alert::peer_speedmsg) .def_readonly("block_index", &block_downloading_alert::block_index) .def_readonly("piece_index", &block_downloading_alert::piece_index) ; class_, noncopyable>( - "storage_moved_alert", no_init - ) + "storage_moved_alert", no_init) .def_readonly("path", &storage_moved_alert::path) ; class_, noncopyable>( - "storage_moved_failed_alert", no_init - ) + "storage_moved_failed_alert", no_init) .def_readonly("error", &storage_moved_failed_alert::error) ; class_, noncopyable>( - "torrent_deleted_alert", no_init - ) + "torrent_deleted_alert", no_init) .def_readonly("info_hash", &torrent_deleted_alert::info_hash) ; class_, noncopyable>( - "torrent_paused_alert", no_init - ); + "torrent_paused_alert", no_init); class_, noncopyable>( - "torrent_checked_alert", no_init - ); + "torrent_checked_alert", no_init); class_, noncopyable>( - "url_seed_alert", no_init - ) + "url_seed_alert", no_init) .def_readonly("url", &url_seed_alert::url) .def_readonly("msg", &url_seed_alert::msg) ; class_, noncopyable>( - "file_error_alert", no_init - ) + "file_error_alert", no_init) .def_readonly("file", &file_error_alert::file) #ifndef TORRENT_NO_DEPRECATE .def_readonly("msg", &file_error_alert::msg) @@ -202,29 +179,24 @@ void bind_alert() ; class_, noncopyable>( - "metadata_failed_alert", no_init - ); + "metadata_failed_alert", no_init); class_, noncopyable>( - "metadata_received_alert", no_init - ); + "metadata_received_alert", no_init); class_, noncopyable>( - "listen_failed_alert", no_init - ) + "listen_failed_alert", no_init) .def_readonly("endpoint", &listen_failed_alert::endpoint) .def_readonly("error", &listen_failed_alert::error) ; class_, noncopyable>( - "listen_succeeded_alert", no_init - ) + "listen_succeeded_alert", no_init) .def_readonly("endpoint", &listen_succeeded_alert::endpoint) ; class_, noncopyable>( - "portmap_error_alert", no_init - ) + "portmap_error_alert", no_init) .def_readonly("mapping", &portmap_error_alert::mapping) .def_readonly("type", &portmap_error_alert::type) #ifndef TORRENT_NO_DEPRECATE @@ -233,16 +205,14 @@ void bind_alert() ; class_, noncopyable>( - "portmap_alert", no_init - ) + "portmap_alert", no_init) .def_readonly("mapping", &portmap_alert::mapping) .def_readonly("external_port", &portmap_alert::external_port) .def_readonly("type", &portmap_alert::type) ; class_, noncopyable>( - "portmap_log_alert", no_init - ) + "portmap_log_alert", no_init) .def_readonly("type", &portmap_log_alert::type) #ifndef TORRENT_NO_DEPRECATE .def_readonly("msg", &portmap_log_alert::msg) @@ -250,59 +220,50 @@ void bind_alert() ; class_, noncopyable>( - "fastresume_rejected_alert", no_init - ) + "fastresume_rejected_alert", no_init) #ifndef TORRENT_NO_DEPRECATE .def_readonly("msg", &fastresume_rejected_alert::msg) #endif ; class_, noncopyable>( - "peer_blocked_alert", no_init - ) + "peer_blocked_alert", no_init) .def_readonly("ip", &peer_blocked_alert::ip) ; class_, noncopyable>( - "scrape_reply_alert", no_init - ) + "scrape_reply_alert", no_init) .def_readonly("incomplete", &scrape_reply_alert::incomplete) .def_readonly("complete", &scrape_reply_alert::complete) ; class_, noncopyable>( - "scrape_failed_alert", no_init - ); + "scrape_failed_alert", no_init); class_, noncopyable>( - "udp_error_alert", no_init - ) + "udp_error_alert", no_init) .def_readonly("endpoint", &udp_error_alert::endpoint) .def_readonly("error", &udp_error_alert::error) ; class_, noncopyable>( - "external_ip_alert", no_init - ) + "external_ip_alert", no_init) .def_readonly("external_address", &external_ip_alert::external_address) ; class_, noncopyable>( - "save_resume_data_alert", no_init - ) + "save_resume_data_alert", no_init) .def_readonly("resume_data", &save_resume_data_alert::resume_data) ; class_, noncopyable>( - "file_renamed_alert", no_init - ) + "file_renamed_alert", no_init) .def_readonly("index", &file_renamed_alert::index) .def_readonly("name", &file_renamed_alert::name) ; class_, noncopyable>( - "file_rename_failed_alert", no_init - ) + "file_rename_failed_alert", no_init) .def_readonly("index", &file_rename_failed_alert::index) .def_readonly("error", &file_rename_failed_alert::error) ; @@ -312,21 +273,18 @@ void bind_alert() ); class_, noncopyable>( - "state_changed_alert", no_init - ) + "state_changed_alert", no_init) .def_readonly("state", &state_changed_alert::state) .def_readonly("prev_state", &state_changed_alert::prev_state) ; class_, noncopyable>( - "dht_reply_alert", no_init - ) + "dht_reply_alert", no_init) .def_readonly("num_peers", &dht_reply_alert::num_peers) ; class_, noncopyable>( - "dht_announce_alert", no_init - ) + "dht_announce_alert", no_init) .def_readonly("ip", &dht_announce_alert::ip) .def_readonly("port", &dht_announce_alert::port) .def_readonly("info_hash", &dht_announce_alert::info_hash) @@ -351,53 +309,46 @@ void bind_alert() ); class_, noncopyable>( - "peer_disconnected_alert", no_init - ) + "peer_disconnected_alert", no_init) #ifndef TORRENT_NO_DEPRECATE .def_readonly("msg", &peer_disconnected_alert::msg) #endif ; class_, noncopyable>( - "request_dropped_alert", no_init - ) + "request_dropped_alert", no_init) .def_readonly("block_index", &request_dropped_alert::block_index) .def_readonly("piece_index", &request_dropped_alert::piece_index) ; class_, noncopyable>( - "block_timeout_alert", no_init - ) + "block_timeout_alert", no_init) .def_readonly("block_index", &block_timeout_alert::block_index) .def_readonly("piece_index", &block_timeout_alert::piece_index) ; class_, noncopyable>( - "unwanted_block_alert", no_init - ) + "unwanted_block_alert", no_init) .def_readonly("block_index", &unwanted_block_alert::block_index) .def_readonly("piece_index", &unwanted_block_alert::piece_index) ; class_, noncopyable>( - "torrent_delete_failed_alert", no_init - ) + "torrent_delete_failed_alert", no_init) #ifndef TORRENT_NO_DEPRECATE .def_readonly("msg", &torrent_delete_failed_alert::msg) #endif ; class_, noncopyable>( - "save_resume_data_failed_alert", no_init - ) + "save_resume_data_failed_alert", no_init) #ifndef TORRENT_NO_DEPRECATE .def_readonly("msg", &save_resume_data_failed_alert::msg) #endif ; class_, noncopyable>( - "performance_alert", no_init - ) + "performance_alert", no_init) .def_readonly("warning_code", &performance_alert::warning_code) ; enum_("performance_warning_t") @@ -409,11 +360,10 @@ void bind_alert() class_, noncopyable>( - "stats_alert", no_init - ) + "stats_alert", no_init) .def_readonly("transferred", &stats_alert::transferred) .def_readonly("interval", &stats_alert::interval) - ; + ; enum_("stats_channel") .value("upload_payload", stats_alert::upload_payload) @@ -428,4 +378,13 @@ void bind_alert() .value("download_tracker_protocol", stats_alert::download_tracker_protocol) ; + class_, noncopyable>( + "anonymous_mode_alert", no_init) + .def_readonly("kind", &anonymous_mode_alert::kind) + .def_readonly("str", &anonymous_mode_alert::str) + ; + + enum_("kind") + .value("tracker_no_anonymous", anonymous_mode_alert::tracker_not_anonymous) + ; } diff --git a/docs/make_torrent.html b/docs/make_torrent.html index 7c8af5c76..592a56e81 100644 --- a/docs/make_torrent.html +++ b/docs/make_torrent.html @@ -57,10 +57,11 @@
  • set_comment()
  • set_creator()
  • set_hash()
  • -
  • add_url_seed()
  • -
  • add_node()
  • -
  • add_tracker()
  • -
  • set_priv() priv()
  • +
  • set_file_hash()
  • +
  • add_url_seed()
  • +
  • add_node()
  • +
  • add_tracker()
  • +
  • set_priv() priv()
  • @@ -110,12 +111,16 @@ bencode(std::ostream_iterator<char>(out), t.generate());
     template <class Pred>
    -void add_files(file_storage& fs, boost::filesystem::path const& path, Pred p);
    +void add_files(file_storage& fs, boost::filesystem::path const& path, Pred p
    +        , boost::uint32_t flags = 0);
     template <class Pred>
    -void add_files(file_storage& fs, boost::filesystem::wpath const& path, Pred p);
    +void add_files(file_storage& fs, boost::filesystem::wpath const& path, Pred p
    +        , boost::uint32_t flags = 0);
     
    -void add_files(file_storage& fs, boost::filesystem::path const& path);
    -void add_files(file_storage& fs, boost::filesystem::wpath const& path);
    +void add_files(file_storage& fs, boost::filesystem::path const& path
    +        , boost::uint32_t flags = 0);
    +void add_files(file_storage& fs, boost::filesystem::wpath const& path
    +        , boost::uint32_t flags = 0);
     

    Adds the file specified by path to the file_storage object. In case path @@ -134,6 +139,8 @@ bool Pred(boost::filesystem::wpath const& p); directory. If no predicate is specified, all files are added, and all directories are traveresed.

    The ".." directory is never traversed.

    +

    The flags argument should be the same as the flags passed to the create_torrent +constructor.

    set_piece_hashes()

    @@ -269,8 +276,10 @@ struct create_torrent , merkle = 2 , modification_time = 4 , symlink = 8 + , calculate_file_hashes = 16 }; - create_torrent(file_storage& fs, int piece_size = 0, int pad_size_limit = -1, int flags = optimize); + create_torrent(file_storage& fs, int piece_size = 0, int pad_size_limit = -1 + , int flags = optimize); create_torrent(torrent_info const& ti); entry generate() const; @@ -280,6 +289,7 @@ struct create_torrent void set_comment(char const* str); void set_creator(char const* str); void set_hash(int index, sha1_hash const& h); + void set_file_hash(int index, sha1_hash const& h); void add_url_seed(std::string const& url); void add_node(std::pair<std::string, int> const& node); void add_tracker(std::string const& url, int tier = 0); @@ -300,8 +310,10 @@ enum { , merkle = 2 , modification_time = 4 , symlink = 8 + , calculate_file_hashes = 16 }; -create_torrent(file_storage& fs, int piece_size = 0, int pad_size_limit = -1, int flags = optimize); +create_torrent(file_storage& fs, int piece_size = 0, int pad_size_limit = -1 + , int flags = optimize); create_torrent(torrent_info const& ti); @@ -338,11 +350,15 @@ yield the same info-hash. If the files have different modification times, with this option enabled, you would get different info-hashes for the files.
    symlink
    -
    If this flag is defined, files that are symlinks get a symlink attribute -set on them. The file data will still be the same, the symlink will always -be followed when opening the file, but the file list will include the path -of the symlink so that the original directory structure can be reproduced -on the downloading side.
    +
    If this flag is set, files that are symlinks get a symlink attribute +set on them and their data will not be included in the torrent. This +is useful if you need to reconstruct a file hierarchy which contains +symlinks.
    +
    calculate_file_hashes
    +
    If this is set, the set_piece_hashes() function will, as it calculates +the piece hashes, also calculate the file hashes and add those associated +with each file. Note that unless you use the set_piece_hashes() function, +this flag will have no effect.
    @@ -406,6 +422,17 @@ to set the hash for every piece in the torrent before generating it. If you have the files on disk, you can use the high level convenience function to do this. See set_piece_hashes().

    +
    +

    set_file_hash()

    +
    +
    +void set_file_hash(int index, sha1_hash const& h);
    +
    +
    +

    This sets the sha1 hash for this file. This hash will end up under the key sha1 +associated with this file (for multi-file torrents) or in the root info dictionary +for single-file torrents.

    +
    @@ -1163,6 +1164,7 @@ socket listening on different ports. If the DHT is active when path is the full (relative) path of each file. i.e. if it is a multi-file @@ -1812,6 +1817,13 @@ file.

    They are just there to make sure the next file is aligned to a particular byte offset or piece boundry. These files should typically be hidden from an end user. They are not written to disk.

    +

    hidden_attribute is true if the file was marked as hidden (on windows).

    +

    executable_attribute is true if the file was marked as executable (posix)

    +

    symlink_attribute is true if the file was a symlink. If this is the case +the symlink_path specifies the original location where the data for this file +was found.

    +

    filehash is a pointer that is set in case the torrent file included a sha1 hash +for this file. This may be use to look up more sources for this file on other networks.

    num_files() file_at()

    @@ -3777,6 +3789,8 @@ struct session_settings int active_downloads; int active_seeds; + int active_dht_limit; + int active_tracker_limit; int active_limit; bool auto_manage_prefer_seeds; bool dont_count_slow_torrents; @@ -3854,6 +3868,9 @@ struct session_settings int default_peer_upload_rate; int default_peer_download_rate; + bool broadcast_lsd; + bool ignore_resume_timestamps; + bool anonymous_mode; };

    user_agent this is the client identification to the tracker. @@ -4142,6 +4159,17 @@ to make it more likely to utilize all available bandwidth, and avoid having torr that don't transfer anything block the active slots.

    active_limit is a hard limit on the number of active torrents. This applies even to slow torrents.

    +

    active_dht_limit is the max number of torrents to announce to the DHT. By default +this is set to 88, which is no more than one DHT announce every 10 seconds.

    +

    active_tracker_limit is the max number of torrents to announce to their trackers. +By default this is 360, which is no more than one announce every 5 seconds.

    +

    active_lsd_limit is the max number of torrents to announce to the local network +over the local service discovery protocol. By default this is 80, which is no more +than one announce every 5 seconds (assuming the default announce interval of 5 minutes).

    +

    You can have more torrents active, even though they are not announced to the DHT, +lsd or their tracker. If some peer knows about you for any reason and tries to connect, +it will still be accepted, unless the torrent is paused, which means it won't accept +any connections.

    auto_manage_interval is the number of seconds between the torrent queue is updated, and rotated.

    share_ratio_limit is the upload / download ratio limit for considering a @@ -4368,6 +4396,28 @@ default to 0, which means unlimited. These settings affect the rate limits set on new peer connections (not existing ones). The peer rate limits can be changed individually later using set_peer_upload_limit() set_peer_download_limit().

    +

    if broadcast_lsd is set to true, the local peer discovery +(or Local Service Discovery) will not only use IP multicast, but also +broadcast its messages. This can be useful when running on networks +that don't support multicast. It's off by default since it's inefficient.

    +

    ignore_resume_timestamps determines if the storage, when loading +resume data files, should verify that the file modification time +with the timestamps in the resume data. This defaults to false, which +means timestamps are taken into account, and resume data is less likely +to accepted (torrents are more likely to be fully checked when loaded). +It might be useful to set this to true if your network is faster than your +disk, and it would be faster to redownload potentially missed pieces than +to go through the whole storage to look for them.

    +

    anonymous_mode defaults to false. When set to true, the client tries +to hide its identity to a certain degree. The peer-ID will no longer +include the client's fingerprint. The user-agent will be reset to an +empty string. Trackers will only be used if they are using a proxy +server. The listen sockets are closed, and incoming connections will +only be accepted through a SOCKS5 or I2P proxy (if a peer proxy is set up and +is run on the same machine as the tracker proxy). Since no incoming connections +are accepted, NAT-PMP, UPnP, DHT and local peer discovery are all turned off +when this setting is enabled.

    +

    If you're using I2P, it might make sense to enable anonymous mode as well.

    @@ -4985,7 +5035,7 @@ has the followinf signature:

    template <T> T* alert_cast(alert* a); template <T> T const* alert_cast(alert const* a); -

    You can also use a dispatcher mechanism that's available in libtorrent.

    +

    You can also use a alert dispatcher mechanism that's available in libtorrent.

    All alert types are defined in the <libtorrent/alert_types.hpp> header file.

    The alert class is the base class that specific messages are derived from. This is its synopsis:

    @@ -5808,8 +5858,32 @@ struct dht_get_peers_alert: alert };
    -
    -

    dispatcher

    +
    +

    anonymous_mode_alert

    +

    This alert is posted when a bittorrent feature is blocked because of the +anonymous mode. For instance, if the tracker proxy is not set up, no +trackers will be used, because trackers can only be used through proxies +when in anonymous mode.

    +
    +struct anonymous_mode_alert: tracker_alert
    +{
    +        // ...
    +        enum kind_t
    +        {
    +                tracker_not_anonymous = 1
    +        };
    +        int kind;
    +        std::string str;
    +};
    +
    +

    kind specifies what error this is, it's one of:

    +

    tracker_not_anonymous means that there's no proxy set up for tracker +communication and the tracker will not be contacted. The tracker which +this failed for is specified in the str member.

    +
    +
    +
    +

    alert dispatcher

    The handle_alert class is defined in <libtorrent/alert.hpp>.

    Examples usage:

    @@ -5853,7 +5927,6 @@ parameters to select between more types. If the number of types are more than
     15, you can define TORRENT_MAX_ALERT_TYPES to a greater number before
     including <libtorrent/alert.hpp>.

    -

    exceptions

    Many functions in libtorrent have two versions, one that throws exceptions on diff --git a/docs/manual.rst b/docs/manual.rst index 54958b93a..ac0a33926 100644 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -3885,6 +3885,7 @@ session_settings int default_peer_download_rate; bool broadcast_lsd; bool ignore_resume_timestamps; + bool anonymous_mode; }; ``user_agent`` this is the client identification to the tracker. @@ -4525,6 +4526,18 @@ It might be useful to set this to true if your network is faster than your disk, and it would be faster to redownload potentially missed pieces than to go through the whole storage to look for them. +``anonymous_mode`` defaults to false. When set to true, the client tries +to hide its identity to a certain degree. The peer-ID will no longer +include the client's fingerprint. The user-agent will be reset to an +empty string. Trackers will only be used if they are using a proxy +server. The listen sockets are closed, and incoming connections will +only be accepted through a SOCKS5 or I2P proxy (if a peer proxy is set up and +is run on the same machine as the tracker proxy). Since no incoming connections +are accepted, NAT-PMP, UPnP, DHT and local peer discovery are all turned off +when this setting is enabled. + +If you're using I2P, it might make sense to enable anonymous mode as well. + pe_settings =========== @@ -5176,7 +5189,7 @@ has the followinf signature:: template T* alert_cast(alert* a); template T const* alert_cast(alert const* a); -You can also use a dispatcher_ mechanism that's available in libtorrent. +You can also use a `alert dispatcher`_ mechanism that's available in libtorrent. All alert types are defined in the ```` header file. @@ -6170,8 +6183,35 @@ It belongs to the ``dht_notification`` category. sha1_hash info_hash; }; -dispatcher ----------- +anonymous_mode_alert +-------------------- + +This alert is posted when a bittorrent feature is blocked because of the +anonymous mode. For instance, if the tracker proxy is not set up, no +trackers will be used, because trackers can only be used through proxies +when in anonymous mode. + +:: + + struct anonymous_mode_alert: tracker_alert + { + // ... + enum kind_t + { + tracker_not_anonymous = 1 + }; + int kind; + std::string str; + }; + +``kind`` specifies what error this is, it's one of: + +``tracker_not_anonymous`` means that there's no proxy set up for tracker +communication and the tracker will not be contacted. The tracker which +this failed for is specified in the ``str`` member. + +alert dispatcher +================ The ``handle_alert`` class is defined in ````. diff --git a/include/libtorrent/alert_types.hpp b/include/libtorrent/alert_types.hpp index 794a5504d..930354221 100644 --- a/include/libtorrent/alert_types.hpp +++ b/include/libtorrent/alert_types.hpp @@ -1130,6 +1130,30 @@ namespace libtorrent const static int static_category = alert::storage_notification; }; + + struct TORRENT_EXPORT anonymous_mode_alert: torrent_alert + { + anonymous_mode_alert(torrent_handle const& h + , int kind_, std::string const& str_) + : torrent_alert(h) + , kind(kind_) + , str(str_) + {} + + TORRENT_DEFINE_ALERT(anonymous_mode_alert); + + const static int static_category = alert::error_notification; + virtual std::string message() const; + + enum kind_t + { + tracker_not_anonymous = 0 + }; + + int kind; + std::string str; + }; + } diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index d228b1841..c7d686aee 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -570,6 +570,7 @@ namespace libtorrent // when as a socks proxy is used for peers, also // listen for incoming connections on a socks connection boost::shared_ptr m_socks_listen_socket; + boost::uint16_t m_socks_listen_port; void open_new_incoming_socks_connection(); diff --git a/include/libtorrent/escape_string.hpp b/include/libtorrent/escape_string.hpp index 9fd8156a5..0d310fb77 100644 --- a/include/libtorrent/escape_string.hpp +++ b/include/libtorrent/escape_string.hpp @@ -53,6 +53,8 @@ namespace libtorrent TORRENT_EXPORT bool string_begins_no_case(char const* s1, char const* s2); TORRENT_EXPORT bool string_equal_no_case(char const* s1, char const* s2); + TORRENT_EXPORT void url_random(char* begin, char* end); + TORRENT_EXPORT std::string unescape_string(std::string const& s, error_code& ec); // replaces all disallowed URL characters by their %-encoding TORRENT_EXPORT std::string escape_string(const char* str, int len); diff --git a/include/libtorrent/session_settings.hpp b/include/libtorrent/session_settings.hpp index 14146a6cd..3c4e56107 100644 --- a/include/libtorrent/session_settings.hpp +++ b/include/libtorrent/session_settings.hpp @@ -212,6 +212,7 @@ namespace libtorrent , default_peer_download_rate(0) , broadcast_lsd(false) , ignore_resume_timestamps(false) + , anonymous_mode(false) {} // this is the user agent that will be sent to the tracker @@ -817,6 +818,12 @@ namespace libtorrent // file and is typically compared to make sure the files haven't changed // since the last session bool ignore_resume_timestamps; + + // when this is true, libtorrent will take actions to make sure any + // privacy sensitive information is leaked out from the client. This + // mode is assumed to be combined with using a proxy for all your + // traffic. With this option, your true IP address will not be exposed + bool anonymous_mode; }; #ifndef TORRENT_DISABLE_DHT diff --git a/src/alert.cpp b/src/alert.cpp index a6c8997cc..6188b5cdb 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -465,5 +465,17 @@ namespace libtorrent { cache_flushed_alert::cache_flushed_alert(torrent_handle const& h): torrent_alert(h) {} + std::string anonymous_mode_alert::message() const + { + char msg[200]; + char const* msgs[] = { + "tracker is not anonymous, set a proxy" + }; + snprintf(msg, sizeof(msg), "%s: %s: %s" + , torrent_alert::message().c_str() + , msgs[kind], str.c_str()); + return msg; + } + } // namespace libtorrent diff --git a/src/bt_peer_connection.cpp b/src/bt_peer_connection.cpp index 8579461bd..2d128874a 100644 --- a/src/bt_peer_connection.cpp +++ b/src/bt_peer_connection.cpp @@ -1869,8 +1869,12 @@ namespace libtorrent // only send the port in case we bade the connection // on incoming connections the other end already knows // our listen port - if (is_local()) handshake["p"] = m_ses.listen_port(); - handshake["v"] = m_ses.settings().user_agent; + if (!m_ses.m_settings.anonymous_mode) + { + if (is_local()) handshake["p"] = m_ses.listen_port(); + handshake["v"] = m_ses.settings().user_agent; + } + std::string remote_address; std::back_insert_iterator out(remote_address); detail::write_address(remote().address(), out); @@ -1893,13 +1897,16 @@ namespace libtorrent )) handshake["upload_only"] = 1; - tcp::endpoint ep = m_ses.get_ipv6_interface(); - if (!is_any(ep.address())) + if (!m_ses.m_settings.anonymous_mode) { - std::string ipv6_address; - std::back_insert_iterator out(ipv6_address); - detail::write_address(ep.address(), out); - handshake["ipv6"] = ipv6_address; + tcp::endpoint ep = m_ses.get_ipv6_interface(); + if (!is_any(ep.address())) + { + std::string ipv6_address; + std::back_insert_iterator out(ipv6_address); + detail::write_address(ep.address(), out); + handshake["ipv6"] = ipv6_address; + } } // loop backwards, to make the first extension be the last diff --git a/src/escape_string.cpp b/src/escape_string.cpp index 8f73f3e8f..040024de5 100644 --- a/src/escape_string.cpp +++ b/src/escape_string.cpp @@ -103,6 +103,19 @@ namespace libtorrent return bool(std::strchr(ws, c)); } + // generate a url-safe random string + void url_random(char* begin, char* end) + { + // http-accepted characters: + // excluding ', since some buggy trackers don't support that + static char const printable[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz-_.!~*()"; + + // the random number + while (begin != end) + *begin++ = printable[rand() % (sizeof(printable)-1)]; + } + char to_lower(char c) { return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; diff --git a/src/http_seed_connection.cpp b/src/http_seed_connection.cpp index 2d3366f2a..75bfa50bd 100644 --- a/src/http_seed_connection.cpp +++ b/src/http_seed_connection.cpp @@ -221,7 +221,7 @@ namespace libtorrent request += " HTTP/1.1\r\n"; request += "Host: "; request += m_host; - if (m_first_request) + if (m_first_request && !m_ses.settings().user_agent.empty()) { request += "\r\nUser-Agent: "; request += m_ses.settings().user_agent; diff --git a/src/http_tracker_connection.cpp b/src/http_tracker_connection.cpp index a2bec5bed..e1f95a897 100644 --- a/src/http_tracker_connection.cpp +++ b/src/http_tracker_connection.cpp @@ -205,7 +205,8 @@ namespace libtorrent :settings.tracker_completion_timeout; m_tracker_connection->get(url, seconds(timeout) - , 1, &m_ps, 5, settings.user_agent, bind_interface() + , 1, &m_ps, 5, settings.anonymous_mode ? "" : settings.user_agent + , bind_interface() #if TORRENT_USE_I2P , m_i2p_conn #endif diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 9ee6fadf2..9987054f1 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -306,7 +306,9 @@ namespace aux { TORRENT_SETTING(boolean, strict_end_game_mode) TORRENT_SETTING(integer, default_peer_upload_rate) TORRENT_SETTING(integer, default_peer_download_rate) + TORRENT_SETTING(boolean, broadcast_lsd) TORRENT_SETTING(boolean, ignore_resume_timestamps) + TORRENT_SETTING(boolean, anonymous_mode) }; #undef TORRENT_SETTING @@ -709,17 +711,7 @@ namespace aux { , print.begin() + print.length() , m_peer_id.begin()); - // http-accepted characters: - // excluding ', since some buggy trackers don't support that - static char const printable[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz-_.!~*()"; - - // the random number - for (unsigned char* i = m_peer_id.begin() + print.length(); - i != m_peer_id.end(); ++i) - { - *i = printable[rand() % (sizeof(printable)-1)]; - } + url_random((char*)&m_peer_id[print.length()], (char*)&m_peer_id[0] + 20); m_timer.expires_from_now(milliseconds(100), ec); m_timer.async_wait(bind(&session_impl::on_tick, this, _1)); @@ -1229,7 +1221,31 @@ namespace aux { || m_settings.active_limit != s.active_limit) && m_auto_manage_time_scaler > 2) m_auto_manage_time_scaler = 2; + + // if anonymous mode was enabled, clear out the peer ID + bool anonymous = (m_settings.anonymous_mode != s.anonymous_mode && s.anonymous_mode); + m_settings = s; + + // enable anonymous mode. We don't want to accept any incoming + // connections, except through a proxy. + if (anonymous) + { + m_settings.user_agent.clear(); + url_random((char*)&m_peer_id[0], (char*)&m_peer_id[0] + 20); + stop_lsd(); + stop_upnp(); + stop_natpmp(); +#ifndef TORRENT_DISABLE_DHT + stop_dht(); +#endif + // close the listen sockets + error_code ec; + for (std::list::iterator i = m_listen_sockets.begin() + , end(m_listen_sockets.end()); i != end; ++i) + i->sock->close(ec); + m_listen_sockets.clear(); + } if (m_settings.connection_speed < 0) m_settings.connection_speed = 200; if (m_settings.broadcast_lsd && m_lsd) m_lsd->use_broadcast(true); @@ -1465,7 +1481,9 @@ namespace aux { socks5_stream& s = *m_socks_listen_socket->get(); s.set_command(2); // 2 means BIND (as opposed to CONNECT) - s.async_connect(tcp::endpoint(address_v4::any(), m_listen_interface.port()) + m_socks_listen_port = m_listen_interface.port(); + if (m_socks_listen_port == 0) m_socks_listen_port = 2000 + rand() % 60000; + s.async_connect(tcp::endpoint(address_v4::any(), m_socks_listen_port) , boost::bind(&session_impl::on_socks_accept, this, m_socks_listen_socket, _1)); } @@ -3173,6 +3191,17 @@ namespace aux { unsigned short session_impl::listen_port() const { + // if peer connections are set up to be received over a socks + // proxy, and it's the same one as we're using for the tracker + // just tell the tracker the socks5 port we're listening on + if (m_socks_listen_socket->is_open() + && m_peer_proxy.hostname == m_tracker_proxy.hostname) + return m_socks_listen_port; + + // if not, don't tell the tracker anything if we're in anonymous + // mode. We don't want to leak our listen port since it can + // potentially identify us if it is leaked elsewere + if (m_settings.anonymous_mode) return 0; if (m_listen_sockets.empty()) return 0; return m_listen_sockets.front().external_port; } diff --git a/src/torrent.cpp b/src/torrent.cpp index b387241f5..1dad5db07 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -1392,11 +1392,14 @@ namespace libtorrent req.event = e; error_code ec; - tcp::endpoint ep; - ep = m_ses.get_ipv6_interface(); - if (ep != tcp::endpoint()) req.ipv6 = ep.address().to_string(ec); - ep = m_ses.get_ipv4_interface(); - if (ep != tcp::endpoint()) req.ipv4 = ep.address().to_string(ec); + if (!m_ses.m_settings.anonymous_mode) + { + tcp::endpoint ep; + ep = m_ses.get_ipv6_interface(); + if (ep != tcp::endpoint()) req.ipv6 = ep.address().to_string(ec); + ep = m_ses.get_ipv4_interface(); + if (ep != tcp::endpoint()) req.ipv4 = ep.address().to_string(ec); + } // if we are aborting. we don't want any new peers req.num_want = (req.event == tracker_request::stopped) @@ -1451,6 +1454,40 @@ namespace libtorrent if (!is_any(bind_interface)) req.bind_ip = bind_interface; else req.bind_ip = m_ses.m_listen_interface.address(); + if (settings().anonymous_mode) + { + // in anonymous_mode we don't talk directly to trackers + // only if there is a proxy + std::string protocol = req.url.substr(0, req.url.find(':')); + int proxy_type = m_ses.m_tracker_proxy.type; + + if ((protocol == "http" || protocol == "https") + && proxy_type == proxy_settings::none) + { + + if (m_ses.m_alerts.should_post()) + { + m_ses.m_alerts.post_alert( + anonymous_mode_alert(get_handle() + , anonymous_mode_alert::tracker_not_anonymous, req.url)); + } + continue; + } + + if (protocol == "udp" + || (proxy_type != proxy_settings::socks5 + && proxy_type != proxy_settings::socks5_pw + && proxy_type != proxy_settings::i2p_proxy)) + { + if (m_ses.m_alerts.should_post()) + { + m_ses.m_alerts.post_alert( + anonymous_mode_alert(get_handle() + , anonymous_mode_alert::tracker_not_anonymous, req.url)); + } + continue; + } + } #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING (*m_ses.m_logger) << time_now_string() << " ==> TACKER REQUEST " << req.url << " event=" << (req.event==tracker_request::stopped?"stopped" diff --git a/src/web_peer_connection.cpp b/src/web_peer_connection.cpp index d15f35a89..9dfdb70ed 100644 --- a/src/web_peer_connection.cpp +++ b/src/web_peer_connection.cpp @@ -224,7 +224,7 @@ namespace libtorrent request += " HTTP/1.1\r\n"; request += "Host: "; request += m_host; - if (m_first_request) + if (m_first_request && !m_ses.settings().user_agent.empty()) { request += "\r\nUser-Agent: "; request += m_ses.settings().user_agent; @@ -285,7 +285,7 @@ namespace libtorrent request += " HTTP/1.1\r\n"; request += "Host: "; request += m_host; - if (m_first_request) + if (m_first_request && !m_ses.settings().user_agent.empty()) { request += "\r\nUser-Agent: "; request += m_ses.settings().user_agent;