2 Copyright (c) 2009-2011 by Juliusz Chroboczek
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 #include <netinet/in.h>
32 #include <sys/resource.h>
33 #include <sys/socket.h>
37 #define MIN(x, y) ((x) <= (y) ? (x) : (y))
44 #define ANNOUNCE_PEER 5
49 static const unsigned char zeroes[20] = {0};
50 static const unsigned char v4prefix[16] =
51 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0};
53 static unsigned char myid[20];
54 static unsigned char my_v[9];
56 static int dht_socket = -1;
57 static int dht_socket6 = -1;
60 unsigned char id[160];
61 struct sockaddr_storage ss;
65 #define CIRCULAR_LIST_SIZE 256
67 struct circular_list {
70 struct node nodes[CIRCULAR_LIST_SIZE];
73 static struct circular_list v4_new, v6_new, v4_confirmed, v6_confirmed;
75 #define MAX_TOKEN_BUCKET_TOKENS 40
76 static time_t token_bucket_time;
77 static int token_bucket_tokens;
79 static int verbose = 1;
81 // ------------------------ >8 ------------------------
84 getAddr(const struct sockaddr *sa, const size_t saLen)
86 static char host[NI_MAXHOST];
87 static char port[NI_MAXSERV];
96 NI_NUMERICHOST | NI_NUMERICSERV);
98 fprintf(stderr, "getnameinfo: %s\n", gai_strerror(rc));
101 snprintf(addr, sizeof addr, "[%s]:%s", host, port);
107 const unsigned char *buf,
109 unsigned char *tid_return,
111 unsigned char *id_return,
112 unsigned char *info_hash_return,
113 unsigned char *target_return,
114 unsigned short *port_return,
115 unsigned char *token_return,
117 unsigned char *nodes_return,
119 unsigned char *nodes6_return,
121 unsigned char *values_return,
123 unsigned char *values6_return,
126 const struct sockaddr *sa,
129 const unsigned char *p;
131 /* This code will happily crash if the buffer is not NUL-terminated. */
132 if (buf[buflen] != '\0') {
134 printf("%s : parse_message with unterminated buffer\n", getAddr(sa, saLen));
138 #define CHECK(ptr, len) \
139 if (((unsigned char *)ptr) + (len) > (buf) + (buflen)) \
143 p = memmem(buf, buflen, "1:t", 3);
147 l = strtol((char *)p + 3, &q, 10);
148 if (q && *q == ':' && l > 0 && l < *tid_len) {
150 memcpy(tid_return, q + 1, l);
157 p = memmem(buf, buflen, "2:id20:", 7);
160 memcpy(id_return, p + 7, 20);
162 memset(id_return, 0, 20);
165 if (info_hash_return) {
166 p = memmem(buf, buflen, "9:info_hash20:", 14);
169 memcpy(info_hash_return, p + 14, 20);
171 memset(info_hash_return, 0, 20);
175 p = memmem(buf, buflen, "porti", 5);
179 l = strtol((char *)p + 5, &q, 10);
180 if (q && *q == 'e' && l > 0 && l < 0x10000)
188 p = memmem(buf, buflen, "6:target20:", 11);
191 memcpy(target_return, p + 11, 20);
193 memset(target_return, 0, 20);
197 p = memmem(buf, buflen, "5:token", 7);
201 l = strtol((char *)p + 7, &q, 10);
202 if (q && *q == ':' && l > 0 && l < *token_len) {
204 memcpy(token_return, q + 1, l);
213 p = memmem(buf, buflen, "5:nodes", 7);
217 l = strtol((char *)p + 7, &q, 10);
218 if (q && *q == ':' && l > 0 && l < *nodes_len) {
220 memcpy(nodes_return, q + 1, l);
229 p = memmem(buf, buflen, "6:nodes6", 8);
233 l = strtol((char *)p + 8, &q, 10);
234 if (q && *q == ':' && l > 0 && l < *nodes6_len) {
236 memcpy(nodes6_return, q + 1, l);
244 if (values_len || values6_len) {
245 p = memmem(buf, buflen, "6:valuesl", 9);
252 l = strtol((char *)buf + i, &q, 10);
253 if (q && *q == ':' && l > 0) {
256 if (j + l > *values_len)
258 i = q + 1 + l - (char *)buf;
259 memcpy((char *)values_return + j, q + 1, l);
261 } else if (l == 18) {
262 if (j6 + l > *values6_len)
264 i = q + 1 + l - (char *)buf;
265 memcpy((char *)values6_return + j6, q + 1, l);
270 "%s : received weird value: %d bytes\n",
273 i = q + 1 + l - (char *)buf;
279 if (i >= buflen || buf[i] != 'e')
281 printf("%s : unexpected end for values\n", getAddr(sa, saLen));
293 p = memmem(buf, buflen, "4:wantl", 7);
297 while (buf[i] > '0' && buf[i] <= '9' && buf[i + 1] == ':' &&
298 i + 2 + buf[i] - '0' < buflen) {
299 CHECK(buf + i + 2, buf[i] - '0');
300 if (buf[i] == '2' && memcmp(buf + i + 2, "n4", 2) == 0)
301 *want_return |= WANT4;
302 else if (buf[i] == '2' && memcmp(buf + i + 2, "n6", 2) == 0)
303 *want_return |= WANT6;
306 "%s : unexpected want flag: %c\n", getAddr(sa, saLen), buf[i]);
307 i += 2 + buf[i] - '0';
309 if (i >= buflen || buf[i] != 'e')
311 printf("%s : unexpected end for want\n", getAddr(sa, saLen));
319 if (memmem(buf, buflen, "1:y1:r", 6))
321 if (memmem(buf, buflen, "1:y1:e", 6))
323 if (!memmem(buf, buflen, "1:y1:q", 6))
325 if (memmem(buf, buflen, "1:q4:ping", 9))
327 if (memmem(buf, buflen, "1:q9:find_node", 14))
329 if (memmem(buf, buflen, "1:q9:get_peers", 14))
331 if (memmem(buf, buflen, "1:q13:announce_peer", 19))
332 return ANNOUNCE_PEER;
337 printf(": truncated message\n");
346 /* We could use a proper bencoding printer and parser, but the format of
347 DHT messages is fairly stylised, so this seemed simpler. */
349 #define CHECK(offset, delta, size) \
350 if (delta < 0 || offset + delta > size) \
353 #define INC(offset, delta, size) \
354 CHECK(offset, delta, size); \
357 #define COPY(buf, offset, src, delta, size) \
358 CHECK(offset, delta, size); \
359 memcpy(buf + offset, src, delta); \
362 #define ADD_V(buf, offset, size) COPY(buf, offset, my_v, (sizeof my_v), size)
365 is_martian(struct sockaddr *sa)
367 switch (sa->sa_family) {
369 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
370 const unsigned char *address = (const unsigned char *)&sin->sin_addr;
371 return sin->sin_port == 0 || (address[0] == 0) || (address[0] == 127) ||
372 ((address[0] & 0xE0) == 0xE0);
375 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
376 const unsigned char *address = (const unsigned char *)&sin6->sin6_addr;
377 return sin6->sin6_port == 0 || (address[0] == 0xFF) ||
378 (address[0] == 0xFE && (address[1] & 0xC0) == 0x80) ||
379 (memcmp(address, zeroes, 15) == 0 &&
380 (address[15] == 0 || address[15] == 1)) ||
381 (memcmp(address, v4prefix, 12) == 0);
389 /* Forget about the ``XOR-metric''. An id is just a path from the
390 root of the tree, so bits are numbered from the start. */
393 id_cmp(const unsigned char *restrict id1, const unsigned char *restrict id2)
395 /* Memcmp is guaranteed to perform an unsigned comparison. */
396 return memcmp(id1, id2, 20);
399 /* Our transaction-ids are 4-bytes long, with the first two bytes identi-
400 fying the kind of request, and the remaining two a sequence number in
404 make_tid(unsigned char *tid_return, const char *prefix, unsigned short seqno)
406 tid_return[0] = prefix[0] & 0xFF;
407 tid_return[1] = prefix[1] & 0xFF;
408 memcpy(tid_return + 2, &seqno, 2);
412 tid_match(const unsigned char *tid, const char *prefix, unsigned short *seqno_return)
414 if (tid[0] == (prefix[0] & 0xFF) && tid[1] == (prefix[1] & 0xFF)) {
416 memcpy(seqno_return, tid + 2, 2);
423 circular(int from, int to)
427 return x + CIRCULAR_LIST_SIZE;
432 list_elements(struct circular_list *list)
434 return circular(list->head, list->tail);
438 list_empty(struct circular_list *list)
440 return list_elements(list) == 0;
444 list_free(struct circular_list *list)
446 return circular(list->tail + 1, list->head);
450 list_pop(struct circular_list *list, struct sockaddr_storage *ss, socklen_t *sslen)
452 if (list->head == list->tail)
455 memcpy(ss, &list->nodes[list->head].ss, list->nodes[list->head].sslen);
456 *sslen = list->nodes[list->head].sslen;
457 list->head = (list->head + 1) % CIRCULAR_LIST_SIZE;
463 struct circular_list *list,
465 struct sockaddr_storage *ss,
468 if (list->head == list->tail)
471 int n = random() % (list->tail - list->head);
472 n = (list->head + n) % CIRCULAR_LIST_SIZE;
475 memcpy(id, &list->nodes[n].id, 20);
476 memcpy(ss, &list->nodes[n].ss, list->nodes[n].sslen);
477 *sslen = list->nodes[n].sslen;
481 /* We just learnt about a node, not necessarily a new one. Confirm is 1 if
482 the node sent a message, 2 if it sent us a reply. */
485 new_node(unsigned char *id, struct sockaddr *sa, socklen_t salen, int confirm)
487 struct circular_list *list;
488 if (sa->sa_family == AF_INET)
489 list = confirm >= 2 ? &v4_confirmed : &v4_new;
490 else if (sa->sa_family == AF_INET6)
491 list = confirm >= 2 ? &v6_confirmed : &v6_new;
495 /* A node that sends us a request is most probably bootstrapping.
496 We want to avoid getting our tables full of very young nodes -- only
497 include such a node if we have plenty of space. */
499 if (confirm == 1 && list_free(list) < 32)
502 for (int i = list->head; i != list->tail; i = (i + 1) % CIRCULAR_LIST_SIZE) {
503 struct node *n = &list->nodes[i];
504 if (n->sslen == salen && memcmp(&n->ss, sa, salen) == 0)
508 memcpy(&list->nodes[list->tail].id, id, 160);
509 memcpy(&list->nodes[list->tail].ss, sa, salen);
510 list->nodes[list->tail].sslen = salen;
511 list->tail = (list->tail + 1) % CIRCULAR_LIST_SIZE;
512 if (list->head == list->tail)
513 list->head = (list->head + 1) % CIRCULAR_LIST_SIZE;
515 printf("%s : new node\n", getAddr(sa, salen));
523 time_t now = time(NULL);
524 if (token_bucket_tokens == 0) {
525 token_bucket_tokens =
526 MIN(MAX_TOKEN_BUCKET_TOKENS, 4 * (now - token_bucket_time));
527 token_bucket_time = now;
529 if (token_bucket_tokens == 0)
531 token_bucket_tokens--;
536 dht_send(const void *buf, size_t len, int flags, const struct sockaddr *sa, int salen)
541 if (sa->sa_family == AF_INET)
543 else if (sa->sa_family == AF_INET6)
548 errno = EAFNOSUPPORT;
551 return sendto(s, buf, len, flags, sa, salen);
555 send_ping(struct sockaddr *sa, int salen, const unsigned char *tid, int tid_len)
559 rc = snprintf(buf + i, 512 - i, "d1:ad2:id20:");
561 COPY(buf, i, myid, 20, 512);
562 rc = snprintf(buf + i, 512 - i, "e1:q4:ping1:t%d:", tid_len);
564 COPY(buf, i, tid, tid_len, 512);
566 rc = snprintf(buf + i, 512 - i, "1:y1:qe");
569 printf("%s <- PING\n", getAddr(sa, salen));
570 return dht_send(buf, i, 0, sa, salen);
578 send_pong(struct sockaddr *sa, int salen, const unsigned char *tid, int tid_len)
582 int rc = snprintf(buf + i, 512 - i, "d1:rd2:id20:");
584 COPY(buf, i, myid, 20, 512);
585 rc = snprintf(buf + i, 512 - i, "e1:t%d:", tid_len);
587 COPY(buf, i, tid, tid_len, 512);
589 rc = snprintf(buf + i, 512 - i, "1:y1:re");
592 printf("%s <- PONG\n", getAddr(sa, salen));
593 return dht_send(buf, i, 0, sa, salen);
604 const unsigned char *tid,
606 const unsigned char *target,
611 int rc = snprintf(buf + i, 512 - i, "d1:ad2:id20:");
613 COPY(buf, i, myid, 20, 512);
614 rc = snprintf(buf + i, 512 - i, "6:target20:");
616 COPY(buf, i, target, 20, 512);
622 (want & WANT4) ? "2:n4" : "",
623 (want & WANT6) ? "2:n6" : "");
626 rc = snprintf(buf + i, 512 - i, "e1:q9:find_node1:t%d:", tid_len);
628 COPY(buf, i, tid, tid_len, 512);
630 rc = snprintf(buf + i, 512 - i, "1:y1:qe");
633 printf("%s <- FIND_NODE\n", getAddr(sa, salen));
634 return dht_send(buf, i, 0, sa, salen);
642 send_request(struct circular_list *list, int dopop, int doping, int want)
644 if (list_empty(list))
647 struct sockaddr_storage ss;
651 rc = list_pop(list, &ss, &sslen);
655 rc = list_random(list, NULL, &ss, &sslen);
660 unsigned char ttid[4];
662 make_tid(ttid, "pn", 0);
663 return send_ping((struct sockaddr *)&ss, sslen, ttid, 4);
665 unsigned char id[20];
666 arc4random_buf(id, sizeof id);
667 make_tid(ttid, "fn", 0);
668 return send_find_node((struct sockaddr *)&ss, sslen, ttid, 4, id, want);
673 newSock(const char *host, const char *port)
675 struct addrinfo hints;
676 memset(&hints, 0, sizeof(hints));
677 hints.ai_family = AF_UNSPEC;
678 hints.ai_socktype = SOCK_DGRAM;
679 struct addrinfo *res = NULL;
680 int rc = getaddrinfo(host, port, &hints, &res);
682 err(EXIT_FAILURE, "getaddrinfo: %s\n", gai_strerror(rc));
683 int sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
685 err(EXIT_FAILURE, "socket()");
686 if (bind(sock, res->ai_addr, res->ai_addrlen) != 0)
687 err(EXIT_FAILURE, "bind()");
688 rc = fcntl(sock, F_GETFL, 0);
690 err(EXIT_FAILURE, "F_GETFL");
691 rc = fcntl(sock, F_SETFL, (rc | O_NONBLOCK));
693 err(EXIT_FAILURE, "F_SETFL");
704 if (setrlimit(res, &r) == -1) {
705 err(EXIT_FAILURE, "can not setrlimit()");
713 const unsigned char *tid,
715 const unsigned char *nodes,
717 const unsigned char *nodes6,
722 int rc = snprintf(buf + i, 2048 - i, "d1:rd2:id20:");
724 COPY(buf, i, myid, 20, 2048);
726 rc = snprintf(buf + i, 2048 - i, "5:nodes%d:", nodes_len);
728 COPY(buf, i, nodes, nodes_len, 2048);
730 if (nodes6_len > 0) {
731 rc = snprintf(buf + i, 2048 - i, "6:nodes6%d:", nodes6_len);
733 COPY(buf, i, nodes6, nodes6_len, 2048);
735 rc = snprintf(buf + i, 2048 - i, "e1:t%d:", tid_len);
737 COPY(buf, i, tid, tid_len, 2048);
739 rc = snprintf(buf + i, 2048 - i, "1:y1:re");
741 return dht_send(buf, i, 0, sa, salen);
749 buffer_random_nodes(int af, unsigned char *nodes)
751 struct circular_list *list;
754 list = &v4_confirmed;
757 list = &v6_confirmed;
763 struct sockaddr_storage ss;
765 unsigned char id[20];
769 rc = list_random(list, id, &ss, &sslen);
774 struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
775 memcpy(nodes + n * 26, id, 20);
776 memcpy(nodes + n * 26 + 20, &sin->sin_addr, 4);
777 memcpy(nodes + n * 26 + 24, &sin->sin_port, 2);
782 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
783 memcpy(nodes + n * 38, id, 20);
784 memcpy(nodes + n * 38 + 20, &sin6->sin6_addr, 16);
785 memcpy(nodes + n * 38 + 36, &sin6->sin6_port, 2);
800 const unsigned char *tid,
804 unsigned char nodes[8 * 26];
805 unsigned char nodes6[8 * 38];
809 want = sa->sa_family == AF_INET ? WANT4 : WANT6;
811 numnodes = buffer_random_nodes(AF_INET, nodes);
813 numnodes6 = buffer_random_nodes(AF_INET6, nodes6);
815 printf("%s <- NODES (%d+%d)\n", getAddr(sa, salen), numnodes, numnodes6);
817 sa, salen, tid, tid_len, nodes, numnodes * 26, nodes6, numnodes6 * 38);
831 int rc = snprintf(buf + i, 512 - i, "d1:eli%de%d:", code, (int)strlen(message));
833 COPY(buf, i, message, (int)strlen(message), 512);
834 rc = snprintf(buf + i, 512 - i, "e1:t%d:", tid_len);
836 COPY(buf, i, tid, tid_len, 512);
838 rc = snprintf(buf + i, 512 - i, "1:y1:ee");
840 return dht_send(buf, i, 0, sa, salen);
848 main(int argc, char **argv)
851 char *ipv4addr = NULL;
852 char *ipv6addr = NULL;
856 opt = getopt(argc, argv, "q4:6:");
865 ipv4addr = strdup(optarg);
868 ipv6addr = strdup(optarg);
880 const char *ourPort = strdup(argv[i++]);
881 if (ipv4addr != NULL) {
882 dht_socket = newSock(ipv4addr, ourPort);
884 if (ipv6addr != NULL) {
885 dht_socket6 = newSock(ipv6addr, ourPort);
888 arc4random_buf(myid, sizeof myid);
889 memcpy(my_v, "1:v4:JB\0\0", 9);
892 unsigned char ttid[4];
895 struct addrinfo hints, *info, *infop;
896 memset(&hints, 0, sizeof(hints));
897 hints.ai_socktype = SOCK_DGRAM;
900 hints.ai_family = AF_INET6;
901 else if (dht_socket6 < 0)
902 hints.ai_family |= AF_INET;
903 rc = getaddrinfo(argv[i], argv[i + 1], &hints, &info);
905 err(EXIT_FAILURE, "getaddrinfo: %s\n", gai_strerror(rc));
913 make_tid(ttid, "pn", 0);
914 send_ping(infop->ai_addr, infop->ai_addrlen, ttid, 4);
915 infop = infop->ai_next;
922 token_bucket_time = time(NULL);
923 token_bucket_tokens = MAX_TOKEN_BUCKET_TOKENS;
925 struct pollfd fds[2];
926 fds[0].fd = dht_socket;
927 fds[0].events = POLLIN;
928 fds[1].fd = dht_socket6;
929 fds[1].events = POLLIN;
933 close(STDOUT_FILENO);
934 rlimited(RLIMIT_NPROC);
935 rlimited(RLIMIT_FSIZE);
937 rlimited(RLIMIT_NOFILE);
938 #endif // __FreeBSD__
942 if ((dht_socket >= 0 && list_elements(&v4_confirmed) <= 16) ||
943 (dht_socket6 >= 0 && list_elements(&v6_confirmed) <= 16))
946 tv_sec = random() % 30;
947 int tv_msec = random() % 1000;
952 list_elements(&v4_confirmed),
953 list_elements(&v6_confirmed),
954 list_elements(&v4_new),
955 list_elements(&v6_new));
958 rc = poll(fds, 2, tv_sec * 1000 + tv_msec);
966 unsigned char tid[16], id[20], info_hash[20], target[20];
967 unsigned char buf[1536], nodes[256], nodes6[1024], token[128];
968 int tid_len = 16, token_len = 128;
969 int nodes_len = 256, nodes6_len = 1024;
971 unsigned char values[2048], values6[2048];
972 int values_len = 2048, values6_len = 2048;
974 struct sockaddr_storage source_storage;
975 struct sockaddr *source = (struct sockaddr *)&source_storage;
976 socklen_t sourcelen = sizeof(source_storage);
977 if (fds[0].revents != 0) {
978 if ((fds[0].revents & (POLLERR | POLLNVAL)) > 0) {
979 fprintf(stderr, "error in fds[0]");
982 rc = recvfrom(dht_socket, buf, 1536, 0, source, &sourcelen);
984 } else if (fds[1].revents != 0) {
985 if ((fds[1].revents & (POLLERR | POLLNVAL)) > 0) {
986 fprintf(stderr, "error in fds[1]");
989 rc = recvfrom(dht_socket6, buf, 1536, 0, source, &sourcelen);
993 if (rc < 0 || sourcelen > sizeof(struct sockaddr_storage))
996 if (is_martian(source))
999 /* There's a bug in parse_message -- it will happily overflow the
1000 buffer if it's not NUL-terminated. For now, put a NUL at the
1007 printf("%s : overlong message\n", getAddr(source, sourcelen));
1011 message = parse_message(
1034 if (id_cmp(id, myid) == 0) {
1037 "%s : received message from self\n",
1038 getAddr(source, sourcelen));
1042 if (message > REPLY) {
1043 /* Rate limit requests. */
1044 if (!token_bucket()) {
1047 "%s : dropping request due to rate limiting.\n",
1048 getAddr(source, sourcelen));
1058 "%s : broken node truncates transaction ids\n",
1059 getAddr(source, sourcelen));
1062 if (tid_match(tid, "pn", NULL)) {
1064 printf("%s -> PONG\n", getAddr(source, sourcelen));
1065 new_node(id, source, sourcelen, 2);
1066 } else if (tid_match(tid, "fn", NULL)) {
1069 "%s -> NODES (%d+%d)\n",
1070 getAddr(source, sourcelen),
1073 if (nodes_len % 26 != 0 || nodes6_len % 38 != 0) {
1076 "%s : unexpected length for node info\n",
1077 getAddr(source, sourcelen));
1079 new_node(id, source, sourcelen, 2);
1080 for (i = 0; i < nodes_len / 26; i++) {
1081 unsigned char *ni = nodes + i * 26;
1082 struct sockaddr_in sin;
1083 if (id_cmp(ni, myid) == 0)
1085 memset(&sin, 0, sizeof(sin));
1086 sin.sin_family = AF_INET;
1087 memcpy(&sin.sin_addr, ni + 20, 4);
1088 memcpy(&sin.sin_port, ni + 24, 2);
1089 new_node(ni, (struct sockaddr *)&sin, sizeof(sin), 0);
1091 for (i = 0; i < nodes6_len / 38; i++) {
1092 unsigned char *ni = nodes6 + i * 38;
1093 struct sockaddr_in6 sin6;
1094 if (id_cmp(ni, myid) == 0)
1096 memset(&sin6, 0, sizeof(sin6));
1097 sin6.sin6_family = AF_INET6;
1098 memcpy(&sin6.sin6_addr, ni + 20, 16);
1099 memcpy(&sin6.sin6_port, ni + 36, 2);
1100 new_node(ni, (struct sockaddr *)&sin6, sizeof(sin6), 0);
1105 printf("%s : unexpected reply\n", getAddr(source, sourcelen));
1111 printf("%s -> PING (%d)\n", getAddr(source, sourcelen), tid_len);
1112 new_node(id, source, sourcelen, 1);
1113 send_pong(source, sourcelen, tid, tid_len);
1119 if (message == FIND_NODE)
1120 printf("%s -> FIND_NODE\n", getAddr(source, sourcelen));
1122 printf("%s -> GET_PEERS\n", getAddr(source, sourcelen));
1124 new_node(id, source, sourcelen, 1);
1125 send_random_nodes(source, sourcelen, tid, tid_len, want);
1129 printf("%s -> ANNOUNCE_PEER\n", getAddr(source, sourcelen));
1136 "This node doesn't accept announces");
1143 /* We need to be careful to avoid a positive feedback loop. Make
1144 sure we send at most one packet each time through the select
1147 if (dht_socket6 < 0)
1149 else if (dht_socket < 0)
1152 send4 = random() % 2;
1155 int want = dht_socket6 >= 0 && list_free(&v6_new) > 8 ? (WANT4 | WANT6) : 0;
1156 if (!list_empty(&v4_new))
1157 send_request(&v4_new, 1, list_free(&v4_new) < 8, want);
1158 else if (!list_empty(&v4_confirmed))
1159 send_request(&v4_confirmed, 0, 0, want);
1161 int want = dht_socket >= 0 && list_free(&v4_new) > 8 ? (WANT4 | WANT6) : 0;
1162 if (!list_empty(&v6_new))
1163 send_request(&v6_new, 1, list_free(&v6_new) < 8, want);
1164 else if (!list_empty(&v6_confirmed))
1165 send_request(&v6_confirmed, 0, 0, want);
1170 fprintf(stderr, "dht-bootstrap [-q] [-4 ADDR4] [-6 ADDR6] port [node port...]\n");