From c3a3e540d70107d6e2f7af54b15f4359514cbdaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anton=20Luka=20=C5=A0ijanec?= Date: Tue, 6 Dec 2022 13:29:24 +0100 Subject: =?UTF-8?q?delo=20v=20=C5=A1oli?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/dht.c | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/dht.c b/src/dht.c index b1b1fa4..b4b3cbf 100644 --- a/src/dht.c +++ b/src/dht.c @@ -754,6 +754,8 @@ int bucket_good (const struct dht * d, const struct bucket * b) { /** * when we are sure that a node exists on a specific ip:port and we know it's port, but we are unsure if the node is already in the routing table, we call this function, which makes a query to this node if it's a candidate for filling the routing table. this doesn't yet add it to the routing table, because we are unsure if it's a good node / can respond to queries. replied() is called if a node replied to our query. * + * see NOTE02 + * * @param d [in] library handle * @param a [in] pointer to sockaddr of the node * @param id [in] id of the node, 20 bytes is read from this address @@ -1110,31 +1112,35 @@ void handle (struct dht * d, char * pkt, int len, struct sockaddr_in6 addr) { break; } break; - case 'R': + case 'R': // we only ever query and expect responses to get_peers and find_node, so it's egal case 'r': struct bencoding * rid = bpath(b, "r/id"); if (rid && rid->type & string && rid->valuelen == 20) replied(d, rid->value, &addr); // since here I'm only really interested about nodes and values struct bencoding * t = bpath(b, "t"); - if (!(t && t->type & string && t->valuelen == 20)) - break; - if (!(torrent = find_torrent(d, t->value))) - break; - if (!torrent->type) // yeet, l33t haxx0r tried to announce a torrent by sending a crafted response to a ficticios get_peers query - break; // this could enable the DHT node to be used as a DDoS spreader. uninterested torrents can't be updated this way - bforeach (bpath(b, "r/values"), p) { - if (!(p->type & string) || (p->valuelen != 6 && p->valuelen != 18)) - break; - struct peer * peer = calloc(1, sizeof *peer); - memcpy(peer->addr.sin6_addr, "\0\0\0\0\0\0\0\0\0\0\0\0\xFF\xFF\xFF\xFF", 12); - peer->addr.sin6_port = *((uint16_t *) (peer->value + peer->valuelen-2)); - memcpy(peer->addr.sin6_addr+(p->valuelen == 6 ? 8 : 0), p->valuelen == 6 ? 4 : 16); - add_peer(d, torrent, peer); - } + struct torrent * torrent = NULL; + if ((t && t->type & string && t->valuelen == 20) && (torrent = find_torrent(d, t->value)) && torrent->type) + bforeach (bpath(b, "r/values"), p) { + if (!(p->type & string) || (p->valuelen != 6 && p->valuelen != 18)) + break; + struct peer * peer = calloc(1, sizeof *peer); + memcpy(peer->addr.sin6_addr, "\0\0\0\0\0\0\0\0\0\0\0\0\xFF\xFF\xFF\xFF", 12); + peer->addr.sin6_port = *((uint16_t *) (p->value + p->valuelen-2)); + memcpy(peer->addr.sin6_addr+(p->valuelen == 6 ? 8 : 0), p->value, p->valuelen == 6 ? 4 : 16); + add_peer(d, torrent, peer); + } bforeach (bpath(b, "r/nodes" /* haha subreddit */), n) { if (!(n->type & string) || (n->valuelen != 4+2+20 && n->valuelen != 16+2+20)) break; - // TODO nodes and nodes6 + struct node * node = node_init(); + memcpy(node->addr.sin6_addr, "\0\0\0\0\0\0\0\0\0\0\0\0\xFF\xFF\xFF\xFF", 12); + node->addr.sin6_port = *((uint16_t *) (n->value + n->valuelen-2)); + memcpy(node->addr.sin6_addr+(n->valuelen == 4+2+20 ? 8 : 0), n->value + 20, n->valuelen == 4+2+20 ? 4 : 16); + memcpy(node->id, n->value, 20); + potential_node(d, &node->addr, id); // NOTE02 this is quite important and means that at the beginning, a lot of packets will be sent, since every reply of potential_node will generate K replies. naively this would generate an exponentially increasing number of packets, in increasing powers of 8 (8**n). to prevent an absolute resource hog, this is only done when node would be useful and would contribute to the routing table + if (torrent) + else + node_free(node); } case 'E': case 'e': -- cgit v1.2.3