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
26 #include <netinet/in.h>
32 #include <sys/socket.h>
36 #define MIN(x, y) ((x) <= (y) ? (x) : (y))
39 send_ping(struct sockaddr *sa, int salen, const unsigned char *tid, int tid_len);
41 send_pong(struct sockaddr *sa, int salen, const unsigned char *tid, int tid_len);
46 const unsigned char *tid,
48 const unsigned char *target,
54 const unsigned char *tid,
56 const unsigned char *nodes,
58 const unsigned char *nodes6,
64 const unsigned char *tid,
66 const unsigned char *id,
82 #define ANNOUNCE_PEER 5
89 const unsigned char *buf,
91 unsigned char *tid_return,
93 unsigned char *id_return,
94 unsigned char *info_hash_return,
95 unsigned char *target_return,
96 unsigned short *port_return,
97 unsigned char *token_return,
99 unsigned char *nodes_return,
101 unsigned char *nodes6_return,
103 unsigned char *values_return,
105 unsigned char *values6_return,
109 static const unsigned char zeroes[20] = {0};
110 static const unsigned char v4prefix[16] =
111 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0};
113 static unsigned char myid[20];
114 static int have_v = 0;
115 static unsigned char my_v[9];
117 static int dht_socket = -1;
118 static int dht_socket6 = -1;
121 unsigned char id[160];
122 struct sockaddr_storage ss;
126 #define CIRCULAR_LIST_SIZE 256
128 struct circular_list {
131 struct node nodes[CIRCULAR_LIST_SIZE];
134 struct circular_list v4_new, v6_new, v4_confirmed, v6_confirmed;
136 #define MAX_TOKEN_BUCKET_TOKENS 40
137 static time_t token_bucket_time;
138 static int token_bucket_tokens;
140 FILE *dht_debug = NULL;
143 __attribute__((format(printf, 1, 2)))
146 debugf(const char *format, ...)
149 va_start(args, format);
151 vfprintf(dht_debug, format, args);
157 is_martian(struct sockaddr *sa)
159 switch (sa->sa_family) {
161 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
162 const unsigned char *address = (const unsigned char *)&sin->sin_addr;
163 return sin->sin_port == 0 || (address[0] == 0) || (address[0] == 127) ||
164 ((address[0] & 0xE0) == 0xE0);
167 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
168 const unsigned char *address = (const unsigned char *)&sin6->sin6_addr;
169 return sin6->sin6_port == 0 || (address[0] == 0xFF) ||
170 (address[0] == 0xFE && (address[1] & 0xC0) == 0x80) ||
171 (memcmp(address, zeroes, 15) == 0 &&
172 (address[15] == 0 || address[15] == 1)) ||
173 (memcmp(address, v4prefix, 12) == 0);
181 /* Forget about the ``XOR-metric''. An id is just a path from the
182 root of the tree, so bits are numbered from the start. */
185 id_cmp(const unsigned char *restrict id1, const unsigned char *restrict id2)
187 /* Memcmp is guaranteed to perform an unsigned comparison. */
188 return memcmp(id1, id2, 20);
191 /* Our transaction-ids are 4-bytes long, with the first two bytes identi-
192 fying the kind of request, and the remaining two a sequence number in
196 make_tid(unsigned char *tid_return, const char *prefix, unsigned short seqno)
198 tid_return[0] = prefix[0] & 0xFF;
199 tid_return[1] = prefix[1] & 0xFF;
200 memcpy(tid_return + 2, &seqno, 2);
204 tid_match(const unsigned char *tid, const char *prefix, unsigned short *seqno_return)
206 if (tid[0] == (prefix[0] & 0xFF) && tid[1] == (prefix[1] & 0xFF)) {
208 memcpy(seqno_return, tid + 2, 2);
215 circular(int from, int to)
219 return x + CIRCULAR_LIST_SIZE;
224 list_elements(struct circular_list *list)
226 return circular(list->head, list->tail);
230 list_empty(struct circular_list *list)
232 return list_elements(list) == 0;
236 list_free(struct circular_list *list)
238 return circular(list->tail + 1, list->head);
242 list_pop(struct circular_list *list, struct sockaddr_storage *ss, socklen_t *sslen)
244 if (list->head == list->tail)
247 memcpy(ss, &list->nodes[list->head].ss, list->nodes[list->head].sslen);
248 *sslen = list->nodes[list->head].sslen;
249 list->head = (list->head + 1) % CIRCULAR_LIST_SIZE;
255 struct circular_list *list,
257 struct sockaddr_storage *ss,
261 if (list->head == list->tail)
264 n = random() % (list->tail - list->head);
265 n = (list->head + n) % CIRCULAR_LIST_SIZE;
268 memcpy(id, &list->nodes[n].id, 20);
269 memcpy(ss, &list->nodes[n].ss, list->nodes[n].sslen);
270 *sslen = list->nodes[n].sslen;
274 /* We just learnt about a node, not necessarily a new one. Confirm is 1 if
275 the node sent a message, 2 if it sent us a reply. */
278 new_node(unsigned char *id, struct sockaddr *sa, socklen_t salen, int confirm)
280 struct circular_list *list;
283 if (sa->sa_family == AF_INET)
284 list = confirm >= 2 ? &v4_confirmed : &v4_new;
285 else if (sa->sa_family == AF_INET6)
286 list = confirm >= 2 ? &v6_confirmed : &v6_new;
290 /* A node that sends us a request is most probably bootstrapping.
291 We want to avoid getting our tables full of very young nodes -- only
292 include such a node if we have plenty of space. */
294 if (confirm == 1 && list_free(list) < 32)
297 for (i = list->head; i != list->tail; i = (i + 1) % CIRCULAR_LIST_SIZE) {
298 struct node *n = &list->nodes[i];
299 if (n->sslen == salen && memcmp(&n->ss, sa, salen) == 0)
303 memcpy(&list->nodes[list->tail].id, id, 160);
304 memcpy(&list->nodes[list->tail].ss, sa, salen);
305 list->nodes[list->tail].sslen = salen;
306 list->tail = (list->tail + 1) % CIRCULAR_LIST_SIZE;
307 if (list->head == list->tail)
308 list->head = (list->head + 1) % CIRCULAR_LIST_SIZE;
316 time_t now = time(NULL);
317 if (token_bucket_tokens == 0) {
318 token_bucket_tokens =
319 MIN(MAX_TOKEN_BUCKET_TOKENS, 4 * (now - token_bucket_time));
320 token_bucket_time = now;
323 if (token_bucket_tokens == 0)
326 token_bucket_tokens--;
331 send_request(struct circular_list *list, int dopop, int doping, int want)
333 unsigned char ttid[4];
334 struct sockaddr_storage ss;
338 if (list_empty(list))
342 rc = list_pop(list, &ss, &sslen);
346 rc = list_random(list, NULL, &ss, &sslen);
352 make_tid(ttid, "pn", 0);
353 debugf("Sending ping.\n");
354 return send_ping((struct sockaddr *)&ss, sslen, ttid, 4);
356 unsigned char id[20];
357 arc4random_buf(id, sizeof id);
358 make_tid(ttid, "fn", 0);
359 debugf("Sending find_node.\n");
360 return send_find_node((struct sockaddr *)&ss, sslen, ttid, 4, id, want);
365 newSock(const char *host, const char *port)
367 struct addrinfo hints;
368 memset(&hints, 0, sizeof(hints));
369 hints.ai_family = AF_UNSPEC;
370 hints.ai_socktype = SOCK_DGRAM;
371 struct addrinfo *res = NULL;
372 int err = getaddrinfo(host, port, &hints, &res);
374 fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
377 int sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
382 if (bind(sock, res->ai_addr, res->ai_addrlen) != 0) {
386 int rc = fcntl(sock, F_GETFL, 0);
391 rc = fcntl(sock, F_SETFL, (rc | O_NONBLOCK));
401 main(int argc, char **argv)
405 char *ipv4addr = NULL;
406 char *ipv6addr = NULL;
410 opt = getopt(argc, argv, "q4:6:");
419 ipv4addr = strdup(optarg);
422 ipv6addr = strdup(optarg);
434 const char *port = strdup(argv[i++]);
436 if (ipv4addr != NULL) {
437 dht_socket = newSock(ipv4addr, port);
439 if (ipv6addr != NULL) {
440 dht_socket6 = newSock(ipv6addr, port);
443 arc4random_buf(myid, sizeof myid);
445 memcpy(my_v, "1:v4:JB\0\0", 9);
452 unsigned char ttid[4];
455 struct addrinfo hints, *info, *infop;
456 memset(&hints, 0, sizeof(hints));
457 hints.ai_socktype = SOCK_DGRAM;
460 hints.ai_family = AF_INET6;
461 else if (dht_socket6 < 0)
462 hints.ai_family |= AF_INET;
463 rc = getaddrinfo(argv[i], argv[i + 1], &hints, &info);
465 fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rc));
475 make_tid(ttid, "pn", 0);
476 debugf("Sending ping.\n");
477 send_ping(infop->ai_addr, infop->ai_addrlen, ttid, 4);
478 infop = infop->ai_next;
485 token_bucket_time = time(NULL);
486 token_bucket_tokens = MAX_TOKEN_BUCKET_TOKENS;
488 struct pollfd fds[2];
489 fds[0].fd = dht_socket;
490 fds[0].events = POLLIN;
491 fds[1].fd = dht_socket6;
492 fds[1].events = POLLIN;
496 if ((dht_socket >= 0 && list_elements(&v4_confirmed) <= 16) ||
497 (dht_socket6 >= 0 && list_elements(&v6_confirmed) <= 16))
500 tv_sec = random() % 30;
501 int tv_msec = random() % 1000;
506 list_elements(&v4_confirmed),
507 list_elements(&v6_confirmed),
508 list_elements(&v4_new),
509 list_elements(&v6_new));
511 int rc = poll(fds, 2, tv_sec * 1000 + tv_msec);
521 unsigned char tid[16], id[20], info_hash[20], target[20];
522 unsigned char buf[1536], nodes[256], nodes6[1024], token[128];
523 int tid_len = 16, token_len = 128;
524 int nodes_len = 256, nodes6_len = 1024;
526 unsigned char values[2048], values6[2048];
527 int values_len = 2048, values6_len = 2048;
529 struct sockaddr_storage source_storage;
530 struct sockaddr *source = (struct sockaddr *)&source_storage;
531 socklen_t sourcelen = sizeof(source_storage);
532 if (fds[0].revents != 0) {
533 if ((fds[0].revents & (POLLERR | POLLNVAL)) > 0) {
534 fprintf(stderr, "error in fds[0]");
537 rc = recvfrom(dht_socket, buf, 1536, 0, source, &sourcelen);
539 } else if (fds[1].revents != 0) {
540 if ((fds[1].revents & (POLLERR | POLLNVAL)) > 0) {
541 fprintf(stderr, "error in fds[1]");
544 rc = recvfrom(dht_socket6, buf, 1536, 0, source, &sourcelen);
548 if (rc < 0 || sourcelen > sizeof(struct sockaddr_storage))
551 if (is_martian(source))
554 /* There's a bug in parse_message -- it will happily overflow the
555 buffer if it's not NUL-terminated. For now, put a NUL at the
561 debugf("Overlong message.\n");
565 message = parse_message(
586 if (id_cmp(id, myid) == 0) {
587 debugf("Received message from self.\n");
591 if (message > REPLY) {
592 /* Rate limit requests. */
593 if (!token_bucket()) {
594 debugf("Dropping request due to rate limiting.\n");
602 debugf("Broken node truncates transaction ids.\n");
605 if (tid_match(tid, "pn", NULL)) {
607 new_node(id, source, sourcelen, 2);
608 } else if (tid_match(tid, "fn", NULL)) {
609 debugf("Nodes found!\n");
610 if (nodes_len % 26 != 0 || nodes6_len % 38 != 0) {
611 debugf("Unexpected length for node info!\n");
613 new_node(id, source, sourcelen, 2);
614 for (i = 0; i < nodes_len / 26; i++) {
615 unsigned char *ni = nodes + i * 26;
616 struct sockaddr_in sin;
617 if (id_cmp(ni, myid) == 0)
619 memset(&sin, 0, sizeof(sin));
620 sin.sin_family = AF_INET;
621 memcpy(&sin.sin_addr, ni + 20, 4);
622 memcpy(&sin.sin_port, ni + 24, 2);
623 new_node(ni, (struct sockaddr *)&sin, sizeof(sin), 0);
625 for (i = 0; i < nodes6_len / 38; i++) {
626 unsigned char *ni = nodes6 + i * 38;
627 struct sockaddr_in6 sin6;
628 if (id_cmp(ni, myid) == 0)
630 memset(&sin6, 0, sizeof(sin6));
631 sin6.sin6_family = AF_INET6;
632 memcpy(&sin6.sin6_addr, ni + 20, 16);
633 memcpy(&sin6.sin6_port, ni + 36, 2);
634 new_node(ni, (struct sockaddr *)&sin6, sizeof(sin6), 0);
638 debugf("Unexpected reply!\n");
643 debugf("Ping (%d)!\n", tid_len);
644 new_node(id, source, sourcelen, 1);
645 debugf("Sending pong.\n");
646 send_pong(source, sourcelen, tid, tid_len);
651 if (message == FIND_NODE)
652 debugf("Find node!\n");
654 debugf("Get peers!\n");
655 new_node(id, source, sourcelen, 1);
656 debugf("Sending nodes (%d).\n", want);
657 send_random_nodes(source, sourcelen, tid, tid_len, target, want);
660 debugf("Announce peer!\n");
667 "This node doesn't accept announces");
674 /* We need to be careful to avoid a positive feedback loop. Make
675 sure we send at most one packet each time through the select
680 else if (dht_socket < 0)
683 send4 = random() % 2;
686 int want = dht_socket6 >= 0 && list_free(&v6_new) > 8 ? (WANT4 | WANT6) : 0;
687 if (!list_empty(&v4_new))
688 send_request(&v4_new, 1, list_free(&v4_new) < 8, want);
689 else if (!list_empty(&v4_confirmed))
690 send_request(&v4_confirmed, 0, 0, want);
692 int want = dht_socket >= 0 && list_free(&v4_new) > 8 ? (WANT4 | WANT6) : 0;
693 if (!list_empty(&v6_new))
694 send_request(&v6_new, 1, list_free(&v6_new) < 8, want);
695 else if (!list_empty(&v6_confirmed))
696 send_request(&v6_confirmed, 0, 0, want);
703 fprintf(stderr, "dht-bootstrap [-q] [-4 ADDR4] [-6 ADDR6] port [node port...]\n");
707 /* We could use a proper bencoding printer and parser, but the format of
708 DHT messages is fairly stylised, so this seemed simpler. */
710 #define CHECK(offset, delta, size) \
711 if (delta < 0 || offset + delta > size) \
714 #define INC(offset, delta, size) \
715 CHECK(offset, delta, size); \
718 #define COPY(buf, offset, src, delta, size) \
719 CHECK(offset, delta, size); \
720 memcpy(buf + offset, src, delta); \
723 #define ADD_V(buf, offset, size) \
725 COPY(buf, offset, my_v, sizeof(my_v), size); \
729 dht_send(const void *buf, size_t len, int flags, const struct sockaddr *sa, int salen)
736 if (sa->sa_family == AF_INET)
738 else if (sa->sa_family == AF_INET6)
744 errno = EAFNOSUPPORT;
748 return sendto(s, buf, len, flags, sa, salen);
752 send_ping(struct sockaddr *sa, int salen, const unsigned char *tid, int tid_len)
756 rc = snprintf(buf + i, 512 - i, "d1:ad2:id20:");
758 COPY(buf, i, myid, 20, 512);
759 rc = snprintf(buf + i, 512 - i, "e1:q4:ping1:t%d:", tid_len);
761 COPY(buf, i, tid, tid_len, 512);
763 rc = snprintf(buf + i, 512 - i, "1:y1:qe");
765 return dht_send(buf, i, 0, sa, salen);
773 send_pong(struct sockaddr *sa, int salen, const unsigned char *tid, int tid_len)
777 rc = snprintf(buf + i, 512 - i, "d1:rd2:id20:");
779 COPY(buf, i, myid, 20, 512);
780 rc = snprintf(buf + i, 512 - i, "e1:t%d:", tid_len);
782 COPY(buf, i, tid, tid_len, 512);
784 rc = snprintf(buf + i, 512 - i, "1:y1:re");
786 return dht_send(buf, i, 0, sa, salen);
797 const unsigned char *tid,
799 const unsigned char *target,
804 rc = snprintf(buf + i, 512 - i, "d1:ad2:id20:");
806 COPY(buf, i, myid, 20, 512);
807 rc = snprintf(buf + i, 512 - i, "6:target20:");
809 COPY(buf, i, target, 20, 512);
815 (want & WANT4) ? "2:n4" : "",
816 (want & WANT6) ? "2:n6" : "");
819 rc = snprintf(buf + i, 512 - i, "e1:q9:find_node1:t%d:", tid_len);
821 COPY(buf, i, tid, tid_len, 512);
823 rc = snprintf(buf + i, 512 - i, "1:y1:qe");
825 return dht_send(buf, i, 0, sa, salen);
836 const unsigned char *tid,
838 const unsigned char *nodes,
840 const unsigned char *nodes6,
846 rc = snprintf(buf + i, 2048 - i, "d1:rd2:id20:");
848 COPY(buf, i, myid, 20, 2048);
850 rc = snprintf(buf + i, 2048 - i, "5:nodes%d:", nodes_len);
852 COPY(buf, i, nodes, nodes_len, 2048);
854 if (nodes6_len > 0) {
855 rc = snprintf(buf + i, 2048 - i, "6:nodes6%d:", nodes6_len);
857 COPY(buf, i, nodes6, nodes6_len, 2048);
860 rc = snprintf(buf + i, 2048 - i, "e1:t%d:", tid_len);
862 COPY(buf, i, tid, tid_len, 2048);
864 rc = snprintf(buf + i, 2048 - i, "1:y1:re");
867 return dht_send(buf, i, 0, sa, salen);
875 buffer_random_nodes(int af, unsigned char *nodes)
877 struct circular_list *list;
878 struct sockaddr_storage ss;
880 unsigned char id[20];
886 list = &v4_confirmed;
889 list = &v6_confirmed;
897 rc = list_random(list, id, &ss, &sslen);
902 struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
903 memcpy(nodes + n * 26, id, 20);
904 memcpy(nodes + n * 26 + 20, &sin->sin_addr, 4);
905 memcpy(nodes + n * 26 + 24, &sin->sin_port, 2);
910 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
911 memcpy(nodes + n * 38, id, 20);
912 memcpy(nodes + n * 38 + 20, &sin6->sin6_addr, 16);
913 memcpy(nodes + n * 38 + 36, &sin6->sin6_port, 2);
928 const unsigned char *tid,
930 const unsigned char *id,
933 unsigned char nodes[8 * 26];
934 unsigned char nodes6[8 * 38];
935 int numnodes = 0, numnodes6 = 0;
938 want = sa->sa_family == AF_INET ? WANT4 : WANT6;
941 numnodes = buffer_random_nodes(AF_INET, nodes);
944 numnodes6 = buffer_random_nodes(AF_INET6, nodes6);
947 sa, salen, tid, tid_len, nodes, numnodes * 26, nodes6, numnodes6 * 38);
962 rc = snprintf(buf + i, 512 - i, "d1:eli%de%d:", code, (int)strlen(message));
964 COPY(buf, i, message, (int)strlen(message), 512);
965 rc = snprintf(buf + i, 512 - i, "e1:t%d:", tid_len);
967 COPY(buf, i, tid, tid_len, 512);
969 rc = snprintf(buf + i, 512 - i, "1:y1:ee");
971 return dht_send(buf, i, 0, sa, salen);
985 const unsigned char *buf,
987 unsigned char *tid_return,
989 unsigned char *id_return,
990 unsigned char *info_hash_return,
991 unsigned char *target_return,
992 unsigned short *port_return,
993 unsigned char *token_return,
995 unsigned char *nodes_return,
997 unsigned char *nodes6_return,
999 unsigned char *values_return,
1001 unsigned char *values6_return,
1005 const unsigned char *p;
1007 /* This code will happily crash if the buffer is not NUL-terminated. */
1008 if (buf[buflen] != '\0') {
1009 debugf("Eek! parse_message with unterminated buffer.\n");
1013 #define CHECK(ptr, len) \
1014 if (((unsigned char *)ptr) + (len) > (buf) + (buflen)) \
1018 p = memmem(buf, buflen, "1:t", 3);
1022 l = strtol((char *)p + 3, &q, 10);
1023 if (q && *q == ':' && l > 0 && l < *tid_len) {
1025 memcpy(tid_return, q + 1, l);
1032 p = memmem(buf, buflen, "2:id20:", 7);
1035 memcpy(id_return, p + 7, 20);
1037 memset(id_return, 0, 20);
1040 if (info_hash_return) {
1041 p = memmem(buf, buflen, "9:info_hash20:", 14);
1044 memcpy(info_hash_return, p + 14, 20);
1046 memset(info_hash_return, 0, 20);
1050 p = memmem(buf, buflen, "porti", 5);
1054 l = strtol((char *)p + 5, &q, 10);
1055 if (q && *q == 'e' && l > 0 && l < 0x10000)
1062 if (target_return) {
1063 p = memmem(buf, buflen, "6:target20:", 11);
1066 memcpy(target_return, p + 11, 20);
1068 memset(target_return, 0, 20);
1072 p = memmem(buf, buflen, "5:token", 7);
1076 l = strtol((char *)p + 7, &q, 10);
1077 if (q && *q == ':' && l > 0 && l < *token_len) {
1079 memcpy(token_return, q + 1, l);
1088 p = memmem(buf, buflen, "5:nodes", 7);
1092 l = strtol((char *)p + 7, &q, 10);
1093 if (q && *q == ':' && l > 0 && l < *nodes_len) {
1095 memcpy(nodes_return, q + 1, l);
1104 p = memmem(buf, buflen, "6:nodes6", 8);
1108 l = strtol((char *)p + 8, &q, 10);
1109 if (q && *q == ':' && l > 0 && l < *nodes6_len) {
1111 memcpy(nodes6_return, q + 1, l);
1119 if (values_len || values6_len) {
1120 p = memmem(buf, buflen, "6:valuesl", 9);
1122 int i = p - buf + 9;
1127 l = strtol((char *)buf + i, &q, 10);
1128 if (q && *q == ':' && l > 0) {
1131 if (j + l > *values_len)
1133 i = q + 1 + l - (char *)buf;
1134 memcpy((char *)values_return + j, q + 1, l);
1136 } else if (l == 18) {
1137 if (j6 + l > *values6_len)
1139 i = q + 1 + l - (char *)buf;
1140 memcpy((char *)values6_return + j6, q + 1, l);
1143 debugf("Received weird value -- %d bytes.\n", (int)l);
1144 i = q + 1 + l - (char *)buf;
1150 if (i >= buflen || buf[i] != 'e')
1151 debugf("eek... unexpected end for values.\n");
1163 p = memmem(buf, buflen, "4:wantl", 7);
1165 int i = p - buf + 7;
1167 while (buf[i] > '0' && buf[i] <= '9' && buf[i + 1] == ':' &&
1168 i + 2 + buf[i] - '0' < buflen) {
1169 CHECK(buf + i + 2, buf[i] - '0');
1170 if (buf[i] == '2' && memcmp(buf + i + 2, "n4", 2) == 0)
1171 *want_return |= WANT4;
1172 else if (buf[i] == '2' && memcmp(buf + i + 2, "n6", 2) == 0)
1173 *want_return |= WANT6;
1175 debugf("eek... unexpected want flag (%c)\n", buf[i]);
1176 i += 2 + buf[i] - '0';
1178 if (i >= buflen || buf[i] != 'e')
1179 debugf("eek... unexpected end for want.\n");
1187 if (memmem(buf, buflen, "1:y1:r", 6))
1189 if (memmem(buf, buflen, "1:y1:e", 6))
1191 if (!memmem(buf, buflen, "1:y1:q", 6))
1193 if (memmem(buf, buflen, "1:q4:ping", 9))
1195 if (memmem(buf, buflen, "1:q9:find_node", 14))
1197 if (memmem(buf, buflen, "1:q9:get_peers", 14))
1199 if (memmem(buf, buflen, "1:q13:announce_peer", 19))
1200 return ANNOUNCE_PEER;
1204 debugf("Truncated message.\n");