1
#include "dht/core/LegacyConnectorModuleInternal.h"
2
#include "dht/DHTConstants.h"
3
#include "net/NetworkTools.h"
7
* Get a bobj_t for a string.
9
* @param string a benc_bstr_t* object to wrap.
10
* @return a pointer to a bobj_t object allocated on the stack
11
* which wraps the given string.
13
#define OBJ_PTR_FOR_STRING(string) \
20
* Get a bobj_t for a dictionary.
22
* @param dictionary a benc_dict_entry_t* object to wrap.
23
* @return a bobj_t* object allocated on the stack
24
* which wraps the given dictionary.
26
#define OBJ_PTR_FOR_DICT(dictionary) \
29
.as.dict = dictionary \
32
#define STRING_OBJ(length, chars) \
35
.as.bstr = &(benc_bstr_t) { \
42
* Send a generic message.
44
* @param address the ip address of the node to ping.
45
* @param messageType the type of message,
46
* DHTDHTConstants_query or DHTDHTConstants_reply
47
* @param queryType if messageType is reply then this should be NULL,
48
* one of [ping, find_node, get_peers, announce_peer]
49
* @param transactionId a string to expect back if a query, return back if a
51
* @param argumentsKey the key to put arguments under.
52
* DHTDHTConstants_arguments or DHTDHTConstants_reply.
53
* @param arguments what will go under the "q" or "r" key.
54
* @param wantProtocols if set then additional entries will be added for ip4
56
* @return 0 if all goes well, -1 if there is an error and errno will be set.
58
static int sendMessage(struct sockaddr* address,
59
benc_bstr_t* messageType,
60
benc_bstr_t* queryType,
61
benc_bstr_t* transactionId,
62
benc_bstr_t* argumentsKey,
63
benc_dict_entry_t* arguments,
66
benc_dict_entry_t* entry = NULL;
68
if (arguments && argumentsKey) {
69
entry = &(benc_dict_entry_t) {
72
.val = OBJ_PTR_FOR_DICT(arguments)
78
entry = &(benc_dict_entry_t) {
80
.key = &DHTConstants_transactionId,
81
.val = OBJ_PTR_FOR_STRING(transactionId)
87
entry = &(benc_dict_entry_t) {
89
.key = &DHTConstants_messageType,
90
.val = OBJ_PTR_FOR_STRING(messageType)
96
entry = &(benc_dict_entry_t) {
98
.key = &DHTConstants_query,
99
.val = OBJ_PTR_FOR_STRING(queryType)
103
/* IP6 compatibility addon.
104
* Not in original specification.
105
* "want": ["n4", "n6"]
107
if (wantProtocols > 0) {
108
benc_list_entry_t* wishList = NULL;
109
if (wantProtocols & WANT4) {
110
wishList = &(benc_list_entry_t) {
112
.elem = OBJ_PTR_FOR_STRING(&DHTConstants_wantIp4)
115
if (wantProtocols & WANT6) {
116
wishList = &(benc_list_entry_t) {
118
.elem = OBJ_PTR_FOR_STRING(&DHTConstants_wantIp6)
121
if (wishList != NULL) {
122
entry = &(benc_dict_entry_t) {
124
.key = &DHTConstants_want,
133
struct DHTMessage message;
134
memset(&message, 0, sizeof(struct DHTMessage));
136
message.addressLength =
137
NetworkTools_addressFromSockaddr((struct sockaddr_storage*) address,
138
message.peerAddress);
139
if (message.addressLength < 6) {
140
/* Failed to get the sockaddr. */
145
/* The last entry in the list is considered the dictionary. */
146
message.bencoded = OBJ_PTR_FOR_DICT(entry);
148
DHTModules_handleOutgoing(&message, context->registry);
150
/* TODO register an error if one occurs. */
156
* INTERNAL Please do not use.
157
* This is used to bridge to legacy dht.
159
* Send a ping to another node.
161
* @param address the ip address of the node to ping.
162
* @param addressLength the length of the address, unused.
163
* @param transactionId a string to expect back from the node.
164
* @param transactionIdLength length of transactionId.
165
* @return 0 if all goes well, -1 if there is an error and errno will be set.
167
int send_ping(struct sockaddr *address,
169
const unsigned char *transactionId,
170
int transactionIdLength)
173
addressLength = addressLength;
175
/* We're creating this:
181
* "id":"abcdefghij0123456789"
185
* bencoded = d1:ad2:id20:abcdefghij0123456789e1:q4:ping1:t2:aa1:y1:qe
188
benc_dict_entry_t arguments = {
190
.key = &DHTConstants_myId,
191
.val = OBJ_PTR_FOR_STRING(&context->myId)
194
return sendMessage(address,
197
&(benc_bstr_t) {transactionIdLength, (char*) transactionId},
198
&DHTConstants_arguments,
204
* INTERNAL Please do not use.
205
* This is used to bridge to legacy dht.
207
* Send a pong to another node who pinged us.
209
* @param address the ip address of the node to ping.
210
* @param addressLength the length of the address, unused.
211
* @param transactionId a string to expect back from the node.
212
* @param transactionIdLength length of transactionId.
213
* @return 0 if all goes well, -1 if there is an error and errno will be set.
215
int send_pong(struct sockaddr *address,
217
const unsigned char *transactionId,
218
int transactionIdLength)
221
addressLength = addressLength;
223
/* We are creating this:
224
* Response = {"t":"aa", "y":"r", "r": {"id":"mnopqrstuvwxyz123456"}}
225
* bencoded = d1:rd2:id20:mnopqrstuvwxyz123456e1:t2:aa1:y1:re
228
benc_dict_entry_t arguments = {
230
.key = &DHTConstants_myId,
231
.val = OBJ_PTR_FOR_STRING(&context->myId)
234
return sendMessage(address,
237
&(benc_bstr_t) {transactionIdLength, (char*) transactionId},
244
* INTERNAL Please do not use.
245
* This is used to bridge to legacy dht.
247
* Send a find_node request
249
* @param address the ip address of the node to ping.
250
* @param addressLength the length of the address, unused.
251
* @param transactionId a string to expect back from the node.
252
* @param transactionIdLength length of transactionId.
253
* @param targetId the ID of the node we are looking for.
254
* @param wantProtocols do we want ip4 or ip6 or both? WANT4 = 1, WANT6 = 2
256
* @param confirm intended to tell the kernel to skip sending an arp packet
257
* before sending the udp packet. Unused as that functionality
258
* is the responsibility of the network module.
259
* @return 0 if all goes well, -1 if there is an error and errno will be set.
261
int send_find_node(struct sockaddr *address,
263
const unsigned char *transactionId,
264
int transactionIdLength,
265
const unsigned char *targetId,
270
addressLength = addressLength;
273
/* We're creating this:
274
* find_node Query = {
279
* "id":"abcdefghij0123456789",
280
* "target":"mnopqrstuvwxyz123456"
285
* d1:ad2:id20:abcdefghij01234567896:target20:mnopqrstuvwxyz123456e
286
* 1:q9:find_node1:t2:aa1:y1:qe
290
* "id":"abcdefghij0123456789",
291
* "target":"mnopqrstuvwxyz123456"
294
benc_dict_entry_t arguments = {
295
.key = &DHTConstants_myId,
296
.val = OBJ_PTR_FOR_STRING(&context->myId),
297
.next = &(benc_dict_entry_t) {
299
.key = &DHTConstants_targetId,
300
.val = STRING_OBJ(20, (char*) targetId)
304
return sendMessage(address,
306
&DHTConstants_findNode,
307
&(benc_bstr_t) {transactionIdLength, (char*) transactionId},
308
&DHTConstants_arguments,
314
* INTERNAL Please do not use.
315
* This is used to bridge to legacy dht.
317
* Send a find_node request
319
* @param address the ip address of the node to ping.
320
* @param addressLength the length of the address, unused.
321
* @param transactionId a string to expect back from the node.
322
* @param transactionIdLength length of transactionId.
323
* @param infohash the hash for the torrent which we are looking for.
324
* this will always be 20 bytes long.
325
* @param wantProtocols do we want ip4 or ip6 or both? WANT4 = 1, WANT6 = 2
327
* @param confirm intended to tell the kernel to skip sending an arp packet
328
* before sending the udp packet. Unused as that functionality
329
* is the responsibility of the network module.
330
* @return 0 if all goes well, -1 if there is an error and errno will be set.
332
int send_get_peers(struct sockaddr *address,
334
unsigned char *transactionId,
335
int transactionIdLength,
336
unsigned char *infoHash,
341
addressLength = addressLength;
344
/* We're creating this:
345
* get_peers Query = {
350
* "id":"abcdefghij0123456789",
351
* "info_hash":"mnopqrstuvwxyz123456"
356
* d1:ad2:id20:abcdefghij01234567899:info_hash20:mnopqrstuvwxyz123456e
357
* 1:q9:get_peers1:t2:aa1:y1:qe
361
* "id":"abcdefghij0123456789",
362
* "info_hash":"mnopqrstuvwxyz123456"
365
benc_dict_entry_t arguments = {
366
.key = &DHTConstants_myId,
367
.val = OBJ_PTR_FOR_STRING(&context->myId),
368
.next = &(benc_dict_entry_t) {
370
.key = &DHTConstants_infoHash,
371
.val = STRING_OBJ(20, (char*) infoHash)
375
return sendMessage(address,
377
&DHTConstants_getPeers,
378
&(benc_bstr_t) {transactionIdLength, (char*) transactionId},
379
&DHTConstants_arguments,
384
struct LegacyConnectorModule_internal_node {
385
char addressPort[18];
386
benc_list_entry_t entry;
392
* INTERNAL Please do not use.
393
* This is used to bridge to legacy dht.
395
* Respond to either a find node or a get peers request.
397
* @param address the ip address of the node to ping.
398
* @param addressLength the length of address, unused.
399
* @param transactionId a number to prevent confusion if multiple
400
* "transactions" are happening with the same peer.
401
* @param transactionIdLength length of transactionId.
402
* @param nodes a buffer containing 20 byte ids of nodes to send.
403
* @param nodesLength the length of nodes.
404
* @param nodes6 a buffer containing 20 byte ids of ip6 nodes to send.
405
* @param nodes6Length the length of nodes6.
406
* @param addressType one of AF_INET or AF_INET6, the protocol which our peer
407
* used to connect to us.
408
* @param store a storage structure for ip addresses of peers.
409
* @param token a random number which must be reflected back to us if the node
410
* announces that he has a torrent.
411
* @param tokenLength the length of token.
412
* @return 0 if all goes well, -1 if there is an error and errno will be set.
414
int send_nodes_peers(struct sockaddr *address,
416
const unsigned char *transactionId,
417
int transactionIdLength,
418
const unsigned char *nodes,
420
const unsigned char *nodes6,
423
struct storage *store,
424
const unsigned char *token,
427
addressLength = addressLength;
429
/* Might be doing any of 3 things :/
431
* if tokenLength == 0 then this is a response to a find_node
432
* else if storage == NULL then this is a response to a get_peers
433
* request but we don't know any peers so we send a node instead.
434
* else this is a response to a get_peers request and we do know
438
benc_dict_entry_t* arguments = NULL;
440
if(nodes && nodesLength > 0) {
441
arguments = &(benc_dict_entry_t) {
443
.key = &DHTConstants_nodes,
444
.val = STRING_OBJ(nodesLength, (char*) nodes)
448
if(nodes6 && nodes6Length > 0) {
449
arguments = &(benc_dict_entry_t) {
451
.key = &DHTConstants_nodes6,
452
.val = STRING_OBJ(nodes6Length, (char*) nodes6)
456
if(token && tokenLength > 0) {
457
arguments = &(benc_dict_entry_t) {
459
.key = &DHTConstants_authToken,
460
.val = STRING_OBJ(tokenLength, (char*) token)
464
if(store && store->numpeers > 0) {
465
int numPeers = store->numpeers;
466
int startingPoint = random() % numPeers;
467
int i = startingPoint;
468
int valuesReturned = 0;
469
int addrLength = (addressType == AF_INET) ? 4 : 16;
471
/* Since you can't define stack variables in a loop. Next best... */
472
struct LegacyConnectorModule_internal_node nodes[51];
473
memset(nodes, 0, sizeof(struct LegacyConnectorModule_internal_node) * 51);
474
struct LegacyConnectorModule_internal_node* node = nodes;
475
node->entry.next = NULL;
478
if (store->peers[i].len == addrLength) {
479
unsigned short bigEndianPort = htons(store->peers[i].port);
481
memcpy(node->addressPort, store->peers[i].ip, addrLength);
482
memcpy((char*) (node->addressPort + addrLength),
483
(char*) &bigEndianPort,
486
node->string.bytes = node->addressPort;
487
node->string.len = addrLength + 2;
488
node->obj.type = BENC_BSTR;
489
node->obj.as.bstr = &node->string;
490
node->entry.elem = &node->obj;
494
node->entry.next = &node[-1].entry;
496
i = (i + 1) % numPeers;
497
} while (i != startingPoint && valuesReturned < 50);
499
if (node->entry.next != NULL) {
500
arguments = &(benc_dict_entry_t) {
502
.key = &DHTConstants_values,
505
.as.list = node->entry.next
511
arguments = &(benc_dict_entry_t) {
512
.key = &DHTConstants_myId,
513
.val = OBJ_PTR_FOR_STRING(&context->myId),
517
return sendMessage(address,
520
&(benc_bstr_t) {transactionIdLength, (char*) transactionId},
527
* INTERNAL Please do not use.
528
* This is used to bridge to legacy dht.
530
* Send an announce_peer query.
532
* @param address the ip address of the node to ping.
533
* @param addressLength the length of address, unused.
534
* @param transactionId a number to prevent confusion if multiple
535
* "transactions" are happening with the same peer.
536
* @param transactionIdLength length of transactionId.
537
* @param infohash the hash for the torrent which we are looking for.
538
* this will always be 20 bytes long.
539
* @param port the port number which this node is announcing from.
540
* @param token a cookie which we use to prove that we own this ip address
541
* and we are not spoofing.
542
* @param tokenLength the length of token.
543
* @param confirm intended to tell the kernel to skip sending an arp packet
544
* before sending the udp packet. Unused as that functionality
545
* is the responsibility of the network module.
546
* @return 0 if all goes well, -1 if there is an error and errno will be set.
548
int send_announce_peer(struct sockaddr *address,
550
unsigned char *transactionId,
551
int transactionIdLength,
552
unsigned char *infoHash,
554
unsigned char *token,
559
addressLength = addressLength;
562
/* We are creating this:
563
* announce_peer Query = {
566
* "q":"announce_peer",
568
* "id":"abcdefghij0123456789",
569
* "info_hash":"mnopqrstuvwxyz123456",
571
* "token": "aoeusnth"
576
* d1:ad2:id20:abcdefghij01234567899:info_hash20:mnopqrstuvwxyz123456
577
* 4:porti6881e5:token8:aoeusnthe1:q13:announce_peer1:t2:aa1:y1:qe
580
benc_dict_entry_t* arguments = NULL;
583
arguments = &(benc_dict_entry_t) {
585
.key = &DHTConstants_infoHash,
586
.val = STRING_OBJ(20, (char*) infoHash)
590
if(token && tokenLength > 0) {
591
arguments = &(benc_dict_entry_t) {
593
.key = &DHTConstants_authToken,
594
.val = STRING_OBJ(tokenLength, (char*) token)
598
arguments = &(benc_dict_entry_t) {
600
.key = &DHTConstants_myId,
601
.val = OBJ_PTR_FOR_STRING(&context->myId)
604
arguments = &(benc_dict_entry_t) {
606
.key = &DHTConstants_port,
613
return sendMessage(address,
615
&DHTConstants_announcePeer,
616
&(benc_bstr_t) {transactionIdLength, (char*) transactionId},
617
&DHTConstants_arguments,
623
* INTERNAL Please do not use.
624
* This is used to bridge to legacy dht.
626
* Send a response to an announce_peer query.
628
* @param address the ip address of the node to ping.
629
* @param addressLength the length of address, unused.
630
* @param transactionId a number to prevent confusion if multiple
631
* "transactions" are happening with the same peer.
632
* @param transactionIdLength length of transactionId.
633
* @return 0 if all goes well, -1 if there is an error and errno will be set.
635
int send_peer_announced(struct sockaddr *address,
637
unsigned char *transactionId,
638
int transactionIdLength)
641
addressLength = addressLength;
643
/* We are creating this:
648
* "id":"mnopqrstuvwxyz123456"
652
* bencoded = d1:rd2:id20:mnopqrstuvwxyz123456e1:t2:aa1:y1:re
655
benc_dict_entry_t* arguments = &(benc_dict_entry_t) {
657
.key = &DHTConstants_myId,
658
.val = OBJ_PTR_FOR_STRING(&context->myId)
661
return sendMessage(address,
664
&(benc_bstr_t) {transactionIdLength, (char*) transactionId},
670
int send_error(struct sockaddr *address,
672
unsigned char *transactionId,
673
int transactionIdLength,
675
const char *errorMessage)
678
addressLength = addressLength;
680
/* We are creating this:
686
* "A Generic Error Ocurred"
690
* bencoded = d1:eli201e23:A Generic Error Ocurrede1:t2:aa1:y1:ee
693
benc_dict_entry_t* entry = NULL;
696
if (transactionId && transactionIdLength > 0) {
697
entry = &(benc_dict_entry_t) {
699
.key = &DHTConstants_transactionId,
700
.val = STRING_OBJ(transactionIdLength, (char*) transactionId)
705
entry = &(benc_dict_entry_t) {
707
.key = &DHTConstants_messageType,
708
.val = OBJ_PTR_FOR_STRING(&DHTConstants_error)
711
/* "e": [201, "A Generic Error Ocurred"] */
712
entry = &(benc_dict_entry_t) {
714
.key = &DHTConstants_error,
717
.as.list = &(benc_list_entry_t) {
718
.elem = &(bobj_t) { .type = BENC_INT, .as.int_ = code },
719
.next = &(benc_list_entry_t) {
720
.elem = STRING_OBJ(strlen(errorMessage), (char*) errorMessage),
727
struct DHTMessage message;
728
memset(&message, 0, sizeof(struct DHTMessage));
730
message.addressLength =
731
NetworkTools_addressFromSockaddr((struct sockaddr_storage*) address,
732
message.peerAddress);
733
if (message.addressLength < 6) {
734
/* Failed to get the sockaddr. */
738
/* The last entry in the list is considered the dictionary. */
739
message.bencoded = OBJ_PTR_FOR_DICT(entry);
741
DHTModules_handleOutgoing(&message, context->registry);
743
/* TODO register an error if one occurs. */
748
#undef OBJ_PTR_FOR_STRING
749
#undef OBJ_PTR_FOR_DICT