* Encrypted (obfuscated) handshake and connection support. Patch by

Josef Drexler, public domain as per earlier agreement.


git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@790 e378c898-3ddf-0310-93e7-cc216c733640
This commit is contained in:
rakshasa
2006-10-14 16:46:43 +00:00
parent eb7c0b5874
commit 1736c8eaf7
9 changed files with 203 additions and 1 deletions
+21 -1
View File
@@ -3,7 +3,7 @@
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> .\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
.\" Please send any bug reports, improvements, comments, patches, .\" Please send any bug reports, improvements, comments, patches,
.\" etc. to Steve Cheng <steve@ggi-project.org>. .\" etc. to Steve Cheng <steve@ggi-project.org>.
.TH "RTORRENT" "1" "11 October 2006" "BitTorrent client for ncurses" "" .TH "RTORRENT" "1" "14 October 2006" "BitTorrent client for ncurses" ""
.SH NAME .SH NAME
rtorrent \- a BitTorrent client for ncurses rtorrent \- a BitTorrent client for ncurses
@@ -229,6 +229,22 @@ Add a preferred filename encoding to the list. The encodings are
attempted in the order they are inserted, if none match the torrent attempted in the order they are inserted, if none match the torrent
default is used. default is used.
.TP .TP
\fBencryption_options = \fIoption\fB,\fI\&...\fB\fR
Set how rtorrent should deal with encrypted Bittorrent connections. By
default, encryption is disabled, equivalent to specifying the option
\fBnone\fR\&. Alternatively, any number of the following
options may be specified:
\fBallow_incoming\fR (allow incoming encrypted connections),
\fBtry_outgoing\fR (use encryption for outgoing connections),
\fBrequire\fR (disable unencrypted handshakes),
\fBrequire_RC4\fR (also disable plaintext transmission after the
initial encrypted handshake),
\fBenable_retry\fR (if the initial outgoing connection fails, retry
with encryption turned on if it was off or off if it was on),
\fBprefer_plaintext\fR (choose plaintext when peer offers a choice
between plaintext transmission and RC4 encryption, otherwise RC4 will be used).
.TP
\fBschedule = \fIid\fB,\fIstart\fB,\fIinterval\fB,\fIcommand\fB\fR \fBschedule = \fIid\fB,\fIstart\fB,\fIinterval\fB,\fIcommand\fB\fR
Call \fBcommand\fR every \fBinterval\fR Call \fBcommand\fR every \fBinterval\fR
seconds, starting from \fBstart\fR\&. An seconds, starting from \fBstart\fR\&. An
@@ -408,6 +424,10 @@ logged at the moment, although disabling it will work as expected.
Change the TOS of peer connections, by default set to Change the TOS of peer connections, by default set to
\fBthroughput\fR\&. If the option is set to \fBthroughput\fR\&. If the option is set to
\fBdefault\fR then the system default TOS is used. \fBdefault\fR then the system default TOS is used.
.TP
\fBhandshake_log = \fIyes\fB\fR
Enable logging of the peer handshake. This generates a large number of
log messages, but may be useful to debug connection problems.
.SH "AUTHORS" .SH "AUTHORS"
.PP .PP
+34
View File
@@ -518,6 +518,30 @@ default is used.
</para></listitem> </para></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>encryption_options = <replaceable>option</replaceable>,<replaceable>...</replaceable></term>
<listitem><para>
Set how rtorrent should deal with encrypted Bittorrent connections. By
default, encryption is disabled, equivalent to specifying the option
<emphasis>none</emphasis>. Alternatively, any number of the following
options may be specified:
</para><para>
<emphasis>allow_incoming</emphasis> (allow incoming encrypted connections),
<emphasis>try_outgoing</emphasis> (use encryption for outgoing connections),
<emphasis>require</emphasis> (disable unencrypted handshakes),
<emphasis>require_RC4</emphasis> (also disable plaintext transmission after the
initial encrypted handshake),
<emphasis>enable_retry</emphasis> (if the initial outgoing connection fails, retry
with encryption turned on if it was off or off if it was on),
<emphasis>prefer_plaintext</emphasis> (choose plaintext when peer offers a choice
between plaintext transmission and RC4 encryption, otherwise RC4 will be used).
</para></listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term>schedule = <replaceable>id</replaceable>,<replaceable>start</replaceable>,<replaceable>interval</replaceable>,<replaceable>command</replaceable></term> <term>schedule = <replaceable>id</replaceable>,<replaceable>start</replaceable>,<replaceable>interval</replaceable>,<replaceable>command</replaceable></term>
<listitem><para> <listitem><para>
@@ -875,6 +899,16 @@ Change the TOS of peer connections, by default set to
</para></listitem> </para></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>handshake_log = <replaceable>yes</replaceable></term>
<listitem><para>
Enable logging of the peer handshake. This generates a large number of
log messages, but may be useful to debug connection problems.
</para></listitem>
</varlistentry>
</variablelist> </variablelist>
</refsect1> </refsect1>
+9
View File
@@ -65,6 +65,15 @@
#schedule = ip_tick,0,1800,ip=rakshasa #schedule = ip_tick,0,1800,ip=rakshasa
#schedule = bind_tick,0,1800,bind=rakshasa #schedule = bind_tick,0,1800,bind=rakshasa
# Encryption options, set to none (default) or any combination of the following:
# allow_incoming, try_outgoing, require, require_RC4, enable_retry, prefer_plaintext
#
# The example value allows incoming encrypted connections, starts unencrypted
# outgoing connections but retries with encryption if they fail, preferring
# plaintext to RC4 encryption after the encrypted handshake
#
# encryption_options = allow_incoming,enable_retry,prefer_plaintext
# #
# Do not modify the following parameters unless you know what you're doing. # Do not modify the following parameters unless you know what you're doing.
# #
+57
View File
@@ -51,6 +51,7 @@
#include <sigc++/hide.h> #include <sigc++/hide.h>
#include <torrent/object.h> #include <torrent/object.h>
#include <torrent/connection_manager.h> #include <torrent/connection_manager.h>
#include <torrent/error.h>
#include <torrent/exceptions.h> #include <torrent/exceptions.h>
#include <torrent/resume.h> #include <torrent/resume.h>
#include <torrent/tracker_list.h> #include <torrent/tracker_list.h>
@@ -105,6 +106,60 @@ receive_tracker_dump(const std::string& url, const char* data, size_t size) {
fstr << std::endl <<"---" << std::endl; fstr << std::endl <<"---" << std::endl;
} }
void
Manager::handshake_log(const sockaddr* sa, torrent::ConnectionManager::HandshakeMessage msg, int err, std::string hash) {
if (!control->variable()->get_value("handshake_log"))
return;
std::string peer;
std::string download;
const rak::socket_address* socketAddress = rak::socket_address::cast_from(sa);
if (socketAddress->is_valid()) {
char port[6];
snprintf(port, sizeof(port), "%d", socketAddress->port());
peer = socketAddress->address_str() + ":" + port;
} else {
peer = "(unknown)";
}
torrent::Download d = torrent::download_find(hash);
if (d.is_valid())
download = ": " + d.name();
else
download = "";
switch (msg) {
case torrent::ConnectionManager::handshake_incoming:
m_logComplete.push_front("Incoming connection from " + peer + download);
break;
case torrent::ConnectionManager::handshake_outgoing_encrypted:
m_logComplete.push_front("Outgoing encrypted connection to " + peer + download);
break;
case torrent::ConnectionManager::handshake_outgoing:
m_logComplete.push_front("Outgoing connection to " + peer + download);
break;
case torrent::ConnectionManager::handshake_success:
m_logComplete.push_front("Successful handshake: " + peer + download);
break;
case torrent::ConnectionManager::handshake_dropped:
m_logComplete.push_front("Dropped handshake: " + peer + " - " + torrent::strerror(err) + download);
break;
case torrent::ConnectionManager::handshake_failed:
m_logComplete.push_front("Handshake failed: " + peer + " - " + torrent::strerror(err) + download);
break;
case torrent::ConnectionManager::handshake_retry_plaintext:
m_logComplete.push_front("Trying again without encryption: " + peer + download);
break;
case torrent::ConnectionManager::handshake_retry_encrypted:
m_logComplete.push_front("Trying again encrypted: " + peer + download);
break;
default:
m_logComplete.push_front("Unknown handshake message for " + peer + download);
break;
}
}
// Hmm... find some better place for all this. // Hmm... find some better place for all this.
void void
Manager::delete_tied(Download* d) { Manager::delete_tied(Download* d) {
@@ -183,6 +238,8 @@ Manager::initialize_second() {
m_downloadList->slot_map_insert()["1_connect_tracker_dump"] = sigc::bind(sigc::ptr_fun(&connect_signal_tracker_dump), sigc::ptr_fun(&receive_tracker_dump)); m_downloadList->slot_map_insert()["1_connect_tracker_dump"] = sigc::bind(sigc::ptr_fun(&connect_signal_tracker_dump), sigc::ptr_fun(&receive_tracker_dump));
m_downloadList->slot_map_erase()["1_delete_tied"] = sigc::mem_fun(this, &Manager::delete_tied); m_downloadList->slot_map_erase()["1_delete_tied"] = sigc::mem_fun(this, &Manager::delete_tied);
torrent::connection_manager()->set_signal_handshake_log(sigc::mem_fun(this, &Manager::handshake_log));
} }
void void
+4
View File
@@ -39,6 +39,8 @@
#include <iosfwd> #include <iosfwd>
#include <torrent/connection_manager.h>
#include "download_list.h" #include "download_list.h"
#include "poll_manager.h" #include "poll_manager.h"
#include "log.h" #include "log.h"
@@ -93,6 +95,8 @@ public:
void push_log(const std::string& msg) { m_logImportant.push_front(msg); m_logComplete.push_front(msg); } void push_log(const std::string& msg) { m_logImportant.push_front(msg); m_logComplete.push_front(msg); }
void handshake_log(const sockaddr* sa, torrent::ConnectionManager::HandshakeMessage msg, int err, std::string hash);
// Temporary, find a better place for this. // Temporary, find a better place for this.
void try_create_download(const std::string& uri, bool start, bool printLog = true, bool tied = false); void try_create_download(const std::string& uri, bool start, bool printLog = true, bool tied = false);
void try_create_download_expand(const std::string& uri, bool start, bool printLog = true, bool tied = false); void try_create_download_expand(const std::string& uri, bool start, bool printLog = true, bool tied = false);
+43
View File
@@ -101,6 +101,43 @@ private:
TextElement* m_branch2; TextElement* m_branch2;
}; };
template <typename slot_type>
class TextElementBranch3 : public TextElement {
public:
typedef typename slot_type::argument_type arg1_type;
typedef typename slot_type::result_type result_type;
TextElementBranch3(const slot_type& slot1, TextElement* branch1, const slot_type& slot2, TextElement* branch2, TextElement* branch3) :
m_slot1(slot1), m_slot2(slot2), m_branch1(branch1), m_branch2(branch2), m_branch3(branch3) {}
~TextElementBranch3() { delete m_branch1; delete m_branch2; delete m_branch3; }
virtual char* print(char* first, char* last, Canvas::attributes_list* attributes, void* object) {
if (object == NULL)
return first;
if (m_slot1(reinterpret_cast<arg1_type>(object)))
return m_branch1 != NULL ? m_branch1->print(first, last, attributes, object) : first;
else if (m_slot2(reinterpret_cast<arg1_type>(object)))
return m_branch2 != NULL ? m_branch2->print(first, last, attributes, object) : first;
else
return m_branch3 != NULL ? m_branch3->print(first, last, attributes, object) : first;
}
virtual extent_type max_length() {
return std::max(m_branch1 != NULL ? m_branch1->max_length() : 0,
std::max(m_branch2 != NULL ? m_branch2->max_length() : 0,
m_branch3 != NULL ? m_branch3->max_length() : 0));
}
private:
slot_type m_slot1;
slot_type m_slot2;
TextElement* m_branch1;
TextElement* m_branch2;
TextElement* m_branch3;
};
template <typename slot_type> template <typename slot_type>
inline TextElementBranchVoid<slot_type>* inline TextElementBranchVoid<slot_type>*
text_element_branch_void(const slot_type& slot, TextElement* branch1, TextElement* branch2) { text_element_branch_void(const slot_type& slot, TextElement* branch1, TextElement* branch2) {
@@ -113,6 +150,12 @@ text_element_branch(const slot_type& slot, TextElement* branch1, TextElement* br
return new TextElementBranch<slot_type>(slot, branch1, branch2); return new TextElementBranch<slot_type>(slot, branch1, branch2);
} }
template <typename slot_type>
inline TextElementBranch3<slot_type>*
text_element_branch3(const slot_type& slot1, TextElement* branch1, const slot_type& slot2, TextElement* branch2, TextElement* branch3) {
return new TextElementBranch3<slot_type>(slot1, branch1, slot2, branch2, branch3);
}
} }
#endif #endif
+1
View File
@@ -107,6 +107,7 @@ WindowPeerList::redraw() {
m_canvas->print(x, y, "%.1f", (double)p.peer_rate()->rate() / 1024); x += 7; m_canvas->print(x, y, "%.1f", (double)p.peer_rate()->rate() / 1024); x += 7;
m_canvas->print(x, y, "%c/%c%c/%c%c", m_canvas->print(x, y, "%c/%c%c/%c%c",
p.is_encrypted() ? p.is_incoming() ? 'R' : 'L' :
p.is_incoming() ? 'r' : 'l', p.is_incoming() ? 'r' : 'l',
p.is_remote_choked() ? 'c' : 'u', p.is_remote_choked() ? 'c' : 'u',
p.is_remote_interested() ? 'i' : 'n', p.is_remote_interested() ? 'i' : 'n',
+33
View File
@@ -228,6 +228,36 @@ apply_encoding_list(__UNUSED Control* m, const std::string& arg) {
torrent::encoding_list()->push_back(arg); torrent::encoding_list()->push_back(arg);
} }
void
apply_encryption_options(const std::string& arg) {
rak::split_iterator_t<std::string> sitr = rak::split_iterator(arg, ',');
uint32_t options_mask = torrent::ConnectionManager::encryption_none;
while (sitr != rak::split_iterator(arg)) {
std::string opt = rak::trim(*sitr);
++sitr;
if (opt == "none")
options_mask = torrent::ConnectionManager::encryption_none;
else if (opt == "allow_incoming")
options_mask |= torrent::ConnectionManager::encryption_allow_incoming;
else if (opt == "try_outgoing")
options_mask |= torrent::ConnectionManager::encryption_try_outgoing;
else if (opt == "require")
options_mask |= torrent::ConnectionManager::encryption_require;
else if (opt == "require_RC4")
options_mask |= torrent::ConnectionManager::encryption_require_RC4;
else if (opt == "enable_retry")
options_mask |= torrent::ConnectionManager::encryption_enable_retry;
else if (opt == "prefer_plaintext")
options_mask |= torrent::ConnectionManager::encryption_prefer_plaintext;
else
throw torrent::input_error("Invalid encryption option '" + opt + "'.");
}
torrent::connection_manager()->set_encryption_options(options_mask);
}
void void
apply_enable_trackers(Control* m, __UNUSED const std::string& arg) { apply_enable_trackers(Control* m, __UNUSED const std::string& arg) {
bool state = (arg != "no"); bool state = (arg != "no");
@@ -503,4 +533,7 @@ initialize_option_handler(Control* c) {
variables->insert("enable_trackers", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_enable_trackers, c))); variables->insert("enable_trackers", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_enable_trackers, c)));
variables->insert("encoding_list", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_encoding_list, c))); variables->insert("encoding_list", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_encoding_list, c)));
variables->insert("encryption_options", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::ptr_fn(&apply_encryption_options)));
variables->insert("handshake_log", new utils::VariableBool(false));
} }
+1
View File
@@ -109,6 +109,7 @@ ElementPeerList::create_info() {
element->push_column("Client:", display::text_element_string_slot(rak::on(std::mem_fun(&torrent::Peer::id), rak::make_mem_fun(control->client_info(), &display::ClientInfo::str_str)))); element->push_column("Client:", display::text_element_string_slot(rak::on(std::mem_fun(&torrent::Peer::id), rak::make_mem_fun(control->client_info(), &display::ClientInfo::str_str))));
element->push_column("Options:", display::text_element_string_slot(std::mem_fun(&torrent::Peer::options), string_base::flag_escape_hex | string_base::flag_fixed_width, 0, 8)); element->push_column("Options:", display::text_element_string_slot(std::mem_fun(&torrent::Peer::options), string_base::flag_escape_hex | string_base::flag_fixed_width, 0, 8));
element->push_column("Connected:", display::text_element_branch(std::mem_fun(&torrent::Peer::is_incoming), te_string("incoming"), te_string("outgoing"))); element->push_column("Connected:", display::text_element_branch(std::mem_fun(&torrent::Peer::is_incoming), te_string("incoming"), te_string("outgoing")));
element->push_column("Encrypted:", display::text_element_branch3(std::mem_fun(&torrent::Peer::is_encrypted), te_string("yes"), std::mem_fun(&torrent::Peer::is_obfuscated), te_string("handshake"), te_string("no")));
element->push_back(""); element->push_back("");
element->push_column("Snubbed:", display::text_element_branch(std::mem_fun(&torrent::Peer::is_snubbed), te_string("yes"), te_string("no"))); element->push_column("Snubbed:", display::text_element_branch(std::mem_fun(&torrent::Peer::is_snubbed), te_string("yes"), te_string("no")));