6 #include <sys/socket.h>
9 #include <libubox/usock.h>
10 #include <libubox/uloop.h>
11 #include <libubox/blob.h>
13 #include "curve25519.h"
20 static struct uloop_timeout periodic_timer
, peer_timer
, status_timer
, disconnect_timer
;
21 static struct uloop_fd dht_fd
;
22 static int dht_unix_fd
;
23 static LIST_HEAD(bootstrap_peers
);
24 static LIST_HEAD(networks
);
25 static struct blob_buf b
;
26 static uint8_t local_id
[20];
27 static const char *node_file
;
28 static const char *unix_path
;
29 static bool udht_connected
;
33 unsigned int peer_count
;
38 struct network_entry
{
39 struct list_head list
;
40 uint8_t auth_key
[CURVE25519_KEY_SIZE
];
42 struct uloop_timeout search_timer
;
48 struct list_head list
;
50 struct sockaddr_storage sa
;
54 void dht_hash(void *hash_return
, int hash_size
,
55 const void *v1
, int len1
,
56 const void *v2
, int len2
,
57 const void *v3
, int len3
)
59 siphash_key_t key
= {};
64 key
.key
[0] = siphash(v1
, len1
, &key
);
65 key
.key
[1] = siphash(v2
, len2
, &key
);
66 siphash_to_le64(hash_return
, v3
, len3
, &key
);
69 int dht_sendto(int sockfd
, const void *buf
, int len
, int flags
,
70 const struct sockaddr
*to
, int tolen
)
72 struct iovec iov
[2] = {
73 { .iov_base
= (void *)to
},
74 { .iov_base
= (void *)buf
, .iov_len
= len
},
78 .msg_iovlen
= ARRAY_SIZE(iov
),
82 if (to
->sa_family
== AF_INET
)
83 iov
[0].iov_len
= sizeof(struct sockaddr_in
);
84 else if (to
->sa_family
== AF_INET6
)
85 iov
[0].iov_len
= sizeof(struct sockaddr_in6
);
89 ret
= sendmsg(sockfd
, &msg
, flags
);
92 if (errno
== ECONNRESET
|| errno
== EDESTADDRREQ
||
93 errno
== ENOTCONN
|| errno
== ECONNREFUSED
)
94 uloop_timeout_set(&disconnect_timer
, 1);
99 int dht_blacklisted(const struct sockaddr
*sa
, int salen
)
104 int dht_random_bytes(void *buf
, size_t size
)
108 fd
= open("/dev/urandom", O_RDONLY
);
112 rc
= read(fd
, buf
, size
);
122 udht_start_search(void)
124 struct network_entry
*n
;
126 if (!state
.dht_ready
)
129 list_for_each_entry(n
, &networks
, list
) {
130 if (n
->search_timer
.pending
)
133 uloop_timeout_set(&n
->search_timer
, 1);
138 udht_send_v4_node(const void *id
, const void *data
)
140 struct network_entry
*n
;
144 struct pex_msg_local_control local
;
147 .sa_family
= AF_LOCAL
151 .sin_family
= AF_INET
,
152 .sin_addr
= *(const struct in_addr
*)data
,
153 .sin_port
= *(const uint16_t *)(data
+ 4),
159 list_for_each_entry(n
, &networks
, list
) {
160 if (memcmp(n
->id
, id
, sizeof(n
->id
)) != 0)
163 memcpy(&msg
.local
.auth_id
, n
->auth_key
, sizeof(msg
.local
.auth_id
));
168 send(dht_unix_fd
, &msg
, sizeof(msg
), 0);
172 udht_cb(void *closure
, int event
, const unsigned char *info_hash
,
173 const void *data
, size_t data_len
)
175 char addrbuf
[INET6_ADDRSTRLEN
];
181 if (event
== DHT_EVENT_SEARCH_DONE
) {
182 printf("Search done.\n");
184 } else if (event
== DHT_EVENT_SEARCH_DONE6
) {
185 printf("IPv6 search done.\n");
186 } else if (event
== DHT_EVENT_VALUES
) {
187 printf("Received %d values.\n", (int)(data_len
/ 6));
188 for (i
= 0; i
< data_len
/ 6; i
++) {
189 fprintf(stderr
, "Node: %s:%d\n", inet_ntop(AF_INET
, data
, addrbuf
, sizeof(addrbuf
)), ntohs(*(uint16_t *)(data
+ 4)));
190 udht_send_v4_node(info_hash
, data
);
194 else if (event
== DHT_EVENT_VALUES6
)
195 printf("Received %d IPv6 values.\n", (int)(data_len
/ 18));
197 printf("Unknown DHT event %d.\n", event
);
201 udht_search_timer_cb(struct uloop_timeout
*t
)
203 struct network_entry
*n
= container_of(t
, struct network_entry
, search_timer
);
207 for (i
= 0; i
< sizeof(n
->id
); i
++)
208 snprintf(&id_str
[i
* 2], sizeof(id_str
) - i
* 2, "%02x", n
->id
[i
]);
210 fprintf(stderr
, "Start search for network, id=%s\n", id_str
);
211 dht_search(n
->id
, UNETD_GLOBAL_PEX_PORT
, AF_INET
, udht_cb
, NULL
);
213 if (++n
->search_count
> 2)
214 uloop_timeout_set(&n
->search_timer
, 30 * 1000);
218 udht_timer_cb(struct uloop_timeout
*t
)
222 dht_periodic(NULL
, 0, NULL
, 0, &tosleep
, udht_cb
, NULL
);
225 uloop_timeout_set(t
, tosleep
* 1000);
229 udht_fd_cb(struct uloop_fd
*fd
, unsigned int events
)
231 static char buf
[4096];
232 struct sockaddr
*sa
= (struct sockaddr
*)buf
;
239 len
= recv(fd
->fd
, buf
, sizeof(buf
) - 1, 0);
248 uloop_timeout_set(&disconnect_timer
, 1);
252 if (len
<= sizeof(struct sockaddr
))
255 if (sa
->sa_family
== AF_INET
)
256 fromlen
= sizeof(struct sockaddr_in
);
257 else if (sa
->sa_family
== AF_INET6
)
258 fromlen
= sizeof(struct sockaddr_in6
);
266 dht_periodic(buf
+ fromlen
, len
- fromlen
, sa
, fromlen
,
267 &tosleep
, udht_cb
, NULL
);
270 uloop_timeout_set(&periodic_timer
, tosleep
* 1000);
275 udht_open_socket(const char *unix_path
)
277 uint8_t fd_buf
[CMSG_SPACE(sizeof(int))] = { 0 };
278 static struct sockaddr sa
= {
279 .sa_family
= AF_LOCAL
,
281 static struct iovec iov
= {
283 .iov_len
= sizeof(sa
),
285 struct msghdr msg
= {
288 .msg_control
= fd_buf
,
289 .msg_controllen
= CMSG_LEN(sizeof(int)),
291 struct cmsghdr
*cmsg
;
295 fd
= usock(USOCK_UNIX
| USOCK_UDP
, unix_path
, NULL
);
299 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, sfd
) < 0)
304 dht_fd
.cb
= udht_fd_cb
;
305 uloop_fd_add(&dht_fd
, ULOOP_READ
);
307 cmsg
= CMSG_FIRSTHDR(&msg
);
308 cmsg
->cmsg_type
= SCM_RIGHTS
;
309 cmsg
->cmsg_level
= SOL_SOCKET
;
310 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int));
311 *(int *)CMSG_DATA(cmsg
) = sfd
[0];
313 sendmsg(dht_unix_fd
, &msg
, 0);
320 udht_close_socket(void)
322 uloop_fd_delete(&dht_fd
);
327 static void udht_id_hash(uint8_t *dest
, const void *data
, int len
)
329 struct sha512_state s
;
330 uint8_t hash
[SHA512_HASH_SIZE
];
333 sha512_add(&s
, data
, len
);
334 sha512_final(&s
, hash
);
335 memcpy(dest
, hash
, 20);
338 static void udht_add_peer(const void *data
, int len
)
340 const struct sockaddr
*sa
= data
;
341 struct peer_entry
*p
;
343 p
= calloc(1, sizeof(*p
));
344 memcpy(&p
->sa
, sa
, len
);
346 list_add_tail(&p
->list
, &bootstrap_peers
);
348 if (!peer_timer
.pending
)
349 uloop_timeout_set(&peer_timer
, 1);
352 static void udht_add_bootstrap_peer(void)
354 const struct addrinfo hints
= {
355 .ai_family
= AF_INET
,
356 .ai_socktype
= SOCK_DGRAM
,
357 .ai_flags
= AI_ADDRCONFIG
,
359 struct addrinfo
*res
, *cur
;
360 static const char * const bootstrap_hosts
[] = {
361 "router.bittorrent.com",
362 "router.utorrent.com",
366 for (i
= 0; i
< ARRAY_SIZE(bootstrap_hosts
); i
++) {
367 if (getaddrinfo(bootstrap_hosts
[i
], "6881", &hints
, &res
) < 0)
370 for (cur
= res
; cur
; cur
= cur
->ai_next
)
371 udht_add_peer(cur
->ai_addr
, cur
->ai_addrlen
);
376 state
.bootstrap_added
= true;
379 static void udht_peer_timer_cb(struct uloop_timeout
*t
)
381 struct peer_entry
*p
;
382 struct sockaddr_in
*sin
;
383 char buf
[INET6_ADDRSTRLEN
];
385 if (list_empty(&bootstrap_peers
)) {
386 if (!state
.peer_count
&& !state
.bootstrap_added
)
387 udht_add_bootstrap_peer();
392 p
= list_first_entry(&bootstrap_peers
, struct peer_entry
, list
);
394 sin
= (struct sockaddr_in
*)&p
->sa
;
395 fprintf(stderr
, "Ping node %s\n", inet_ntop(sin
->sin_family
, &sin
->sin_addr
, buf
, sizeof(buf
)));
396 dht_ping_node((struct sockaddr
*)&p
->sa
, p
->sa_len
);
399 if (state
.peer_count
++ < 8)
400 uloop_timeout_set(t
, 2000);
402 uloop_timeout_set(t
, 15000);
405 void udht_network_add(const uint8_t *auth_key
, int seq
)
407 struct network_entry
*n
;
409 list_for_each_entry(n
, &networks
, list
) {
410 if (memcmp(n
->auth_key
, auth_key
, sizeof(n
->auth_key
)) != 0)
416 n
= calloc(1, sizeof(*n
));
417 n
->search_timer
.cb
= udht_search_timer_cb
;
418 memcpy(n
->auth_key
, auth_key
, sizeof(n
->auth_key
));
419 udht_id_hash(n
->id
, n
->auth_key
, sizeof(n
->auth_key
));
420 list_add_tail(&n
->list
, &networks
);
423 uloop_timeout_set(&n
->search_timer
, 1);
429 void udht_network_flush(int seq
)
431 struct network_entry
*n
, *tmp
;
433 list_for_each_entry_safe(n
, tmp
, &networks
, list
) {
434 if (seq
>= 0 && (n
->seq
< 0 || n
->seq
== seq
))
438 uloop_timeout_cancel(&n
->search_timer
);
445 udht_status_check(struct uloop_timeout
*t
)
447 int good
= 0, dubious
= 0, incoming
= 0;
448 static int prev_good
, prev_dubious
, prev_incoming
;
451 uloop_timeout_set(t
, 1000);
453 dht_nodes(AF_INET
, &good
, &dubious
, NULL
, &incoming
);
454 if (good
!= prev_good
|| dubious
!= prev_dubious
|| incoming
!= prev_incoming
)
455 fprintf(stderr
, "DHT status: good=%d, dubious=%d, incoming=%d\n", good
, dubious
, incoming
);
458 prev_dubious
= dubious
;
459 prev_incoming
= incoming
;
464 if (good
< 4 || good
+ dubious
< 8) {
465 if (state
.tick
> 45 && !state
.bootstrap_added
)
466 udht_add_bootstrap_peer();
471 state
.dht_ready
= true;
472 fprintf(stderr
, "DHT is ready\n");
477 udht_load_nodes(const char *filename
)
479 struct blob_attr
*data
, *cur
;
484 f
= fopen(filename
, "r");
488 data
= malloc(sizeof(struct blob_attr
));
489 if (fread(data
, sizeof(struct blob_attr
), 1, f
) != 1)
492 len
= blob_pad_len(data
);
493 if (len
<= sizeof(struct blob_attr
))
496 if (len
>= 256 * 1024)
499 data
= realloc(data
, len
);
500 if (fread(data
+ 1, len
- sizeof(struct blob_attr
), 1, f
) != 1)
503 blob_for_each_attr(cur
, data
, rem
) {
504 void *entry
= blob_data(cur
);
506 if (blob_len(cur
) == 6) {
507 struct sockaddr_in sin
= {
508 .sin_family
= AF_INET
,
509 .sin_addr
= *(struct in_addr
*)entry
,
510 .sin_port
= *(uint16_t *)(entry
+ 4),
512 udht_add_peer(&sin
, sizeof(sin
));
523 udht_save_nodes(const char *filename
)
525 struct sockaddr_in sin
[128];
526 struct sockaddr_in6 sin6
[128];
527 int n_sin
= ARRAY_SIZE(sin
);
528 int n_sin6
= ARRAY_SIZE(sin6
);
535 if (dht_get_nodes(sin
, &n_sin
, sin6
, &n_sin6
) <= 0)
541 blob_buf_init(&b
, 0);
542 for (i
= 0; i
< n_sin
; i
++) {
546 } __attribute__((packed
)) data
= {
547 .addr
= sin
[i
].sin_addr
,
548 .port
= sin
[i
].sin_port
,
550 blob_put(&b
, 4, &data
, sizeof(data
));
553 f
= fopen(filename
, "w");
557 fwrite(b
.head
, blob_pad_len(b
.head
), 1, f
);
562 static int usage(const char *progname
)
564 fprintf(stderr
, "Usage: %s [<options>] <id string>\n"
566 " -d Enable debug mode\n"
567 " -n <file> Set node filename\n"
568 " -N <key> Add network key\n"
574 static void udht_disconnect(struct uloop_timeout
*t
)
576 struct peer_entry
*p
, *tmp
;
581 list_for_each_entry_safe(p
, tmp
, &bootstrap_peers
, list
) {
586 uloop_timeout_cancel(&disconnect_timer
);
587 udht_connected
= false;
588 udht_network_flush(-1);
590 uloop_timeout_cancel(&peer_timer
);
591 uloop_timeout_cancel(&status_timer
);
592 uloop_timeout_cancel(&periodic_timer
);
594 udht_save_nodes(node_file
);
597 memset(&state
, 0, sizeof(state
));
606 int udht_reconnect(void)
608 udht_disconnect(&disconnect_timer
);
610 if (udht_open_socket(unix_path
) < 0)
613 if (dht_init(dht_unix_fd
, -1, local_id
, NULL
) < 0) {
618 udht_connected
= true;
619 fprintf(stderr
, "DHT connected\n");
621 udht_load_nodes(node_file
);
623 uloop_timeout_set(&peer_timer
, 1);
624 uloop_timeout_set(&status_timer
, 1000);
629 int main(int argc
, char **argv
)
631 const char *progname
= argv
[0];
632 uint8_t auth_key
[CURVE25519_KEY_SIZE
];
635 while ((ch
= getopt(argc
, argv
, "dN:n:u:")) != -1) {
638 if (b64_decode(optarg
, auth_key
, CURVE25519_KEY_SIZE
) != CURVE25519_KEY_SIZE
) {
639 fprintf(stderr
, "Invalid network key\n");
643 udht_network_add(auth_key
, -1);
655 return usage(progname
);
663 return usage(progname
);
665 udht_id_hash(local_id
, argv
[0], strlen(argv
[0]));
667 status_timer
.cb
= udht_status_check
;
668 periodic_timer
.cb
= udht_timer_cb
;
669 peer_timer
.cb
= udht_peer_timer_cb
;
670 disconnect_timer
.cb
= udht_disconnect
;
676 if (udht_reconnect() < 0) {
677 fprintf(stderr
, "Failed to connect to unetd\n");
685 udht_disconnect(&disconnect_timer
);