- send4 = random() % 2;
-
- if(send4) {
- int want =
- dht_socket6 >= 0 && list_free(&v6_new) > 8 ?
- (WANT4 | WANT6) : 0;
- if(!list_empty(&v4_new))
- send_request(&v4_new, 1, list_free(&v4_new) < 8, want);
- else if(!list_empty(&v4_confirmed))
- send_request(&v4_confirmed, 0, 0, want);
- } else {
- int want =
- dht_socket >= 0 && list_free(&v4_new) > 8 ?
- (WANT4 | WANT6) : 0;
- if(!list_empty(&v6_new))
- send_request(&v6_new, 1, list_free(&v6_new) < 8, want);
- else if(!list_empty(&v6_confirmed))
- send_request(&v6_confirmed, 0, 0, want);
- }
- }
-
- return 0;
-
- usage:
- fprintf(stderr, "dht-bootstrap [-q] [-4] [-6] port [node port...]\n");
- exit(1);
-}
-
-/* We could use a proper bencoding printer and parser, but the format of
- DHT messages is fairly stylised, so this seemed simpler. */
-
-#define CHECK(offset, delta, size) \
- if(delta < 0 || offset + delta > size) goto fail
-
-#define INC(offset, delta, size) \
- CHECK(offset, delta, size); \
- offset += delta
-
-#define COPY(buf, offset, src, delta, size) \
- CHECK(offset, delta, size); \
- memcpy(buf + offset, src, delta); \
- offset += delta;
-
-#define ADD_V(buf, offset, size) \
- if(have_v) { \
- COPY(buf, offset, my_v, sizeof(my_v), size); \
- }
-
-static int
-dht_send(const void *buf, size_t len, int flags,
- const struct sockaddr *sa, int salen)
-{
- int s;
-
- if(salen == 0)
- abort();
-
- if(sa->sa_family == AF_INET)
- s = dht_socket;
- else if(sa->sa_family == AF_INET6)
- s = dht_socket6;
- else
- s = -1;
-
- if(s < 0) {
- errno = EAFNOSUPPORT;
- return -1;
- }
-
- return sendto(s, buf, len, flags, sa, salen);
-}
-
-int
-send_ping(struct sockaddr *sa, int salen,
- const unsigned char *tid, int tid_len)
-{
- char buf[512];
- int i = 0, rc;
- rc = snprintf(buf + i, 512 - i, "d1:ad2:id20:"); INC(i, rc, 512);
- COPY(buf, i, myid, 20, 512);
- rc = snprintf(buf + i, 512 - i, "e1:q4:ping1:t%d:", tid_len);
- INC(i, rc, 512);
- COPY(buf, i, tid, tid_len, 512);
- ADD_V(buf, i, 512);
- rc = snprintf(buf + i, 512 - i, "1:y1:qe"); INC(i, rc, 512);
- return dht_send(buf, i, 0, sa, salen);
-
- fail:
- errno = ENOSPC;
- return -1;
-}
-
-int
-send_pong(struct sockaddr *sa, int salen,
- const unsigned char *tid, int tid_len)
-{
- char buf[512];
- int i = 0, rc;
- rc = snprintf(buf + i, 512 - i, "d1:rd2:id20:"); INC(i, rc, 512);
- COPY(buf, i, myid, 20, 512);
- rc = snprintf(buf + i, 512 - i, "e1:t%d:", tid_len); INC(i, rc, 512);
- COPY(buf, i, tid, tid_len, 512);
- ADD_V(buf, i, 512);
- rc = snprintf(buf + i, 512 - i, "1:y1:re"); INC(i, rc, 512);
- return dht_send(buf, i, 0, sa, salen);
-
- fail:
- errno = ENOSPC;
- return -1;
-}
-
-int
-send_find_node(struct sockaddr *sa, int salen,
- const unsigned char *tid, int tid_len,
- const unsigned char *target, int want, int confirm)
-{
- char buf[512];
- int i = 0, rc;
- rc = snprintf(buf + i, 512 - i, "d1:ad2:id20:"); INC(i, rc, 512);
- COPY(buf, i, myid, 20, 512);
- rc = snprintf(buf + i, 512 - i, "6:target20:"); INC(i, rc, 512);
- COPY(buf, i, target, 20, 512);
- if(want > 0) {
- rc = snprintf(buf + i, 512 - i, "4:wantl%s%se",
- (want & WANT4) ? "2:n4" : "",
- (want & WANT6) ? "2:n6" : "");
- INC(i, rc, 512);
- }
- rc = snprintf(buf + i, 512 - i, "e1:q9:find_node1:t%d:", tid_len);
- INC(i, rc, 512);
- COPY(buf, i, tid, tid_len, 512);
- ADD_V(buf, i, 512);
- rc = snprintf(buf + i, 512 - i, "1:y1:qe"); INC(i, rc, 512);
- return dht_send(buf, i, confirm ? MSG_CONFIRM : 0, sa, salen);
-
- fail:
- errno = ENOSPC;
- return -1;
-}
-
-int
-send_nodes(struct sockaddr *sa, int salen,
- const unsigned char *tid, int tid_len,
- const unsigned char *nodes, int nodes_len,
- const unsigned char *nodes6, int nodes6_len)
-{
- char buf[2048];
- int i = 0, rc;
-
- rc = snprintf(buf + i, 2048 - i, "d1:rd2:id20:"); INC(i, rc, 2048);
- COPY(buf, i, myid, 20, 2048);
- if(nodes_len > 0) {
- rc = snprintf(buf + i, 2048 - i, "5:nodes%d:", nodes_len);
- INC(i, rc, 2048);
- COPY(buf, i, nodes, nodes_len, 2048);
- }
- if(nodes6_len > 0) {
- rc = snprintf(buf + i, 2048 - i, "6:nodes6%d:", nodes6_len);
- INC(i, rc, 2048);
- COPY(buf, i, nodes6, nodes6_len, 2048);
- }
-
- rc = snprintf(buf + i, 2048 - i, "e1:t%d:", tid_len); INC(i, rc, 2048);
- COPY(buf, i, tid, tid_len, 2048);
- ADD_V(buf, i, 2048);
- rc = snprintf(buf + i, 2048 - i, "1:y1:re"); INC(i, rc, 2048);
-
- return dht_send(buf, i, 0, sa, salen);
-
- fail:
- errno = ENOSPC;
- return -1;
-}
-
-static int
-buffer_random_nodes(int af, unsigned char *nodes)
-{
- struct circular_list *list;
- struct sockaddr_storage ss;
- socklen_t sslen;
- unsigned char id[20];
- int n;
- int rc;
-
- switch(af) {
- case AF_INET: list = &v4_confirmed; break;
- case AF_INET6: list = &v6_confirmed; break;
- default: abort();
- }
-
- n = 0;
- while(n < 8) {
- rc = list_random(list, id, &ss, &sslen);
- if(rc < 1)
- break;
- switch(af) {
- case AF_INET: {
- struct sockaddr_in *sin = (struct sockaddr_in*)&ss;
- memcpy(nodes + n * 26, id, 20);
- memcpy(nodes + n * 26 + 20, &sin->sin_addr, 4);
- memcpy(nodes + n * 26 + 24, &sin->sin_port, 2);
- n++;
- break;
- }
- case AF_INET6: {
- struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&ss;
- memcpy(nodes + n * 38, id, 20);
- memcpy(nodes + n * 38 + 20, &sin6->sin6_addr, 16);
- memcpy(nodes + n * 38 + 36, &sin6->sin6_port, 2);
- n++;
- break;
- }
- default:
- abort();
- }
- }
- return n;
-}
-
-int
-send_random_nodes(struct sockaddr *sa, int salen,
- const unsigned char *tid, int tid_len,
- const unsigned char *id, int want)
-{
- unsigned char nodes[8 * 26];
- unsigned char nodes6[8 * 38];
- int numnodes = 0, numnodes6 = 0;
-
- if(want < 0)
- want = sa->sa_family == AF_INET ? WANT4 : WANT6;
-
- if((want & WANT4))
- numnodes = buffer_random_nodes(AF_INET, nodes);
-
- if((want & WANT6))
- numnodes6 = buffer_random_nodes(AF_INET6, nodes6);
-
- return send_nodes(sa, salen, tid, tid_len,
- nodes, numnodes * 26,
- nodes6, numnodes6 * 38);
-}
-
-static int
-send_error(struct sockaddr *sa, int salen,
- unsigned char *tid, int tid_len,
- int code, const char *message)
-{
- char buf[512];
- int i = 0, rc;
-
- rc = snprintf(buf + i, 512 - i, "d1:eli%de%d:",
- code, (int)strlen(message));
- INC(i, rc, 512);
- COPY(buf, i, message, (int)strlen(message), 512);
- rc = snprintf(buf + i, 512 - i, "e1:t%d:", tid_len); INC(i, rc, 512);
- COPY(buf, i, tid, tid_len, 512);
- ADD_V(buf, i, 512);
- rc = snprintf(buf + i, 512 - i, "1:y1:ee"); INC(i, rc, 512);
- return dht_send(buf, i, 0, sa, salen);
-
- fail:
- errno = ENOSPC;
- return -1;
-}
-
-#undef CHECK
-#undef INC
-#undef COPY
-#undef ADD_V
-
-#ifndef HAVE_MEMMEM
-static void *
-memmem(const void *haystack, size_t haystacklen,
- const void *needle, size_t needlelen)
-{
- const char *h = haystack;
- const char *n = needle;
- size_t i;
-
- /* size_t is unsigned */
- if(needlelen > haystacklen)
- return NULL;
-
- for(i = 0; i <= haystacklen - needlelen; i++) {
- if(memcmp(h + i, n, needlelen) == 0)
- return (void*)(h + i);
- }
- return NULL;
-}
-#endif
-
-static int
-parse_message(const unsigned char *buf, int buflen,
- unsigned char *tid_return, int *tid_len,
- unsigned char *id_return, unsigned char *info_hash_return,
- unsigned char *target_return, unsigned short *port_return,
- unsigned char *token_return, int *token_len,
- unsigned char *nodes_return, int *nodes_len,
- unsigned char *nodes6_return, int *nodes6_len,
- unsigned char *values_return, int *values_len,
- unsigned char *values6_return, int *values6_len,
- int *want_return)
-{
- const unsigned char *p;
-
- /* This code will happily crash if the buffer is not NUL-terminated. */
- if(buf[buflen] != '\0') {
- debugf("Eek! parse_message with unterminated buffer.\n");
- return -1;
- }
-
-#define CHECK(ptr, len) \
- if(((unsigned char*)ptr) + (len) > (buf) + (buflen)) goto overflow;
-
- if(tid_return) {
- p = memmem(buf, buflen, "1:t", 3);
- if(p) {
- long l;
- char *q;
- l = strtol((char*)p + 3, &q, 10);
- if(q && *q == ':' && l > 0 && l < *tid_len) {
- CHECK(q + 1, l);
- memcpy(tid_return, q + 1, l);
- *tid_len = l;
- } else
- *tid_len = 0;
- }
- }
- if(id_return) {
- p = memmem(buf, buflen, "2:id20:", 7);
- if(p) {
- CHECK(p + 7, 20);
- memcpy(id_return, p + 7, 20);
- } else {
- memset(id_return, 0, 20);
- }
- }
- if(info_hash_return) {
- p = memmem(buf, buflen, "9:info_hash20:", 14);
- if(p) {
- CHECK(p + 14, 20);
- memcpy(info_hash_return, p + 14, 20);
- } else {
- memset(info_hash_return, 0, 20);
- }
- }
- if(port_return) {
- p = memmem(buf, buflen, "porti", 5);
- if(p) {
- long l;
- char *q;
- l = strtol((char*)p + 5, &q, 10);
- if(q && *q == 'e' && l > 0 && l < 0x10000)
- *port_return = l;
- else
- *port_return = 0;
- } else
- *port_return = 0;
- }
- if(target_return) {
- p = memmem(buf, buflen, "6:target20:", 11);
- if(p) {
- CHECK(p + 11, 20);
- memcpy(target_return, p + 11, 20);