forked from premiere/premiere-libtorrent
merged DHT fix from RC_0_16
This commit is contained in:
parent
6612d1f88a
commit
f12e1c1a3f
|
@ -5,6 +5,7 @@
|
|||
* fix uTP edge case where udp socket buffer fills up
|
||||
* fix nagle implementation in uTP
|
||||
|
||||
* fix support for storing arbitrary data in the DHT
|
||||
* fixed bug in uTP packet circle buffer
|
||||
* fix potential crash when using torrent_handle::add_piece
|
||||
* added missing add_torrent_alert to python binding
|
||||
|
|
|
@ -98,14 +98,19 @@ i.e. the node ID of the node sending the message, to maintain the structure of t
|
|||
network.</p>
|
||||
<p>The <tt class="docutils literal">token</tt> field also has the same semantics as the standard DHT message <tt class="docutils literal">get_peers</tt>
|
||||
and <tt class="docutils literal">announce_peer</tt>, when requesting an item and to write an item respectively.</p>
|
||||
<p>The <tt class="docutils literal">k</tt> field is the PKCS#1 encoded 2048 bit RSA public key, which the signature
|
||||
can be authenticated with. When looking up a mutable item, the <tt class="docutils literal">target</tt> field
|
||||
MUST be the SHA-1 hash of this key.</p>
|
||||
<p>The distinction between storing mutable and immutable items is the inclusion
|
||||
of a public key, a sequence number and signature (<tt class="docutils literal">k</tt>, <tt class="docutils literal">seq</tt> and <tt class="docutils literal">sig</tt>).
|
||||
The distinction betwewn retrieving a mutable and immutable item is the inclusion of
|
||||
the public key spill-over (<tt class="docutils literal">k</tt>) in the <tt class="docutils literal">get</tt> request.</p>
|
||||
<p>The <tt class="docutils literal">v</tt> key is the <em>value</em> to be stored. It is allowed to be any bencoded type (list,
|
||||
of a public key, a sequence number and signature (<tt class="docutils literal">k</tt>, <tt class="docutils literal">seq</tt> and <tt class="docutils literal">sig</tt>).</p>
|
||||
<p><tt class="docutils literal">get</tt> requests for mutable items and immutable items cannot be distinguished from
|
||||
eachother. An implementation can either store mutable and immutable items in the same
|
||||
hash table internally, or in separate ones and potentially do two lookups for <tt class="docutils literal">get</tt>
|
||||
requests.</p>
|
||||
<p>The <tt class="docutils literal">v</tt> field is the <em>value</em> to be stored. It is allowed to be any bencoded type (list,
|
||||
dict, string or integer). When it's being hashed (for verifying its signature or to calculate
|
||||
its key), its flattened, bencoded, form is used.</p>
|
||||
<p>Storing nodes are SHOULD reject <tt class="docutils literal">put</tt> requests where the bencoded form of <tt class="docutils literal">v</tt> is longer
|
||||
<p>Storing nodes SHOULD reject <tt class="docutils literal">put</tt> requests where the bencoded form of <tt class="docutils literal">v</tt> is longer
|
||||
than 767 bytes.</p>
|
||||
</div>
|
||||
<div class="section" id="immutable-items">
|
||||
|
@ -172,7 +177,8 @@ there is no need to authenticate the origin of them. This makes immutable items
|
|||
<h1>mutable items</h1>
|
||||
<p>Mutable items can be updated, without changing their DHT keys. To authenticate
|
||||
that only the original publisher can update an item, it is signed by a private key
|
||||
generated by the original publisher.</p>
|
||||
generated by the original publisher. The target ID mutable items are stored under
|
||||
is the SHA-1 hash of the public key (as it appears in the <tt class="docutils literal">put</tt> message).</p>
|
||||
<p>In order to avoid a malicious node to overwrite the list head with an old
|
||||
version, the sequence number <tt class="docutils literal">seq</tt> must be monotonically increasing for each update,
|
||||
and a node hosting the list node MUST not downgrade a list head from a higher sequence
|
||||
|
@ -187,7 +193,7 @@ number and <tt class="docutils literal">v</tt> key. e.g. something like this:: <
|
|||
"a":
|
||||
{
|
||||
"id": <em><20 byte id of sending node (string)></em>,
|
||||
"k": <em><RSA-2048 public key (268 bytes string)></em>,
|
||||
"k": <em><RSA-2048 public key (PKCS#1 encoded)></em>,
|
||||
"seq": <em><monotonically increasing sequence number (integer)></em>,
|
||||
"sig": <em><RSA-2048 signature (256 bytes string)></em>,
|
||||
"token": <em><write-token (string)></em>,
|
||||
|
@ -217,8 +223,7 @@ stored on the node, MUST reject the request.</p>
|
|||
"a":
|
||||
{
|
||||
"id": <em><20 byte id of sending node (string)></em>,
|
||||
"target:" <em><first 20 bytes of public key (string)></em>,
|
||||
"k": <em><remaining 248 bytes of public key (string)></em>
|
||||
"target:" <em><20 byte SHA-1 hash of public key (string)></em>
|
||||
},
|
||||
"t": <em><transaction-id (string)></em>,
|
||||
"y": "q",
|
||||
|
@ -259,6 +264,11 @@ verification failure if a bencoding serializer alters the order of entries in th
|
|||
<li>hash the concatenated string with SHA-1</li>
|
||||
<li>sign or verify the hash digest.</li>
|
||||
</ol>
|
||||
<p>On the storage node, the signature MUST be verified before accepting the store command. The data
|
||||
MUST be stored under the SHA-1 hash of the public key (as it appears in the bencoded dict).</p>
|
||||
<p>On the subscribing nodes, the key they get back from a <tt class="docutils literal">get</tt> request MUST be verified to hash
|
||||
to the target ID the lookup was made for, as well as verifying the signature. If any of these fail,
|
||||
the response SHOULD be considered invalid.</p>
|
||||
</div>
|
||||
<div class="section" id="expiration">
|
||||
<h1>expiration</h1>
|
||||
|
|
|
@ -44,16 +44,23 @@ network.
|
|||
The ``token`` field also has the same semantics as the standard DHT message ``get_peers``
|
||||
and ``announce_peer``, when requesting an item and to write an item respectively.
|
||||
|
||||
The ``k`` field is the PKCS#1 encoded 2048 bit RSA public key, which the signature
|
||||
can be authenticated with. When looking up a mutable item, the ``target`` field
|
||||
MUST be the SHA-1 hash of this key.
|
||||
|
||||
The distinction between storing mutable and immutable items is the inclusion
|
||||
of a public key, a sequence number and signature (``k``, ``seq`` and ``sig``).
|
||||
The distinction betwewn retrieving a mutable and immutable item is the inclusion of
|
||||
the public key spill-over (``k``) in the ``get`` request.
|
||||
|
||||
The ``v`` key is the *value* to be stored. It is allowed to be any bencoded type (list,
|
||||
``get`` requests for mutable items and immutable items cannot be distinguished from
|
||||
eachother. An implementation can either store mutable and immutable items in the same
|
||||
hash table internally, or in separate ones and potentially do two lookups for ``get``
|
||||
requests.
|
||||
|
||||
The ``v`` field is the *value* to be stored. It is allowed to be any bencoded type (list,
|
||||
dict, string or integer). When it's being hashed (for verifying its signature or to calculate
|
||||
its key), its flattened, bencoded, form is used.
|
||||
|
||||
Storing nodes are SHOULD reject ``put`` requests where the bencoded form of ``v`` is longer
|
||||
Storing nodes SHOULD reject ``put`` requests where the bencoded form of ``v`` is longer
|
||||
than 767 bytes.
|
||||
|
||||
immutable items
|
||||
|
@ -131,7 +138,8 @@ mutable items
|
|||
|
||||
Mutable items can be updated, without changing their DHT keys. To authenticate
|
||||
that only the original publisher can update an item, it is signed by a private key
|
||||
generated by the original publisher.
|
||||
generated by the original publisher. The target ID mutable items are stored under
|
||||
is the SHA-1 hash of the public key (as it appears in the ``put`` message).
|
||||
|
||||
In order to avoid a malicious node to overwrite the list head with an old
|
||||
version, the sequence number ``seq`` must be monotonically increasing for each update,
|
||||
|
@ -152,7 +160,7 @@ Request:
|
|||
"a":
|
||||
{
|
||||
"id": *<20 byte id of sending node (string)>*,
|
||||
"k": *<RSA-2048 public key (268 bytes string)>*,
|
||||
"k": *<RSA-2048 public key (PKCS#1 encoded)>*,
|
||||
"seq": *<monotonically increasing sequence number (integer)>*,
|
||||
"sig": *<RSA-2048 signature (256 bytes string)>*,
|
||||
"token": *<write-token (string)>*,
|
||||
|
@ -187,8 +195,7 @@ Request:
|
|||
"a":
|
||||
{
|
||||
"id": *<20 byte id of sending node (string)>*,
|
||||
"target:" *<first 20 bytes of public key (string)>*,
|
||||
"k": *<remaining 248 bytes of public key (string)>*
|
||||
"target:" *<20 byte SHA-1 hash of public key (string)>*
|
||||
},
|
||||
"t": *<transaction-id (string)>*,
|
||||
"y": "q",
|
||||
|
@ -230,6 +237,13 @@ value and sequence number should be done as follows:
|
|||
3. hash the concatenated string with SHA-1
|
||||
4. sign or verify the hash digest.
|
||||
|
||||
On the storage node, the signature MUST be verified before accepting the store command. The data
|
||||
MUST be stored under the SHA-1 hash of the public key (as it appears in the bencoded dict).
|
||||
|
||||
On the subscribing nodes, the key they get back from a ``get`` request MUST be verified to hash
|
||||
to the target ID the lookup was made for, as well as verifying the signature. If any of these fail,
|
||||
the response SHOULD be considered invalid.
|
||||
|
||||
expiration
|
||||
----------
|
||||
|
||||
|
|
|
@ -131,14 +131,15 @@ struct dht_immutable_item
|
|||
int size;
|
||||
};
|
||||
|
||||
struct rsa_key { char bytes[268]; };
|
||||
|
||||
struct dht_mutable_item : dht_immutable_item
|
||||
{
|
||||
char sig[256];
|
||||
int seq;
|
||||
rsa_key key;
|
||||
};
|
||||
|
||||
struct rsa_key { char bytes[268]; };
|
||||
|
||||
inline bool operator<(rsa_key const& lhs, rsa_key const& rhs)
|
||||
{
|
||||
return memcmp(lhs.bytes, rhs.bytes, sizeof(lhs.bytes)) < 0;
|
||||
|
@ -184,7 +185,7 @@ class TORRENT_EXTRA_EXPORT node_impl : boost::noncopyable
|
|||
{
|
||||
typedef std::map<node_id, torrent_entry> table_t;
|
||||
typedef std::map<node_id, dht_immutable_item> dht_immutable_table_t;
|
||||
typedef std::map<rsa_key, dht_mutable_item> dht_mutable_table_t;
|
||||
typedef std::map<node_id, dht_mutable_item> dht_mutable_table_t;
|
||||
|
||||
public:
|
||||
node_impl(alert_dispatcher* alert_disp, udp_socket_interface* sock
|
||||
|
|
|
@ -891,8 +891,7 @@ void node_impl::incoming_request(msg const& m, entry& e)
|
|||
return;
|
||||
#endif
|
||||
|
||||
rsa_key target;
|
||||
memcpy(target.bytes, msg_keys[3]->string_ptr(), sizeof(target.bytes));
|
||||
sha1_hash target = hasher(msg_keys[3]->string_ptr(), msg_keys[3]->string_length()).final();
|
||||
dht_mutable_table_t::iterator i = m_mutable_table.find(target);
|
||||
if (i == m_mutable_table.end())
|
||||
{
|
||||
|
@ -916,6 +915,7 @@ void node_impl::incoming_request(msg const& m, entry& e)
|
|||
memcpy(to_add.sig, msg_keys[4]->string_ptr(), sizeof(to_add.sig));
|
||||
TORRENT_ASSERT(sizeof(to_add.sig) == msg_keys[4]->string_length());
|
||||
memcpy(to_add.value, buf.first, buf.second);
|
||||
memcpy(&to_add.key, msg_keys[3]->string_ptr(), sizeof(to_add.key));
|
||||
|
||||
boost::tie(i, boost::tuples::ignore) = m_mutable_table.insert(
|
||||
std::make_pair(target, to_add));
|
||||
|
@ -967,14 +967,13 @@ void node_impl::incoming_request(msg const& m, entry& e)
|
|||
{
|
||||
key_desc_t msg_desc[] = {
|
||||
{"target", lazy_entry::string_t, 20, 0},
|
||||
{"k", lazy_entry::string_t, 268-20, key_desc_t::optional},
|
||||
};
|
||||
|
||||
// k is not used for now
|
||||
|
||||
// attempt to parse the message
|
||||
lazy_entry const* msg_keys[2];
|
||||
if (!verify_message(arg_ent, msg_desc, msg_keys, 2, error_string, sizeof(error_string)))
|
||||
lazy_entry const* msg_keys[1];
|
||||
if (!verify_message(arg_ent, msg_desc, msg_keys, 1, error_string, sizeof(error_string)))
|
||||
{
|
||||
incoming_error(e, error_string);
|
||||
return;
|
||||
|
@ -993,27 +992,22 @@ void node_impl::incoming_request(msg const& m, entry& e)
|
|||
m_table.find_node(target, n, 0);
|
||||
write_nodes_entry(reply, n);
|
||||
|
||||
if (msg_keys[1])
|
||||
dht_immutable_table_t::iterator i = m_immutable_table.find(target);
|
||||
if (i != m_immutable_table.end())
|
||||
{
|
||||
rsa_key key;
|
||||
memcpy(key.bytes, msg_keys[0]->string_ptr(), 20);
|
||||
memcpy(key.bytes + 20, msg_keys[1]->string_ptr(), 268-20);
|
||||
dht_mutable_table_t::iterator i = m_mutable_table.find(key);
|
||||
dht_immutable_item const& f = i->second;
|
||||
reply["v"] = bdecode(f.value, f.value + f.size);
|
||||
}
|
||||
else
|
||||
{
|
||||
dht_mutable_table_t::iterator i = m_mutable_table.find(target);
|
||||
if (i != m_mutable_table.end())
|
||||
{
|
||||
dht_mutable_item const& f = i->second;
|
||||
reply["v"] = bdecode(f.value, f.value + f.size);
|
||||
reply["seq"] = f.seq;
|
||||
reply["sig"] = std::string(f.sig, f.sig + 256);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dht_immutable_table_t::iterator i = m_immutable_table.find(target);
|
||||
if (i != m_immutable_table.end())
|
||||
{
|
||||
dht_immutable_item const& f = i->second;
|
||||
reply["v"] = bdecode(f.value, f.value + f.size);
|
||||
reply["k"] = std::string(f.key.bytes, f.key.bytes + sizeof(f.key.bytes));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue