summaryrefslogtreecommitdiff
path: root/toxcore
diff options
context:
space:
mode:
Diffstat (limited to 'toxcore')
-rw-r--r--toxcore/DHT.c315
-rw-r--r--toxcore/DHT.h36
-rw-r--r--toxcore/LAN_discovery.c85
-rw-r--r--toxcore/Lossless_UDP.c58
-rw-r--r--toxcore/Lossless_UDP.h6
-rw-r--r--toxcore/Messenger.c74
-rw-r--r--toxcore/Messenger.h2
-rw-r--r--toxcore/friend_requests.c12
-rw-r--r--toxcore/group_chats.c4
-rw-r--r--toxcore/net_crypto.c2
-rw-r--r--toxcore/network.c604
-rw-r--r--toxcore/network.h100
-rw-r--r--toxcore/ping.c10
-rw-r--r--toxcore/tox.c12
-rw-r--r--toxcore/tox.h65
-rw-r--r--toxcore/util.c69
-rw-r--r--toxcore/util.h20
17 files changed, 1265 insertions, 209 deletions
diff --git a/toxcore/DHT.c b/toxcore/DHT.c
index e2d91256..1798ea1a 100644
--- a/toxcore/DHT.c
+++ b/toxcore/DHT.c
@@ -115,11 +115,6 @@ static int client_id_cmp(ClientPair p1, ClientPair p2)
115 return c; 115 return c;
116} 116}
117 117
118static int ipport_equal(IP_Port a, IP_Port b)
119{
120 return (a.ip.uint32 == b.ip.uint32) && (a.port == b.port);
121}
122
123static int id_equal(uint8_t *a, uint8_t *b) 118static int id_equal(uint8_t *a, uint8_t *b)
124{ 119{
125 return memcmp(a, b, CLIENT_ID_SIZE) == 0; 120 return memcmp(a, b, CLIENT_ID_SIZE) == 0;
@@ -142,20 +137,23 @@ static int client_in_list(Client_data *list, uint32_t length, uint8_t *client_id
142 uint32_t i; 137 uint32_t i;
143 uint64_t temp_time = unix_time(); 138 uint64_t temp_time = unix_time();
144 139
145 for (i = 0; i < length; ++i) { 140 /* if client_id is in list, find it and maybe overwrite ip_port */
146 /* If ip_port is assigned to a different client_id replace it */ 141 for (i = 0; i < length; ++i)
147 if (ipport_equal(list[i].ip_port, ip_port)) { 142 if (id_equal(list[i].client_id, client_id)) {
148 memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE); 143 /* Refresh the client timestamp. */
144 list[i].timestamp = temp_time;
145 list[i].ip_port = ip_port;
146 return 1;
149 } 147 }
150 148
151 if (id_equal(list[i].client_id, client_id)) { 149 /* client_id not in list yet: find ip_port to overwrite */
150 for (i = 0; i < length; ++i)
151 if (ipport_equal(&list[i].ip_port, &ip_port)) {
152 /* Refresh the client timestamp. */ 152 /* Refresh the client timestamp. */
153 list[i].timestamp = temp_time; 153 list[i].timestamp = temp_time;
154 list[i].ip_port.ip.uint32 = ip_port.ip.uint32; 154 memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE);
155 list[i].ip_port.port = ip_port.port;
156 return 1; 155 return 1;
157 } 156 }
158 }
159 157
160 return 0; 158 return 0;
161} 159}
@@ -197,18 +195,37 @@ static int friend_number(DHT *dht, uint8_t *client_id)
197 * 195 *
198 * TODO: For the love of based Allah make this function cleaner and much more efficient. 196 * TODO: For the love of based Allah make this function cleaner and much more efficient.
199 */ 197 */
200static int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list) 198static int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list, sa_family_t sa_family)
201{ 199{
202 uint32_t i, j, k; 200 uint32_t i, j, k;
203 uint64_t temp_time = unix_time(); 201 uint64_t temp_time = unix_time();
204 int num_nodes = 0, closest, tout, inlist; 202 int num_nodes = 0, closest, tout, inlist, ipv46x;
205 203
206 for (i = 0; i < LCLIENT_LIST; ++i) { 204 for (i = 0; i < LCLIENT_LIST; ++i) {
207 tout = is_timeout(temp_time, dht->close_clientlist[i].timestamp, BAD_NODE_TIMEOUT); 205 tout = is_timeout(temp_time, dht->close_clientlist[i].timestamp, BAD_NODE_TIMEOUT);
208 inlist = client_in_nodelist(nodes_list, MAX_SENT_NODES, dht->close_clientlist[i].client_id); 206 inlist = client_in_nodelist(nodes_list, MAX_SENT_NODES, dht->close_clientlist[i].client_id);
209 207
208 /*
209 * NET_PACKET_SEND_NODES sends ONLY AF_INET
210 * NET_PACKET_SEND_NODES_EX sends ALL BUT AF_INET (i.e. AF_INET6),
211 * it could send both, but then a) packet size is an issue and
212 * b) duplicates the traffic (NET_PACKET_SEND_NODES has to be
213 * sent anyways for backwards compatibility)
214 * we COULD send ALL as NET_PACKET_SEND_NODES_EX if we KNEW that the
215 * partner node understands - that's true if *they* are on IPv6
216 */
217#ifdef TOX_ENABLE_IPV6
218 ipv46x = 0;
219 if (sa_family == AF_INET)
220 ipv46x = dht->close_clientlist[i].ip_port.ip.family != AF_INET;
221 else
222 ipv46x = dht->close_clientlist[i].ip_port.ip.family == AF_INET;
223#else
224 ipv46x = sa_family != AF_INET;
225#endif
226
210 /* If node isn't good or is already in list. */ 227 /* If node isn't good or is already in list. */
211 if (tout || inlist) 228 if (tout || inlist || ipv46x)
212 continue; 229 continue;
213 230
214 if (num_nodes < MAX_SENT_NODES) { 231 if (num_nodes < MAX_SENT_NODES) {
@@ -247,8 +264,18 @@ static int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list
247 MAX_SENT_NODES, 264 MAX_SENT_NODES,
248 dht->friends_list[i].client_list[j].client_id); 265 dht->friends_list[i].client_list[j].client_id);
249 266
267#ifdef TOX_ENABLE_IPV6
268 ipv46x = 0;
269 if (sa_family == AF_INET)
270 ipv46x = dht->friends_list[i].client_list[j].ip_port.ip.family != AF_INET;
271 else
272 ipv46x = dht->friends_list[i].client_list[j].ip_port.ip.family == AF_INET;
273#else
274 ipv46x = sa_family != AF_INET;
275#endif
276
250 /* If node isn't good or is already in list. */ 277 /* If node isn't good or is already in list. */
251 if (tout || inlist) 278 if (tout || inlist || ipv46x)
252 continue; 279 continue;
253 280
254 if (num_nodes < MAX_SENT_NODES) { 281 if (num_nodes < MAX_SENT_NODES) {
@@ -301,7 +328,7 @@ static int replace_bad( Client_data *list,
301 memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE); 328 memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE);
302 list[i].ip_port = ip_port; 329 list[i].ip_port = ip_port;
303 list[i].timestamp = temp_time; 330 list[i].timestamp = temp_time;
304 list[i].ret_ip_port.ip.uint32 = 0; 331 ip_reset(&list[i].ret_ip_port.ip);
305 list[i].ret_ip_port.port = 0; 332 list[i].ret_ip_port.port = 0;
306 list[i].ret_timestamp = 0; 333 list[i].ret_timestamp = 0;
307 return 0; 334 return 0;
@@ -349,7 +376,7 @@ static int replace_good( Client_data *list,
349 memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE); 376 memcpy(list[i].client_id, client_id, CLIENT_ID_SIZE);
350 list[i].ip_port = ip_port; 377 list[i].ip_port = ip_port;
351 list[i].timestamp = temp_time; 378 list[i].timestamp = temp_time;
352 list[i].ret_ip_port.ip.uint32 = 0; 379 ip_reset(&list[i].ret_ip_port.ip);
353 list[i].ret_ip_port.port = 0; 380 list[i].ret_ip_port.port = 0;
354 list[i].ret_timestamp = 0; 381 list[i].ret_timestamp = 0;
355 return 0; 382 return 0;
@@ -447,13 +474,13 @@ static int is_gettingnodes(DHT *dht, IP_Port ip_port, uint64_t ping_id)
447 if (!is_timeout(temp_time, dht->send_nodes[i].timestamp, PING_TIMEOUT)) { 474 if (!is_timeout(temp_time, dht->send_nodes[i].timestamp, PING_TIMEOUT)) {
448 pinging = 0; 475 pinging = 0;
449 476
450 if (ip_port.ip.uint32 != 0 && ipport_equal(dht->send_nodes[i].ip_port, ip_port)) 477 if (ping_id != 0 && dht->send_nodes[i].ping_id == ping_id)
451 ++pinging; 478 ++pinging;
452 479
453 if (ping_id != 0 && dht->send_nodes[i].ping_id == ping_id) 480 if (ip_isset(&ip_port.ip) && ipport_equal(&dht->send_nodes[i].ip_port, &ip_port))
454 ++pinging; 481 ++pinging;
455 482
456 if (pinging == (ping_id != 0) + (ip_port.ip.uint32 != 0)) 483 if (pinging == (ping_id != 0) + (ip_isset(&ip_port.ip) != 0))
457 return 1; 484 return 1;
458 } 485 }
459 } 486 }
@@ -518,44 +545,65 @@ static int getnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *cli
518 memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES); 545 memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES);
519 memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len); 546 memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len);
520 547
521 return sendpacket(dht->c->lossless_udp->net->sock, ip_port, data, sizeof(data)); 548 return sendpacket(dht->c->lossless_udp->net, ip_port, data, sizeof(data));
522} 549}
523 550
524/* Send a send nodes response. */ 551/* Send a send nodes response. */
552/* because of BINARY compatibility, the Node_format MUST BE Node4_format,
553 * IPv6 nodes are sent in a different message */
525static int sendnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *client_id, uint64_t ping_id) 554static int sendnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *client_id, uint64_t ping_id)
526{ 555{
527 /* Check if packet is going to be sent to ourself. */ 556 /* Check if packet is going to be sent to ourself. */
528 if (id_equal(public_key, dht->c->self_public_key)) 557 if (id_equal(public_key, dht->c->self_public_key))
529 return -1; 558 return -1;
530 559
560 size_t Node4_format_size = sizeof(Node4_format);
531 uint8_t data[1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(ping_id) 561 uint8_t data[1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(ping_id)
532 + sizeof(Node_format) * MAX_SENT_NODES + ENCRYPTION_PADDING]; 562 + Node4_format_size * MAX_SENT_NODES + ENCRYPTION_PADDING];
533 563
534 Node_format nodes_list[MAX_SENT_NODES]; 564 Node_format nodes_list[MAX_SENT_NODES];
535 int num_nodes = get_close_nodes(dht, client_id, nodes_list); 565 int num_nodes = get_close_nodes(dht, client_id, nodes_list, AF_INET);
536 566
537 if (num_nodes == 0) 567 if (num_nodes == 0)
538 return 0; 568 return 0;
539 569
540 uint8_t plain[sizeof(ping_id) + sizeof(Node_format) * MAX_SENT_NODES]; 570 uint8_t plain[sizeof(ping_id) + Node4_format_size * MAX_SENT_NODES];
541 uint8_t encrypt[sizeof(ping_id) + sizeof(Node_format) * MAX_SENT_NODES + ENCRYPTION_PADDING]; 571 uint8_t encrypt[sizeof(ping_id) + Node4_format_size * MAX_SENT_NODES + ENCRYPTION_PADDING];
542 uint8_t nonce[crypto_box_NONCEBYTES]; 572 uint8_t nonce[crypto_box_NONCEBYTES];
543 random_nonce(nonce); 573 random_nonce(nonce);
544 574
545 memcpy(plain, &ping_id, sizeof(ping_id)); 575 memcpy(plain, &ping_id, sizeof(ping_id));
546 memcpy(plain + sizeof(ping_id), nodes_list, num_nodes * sizeof(Node_format)); 576#ifdef TOX_ENABLE_IPV6
577 Node4_format *nodes4_list = (Node4_format *)(plain + sizeof(ping_id));
578 int i, num_nodes_ok = 0;
579 for(i = 0; i < num_nodes; i++)
580 if (nodes_list[i].ip_port.ip.family == AF_INET) {
581 memcpy(nodes4_list[num_nodes_ok].client_id, nodes_list[i].client_id, CLIENT_ID_SIZE);
582 nodes4_list[num_nodes_ok].ip_port.ip.uint32 = nodes_list[i].ip_port.ip.ip4.uint32;
583 nodes4_list[num_nodes_ok].ip_port.port = nodes_list[i].ip_port.port;
584
585 num_nodes_ok++;
586 }
587
588 if (num_nodes_ok < num_nodes) {
589 /* shouldn't happen */
590 num_nodes = num_nodes_ok;
591 }
592#else
593 memcpy(plain + sizeof(ping_id), nodes_list, num_nodes * Node4_format_size);
594#endif
547 595
548 int len = encrypt_data( public_key, 596 int len = encrypt_data( public_key,
549 dht->c->self_secret_key, 597 dht->c->self_secret_key,
550 nonce, 598 nonce,
551 plain, 599 plain,
552 sizeof(ping_id) + num_nodes * sizeof(Node_format), 600 sizeof(ping_id) + num_nodes * Node4_format_size,
553 encrypt ); 601 encrypt );
554 602
555 if (len == -1) 603 if (len == -1)
556 return -1; 604 return -1;
557 605
558 if ((unsigned int)len != sizeof(ping_id) + num_nodes * sizeof(Node_format) + ENCRYPTION_PADDING) 606 if ((unsigned int)len != sizeof(ping_id) + num_nodes * Node4_format_size + ENCRYPTION_PADDING)
559 return -1; 607 return -1;
560 608
561 data[0] = NET_PACKET_SEND_NODES; 609 data[0] = NET_PACKET_SEND_NODES;
@@ -563,9 +611,57 @@ static int sendnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *cl
563 memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES); 611 memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES);
564 memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len); 612 memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len);
565 613
566 return sendpacket(dht->c->lossless_udp->net->sock, ip_port, data, 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + len); 614 return sendpacket(dht->c->lossless_udp->net, ip_port, data, 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + len);
567} 615}
568 616
617#ifdef TOX_ENABLE_IPV6
618/* Send a send nodes response: message for IPv6 nodes */
619static int sendnodes_ex(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *client_id, uint64_t ping_id)
620{
621 /* Check if packet is going to be sent to ourself. */
622 if (id_equal(public_key, dht->c->self_public_key))
623 return -1;
624
625 size_t Node_format_size = sizeof(Node_format);
626 uint8_t data[1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(ping_id)
627 + Node_format_size * MAX_SENT_NODES + ENCRYPTION_PADDING];
628
629 Node_format nodes_list[MAX_SENT_NODES];
630 int num_nodes = get_close_nodes(dht, client_id, nodes_list, AF_INET6);
631
632 if (num_nodes == 0)
633 return 0;
634
635 uint8_t plain[sizeof(ping_id) + Node_format_size * MAX_SENT_NODES];
636 uint8_t encrypt[sizeof(ping_id) + Node_format_size * MAX_SENT_NODES + ENCRYPTION_PADDING];
637 uint8_t nonce[crypto_box_NONCEBYTES];
638 random_nonce(nonce);
639
640 memcpy(plain, &ping_id, sizeof(ping_id));
641 memcpy(plain + sizeof(ping_id), nodes_list, num_nodes * Node_format_size);
642
643 int len = encrypt_data( public_key,
644 dht->c->self_secret_key,
645 nonce,
646 plain,
647 sizeof(ping_id) + num_nodes * Node_format_size,
648 encrypt );
649
650 if (len == -1)
651 return -1;
652
653 if ((unsigned int)len != sizeof(ping_id) + num_nodes * Node_format_size + ENCRYPTION_PADDING)
654 return -1;
655
656 data[0] = NET_PACKET_SEND_NODES_EX;
657 memcpy(data + 1, dht->c->self_public_key, CLIENT_ID_SIZE);
658 memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES);
659 memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len);
660
661 return sendpacket(dht->c->lossless_udp->net, ip_port, data, 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + len);
662}
663#endif
664
569static int handle_getnodes(void *object, IP_Port source, uint8_t *packet, uint32_t length) 665static int handle_getnodes(void *object, IP_Port source, uint8_t *packet, uint32_t length)
570{ 666{
571 DHT *dht = object; 667 DHT *dht = object;
@@ -593,6 +689,9 @@ static int handle_getnodes(void *object, IP_Port source, uint8_t *packet, uint32
593 689
594 memcpy(&ping_id, plain, sizeof(ping_id)); 690 memcpy(&ping_id, plain, sizeof(ping_id));
595 sendnodes(dht, source, packet + 1, plain + sizeof(ping_id), ping_id); 691 sendnodes(dht, source, packet + 1, plain + sizeof(ping_id), ping_id);
692#ifdef TOX_ENABLE_IPV6
693 sendnodes_ex(dht, source, packet + 1, plain + sizeof(ping_id), ping_id);
694#endif
596 695
597 //send_ping_request(dht, source, packet + 1); /* TODO: make this smarter? */ 696 //send_ping_request(dht, source, packet + 1); /* TODO: make this smarter? */
598 697
@@ -606,22 +705,23 @@ static int handle_sendnodes(void *object, IP_Port source, uint8_t *packet, uint3
606 uint32_t cid_size = 1 + CLIENT_ID_SIZE; 705 uint32_t cid_size = 1 + CLIENT_ID_SIZE;
607 cid_size += crypto_box_NONCEBYTES + sizeof(ping_id) + ENCRYPTION_PADDING; 706 cid_size += crypto_box_NONCEBYTES + sizeof(ping_id) + ENCRYPTION_PADDING;
608 707
609 if (length > (cid_size + sizeof(Node_format) * MAX_SENT_NODES) || 708 size_t Node4_format_size = sizeof(Node4_format);
610 ((length - cid_size) % sizeof(Node_format)) != 0 || 709 if (length > (cid_size + Node4_format_size * MAX_SENT_NODES) ||
611 (length < cid_size + sizeof(Node_format))) 710 ((length - cid_size) % Node4_format_size) != 0 ||
711 (length < cid_size + Node4_format_size))
612 return 1; 712 return 1;
613 713
614 uint32_t num_nodes = (length - cid_size) / sizeof(Node_format); 714 uint32_t num_nodes = (length - cid_size) / Node4_format_size;
615 uint8_t plain[sizeof(ping_id) + sizeof(Node_format) * MAX_SENT_NODES]; 715 uint8_t plain[sizeof(ping_id) + Node4_format_size * MAX_SENT_NODES];
616 716
617 int len = decrypt_data( 717 int len = decrypt_data(
618 packet + 1, 718 packet + 1,
619 dht->c->self_secret_key, 719 dht->c->self_secret_key,
620 packet + 1 + CLIENT_ID_SIZE, 720 packet + 1 + CLIENT_ID_SIZE,
621 packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, 721 packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES,
622 sizeof(ping_id) + num_nodes * sizeof(Node_format) + ENCRYPTION_PADDING, plain ); 722 sizeof(ping_id) + num_nodes * Node4_format_size + ENCRYPTION_PADDING, plain );
623 723
624 if ((unsigned int)len != sizeof(ping_id) + num_nodes * sizeof(Node_format)) 724 if ((unsigned int)len != sizeof(ping_id) + num_nodes * Node4_format_size)
625 return 1; 725 return 1;
626 726
627 memcpy(&ping_id, plain, sizeof(ping_id)); 727 memcpy(&ping_id, plain, sizeof(ping_id));
@@ -629,12 +729,78 @@ static int handle_sendnodes(void *object, IP_Port source, uint8_t *packet, uint3
629 if (!is_gettingnodes(dht, source, ping_id)) 729 if (!is_gettingnodes(dht, source, ping_id))
630 return 1; 730 return 1;
631 731
732 uint32_t i;
632 Node_format nodes_list[MAX_SENT_NODES]; 733 Node_format nodes_list[MAX_SENT_NODES];
734
735#ifdef TOX_ENABLE_IPV6
736 Node4_format *nodes4_list = (Node4_format *)(plain + sizeof(ping_id));
737
738 int num_nodes_ok = 0;
739 for(i = 0; i < num_nodes; i++)
740 if ((nodes4_list[i].ip_port.ip.uint32 != 0) && (nodes4_list[i].ip_port.ip.uint32 != ~0)) {
741 memcpy(nodes_list[num_nodes_ok].client_id, nodes4_list[i].client_id, CLIENT_ID_SIZE);
742 nodes_list[num_nodes_ok].ip_port.ip.family = AF_INET;
743 nodes_list[num_nodes_ok].ip_port.ip.ip4.uint32 = nodes4_list[i].ip_port.ip.uint32;
744 nodes_list[num_nodes_ok].ip_port.port = nodes4_list[i].ip_port.port;
745
746 num_nodes_ok++;
747 }
748
749 if (num_nodes_ok < num_nodes) {
750 /* shouldn't happen */
751 num_nodes = num_nodes_ok;
752 }
753#else
633 memcpy(nodes_list, plain + sizeof(ping_id), num_nodes * sizeof(Node_format)); 754 memcpy(nodes_list, plain + sizeof(ping_id), num_nodes * sizeof(Node_format));
755#endif
634 756
635 addto_lists(dht, source, packet + 1); 757 addto_lists(dht, source, packet + 1);
636 758
759 for (i = 0; i < num_nodes; ++i) {
760 send_ping_request(dht->ping, dht->c, nodes_list[i].ip_port, nodes_list[i].client_id);
761 returnedip_ports(dht, nodes_list[i].ip_port, nodes_list[i].client_id, packet + 1);
762 }
763
764 return 0;
765}
766
767#ifdef TOX_ENABLE_IPV6
768static int handle_sendnodes_ex(void *object, IP_Port source, uint8_t *packet, uint32_t length)
769{
770 DHT *dht = object;
771 uint64_t ping_id;
772 uint32_t cid_size = 1 + CLIENT_ID_SIZE;
773 cid_size += crypto_box_NONCEBYTES + sizeof(ping_id) + ENCRYPTION_PADDING;
774
775 size_t Node_format_size = sizeof(Node4_format);
776 if (length > (cid_size + Node_format_size * MAX_SENT_NODES) ||
777 ((length - cid_size) % Node_format_size) != 0 ||
778 (length < cid_size + Node_format_size))
779 return 1;
780
781 uint32_t num_nodes = (length - cid_size) / Node_format_size;
782 uint8_t plain[sizeof(ping_id) + Node_format_size * MAX_SENT_NODES];
783
784 int len = decrypt_data(
785 packet + 1,
786 dht->c->self_secret_key,
787 packet + 1 + CLIENT_ID_SIZE,
788 packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES,
789 sizeof(ping_id) + num_nodes * Node_format_size + ENCRYPTION_PADDING, plain );
790
791 if ((unsigned int)len != sizeof(ping_id) + num_nodes * Node_format_size)
792 return 1;
793
794 memcpy(&ping_id, plain, sizeof(ping_id));
795
796 if (!is_gettingnodes(dht, source, ping_id))
797 return 1;
798
637 uint32_t i; 799 uint32_t i;
800 Node_format nodes_list[MAX_SENT_NODES];
801 memcpy(nodes_list, plain + sizeof(ping_id), num_nodes * sizeof(Node_format));
802
803 addto_lists(dht, source, packet + 1);
638 804
639 for (i = 0; i < num_nodes; ++i) { 805 for (i = 0; i < num_nodes; ++i) {
640 send_ping_request(dht->ping, dht->c, nodes_list[i].ip_port, nodes_list[i].client_id); 806 send_ping_request(dht->ping, dht->c, nodes_list[i].ip_port, nodes_list[i].client_id);
@@ -643,6 +809,7 @@ static int handle_sendnodes(void *object, IP_Port source, uint8_t *packet, uint3
643 809
644 return 0; 810 return 0;
645} 811}
812#endif
646 813
647/*----------------------------------------------------------------------------------*/ 814/*----------------------------------------------------------------------------------*/
648/*------------------------END of packet handling functions--------------------------*/ 815/*------------------------END of packet handling functions--------------------------*/
@@ -703,27 +870,30 @@ int DHT_delfriend(DHT *dht, uint8_t *client_id)
703} 870}
704 871
705/* TODO: Optimize this. */ 872/* TODO: Optimize this. */
706IP_Port DHT_getfriendip(DHT *dht, uint8_t *client_id) 873int DHT_getfriendip(DHT *dht, uint8_t *client_id, IP_Port *ip_port)
707{ 874{
708 uint32_t i, j; 875 uint32_t i, j;
709 uint64_t temp_time = unix_time(); 876 uint64_t temp_time = unix_time();
710 IP_Port empty = {{{{0}}, 0, 0}}; 877
878 ip_reset(&ip_port->ip);
879 ip_port->port = 0;
711 880
712 for (i = 0; i < dht->num_friends; ++i) { 881 for (i = 0; i < dht->num_friends; ++i) {
713 /* Equal */ 882 /* Equal */
714 if (id_equal(dht->friends_list[i].client_id, client_id)) { 883 if (id_equal(dht->friends_list[i].client_id, client_id)) {
715 for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) { 884 for (j = 0; j < MAX_FRIEND_CLIENTS; ++j) {
716 if (id_equal(dht->friends_list[i].client_list[j].client_id, client_id) 885 if (id_equal(dht->friends_list[i].client_list[j].client_id, client_id)
717 && !is_timeout(temp_time, dht->friends_list[i].client_list[j].timestamp, BAD_NODE_TIMEOUT)) 886 && !is_timeout(temp_time, dht->friends_list[i].client_list[j].timestamp, BAD_NODE_TIMEOUT)) {
718 return dht->friends_list[i].client_list[j].ip_port; 887 *ip_port = dht->friends_list[i].client_list[j].ip_port;
888 return 1;
889 }
719 } 890 }
720 891
721 return empty; 892 return 0;
722 } 893 }
723 } 894 }
724 895
725 empty.ip.uint32 = 1; 896 return -1;
726 return empty;
727} 897}
728 898
729/* Ping each client in the "friends" list every PING_INTERVAL seconds. Send a get nodes request 899/* Ping each client in the "friends" list every PING_INTERVAL seconds. Send a get nodes request
@@ -808,6 +978,18 @@ void DHT_bootstrap(DHT *dht, IP_Port ip_port, uint8_t *public_key)
808 getnodes(dht, ip_port, public_key, dht->c->self_public_key); 978 getnodes(dht, ip_port, public_key, dht->c->self_public_key);
809 send_ping_request(dht->ping, dht->c, ip_port, public_key); 979 send_ping_request(dht->ping, dht->c, ip_port, public_key);
810} 980}
981int DHT_bootstrap_ex(DHT *dht, const char *address, uint8_t ipv6enabled, uint16_t port, uint8_t *public_key)
982{
983 IP_Port ip_port;
984 ip_init(&ip_port.ip, ipv6enabled);
985 if (addr_resolve_or_parse_ip(address, &ip_port.ip)) {
986 ip_port.port = port;
987 DHT_bootstrap(dht, ip_port, public_key);
988 return 1;
989 }
990 else
991 return 0;
992}
811 993
812/* Send the given packet to node with client_id 994/* Send the given packet to node with client_id
813 * 995 *
@@ -819,7 +1001,7 @@ int route_packet(DHT *dht, uint8_t *client_id, uint8_t *packet, uint32_t length)
819 1001
820 for (i = 0; i < LCLIENT_LIST; ++i) { 1002 for (i = 0; i < LCLIENT_LIST; ++i) {
821 if (id_equal(client_id, dht->close_clientlist[i].client_id)) 1003 if (id_equal(client_id, dht->close_clientlist[i].client_id))
822 return sendpacket(dht->c->lossless_udp->net->sock, dht->close_clientlist[i].ip_port, packet, length); 1004 return sendpacket(dht->c->lossless_udp->net, dht->close_clientlist[i].ip_port, packet, length);
823 } 1005 }
824 1006
825 return -1; 1007 return -1;
@@ -848,7 +1030,7 @@ static int friend_iplist(DHT *dht, IP_Port *ip_portlist, uint16_t friend_num)
848 client = &friend->client_list[i]; 1030 client = &friend->client_list[i];
849 1031
850 /* If ip is not zero and node is good. */ 1032 /* If ip is not zero and node is good. */
851 if (client->ret_ip_port.ip.uint32 != 0 && !is_timeout(temp_time, client->ret_timestamp, BAD_NODE_TIMEOUT)) { 1033 if (ip_isset(&client->ret_ip_port.ip) && !is_timeout(temp_time, client->ret_timestamp, BAD_NODE_TIMEOUT)) {
852 1034
853 if (id_equal(client->client_id, friend->client_id)) 1035 if (id_equal(client->client_id, friend->client_id))
854 return 0; 1036 return 0;
@@ -890,8 +1072,8 @@ int route_tofriend(DHT *dht, uint8_t *friend_id, uint8_t *packet, uint32_t lengt
890 client = &friend->client_list[i]; 1072 client = &friend->client_list[i];
891 1073
892 /* If ip is not zero and node is good. */ 1074 /* If ip is not zero and node is good. */
893 if (client->ret_ip_port.ip.uint32 != 0 && !is_timeout(temp_time, client->ret_timestamp, BAD_NODE_TIMEOUT)) { 1075 if (ip_isset(&client->ret_ip_port.ip) && !is_timeout(temp_time, client->ret_timestamp, BAD_NODE_TIMEOUT)) {
894 int retval = sendpacket(dht->c->lossless_udp->net->sock, client->ip_port, packet, length); 1076 int retval = sendpacket(dht->c->lossless_udp->net, client->ip_port, packet, length);
895 1077
896 if ((unsigned int)retval == length) 1078 if ((unsigned int)retval == length)
897 ++sent; 1079 ++sent;
@@ -924,7 +1106,7 @@ static int routeone_tofriend(DHT *dht, uint8_t *friend_id, uint8_t *packet, uint
924 client = &friend->client_list[i]; 1106 client = &friend->client_list[i];
925 1107
926 /* If ip is not zero and node is good. */ 1108 /* If ip is not zero and node is good. */
927 if (client->ret_ip_port.ip.uint32 != 0 && !is_timeout(temp_time, client->ret_timestamp, BAD_NODE_TIMEOUT)) { 1109 if (ip_isset(&client->ret_ip_port.ip) && !is_timeout(temp_time, client->ret_timestamp, BAD_NODE_TIMEOUT)) {
928 ip_list[n] = client->ip_port; 1110 ip_list[n] = client->ip_port;
929 ++n; 1111 ++n;
930 } 1112 }
@@ -933,7 +1115,7 @@ static int routeone_tofriend(DHT *dht, uint8_t *friend_id, uint8_t *packet, uint
933 if (n < 1) 1115 if (n < 1)
934 return 0; 1116 return 0;
935 1117
936 int retval = sendpacket(dht->c->lossless_udp->net->sock, ip_list[rand() % n], packet, length); 1118 int retval = sendpacket(dht->c->lossless_udp->net, ip_list[rand() % n], packet, length);
937 1119
938 if ((unsigned int)retval == length) 1120 if ((unsigned int)retval == length)
939 return 1; 1121 return 1;
@@ -1032,7 +1214,8 @@ static int handle_NATping(void *object, IP_Port source, uint8_t *source_pubkey,
1032 */ 1214 */
1033static IP NAT_commonip(IP_Port *ip_portlist, uint16_t len, uint16_t min_num) 1215static IP NAT_commonip(IP_Port *ip_portlist, uint16_t len, uint16_t min_num)
1034{ 1216{
1035 IP zero = {{0}}; 1217 IP zero;
1218 ip_reset(&zero);
1036 1219
1037 if (len > MAX_FRIEND_CLIENTS) 1220 if (len > MAX_FRIEND_CLIENTS)
1038 return zero; 1221 return zero;
@@ -1042,7 +1225,7 @@ static IP NAT_commonip(IP_Port *ip_portlist, uint16_t len, uint16_t min_num)
1042 1225
1043 for (i = 0; i < len; ++i) { 1226 for (i = 0; i < len; ++i) {
1044 for (j = 0; j < len; ++j) { 1227 for (j = 0; j < len; ++j) {
1045 if (ip_portlist[i].ip.uint32 == ip_portlist[j].ip.uint32) 1228 if (ip_equal(&ip_portlist[i].ip, &ip_portlist[j].ip))
1046 ++numbers[i]; 1229 ++numbers[i];
1047 } 1230 }
1048 1231
@@ -1065,7 +1248,7 @@ static uint16_t NAT_getports(uint16_t *portlist, IP_Port *ip_portlist, uint16_t
1065 uint16_t num = 0; 1248 uint16_t num = 0;
1066 1249
1067 for (i = 0; i < len; ++i) { 1250 for (i = 0; i < len; ++i) {
1068 if (ip_portlist[i].ip.uint32 == ip.uint32) { 1251 if (ip_equal(&ip_portlist[i].ip, &ip)) {
1069 portlist[num] = ntohs(ip_portlist[i].port); 1252 portlist[num] = ntohs(ip_portlist[i].port);
1070 ++num; 1253 ++num;
1071 } 1254 }
@@ -1085,7 +1268,9 @@ static void punch_holes(DHT *dht, IP ip, uint16_t *port_list, uint16_t numports,
1085 for (i = dht->friends_list[friend_num].punching_index; i != top; i++) { 1268 for (i = dht->friends_list[friend_num].punching_index; i != top; i++) {
1086 /* TODO: Improve port guessing algorithm. */ 1269 /* TODO: Improve port guessing algorithm. */
1087 uint16_t port = port_list[(i / 2) % numports] + (i / (2 * numports)) * ((i % 2) ? -1 : 1); 1270 uint16_t port = port_list[(i / 2) % numports] + (i / (2 * numports)) * ((i % 2) ? -1 : 1);
1088 IP_Port pinging = {{ip, htons(port), 0}}; 1271 IP_Port pinging;
1272 ip_copy(&pinging.ip, &ip);
1273 pinging.port = htons(port);
1089 send_ping_request(dht->ping, dht->c, pinging, dht->friends_list[friend_num].client_id); 1274 send_ping_request(dht->ping, dht->c, pinging, dht->friends_list[friend_num].client_id);
1090 } 1275 }
1091 1276
@@ -1115,8 +1300,7 @@ static void do_NAT(DHT *dht)
1115 dht->friends_list[i].recvNATping_timestamp + PUNCH_INTERVAL * 2 >= temp_time) { 1300 dht->friends_list[i].recvNATping_timestamp + PUNCH_INTERVAL * 2 >= temp_time) {
1116 1301
1117 IP ip = NAT_commonip(ip_list, num, MAX_FRIEND_CLIENTS / 2); 1302 IP ip = NAT_commonip(ip_list, num, MAX_FRIEND_CLIENTS / 2);
1118 1303 if (!ip_isset(&ip))
1119 if (ip.uint32 == 0)
1120 continue; 1304 continue;
1121 1305
1122 uint16_t port_list[MAX_FRIEND_CLIENTS]; 1306 uint16_t port_list[MAX_FRIEND_CLIENTS];
@@ -1145,16 +1329,15 @@ static void do_NAT(DHT *dht)
1145 */ 1329 */
1146int add_toping(DHT *dht, uint8_t *client_id, IP_Port ip_port) 1330int add_toping(DHT *dht, uint8_t *client_id, IP_Port ip_port)
1147{ 1331{
1148 if (ip_port.ip.uint32 == 0) 1332 if (!ip_isset(&ip_port.ip))
1149 return -1; 1333 return -1;
1150 1334
1151 uint32_t i; 1335 uint32_t i;
1152 1336
1153 for (i = 0; i < MAX_TOPING; ++i) { 1337 for (i = 0; i < MAX_TOPING; ++i) {
1154 if (dht->toping[i].ip_port.ip.uint32 == 0) { 1338 if (!ip_isset(&dht->toping[i].ip_port.ip)) {
1155 memcpy(dht->toping[i].client_id, client_id, CLIENT_ID_SIZE); 1339 memcpy(dht->toping[i].client_id, client_id, CLIENT_ID_SIZE);
1156 dht->toping[i].ip_port.ip.uint32 = ip_port.ip.uint32; 1340 ipport_copy(&dht->toping[i].ip_port, &ip_port);
1157 dht->toping[i].ip_port.port = ip_port.port;
1158 return 0; 1341 return 0;
1159 } 1342 }
1160 } 1343 }
@@ -1162,8 +1345,7 @@ int add_toping(DHT *dht, uint8_t *client_id, IP_Port ip_port)
1162 for (i = 0; i < MAX_TOPING; ++i) { 1345 for (i = 0; i < MAX_TOPING; ++i) {
1163 if (id_closest(dht->c->self_public_key, dht->toping[i].client_id, client_id) == 2) { 1346 if (id_closest(dht->c->self_public_key, dht->toping[i].client_id, client_id) == 2) {
1164 memcpy(dht->toping[i].client_id, client_id, CLIENT_ID_SIZE); 1347 memcpy(dht->toping[i].client_id, client_id, CLIENT_ID_SIZE);
1165 dht->toping[i].ip_port.ip.uint32 = ip_port.ip.uint32; 1348 ipport_copy(&dht->toping[i].ip_port, &ip_port);
1166 dht->toping[i].ip_port.port = ip_port.port;
1167 return 0; 1349 return 0;
1168 } 1350 }
1169 } 1351 }
@@ -1185,11 +1367,11 @@ static void do_toping(DHT *dht)
1185 uint32_t i; 1367 uint32_t i;
1186 1368
1187 for (i = 0; i < MAX_TOPING; ++i) { 1369 for (i = 0; i < MAX_TOPING; ++i) {
1188 if (dht->toping[i].ip_port.ip.uint32 == 0) 1370 if (!ip_isset(&dht->toping[i].ip_port.ip))
1189 return; 1371 return;
1190 1372
1191 send_ping_request(dht->ping, dht->c, dht->toping[i].ip_port, dht->toping[i].client_id); 1373 send_ping_request(dht->ping, dht->c, dht->toping[i].ip_port, dht->toping[i].client_id);
1192 dht->toping[i].ip_port.ip.uint32 = 0; 1374 ip_reset(&dht->toping[i].ip_port.ip);
1193 } 1375 }
1194} 1376}
1195 1377
@@ -1216,6 +1398,9 @@ DHT *new_DHT(Net_Crypto *c)
1216 networking_registerhandler(c->lossless_udp->net, NET_PACKET_PING_RESPONSE, &handle_ping_response, temp); 1398 networking_registerhandler(c->lossless_udp->net, NET_PACKET_PING_RESPONSE, &handle_ping_response, temp);
1217 networking_registerhandler(c->lossless_udp->net, NET_PACKET_GET_NODES, &handle_getnodes, temp); 1399 networking_registerhandler(c->lossless_udp->net, NET_PACKET_GET_NODES, &handle_getnodes, temp);
1218 networking_registerhandler(c->lossless_udp->net, NET_PACKET_SEND_NODES, &handle_sendnodes, temp); 1400 networking_registerhandler(c->lossless_udp->net, NET_PACKET_SEND_NODES, &handle_sendnodes, temp);
1401#ifdef TOX_ENABLE_IPV6
1402 networking_registerhandler(c->lossless_udp->net, NET_PACKET_SEND_NODES_EX, &handle_sendnodes_ex, temp);
1403#endif
1219 init_cryptopackets(temp); 1404 init_cryptopackets(temp);
1220 cryptopacket_registerhandler(c, CRYPTO_PACKET_NAT_PING, &handle_NATping, temp); 1405 cryptopacket_registerhandler(c, CRYPTO_PACKET_NAT_PING, &handle_NATping, temp);
1221 return temp; 1406 return temp;
diff --git a/toxcore/DHT.h b/toxcore/DHT.h
index e5122b5e..90b76a2f 100644
--- a/toxcore/DHT.h
+++ b/toxcore/DHT.h
@@ -75,10 +75,22 @@ typedef struct {
75 uint64_t NATping_timestamp; 75 uint64_t NATping_timestamp;
76} DHT_Friend; 76} DHT_Friend;
77 77
78/* this must be kept even if IP_Port is expanded: wire compatibility */
79typedef struct {
80 uint8_t client_id[CLIENT_ID_SIZE];
81 IP4_Port ip_port;
82} Node4_format;
83
78typedef struct { 84typedef struct {
79 uint8_t client_id[CLIENT_ID_SIZE]; 85 uint8_t client_id[CLIENT_ID_SIZE];
80 IP_Port ip_port; 86 IP_Port ip_port;
81} Node_format; 87} Node46_format;
88
89#ifdef TOX_ENABLE_IPV6
90typedef Node46_format Node_format;
91#else
92typedef Node4_format Node_format;
93#endif
82 94
83typedef struct { 95typedef struct {
84 IP_Port ip_port; 96 IP_Port ip_port;
@@ -88,15 +100,15 @@ typedef struct {
88 100
89/*----------------------------------------------------------------------------------*/ 101/*----------------------------------------------------------------------------------*/
90typedef struct { 102typedef struct {
91 Net_Crypto *c; 103 Net_Crypto *c;
92 Client_data close_clientlist[LCLIENT_LIST]; 104 Client_data close_clientlist[LCLIENT_LIST];
93 DHT_Friend *friends_list; 105 DHT_Friend *friends_list;
94 uint16_t num_friends; 106 uint16_t num_friends;
95 Pinged send_nodes[LSEND_NODES_ARRAY]; 107 Pinged send_nodes[LSEND_NODES_ARRAY];
96 Node_format toping[MAX_TOPING]; 108 Node_format toping[MAX_TOPING];
97 uint64_t last_toping; 109 uint64_t last_toping;
98 uint64_t close_lastgetnodes; 110 uint64_t close_lastgetnodes;
99 void *ping; 111 void *ping;
100} DHT; 112} DHT;
101/*----------------------------------------------------------------------------------*/ 113/*----------------------------------------------------------------------------------*/
102 114
@@ -124,19 +136,31 @@ int DHT_delfriend(DHT *dht, uint8_t *client_id);
124 * ip must be 4 bytes long. 136 * ip must be 4 bytes long.
125 * port must be 2 bytes long. 137 * port must be 2 bytes long.
126 * 138 *
139 * !!! Signature changed!!!
140 *
141 * OLD: IP_Port DHT_getfriendip(DHT *dht, uint8_t *client_id);
142 *
127 * return ip if success. 143 * return ip if success.
128 * return ip of 0 if failure (This means the friend is either offline or we have not found him yet). 144 * return ip of 0 if failure (This means the friend is either offline or we have not found him yet).
129 * return ip of 1 if friend is not in list. 145 * return ip of 1 if friend is not in list.
146 *
147 * NEW: int DHT_getfriendip(DHT *dht, uint8_t *client_id, IP_Port *ip_port);
148 *
149 * return -1, -- if client_id does NOT refer to a friend
150 * return 0, -- if client_id refers to a friend and we failed to find the friend (yet)
151 * return 1, ip if client_id refers to a friend and we found him
130 */ 152 */
131IP_Port DHT_getfriendip(DHT *dht, uint8_t *client_id); 153int DHT_getfriendip(DHT *dht, uint8_t *client_id, IP_Port *ip_port);
132 154
133/* Run this function at least a couple times per second (It's the main loop). */ 155/* Run this function at least a couple times per second (It's the main loop). */
134void do_DHT(DHT *dht); 156void do_DHT(DHT *dht);
135 157
136/* Use this function to bootstrap the client. 158/* Use this function to bootstrap the client.
137 * Sends a get nodes request to the given node with ip port and public_key. 159 * Sends a get nodes request to the given node with ip port and public_key.
160 * DHT_bootstrap_ex() returns 1 if the address could be converted, 0 otherwise
138 */ 161 */
139void DHT_bootstrap(DHT *dht, IP_Port ip_port, uint8_t *public_key); 162void DHT_bootstrap(DHT *dht, IP_Port ip_port, uint8_t *public_key);
163int DHT_bootstrap_ex(DHT *dht, const char *address, uint8_t ipv6enabled, uint16_t port, uint8_t *public_key);
140 164
141/* Add nodes to the toping list. 165/* Add nodes to the toping list.
142 * All nodes in this list are pinged every TIME_TOPING seconds 166 * All nodes in this list are pinged every TIME_TOPING seconds
diff --git a/toxcore/LAN_discovery.c b/toxcore/LAN_discovery.c
index 1980cd93..4cbe3177 100644
--- a/toxcore/LAN_discovery.c
+++ b/toxcore/LAN_discovery.c
@@ -71,7 +71,7 @@ static uint32_t send_broadcasts(Networking_Core *net, uint16_t port, uint8_t * d
71 sock_holder = (struct sockaddr_in *)&i_faces[i].ifr_broadaddr; 71 sock_holder = (struct sockaddr_in *)&i_faces[i].ifr_broadaddr;
72 if (sock_holder != NULL) { 72 if (sock_holder != NULL) {
73 IP_Port ip_port = {{{{sock_holder->sin_addr.s_addr}}, port, 0}}; 73 IP_Port ip_port = {{{{sock_holder->sin_addr.s_addr}}, port, 0}};
74 sendpacket(net->sock, ip_port, data, 1 + crypto_box_PUBLICKEYBYTES); 74 sendpacket(net, ip_port, data, 1 + crypto_box_PUBLICKEYBYTES);
75 } 75 }
76 } 76 }
77 77
@@ -81,10 +81,32 @@ static uint32_t send_broadcasts(Networking_Core *net, uint16_t port, uint8_t * d
81#endif 81#endif
82 82
83/* Return the broadcast ip. */ 83/* Return the broadcast ip. */
84static IP broadcast_ip(void) 84static IP broadcast_ip(sa_family_t sa_family)
85{ 85{
86 IP ip; 86 IP ip;
87 ip.uint32 = ~0; 87 ip_reset(&ip);
88
89#ifdef TOX_ENABLE_IPV6
90 if (sa_family == AF_INET)
91 {
92 ip.family = AF_INET;
93 ip.ip4.uint32 = INADDR_BROADCAST;
94 }
95
96 if (sa_family == AF_INET6)
97 {
98 ip.family = AF_INET6;
99 /* FF02::1 is - according to RFC 4291 - multicast all-nodes link-local */
100 /* FE80::*: MUST be exact, for that we would need to look over all
101 * interfaces and check in which status they are */
102 ip.ip6.s6_addr[ 0] = 0xFF;
103 ip.ip6.s6_addr[ 1] = 0x02;
104 ip.ip6.s6_addr[15] = 0x01;
105 }
106#else
107 ip.uint32 = INADDR_BROADCAST;
108#endif
109
88 return ip; 110 return ip;
89} 111}
90 112
@@ -93,21 +115,42 @@ static IP broadcast_ip(void)
93 */ 115 */
94static int LAN_ip(IP ip) 116static int LAN_ip(IP ip)
95{ 117{
96 if (ip.uint8[0] == 127) /* Loopback. */ 118#ifdef TOX_ENABLE_IPV6
97 return 0; 119 if (ip.family == AF_INET) {
98 120 IP4 ip4 = ip.ip4;
99 if (ip.uint8[0] == 10) /* 10.0.0.0 to 10.255.255.255 range. */ 121#else
100 return 0; 122 IP4 ip4 = ip;
101 123#endif
102 if (ip.uint8[0] == 172 && ip.uint8[1] >= 16 && ip.uint8[1] <= 31) /* 172.16.0.0 to 172.31.255.255 range. */ 124 /* Loopback. */
103 return 0; 125 if (ip4.uint8[0] == 127)
104 126 return 0;
105 if (ip.uint8[0] == 192 && ip.uint8[1] == 168) /* 192.168.0.0 to 192.168.255.255 range. */ 127
106 return 0; 128 /* 10.0.0.0 to 10.255.255.255 range. */
107 129 if (ip4.uint8[0] == 10)
108 if (ip.uint8[0] == 169 && ip.uint8[1] == 254 && ip.uint8[2] != 0 130 return 0;
109 && ip.uint8[2] != 255)/* 169.254.1.0 to 169.254.254.255 range. */ 131
110 return 0; 132 /* 172.16.0.0 to 172.31.255.255 range. */
133 if (ip4.uint8[0] == 172 && ip4.uint8[1] >= 16 && ip4.uint8[1] <= 31)
134 return 0;
135
136 /* 192.168.0.0 to 192.168.255.255 range. */
137 if (ip4.uint8[0] == 192 && ip4.uint8[1] == 168)
138 return 0;
139
140 /* 169.254.1.0 to 169.254.254.255 range. */
141 if (ip4.uint8[0] == 169 && ip4.uint8[1] == 254 && ip4.uint8[2] != 0
142 && ip4.uint8[2] != 255)
143 return 0;
144#ifdef TOX_ENABLE_IPV6
145 }
146 else if (ip.family == AF_INET6) {
147 /* autogenerated for each interface: FE80::* (up to FEBF::*)
148 /* FF02::1 is - according to RFC 4291 - multicast all-nodes link-local */
149 if (((ip.ip6.s6_addr[0] == 0xFF) && (ip.ip6.s6_addr[1] < 3) && (ip.ip6.s6_addr[15] == 1)) ||
150 ((ip.ip6.s6_addr[0] == 0xFE) && ((ip.ip6.s6_addr[1] & 0xC0) == 0x80)))
151 return 0;
152 }
153#endif
111 154
112 return -1; 155 return -1;
113} 156}
@@ -135,8 +178,10 @@ int send_LANdiscovery(uint16_t port, Net_Crypto *c)
135#ifdef __linux 178#ifdef __linux
136 send_broadcasts(c->lossless_udp->net, port, data, 1 + crypto_box_PUBLICKEYBYTES); 179 send_broadcasts(c->lossless_udp->net, port, data, 1 + crypto_box_PUBLICKEYBYTES);
137#endif 180#endif
138 IP_Port ip_port = {{broadcast_ip(), port, 0}}; 181 IP_Port ip_port;
139 return sendpacket(c->lossless_udp->net->sock, ip_port, data, 1 + crypto_box_PUBLICKEYBYTES); 182 ip_port.ip = broadcast_ip(c->lossless_udp->net->family);
183 ip_port.port = port;
184 return sendpacket(c->lossless_udp->net, ip_port, data, 1 + crypto_box_PUBLICKEYBYTES);
140} 185}
141 186
142 187
diff --git a/toxcore/Lossless_UDP.c b/toxcore/Lossless_UDP.c
index fbb473e7..ca874562 100644
--- a/toxcore/Lossless_UDP.c
+++ b/toxcore/Lossless_UDP.c
@@ -44,9 +44,7 @@
44int getconnection_id(Lossless_UDP *ludp, IP_Port ip_port) 44int getconnection_id(Lossless_UDP *ludp, IP_Port ip_port)
45{ 45{
46 tox_array_for_each(&ludp->connections, Connection, tmp) { 46 tox_array_for_each(&ludp->connections, Connection, tmp) {
47 if (tmp->ip_port.ip.uint32 == ip_port.ip.uint32 && 47 if (tmp-> status > 0 && ipport_equal(&tmp->ip_port, &ip_port)) {
48 tmp->ip_port.port == ip_port.port &&
49 tmp->status > 0) {
50 return tmp_i; 48 return tmp_i;
51 } 49 }
52 } 50 }
@@ -61,17 +59,49 @@ int getconnection_id(Lossless_UDP *ludp, IP_Port ip_port)
61 * 59 *
62 * TODO: make this better 60 * TODO: make this better
63 */ 61 */
64static uint32_t handshake_id(Lossless_UDP *ludp, IP_Port source) 62
63static uint8_t randtable_initget(Lossless_UDP *ludp, uint32_t index, uint8_t value)
65{ 64{
66 uint32_t id = 0, i; 65 if (ludp->randtable[index][value] == 0)
66 ludp->randtable[index][value] = random_int();
67 67
68 for (i = 0; i < 6; ++i) { 68 return ludp->randtable[index][value];
69 if (ludp->randtable[i][source.uint8[i]] == 0) 69}
70 ludp->randtable[i][source.uint8[i]] = random_int();
71 70
72 id ^= ludp->randtable[i][source.uint8[i]]; 71static uint32_t handshake_id(Lossless_UDP *ludp, IP_Port source)
72{
73 uint32_t id = 0, i = 0;
74
75 uint8_t *uint8;
76 uint8 = (uint8_t *)&source.port;
77 id ^= randtable_initget(ludp, i, *uint8);
78 i++, uint8++;
79 id ^= randtable_initget(ludp, i, *uint8);
80 i++;
81
82#ifdef TOX_ENABLE_IPV6
83 if (source.ip.family == AF_INET)
84 {
85 IP4 ip4 = source.ip.ip4;
86#else
87 IP4 ip4 = source.ip;
88#endif
89 int k;
90 for (k = 0; k < 4; k++) {
91 id ^= randtable_initget(ludp, i++, ip4.uint8[k]);
92 }
93#ifdef TOX_ENABLE_IPV6
73 } 94 }
74 95
96 if (source.ip.family == AF_INET6)
97 {
98 int k;
99 for (k = 0; k < 16; k++) {
100 id ^= randtable_initget(ludp, i++, source.ip.ip6.s6_addr[k]);
101 }
102 }
103#endif
104
75 /* id can't be zero. */ 105 /* id can't be zero. */
76 if (id == 0) 106 if (id == 0)
77 id = 1; 107 id = 1;
@@ -290,7 +320,9 @@ IP_Port connection_ip(Lossless_UDP *ludp, int connection_id)
290 if ((unsigned int)connection_id < ludp->connections.len) 320 if ((unsigned int)connection_id < ludp->connections.len)
291 return tox_array_get(&ludp->connections, connection_id, Connection).ip_port; 321 return tox_array_get(&ludp->connections, connection_id, Connection).ip_port;
292 322
293 IP_Port zero = {{{{0}}, 0, 0}}; 323 IP_Port zero;
324 ip_reset(&zero.ip);
325 zero.port = 0;
294 return zero; 326 return zero;
295} 327}
296 328
@@ -429,7 +461,7 @@ static int send_handshake(Lossless_UDP *ludp, IP_Port ip_port, uint32_t handshak
429 temp = htonl(handshake_id2); 461 temp = htonl(handshake_id2);
430 memcpy(packet + 5, &temp, 4); 462 memcpy(packet + 5, &temp, 4);
431 463
432 return sendpacket(ludp->net->sock, ip_port, packet, sizeof(packet)); 464 return sendpacket(ludp->net, ip_port, packet, sizeof(packet));
433} 465}
434 466
435static int send_SYNC(Lossless_UDP *ludp, int connection_id) 467static int send_SYNC(Lossless_UDP *ludp, int connection_id)
@@ -456,7 +488,7 @@ static int send_SYNC(Lossless_UDP *ludp, int connection_id)
456 index += 4; 488 index += 4;
457 memcpy(packet + index, requested, 4 * number); 489 memcpy(packet + index, requested, 4 * number);
458 490
459 return sendpacket(ludp->net->sock, ip_port, packet, (number * 4 + 4 + 4 + 2)); 491 return sendpacket(ludp->net, ip_port, packet, (number * 4 + 4 + 4 + 2));
460 492
461} 493}
462 494
@@ -471,7 +503,7 @@ static int send_data_packet(Lossless_UDP *ludp, int connection_id, uint32_t pack
471 temp = htonl(packet_num); 503 temp = htonl(packet_num);
472 memcpy(packet + 1, &temp, 4); 504 memcpy(packet + 1, &temp, 4);
473 memcpy(packet + 5, connection->sendbuffer[index].data, connection->sendbuffer[index].size); 505 memcpy(packet + 5, connection->sendbuffer[index].data, connection->sendbuffer[index].size);
474 return sendpacket(ludp->net->sock, connection->ip_port, packet, 1 + 4 + connection->sendbuffer[index].size); 506 return sendpacket(ludp->net, connection->ip_port, packet, 1 + 4 + connection->sendbuffer[index].size);
475} 507}
476 508
477/* Sends 1 data packet. */ 509/* Sends 1 data packet. */
diff --git a/toxcore/Lossless_UDP.h b/toxcore/Lossless_UDP.h
index 20471b0a..f0ce0e87 100644
--- a/toxcore/Lossless_UDP.h
+++ b/toxcore/Lossless_UDP.h
@@ -123,7 +123,13 @@ typedef struct {
123 tox_array connections; 123 tox_array connections;
124 124
125 /* Table of random numbers used in handshake_id. */ 125 /* Table of random numbers used in handshake_id. */
126#ifdef TOX_ENABLE_IPV6
127 /* IPv6 (16) + port (2)*/
128 uint32_t randtable[18][256];
129#else
130 /* IPv4 (4) + port (2) */
126 uint32_t randtable[6][256]; 131 uint32_t randtable[6][256];
132#endif
127 133
128} Lossless_UDP; 134} Lossless_UDP;
129 135
diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c
index b712d142..b955ad5a 100644
--- a/toxcore/Messenger.c
+++ b/toxcore/Messenger.c
@@ -651,7 +651,7 @@ static void LANdiscovery(Messenger *m)
651} 651}
652 652
653/* Run this at startup. */ 653/* Run this at startup. */
654Messenger *initMessenger(void) 654Messenger *initMessenger(uint8_t ipv6enabled)
655{ 655{
656 Messenger *m = calloc(1, sizeof(Messenger)); 656 Messenger *m = calloc(1, sizeof(Messenger));
657 657
@@ -659,7 +659,7 @@ Messenger *initMessenger(void)
659 return NULL; 659 return NULL;
660 660
661 IP ip; 661 IP ip;
662 ip.uint32 = 0; 662 ip_init(&ip, ipv6enabled);
663 m->net = new_networking(ip, PORT); 663 m->net = new_networking(ip, PORT);
664 664
665 if (m->net == NULL) { 665 if (m->net == NULL) {
@@ -743,11 +743,12 @@ void doFriends(Messenger *m)
743 } 743 }
744 } 744 }
745 745
746 IP_Port friendip = DHT_getfriendip(m->dht, m->friendlist[i].client_id); 746 IP_Port friendip;
747 int friendok = DHT_getfriendip(m->dht, m->friendlist[i].client_id, &friendip);
747 748
748 switch (is_cryptoconnected(m->net_crypto, m->friendlist[i].crypt_connection_id)) { 749 switch (is_cryptoconnected(m->net_crypto, m->friendlist[i].crypt_connection_id)) {
749 case 0: 750 case 0:
750 if (friendip.ip.uint32 > 1) 751 if (friendok == 1)
751 m->friendlist[i].crypt_connection_id = crypto_connect(m->net_crypto, m->friendlist[i].client_id, friendip); 752 m->friendlist[i].crypt_connection_id = crypto_connect(m->net_crypto, m->friendlist[i].client_id, friendip);
752 753
753 break; 754 break;
@@ -964,19 +965,23 @@ void Messenger_save(Messenger *m, uint8_t *data)
964{ 965{
965 save_keys(m->net_crypto, data); 966 save_keys(m->net_crypto, data);
966 data += crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES; 967 data += crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;
968
967 uint32_t nospam = get_nospam(&(m->fr)); 969 uint32_t nospam = get_nospam(&(m->fr));
968 memcpy(data, &nospam, sizeof(nospam)); 970 memcpy(data, &nospam, sizeof(nospam));
969 data += sizeof(nospam); 971 data += sizeof(nospam);
972
970 uint32_t size = DHT_size(m->dht); 973 uint32_t size = DHT_size(m->dht);
971 memcpy(data, &size, sizeof(size)); 974 memcpy(data, &size, sizeof(size));
972 data += sizeof(size); 975 data += sizeof(size);
973 DHT_save(m->dht, data); 976 DHT_save(m->dht, data);
974 data += size; 977 data += size;
978
975 size = sizeof(Friend) * m->numfriends; 979 size = sizeof(Friend) * m->numfriends;
976 memcpy(data, &size, sizeof(size)); 980 memcpy(data, &size, sizeof(size));
977 data += sizeof(size); 981 data += sizeof(size);
978 memcpy(data, m->friendlist, sizeof(Friend) * m->numfriends); 982 memcpy(data, m->friendlist, sizeof(Friend) * m->numfriends);
979 data += size; 983 data += size;
984
980 uint16_t small_size = m->name_length; 985 uint16_t small_size = m->name_length;
981 memcpy(data, &small_size, sizeof(small_size)); 986 memcpy(data, &small_size, sizeof(small_size));
982 data += sizeof(small_size); 987 data += sizeof(small_size);
@@ -989,59 +994,64 @@ int Messenger_load(Messenger *m, uint8_t *data, uint32_t length)
989 if (length == ~((uint32_t)0)) 994 if (length == ~((uint32_t)0))
990 return -1; 995 return -1;
991 996
992 if (length < crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES + sizeof(uint32_t) * 3) 997 /* BLOCK1: PUBKEY, SECKEY, NOSPAM, SIZE */
998 if (length < crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES + sizeof(uint32_t) * 2)
993 return -1; 999 return -1;
994 1000
995 length -= crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES + sizeof(uint32_t) * 3;
996 load_keys(m->net_crypto, data); 1001 load_keys(m->net_crypto, data);
997 data += crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES; 1002 data += crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;
1003 length -= crypto_box_PUBLICKEYBYTES + crypto_box_SECRETKEYBYTES;
1004
998 uint32_t nospam; 1005 uint32_t nospam;
999 memcpy(&nospam, data, sizeof(nospam)); 1006 memcpy(&nospam, data, sizeof(nospam));
1000 set_nospam(&(m->fr), nospam); 1007 set_nospam(&(m->fr), nospam);
1001 data += sizeof(nospam); 1008 data += sizeof(nospam);
1009 length -= sizeof(nospam);
1010
1002 uint32_t size; 1011 uint32_t size;
1003 memcpy(&size, data, sizeof(size)); 1012 memcpy(&size, data, sizeof(size));
1004 data += sizeof(size); 1013 data += sizeof(size);
1014 length -= sizeof(size);
1005 1015
1006 if (length < size) 1016 if (length < size)
1007 return -1; 1017 return -1;
1008 1018
1009 length -= size;
1010
1011 if (DHT_load(m->dht, data, size) == -1) 1019 if (DHT_load(m->dht, data, size) == -1)
1012 return -1; 1020 fprintf(stderr, "Data file: Something wicked happened to the stored connections.\n");
1021
1022 /* go on, friends still might be intact */
1013 1023
1014 data += size; 1024 data += size;
1025 length -= size;
1026
1015 memcpy(&size, data, sizeof(size)); 1027 memcpy(&size, data, sizeof(size));
1016 data += sizeof(size); 1028 data += sizeof(size);
1017 1029 if (length < size)
1018 if (length < size || size % sizeof(Friend) != 0)
1019 return -1; 1030 return -1;
1020 1031
1021 Friend *temp = malloc(size); 1032 if (!(size % sizeof(Friend))) {
1022 memcpy(temp, data, size); 1033 uint16_t num = size / sizeof(Friend);
1023 1034 Friend temp[num];
1024 uint16_t num = size / sizeof(Friend); 1035 memcpy(temp, data, size);
1025 1036
1026 uint32_t i; 1037 uint32_t i;
1027 1038 for (i = 0; i < num; ++i) {
1028 for (i = 0; i < num; ++i) { 1039 if (temp[i].status >= 3) {
1029 if (temp[i].status >= 3) { 1040 int fnum = m_addfriend_norequest(m, temp[i].client_id);
1030 int fnum = m_addfriend_norequest(m, temp[i].client_id); 1041 setfriendname(m, fnum, temp[i].name, temp[i].name_length);
1031 setfriendname(m, fnum, temp[i].name, temp[i].name_length); 1042 /* set_friend_statusmessage(fnum, temp[i].statusmessage, temp[i].statusmessage_length); */
1032 /* set_friend_statusmessage(fnum, temp[i].statusmessage, temp[i].statusmessage_length); */ 1043 } else if (temp[i].status != 0) {
1033 } else if (temp[i].status != 0) { 1044 /* TODO: This is not a good way to do this. */
1034 /* TODO: This is not a good way to do this. */ 1045 uint8_t address[FRIEND_ADDRESS_SIZE];
1035 uint8_t address[FRIEND_ADDRESS_SIZE]; 1046 memcpy(address, temp[i].client_id, crypto_box_PUBLICKEYBYTES);
1036 memcpy(address, temp[i].client_id, crypto_box_PUBLICKEYBYTES); 1047 memcpy(address + crypto_box_PUBLICKEYBYTES, &(temp[i].friendrequest_nospam), sizeof(uint32_t));
1037 memcpy(address + crypto_box_PUBLICKEYBYTES, &(temp[i].friendrequest_nospam), sizeof(uint32_t)); 1048 uint16_t checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum));
1038 uint16_t checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum)); 1049 memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(uint32_t), &checksum, sizeof(checksum));
1039 memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(uint32_t), &checksum, sizeof(checksum)); 1050 m_addfriend(m, address, temp[i].info, temp[i].info_size);
1040 m_addfriend(m, address, temp[i].info, temp[i].info_size); 1051 }
1041 } 1052 }
1042 } 1053 }
1043 1054
1044 free(temp);
1045 data += size; 1055 data += size;
1046 length -= size; 1056 length -= size;
1047 1057
diff --git a/toxcore/Messenger.h b/toxcore/Messenger.h
index 40617d08..dfb3f7c6 100644
--- a/toxcore/Messenger.h
+++ b/toxcore/Messenger.h
@@ -371,7 +371,7 @@ void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, in
371 * return allocated instance of Messenger on success. 371 * return allocated instance of Messenger on success.
372 * return 0 if there are problems. 372 * return 0 if there are problems.
373 */ 373 */
374Messenger *initMessenger(void); 374Messenger *initMessenger(uint8_t ipv6enabled);
375 375
376/* Run this before closing shop 376/* Run this before closing shop
377 * Free all datastructures. 377 * Free all datastructures.
diff --git a/toxcore/friend_requests.c b/toxcore/friend_requests.c
index b01015c4..c821d998 100644
--- a/toxcore/friend_requests.c
+++ b/toxcore/friend_requests.c
@@ -50,18 +50,22 @@ int send_friendrequest(DHT *dht, uint8_t *public_key, uint32_t nospam_num, uint8
50 if (len == -1) 50 if (len == -1)
51 return -1; 51 return -1;
52 52
53 IP_Port ip_port = DHT_getfriendip(dht, public_key); 53 IP_Port ip_port;
54 int friendok = DHT_getfriendip(dht, public_key, &ip_port);
54 55
55 if (ip_port.ip.uint32 == 1) 56 // not a friend
57 if (friendok == -1)
56 return -1; 58 return -1;
57 59
58 if (ip_port.ip.uint32 != 0) { 60 // is a friend and we know how to reach him
59 if (sendpacket(dht->c->lossless_udp->net->sock, ip_port, packet, len) != -1) 61 if (friendok == 1) {
62 if (sendpacket(dht->c->lossless_udp->net, ip_port, packet, len) != -1)
60 return 0; 63 return 0;
61 64
62 return -1; 65 return -1;
63 } 66 }
64 67
68 // is a friend, we DON'T know how to reach him
65 int num = route_tofriend(dht, public_key, packet, len); 69 int num = route_tofriend(dht, public_key, packet, len);
66 70
67 if (num == 0) 71 if (num == 0)
diff --git a/toxcore/group_chats.c b/toxcore/group_chats.c
index 4581eb38..4ee487d9 100644
--- a/toxcore/group_chats.c
+++ b/toxcore/group_chats.c
@@ -189,7 +189,7 @@ static int send_groupchatpacket(Group_Chat *chat, IP_Port ip_port, uint8_t *publ
189 if (len == -1) 189 if (len == -1)
190 return -1; 190 return -1;
191 191
192 if (sendpacket(chat->net->sock, ip_port, packet, len) == len) 192 if (sendpacket(chat->net, ip_port, packet, len) == len)
193 return 0; 193 return 0;
194 194
195 return -1; 195 return -1;
@@ -208,7 +208,7 @@ static uint8_t sendto_allpeers(Group_Chat *chat, uint8_t *data, uint16_t length,
208 uint64_t temp_time = unix_time(); 208 uint64_t temp_time = unix_time();
209 209
210 for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) { 210 for (i = 0; i < GROUP_CLOSE_CONNECTIONS; ++i) {
211 if (chat->close[i].ip_port.ip.uint32 != 0 && chat->close[i].last_recv + BAD_NODE_TIMEOUT > temp_time) { 211 if (ip_isset(&chat->close[i].ip_port.ip) && chat->close[i].last_recv + BAD_NODE_TIMEOUT > temp_time) {
212 if (send_groupchatpacket(chat, chat->close[i].ip_port, chat->close[i].client_id, data, length, request_id) == 0) 212 if (send_groupchatpacket(chat, chat->close[i].ip_port, chat->close[i].client_id, data, length, request_id) == 0)
213 ++sent; 213 ++sent;
214 } 214 }
diff --git a/toxcore/net_crypto.c b/toxcore/net_crypto.c
index a182bb53..b6f08fe4 100644
--- a/toxcore/net_crypto.c
+++ b/toxcore/net_crypto.c
@@ -439,7 +439,7 @@ int crypto_connect(Net_Crypto *c, uint8_t *public_key, IP_Port ip_port)
439 if (id != -1) { 439 if (id != -1) {
440 IP_Port c_ip = connection_ip(c->lossless_udp, c->crypto_connections[id].number); 440 IP_Port c_ip = connection_ip(c->lossless_udp, c->crypto_connections[id].number);
441 441
442 if (c_ip.ip.uint32 == ip_port.ip.uint32 && c_ip.port == ip_port.port) 442 if (ipport_equal(&c_ip, &ip_port))
443 return -1; 443 return -1;
444 } 444 }
445 445
diff --git a/toxcore/network.c b/toxcore/network.c
index ed3dff8a..0b5eba61 100644
--- a/toxcore/network.c
+++ b/toxcore/network.c
@@ -26,6 +26,7 @@
26#endif 26#endif
27 27
28#include "network.h" 28#include "network.h"
29#include "util.h"
29 30
30/* return current UNIX time in microseconds (us). */ 31/* return current UNIX time in microseconds (us). */
31uint64_t current_time(void) 32uint64_t current_time(void)
@@ -61,17 +62,76 @@ uint32_t random_int(void)
61#endif 62#endif
62} 63}
63 64
65#ifdef LOGGING
66static void loglogdata(char *message, uint8_t *buffer, size_t buflen, IP_Port *ip_port, ssize_t res);
67#endif
68
64/* Basic network functions: 69/* Basic network functions:
65 * Function to send packet(data) of length length to ip_port. 70 * Function to send packet(data) of length length to ip_port.
66 */ 71 */
67#ifdef WIN32 72int sendpacket(Networking_Core *net, IP_Port ip_port, uint8_t *data, uint32_t length)
68int sendpacket(unsigned int sock, IP_Port ip_port, uint8_t *data, uint32_t length) 73{
74#ifdef TOX_ENABLE_IPV6
75 /* socket AF_INET, but target IP NOT: can't send */
76 if ((net->family == AF_INET) && (ip_port.ip.family != AF_INET))
77 return 0;
78#endif
79
80 struct sockaddr_storage addr;
81 size_t addrsize = 0;
82
83#ifdef TOX_ENABLE_IPV6
84 if (ip_port.ip.family == AF_INET) {
85 if (net->family == AF_INET6) {
86 /* must convert to IPV4-in-IPV6 address */
87 addrsize = sizeof(struct sockaddr_in6);
88 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr;
89 addr6->sin6_family = AF_INET6;
90 addr6->sin6_port = ip_port.port;
91
92 /* there should be a macro for this in a standards compliant
93 * environment, not found */
94 addr6->sin6_addr.s6_addr32[0] = 0;
95 addr6->sin6_addr.s6_addr32[1] = 0;
96 addr6->sin6_addr.s6_addr32[2] = htonl(0xFFFF);
97 addr6->sin6_addr.s6_addr32[3] = ip_port.ip.ip4.uint32;
98
99 addr6->sin6_flowinfo = 0;
100 addr6->sin6_scope_id = 0;
101 }
102 else {
103 IP4 ip4 = ip_port.ip.ip4;
69#else 104#else
70int sendpacket(int sock, IP_Port ip_port, uint8_t *data, uint32_t length) 105 IP4 ip4 = ip_port.ip;
71#endif 106#endif
72{ 107 addrsize = sizeof(struct sockaddr_in);
73 ADDR addr = {AF_INET, ip_port.port, ip_port.ip, {0}}; 108 struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr;
74 return sendto(sock, (char *) data, length, 0, (struct sockaddr *)&addr, sizeof(addr)); 109 addr4->sin_family = AF_INET;
110 addr4->sin_addr = ip4.in_addr;
111 addr4->sin_port = ip_port.port;
112#ifdef TOX_ENABLE_IPV6
113 }
114 }
115 else if (ip_port.ip.family == AF_INET6) {
116 addrsize = sizeof(struct sockaddr_in6);
117 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr;
118 addr6->sin6_family = AF_INET6;
119 addr6->sin6_port = ip_port.port;
120 addr6->sin6_addr = ip_port.ip.ip6;
121
122 addr6->sin6_flowinfo = 0;
123 addr6->sin6_scope_id = 0;
124 } else {
125 /* unknown address type*/
126 return 0;
127 }
128#endif
129
130 int res = sendto(net->sock, (char *) data, length, 0, (struct sockaddr *)&addr, addrsize);
131#ifdef LOGGING
132 loglogdata("O=>", data, length, &ip_port, res);
133#endif
134 return res;
75} 135}
76 136
77/* Function to receive data 137/* Function to receive data
@@ -80,13 +140,9 @@ int sendpacket(int sock, IP_Port ip_port, uint8_t *data, uint32_t length)
80 * Packet length is put into length. 140 * Packet length is put into length.
81 * Dump all empty packets. 141 * Dump all empty packets.
82 */ 142 */
83#ifdef WIN32 143static int receivepacket(sock_t sock, IP_Port *ip_port, uint8_t *data, uint32_t *length)
84static int receivepacket(unsigned int sock, IP_Port *ip_port, uint8_t *data, uint32_t *length)
85#else
86static int receivepacket(int sock, IP_Port *ip_port, uint8_t *data, uint32_t *length)
87#endif
88{ 144{
89 ADDR addr; 145 struct sockaddr_storage addr;
90#ifdef WIN32 146#ifdef WIN32
91 int addrlen = sizeof(addr); 147 int addrlen = sizeof(addr);
92#else 148#else
@@ -94,11 +150,43 @@ static int receivepacket(int sock, IP_Port *ip_port, uint8_t *data, uint32_t *le
94#endif 150#endif
95 (*(int32_t *)length) = recvfrom(sock, (char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen); 151 (*(int32_t *)length) = recvfrom(sock, (char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen);
96 152
97 if (*(int32_t *)length <= 0) 153 if (*(int32_t *)length <= 0) {
154#ifdef LOGGING
155 if ((length < 0) && (errno != EWOULDBLOCK))
156 sprintf(logbuffer, "Unexpected error reading from socket: %u, %s\n", errno, strerror(errno));
157#endif
98 return -1; /* Nothing received or empty packet. */ 158 return -1; /* Nothing received or empty packet. */
159 }
160
161#ifdef TOX_ENABLE_IPV6
162 if (addr.ss_family == AF_INET) {
163 struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr;
164 ip_port->ip.family = addr_in->sin_family;
165 ip_port->ip.ip4.in_addr = addr_in->sin_addr;
166 ip_port->port = addr_in->sin_port;
167 }
168 else if (addr.ss_family == AF_INET6) {
169 struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)&addr;
170 ip_port->ip.family = addr_in6->sin6_family;
171 ip_port->ip.ip6 = addr_in6->sin6_addr;
172 ip_port->port = addr_in6->sin6_port;
173 }
174 else
175 return -1;
176#else
177 if (addr.ss_family == AF_INET) {
178 struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr;
179 ip_port->ip.in_addr = addr_in->sin_addr;
180 ip_port->port = addr_in->sin_port;
181 }
182 else
183 return -1;
184#endif
185
186#ifdef LOGGING
187 loglogdata("=>O", data, *length, ip_port, 0);
188#endif
99 189
100 ip_port->ip = addr.ip;
101 ip_port->port = addr.port;
102 return 0; 190 return 0;
103} 191}
104 192
@@ -162,16 +250,31 @@ static void at_shutdown(void)
162 */ 250 */
163Networking_Core *new_networking(IP ip, uint16_t port) 251Networking_Core *new_networking(IP ip, uint16_t port)
164{ 252{
253#ifdef TOX_ENABLE_IPV6
254 /* maybe check for invalid IPs like 224+.x.y.z? if there is any IP set ever */
255 if (ip.family != AF_INET && ip.family != AF_INET6)
256 return NULL;
257#endif
258
165 if (at_startup() != 0) 259 if (at_startup() != 0)
166 return NULL; 260 return NULL;
167 261
168 /* Initialize our socket. */
169 Networking_Core *temp = calloc(1, sizeof(Networking_Core)); 262 Networking_Core *temp = calloc(1, sizeof(Networking_Core));
170
171 if (temp == NULL) 263 if (temp == NULL)
172 return NULL; 264 return NULL;
173 265
174 temp->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 266 sa_family_t family = 0;
267#ifdef TOX_ENABLE_IPV6
268 family = ip.family;
269#else
270 family = AF_INET;
271#endif
272 temp->family = family;
273 temp->port = 0;
274
275 /* Initialize our socket. */
276 /* add log message what we're creating */
277 temp->sock = socket(temp->family, SOCK_DGRAM, IPPROTO_UDP);
175 278
176 /* Check for socket error. */ 279 /* Check for socket error. */
177#ifdef WIN32 280#ifdef WIN32
@@ -204,7 +307,7 @@ Networking_Core *new_networking(IP ip, uint16_t port)
204 return -1; 307 return -1;
205 */ 308 */
206 309
207 /* Enable broadcast on socket. */ 310 /* Enable broadcast on socket? */
208 int broadcast = 1; 311 int broadcast = 1;
209 setsockopt(temp->sock, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof(broadcast)); 312 setsockopt(temp->sock, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof(broadcast));
210 313
@@ -218,10 +321,106 @@ Networking_Core *new_networking(IP ip, uint16_t port)
218 fcntl(temp->sock, F_SETFL, O_NONBLOCK, 1); 321 fcntl(temp->sock, F_SETFL, O_NONBLOCK, 1);
219#endif 322#endif
220 323
221 /* Bind our socket to port PORT and address 0.0.0.0 */ 324#ifdef LOGGING
222 ADDR addr = {AF_INET, htons(port), ip, {0}}; 325 loginit(ntohs(port));
223 bind(temp->sock, (struct sockaddr *)&addr, sizeof(addr)); 326#endif
224 return temp; 327
328 /* Bind our socket to port PORT and the given IP address (usually 0.0.0.0 or ::) */
329 uint16_t *portptr = NULL;
330 struct sockaddr_storage addr;
331 size_t addrsize;
332#ifdef TOX_ENABLE_IPV6
333 if (temp->family == AF_INET)
334 {
335 IP4 ip4 = ip.ip4;
336#else
337 IP4 ip4 = ip;
338#endif
339 addrsize = sizeof(struct sockaddr_in);
340 struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr;
341 addr4->sin_family = AF_INET;
342 addr4->sin_port = htons(port);
343 addr4->sin_addr = ip4.in_addr;
344
345 portptr = &addr4->sin_port;
346#ifdef TOX_ENABLE_IPV6
347 }
348 else if (temp->family == AF_INET6)
349 {
350 addrsize = sizeof(struct sockaddr_in6);
351 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr;
352 addr6->sin6_family = AF_INET6;
353 addr6->sin6_port = htons(port);
354 addr6->sin6_addr = ip.ip6;
355
356 addr6->sin6_flowinfo = 0;
357 addr6->sin6_scope_id = 0;
358
359 portptr = &addr6->sin6_port;
360 }
361 else
362 return NULL;
363
364 if (ip.family == AF_INET6) {
365 char ipv6only = 0;
366 int res = setsockopt(temp->sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&ipv6only, sizeof(ipv6only));
367#ifdef LOGGING
368 if (res < 0) {
369 sprintf(logbuffer, "Failed to enable dual-stack on IPv6 socket, won't be able to receive from/send to IPv4 addresses. (%u, %s)\n",
370 errno, strerror(errno));
371 loglog(logbuffer);
372 }
373 else
374 loglog("Embedded IPv4 addresses enabled successfully.\n");
375#endif
376
377 /* multicast local nodes */
378 struct ipv6_mreq mreq;
379 memset(&mreq, 0, sizeof(mreq));
380 mreq.ipv6mr_multiaddr.s6_addr[ 0] = 0xFF;
381 mreq.ipv6mr_multiaddr.s6_addr[ 1] = 0x02;
382 mreq.ipv6mr_multiaddr.s6_addr[15] = 0x01;
383 mreq.ipv6mr_interface = 0;
384 res = setsockopt(temp->sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
385#ifdef LOGGING
386 if (res < 0) {
387 sprintf(logbuffer, "Failed to activate local multicast membership. (%u, %s)\n",
388 errno, strerror(errno));
389 loglog(logbuffer);
390 }
391 else
392 loglog("Local multicast group FF02::1 joined successfully.\n");
393#endif
394 }
395#endif
396
397 /* a hanging program or a different user might block the standard port;
398 * as long as it isn't a parameter coming from the commandline,
399 * try a few ports after it, to see if we can find a "free" one
400 */
401 int tries, res;
402 for(tries = 0; tries < 9; tries++)
403 {
404 res = bind(temp->sock, (struct sockaddr *)&addr, addrsize);
405 if (!res)
406 {
407 temp->port = *portptr;
408#ifdef LOGGING
409 sprintf(logbuffer, "Bound successfully to %s:%u.\n", ip_ntoa(&ip), ntohs(temp->port));
410 loglog(logbuffer);
411#endif
412 return temp;
413 }
414
415 uint16_t port = ntohs(*portptr);
416 port++;
417 *portptr = htons(port);
418 }
419
420 fprintf(stderr, "Failed to bind socket: %u, %s (IP/Port: %s:%u\n", errno,
421 strerror(errno), ip_ntoa(&ip), port);
422 free(temp);
423 return NULL;
225} 424}
226 425
227/* Function to cleanup networking stuff. */ 426/* Function to cleanup networking stuff. */
@@ -235,3 +434,362 @@ void kill_networking(Networking_Core *net)
235 free(net); 434 free(net);
236 return; 435 return;
237} 436}
437
438/* ip_equal
439 * compares two IPAny structures
440 * unset means unequal
441 *
442 * returns 0 when not equal or when uninitialized
443 */
444int ip_equal(IP *a, IP *b)
445{
446 if (!a || !b)
447 return 0;
448
449#ifdef TOX_ENABLE_IPV6
450 if (a->family == AF_INET)
451 return (a->ip4.in_addr.s_addr == b->ip4.in_addr.s_addr);
452
453 if (a->family == AF_INET6)
454 return IN6_ARE_ADDR_EQUAL(&a->ip6, &b->ip6);
455
456 return 0;
457#else
458 return (a->uint32 == b->uint32);
459#endif
460};
461
462/* ipport_equal
463 * compares two IPAny_Port structures
464 * unset means unequal
465 *
466 * returns 0 when not equal or when uninitialized
467 */
468int ipport_equal(IP_Port *a, IP_Port *b)
469{
470 if (!a || !b)
471 return 0;
472
473 if (!a->port || (a->port != b->port))
474 return 0;
475
476 return ip_equal(&a->ip, &b->ip);
477};
478
479/* nulls out ip */
480void ip_reset(IP *ip)
481{
482 if (!ip)
483 return;
484
485#ifdef TOX_ENABLE_IPV6
486 memset(ip, 0, sizeof(IP));
487#else
488 ip->uint32 = 0;
489#endif
490};
491
492/* nulls out ip, sets family according to flag */
493void ip_init(IP *ip, uint8_t ipv6enabled)
494{
495 if (!ip)
496 return;
497
498#ifdef TOX_ENABLE_IPV6
499 memset(ip, 0, sizeof(IP));
500 ip->family = ipv6enabled ? AF_INET6 : AF_INET;
501#else
502 ip->uint32 = 0;
503#endif
504};
505
506/* checks if ip is valid */
507int ip_isset(IP *ip)
508{
509 if (!ip)
510 return 0;
511
512#ifdef TOX_ENABLE_IPV6
513 return (ip->family != 0);
514#else
515 return (ip->uint32 != 0);
516#endif
517};
518
519/* checks if ip is valid */
520int ipport_isset(IP_Port *ipport)
521{
522 if (!ipport)
523 return 0;
524
525 if (!ipport->port)
526 return 0;
527
528 return ip_isset(&ipport->ip);
529};
530
531/* copies an ip structure (careful about direction!) */
532void ip_copy(IP *target, IP *source)
533{
534 if (!source || !target)
535 return;
536
537 memcpy(target, source, sizeof(IP));
538};
539
540/* copies an ip_port structure (careful about direction!) */
541void ipport_copy(IP_Port *target, IP_Port *source)
542{
543 if (!source || !target)
544 return;
545
546 memcpy(target, source, sizeof(IP_Port));
547};
548
549/* ip_ntoa
550 * converts ip into a string
551 * uses a static buffer, so mustn't used multiple times in the same output
552 */
553/* there would be INET6_ADDRSTRLEN, but it might be too short for the error message */
554static char addresstext[96];
555const char *ip_ntoa(IP *ip)
556{
557 if (ip) {
558#ifdef TOX_ENABLE_IPV6
559 if (ip->family == AF_INET) {
560 addresstext[0] = 0;
561 struct in_addr *addr = (struct in_addr *)&ip->ip4;
562 inet_ntop(ip->family, addr, addresstext, sizeof(addresstext));
563 }
564 else if (ip->family == AF_INET6) {
565 addresstext[0] = '[';
566 struct in6_addr *addr = (struct in6_addr *)&ip->ip6;
567 inet_ntop(ip->family, addr, &addresstext[1], sizeof(addresstext) - 3);
568 size_t len = strlen(addresstext);
569 addresstext[len] = ']';
570 addresstext[len + 1] = 0;
571 }
572 else
573 snprintf(addresstext, sizeof(addresstext), "(IP invalid, family %u)", ip->family);
574#else
575 addresstext[0] = 0;
576 struct in_addr *addr = (struct in_addr *)&ip;
577 inet_ntop(AF_INET, addr, addresstext, sizeof(addresstext));
578#endif
579 }
580 else
581 snprintf(addresstext, sizeof(addresstext), "(IP invalid: NULL)");
582
583 addresstext[INET6_ADDRSTRLEN + 2] = 0;
584 return addresstext;
585};
586
587/*
588 * addr_parse_ip
589 * directly parses the input into an IP structure
590 * tries IPv4 first, then IPv6
591 *
592 * input
593 * address: dotted notation (IPv4: quad, IPv6: 16) or colon notation (IPv6)
594 *
595 * output
596 * IP: family and the value is set on success
597 *
598 * returns 1 on success, 0 on failure
599 */
600
601int addr_parse_ip(const char *address, IP *to)
602{
603 if (!address || !to)
604 return 0;
605
606#ifdef TOX_ENABLE_IPV6
607 struct in_addr addr4;
608 if (1 == inet_pton(AF_INET, address, &addr4)) {
609 to->family = AF_INET;
610 to->ip4.in_addr = addr4;
611 return 1;
612 };
613
614 struct in6_addr addr6;
615 if (1 == inet_pton(AF_INET6, address, &addr6)) {
616 to->family = AF_INET6;
617 to->ip6 = addr6;
618 return 1;
619 };
620#else
621 struct in_addr addr4;
622 if (1 == inet_pton(AF_INET, address, &addr4)) {
623 to->in_addr = addr4;
624 return 1;
625 };
626#endif
627
628 return 0;
629};
630
631/*
632 * addr_resolve():
633 * uses getaddrinfo to resolve an address into an IP address
634 * uses the first IPv4/IPv6 addresses returned by getaddrinfo
635 *
636 * input
637 * address: a hostname (or something parseable to an IP address)
638 * ip: ip.family MUST be initialized, either set to a specific IP version
639 * (AF_INET/AF_INET6) or to the unspecified AF_UNSPEC (= 0), if both
640 * IP versions are acceptable
641 *
642 * returns in ip a valid IPAny (v4/v6),
643 * prefers v6 if ip.family was AF_UNSPEC and both available
644 * returns 0 on failure
645 */
646
647int addr_resolve(const char *address, IP *to)
648{
649 if (!address || !to)
650 return 0;
651
652 sa_family_t family;
653#ifdef TOX_ENABLE_IPV6
654 family = to->family;
655#else
656 family = AF_INET;
657#endif
658
659 struct addrinfo *server = NULL;
660 struct addrinfo *walker = NULL;
661 struct addrinfo hints;
662 int rc;
663
664 memset(&hints, 0, sizeof(hints));
665 hints.ai_family = family;
666 hints.ai_socktype = SOCK_DGRAM; // type of socket Tox uses.
667
668#ifdef __WIN32__
669 WSADATA wsa_data;
670
671 /* CLEANUP: really not the best place to put this */
672 rc = WSAStartup(MAKEWORD(2, 2), &wsa_data);
673
674 if (rc != 0) {
675 return 0;
676 }
677
678#endif
679
680 rc = getaddrinfo(address, NULL, &hints, &server);
681 // Lookup failed.
682 if (rc != 0) {
683#ifdef __WIN32__
684 WSACleanup();
685#endif
686 return 0;
687 }
688
689#ifdef TOX_ENABLE_IPV6
690 IP4 ip4;
691 memset(&ip4, 0, sizeof(ip4));
692 IP6 ip6;
693 memset(&ip6, 0, sizeof(ip6));
694#endif
695
696 walker = server;
697 while (walker && (rc != 3)) {
698 if (family != AF_UNSPEC) {
699 if (walker->ai_family == family) {
700 if (family == AF_INET) {
701 if (walker->ai_addrlen == sizeof(struct sockaddr_in)) {
702 struct sockaddr_in *addr = (struct sockaddr_in *)walker->ai_addr;
703#ifdef TOX_ENABLE_IPV6
704 to->ip4.in_addr = addr->sin_addr;
705#else
706 to->in_addr = addr->sin_addr;
707#endif
708 rc = 3;
709 }
710 }
711#ifdef TOX_ENABLE_IPV6
712 else if (family == AF_INET6) {
713 if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) {
714 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)walker->ai_addr;
715 to->ip6 = addr->sin6_addr;
716 rc = 3;
717 }
718 }
719#endif
720 }
721 }
722#ifdef TOX_ENABLE_IPV6
723 else {
724 if (walker->ai_family == AF_INET) {
725 if (walker->ai_addrlen == sizeof(struct sockaddr_in)) {
726 struct sockaddr_in *addr = (struct sockaddr_in *)walker->ai_addr;
727 ip4.in_addr = addr->sin_addr;
728 rc |= 1;
729 }
730 }
731 else if (walker->ai_family == AF_INET6) {
732 if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) {
733 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)walker->ai_addr;
734 ip6 = addr->sin6_addr;
735 rc |= 2;
736 }
737 }
738 }
739#endif
740
741 walker = walker->ai_next;
742 }
743
744#ifdef TOX_ENABLE_IPV6
745 if (to->family == AF_UNSPEC) {
746 if (rc & 2) {
747 to->family = AF_INET6;
748 to->ip6 = ip6;
749 }
750 else if (rc & 1) {
751 to->family = AF_INET;
752 to->ip4 = ip4;
753 }
754 else
755 rc = 0;
756 }
757#endif
758
759
760 freeaddrinfo(server);
761#ifdef __WIN32__
762 WSACleanup();
763#endif
764 return rc;
765}
766
767/*
768 * addr_resolve_or_parse_ip
769 * resolves string into an IP address
770 *
771 * to->family MUST be set (AF_UNSPEC, AF_INET, AF_INET6)
772 * returns 1 on success, 0 on failure
773 */
774int addr_resolve_or_parse_ip(const char *address, IP *to)
775{
776 if (!addr_resolve(address, to))
777 if (!addr_parse_ip(address, to))
778 return 0;
779
780 return 1;
781};
782
783#ifdef LOGGING
784static void loglogdata(char *message, uint8_t *buffer, size_t buflen, IP_Port *ip_port, ssize_t res)
785{
786 snprintf(logbuffer, sizeof(logbuffer), "[%2u] %3u%c %s %s:%u (%u: %s) | %04x%04x\n",
787 buffer[0], res < 0 ? (buflen & 0xFF) : res,
788 res < 0 ? '-' : (res == buflen ? '=' : '+'),
789 message, ip_ntoa(&ip_port->ip), ntohs(ip_port->port), res < 0 ? errno : 0,
790 res < 0 ? strerror(errno) : "OK", buflen > 4 ? ntohl(*(uint32_t *)&buffer[1]) : 0,
791 buflen > 7 ? ntohl(*(uint32_t *)(&buffer[5])) : 0);
792 logbuffer[sizeof(logbuffer) - 1] = 0;
793 loglog(logbuffer);
794}
795#endif
diff --git a/toxcore/network.h b/toxcore/network.h
index 2d08e88d..e804379d 100644
--- a/toxcore/network.h
+++ b/toxcore/network.h
@@ -39,17 +39,22 @@
39#include <windows.h> 39#include <windows.h>
40#include <ws2tcpip.h> 40#include <ws2tcpip.h>
41 41
42typedef unsigned int sock_t;
43
42#else // Linux includes 44#else // Linux includes
43 45
44#include <fcntl.h> 46#include <fcntl.h>
45#include <sys/socket.h> 47#include <sys/socket.h>
46#include <netinet/in.h> 48#include <netinet/in.h>
49#include <arpa/inet.h>
47#include <errno.h> 50#include <errno.h>
48#include <sys/time.h> 51#include <sys/time.h>
49#include <sys/types.h> 52#include <sys/types.h>
50#include <netdb.h> 53#include <netdb.h>
51#include <unistd.h> 54#include <unistd.h>
52 55
56typedef int sock_t;
57
53#endif 58#endif
54 59
55#ifndef VANILLA_NACL 60#ifndef VANILLA_NACL
@@ -66,7 +71,8 @@
66#define NET_PACKET_PING_REQUEST 0 /* Ping request packet ID. */ 71#define NET_PACKET_PING_REQUEST 0 /* Ping request packet ID. */
67#define NET_PACKET_PING_RESPONSE 1 /* Ping response packet ID. */ 72#define NET_PACKET_PING_RESPONSE 1 /* Ping response packet ID. */
68#define NET_PACKET_GET_NODES 2 /* Get nodes request packet ID. */ 73#define NET_PACKET_GET_NODES 2 /* Get nodes request packet ID. */
69#define NET_PACKET_SEND_NODES 3 /* Send nodes response packet ID. */ 74#define NET_PACKET_SEND_NODES 3 /* Send nodes response packet ID for IPv4 addresses. */
75#define NET_PACKET_SEND_NODES_EX 4 /* Send nodes response packet ID for other addresses. */
70#define NET_PACKET_HANDSHAKE 16 /* Handshake packet ID. */ 76#define NET_PACKET_HANDSHAKE 16 /* Handshake packet ID. */
71#define NET_PACKET_SYNC 17 /* SYNC packet ID. */ 77#define NET_PACKET_SYNC 17 /* SYNC packet ID. */
72#define NET_PACKET_DATA 18 /* Data packet ID. */ 78#define NET_PACKET_DATA 18 /* Data packet ID. */
@@ -82,27 +88,83 @@ typedef union {
82 uint8_t uint8[4]; 88 uint8_t uint8[4];
83 uint16_t uint16[2]; 89 uint16_t uint16[2];
84 uint32_t uint32; 90 uint32_t uint32;
85} IP; 91 struct in_addr in_addr;
92} IP4;
93
94typedef struct in6_addr IP6;
95
96typedef struct {
97 sa_family_t family;
98 union {
99 IP4 ip4;
100 IP6 ip6;
101 };
102} IPAny;
86 103
87typedef union { 104typedef union {
88 struct { 105 struct {
89 IP ip; 106 IP4 ip;
90 uint16_t port; 107 uint16_t port;
91 /* Not used for anything right now. */ 108 /* Not used for anything right now. */
92 uint16_t padding; 109 uint16_t padding;
93 }; 110 };
94 uint8_t uint8[8]; 111 uint8_t uint8[8];
95} IP_Port; 112} IP4_Port;
96 113
114/* will replace IP_Port as soon as the complete infrastructure is in place
115 * removed the unused union and padding also */
97typedef struct { 116typedef struct {
98 int16_t family; 117 IPAny ip;
99 uint16_t port; 118 uint16_t port;
100 IP ip; 119} IPAny_Port;
101 uint8_t zeroes[8]; 120
102#ifdef ENABLE_IPV6 121#undef TOX_ENABLE_IPV6
103 uint8_t zeroes2[12]; 122/* #define TOX_ENABLE_IPV6 */
123#ifdef TOX_ENABLE_IPV6
124#define TOX_ENABLE_IPV6_DEFAULT 1
125typedef IPAny IP;
126typedef IPAny_Port IP_Port;
127#else
128#define TOX_ENABLE_IPV6_DEFAULT 0
129typedef IP4 IP;
130typedef IP4_Port IP_Port;
104#endif 131#endif
105} ADDR; 132
133/* ip_ntoa
134 * converts ip into a string
135 * uses a static buffer, so mustn't used multiple times in the same output
136 */
137const char *ip_ntoa(IP *ip);
138
139/* ipport_equal
140 * compares two IPAny_Port structures
141 * unset means unequal
142 *
143 * returns 0 when not equal or when uninitialized
144 */
145int ipport_equal(IP_Port *a, IP_Port *b);
146
147/* nulls out ip */
148void ip_reset(IP *ip);
149/* nulls out ip, sets family according to flag */
150void ip_init(IP *ip, uint8_t ipv6enabled);
151/* checks if ip is valid */
152int ip_isset(IP *ip);
153/* checks if ip is valid */
154int ipport_isset(IP_Port *ipport);
155/* copies an ip structure */
156void ip_copy(IP *target, IP *source);
157/* copies an ip_port structure */
158void ipport_copy(IP_Port *target, IP_Port *source);
159
160/*
161 * addr_resolve_or_parse_ip
162 * resolves string into an IP address
163 *
164 * to->family MUST be set (AF_UNSPEC, AF_INET, AF_INET6)
165 * returns 1 on success, 0 on failure
166 */
167int addr_resolve_or_parse_ip(const char *address, IP *to);
106 168
107/* Function to receive data, ip and port of sender is put into ip_port. 169/* Function to receive data, ip and port of sender is put into ip_port.
108 * Packet data is put into data. 170 * Packet data is put into data.
@@ -117,13 +179,11 @@ typedef struct {
117 179
118typedef struct { 180typedef struct {
119 Packet_Handles packethandlers[256]; 181 Packet_Handles packethandlers[256];
120 /* Our UDP socket. */
121#ifdef WIN32
122 unsigned int sock;
123#else
124 int sock;
125#endif
126 182
183 /* Our UDP socket. */
184 sa_family_t family;
185 uint16_t port;
186 sock_t sock;
127} Networking_Core; 187} Networking_Core;
128 188
129/* return current time in milleseconds since the epoch. */ 189/* return current time in milleseconds since the epoch. */
@@ -137,12 +197,7 @@ uint32_t random_int(void);
137/* Basic network functions: */ 197/* Basic network functions: */
138 198
139/* Function to send packet(data) of length length to ip_port. */ 199/* Function to send packet(data) of length length to ip_port. */
140#ifdef WIN32 200int sendpacket(Networking_Core *net, IP_Port ip_port, uint8_t *data, uint32_t length);
141int sendpacket(unsigned int sock, IP_Port ip_port, uint8_t *data, uint32_t length);
142#else
143int sendpacket(int sock, IP_Port ip_port, uint8_t *data, uint32_t length);
144#endif
145
146 201
147/* Function to call when packet beginning with byte is received. */ 202/* Function to call when packet beginning with byte is received. */
148void networking_registerhandler(Networking_Core *net, uint8_t byte, packet_handler_callback cb, void *object); 203void networking_registerhandler(Networking_Core *net, uint8_t byte, packet_handler_callback cb, void *object);
@@ -163,5 +218,4 @@ Networking_Core *new_networking(IP ip, uint16_t port);
163/* Function to cleanup networking stuff (doesn't do much right now). */ 218/* Function to cleanup networking stuff (doesn't do much right now). */
164void kill_networking(Networking_Core *net); 219void kill_networking(Networking_Core *net);
165 220
166
167#endif 221#endif
diff --git a/toxcore/ping.c b/toxcore/ping.c
index 3b39d911..49e0dba9 100644
--- a/toxcore/ping.c
+++ b/toxcore/ping.c
@@ -100,7 +100,8 @@ bool is_pinging(void *ping, IP_Port ipp, uint64_t ping_id) // O(n) TODO: Repl
100{ 100{
101 PING *png = ping; 101 PING *png = ping;
102 102
103 if (ipp.ip.uint32 == 0 && ping_id == 0) 103 /* shouldn't that be an OR ? */
104 if (!ip_isset(&ipp.ip) && ping_id == 0)
104 return false; 105 return false;
105 106
106 size_t i, id; 107 size_t i, id;
@@ -111,7 +112,8 @@ bool is_pinging(void *ping, IP_Port ipp, uint64_t ping_id) // O(n) TODO: Repl
111 id = (png->pos_pings + i) % PING_NUM_MAX; 112 id = (png->pos_pings + i) % PING_NUM_MAX;
112 113
113 /* ping_id = 0 means match any id. */ 114 /* ping_id = 0 means match any id. */
114 if ((ipp_eq(png->pings[id].ipp, ipp) || ipp.ip.uint32 == 0) && (png->pings[id].id == ping_id || ping_id == 0)) { 115 if ((!ip_isset(&ipp.ip) || ipport_equal(&png->pings[id].ipp, &ipp)) &&
116 (png->pings[id].id == ping_id || ping_id == 0)) {
115 return true; 117 return true;
116 } 118 }
117 } 119 }
@@ -147,7 +149,7 @@ int send_ping_request(void *ping, Net_Crypto *c, IP_Port ipp, uint8_t *client_id
147 if (rc != sizeof(ping_id) + ENCRYPTION_PADDING) 149 if (rc != sizeof(ping_id) + ENCRYPTION_PADDING)
148 return 1; 150 return 1;
149 151
150 return sendpacket(c->lossless_udp->net->sock, ipp, pk, sizeof(pk)); 152 return sendpacket(c->lossless_udp->net, ipp, pk, sizeof(pk));
151} 153}
152 154
153int send_ping_response(Net_Crypto *c, IP_Port ipp, uint8_t *client_id, uint64_t ping_id) 155int send_ping_response(Net_Crypto *c, IP_Port ipp, uint8_t *client_id, uint64_t ping_id)
@@ -172,7 +174,7 @@ int send_ping_response(Net_Crypto *c, IP_Port ipp, uint8_t *client_id, uint64_t
172 if (rc != sizeof(ping_id) + ENCRYPTION_PADDING) 174 if (rc != sizeof(ping_id) + ENCRYPTION_PADDING)
173 return 1; 175 return 1;
174 176
175 return sendpacket(c->lossless_udp->net->sock, ipp, pk, sizeof(pk)); 177 return sendpacket(c->lossless_udp->net, ipp, pk, sizeof(pk));
176} 178}
177 179
178int handle_ping_request(void *object, IP_Port source, uint8_t *packet, uint32_t length) 180int handle_ping_request(void *object, IP_Port source, uint8_t *packet, uint32_t length)
diff --git a/toxcore/tox.c b/toxcore/tox.c
index 54bbd9f0..5e3893ec 100644
--- a/toxcore/tox.c
+++ b/toxcore/tox.c
@@ -374,6 +374,12 @@ void tox_bootstrap(void *tox, IP_Port ip_port, uint8_t *public_key)
374 Messenger *m = tox; 374 Messenger *m = tox;
375 DHT_bootstrap(m->dht, ip_port, public_key); 375 DHT_bootstrap(m->dht, ip_port, public_key);
376} 376}
377int tox_bootstrap_ex(void *tox, const char *address, uint8_t ipv6enabled,
378 uint16_t port, uint8_t *public_key)
379{
380 Messenger *m = tox;
381 return DHT_bootstrap_ex(m->dht, address, ipv6enabled, port, public_key);
382};
377 383
378/* return 0 if we are not connected to the DHT. 384/* return 0 if we are not connected to the DHT.
379 * return 1 if we are. 385 * return 1 if we are.
@@ -389,9 +395,13 @@ int tox_isconnected(void *tox)
389 * return allocated instance of tox on success. 395 * return allocated instance of tox on success.
390 * return 0 if there are problems. 396 * return 0 if there are problems.
391 */ 397 */
398void *tox_new_ex(uint8_t ipv6enabled)
399{
400 return initMessenger(ipv6enabled);
401}
392void *tox_new(void) 402void *tox_new(void)
393{ 403{
394 return initMessenger(); 404 return tox_new_ex(0);
395} 405}
396 406
397/* Run this before closing shop. 407/* Run this before closing shop.
diff --git a/toxcore/tox.h b/toxcore/tox.h
index 811e798b..cf5d6b2a 100644
--- a/toxcore/tox.h
+++ b/toxcore/tox.h
@@ -26,6 +26,22 @@
26 26
27#include <stdint.h> 27#include <stdint.h>
28 28
29#ifdef WIN32
30#ifndef WINVER
31//Windows XP
32#define WINVER 0x0501
33#endif
34
35#include <winsock2.h>
36#include <windows.h>
37#include <ws2tcpip.h>
38
39#else
40
41#include <netinet/ip.h>
42
43#endif
44
29#ifdef __cplusplus 45#ifdef __cplusplus
30extern "C" { 46extern "C" {
31#endif 47#endif
@@ -36,19 +52,52 @@ extern "C" {
36 52
37#define TOX_FRIEND_ADDRESS_SIZE (TOX_CLIENT_ID_SIZE + sizeof(uint32_t) + sizeof(uint16_t)) 53#define TOX_FRIEND_ADDRESS_SIZE (TOX_CLIENT_ID_SIZE + sizeof(uint32_t) + sizeof(uint16_t))
38 54
39
40typedef union { 55typedef union {
41 uint8_t c[4]; 56 uint8_t c[4];
42 uint16_t s[2]; 57 uint16_t s[2];
43 uint32_t i; 58 uint32_t i;
44} tox_IP; 59} tox_IP4;
60
61
62typedef struct in6_addr tox_IP6;
45 63
46typedef struct { 64typedef struct {
47 tox_IP ip; 65 sa_family_t family;
66 union {
67 tox_IP4 ip4;
68 tox_IP6 ip6;
69 };
70} tox_IPAny;
71
72typedef union {
73 struct {
74 tox_IP4 ip;
75 uint16_t port;
76 /* Not used for anything right now. */
77 uint16_t padding;
78 };
79 uint8_t uint8[8];
80} tox_IP4_Port;
81
82/* will replace IP_Port as soon as the complete infrastructure is in place
83 * removed the unused union and padding also */
84typedef struct {
85 tox_IPAny ip;
48 uint16_t port; 86 uint16_t port;
49 /* Not used for anything right now. */ 87} tox_IPAny_Port;
50 uint16_t padding; 88
51} tox_IP_Port; 89#undef TOX_ENABLE_IPV6
90/* #define TOX_ENABLE_IPV6 */
91#ifdef TOX_ENABLE_IPV6
92#define TOX_ENABLE_IPV6_DEFAULT 1
93typedef tox_IPAny tox_IP;
94typedef tox_IPAny_Port tox_IP_Port;
95#else
96#define TOX_ENABLE_IPV6_DEFAULT 0
97typedef tox_IP4 tox_IP;
98typedef tox_IP4_Port tox_IP_Port;
99#endif
100
52 101
53/* Errors for m_addfriend 102/* Errors for m_addfriend
54 * FAERR - Friend Add Error 103 * FAERR - Friend Add Error
@@ -291,8 +340,11 @@ void tox_callback_connectionstatus(Tox *tox, void (*function)(Tox *tox, int, uin
291 340
292/* Use this function to bootstrap the client. 341/* Use this function to bootstrap the client.
293 * Sends a get nodes request to the given node with ip port and public_key. 342 * Sends a get nodes request to the given node with ip port and public_key.
343 * tox_bootstrap_ex() returns 1 if the address could be converted, 0 otherwise
294 */ 344 */
295void tox_bootstrap(Tox *tox, tox_IP_Port ip_port, uint8_t *public_key); 345void tox_bootstrap(Tox *tox, tox_IP_Port ip_port, uint8_t *public_key);
346int tox_bootstrap_ex(Tox *tox, const char *address, uint8_t ipv6enabled,
347 uint16_t port, uint8_t *public_key);
296 348
297/* return 0 if we are not connected to the DHT. 349/* return 0 if we are not connected to the DHT.
298 * return 1 if we are. 350 * return 1 if we are.
@@ -305,6 +357,7 @@ int tox_isconnected(Tox *tox);
305 * return 0 if there are problems. 357 * return 0 if there are problems.
306 */ 358 */
307Tox *tox_new(void); 359Tox *tox_new(void);
360Tox *tox_new_ex(uint8_t ipv6enabled);
308 361
309/* Run this before closing shop. 362/* Run this before closing shop.
310 * Free all datastructures. */ 363 * Free all datastructures. */
diff --git a/toxcore/util.c b/toxcore/util.c
index 1728ea21..7b5ddc49 100644
--- a/toxcore/util.c
+++ b/toxcore/util.c
@@ -10,11 +10,12 @@
10#endif 10#endif
11 11
12#include <time.h> 12#include <time.h>
13#include <stdint.h>
14#include <stdbool.h>
15 13
14/* for CLIENT_ID_SIZE */
16#include "DHT.h" 15#include "DHT.h"
17 16
17#include "util.h"
18
18uint64_t now() 19uint64_t now()
19{ 20{
20 return time(NULL); 21 return time(NULL);
@@ -32,11 +33,6 @@ uint64_t random_64b()
32 return r; 33 return r;
33} 34}
34 35
35bool ipp_eq(IP_Port a, IP_Port b)
36{
37 return (a.ip.uint32 == b.ip.uint32) && (a.port == b.port);
38}
39
40bool id_eq(uint8_t *dest, uint8_t *src) 36bool id_eq(uint8_t *dest, uint8_t *src)
41{ 37{
42 return memcmp(dest, src, CLIENT_ID_SIZE) == 0; 38 return memcmp(dest, src, CLIENT_ID_SIZE) == 0;
@@ -46,3 +42,62 @@ void id_cpy(uint8_t *dest, uint8_t *src)
46{ 42{
47 memcpy(dest, src, CLIENT_ID_SIZE); 43 memcpy(dest, src, CLIENT_ID_SIZE);
48} 44}
45
46int cmdline_parsefor_ipv46(int argc, char **argv, uint8_t *ipv6enabled)
47{
48 int argvoffset = 0, argi;
49 for(argi = 1; argi < argc; argi++)
50 if (!strncasecmp(argv[argi], "--ipv", 5)) {
51 if (argv[argi][5] && !argv[argi][6]) {
52 char c = argv[argi][5];
53 if (c == '4')
54 *ipv6enabled = 0;
55 else if (c == '6')
56 *ipv6enabled = 1;
57 else {
58 printf("Invalid argument: %s. Try --ipv4 or --ipv6!\n", argv[argi]);
59 return -1;
60 }
61 }
62 else {
63 printf("Invalid argument: %s. Try --ipv4 or --ipv6!\n", argv[argi]);
64 return -1;
65 }
66
67 if (argvoffset != argi - 1) {
68 printf("Argument must come first: %s.\n", argv[argi]);
69 return -1;
70 }
71
72 argvoffset++;
73 }
74
75 return argvoffset;
76};
77
78#ifdef LOGGING
79char logbuffer[512];
80static FILE *logfile = NULL;
81void loginit(uint16_t port)
82{
83 if (logfile)
84 fclose(logfile);
85
86 sprintf(logbuffer, "%u-%u.log", ntohs(port), now);
87 logfile = fopen(logbuffer, "w");
88};
89void loglog(char *text)
90{
91 if (logfile) {
92 fprintf(logfile, text);
93 fflush(logfile);
94 }
95};
96void logexit()
97{
98 if (logfile) {
99 fclose(logfile);
100 logfile = NULL;
101 }
102};
103#endif
diff --git a/toxcore/util.h b/toxcore/util.h
index 90a3c8e4..e7be2d51 100644
--- a/toxcore/util.h
+++ b/toxcore/util.h
@@ -5,8 +5,26 @@
5 * Copyright 2013 plutooo 5 * Copyright 2013 plutooo
6 */ 6 */
7 7
8#ifndef __UTIL_H__
9#define __UTIL_H__
10
11#include <stdbool.h>
12#include <stdint.h>
13
8uint64_t now(); 14uint64_t now();
9uint64_t random_64b(); 15uint64_t random_64b();
10bool ipp_eq(IP_Port a, IP_Port b);
11bool id_eq(uint8_t *dest, uint8_t *src); 16bool id_eq(uint8_t *dest, uint8_t *src);
12void id_cpy(uint8_t *dest, uint8_t *src); 17void id_cpy(uint8_t *dest, uint8_t *src);
18
19int cmdline_parsefor_ipv46(int argc, char **argv, uint8_t *ipv6enabled);
20
21#undef LOGGING
22/* #define LOGGING */
23#ifdef LOGGING
24extern char logbuffer[512];
25void loginit(uint16_t port);
26void loglog(char *text);
27void logexit();
28#endif
29
30#endif /* __UTIL_H__ */