Merge upstream and other stuff

This commit is contained in:
mannol 2014-05-20 00:10:40 +02:00
parent ea96c1758a
commit a1f2a18ae4
50 changed files with 5326 additions and 4307 deletions

View File

@ -15,6 +15,7 @@ AUTOTEST_LDADD = \
$(NACL_LDFLAGS) \
libtoxcore.la \
$(LIBSODIUM_LIBS) \
$(NACL_OBJECTS) \
$(NACL_LIBS) \
$(CHECK_LIBS)

View File

@ -427,6 +427,17 @@ AC_C_BIGENDIAN
# Checks for library functions.
AC_FUNC_FORK
AC_CHECK_FUNCS([gettimeofday memset socket strchr malloc])
if test "x$WIN32" != "xyes"; then
AC_CHECK_LIB(rt, clock_gettime,
[
RT_LIBS="-lrt"
AC_SUBST(RT_LIBS)
],
[
AC_MSG_ERROR([required library rt was not found on your system])
]
)
fi
if test "x$BUILD_AV" = "xyes"; then
AX_PTHREAD(

View File

@ -31,6 +31,12 @@
#include "../toxcore/friend_requests.h"
#include "../toxcore/util.h"
#define TCP_RELAY_ENABLED
#ifdef TCP_RELAY_ENABLED
#include "../toxcore/TCP_server.h"
#endif
#include "../testing/misc_tools.c"
#ifdef DHT_NODE_EXTRA_PACKETS
@ -69,11 +75,12 @@ void manage_keys(DHT *dht)
exit(1);
}
load_keys(dht->c, keys);
memcpy(dht->self_public_key, keys, crypto_box_PUBLICKEYBYTES);
memcpy(dht->self_secret_key, keys + crypto_box_PUBLICKEYBYTES, crypto_box_SECRETKEYBYTES);
printf("Keys loaded successfully.\n");
} else {
new_keys(dht->c);
save_keys(dht->c, keys);
memcpy(keys, dht->self_public_key, crypto_box_PUBLICKEYBYTES);
memcpy(keys + crypto_box_PUBLICKEYBYTES, dht->self_secret_key, crypto_box_SECRETKEYBYTES);
keys_file = fopen("key", "w");
if (fwrite(keys, sizeof(uint8_t), KEYS_SIZE, keys_file) != KEYS_SIZE) {
@ -107,7 +114,7 @@ int main(int argc, char *argv[])
IP ip;
ip_init(&ip, ipv6enabled);
DHT *dht = new_DHT(new_net_crypto(new_networking(ip, PORT)));
DHT *dht = new_DHT(new_networking(ip, PORT));
Onion *onion = new_onion(dht);
Onion_Announce *onion_a = new_onion_announce(dht);
@ -123,27 +130,33 @@ int main(int argc, char *argv[])
perror("Initialization");
manage_keys(dht);
/* We want our DHT public key to be the same as our internal one since this is a bootstrap node */
memcpy(dht->self_public_key, dht->c->self_public_key, crypto_box_PUBLICKEYBYTES);
memcpy(dht->self_secret_key, dht->c->self_secret_key, crypto_box_SECRETKEYBYTES);
printf("Public key: ");
uint32_t i;
#ifdef TCP_RELAY_ENABLED
#define NUM_PORTS 3
uint16_t ports[NUM_PORTS] = {443, 3389, PORT};
TCP_Server *tcp_s = new_TCP_server(ipv6enabled, NUM_PORTS, ports, dht->self_public_key, dht->self_secret_key, onion);
if (tcp_s == NULL) {
printf("TCP server failed to initialize.\n");
exit(1);
}
#endif
FILE *file;
file = fopen("PUBLIC_ID.txt", "w");
for (i = 0; i < 32; i++) {
if (dht->c->self_public_key[i] < 16)
printf("0");
printf("%hhX", dht->c->self_public_key[i]);
fprintf(file, "%hhX", dht->c->self_public_key[i]);
printf("%02hhX", dht->self_public_key[i]);
fprintf(file, "%02hhX", dht->self_public_key[i]);
}
fclose(file);
printf("\n");
printf("Port: %u\n", ntohs(dht->c->lossless_udp->net->port));
printf("Port: %u\n", ntohs(dht->net->port));
if (argc > argvoffset + 3) {
printf("Trying to bootstrap into the network...\n");
@ -177,7 +190,10 @@ int main(int argc, char *argv[])
last_LANdiscovery = unix_time();
}
networking_poll(dht->c->lossless_udp->net);
#ifdef TCP_RELAY_ENABLED
do_TCP_server(tcp_s);
#endif
networking_poll(dht->net);
c_sleep(1);
}

View File

@ -1,3 +1,3 @@
As maintaining 2 seperate lists of the same information seemed redundant, this list has been phased out.
As maintaining 2 separate lists of the same information seemed redundant, this list has been phased out.
For a current DHT node list please visit http://wiki.tox.im/nodes

View File

@ -187,9 +187,7 @@ int main(int argc, char *argv[])
IP ip;
ip_init(&ip, ipv6enabled);
DHT *dht = new_DHT(new_net_crypto(new_networking(ip, PORT)));
new_keys(dht->c);
DHT *dht = new_DHT(new_networking(ip, PORT));
printf("OUR ID: ");
uint32_t i;
@ -245,7 +243,7 @@ int main(int argc, char *argv[])
}
}
*/
networking_poll(dht->c->lossless_udp->net);
networking_poll(dht->net);
print_clientlist(dht);
print_friendlist(dht);

View File

@ -1,260 +0,0 @@
/* Lossless_UDP testclient
* A program that connects and sends a file using our lossless UDP algorithm.
* NOTE: this program simulates a 33% packet loss.
*
* Best used in combination with Lossless_UDP_testserver
*
* Compile with: gcc -O2 -Wall -lsodium -o testclient ../toxcore/network.c ../toxcore/Lossless_UDP.c ../toxcore/util.c Lossless_UDP_testclient.c
*
* Command line arguments are the ip and port to connect and send the file to.
* EX: ./testclient --ipv4 127.0.0.1 33445 filename.txt
*
* Copyright (C) 2013 Tox project All Rights Reserved.
*
* This file is part of Tox.
*
* Tox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../toxcore/network.h"
#include "../toxcore/Lossless_UDP.h"
#include "../toxcore/util.h"
#include "misc_tools.c"
#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
#define c_sleep(x) Sleep(1*x)
#else
#include <unistd.h>
#include <arpa/inet.h>
#define c_sleep(x) usleep(1000*x)
#endif
#define PORT 33446
void printpacket(uint8_t *data, uint32_t length, IP_Port ip_port)
{
uint32_t i;
printf("UNHANDLED PACKET RECEIVED\nLENGTH:%u\nCONTENTS:\n", length);
printf("--------------------BEGIN-----------------------------\n");
for (i = 0; i < length; i++) {
if (data[i] < 16)
printf("0");
printf("%hhX", data[i]);
}
printf("\n--------------------END-----------------------------\n\n\n");
}
void printip(IP_Port ip_port)
{
printf("\nIP: %s Port: %u", ip_ntoa(&ip_port.ip), ntohs(ip_port.port));
}
/*
void printpackets(Data test)
{
int i;
if(test.size == 0)
return;
printf("SIZE: %u\n", test.size);
for(i =0; i < test.size; i++)
{
printf("%hhX", test.data[i]);
}
printf("\n");
}
void printconnection(int connection_id)
{
printf("--------------------BEGIN---------------------\n");
IP_Port ip_port = connections[connection_id].ip_port;
printf("IP: %u.%u.%u.%u Port: %u\n",ip_port.ip.c[0],ip_port.ip.c[1],ip_port.ip.c[2],ip_port.ip.c[3],ntohs(ip_port.port));
printf("status: %u, inbound: %u, SYNC_rate: %u\n", connections[connection_id].status,
connections[connection_id].inbound, connections[connection_id].SYNC_rate);
printf("data rate: %u, last sync: %llu, last sent: %llu, last recv: %llu \n", connections[connection_id].data_rate,
connections[connection_id].last_SYNC, connections[connection_id].last_sent, connections[connection_id].last_recv);
int i;
for(i =0; i < MAX_QUEUE_NUM; i++)
{
printf(" %u ",i);
printpackets(connections[connection_id].sendbuffer[i]);
}
for(i =0; i < MAX_QUEUE_NUM; i++)
{
printf(" %u ",i);
printpackets(connections[connection_id].recvbuffer[i]);
}
Data sendbuffer[MAX_QUEUE_NUM];
Data recvbuffer[MAX_QUEUE_NUM];
printf("recv_num: %u, orecv_num: %u, sent_packetnum %u, osent_packetnum: %u, successful_sent: %u, successful_read: %u\n",
connections[connection_id].recv_packetnum,
connections[connection_id].orecv_packetnum, connections[connection_id].sent_packetnum, connections[connection_id].osent_packetnum,
connections[connection_id].successful_sent,
connections[connection_id].successful_read);
printf("req packets: \n");
for(i = 0; i < BUFFER_PACKET_NUM; i++)
{
printf(" %u ", connections[connection_id].req_packets[i]);
}
printf("\nNumber: %u recv_counter: %u, send_counter: %u\n", connections[connection_id].num_req_paquets,
connections[connection_id].recv_counter, connections[connection_id].send_counter);
printf("--------------------END---------------------\n");
}
*/
/*( receive packets and send them to the packethandler */
/*run doLossless_UDP(); */
//void Lossless_UDP()
//{
/* IP_Port ip_port;
uint8_t data[MAX_UDP_PACKET_SIZE];
uint32_t length;
while (receivepacket(&ip_port, data, &length) != -1) {
printf("packet with length: %u\n", length); */
/* if(rand() % 3 != 1)//add packet loss
{ */
/*
if (LosslessUDP_handlepacket(data, length, ip_port))
printpacket(data, length, ip_port);
else
printf("Received handled packet with length: %u\n", length); //printconnection(0); */
/* } */
/* }*/
//networking_poll();
//doLossless_UDP();
//}
int main(int argc, char *argv[])
{
/* let user override default by cmdline */
uint8_t ipv6enabled = TOX_ENABLE_IPV6_DEFAULT; /* x */
int argvoffset = cmdline_parsefor_ipv46(argc, argv, &ipv6enabled);
if (argvoffset < 0)
exit(1);
if (argc < argvoffset + 4) {
printf("Usage: %s [--ipv4|--ipv6] ip port filename\n", argv[0]);
exit(0);
}
uint8_t buffer[MAX_DATA_SIZE];
int read;
FILE *file = fopen(argv[argvoffset + 3], "rb");
if (file == NULL) {
printf("Failed to open file \"%s\".\n", argv[argvoffset + 3]);
return 1;
}
/* initialize networking */
/* bind to ip 0.0.0.0:PORT */
IP ip;
ip_init(&ip, ipv6enabled);
Lossless_UDP *ludp = new_lossless_udp(new_networking(ip, PORT));
perror("Initialization");
IP_Port serverip;
ip_init(&serverip.ip, ipv6enabled);
if (!addr_resolve(argv[argvoffset + 1], &serverip.ip, NULL)) {
printf("Failed to convert \"%s\" into an IP address.\n", argv[argvoffset + 1]);
return 1;
}
serverip.port = htons(atoi(argv[argvoffset + 2]));
printip(serverip);
int connection = new_connection(ludp, serverip);
uint64_t timer = current_time();
while (1) {
/* printconnection(connection); */
networking_poll(ludp->net);
do_lossless_udp(ludp);
if (is_connected(ludp, connection) == LUDP_ESTABLISHED) {
printf("Connecting took: %llu us\n", (unsigned long long)(current_time() - timer));
break;
}
if (is_connected(ludp, connection) == LUDP_NO_CONNECTION) {
printf("Connection timeout after: %llu us\n", (unsigned long long)(current_time() - timer));
return 1;
}
c_sleep(1);
}
timer = current_time();
unsigned long long bytes_sent = 0;
/*read first part of file */
read = fread(buffer, 1, MAX_DATA_SIZE, file);
while (1) {
/* printconnection(connection); */
networking_poll(ludp->net);
do_lossless_udp(ludp);
if (is_connected(ludp, connection) == LUDP_ESTABLISHED) {
while (write_packet(ludp, connection, buffer, read)) {
bytes_sent += read;
/* printf("Wrote data.\n"); */
read = fread(buffer, 1, MAX_DATA_SIZE, file);
}
/* printf("%u\n", sendqueue(connection)); */
if (sendqueue(ludp, connection) == 0) {
if (read == 0) {
unsigned long long us = (unsigned long long)(current_time() - timer);
printf("Sent file successfully in: %llu us = %llu seconds. Average speed: %llu KB/s\n", us, us / 1000000UL,
bytes_sent / (us / 1024UL));
//printf("Total bytes sent: %llu B, Total data sent: %llu B, overhead: %llu B\n", total_bytes_sent, bytes_sent, total_bytes_sent-bytes_sent);
break;
}
}
} else {
printf("%u Client Connecting Lost after: %llu us\n", is_connected(ludp, connection),
(unsigned long long)(current_time() - timer));
return 0;
}
}
c_sleep(25);
return 0;
}

View File

@ -1,237 +0,0 @@
/* Lossless_UDP testserver
* A program that waits for a lossless UDP connection and then saves all the data received to a file.
* NOTE: this program simulates a 33% packet loss.
*
* Best used in combination with Lossless_UDP_testclient
*
* Compile with: gcc -O2 -Wall -lsodium -o testserver ../toxcore/network.c ../toxcore/Lossless_UDP.c ../toxcore/util.c Lossless_UDP_testserver.c
*
* Command line argument is the name of the file to save what we receive to.
* EX: ./testserver filename1.txt
*
* Copyright (C) 2013 Tox project All Rights Reserved.
*
* This file is part of Tox.
*
* Tox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../toxcore/network.h"
#include "../toxcore/Lossless_UDP.h"
#include "../toxcore/util.h"
#include "misc_tools.c"
//Sleep function (x = milliseconds)
#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
#define c_sleep(x) Sleep(1*x)
#else
#include <unistd.h>
#include <arpa/inet.h>
#define c_sleep(x) usleep(1000*x)
#endif
#define PORT 33445
void printpacket(uint8_t *data, uint32_t length, IP_Port ip_port)
{
uint32_t i;
printf("UNHANDLED PACKET RECEIVED\nLENGTH:%u\nCONTENTS:\n", length);
printf("--------------------BEGIN-----------------------------\n");
for (i = 0; i < length; i++) {
if (data[i] < 16)
printf("0");
printf("%hhX", data[i]);
}
printf("\n--------------------END-----------------------------\n\n\n");
}
/*
void printpackets(Data test)
{
int i;
if(test.size == 0)
return;
printf("SIZE: %u\n", test.size);
for(i =0; i < test.size; i++)
{
printf("%hhX", test.data[i]);
}
printf("\n");
}
void printconnection(int connection_id)
{
printf("--------------------BEGIN---------------------\n");
IP_Port ip_port = connections[connection_id].ip_port;
printf("IP: %u.%u.%u.%u Port: %u\n",ip_port.ip.c[0],ip_port.ip.c[1],ip_port.ip.c[2],ip_port.ip.c[3],ntohs(ip_port.port));
printf("status: %u, inbound: %u, SYNC_rate: %u\n", connections[connection_id].status,
connections[connection_id].inbound, connections[connection_id].SYNC_rate);
printf("data rate: %u, last sync: %llu, last sent: %llu, last recv: %llu \n", connections[connection_id].data_rate,
connections[connection_id].last_SYNC, connections[connection_id].last_sent, connections[connection_id].last_recv);
int i;
for(i =0; i < MAX_QUEUE_NUM; i++)
{
printf(" %u ",i);
printpackets(connections[connection_id].sendbuffer[i]);
}
for(i =0; i < MAX_QUEUE_NUM; i++)
{
printf(" %u ",i);
printpackets(connections[connection_id].recvbuffer[i]);
}
Data sendbuffer[MAX_QUEUE_NUM];
Data recvbuffer[MAX_QUEUE_NUM];
printf("recv_num: %u, orecv_num: %u, sent_packetnum %u, osent_packetnum: %u, successful_sent: %u, successful_read: %u\n",
connections[connection_id].recv_packetnum,
connections[connection_id].orecv_packetnum, connections[connection_id].sent_packetnum, connections[connection_id].osent_packetnum,
connections[connection_id].successful_sent,
connections[connection_id].successful_read);
printf("req packets: \n");
for(i = 0; i < BUFFER_PACKET_NUM; i++)
{
printf(" %u ", connections[connection_id].req_packets[i]);
}
printf("\nNumber: %u recv_counter: %u, send_counter: %u\n", connections[connection_id].num_req_paquets,
connections[connection_id].recv_counter, connections[connection_id].send_counter);
printf("--------------------END---------------------\n");
}
*/
/* receive packets and send them to the packethandler
* run doLossless_UDP(); */
//void Lossless_UDP()
//{
// IP_Port ip_port;
// uint8_t data[MAX_UDP_PACKET_SIZE];
// uint32_t length;
// while (receivepacket(&ip_port, data, &length) != -1) {
//if(rand() % 3 != 1)//add packet loss
//{
// if (LosslessUDP_handlepacket(data, length, ip_port)) {
// printpacket(data, length, ip_port);
// } else {
//printconnection(0);
// printf("Received handled packet with length: %u\n", length);
// }
//}
// }
// networking_poll();
//doLossless_UDP();
//}
int main(int argc, char *argv[])
{
/* let user override default by cmdline */
uint8_t ipv6enabled = TOX_ENABLE_IPV6_DEFAULT; /* x */
int argvoffset = cmdline_parsefor_ipv46(argc, argv, &ipv6enabled);
if (argvoffset < 0)
exit(1);
if (argc < argvoffset + 2) {
printf("Usage: %s [--ipv4|--ipv6] filename\n", argv[0]);
exit(0);
}
uint8_t buffer[MAX_DATA_SIZE];
int read;
FILE *file = fopen(argv[argvoffset + 1], "wb");
if (file == NULL) {
printf("Failed to open file \"%s\".\n", argv[argvoffset + 1]);
return 1;
}
//initialize networking
//bind to ip 0.0.0.0:PORT
IP ip;
ip_init(&ip, ipv6enabled);
Lossless_UDP *ludp = new_lossless_udp(new_networking(ip, PORT));
perror("Initialization");
int connection;
uint64_t timer = current_time();
while (1) {
networking_poll(ludp->net);
do_lossless_udp(ludp);
connection = incoming_connection(ludp, 0);
if (connection != -1) {
if (is_connected(ludp, connection) == LUDP_NOT_CONFIRMED) {
printf("Received the connection.\n");
}
break;
}
c_sleep(1);
}
timer = current_time();
while (1) {
//printconnection(0);
networking_poll(ludp->net);
if (is_connected(ludp, connection) >= LUDP_NOT_CONFIRMED) {
confirm_connection(ludp, connection);
while (1) {
read = read_packet(ludp, connection, buffer);
if (read != 0) {
// printf("Received data.\n");
if (!fwrite(buffer, read, 1, file))
printf("file write error\n");
} else {
break;
}
}
}
do_lossless_udp(ludp);
if (is_connected(ludp, connection) == LUDP_TIMED_OUT) {
printf("Server Connecting Lost after: %llu us\n", (unsigned long long)(current_time() - timer));
fclose(file);
return 1;
}
c_sleep(25);
}
return 0;
}

View File

@ -22,8 +22,6 @@ endif
if BUILD_TESTING
noinst_PROGRAMS += DHT_test \
Lossless_UDP_testclient \
Lossless_UDP_testserver \
Messenger_test \
crypto_speed_test
@ -41,40 +39,6 @@ DHT_test_LDADD = $(LIBSODIUM_LDFLAGS) \
$(WINSOCK2_LIBS)
Lossless_UDP_testclient_SOURCES = \
../testing/Lossless_UDP_testclient.c
Lossless_UDP_testclient_CFLAGS = \
$(LIBSODIUM_CFLAGS) \
$(NACL_CFLAGS)
Lossless_UDP_testclient_LDADD = \
$(LIBSODIUM_LDFLAGS) \
$(NACL_LDFLAGS) \
libtoxcore.la \
$(LIBSODIUM_LIBS) \
$(NACL_OBJECTS) \
$(NACL_LIBS) \
$(WINSOCK2_LIBS)
Lossless_UDP_testserver_SOURCES = \
../testing/Lossless_UDP_testserver.c
Lossless_UDP_testserver_CFLAGS = \
$(LIBSODIUM_CFLAGS) \
$(NACL_CFLAGS)
Lossless_UDP_testserver_LDADD = \
$(LIBSODIUM_LDFLAGS) \
$(NACL_LDFLAGS) \
libtoxcore.la \
$(LIBSODIUM_LIBS) \
$(NACL_OBJECTS) \
$(NACL_LIBS) \
$(WINSOCK2_LIBS)
Messenger_test_SOURCES = \
../testing/Messenger_test.c

View File

@ -97,8 +97,8 @@ int main(int argc, char *argv[])
starttime = get_time();
for (trialno = 0; trialno < numtrials; trialno++) {
encrypt_data_fast(k1, n, m, sizeof(m), c);
decrypt_data_fast(k2, n, c, sizeof(c), m);
encrypt_data_symmetric(k1, n, m, sizeof(m), c);
decrypt_data_symmetric(k2, n, c, sizeof(c), m);
}
endtime = get_time();

View File

@ -18,15 +18,18 @@ libtoxav_la_SOURCES = ../toxav/event.h \
libtoxav_la_CFLAGS = -I../toxcore \
-I../toxav \
$(LIBSODIUM_CFLAGS) \
$(NACL_CFLAGS) \
$(AV_CFLAGS) \
$(PTHREAD_CFLAGS)
libtoxav_la_LDFLAGS = $(TOXAV_LT_LDFLAGS) \
$(LIBSODIUM_LDFLAGS) \
$(NACL_LDFLAGS) \
$(EXTRA_LT_LDFLAGS)
libtoxav_la_LIBADD = libtoxcore.la \
$(LIBSODIUM_LIBS) \
$(NACL_LIBS) \
$(PTHREAD_LIBS) \
$(AV_LIBS)

View File

@ -27,6 +27,7 @@
#endif /* HAVE_CONFIG_H */
#include <stdlib.h>
#include "../toxcore/network.h" /* current_time_monotonic() */
#include "event.h"
#define _GNU_SOURCE
@ -199,7 +200,7 @@ void *event_poll( void *arg )
if ( _event_handler->timed_events ) {
uint32_t _time = ((uint32_t)(current_time() / 1000));
uint32_t _time = ((uint32_t)current_time_monotonic());
if ( _event_handler->timed_events[0].timeout < _time ) {
@ -249,7 +250,7 @@ int throw_timer_event ( void * (func)(void *), void *arg, unsigned timeout)
size_t _counter = event_handler.timed_events_count;
event_handler.timed_events[_counter - 1].timeout = timeout + ((uint32_t)(current_time() / 1000));
event_handler.timed_events[_counter - 1].timeout = timeout + ((uint32_t)current_time_monotonic());
event_handler.timed_events[_counter - 1].id = _unique_id;
++_unique_id;
@ -330,7 +331,7 @@ int reset_timer_event ( int id, uint32_t timeout )
/* Find it and change */
for ( ; _i; _i-- ) {
if ( _it->id == id ) {
_it->timeout = timeout + ((uint32_t)(current_time() / 1000));
_it->timeout = timeout + ((uint32_t)current_time_monotonic());
break;
}

View File

@ -36,7 +36,7 @@
#define VIDEO_CODEC_ENCODER_INTERFACE (vpx_codec_vp8_cx())
/* Audio encoding/decoding */
#include <opus/opus.h>
#include <opus.h>
typedef enum _Capabilities
{

View File

@ -28,8 +28,6 @@
#include "../toxcore/logger.h"
/*#define _BSD_SOURCE*/
#include "msi.h"
#include "event.h"
@ -219,7 +217,7 @@ static inline__ const uint8_t *stringify_response ( MSIResponse response )
* @param msg Container.
* @param data The data.
* @return int
* @retval -1 Error occured.
* @retval -1 Error occurred.
* @retval 0 Success.
*/
int parse_raw_data ( MSIMessage *msg, const uint8_t *data, uint16_t length )
@ -354,7 +352,7 @@ void free_message ( MSIMessage *msg )
* @param type Request or response.
* @param type_id Type of request/response.
* @return MSIMessage* Created message.
* @retval NULL Error occured.
* @retval NULL Error occurred.
*/
MSIMessage *msi_new_message ( uint8_t type, const uint8_t *type_id )
{
@ -387,7 +385,7 @@ MSIMessage *msi_new_message ( uint8_t type, const uint8_t *type_id )
*
* @param data The data.
* @return MSIMessage* Parsed message.
* @retval NULL Error occured.
* @retval NULL Error occurred.
*/
MSIMessage *parse_message ( const uint8_t *data, uint16_t length )
{
@ -495,7 +493,7 @@ uint8_t *append_header_to_string (
*dest = field_byte; /* Set the first byte */
uint8_t *_getback_byte = dest + 1; /* remeber the byte we were on */
uint8_t *_getback_byte = dest + 1; /* remember the byte we were on */
dest += 3; /* swith to 4th byte where field value starts */
/* Now set the field value and calculate it's length */
@ -685,7 +683,7 @@ static inline__ const uint8_t *stringify_error_code ( MSICallError error_code )
* @param msg The message.
* @param to Where to.
* @return int
* @retval -1 Error occured.
* @retval -1 Error occurred.
* @retval 0 Success.
*/
int send_message ( MSISession *session, MSICall* call, MSIMessage *msg, uint32_t to )
@ -838,7 +836,7 @@ int handle_error ( MSISession *session, MSICall* call, MSICallError errid, uint3
* @param msg The message.
* @return int
* @retval -1 No error.
* @retval 0 Error occured and response sent.
* @retval 0 Error occurred and response sent.
*/
int has_call_error ( MSISession *session, MSICall* call, MSIMessage *msg )
{
@ -951,7 +949,7 @@ MSICall *init_call ( MSISession *session, int peers, int ringing_timeout )
*
* @param session Control session.
* @return int
* @retval -1 Error occured.
* @retval -1 Error occurred.
* @retval 0 Success.
*/
int terminate_call ( MSISession *session, MSICall *call )
@ -1031,7 +1029,7 @@ int handle_recv_invite ( MSISession *session, MSICall* call, MSIMessage *msg )
* B calls A. Who has advantage is set bey calculating
* 'bigger' Call id and then that call id is being used in
* future. User with 'bigger' Call id has the advantage
* as in he will wait the reponse from the other.
* as in he will wait the response from the other.
*/
if ( call_id_bigger (call->id, msg->callid.header_value) == 1 ) { /* Peer has advantage */
@ -1408,7 +1406,7 @@ void msi_register_callback ( MSICallback callback, MSICallbackID id, void* userd
* @param messenger Tox* object.
* @param max_calls Amount of calls possible
* @return MSISession* The created session.
* @retval NULL Error occured.
* @retval NULL Error occurred.
*/
MSISession *msi_init_session ( Messenger* messenger, int32_t max_calls )
{
@ -1530,7 +1528,7 @@ int msi_invite ( MSISession* session, int32_t* call_index, MSICallType call_type
* @param session Control session.
* @param call_id To which call is this action handled.
* @return int
* @retval -1 Error occured.
* @retval -1 Error occurred.
* @retval 0 Success.
*/
int msi_hangup ( MSISession* session, int32_t call_index )

View File

@ -84,7 +84,7 @@ typedef struct _MSICall { /* Call info structure */
int ringing_timer_id; /* Timer id for ringing timeout */
pthread_mutex_t mutex; /* It's to be assumed that call will have
* seperate thread so add mutex
* separate thread so add mutex
*/
uint32_t *peers;
uint16_t peer_count;
@ -156,7 +156,7 @@ void msi_register_callback(MSICallback callback, MSICallbackID id, void* userdat
* @param messenger Tox* object.
* @param max_calls Amount of calls possible
* @return MSISession* The created session.
* @retval NULL Error occured.
* @retval NULL Error occurred.
*/
MSISession *msi_init_session ( Messenger *messenger, int32_t max_calls );
@ -189,7 +189,7 @@ int msi_invite ( MSISession *session, int32_t* call_index, MSICallType call_type
* @param session Control session.
* @param call_index To which call is this action handled.
* @return int
* @retval -1 Error occured.
* @retval -1 Error occurred.
* @retval 0 Success.
*/
int msi_hangup ( MSISession *session, int32_t call_index );

View File

@ -170,8 +170,8 @@ inline__ void increase_nonce(uint8_t *nonce, uint16_t target)
uint16_t _nonce_counter;
uint8_t _reverse_bytes[2];
_reverse_bytes[0] = nonce[crypto_secretbox_NONCEBYTES - 1];
_reverse_bytes[1] = nonce[crypto_secretbox_NONCEBYTES - 2];
_reverse_bytes[0] = nonce[crypto_box_NONCEBYTES - 1];
_reverse_bytes[1] = nonce[crypto_box_NONCEBYTES - 2];
bytes_to_U16(&_nonce_counter, _reverse_bytes );
@ -179,8 +179,8 @@ inline__ void increase_nonce(uint8_t *nonce, uint16_t target)
if (_nonce_counter > UINT16_MAX - target ) { /* 2 bytes are not long enough */
uint8_t _it = 3;
while ( _it <= crypto_secretbox_NONCEBYTES ) _it += ++nonce[crypto_secretbox_NONCEBYTES - _it] ?
crypto_secretbox_NONCEBYTES : 1;
while ( _it <= crypto_box_NONCEBYTES ) _it += ++nonce[crypto_box_NONCEBYTES - _it] ?
crypto_box_NONCEBYTES : 1;
_nonce_counter = _nonce_counter - (UINT16_MAX - target ); /* Assign the rest of it */
} else { /* Increase nonce */
@ -191,8 +191,8 @@ inline__ void increase_nonce(uint8_t *nonce, uint16_t target)
/* Assign the last bytes */
U16_to_bytes( _reverse_bytes, _nonce_counter);
nonce [crypto_secretbox_NONCEBYTES - 1] = _reverse_bytes[0];
nonce [crypto_secretbox_NONCEBYTES - 2] = _reverse_bytes[1];
nonce [crypto_box_NONCEBYTES - 1] = _reverse_bytes[0];
nonce [crypto_box_NONCEBYTES - 2] = _reverse_bytes[1];
}
@ -416,7 +416,7 @@ RTPHeader *build_header ( RTPSession *session )
ADD_SETTING_PAYLOAD ( _retu, session->payload_type );
_retu->sequnum = session->sequnum;
_retu->timestamp = ((uint32_t)(current_time() / 1000)); /* micro to milli */
_retu->timestamp = current_time_monotonic(); /* milliseconds */
_retu->ssrc = session->ssrc;
int i;
@ -505,7 +505,7 @@ int rtp_handle_packet ( void *object, IP_Port ip_port, uint8_t *data, uint32_t l
RTPSession *_session = object;
RTPMessage *_msg;
if ( !_session || length < 13 + crypto_secretbox_MACBYTES) { /* 12 is the minimum length for rtp + desc. byte */
if ( !_session || length < 13 + crypto_box_MACBYTES) { /* 12 is the minimum length for rtp + desc. byte */
LOGGER_WARNING("No session or invalid length of received buffer!");
return -1;
}
@ -521,12 +521,13 @@ int rtp_handle_packet ( void *object, IP_Port ip_port, uint8_t *data, uint32_t l
bytes_to_U16(&_sequnum, data + 1);
/* Clculate the right nonce */
uint8_t _calculated[crypto_secretbox_NONCEBYTES];
memcpy(_calculated, _session->decrypt_nonce, crypto_secretbox_NONCEBYTES);
uint8_t _calculated[crypto_box_NONCEBYTES];
memcpy(_calculated, _session->decrypt_nonce, crypto_box_NONCEBYTES);
increase_nonce ( _calculated, _sequnum );
/* Decrypt message */
int _decrypted_length = decrypt_data_symmetric((uint8_t *)_session->decrypt_key, _calculated, data + 3, length - 3, _plain );
int _decrypted_length = decrypt_data_symmetric(
(uint8_t *)_session->decrypt_key, _calculated, data + 3, length - 3, _plain );
/* This packet is either not encrypted properly or late
*/
@ -557,8 +558,8 @@ int rtp_handle_packet ( void *object, IP_Port ip_port, uint8_t *data, uint32_t l
}
/* A new cycle setting. */
memcpy(_session->nonce_cycle, _session->decrypt_nonce, crypto_secretbox_NONCEBYTES);
memcpy(_session->decrypt_nonce, _calculated, crypto_secretbox_NONCEBYTES);
memcpy(_session->nonce_cycle, _session->decrypt_nonce, crypto_box_NONCEBYTES);
memcpy(_session->decrypt_nonce, _calculated, crypto_box_NONCEBYTES);
}
}
@ -774,8 +775,8 @@ int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *dat
_send_data[0] = session->prefix;
/* Generate the right nonce */
uint8_t _calculated[crypto_secretbox_NONCEBYTES];
memcpy(_calculated, session->encrypt_nonce, crypto_secretbox_NONCEBYTES);
uint8_t _calculated[crypto_box_NONCEBYTES];
memcpy(_calculated, session->encrypt_nonce, crypto_box_NONCEBYTES);
increase_nonce ( _calculated, msg->header->sequnum );
/* Need to skip 2 bytes that are for sequnum */
@ -798,7 +799,7 @@ int rtp_send_msg ( RTPSession *session, Messenger *messenger, const uint8_t *dat
/* Set sequ number */
if ( session->sequnum >= MAX_SEQU_NUM ) {
session->sequnum = 0;
memcpy(session->encrypt_nonce, _calculated, crypto_secretbox_NONCEBYTES);
memcpy(session->encrypt_nonce, _calculated, crypto_box_NONCEBYTES);
} else {
session->sequnum++;
}
@ -888,16 +889,16 @@ RTPSession *rtp_init_session ( int payload_type,
_retu->decrypt_key = decrypt_key;
/* Need to allocate new memory */
_retu->encrypt_nonce = calloc ( crypto_secretbox_NONCEBYTES, sizeof (uint8_t) );
_retu->encrypt_nonce = calloc ( crypto_box_NONCEBYTES, sizeof (uint8_t) );
assert(_retu->encrypt_nonce);
_retu->decrypt_nonce = calloc ( crypto_secretbox_NONCEBYTES, sizeof (uint8_t) );
_retu->decrypt_nonce = calloc ( crypto_box_NONCEBYTES, sizeof (uint8_t) );
assert(_retu->decrypt_nonce);
_retu->nonce_cycle = calloc ( crypto_secretbox_NONCEBYTES, sizeof (uint8_t) );
_retu->nonce_cycle = calloc ( crypto_box_NONCEBYTES, sizeof (uint8_t) );
assert(_retu->nonce_cycle);
memcpy(_retu->encrypt_nonce, encrypt_nonce, crypto_secretbox_NONCEBYTES);
memcpy(_retu->decrypt_nonce, decrypt_nonce, crypto_secretbox_NONCEBYTES);
memcpy(_retu->nonce_cycle , decrypt_nonce, crypto_secretbox_NONCEBYTES);
memcpy(_retu->encrypt_nonce, encrypt_nonce, crypto_box_NONCEBYTES);
memcpy(_retu->decrypt_nonce, decrypt_nonce, crypto_box_NONCEBYTES);
memcpy(_retu->nonce_cycle , decrypt_nonce, crypto_box_NONCEBYTES);
_retu->csrc = calloc(1, sizeof (uint32_t));
assert(_retu->csrc);

View File

@ -165,15 +165,15 @@ void get_shared_key(Shared_Keys *shared_keys, uint8_t *shared_key, uint8_t *secr
}
}
/* Copy shared_key to decrypt DHT packet from client_id into shared_key
* for packets that we recieve.
/* Copy shared_key to encrypt/decrypt DHT packet from client_id into shared_key
* for packets that we receive.
*/
void DHT_get_shared_key_recv(DHT *dht, uint8_t *shared_key, uint8_t *client_id)
{
return get_shared_key(&dht->shared_keys_recv, shared_key, dht->self_secret_key, client_id);
}
/* Copy shared_key to decrypt DHT packet from client_id into shared_key
/* Copy shared_key to encrypt/decrypt DHT packet from client_id into shared_key
* for packets that we send.
*/
void DHT_get_shared_key_sent(DHT *dht, uint8_t *shared_key, uint8_t *client_id)
@ -181,6 +181,155 @@ void DHT_get_shared_key_sent(DHT *dht, uint8_t *shared_key, uint8_t *client_id)
return get_shared_key(&dht->shared_keys_sent, shared_key, dht->self_secret_key, client_id);
}
void to_net_family(IP *ip)
{
if (ip->family == AF_INET)
ip->family = TOX_AF_INET;
else if (ip->family == AF_INET6)
ip->family = TOX_AF_INET6;
}
void to_host_family(IP *ip)
{
if (ip->family == TOX_AF_INET)
ip->family = AF_INET;
else if (ip->family == TOX_AF_INET6)
ip->family = AF_INET6;
}
/* Pack number of nodes into data of maxlength length.
*
* return length of packed nodes on success.
* return -1 on failure.
*/
int pack_nodes(uint8_t *data, uint16_t length, Node_format *nodes, uint16_t number)
{
uint32_t i, packed_length = 0;
for (i = 0; i < number; ++i) {
int ipv6 = -1;
uint8_t net_family;
if (nodes[i].ip_port.ip.family == AF_INET) {
ipv6 = 0;
net_family = TOX_AF_INET;
} else if (nodes[i].ip_port.ip.family == TCP_INET) {
ipv6 = 0;
net_family = TOX_TCP_INET;
} else if (nodes[i].ip_port.ip.family == AF_INET6) {
ipv6 = 1;
net_family = TOX_AF_INET6;
} else if (nodes[i].ip_port.ip.family == TCP_INET6) {
ipv6 = 1;
net_family = TOX_TCP_INET6;
} else {
return -1;
}
if (ipv6 == 0) {
uint32_t size = 1 + sizeof(IP4) + sizeof(uint16_t) + CLIENT_ID_SIZE;
if (packed_length + size > length)
return -1;
data[packed_length] = net_family;
memcpy(data + packed_length + 1, &nodes[i].ip_port.ip.ip4, sizeof(IP4));
memcpy(data + packed_length + 1 + sizeof(IP4), &nodes[i].ip_port.port, sizeof(uint16_t));
memcpy(data + packed_length + 1 + sizeof(IP4) + sizeof(uint16_t), nodes[i].client_id, CLIENT_ID_SIZE);
packed_length += size;
} else if (ipv6 == 1) {
uint32_t size = 1 + sizeof(IP6) + sizeof(uint16_t) + CLIENT_ID_SIZE;
if (packed_length + size > length)
return -1;
data[packed_length] = net_family;
memcpy(data + packed_length + 1, &nodes[i].ip_port.ip.ip6, sizeof(IP6));
memcpy(data + packed_length + 1 + sizeof(IP6), &nodes[i].ip_port.port, sizeof(uint16_t));
memcpy(data + packed_length + 1 + sizeof(IP6) + sizeof(uint16_t), nodes[i].client_id, CLIENT_ID_SIZE);
packed_length += size;
} else {
return -1;
}
}
return packed_length;
}
/* Unpack data of length into nodes of size max_num_nodes.
* Put the length of the data processed in processed_data_len.
* tcp_enabled sets if TCP nodes are expected (true) or not (false).
*
* return number of unpacked nodes on success.
* return -1 on failure.
*/
int unpack_nodes(Node_format *nodes, uint16_t max_num_nodes, uint16_t *processed_data_len, uint8_t *data,
uint16_t length, uint8_t tcp_enabled)
{
uint32_t num = 0, len_processed = 0;
while (num < max_num_nodes && len_processed < length) {
int ipv6 = -1;
uint8_t host_family;
if (data[len_processed] == TOX_AF_INET) {
ipv6 = 0;
host_family = AF_INET;
} else if (data[len_processed] == TOX_TCP_INET) {
if (!tcp_enabled)
return -1;
ipv6 = 0;
host_family = TCP_INET;
} else if (data[len_processed] == TOX_AF_INET6) {
ipv6 = 1;
host_family = AF_INET6;
} else if (data[len_processed] == TOX_TCP_INET6) {
if (!tcp_enabled)
return -1;
ipv6 = 1;
host_family = TCP_INET6;
} else {
return -1;
}
if (ipv6 == 0) {
uint32_t size = 1 + sizeof(IP4) + sizeof(uint16_t) + CLIENT_ID_SIZE;
if (len_processed + size > length)
return -1;
nodes[num].ip_port.ip.family = host_family;
memcpy(&nodes[num].ip_port.ip.ip4, data + len_processed + 1, sizeof(IP4));
memcpy(&nodes[num].ip_port.port, data + len_processed + 1 + sizeof(IP4), sizeof(uint16_t));
memcpy(nodes[num].client_id, data + len_processed + 1 + sizeof(IP4) + sizeof(uint16_t), CLIENT_ID_SIZE);
len_processed += size;
++num;
} else if (ipv6 == 1) {
uint32_t size = 1 + sizeof(IP6) + sizeof(uint16_t) + CLIENT_ID_SIZE;
if (len_processed + size > length)
return -1;
nodes[num].ip_port.ip.family = host_family;
memcpy(&nodes[num].ip_port.ip.ip6, data + len_processed + 1, sizeof(IP6));
memcpy(&nodes[num].ip_port.port, data + len_processed + 1 + sizeof(IP6), sizeof(uint16_t));
memcpy(nodes[num].client_id, data + len_processed + 1 + sizeof(IP6) + sizeof(uint16_t), CLIENT_ID_SIZE);
len_processed += size;
++num;
} else {
return -1;
}
}
if (processed_data_len)
*processed_data_len = len_processed;
return num;
}
/* Check if client with client_id is already in list of length length.
* If it is then set its corresponding timestamp to current time.
@ -266,7 +415,7 @@ static int client_or_ip_port_in_list(Client_data *list, uint32_t length, uint8_t
/* Check if client with client_id is already in node format list of length length.
*
* return 1 if true.
* return 2 if false.
* return 0 if false.
*/
static int client_in_nodelist(Node_format *list, uint32_t length, uint8_t *client_id)
{
@ -310,15 +459,15 @@ static uint8_t hardening_correct(Hardening *h)
/*
* helper for get_close_nodes(). argument list is a monster :D
*/
static void get_close_nodes_inner(DHT *dht, uint8_t *client_id, Node_format *nodes_list,
static void get_close_nodes_inner(uint8_t *client_id, Node_format *nodes_list,
sa_family_t sa_family, Client_data *client_list, uint32_t client_list_length,
uint32_t *num_nodes_ptr, uint8_t is_LAN, uint8_t want_good)
{
if ((sa_family != AF_INET) && (sa_family != AF_INET6))
if ((sa_family != AF_INET) && (sa_family != AF_INET6) && (sa_family != 0))
return;
uint32_t num_nodes = *num_nodes_ptr;
int ipv46x, j, closest;
int j, closest;
uint32_t i;
for (i = 0; i < client_list_length; i++) {
@ -330,39 +479,22 @@ static void get_close_nodes_inner(DHT *dht, uint8_t *client_id, Node_format *nod
IPPTsPng *ipptp = NULL;
if (sa_family == AF_INET)
if (sa_family == AF_INET) {
ipptp = &client->assoc4;
else
} else if (sa_family == AF_INET6) {
ipptp = &client->assoc6;
} else {
if (client->assoc4.timestamp >= client->assoc6.timestamp) {
ipptp = &client->assoc4;
} else {
ipptp = &client->assoc6;
}
}
/* node not in a good condition? */
if (is_timeout(ipptp->timestamp, BAD_NODE_TIMEOUT))
continue;
IP *client_ip = &ipptp->ip_port.ip;
/*
* Careful: AF_INET isn't seen as AF_INET on dual-stack sockets for
* our connections, instead we have to look if it is an embedded
* IPv4-in-IPv6 here and convert it down in sendnodes().
*/
sa_family_t ip_treat_as_family = client_ip->family;
if ((dht->net->family == AF_INET6) &&
(client_ip->family == AF_INET6)) {
/* socket is AF_INET6, address claims AF_INET6:
* check for embedded IPv4-in-IPv6 (shouldn't happen anymore,
* all storing functions should already convert down to IPv4) */
if (IN6_IS_ADDR_V4MAPPED(&client_ip->ip6.in6_addr))
ip_treat_as_family = AF_INET;
}
ipv46x = !(sa_family == ip_treat_as_family);
/* node address of the wrong family? */
if (ipv46x)
continue;
/* don't send LAN ips to non LAN peers */
if (LAN_ip(ipptp->ip_port.ip) == 0 && !is_LAN)
continue;
@ -416,7 +548,7 @@ static int get_somewhat_close_nodes(DHT *dht, uint8_t *client_id, Node_format *n
uint8_t is_LAN, uint8_t want_good)
{
uint32_t num_nodes = 0, i;
get_close_nodes_inner(dht, client_id, nodes_list, sa_family,
get_close_nodes_inner(client_id, nodes_list, sa_family,
dht->close_clientlist, LCLIENT_LIST, &num_nodes, is_LAN, want_good);
/*TODO uncomment this when hardening is added to close friend clients
@ -426,7 +558,7 @@ static int get_somewhat_close_nodes(DHT *dht, uint8_t *client_id, Node_format *n
&num_nodes, is_LAN, want_good);
*/
for (i = 0; i < dht->num_friends; ++i)
get_close_nodes_inner(dht, client_id, nodes_list, sa_family,
get_close_nodes_inner(client_id, nodes_list, sa_family,
dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS,
&num_nodes, is_LAN, 0);
@ -444,6 +576,7 @@ int get_close_nodes(DHT *dht, uint8_t *client_id, Node_format *nodes_list, sa_fa
return get_somewhat_close_nodes(dht, client_id, nodes_list, sa_family, is_LAN, want_good);
#ifdef ENABLE_ASSOC_DHT
//TODO: assoc, sa_family 0 (don't care if ipv4 or ipv6) support.
Client_data *result[MAX_SENT_NODES];
Assoc_close_entries request;
@ -581,7 +714,7 @@ static int replace_possible_bad( Client_data *list,
sort_list(list, length, comp_client_id);
/* TODO: decide if the folowing lines should stay commented or not.
/* TODO: decide if the following lines should stay commented or not.
if (id_closest(comp_client_id, list[0].client_id, client_id) == 1)
return 0;*/
@ -823,7 +956,7 @@ end:
return 0;
}
#define NODES_ENCRYPTED_MESSAGE_LENGTH (crypto_secretbox_NONCEBYTES + sizeof(uint64_t) + sizeof(Node_format) + sizeof(Node_format) + crypto_secretbox_MACBYTES)
#define NODES_ENCRYPTED_MESSAGE_LENGTH (crypto_box_NONCEBYTES + sizeof(uint64_t) + sizeof(Node_format) + sizeof(Node_format) + crypto_box_MACBYTES)
/* Send a getnodes request.
sendback_node is the node that it will send back the response to (set to NULL to disable this) */
@ -842,23 +975,23 @@ static int getnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *cli
uint64_t temp_time = unix_time();
memcpy(plain_message, &temp_time, sizeof(temp_time));
Node_format reciever;
memcpy(reciever.client_id, public_key, CLIENT_ID_SIZE);
reciever.ip_port = ip_port;
memcpy(plain_message + sizeof(temp_time), &reciever, sizeof(reciever));
Node_format receiver;
memcpy(receiver.client_id, public_key, CLIENT_ID_SIZE);
receiver.ip_port = ip_port;
memcpy(plain_message + sizeof(temp_time), &receiver, sizeof(receiver));
if (sendback_node != NULL)
memcpy(plain_message + sizeof(temp_time) + sizeof(reciever), sendback_node, sizeof(Node_format));
memcpy(plain_message + sizeof(temp_time) + sizeof(receiver), sendback_node, sizeof(Node_format));
else
memset(plain_message + sizeof(temp_time) + sizeof(reciever), 0, sizeof(Node_format));
memset(plain_message + sizeof(temp_time) + sizeof(receiver), 0, sizeof(Node_format));
int len_m = encrypt_data_symmetric(dht->secret_symmetric_key,
nonce,
plain_message,
sizeof(temp_time) + sizeof(reciever) + sizeof(Node_format),
encrypted_message + crypto_secretbox_NONCEBYTES);
sizeof(temp_time) + sizeof(receiver) + sizeof(Node_format),
encrypted_message + crypto_box_NONCEBYTES);
if (len_m != NODES_ENCRYPTED_MESSAGE_LENGTH - crypto_secretbox_NONCEBYTES)
if (len_m != NODES_ENCRYPTED_MESSAGE_LENGTH - crypto_box_NONCEBYTES)
return -1;
uint8_t data[1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + CLIENT_ID_SIZE + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES];
@ -871,11 +1004,11 @@ static int getnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *cli
uint8_t shared_key[crypto_box_BEFORENMBYTES];
DHT_get_shared_key_sent(dht, shared_key, public_key);
int len = encrypt_data_fast( shared_key,
nonce,
plain,
CLIENT_ID_SIZE + NODES_ENCRYPTED_MESSAGE_LENGTH,
encrypt );
int len = encrypt_data_symmetric( shared_key,
nonce,
plain,
CLIENT_ID_SIZE + NODES_ENCRYPTED_MESSAGE_LENGTH,
encrypt );
if (len != CLIENT_ID_SIZE + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES)
return -1;
@ -888,132 +1021,46 @@ static int getnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *cli
return sendpacket(dht->net, ip_port, data, sizeof(data));
}
/* Send a send nodes response. */
/* because of BINARY compatibility, the Node_format MUST BE Node4_format,
* IPv6 nodes are sent in a different message
* encrypted_data must be of size NODES_ENCRYPTED_MESSAGE_LENGTH */
static int sendnodes(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *client_id, uint8_t *encrypted_data,
uint8_t *shared_encryption_key)
{
/* Check if packet is going to be sent to ourself. */
if (id_equal(public_key, dht->self_public_key))
return -1;
size_t Node4_format_size = sizeof(Node4_format);
uint8_t data[1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES
+ Node4_format_size * MAX_SENT_NODES + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES];
Node_format nodes_list[MAX_SENT_NODES];
uint32_t num_nodes = get_close_nodes(dht, client_id, nodes_list, AF_INET, LAN_ip(ip_port.ip) == 0, 1);
if (num_nodes == 0)
return 0;
uint8_t plain[Node4_format_size * MAX_SENT_NODES + NODES_ENCRYPTED_MESSAGE_LENGTH];
uint8_t encrypt[Node4_format_size * MAX_SENT_NODES + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES];
uint8_t nonce[crypto_box_NONCEBYTES];
new_nonce(nonce);
Node4_format *nodes4_list = (Node4_format *)(plain);
uint32_t i, num_nodes_ok = 0;
for (i = 0; i < num_nodes; i++) {
memcpy(nodes4_list[num_nodes_ok].client_id, nodes_list[i].client_id, CLIENT_ID_SIZE);
nodes4_list[num_nodes_ok].ip_port.port = nodes_list[i].ip_port.port;
IP *node_ip = &nodes_list[i].ip_port.ip;
if ((node_ip->family == AF_INET6) && IN6_IS_ADDR_V4MAPPED(&node_ip->ip6.in6_addr))
/* embedded IPv4-in-IPv6 address: return it in regular sendnodes packet */
nodes4_list[num_nodes_ok].ip_port.ip.uint32 = node_ip->ip6.uint32[3];
else if (node_ip->family == AF_INET)
nodes4_list[num_nodes_ok].ip_port.ip.uint32 = node_ip->ip4.uint32;
else /* shouldn't happen */
continue;
num_nodes_ok++;
}
if (num_nodes_ok < num_nodes) {
/* shouldn't happen */
num_nodes = num_nodes_ok;
}
memcpy(plain + num_nodes * Node4_format_size, encrypted_data, NODES_ENCRYPTED_MESSAGE_LENGTH);
int len = encrypt_data_fast( shared_encryption_key,
nonce,
plain,
num_nodes * Node4_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH,
encrypt );
if ((unsigned int)len != num_nodes * Node4_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH +
crypto_box_MACBYTES)
return -1;
data[0] = NET_PACKET_SEND_NODES;
memcpy(data + 1, dht->self_public_key, CLIENT_ID_SIZE);
memcpy(data + 1 + CLIENT_ID_SIZE, nonce, crypto_box_NONCEBYTES);
memcpy(data + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, encrypt, len);
return sendpacket(dht->net, ip_port, data, 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + len);
}
void to_net_family(IP *ip)
{
ip->padding[0] = 0;
ip->padding[1] = 0;
ip->padding[2] = 0;
if (ip->family == AF_INET)
ip->family = TOX_AF_INET;
else if (ip->family == AF_INET6)
ip->family = TOX_AF_INET6;
}
void to_host_family(IP *ip)
{
if (ip->family == TOX_AF_INET)
ip->family = AF_INET;
else if (ip->family == TOX_AF_INET6)
ip->family = AF_INET6;
}
/* Send a send nodes response: message for IPv6 nodes */
static int sendnodes_ipv6(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *client_id, uint8_t *encrypted_data,
uint8_t *shared_encryption_key)
static int sendnodes_ipv6(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_t *client_id, uint8_t *sendback_data,
uint16_t length, uint8_t *shared_encryption_key)
{
/* Check if packet is going to be sent to ourself. */
if (id_equal(public_key, dht->self_public_key))
return -1;
if (length > NODES_ENCRYPTED_MESSAGE_LENGTH || length == 0)
return -1;
size_t Node_format_size = sizeof(Node_format);
uint8_t data[1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES
+ Node_format_size * MAX_SENT_NODES + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES];
+ Node_format_size * MAX_SENT_NODES + length + crypto_box_MACBYTES];
Node_format nodes_list[MAX_SENT_NODES];
uint32_t num_nodes = get_close_nodes(dht, client_id, nodes_list, AF_INET6, LAN_ip(ip_port.ip) == 0, 1);
uint32_t num_nodes = get_close_nodes(dht, client_id, nodes_list, 0, LAN_ip(ip_port.ip) == 0, 1);
if (num_nodes == 0)
return 0;
uint8_t plain[Node_format_size * MAX_SENT_NODES + NODES_ENCRYPTED_MESSAGE_LENGTH];
uint8_t encrypt[Node_format_size * MAX_SENT_NODES + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES];
uint8_t plain[1 + Node_format_size * MAX_SENT_NODES + length];
uint8_t encrypt[sizeof(plain) + crypto_box_MACBYTES];
uint8_t nonce[crypto_box_NONCEBYTES];
new_nonce(nonce);
uint32_t i;
int nodes_length = pack_nodes(plain + 1, Node_format_size * MAX_SENT_NODES, nodes_list, num_nodes);
for (i = 0; i < num_nodes; ++i)
to_net_family(&nodes_list[i].ip_port.ip);
if (nodes_length <= 0)
return -1;
memcpy(plain, nodes_list, num_nodes * Node_format_size);
memcpy(plain + num_nodes * Node_format_size, encrypted_data, NODES_ENCRYPTED_MESSAGE_LENGTH);
int len = encrypt_data_fast( shared_encryption_key,
nonce,
plain,
num_nodes * Node_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH,
encrypt );
plain[0] = num_nodes;
memcpy(plain + 1 + nodes_length, sendback_data, length);
int len = encrypt_data_symmetric( shared_encryption_key,
nonce,
plain,
1 + nodes_length + length,
encrypt );
if ((unsigned int)len != num_nodes * Node_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES)
if (len != 1 + nodes_length + length + crypto_box_MACBYTES)
return -1;
data[0] = NET_PACKET_SEND_NODES_IPV6;
@ -1026,35 +1073,38 @@ static int sendnodes_ipv6(DHT *dht, IP_Port ip_port, uint8_t *public_key, uint8_
static int handle_getnodes(void *object, IP_Port source, uint8_t *packet, uint32_t length)
{
DHT *dht = object;
uint32_t cmp_len = 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + CLIENT_ID_SIZE + crypto_box_MACBYTES;
if (length != ( 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + CLIENT_ID_SIZE + NODES_ENCRYPTED_MESSAGE_LENGTH +
crypto_box_MACBYTES ))
if (length <= cmp_len)
return 1;
if (length > cmp_len + NODES_ENCRYPTED_MESSAGE_LENGTH)
return 1;
uint16_t sendback_data_length = length - cmp_len;
DHT *dht = object;
/* Check if packet is from ourself. */
if (id_equal(packet + 1, dht->self_public_key))
return 1;
uint8_t plain[CLIENT_ID_SIZE + NODES_ENCRYPTED_MESSAGE_LENGTH];
uint8_t plain[CLIENT_ID_SIZE + sendback_data_length];
uint8_t shared_key[crypto_box_BEFORENMBYTES];
DHT_get_shared_key_recv(dht, shared_key, packet + 1);
int len = decrypt_data_fast( shared_key,
packet + 1 + CLIENT_ID_SIZE,
packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES,
CLIENT_ID_SIZE + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES,
plain );
int len = decrypt_data_symmetric( shared_key,
packet + 1 + CLIENT_ID_SIZE,
packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES,
CLIENT_ID_SIZE + sendback_data_length + crypto_box_MACBYTES,
plain );
if (len != CLIENT_ID_SIZE + NODES_ENCRYPTED_MESSAGE_LENGTH)
if (len != CLIENT_ID_SIZE + sendback_data_length)
return 1;
sendnodes(dht, source, packet + 1, plain, plain + CLIENT_ID_SIZE, shared_key);
sendnodes_ipv6(dht, source, packet + 1, plain,
plain + CLIENT_ID_SIZE, shared_key); /* TODO: prevent possible amplification attacks */
sendnodes_ipv6(dht, source, packet + 1, plain, plain + CLIENT_ID_SIZE, sendback_data_length, shared_key);
add_to_ping(dht->ping, packet + 1, source);
//send_ping_request(dht, source, packet + 1); /* TODO: make this smarter? */
return 0;
}
@ -1066,8 +1116,8 @@ static uint8_t sent_getnode_to_node(DHT *dht, uint8_t *client_id, IP_Port node_i
{
uint8_t plain_message[NODES_ENCRYPTED_MESSAGE_LENGTH];
if (decrypt_data_symmetric(dht->secret_symmetric_key, encrypted_data, encrypted_data + crypto_secretbox_NONCEBYTES,
NODES_ENCRYPTED_MESSAGE_LENGTH - crypto_secretbox_NONCEBYTES,
if (decrypt_data_symmetric(dht->secret_symmetric_key, encrypted_data, encrypted_data + crypto_box_NONCEBYTES,
NODES_ENCRYPTED_MESSAGE_LENGTH - crypto_box_NONCEBYTES,
plain_message) != sizeof(uint64_t) + sizeof(Node_format) * 2)
return 0;
@ -1089,44 +1139,58 @@ static uint8_t sent_getnode_to_node(DHT *dht, uint8_t *client_id, IP_Port node_i
}
/* Function is needed in following functions. */
static int send_hardening_getnode_res(DHT *dht, Node_format *sendto, uint8_t *queried_client_id, Node_format *list,
uint16_t num_nodes);
static int send_hardening_getnode_res(DHT *dht, Node_format *sendto, uint8_t *queried_client_id, uint8_t *nodes_data,
uint16_t nodes_data_length);
static int handle_sendnodes_core(void *object, IP_Port source, uint8_t *packet, uint32_t length,
size_t node_format_size, uint8_t *plain, uint16_t plain_length, uint32_t *num_nodes_out, Node_format *sendback_node)
Node_format *plain_nodes, uint16_t size_plain_nodes, uint32_t *num_nodes_out)
{
if (plain_length != MAX_SENT_NODES * node_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH)
return 1;
DHT *dht = object;
uint32_t cid_size = 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES;
uint32_t cid_size = 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + 1 + NODES_ENCRYPTED_MESSAGE_LENGTH +
crypto_box_MACBYTES;
if (length <= cid_size) /* too short */
return 1;
uint32_t data_size = length - cid_size;
if ((data_size % node_format_size) != 0) /* invalid length */
if (data_size == 0)
return 1;
uint32_t num_nodes = data_size / node_format_size;
if (num_nodes > MAX_SENT_NODES) /* too long */
if (data_size > sizeof(Node_format) * MAX_SENT_NODES) /* invalid length */
return 1;
uint8_t plain[1 + data_size + NODES_ENCRYPTED_MESSAGE_LENGTH];
uint8_t shared_key[crypto_box_BEFORENMBYTES];
DHT_get_shared_key_sent(dht, shared_key, packet + 1);
int len = decrypt_data_fast(
int len = decrypt_data_symmetric(
shared_key,
packet + 1 + CLIENT_ID_SIZE,
packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES,
num_nodes * node_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES,
1 + data_size + NODES_ENCRYPTED_MESSAGE_LENGTH + crypto_box_MACBYTES,
plain);
if ((unsigned int)len != num_nodes * node_format_size + NODES_ENCRYPTED_MESSAGE_LENGTH)
if ((unsigned int)len != sizeof(plain))
return 1;
if (!sent_getnode_to_node(dht, packet + 1, source, plain + num_nodes * node_format_size, sendback_node))
if (plain[0] > size_plain_nodes || plain[0] == 0)
return 1;
Node_format sendback_node;
if (!sent_getnode_to_node(dht, packet + 1, source, plain + 1 + data_size, &sendback_node))
return 1;
uint16_t length_nodes = 0;
int num_nodes = unpack_nodes(plain_nodes, plain[0], &length_nodes, plain + 1, data_size, 0);
if (length_nodes != data_size)
return 1;
if (num_nodes != plain[0])
return 1;
if (num_nodes <= 0)
return 1;
/* store the address the *request* was sent to */
@ -1134,79 +1198,28 @@ static int handle_sendnodes_core(void *object, IP_Port source, uint8_t *packet,
*num_nodes_out = num_nodes;
return 0;
}
static int handle_sendnodes(void *object, IP_Port source, uint8_t *packet, uint32_t length)
{
DHT *dht = object;
size_t node4_format_size = sizeof(Node4_format);
uint8_t plain[node4_format_size * MAX_SENT_NODES + NODES_ENCRYPTED_MESSAGE_LENGTH];
uint32_t num_nodes;
Node_format sendback_node;
if (handle_sendnodes_core(object, source, packet, length, node4_format_size, plain, sizeof(plain), &num_nodes,
&sendback_node))
return 1;
if (num_nodes == 0)
return 0;
Node4_format *nodes4_list = (Node4_format *)(plain);
uint64_t time_now = unix_time();
IPPTs ippts;
ippts.ip_port.ip.family = AF_INET;
ippts.timestamp = time_now;
uint32_t i;
Node_format nodes_list[MAX_SENT_NODES];
for (i = 0; i < num_nodes; i++)
if ((nodes4_list[i].ip_port.ip.uint32 != 0) && (nodes4_list[i].ip_port.ip.uint32 != (uint32_t)~0)) {
ippts.ip_port.ip.ip4.uint32 = nodes4_list[i].ip_port.ip.uint32;
ippts.ip_port.port = nodes4_list[i].ip_port.port;
send_ping_request(dht->ping, ippts.ip_port, nodes4_list[i].client_id);
returnedip_ports(dht, ippts.ip_port, nodes4_list[i].client_id, packet + 1);
memcpy(nodes_list[i].client_id, nodes4_list[i].client_id, CLIENT_ID_SIZE);
ipport_copy(&nodes_list[i].ip_port, &ippts.ip_port);
}
send_hardening_getnode_res(dht, &sendback_node, packet + 1, nodes_list, num_nodes);
send_hardening_getnode_res(dht, &sendback_node, packet + 1, plain + 1, data_size);
return 0;
}
static int handle_sendnodes_ipv6(void *object, IP_Port source, uint8_t *packet, uint32_t length)
{
DHT *dht = object;
size_t node_format_size = sizeof(Node_format);
uint8_t plain[node_format_size * MAX_SENT_NODES + NODES_ENCRYPTED_MESSAGE_LENGTH];
Node_format plain_nodes[MAX_SENT_NODES];
uint32_t num_nodes;
Node_format sendback_node;
if (handle_sendnodes_core(object, source, packet, length, node_format_size, plain, sizeof(plain), &num_nodes,
&sendback_node))
if (handle_sendnodes_core(object, source, packet, length, plain_nodes, MAX_SENT_NODES, &num_nodes))
return 1;
if (num_nodes == 0)
return 0;
Node_format *nodes_list = (Node_format *)(plain);
uint32_t i;
send_hardening_getnode_res(dht, &sendback_node, packet + 1, nodes_list, num_nodes);
for (i = 0; i < num_nodes; i++) {
to_host_family(&nodes_list[i].ip_port.ip);
if (ipport_isset(&nodes_list[i].ip_port)) {
send_ping_request(dht->ping, nodes_list[i].ip_port, nodes_list[i].client_id);
returnedip_ports(dht, nodes_list[i].ip_port, nodes_list[i].client_id, packet + 1);
if (ipport_isset(&plain_nodes[i].ip_port)) {
send_ping_request(dht->ping, plain_nodes[i].ip_port, plain_nodes[i].client_id);
returnedip_ports(dht, plain_nodes[i].ip_port, plain_nodes[i].client_id, packet + 1);
}
}
@ -1595,7 +1608,7 @@ static int friend_iplist(DHT *dht, IP_Port *ip_portlist, uint16_t friend_num)
/* Send the following packet to everyone who tells us they are connected to friend_id.
*
* return ip for friend.
* return number of nodes the packet was sent to. (Only works if more than (MAX_FRIEND_CLIENTS / 2).
* return number of nodes the packet was sent to. (Only works if more than (MAX_FRIEND_CLIENTS / 4).
*/
int route_tofriend(DHT *dht, uint8_t *friend_id, uint8_t *packet, uint32_t length)
{
@ -1724,7 +1737,7 @@ int friend_ips(DHT *dht, IP_Port *ip_portlist, uint8_t *friend_id)
static int send_NATping(DHT *dht, uint8_t *public_key, uint64_t ping_id, uint8_t type)
{
uint8_t data[sizeof(uint64_t) + 1];
uint8_t packet[MAX_DATA_SIZE];
uint8_t packet[MAX_CRYPTO_REQUEST_SIZE];
int num = 0;
@ -1935,7 +1948,7 @@ static int send_hardening_req(DHT *dht, Node_format *sendto, uint8_t type, uint8
if (length > HARDREQ_DATA_SIZE - 1)
return -1;
uint8_t packet[MAX_DATA_SIZE];
uint8_t packet[MAX_CRYPTO_REQUEST_SIZE];
uint8_t data[HARDREQ_DATA_SIZE] = {0};
data[0] = type;
memcpy(data + 1, contents, length);
@ -1958,17 +1971,17 @@ static int send_hardening_getnode_req(DHT *dht, Node_format *dest, Node_format *
}
/* Send a get node hardening response */
static int send_hardening_getnode_res(DHT *dht, Node_format *sendto, uint8_t *queried_client_id, Node_format *list,
uint16_t num_nodes)
static int send_hardening_getnode_res(DHT *dht, Node_format *sendto, uint8_t *queried_client_id, uint8_t *nodes_data,
uint16_t nodes_data_length)
{
if (!ip_isset(&sendto->ip_port.ip))
return -1;
uint8_t packet[MAX_DATA_SIZE];
uint8_t data[1 + CLIENT_ID_SIZE + num_nodes * sizeof(Node_format)];
uint8_t packet[MAX_CRYPTO_REQUEST_SIZE];
uint8_t data[1 + CLIENT_ID_SIZE + nodes_data_length];
data[0] = CHECK_TYPE_GETNODE_RES;
memcpy(data + 1, queried_client_id, CLIENT_ID_SIZE);
memcpy(data + 1 + CLIENT_ID_SIZE, list, num_nodes * sizeof(Node_format));
memcpy(data + 1 + CLIENT_ID_SIZE, nodes_data, nodes_data_length);
int len = create_request(dht->self_public_key, dht->self_secret_key, packet, sendto->client_id, data,
sizeof(data), CRYPTO_PACKET_HARDENING);
@ -2056,28 +2069,22 @@ static int handle_hardening(void *object, IP_Port source, uint8_t *source_pubkey
if (length <= CLIENT_ID_SIZE + 1)
return 1;
if ((length - 1 - CLIENT_ID_SIZE) % sizeof(Node_format) != 0)
if (length > 1 + CLIENT_ID_SIZE + sizeof(Node_format) * MAX_SENT_NODES)
return 1;
uint16_t num = (length - 1 - CLIENT_ID_SIZE) / sizeof(Node_format);
uint16_t length_nodes = length - 1 - CLIENT_ID_SIZE;
Node_format nodes[MAX_SENT_NODES];
int num_nodes = unpack_nodes(nodes, MAX_SENT_NODES, 0, packet + 1 + CLIENT_ID_SIZE, length_nodes, 0);
/* TODO: MAX_SENT_NODES nodes should be returned at all times
(right now we have a small network size so it could cause problems for testing and etc..) */
if (num > MAX_SENT_NODES || num == 0)
if (num_nodes <= 0)
return 1;
Node_format nodes[num];
memcpy(nodes, packet + 1 + CLIENT_ID_SIZE, sizeof(Node_format)*num);
uint32_t i;
for (i = 0; i < num; ++i)
to_host_family(&nodes[i].ip_port.ip);
/* NOTE: This should work for now but should be changed to something better. */
if (have_nodes_closelist(dht, nodes, num) < (uint32_t)((num + 2) / 2))
if (have_nodes_closelist(dht, nodes, num_nodes) < (uint32_t)((num_nodes + 2) / 2))
return 1;
IPPTsPng *temp = get_closelist_IPPTsPng(dht, packet + 1, nodes[0].ip_port.ip.family);
if (temp == NULL)
@ -2204,6 +2211,8 @@ static int random_node_fromlist(Client_data *list, uint16_t list_size, Node_form
* return the number of nodes.
*
* NOTE:this is used to pick nodes for paths.
*
* TODO: remove the LAN stuff from this.
*/
uint16_t random_nodes_path(DHT *dht, Node_format *nodes, uint16_t max_num)
{
@ -2287,12 +2296,54 @@ void do_hardening(DHT *dht)
/*----------------------------------------------------------------------------------*/
DHT *new_DHT(Net_Crypto *c)
void cryptopacket_registerhandler(DHT *dht, uint8_t byte, cryptopacket_handler_callback cb, void *object)
{
dht->cryptopackethandlers[byte].function = cb;
dht->cryptopackethandlers[byte].object = object;
}
static int cryptopacket_handle(void *object, IP_Port source, uint8_t *packet, uint32_t length)
{
DHT *dht = object;
if (packet[0] == NET_PACKET_CRYPTO) {
if (length <= crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + crypto_box_MACBYTES ||
length > MAX_CRYPTO_REQUEST_SIZE + crypto_box_MACBYTES)
return 1;
if (memcmp(packet + 1, dht->self_public_key, crypto_box_PUBLICKEYBYTES) == 0) { // Check if request is for us.
uint8_t public_key[crypto_box_PUBLICKEYBYTES];
uint8_t data[MAX_CRYPTO_REQUEST_SIZE];
uint8_t number;
int len = handle_request(dht->self_public_key, dht->self_secret_key, public_key, data, &number, packet, length);
if (len == -1 || len == 0)
return 1;
if (!dht->cryptopackethandlers[number].function) return 1;
return dht->cryptopackethandlers[number].function(dht->cryptopackethandlers[number].object, source, public_key,
data, len);
} else { /* If request is not for us, try routing it. */
int retval = route_packet(dht, packet + 1, packet, length);
if ((unsigned int)retval == length)
return 0;
}
}
return 1;
}
/*----------------------------------------------------------------------------------*/
DHT *new_DHT(Networking_Core *net)
{
/* init time */
unix_time_update();
if (c == NULL)
if (net == NULL)
return NULL;
DHT *dht = calloc(1, sizeof(DHT));
@ -2300,8 +2351,7 @@ DHT *new_DHT(Net_Crypto *c)
if (dht == NULL)
return NULL;
dht->c = c;
dht->net = c->lossless_udp->net;
dht->net = net;
dht->ping = new_ping(dht);
if (dht->ping == NULL) {
@ -2310,11 +2360,10 @@ DHT *new_DHT(Net_Crypto *c)
}
networking_registerhandler(dht->net, NET_PACKET_GET_NODES, &handle_getnodes, dht);
networking_registerhandler(dht->net, NET_PACKET_SEND_NODES, &handle_sendnodes, dht);
networking_registerhandler(dht->net, NET_PACKET_SEND_NODES_IPV6, &handle_sendnodes_ipv6, dht);
init_cryptopackets(dht);
cryptopacket_registerhandler(c, CRYPTO_PACKET_NAT_PING, &handle_NATping, dht);
cryptopacket_registerhandler(c, CRYPTO_PACKET_HARDENING, &handle_hardening, dht);
networking_registerhandler(dht->net, NET_PACKET_CRYPTO, &cryptopacket_handle, dht);
cryptopacket_registerhandler(dht, CRYPTO_PACKET_NAT_PING, &handle_NATping, dht);
cryptopacket_registerhandler(dht, CRYPTO_PACKET_HARDENING, &handle_hardening, dht);
new_symmetric_key(dht->secret_symmetric_key);
crypto_box_keypair(dht->self_public_key, dht->self_secret_key);
@ -2361,8 +2410,8 @@ void kill_DHT(DHT *dht)
networking_registerhandler(dht->net, NET_PACKET_GET_NODES, NULL, NULL);
networking_registerhandler(dht->net, NET_PACKET_SEND_NODES, NULL, NULL);
networking_registerhandler(dht->net, NET_PACKET_SEND_NODES_IPV6, NULL, NULL);
cryptopacket_registerhandler(dht->c, CRYPTO_PACKET_NAT_PING, NULL, NULL);
cryptopacket_registerhandler(dht->c, CRYPTO_PACKET_HARDENING, NULL, NULL);
cryptopacket_registerhandler(dht, CRYPTO_PACKET_NAT_PING, NULL, NULL);
cryptopacket_registerhandler(dht, CRYPTO_PACKET_HARDENING, NULL, NULL);
kill_ping(dht->ping);
free(dht->friends_list);
free(dht);

View File

@ -24,7 +24,8 @@
#ifndef DHT_H
#define DHT_H
#include "net_crypto.h"
#include "crypto_core.h"
#include "network.h"
/* Size of the client_id in bytes. */
#define CLIENT_ID_SIZE crypto_box_PUBLICKEYBYTES
@ -36,7 +37,7 @@
#define LCLIENT_LIST 32
/* The max number of nodes to send with send nodes. */
#define MAX_SENT_NODES 8
#define MAX_SENT_NODES 4
/* Ping timeout in seconds */
#define PING_TIMEOUT 3
@ -52,6 +53,8 @@
/* Redefinitions of variables for safe transfer over wire. */
#define TOX_AF_INET 2
#define TOX_AF_INET6 10
#define TOX_TCP_INET 130
#define TOX_TCP_INET6 138
/* The number of "fake" friends to add (for optimization purposes and so our paths for the onion part are more random) */
#define DHT_FAKE_FRIEND_NUMBER 4
@ -128,16 +131,30 @@ typedef struct {
NAT nat;
} DHT_Friend;
/* this must be kept even if IP_Port is expanded: wire compatibility */
typedef struct {
uint8_t client_id[CLIENT_ID_SIZE];
IP4_Port ip_port;
} Node4_format;
typedef struct {
typedef struct __attribute__ ((__packed__))
{
uint8_t client_id[CLIENT_ID_SIZE];
IP_Port ip_port;
} Node_format;
}
Node_format;
/* Pack number of nodes into data of maxlength length.
*
* return length of packed nodes on success.
* return -1 on failure.
*/
int pack_nodes(uint8_t *data, uint16_t length, Node_format *nodes, uint16_t number);
/* Unpack data of length into nodes of size max_num_nodes.
* Put the length of the data processed in processed_data_len.
* tcp_enabled sets if TCP nodes are expected (true) or not (false).
*
* return number of unpacked nodes on success.
* return -1 on failure.
*/
int unpack_nodes(Node_format *nodes, uint16_t max_num_nodes, uint16_t *processed_data_len, uint8_t *data,
uint16_t length, uint8_t tcp_enabled);
/*----------------------------------------------------------------------------------*/
/* struct to store some shared keys so we don't have to regenerate them for each request. */
@ -155,8 +172,15 @@ typedef struct {
/*----------------------------------------------------------------------------------*/
typedef int (*cryptopacket_handler_callback)(void *object, IP_Port ip_port, uint8_t *source_pubkey, uint8_t *data,
uint32_t len);
typedef struct {
cryptopacket_handler_callback function;
void *object;
} Cryptopacket_Handles;
typedef struct {
Net_Crypto *c;
Networking_Core *net;
Client_data close_clientlist[LCLIENT_LIST];
@ -164,7 +188,7 @@ typedef struct {
uint32_t close_bootstrap_times;
/* Note: this key should not be/is not used to transmit any sensitive materials */
uint8_t secret_symmetric_key[crypto_secretbox_KEYBYTES];
uint8_t secret_symmetric_key[crypto_box_KEYBYTES];
/* DHT keypair */
uint8_t self_public_key[crypto_box_PUBLICKEYBYTES];
uint8_t self_secret_key[crypto_box_SECRETKEYBYTES];
@ -180,6 +204,8 @@ typedef struct {
struct Assoc *assoc;
#endif
uint64_t last_run;
Cryptopacket_Handles cryptopackethandlers[256];
} DHT;
/*----------------------------------------------------------------------------------*/
@ -191,12 +217,12 @@ typedef struct {
*/
void get_shared_key(Shared_Keys *shared_keys, uint8_t *shared_key, uint8_t *secret_key, uint8_t *client_id);
/* Copy shared_key to decrypt DHT packet from client_id into shared_key
* for packets that we recieve.
/* Copy shared_key to encrypt/decrypt DHT packet from client_id into shared_key
* for packets that we receive.
*/
void DHT_get_shared_key_recv(DHT *dht, uint8_t *shared_key, uint8_t *client_id);
/* Copy shared_key to decrypt DHT packet from client_id into shared_key
/* Copy shared_key to encrypt/decrypt DHT packet from client_id into shared_key
* for packets that we send.
*/
void DHT_get_shared_key_sent(DHT *dht, uint8_t *shared_key, uint8_t *client_id);
@ -251,7 +277,7 @@ int id_closest(uint8_t *id, uint8_t *id1, uint8_t *id2);
/* Get the (maximum MAX_SENT_NODES) closest nodes to client_id we know
* and put them in nodes_list (must be MAX_SENT_NODES big).
*
* sa_family = family (IPv4 or IPv6)?
* sa_family = family (IPv4 or IPv6) (0 if we don't care)?
* is_LAN = return some LAN ips (true or false)
* want_good = do we want tested nodes or not? (TODO)
*
@ -315,6 +341,10 @@ int route_packet(DHT *dht, uint8_t *client_id, uint8_t *packet, uint32_t length)
*/
int route_tofriend(DHT *dht, uint8_t *friend_id, uint8_t *packet, uint32_t length);
/* Function to handle crypto packets.
*/
void cryptopacket_registerhandler(DHT *dht, uint8_t byte, cryptopacket_handler_callback cb, void *object);
/* NAT PUNCHING FUNCTIONS */
/* Puts all the different ips returned by the nodes for a friend_id into array ip_portlist.
@ -341,7 +371,7 @@ void DHT_save(DHT *dht, uint8_t *data);
int DHT_load(DHT *dht, uint8_t *data, uint32_t length);
/* Initialize DHT. */
DHT *new_DHT(Net_Crypto *c);
DHT *new_DHT(Networking_Core *net);
void kill_DHT(DHT *dht);

View File

@ -78,8 +78,10 @@ static void fetch_broadcast_info(uint16_t port)
struct sockaddr_in *sock4 = (struct sockaddr_in *)&i_faces[i].ifr_broadaddr;
if (broadcast_count >= MAX_INTERFACES)
if (broadcast_count >= MAX_INTERFACES) {
close(sock);
return;
}
IP_Port *ip_port = &broadcast_ip_port[broadcast_count];
ip_port->ip.family = AF_INET;

File diff suppressed because it is too large Load Diff

View File

@ -1,261 +0,0 @@
/* Lossless_UDP.h
*
* An implementation of the Lossless_UDP protocol as seen in http://wiki.tox.im/index.php/Lossless_UDP
*
* Copyright (C) 2013 Tox project All Rights Reserved.
*
* This file is part of Tox.
*
* Tox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef LOSSLESS_UDP_H
#define LOSSLESS_UDP_H
#include "network.h"
#include "misc_tools.h"
/* Maximum length of the data in the data packets. */
#define MAX_DATA_SIZE 1024
/* Maximum data packets in sent and receive queues. */
#define MAX_QUEUE_NUM 1024
#define DEFAULT_QUEUE_NUM 4
/* Maximum number of data packets in the buffer. */
#define MAX_REQUESTED_PACKETS 256
/* Timeout per connection is randomly set between CONNECTION_TIMEOUT and 2*CONNECTION_TIMEOUT. */
#define CONNECTION_TIMEOUT 5
/* Initial amount of sync/handshake packets to send per second. */
#define SYNC_RATE 2
/* Initial send rate of data. */
#define DATA_SYNC_RATE 30
typedef struct {
uint8_t data[MAX_DATA_SIZE];
uint16_t size;
} Data;
#define LUDP_NO_CONNECTION 0
#define LUDP_HANDSHAKE_SENDING 1
#define LUDP_NOT_CONFIRMED 2
#define LUDP_ESTABLISHED 3
#define LUDP_TIMED_OUT 4
typedef struct {
IP_Port ip_port;
/*
* return LUDP_NO_CONNECTION if connection is dead.
* return LUDP_HANDSHAKE_SENDING if attempting handshake.
* return LUDP_NOT_CONFIRMED if handshake is done (we start sending SYNC packets).
* return LUDP_ESTABLISHED if we are sending SYNC packets and can send data.
* return LUDP_TIMED_OUT if the connection has timed out.
*/
uint8_t status;
/*
* return 0 if connection was not initiated by someone else.
* return 1 if incoming_connection() has returned.
* return 2 if it has not.
*/
uint8_t inbound;
uint16_t SYNC_rate; /* Current SYNC packet send rate packets per second. */
uint32_t data_rate; /* Current data packet send rate packets per second. */
uint64_t last_SYNC; /* Time our last SYNC packet was sent. */
uint64_t last_sent; /* Time our last data or handshake packet was sent. */
uint64_t last_recvSYNC; /* Time we last received a SYNC packet from the other. */
uint64_t last_recvdata; /* Time we last received a DATA packet from the other. */
uint64_t killat; /* Time to kill the connection. */
Data *sendbuffer; /* packet send buffer. */
uint32_t sendbuffer_length;
Data *recvbuffer; /* packet receive buffer. */
uint32_t recvbuffer_length;
uint32_t handshake_id1;
uint32_t handshake_id2;
/* Number of data packets received (also used as handshake_id1). */
uint32_t recv_packetnum;
/* Number of packets received by the other peer. */
uint32_t orecv_packetnum;
/* Number of data packets sent. */
uint32_t sent_packetnum;
/* Number of packets sent by the other peer. */
uint32_t osent_packetnum;
/* Number of latest packet written onto the sendbuffer. */
uint32_t sendbuff_packetnum;
/* We know all packets before that number were successfully sent. */
uint32_t successful_sent;
/* Packet number of last packet read with the read_packet function. */
uint32_t successful_read;
/* List of currently requested packet numbers(by the other person). */
uint32_t req_packets[MAX_REQUESTED_PACKETS];
/* Total number of currently requested packets(by the other person). */
uint16_t num_req_paquets;
uint8_t recv_counter;
uint8_t send_counter;
uint8_t timeout; /* connection timeout in seconds. */
/* Is the connection confirmed or not? 1 if yes, 0 if no */
uint8_t confirmed;
} Connection;
typedef struct {
Networking_Core *net;
tox_array connections;
/* Table of random numbers used in handshake_id. */
/* IPv6 (16) + port (2)*/
uint32_t randtable[18][256];
} Lossless_UDP;
/*
* Initialize a new connection to ip_port.
*
* return an integer corresponding to the connection id.
* return -1 if it could not initialize the connection.
* return number if there already was an existing connection to that ip_port.
*/
int new_connection(Lossless_UDP *ludp, IP_Port ip_port);
/*
* Get connection id from IP_Port.
*
* return -1 if there are no connections like we are looking for.
* return id if it found it .
*/
int getconnection_id(Lossless_UDP *ludp, IP_Port ip_port);
/*
* return an integer corresponding to the next connection in our incoming connection list with at least numpackets in the recieve queue.
* return -1 if there are no new incoming connections in the list.
*/
int incoming_connection(Lossless_UDP *ludp, uint32_t numpackets);
/* return -1 if it could not kill the connection.
* return 0 if killed successfully.
*/
int kill_connection(Lossless_UDP *ludp, int connection_id);
/*
* timeout connection in seconds seconds.
*
* return -1 if it can not kill the connection.
* return 0 if it will kill it.
*/
int timeout_connection_in(Lossless_UDP *ludp, int connection_id, uint32_t seconds);
/* Check if connection is confirmed.
*
* returns 1 if yes.
* returns 0 if no.
*/
int connection_confirmed(Lossless_UDP *ludp, int connection_id);
/* Confirm an incoming connection.
* Also disables the auto kill timeout on incomming connections.
*
* return 0 on success
* return -1 on failure.
*/
int confirm_connection(Lossless_UDP *ludp, int connection_id);
/* returns the ip_port of the corresponding connection.
* return 0 if there is no such connection.
*/
IP_Port connection_ip(Lossless_UDP *ludp, int connection_id);
/* returns the id of the next packet in the queue.
* return -1 if no packet in queue.
*/
uint8_t id_packet(Lossless_UDP *ludp, int connection_id);
/* return 0 if there is no received data in the buffer.
* return length of received packet if successful.
*/
int read_packet(Lossless_UDP *ludp, int connection_id, uint8_t *data);
/* Like read_packet() but does leaves the queue as is.
* return 0 if there is no received data in the buffer.
* return length of received packet if successful.
*/
int read_packet_silent(Lossless_UDP *ludp, int connection_id, uint8_t *data);
/* Discard the next packet to be read from the queue
* return 0 if success.
* return -1 if failure.
*/
int discard_packet(Lossless_UDP *ludp, int connection_id);
/* returns the number of packet slots left in the sendbuffer.
* return 0 if failure.
*/
uint32_t num_free_sendqueue_slots(Lossless_UDP *ludp, int connection_id);
/* return 0 if data could not be put in packet queue.
* return 1 if data was put into the queue.
*/
int write_packet(Lossless_UDP *ludp, int connection_id, uint8_t *data, uint32_t length);
/* return number of packets in the queue waiting to be successfully sent. */
uint32_t sendqueue(Lossless_UDP *ludp, int connection_id);
/* return number of packets in all queues waiting to be successfully sent. */
uint32_t sendqueue_total(Lossless_UDP *ludp);
/*
* return number of packets in the queue waiting to be successfully
* read with read_packet(...).
*/
uint32_t recvqueue(Lossless_UDP *ludp, int connection_id);
/* Check if connection is connected:
*
* return LUDP_NO_CONNECTION if not.
* return LUDP_HANDSHAKE_SENDING if attempting handshake.
* return LUDP_NOT_CONFIRMED if handshake is done.
* return LUDP_ESTABLISHED if fully connected.
* return LUDP_TIMED_OUT if timed out and wating to be killed.
*/
int is_connected(Lossless_UDP *ludp, int connection_id);
/* Call this function a couple times per second. It is the main loop. */
void do_lossless_udp(Lossless_UDP *ludp);
/* This function sets up LosslessUDP packet handling. */
Lossless_UDP *new_lossless_udp(Networking_Core *net);
void kill_lossless_udp(Lossless_UDP *ludp);
#endif

View File

@ -9,8 +9,10 @@ libtoxcore_la_SOURCES = ../toxcore/DHT.h \
../toxcore/DHT.c \
../toxcore/network.h \
../toxcore/network.c \
../toxcore/Lossless_UDP.h \
../toxcore/Lossless_UDP.c \
../toxcore/crypto_core.h \
../toxcore/crypto_core.c \
../toxcore/ping_array.h \
../toxcore/ping_array.c \
../toxcore/net_crypto.h \
../toxcore/net_crypto.c \
../toxcore/friend_requests.h \
@ -52,6 +54,7 @@ libtoxcore_la_LDFLAGS = $(TOXCORE_LT_LDFLAGS) \
$(EXTRA_LT_LDFLAGS) \
$(LIBSODIUM_LDFLAGS) \
$(NACL_LDFLAGS) \
$(RT_LIBS) \
$(WINSOCK2_LIBS)
libtoxcore_la_LIBADD = $(LIBSODIUM_LIBS) \

File diff suppressed because it is too large Load Diff

View File

@ -34,18 +34,20 @@
#include "onion_client.h"
#define MAX_NAME_LENGTH 128
/* TODO: this must depend on other variable. */
#define MAX_STATUSMESSAGE_LENGTH 1007
#define FRIEND_ADDRESS_SIZE (crypto_box_PUBLICKEYBYTES + sizeof(uint32_t) + sizeof(uint16_t))
#define PACKET_ID_PING 0
/* NOTE: Packet ids below 16 must never be used. */
#define PACKET_ID_ALIVE 16
#define PACKET_ID_NICKNAME 48
#define PACKET_ID_STATUSMESSAGE 49
#define PACKET_ID_USERSTATUS 50
#define PACKET_ID_TYPING 51
#define PACKET_ID_RECEIPT 65
#define PACKET_ID_RECEIPT 63
#define PACKET_ID_MESSAGE 64
#define PACKET_ID_ACTION 63
#define PACKET_ID_ACTION 65
#define PACKET_ID_MSI 69
#define PACKET_ID_FILE_SENDREQUEST 80
#define PACKET_ID_FILE_CONTROL 81
@ -80,17 +82,13 @@ enum {
FAERR_NOMEM = -8
};
/* Don't assume MAX_STATUSMESSAGE_LENGTH will stay at 128, it may be increased
* to an absurdly large number later.
*/
/* Default start timeout in seconds between friend requests. */
#define FRIENDREQUEST_TIMEOUT 5;
/* Interval between the sending of ping packets. */
#define FRIEND_PING_INTERVAL 5
/* If no packets are recieved from friend in this time interval, kill the connection. */
/* If no packets are received from friend in this time interval, kill the connection. */
#define FRIEND_CONNECTION_TIMEOUT (FRIEND_PING_INTERVAL * 2)
/* USERSTATUS -
@ -137,7 +135,7 @@ typedef struct {
uint64_t friendrequest_lastsent; // Time at which the last friend request was sent.
uint32_t friendrequest_timeout; // The timeout between successful friendrequest sending attempts.
uint8_t status; // 0 if no friend, 1 if added, 2 if friend request sent, 3 if confirmed friend, 4 if online.
uint8_t info[MAX_DATA_SIZE]; // the data that is sent during the friend requests we do.
uint8_t info[MAX_FRIEND_REQUEST_DATA_SIZE]; // the data that is sent during the friend requests we do.
uint8_t name[MAX_NAME_LENGTH];
uint16_t name_length;
uint8_t name_sent; // 0 if we didn't send our name to this friend 1 if we have.
@ -354,7 +352,7 @@ int setname(Messenger *m, uint8_t *name, uint16_t length);
/*
* Get your nickname.
* m - The messanger context to use.
* m - The messenger context to use.
* name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes.
*
* return length of the name.
@ -376,11 +374,6 @@ int getname(Messenger *m, int32_t friendnumber, uint8_t *name);
int m_get_name_size(Messenger *m, int32_t friendnumber);
int m_get_self_name_size(Messenger *m);
/* returns valid ip port of connected friend on success
* returns zeroed out IP_Port on failure
*/
IP_Port get_friend_ipport(Messenger *m, int32_t friendnumber);
/* Set our user status.
* You are responsible for freeing status after.
*
@ -739,24 +732,6 @@ void messenger_save(Messenger *m, uint8_t *data);
/* Load the messenger from data of size length. */
int messenger_load(Messenger *m, uint8_t *data, uint32_t length);
/* return the size of data to pass to messenger_save_encrypted(...)
*/
uint32_t messenger_size_encrypted(Messenger *m);
/* Save the messenger, encrypting the data with key of length key_length
*
* return 0 on success.
* return -1 on failure.
*/
int messenger_save_encrypted(Messenger *m, uint8_t *data, uint8_t *key, uint16_t key_length);
/* Load the messenger from data of size length encrypted with key of key_length.
*
* return 0 on success.
* return -1 on failure.
*/
int messenger_load_encrypted(Messenger *m, uint8_t *data, uint32_t length, uint8_t *key, uint16_t key_length);
/* Return the number of friends in the instance m.
* You should use this to determine how much memory to allocate
* for copy_friendlist. */

View File

@ -20,6 +20,9 @@
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "TCP_client.h"
@ -71,8 +74,8 @@ static int generate_handshake(TCP_Client_Connection *TCP_conn, uint8_t *self_pub
memcpy(plain + crypto_box_PUBLICKEYBYTES, TCP_conn->sent_nonce, crypto_box_NONCEBYTES);
memcpy(TCP_conn->last_packet, self_public_key, crypto_box_PUBLICKEYBYTES);
new_nonce(TCP_conn->last_packet + crypto_box_PUBLICKEYBYTES);
int len = encrypt_data_fast(TCP_conn->shared_key, TCP_conn->last_packet + crypto_box_PUBLICKEYBYTES, plain,
sizeof(plain), TCP_conn->last_packet + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);
int len = encrypt_data_symmetric(TCP_conn->shared_key, TCP_conn->last_packet + crypto_box_PUBLICKEYBYTES, plain,
sizeof(plain), TCP_conn->last_packet + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);
if (len != sizeof(plain) + crypto_box_MACBYTES)
return -1;
@ -90,8 +93,8 @@ static int generate_handshake(TCP_Client_Connection *TCP_conn, uint8_t *self_pub
static int handle_handshake(TCP_Client_Connection *TCP_conn, uint8_t *data)
{
uint8_t plain[crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES];
int len = decrypt_data_fast(TCP_conn->shared_key, data, data + crypto_box_NONCEBYTES,
TCP_SERVER_HANDSHAKE_SIZE - crypto_box_NONCEBYTES, plain);
int len = decrypt_data_symmetric(TCP_conn->shared_key, data, data + crypto_box_NONCEBYTES,
TCP_SERVER_HANDSHAKE_SIZE - crypto_box_NONCEBYTES, plain);
if (len != sizeof(plain))
return -1;
@ -130,6 +133,206 @@ static int send_pending_data(TCP_Client_Connection *con)
return -1;
}
/* return 1 on success.
* return 0 if could not send packet.
* return -1 on failure (connection must be killed).
*/
static int write_packet_TCP_secure_connection(TCP_Client_Connection *con, uint8_t *data, uint16_t length)
{
if (length + crypto_box_MACBYTES > MAX_PACKET_SIZE)
return -1;
if (send_pending_data(con) == -1)
return 0;
uint8_t packet[sizeof(uint16_t) + length + crypto_box_MACBYTES];
uint16_t c_length = htons(length + crypto_box_MACBYTES);
memcpy(packet, &c_length, sizeof(uint16_t));
int len = encrypt_data_symmetric(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t));
if ((unsigned int)len != (sizeof(packet) - sizeof(uint16_t)))
return -1;
increment_nonce(con->sent_nonce);
len = send(con->sock, packet, sizeof(packet), MSG_NOSIGNAL);
if ((unsigned int)len == sizeof(packet))
return 1;
if (len <= 0)
return 0;
memcpy(con->last_packet, packet, length);
con->last_packet_length = sizeof(packet);
con->last_packet_sent = len;
return 1;
}
/* return 1 on success.
* return 0 if could not send packet.
* return -1 on failure (connection must be killed).
*/
int send_routing_request(TCP_Client_Connection *con, uint8_t *public_key)
{
uint8_t packet[1 + crypto_box_PUBLICKEYBYTES];
packet[0] = TCP_PACKET_ROUTING_REQUEST;
memcpy(packet + 1, public_key, crypto_box_PUBLICKEYBYTES);
return write_packet_TCP_secure_connection(con, packet, sizeof(packet));
}
void routing_response_handler(TCP_Client_Connection *con, int (*response_callback)(void *object, uint8_t connection_id,
uint8_t *public_key), void *object)
{
con->response_callback = response_callback;
con->response_callback_object = object;
}
void routing_status_handler(TCP_Client_Connection *con, int (*status_callback)(void *object, uint32_t number,
uint8_t connection_id, uint8_t status), void *object)
{
con->status_callback = status_callback;
con->status_callback_object = object;
}
/* return 1 on success.
* return 0 if could not send packet.
* return -1 on failure.
*/
int send_data(TCP_Client_Connection *con, uint8_t con_id, uint8_t *data, uint16_t length)
{
if (con_id >= NUM_CLIENT_CONNECTIONS)
return -1;
if (con->connections[con_id].status != 2)
return -1;
uint8_t packet[1 + length];
packet[0] = con_id + NUM_RESERVED_PORTS;
memcpy(packet + 1, data, length);
return write_packet_TCP_secure_connection(con, packet, sizeof(packet));
}
/* return 1 on success.
* return 0 if could not send packet.
* return -1 on failure.
*/
int send_oob_packet(TCP_Client_Connection *con, uint8_t *public_key, uint8_t *data, uint16_t length)
{
if (length == 0 || length > TCP_MAX_OOB_DATA_LENGTH)
return -1;
uint8_t packet[1 + crypto_box_PUBLICKEYBYTES + length];
packet[0] = TCP_PACKET_OOB_SEND;
memcpy(packet + 1, public_key, crypto_box_PUBLICKEYBYTES);
memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES, data, length);
return write_packet_TCP_secure_connection(con, packet, sizeof(packet));
}
/* Set the number that will be used as an argument in the callbacks related to con_id.
*
* When not set by this function, the number is ~0.
*
* return 0 on success.
* return -1 on failure.
*/
int set_tcp_connection_number(TCP_Client_Connection *con, uint8_t con_id, uint32_t number)
{
if (con_id >= NUM_CLIENT_CONNECTIONS)
return -1;
if (con->connections[con_id].status == 0)
return -1;
con->connections[con_id].number = number;
return 0;
}
void routing_data_handler(TCP_Client_Connection *con, int (*data_callback)(void *object, uint32_t number,
uint8_t connection_id, uint8_t *data, uint16_t length), void *object)
{
con->data_callback = data_callback;
con->data_callback_object = object;
}
void oob_data_handler(TCP_Client_Connection *con, int (*oob_data_callback)(void *object, uint8_t *public_key,
uint8_t *data, uint16_t length), void *object)
{
con->oob_data_callback = oob_data_callback;
con->oob_data_callback_object = object;
}
/* return 1 on success.
* return 0 if could not send packet.
* return -1 on failure (connection must be killed).
*/
static int send_disconnect_notification(TCP_Client_Connection *con, uint8_t id)
{
uint8_t packet[1 + 1];
packet[0] = TCP_PACKET_DISCONNECT_NOTIFICATION;
packet[1] = id;
return write_packet_TCP_secure_connection(con, packet, sizeof(packet));
}
/* return 1 on success.
* return 0 if could not send packet.
* return -1 on failure (connection must be killed).
*/
static int send_ping_request(TCP_Client_Connection *con, uint64_t ping_id)
{
uint8_t packet[1 + sizeof(uint64_t)];
packet[0] = TCP_PACKET_PING;
memcpy(packet + 1, &ping_id, sizeof(uint64_t));
return write_packet_TCP_secure_connection(con, packet, sizeof(packet));
}
/* return 1 on success.
* return 0 if could not send packet.
* return -1 on failure (connection must be killed).
*/
static int send_ping_response(TCP_Client_Connection *con, uint64_t ping_id)
{
uint8_t packet[1 + sizeof(uint64_t)];
packet[0] = TCP_PACKET_PONG;
memcpy(packet + 1, &ping_id, sizeof(uint64_t));
return write_packet_TCP_secure_connection(con, packet, sizeof(packet));
}
/* return 1 on success.
* return 0 if could not send packet.
* return -1 on failure (connection must be killed).
*/
int send_disconnect_request(TCP_Client_Connection *con, uint8_t con_id)
{
if (con_id >= NUM_CLIENT_CONNECTIONS)
return -1;
con->connections[con_id].status = 0;
con->connections[con_id].number = 0;
return send_disconnect_notification(con, con_id + NUM_RESERVED_PORTS);
}
/* return 1 on success.
* return 0 if could not send packet.
* return -1 on failure (connection must be killed).
*/
int send_onion_request(TCP_Client_Connection *con, uint8_t *data, uint16_t length)
{
uint8_t packet[1 + length];
packet[0] = TCP_PACKET_ONION_REQUEST;
memcpy(packet + 1, data, length);
return write_packet_TCP_secure_connection(con, packet, sizeof(packet));
}
void onion_response_handler(TCP_Client_Connection *con, int (*onion_callback)(void *object, uint8_t *data,
uint16_t length), void *object)
{
con->onion_callback = onion_callback;
con->onion_callback_object = object;
}
/* Create new TCP connection to ip_port/public_key
*/
TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, uint8_t *public_key, uint8_t *self_public_key,
@ -149,6 +352,11 @@ TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, uint8_t *public_key,
return NULL;
}
if (!set_socket_nosigpipe(sock)) {
kill_sock(sock);
return 0;
}
if (!(set_socket_nonblock(sock) && connect_sock_to(sock, ip_port))) {
kill_sock(sock);
return NULL;
@ -164,6 +372,7 @@ TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, uint8_t *public_key,
temp->status = TCP_CLIENT_CONNECTING;
temp->sock = sock;
memcpy(temp->public_key, public_key, crypto_box_PUBLICKEYBYTES);
temp->ip_port = ip_port;
if (generate_handshake(temp, self_public_key, self_secret_key) == -1) {
kill_sock(sock);
@ -176,8 +385,181 @@ TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, uint8_t *public_key,
return temp;
}
static int do_confirmed_TCP(TCP_Client_Connection *TCP_connection)
/* return 0 on success
* return -1 on failure
*/
static int handle_TCP_packet(TCP_Client_Connection *conn, uint8_t *data, uint16_t length)
{
if (length <= 1)
return -1;
switch (data[0]) {
case TCP_PACKET_ROUTING_RESPONSE: {
if (length != 1 + 1 + crypto_box_PUBLICKEYBYTES)
return -1;
if (data[1] < NUM_RESERVED_PORTS)
return 0;
uint8_t con_id = data[1] - NUM_RESERVED_PORTS;
if (conn->connections[con_id].status != 0)
return 0;
conn->connections[con_id].status = 1;
conn->connections[con_id].number = ~0;
memcpy(conn->connections[con_id].public_key, data + 2, crypto_box_PUBLICKEYBYTES);
if (conn->response_callback)
conn->response_callback(conn->response_callback_object, con_id, conn->connections[con_id].public_key);
return 0;
}
case TCP_PACKET_CONNECTION_NOTIFICATION: {
if (length != 1 + 1)
return -1;
if (data[1] < NUM_RESERVED_PORTS)
return -1;
uint8_t con_id = data[1] - NUM_RESERVED_PORTS;
if (conn->connections[con_id].status != 1)
return -1;
conn->connections[con_id].status = 2;
if (conn->status_callback)
conn->status_callback(conn->status_callback_object, conn->connections[con_id].number, con_id,
conn->connections[con_id].status);
return 0;
}
case TCP_PACKET_DISCONNECT_NOTIFICATION: {
if (length != 1 + 1)
return -1;
if (data[1] < NUM_RESERVED_PORTS)
return -1;
uint8_t con_id = data[1] - NUM_RESERVED_PORTS;
if (conn->connections[con_id].status == 0)
return 0;
if (conn->connections[con_id].status != 2)
return -1;
conn->connections[con_id].status = 1;
if (conn->status_callback)
conn->status_callback(conn->status_callback_object, conn->connections[con_id].number, con_id,
conn->connections[con_id].status);
return 0;
}
case TCP_PACKET_PING: {
if (length != 1 + sizeof(uint64_t))
return -1;
uint64_t ping_id;
memcpy(&ping_id, data + 1, sizeof(uint64_t));
send_ping_response(conn, ping_id);
return 0;
}
case TCP_PACKET_PONG: {
if (length != 1 + sizeof(uint64_t))
return -1;
uint64_t ping_id;
memcpy(&ping_id, data + 1, sizeof(uint64_t));
if (ping_id) {
if (ping_id == conn->ping_id) {
conn->ping_id = 0;
}
return 0;
} else {
return -1;
}
}
case TCP_PACKET_OOB_RECV: {
if (length <= 1 + crypto_box_PUBLICKEYBYTES)
return -1;
if (conn->oob_data_callback)
conn->oob_data_callback(conn->oob_data_callback_object, data + 1, data + 1 + crypto_box_PUBLICKEYBYTES,
length - (1 + crypto_box_PUBLICKEYBYTES));
return 0;
}
case TCP_PACKET_ONION_RESPONSE: {
conn->onion_callback(conn->onion_callback_object, data + 1, length - 1);
return 0;
}
default: {
if (data[0] < NUM_RESERVED_PORTS)
return -1;
uint8_t con_id = data[0] - NUM_RESERVED_PORTS;
if (conn->data_callback)
conn->data_callback(conn->data_callback_object, conn->connections[con_id].number, con_id, data + 1, length - 1);
}
}
return 0;
}
static int do_confirmed_TCP(TCP_Client_Connection *conn)
{
send_pending_data(conn);
uint8_t packet[MAX_PACKET_SIZE];
int len;
if (is_timeout(conn->last_pinged, TCP_PING_FREQUENCY)) {
uint64_t ping_id = random_64b();
if (!ping_id)
++ping_id;
int ret = send_ping_request(conn, ping_id);
if (ret == 1) {
conn->last_pinged = unix_time();
conn->ping_id = ping_id;
} else {
if (is_timeout(conn->last_pinged, TCP_PING_FREQUENCY + TCP_PING_TIMEOUT)) {
conn->status = TCP_CLIENT_DISCONNECTED;
}
}
}
if (conn->ping_id && is_timeout(conn->last_pinged, TCP_PING_TIMEOUT)) {
conn->status = TCP_CLIENT_DISCONNECTED;
return 0;
}
while ((len = read_packet_TCP_secure_connection(conn->sock, &conn->next_packet_length, conn->shared_key,
conn->recv_nonce, packet, sizeof(packet)))) {
if (len == -1) {
conn->status = TCP_CLIENT_DISCONNECTED;
break;
}
if (handle_TCP_packet(conn, packet, len) == -1) {
conn->status = TCP_CLIENT_DISCONNECTED;
break;
}
}
return 0;
}
@ -204,6 +586,7 @@ void do_TCP_connection(TCP_Client_Connection *TCP_connection)
if (sizeof(data) == len) {
if (handle_handshake(TCP_connection, data) == 0) {
TCP_connection->kill_at = ~0;
TCP_connection->status = TCP_CLIENT_CONFIRMED;
} else {
TCP_connection->kill_at = 0;
@ -225,7 +608,10 @@ void do_TCP_connection(TCP_Client_Connection *TCP_connection)
*/
void kill_TCP_connection(TCP_Client_Connection *TCP_connection)
{
if (TCP_connection == NULL)
return;
kill_sock(TCP_connection->sock);
memset(TCP_connection, 0, sizeof(TCP_Client_Connection));
free(TCP_connection);
}
}

View File

@ -24,7 +24,7 @@
#ifndef TCP_CLIENT_H
#define TCP_CLIENT_H
#include "net_crypto.h"
#include "crypto_core.h"
#include "TCP_server.h"
#define TCP_CONNECTION_TIMEOUT 10
@ -40,6 +40,7 @@ typedef struct {
uint8_t status;
sock_t sock;
uint8_t public_key[crypto_box_PUBLICKEYBYTES]; /* public key of the server */
IP_Port ip_port; /* The ip and port of the server */
uint8_t recv_nonce[crypto_box_NONCEBYTES]; /* Nonce of received packets. */
uint8_t sent_nonce[crypto_box_NONCEBYTES]; /* Nonce of sent packets. */
uint8_t shared_key[crypto_box_BEFORENMBYTES];
@ -55,6 +56,25 @@ typedef struct {
uint64_t last_pinged;
uint64_t ping_id;
void *net_crypto_pointer;
uint32_t net_crypto_location;
struct {
uint8_t status; /* 0 if not used, 1 if other is offline, 2 if other is online. */
uint8_t public_key[crypto_box_PUBLICKEYBYTES];
uint32_t number;
} connections[NUM_CLIENT_CONNECTIONS];
int (*response_callback)(void *object, uint8_t connection_id, uint8_t *public_key);
void *response_callback_object;
int (*status_callback)(void *object, uint32_t number, uint8_t connection_id, uint8_t status);
void *status_callback_object;
int (*data_callback)(void *object, uint32_t number, uint8_t connection_id, uint8_t *data, uint16_t length);
void *data_callback_object;
int (*oob_data_callback)(void *object, uint8_t *public_key, uint8_t *data, uint16_t length);
void *oob_data_callback_object;
int (*onion_callback)(void *object, uint8_t *data, uint16_t length);
void *onion_callback_object;
} TCP_Client_Connection;
/* Create new TCP connection to ip_port/public_key
@ -70,9 +90,54 @@ void do_TCP_connection(TCP_Client_Connection *TCP_connection);
*/
void kill_TCP_connection(TCP_Client_Connection *TCP_connection);
int get_TCP_connection_status(TCP_Client_Connection *TCP_connection);
/* return 1 on success.
* return 0 if could not send packet.
* return -1 on failure (connection must be killed).
*/
int send_onion_request(TCP_Client_Connection *con, uint8_t *data, uint16_t length);
void onion_response_handler(TCP_Client_Connection *con, int (*onion_callback)(void *object, uint8_t *data,
uint16_t length), void *object);
int read_TCP_connection(TCP_Client_Connection *TCP_connection, uint8_t *data);
/* return 1 on success.
* return 0 if could not send packet.
* return -1 on failure (connection must be killed).
*/
int send_routing_request(TCP_Client_Connection *con, uint8_t *public_key);
void routing_response_handler(TCP_Client_Connection *con, int (*response_callback)(void *object, uint8_t connection_id,
uint8_t *public_key), void *object);
void routing_status_handler(TCP_Client_Connection *con, int (*status_callback)(void *object, uint32_t number,
uint8_t connection_id, uint8_t status), void *object);
/* return 1 on success.
* return 0 if could not send packet.
* return -1 on failure (connection must be killed).
*/
int send_disconnect_request(TCP_Client_Connection *con, uint8_t con_id);
/* Set the number that will be used as an argument in the callbacks related to con_id.
*
* When not set by this function, the number is ~0.
*
* return 0 on success.
* return -1 on failure.
*/
int set_tcp_connection_number(TCP_Client_Connection *con, uint8_t con_id, uint32_t number);
/* return 1 on success.
* return 0 if could not send packet.
* return -1 on failure.
*/
int send_data(TCP_Client_Connection *con, uint8_t con_id, uint8_t *data, uint16_t length);
void routing_data_handler(TCP_Client_Connection *con, int (*data_callback)(void *object, uint32_t number,
uint8_t connection_id, uint8_t *data, uint16_t length), void *object);
/* return 1 on success.
* return 0 if could not send packet.
* return -1 on failure.
*/
int send_oob_packet(TCP_Client_Connection *con, uint8_t *public_key, uint8_t *data, uint16_t length);
void oob_data_handler(TCP_Client_Connection *con, int (*oob_data_callback)(void *object, uint8_t *public_key,
uint8_t *data, uint16_t length), void *object);
#endif

View File

@ -20,6 +20,10 @@
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "TCP_server.h"
#if !defined(_WIN32) && !defined(__WIN32__) && !defined (WIN32)
@ -69,17 +73,46 @@ static int realloc_connection(TCP_Server *TCP_server, uint32_t num)
return 0;
}
if (num == TCP_server->size_accepted_connections) {
return 0;
}
TCP_Secure_Connection *new_connections = realloc(TCP_server->accepted_connection_array,
num * sizeof(TCP_Secure_Connection));
if (new_connections == NULL)
return -1;
if (num > TCP_server->size_accepted_connections) {
uint32_t old_size = TCP_server->size_accepted_connections;
uint32_t size_new_entries = (num - old_size) * sizeof(TCP_Secure_Connection);
memset(new_connections + old_size, 0, size_new_entries);
}
TCP_server->accepted_connection_array = new_connections;
TCP_server->size_accepted_connections = num;
return 0;
}
/* return index corresponding to connection with peer on success
* return -1 on failure.
*/
static int get_TCP_connection_index(TCP_Server *TCP_server, uint8_t *public_key)
{
//TODO optimize this function.
uint32_t i;
for (i = 0; i < TCP_server->size_accepted_connections; ++i) {
if (memcmp(TCP_server->accepted_connection_array[i].public_key, public_key, crypto_box_PUBLICKEYBYTES) == 0)
return i;
}
return -1;
}
static int kill_accepted(TCP_Server *TCP_server, int index);
/* Add accepted TCP connection to the list.
*
* return index on success
@ -87,7 +120,12 @@ static int realloc_connection(TCP_Server *TCP_server, uint32_t num)
*/
static int add_accepted(TCP_Server *TCP_server, TCP_Secure_Connection *con)
{
int index = -1;
int index = get_TCP_connection_index(TCP_server, con->public_key);
if (index != -1) { /* If an old connection to the same public key exists, kill it. */
kill_accepted(TCP_server, index);
index = -1;
}
if (TCP_server->size_accepted_connections == TCP_server->num_accepted_connections) {
if (realloc_connection(TCP_server, TCP_server->size_accepted_connections + 4) == -1)
@ -141,22 +179,6 @@ static int del_accepted(TCP_Server *TCP_server, int index)
return 0;
}
/* return index corresponding to connection with peer on success
* return -1 on failure.
*/
static int get_TCP_connection_index(TCP_Server *TCP_server, uint8_t *public_key)
{
//TODO optimize this function.
uint32_t i;
for (i = 0; i < TCP_server->size_accepted_connections; ++i) {
if (memcmp(TCP_server->accepted_connection_array[i].public_key, public_key, crypto_box_PUBLICKEYBYTES) == 0)
return i;
}
return -1;
}
/* Read the next two bytes in TCP stream then convert them to
* length (host byte order).
*
@ -224,14 +246,15 @@ int read_TCP_packet(sock_t sock, uint8_t *data, uint16_t length)
return -1;
}
/* return length of recieved packet on success.
/* return length of received packet on success.
* return 0 if could not read any packet.
* return -1 on failure (connection must be killed).
*/
static int read_packet_TCP_secure_connection(TCP_Secure_Connection *con, uint8_t *data, uint16_t max_len)
int read_packet_TCP_secure_connection(sock_t sock, uint16_t *next_packet_length, uint8_t *shared_key,
uint8_t *recv_nonce, uint8_t *data, uint16_t max_len)
{
if (con->next_packet_length == 0) {
uint16_t len = read_TCP_length(con->sock);
if (*next_packet_length == 0) {
uint16_t len = read_TCP_length(sock);
if (len == (uint16_t)~0)
return -1;
@ -239,26 +262,26 @@ static int read_packet_TCP_secure_connection(TCP_Secure_Connection *con, uint8_t
if (len == 0)
return 0;
con->next_packet_length = len;
*next_packet_length = len;
}
if (max_len + crypto_box_MACBYTES < con->next_packet_length)
if (max_len + crypto_box_MACBYTES < *next_packet_length)
return -1;
uint8_t data_encrypted[con->next_packet_length];
int len_packet = read_TCP_packet(con->sock, data_encrypted, con->next_packet_length);
uint8_t data_encrypted[*next_packet_length];
int len_packet = read_TCP_packet(sock, data_encrypted, *next_packet_length);
if (len_packet != con->next_packet_length)
if (len_packet != *next_packet_length)
return 0;
con->next_packet_length = 0;
*next_packet_length = 0;
int len = decrypt_data_fast(con->shared_key, con->recv_nonce, data_encrypted, len_packet, data);
int len = decrypt_data_symmetric(shared_key, recv_nonce, data_encrypted, len_packet, data);
if (len + crypto_box_MACBYTES != len_packet)
return -1;
increment_nonce(con->recv_nonce);
increment_nonce(recv_nonce);
return len;
}
@ -308,7 +331,7 @@ static int write_packet_TCP_secure_connection(TCP_Secure_Connection *con, uint8_
uint16_t c_length = htons(length + crypto_box_MACBYTES);
memcpy(packet, &c_length, sizeof(uint16_t));
int len = encrypt_data_fast(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t));
int len = encrypt_data_symmetric(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t));
if ((unsigned int)len != (sizeof(packet) - sizeof(uint16_t)))
return -1;
@ -337,6 +360,33 @@ static void kill_TCP_connection(TCP_Secure_Connection *con)
memset(con, 0, sizeof(TCP_Secure_Connection));
}
static int rm_connection_index(TCP_Server *TCP_server, TCP_Secure_Connection *con, uint8_t con_number);
/* Kill an accepted TCP_Secure_Connection
*
* return -1 on failure.
* return 0 on success.
*/
static int kill_accepted(TCP_Server *TCP_server, int index)
{
if ((uint32_t)index >= TCP_server->size_accepted_connections)
return -1;
uint32_t i;
for (i = 0; i < NUM_CLIENT_CONNECTIONS; ++i) {
rm_connection_index(TCP_server, &TCP_server->accepted_connection_array[index], i);
}
sock_t sock = TCP_server->accepted_connection_array[index].sock;
if (del_accepted(TCP_server, index) != 0)
return -1;
kill_sock(sock);
return 0;
}
/* return 1 if everything went well.
* return -1 if the connection must be killed.
*/
@ -351,8 +401,8 @@ static int handle_TCP_handshake(TCP_Secure_Connection *con, uint8_t *data, uint1
uint8_t shared_key[crypto_box_BEFORENMBYTES];
encrypt_precompute(data, self_secret_key, shared_key);
uint8_t plain[TCP_HANDSHAKE_PLAIN_SIZE];
int len = decrypt_data_fast(shared_key, data + crypto_box_PUBLICKEYBYTES,
data + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, TCP_HANDSHAKE_PLAIN_SIZE + crypto_box_MACBYTES, plain);
int len = decrypt_data_symmetric(shared_key, data + crypto_box_PUBLICKEYBYTES,
data + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, TCP_HANDSHAKE_PLAIN_SIZE + crypto_box_MACBYTES, plain);
if (len != TCP_HANDSHAKE_PLAIN_SIZE)
return -1;
@ -368,7 +418,8 @@ static int handle_TCP_handshake(TCP_Secure_Connection *con, uint8_t *data, uint1
uint8_t response[TCP_SERVER_HANDSHAKE_SIZE];
new_nonce(response);
len = encrypt_data_fast(shared_key, response, resp_plain, TCP_HANDSHAKE_PLAIN_SIZE, response + crypto_box_NONCEBYTES);
len = encrypt_data_symmetric(shared_key, response, resp_plain, TCP_HANDSHAKE_PLAIN_SIZE,
response + crypto_box_NONCEBYTES);
if (len != TCP_HANDSHAKE_PLAIN_SIZE + crypto_box_MACBYTES)
return -1;
@ -449,9 +500,16 @@ static int handle_TCP_routing_req(TCP_Server *TCP_server, uint32_t con_id, uint8
}
for (i = 0; i < NUM_CLIENT_CONNECTIONS; ++i) {
if (con->connections[i].status == 0) {
if (con->connections[i].status != 0) {
if (memcmp(public_key, con->connections[i].public_key, crypto_box_PUBLICKEYBYTES) == 0) {
if (send_routing_response(con, i + NUM_RESERVED_PORTS, public_key) == -1) {
return -1;
} else {
return 0;
}
}
} else if (index == (uint32_t)~0) {
index = i;
break;
}
}
@ -502,7 +560,37 @@ static int handle_TCP_routing_req(TCP_Server *TCP_server, uint32_t con_id, uint8
return 0;
}
static int disconnect_conection_index(TCP_Server *TCP_server, TCP_Secure_Connection *con, uint8_t con_number)
/* return 0 on success.
* return -1 on failure (connection must be killed).
*/
static int handle_TCP_oob_send(TCP_Server *TCP_server, uint32_t con_id, uint8_t *public_key, uint8_t *data,
uint16_t length)
{
if (length == 0 || length > TCP_MAX_OOB_DATA_LENGTH)
return -1;
TCP_Secure_Connection *con = &TCP_server->accepted_connection_array[con_id];
int other_index = get_TCP_connection_index(TCP_server, public_key);
if (other_index != -1) {
uint8_t resp_packet[1 + crypto_box_PUBLICKEYBYTES + length];
resp_packet[0] = TCP_PACKET_OOB_RECV;
memcpy(resp_packet + 1, con->public_key, crypto_box_PUBLICKEYBYTES);
memcpy(resp_packet + 1 + crypto_box_PUBLICKEYBYTES, data, length);
write_packet_TCP_secure_connection(&TCP_server->accepted_connection_array[other_index], resp_packet,
sizeof(resp_packet));
}
return 0;
}
/* Remove connection with con_number from the connections array of con.
*
* return -1 on failure.
* return 0 on success.
*/
static int rm_connection_index(TCP_Server *TCP_server, TCP_Secure_Connection *con, uint8_t con_number)
{
if (con_number >= NUM_CLIENT_CONNECTIONS)
return -1;
@ -526,8 +614,6 @@ static int disconnect_conection_index(TCP_Server *TCP_server, TCP_Secure_Connect
con->connections[con_number].index = 0;
con->connections[con_number].other_id = 0;
con->connections[con_number].status = 0;
//TODO: return values?
send_disconnect_notification(con, con_number);
return 0;
} else {
return -1;
@ -586,7 +672,7 @@ static int handle_TCP_packet(TCP_Server *TCP_server, uint32_t con_id, uint8_t *d
if (length != 2)
return -1;
return disconnect_conection_index(TCP_server, con, data[1] - NUM_RESERVED_PORTS);
return rm_connection_index(TCP_server, con, data[1] - NUM_RESERVED_PORTS);
}
case TCP_PACKET_PING: {
@ -618,6 +704,14 @@ static int handle_TCP_packet(TCP_Server *TCP_server, uint32_t con_id, uint8_t *d
}
}
case TCP_PACKET_OOB_SEND: {
if (length <= 1 + crypto_box_PUBLICKEYBYTES)
return -1;
return handle_TCP_oob_send(TCP_server, con_id, data + 1, data + 1 + crypto_box_PUBLICKEYBYTES,
length - (1 + crypto_box_PUBLICKEYBYTES));
}
case TCP_PACKET_ONION_REQUEST: {
if (TCP_server->onion) {
if (length <= 1 + crypto_box_NONCEBYTES + ONION_SEND_BASE * 2)
@ -642,22 +736,22 @@ static int handle_TCP_packet(TCP_Server *TCP_server, uint32_t con_id, uint8_t *d
if (data[0] < NUM_RESERVED_PORTS)
return -1;
uint8_t con_id = data[0] - NUM_RESERVED_PORTS;
uint8_t c_id = data[0] - NUM_RESERVED_PORTS;
if (con_id >= NUM_CLIENT_CONNECTIONS)
if (c_id >= NUM_CLIENT_CONNECTIONS)
return -1;
if (con->connections[con_id].status == 0)
if (con->connections[c_id].status == 0)
return -1;
if (con->connections[con_id].status != 2)
if (con->connections[c_id].status != 2)
return 0;
uint32_t index = con->connections[con_id].index;
uint8_t other_con_id = con->connections[con_id].other_id + NUM_RESERVED_PORTS;
uint32_t index = con->connections[c_id].index;
uint8_t other_c_id = con->connections[c_id].other_id + NUM_RESERVED_PORTS;
uint8_t new_data[length];
memcpy(new_data, data, length);
new_data[0] = other_con_id;
new_data[0] = other_c_id;
int ret = write_packet_TCP_secure_connection(&TCP_server->accepted_connection_array[index], new_data, length);
if (ret == -1)
@ -678,11 +772,8 @@ static int confirm_TCP_connection(TCP_Server *TCP_server, TCP_Secure_Connection
if (index == -1)
return -1;
TCP_Secure_Connection *conn = &TCP_server->accepted_connection_array[index];
if (handle_TCP_packet(TCP_server, index, data, length) == -1) {
kill_TCP_connection(conn);
del_accepted(TCP_server, index);
kill_accepted(TCP_server, index);
}
return 0;
@ -701,6 +792,11 @@ static int accept_connection(TCP_Server *TCP_server, sock_t sock)
return 0;
}
if (!set_socket_nosigpipe(sock)) {
kill_sock(sock);
return 0;
}
TCP_Secure_Connection *conn =
&TCP_server->incomming_connection_queue[TCP_server->incomming_connection_queue_index % MAX_INCOMMING_CONNECTIONS];
@ -848,7 +944,8 @@ static void do_TCP_unconfirmed(TCP_Server *TCP_server)
continue;
uint8_t packet[MAX_PACKET_SIZE];
int len = read_packet_TCP_secure_connection(conn, packet, sizeof(packet));
int len = read_packet_TCP_secure_connection(conn->sock, &conn->next_packet_length, conn->shared_key, conn->recv_nonce,
packet, sizeof(packet));
if (len == 0) {
continue;
@ -889,12 +986,16 @@ static void do_TCP_confirmed(TCP_Server *TCP_server)
if (ret == 1) {
conn->last_pinged = unix_time();
conn->ping_id = ping_id;
} else {
if (is_timeout(conn->last_pinged, TCP_PING_FREQUENCY + TCP_PING_TIMEOUT)) {
kill_accepted(TCP_server, i);
continue;
}
}
}
if (conn->ping_id && is_timeout(conn->last_pinged, TCP_PING_TIMEOUT)) {
kill_TCP_connection(conn);
del_accepted(TCP_server, i);
kill_accepted(TCP_server, i);
continue;
}
@ -902,16 +1003,15 @@ static void do_TCP_confirmed(TCP_Server *TCP_server)
uint8_t packet[MAX_PACKET_SIZE];
int len;
while ((len = read_packet_TCP_secure_connection(conn, packet, sizeof(packet)))) {
while ((len = read_packet_TCP_secure_connection(conn->sock, &conn->next_packet_length, conn->shared_key,
conn->recv_nonce, packet, sizeof(packet)))) {
if (len == -1) {
kill_TCP_connection(conn);
del_accepted(TCP_server, i);
kill_accepted(TCP_server, i);
break;
}
if (handle_TCP_packet(TCP_server, i, packet, len) == -1) {
kill_TCP_connection(conn);
del_accepted(TCP_server, i);
kill_accepted(TCP_server, i);
break;
}
}

View File

@ -23,10 +23,10 @@
#ifndef TCP_SERVER_H
#define TCP_SERVER_H
#include "net_crypto.h"
#include "crypto_core.h"
#include "onion.h"
#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MACH__)
#define MSG_NOSIGNAL 0
#endif
@ -39,6 +39,7 @@
#define TCP_HANDSHAKE_PLAIN_SIZE (crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES)
#define TCP_SERVER_HANDSHAKE_SIZE (crypto_box_NONCEBYTES + TCP_HANDSHAKE_PLAIN_SIZE + crypto_box_MACBYTES)
#define TCP_CLIENT_HANDSHAKE_SIZE (crypto_box_PUBLICKEYBYTES + TCP_SERVER_HANDSHAKE_SIZE)
#define TCP_MAX_OOB_DATA_LENGTH 1024
#define NUM_RESERVED_PORTS 16
#define NUM_CLIENT_CONNECTIONS (256 - NUM_RESERVED_PORTS)
@ -49,16 +50,16 @@
#define TCP_PACKET_DISCONNECT_NOTIFICATION 3
#define TCP_PACKET_PING 4
#define TCP_PACKET_PONG 5
#define TCP_PACKET_OOB_SEND 6
#define TCP_PACKET_OOB_RECV 7
#define TCP_PACKET_ONION_REQUEST 8
#define TCP_PACKET_ONION_RESPONSE 9
#define ARRAY_ENTRY_SIZE 6
#define TCP_ONION_FAMILY (AF_INET6 + 1)
/* frequency to ping connected nodes and timeout in seconds */
#define TCP_PING_FREQUENCY 30
#define TCP_PING_TIMEOUT 20
#define TCP_PING_TIMEOUT 10
enum {
TCP_STATUS_NO_STATUS,
@ -140,4 +141,12 @@ uint16_t read_TCP_length(sock_t sock);
*/
int read_TCP_packet(sock_t sock, uint8_t *data, uint16_t length);
/* return length of received packet on success.
* return 0 if could not read any packet.
* return -1 on failure (connection must be killed).
*/
int read_packet_TCP_secure_connection(sock_t sock, uint16_t *next_packet_length, uint8_t *shared_key,
uint8_t *recv_nonce, uint8_t *data, uint16_t max_len);
#endif

View File

@ -29,7 +29,7 @@
* Candidates are kept in buckets of hash tables. The hash
* function is calculated from the client_id. Up to
* HASH_COLLIDE_COUNT alternative positions are tried if
* the inital position is already used by a different entry.
* the initial position is already used by a different entry.
* The collision function is multiplicative, not additive.
*
* A new candidate can bump an existing candidate, if it is

262
toxcore/crypto_core.c Normal file
View File

@ -0,0 +1,262 @@
/* net_crypto.c
*
* Functions for the core crypto.
*
* NOTE: This code has to be perfect. We don't mess around with encryption.
*
* Copyright (C) 2013 Tox project All Rights Reserved.
*
* This file is part of Tox.
*
* Tox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "crypto_core.h"
/* Use this instead of memcmp; not vulnerable to timing attacks.
returns 0 if both mem locations of length are equal,
return -1 if they are not. */
int crypto_cmp(uint8_t *mem1, uint8_t *mem2, uint32_t length)
{
if (length == 16) {
return crypto_verify_16(mem1, mem2);
} else if (length == 32) {
return crypto_verify_32(mem1, mem2);
}
unsigned int i, check = 0;
for (i = 0; i < length; ++i) {
check |= mem1[i] ^ mem2[i];
}
return (1 & ((check - 1) >> 8)) - 1;
}
/* return a random number.
*/
uint32_t random_int(void)
{
uint32_t randnum;
randombytes((uint8_t *)&randnum , sizeof(randnum));
return randnum;
}
uint64_t random_64b(void)
{
uint64_t randnum;
randombytes((uint8_t *)&randnum, sizeof(randnum));
return randnum;
}
/* Precomputes the shared key from their public_key and our secret_key.
* This way we can avoid an expensive elliptic curve scalar multiply for each
* encrypt/decrypt operation.
* enc_key has to be crypto_box_BEFORENMBYTES bytes long.
*/
void encrypt_precompute(uint8_t *public_key, uint8_t *secret_key, uint8_t *enc_key)
{
crypto_box_beforenm(enc_key, public_key, secret_key);
}
int encrypt_data_symmetric(uint8_t *secret_key, uint8_t *nonce, uint8_t *plain, uint32_t length, uint8_t *encrypted)
{
if (length == 0)
return -1;
uint8_t temp_plain[length + crypto_box_ZEROBYTES];
uint8_t temp_encrypted[length + crypto_box_MACBYTES + crypto_box_BOXZEROBYTES];
memset(temp_plain, 0, crypto_box_ZEROBYTES);
memcpy(temp_plain + crypto_box_ZEROBYTES, plain, length); // Pad the message with 32 0 bytes.
if (crypto_box_afternm(temp_encrypted, temp_plain, length + crypto_box_ZEROBYTES, nonce, secret_key) != 0)
return -1;
/* Unpad the encrypted message. */
memcpy(encrypted, temp_encrypted + crypto_box_BOXZEROBYTES, length + crypto_box_MACBYTES);
return length + crypto_box_MACBYTES;
}
int decrypt_data_symmetric(uint8_t *secret_key, uint8_t *nonce, uint8_t *encrypted, uint32_t length, uint8_t *plain)
{
if (length <= crypto_box_BOXZEROBYTES)
return -1;
uint8_t temp_plain[length + crypto_box_ZEROBYTES];
uint8_t temp_encrypted[length + crypto_box_BOXZEROBYTES];
memset(temp_plain, 0, crypto_box_BOXZEROBYTES);
memcpy(temp_encrypted + crypto_box_BOXZEROBYTES, encrypted, length); // Pad the message with 16 0 bytes.
if (crypto_box_open_afternm(temp_plain, temp_encrypted, length + crypto_box_BOXZEROBYTES, nonce, secret_key) != 0)
return -1;
memcpy(plain, temp_plain + crypto_box_ZEROBYTES, length - crypto_box_MACBYTES);
return length - crypto_box_MACBYTES;
}
int encrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce,
uint8_t *plain, uint32_t length, uint8_t *encrypted)
{
uint8_t k[crypto_box_BEFORENMBYTES];
encrypt_precompute(public_key, secret_key, k);
return encrypt_data_symmetric(k, nonce, plain, length, encrypted);
}
int decrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce,
uint8_t *encrypted, uint32_t length, uint8_t *plain)
{
uint8_t k[crypto_box_BEFORENMBYTES];
encrypt_precompute(public_key, secret_key, k);
return decrypt_data_symmetric(k, nonce, encrypted, length, plain);
}
/* Increment the given nonce by 1. */
void increment_nonce(uint8_t *nonce)
{
uint32_t i;
for (i = crypto_box_NONCEBYTES; i != 0; --i) {
++nonce[i - 1];
if (nonce[i - 1] != 0)
break;
}
}
/* increment the given nonce by num */
void increment_nonce_number(uint8_t *nonce, uint32_t num)
{
uint32_t num1, num2;
memcpy(&num1, nonce + (crypto_box_NONCEBYTES - sizeof(num1)), sizeof(num1));
num1 = ntohl(num1);
num2 = num + num1;
if (num2 < num1) {
uint32_t i;
for (i = crypto_box_NONCEBYTES - sizeof(num1); i != 0; --i) {
++nonce[i - 1];
if (nonce[i - 1] != 0)
break;
}
}
num2 = htonl(num2);
memcpy(nonce + (crypto_box_NONCEBYTES - sizeof(num2)), &num2, sizeof(num2));
}
/* Fill the given nonce with random bytes. */
void random_nonce(uint8_t *nonce)
{
randombytes(nonce, crypto_box_NONCEBYTES);
}
/* Fill a key crypto_box_KEYBYTES big with random bytes */
void new_symmetric_key(uint8_t *key)
{
randombytes(key, crypto_box_KEYBYTES);
}
static uint8_t base_nonce[crypto_box_NONCEBYTES];
static uint8_t nonce_set = 0;
/* Gives a nonce guaranteed to be different from previous ones.*/
void new_nonce(uint8_t *nonce)
{
if (nonce_set == 0) {
random_nonce(base_nonce);
nonce_set = 1;
}
increment_nonce(base_nonce);
memcpy(nonce, base_nonce, crypto_box_NONCEBYTES);
}
/* Create a request to peer.
* send_public_key and send_secret_key are the pub/secret keys of the sender.
* recv_public_key is public key of reciever.
* packet must be an array of MAX_CRYPTO_REQUEST_SIZE big.
* Data represents the data we send with the request with length being the length of the data.
* request_id is the id of the request (32 = friend request, 254 = ping request).
*
* return -1 on failure.
* return the length of the created packet on success.
*/
int create_request(uint8_t *send_public_key, uint8_t *send_secret_key, uint8_t *packet, uint8_t *recv_public_key,
uint8_t *data, uint32_t length, uint8_t request_id)
{
if (MAX_CRYPTO_REQUEST_SIZE < length + 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 +
crypto_box_MACBYTES)
return -1;
uint8_t nonce[crypto_box_NONCEBYTES];
uint8_t temp[MAX_CRYPTO_REQUEST_SIZE];
memcpy(temp + 1, data, length);
temp[0] = request_id;
new_nonce(nonce);
int len = encrypt_data(recv_public_key, send_secret_key, nonce, temp, length + 1,
1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + packet);
if (len == -1)
return -1;
packet[0] = NET_PACKET_CRYPTO;
memcpy(packet + 1, recv_public_key, crypto_box_PUBLICKEYBYTES);
memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES, send_public_key, crypto_box_PUBLICKEYBYTES);
memcpy(packet + 1 + crypto_box_PUBLICKEYBYTES * 2, nonce, crypto_box_NONCEBYTES);
return len + 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES;
}
/* Puts the senders public key in the request in public_key, the data from the request
* in data if a friend or ping request was sent to us and returns the length of the data.
* packet is the request packet and length is its length.
*
* return -1 if not valid request.
*/
int handle_request(uint8_t *self_public_key, uint8_t *self_secret_key, uint8_t *public_key, uint8_t *data,
uint8_t *request_id, uint8_t *packet, uint16_t length)
{
if (length > crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1 + crypto_box_MACBYTES &&
length <= MAX_CRYPTO_REQUEST_SIZE) {
if (memcmp(packet + 1, self_public_key, crypto_box_PUBLICKEYBYTES) == 0) {
memcpy(public_key, packet + 1 + crypto_box_PUBLICKEYBYTES, crypto_box_PUBLICKEYBYTES);
uint8_t nonce[crypto_box_NONCEBYTES];
uint8_t temp[MAX_CRYPTO_REQUEST_SIZE];
memcpy(nonce, packet + 1 + crypto_box_PUBLICKEYBYTES * 2, crypto_box_NONCEBYTES);
int len1 = decrypt_data(public_key, self_secret_key, nonce,
packet + 1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES,
length - (crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES + 1), temp);
if (len1 == -1 || len1 == 0)
return -1;
request_id[0] = temp[0];
--len1;
memcpy(data, temp + 1, len1);
return len1;
}
}
return -1;
}

142
toxcore/crypto_core.h Normal file
View File

@ -0,0 +1,142 @@
/* crypto_core.h
*
* Functions for the core crypto.
*
* Copyright (C) 2013 Tox project All Rights Reserved.
*
* This file is part of Tox.
*
* Tox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef CORE_CRYPTO_H
#define CORE_CRYPTO_H
#include "network.h"
#ifndef VANILLA_NACL
/* We use libsodium by default. */
#include <sodium.h>
#else
#include <crypto_box.h>
#include <randombytes.h>
#include <crypto_hash_sha256.h>
#include <crypto_hash_sha512.h>
#include <crypto_verify_16.h>
#include <crypto_verify_32.h>
#define crypto_box_MACBYTES (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES)
#endif
#define crypto_box_KEYBYTES (crypto_box_BEFORENMBYTES)
/* Use this instead of memcmp; not vulnerable to timing attacks.
returns 0 if both mem locations of length are equal,
return -1 if they are not. */
int crypto_cmp(uint8_t *mem1, uint8_t *mem2, uint32_t length);
/* return a random number.
*
* random_int for a 32bin int.
* random_64b for a 64bit int.
*/
uint32_t random_int(void);
uint64_t random_64b(void);
/* Encrypts plain of length length to encrypted of length + 16 using the
* public key(32 bytes) of the receiver and the secret key of the sender and a 24 byte nonce.
*
* return -1 if there was a problem.
* return length of encrypted data if everything was fine.
*/
int encrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce,
uint8_t *plain, uint32_t length, uint8_t *encrypted);
/* Decrypts encrypted of length length to plain of length length - 16 using the
* public key(32 bytes) of the sender, the secret key of the receiver and a 24 byte nonce.
*
* return -1 if there was a problem (decryption failed).
* return length of plain data if everything was fine.
*/
int decrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce,
uint8_t *encrypted, uint32_t length, uint8_t *plain);
/* Fast encrypt/decrypt operations. Use if this is not a one-time communication.
encrypt_precompute does the shared-key generation once so it does not have
to be preformed on every encrypt/decrypt. */
void encrypt_precompute(uint8_t *public_key, uint8_t *secret_key, uint8_t *enc_key);
/* Encrypts plain of length length to encrypted of length + 16 using a
* secret key crypto_box_KEYBYTES big and a 24 byte nonce.
*
* return -1 if there was a problem.
* return length of encrypted data if everything was fine.
*/
int encrypt_data_symmetric(uint8_t *secret_key, uint8_t *nonce, uint8_t *plain, uint32_t length, uint8_t *encrypted);
/* Decrypts encrypted of length length to plain of length length - 16 using a
* secret key crypto_box_KEYBYTES big and a 24 byte nonce.
*
* return -1 if there was a problem (decryption failed).
* return length of plain data if everything was fine.
*/
int decrypt_data_symmetric(uint8_t *secret_key, uint8_t *nonce, uint8_t *encrypted, uint32_t length, uint8_t *plain);
/* Increment the given nonce by 1. */
void increment_nonce(uint8_t *nonce);
/* increment the given nonce by num */
void increment_nonce_number(uint8_t *nonce, uint32_t num);
/* Fill the given nonce with random bytes. */
void random_nonce(uint8_t *nonce);
/* Fill a key crypto_box_KEYBYTES big with random bytes */
void new_symmetric_key(uint8_t *key);
/*Gives a nonce guaranteed to be different from previous ones.*/
void new_nonce(uint8_t *nonce);
#define MAX_CRYPTO_REQUEST_SIZE 1024
#define CRYPTO_PACKET_FRIEND_REQ 32 /* Friend request crypto packet ID. */
#define CRYPTO_PACKET_HARDENING 48 /* Hardening crypto packet ID. */
#define CRYPTO_PACKET_NAT_PING 254 /* NAT ping crypto packet ID. */
#define CRYPTO_PACKET_GROUP_CHAT_GET_NODES 48 /* Group chat get Nodes packet */
#define CRYPTO_PACKET_GROUP_CHAT_SEND_NODES 49 /* Group chat send Nodes packet */
#define CRYPTO_PACKET_GROUP_CHAT_BROADCAST 50 /* Group chat broadcast packet */
/* Create a request to peer.
* send_public_key and send_secret_key are the pub/secret keys of the sender.
* recv_public_key is public key of reciever.
* packet must be an array of MAX_CRYPTO_REQUEST_SIZE big.
* Data represents the data we send with the request with length being the length of the data.
* request_id is the id of the request (32 = friend request, 254 = ping request).
*
* return -1 on failure.
* return the length of the created packet on success.
*/
int create_request(uint8_t *send_public_key, uint8_t *send_secret_key, uint8_t *packet, uint8_t *recv_public_key,
uint8_t *data, uint32_t length, uint8_t request_id);
/* puts the senders public key in the request in public_key, the data from the request
in data if a friend or ping request was sent to us and returns the length of the data.
packet is the request packet and length is its length
return -1 if not valid request. */
int handle_request(uint8_t *self_public_key, uint8_t *self_secret_key, uint8_t *public_key, uint8_t *data,
uint8_t *request_id, uint8_t *packet, uint16_t length);
#endif

View File

@ -37,10 +37,10 @@
*/
int send_friendrequest(Onion_Client *onion_c, uint8_t *public_key, uint32_t nospam_num, uint8_t *data, uint32_t length)
{
if (length + sizeof(nospam_num) > MAX_DATA_SIZE)
if (1 + sizeof(nospam_num) + length > ONION_CLIENT_MAX_DATA_SIZE || length == 0)
return -1;
uint8_t temp[MAX_DATA_SIZE];
uint8_t temp[1 + sizeof(nospam_num) + length];
temp[0] = CRYPTO_PACKET_FRIEND_REQ;
memcpy(temp + 1, &nospam_num, sizeof(nospam_num));
memcpy(temp + 1 + sizeof(nospam_num), data, length);
@ -50,7 +50,7 @@ int send_friendrequest(Onion_Client *onion_c, uint8_t *public_key, uint32_t nosp
if (friend_num == -1)
return -1;
int num = send_onion_data(onion_c, friend_num, temp, 1 + sizeof(nospam_num) + length);
int num = send_onion_data(onion_c, friend_num, temp, sizeof(temp));
if (num <= 0)
return -1;
@ -135,20 +135,17 @@ int remove_request_received(Friend_Requests *fr, uint8_t *client_id)
static int friendreq_handlepacket(void *object, uint8_t *source_pubkey, uint8_t *packet, uint32_t length)
{
if (length == 0)
Friend_Requests *fr = object;
if (length <= 1 + sizeof(fr->nospam) || length > ONION_CLIENT_MAX_DATA_SIZE)
return 1;
++packet;
--length;
Friend_Requests *fr = object;
if (fr->handle_friendrequest_isset == 0)
return 1;
if (length <= sizeof(fr->nospam))
return 1;
if (request_received(fr, source_pubkey))
return 1;
@ -161,11 +158,12 @@ static int friendreq_handlepacket(void *object, uint8_t *source_pubkey, uint8_t
addto_receivedlist(fr, source_pubkey);
uint8_t message[length - 4 + 1];
memcpy(message, packet + 4, length - 4);
uint32_t message_len = length - sizeof(fr->nospam);
uint8_t message[message_len + 1];
memcpy(message, packet + sizeof(fr->nospam), message_len);
message[sizeof(message) - 1] = 0; /* Be sure the message is null terminated. */
(*fr->handle_friendrequest)(fr->handle_friendrequest_object, source_pubkey, message, length - 4,
(*fr->handle_friendrequest)(fr->handle_friendrequest_object, source_pubkey, message, message_len,
fr->handle_friendrequest_userdata);
return 0;
}

View File

@ -25,8 +25,8 @@
#define FRIEND_REQUESTS_H
#include "onion_client.h"
#include "net_crypto.h"
#define MAX_FRIEND_REQUEST_DATA_SIZE (ONION_CLIENT_MAX_DATA_SIZE - (1 + sizeof(uint32_t)))
typedef struct {
uint32_t nospam;
@ -48,7 +48,8 @@ typedef struct {
} Friend_Requests;
/* Try to send a friendrequest to peer with public_key.
* data is the data in the request and length is the length.
* data is the data in the request and length is the length.
* Maximum length of data is MAX_FRIEND_REQUEST_DATA_SIZE.
*/
int send_friendrequest(Onion_Client *onion_c, uint8_t *public_key, uint32_t nospam_num, uint8_t *data, uint32_t length);
/* Set and get the nospam variable used to prevent one type of friend request spam. */

View File

@ -26,12 +26,13 @@
#include "config.h"
#endif
#include "group_chats.h"
#include "DHT.h"
#include "assoc.h"
#include "group_chats.h"
#include "LAN_discovery.h"
#include "util.h"
#define GROUPCHAT_MAXDATA_LENGTH (MAX_DATA_SIZE - (1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES))
#define GROUPCHAT_MAXDATA_LENGTH (MAX_CRYPTO_REQUEST_SIZE - (1 + crypto_box_PUBLICKEYBYTES * 2 + crypto_box_NONCEBYTES))
#define GROUPCHAT_MAXPLAINDATA_LENGTH (GROUPCHAT_MAXDATA_LENGTH - crypto_box_MACBYTES)
#define GROUP_MAX_SENDNODES (GROUP_CLOSE_CONNECTIONS * 2)
@ -180,7 +181,7 @@ static int send_groupchatpacket(Group_Chat *chat, IP_Port ip_port, uint8_t *publ
if (id_equal(chat->self_public_key, public_key))
return -1;
uint8_t packet[MAX_DATA_SIZE];
uint8_t packet[MAX_CRYPTO_REQUEST_SIZE];
int len = create_request(chat->self_public_key, chat->self_secret_key, packet, public_key, data, length, request_id);
packet[0] = NET_PACKET_GROUP_CHATS;
@ -586,10 +587,10 @@ static int handle_data(Group_Chat *chat, uint8_t *data, uint32_t len)
static uint8_t send_data(Group_Chat *chat, uint8_t *data, uint32_t len, uint8_t message_id)
{
if (len + GROUP_DATA_MIN_SIZE > MAX_DATA_SIZE) /*NOTE: not the real maximum len.*/
if (len + GROUP_DATA_MIN_SIZE > MAX_CRYPTO_REQUEST_SIZE) /*NOTE: not the real maximum len.*/
return 1;
uint8_t packet[MAX_DATA_SIZE];
uint8_t packet[MAX_CRYPTO_REQUEST_SIZE];
++chat->message_number;
if (chat->message_number == 0)
@ -615,11 +616,11 @@ static uint8_t send_data(Group_Chat *chat, uint8_t *data, uint32_t len, uint8_t
int handle_groupchatpacket(Group_Chat *chat, IP_Port source, uint8_t *packet, uint32_t length)
{
if (length > MAX_DATA_SIZE)
if (length > MAX_CRYPTO_REQUEST_SIZE)
return 1;
uint8_t public_key[crypto_box_PUBLICKEYBYTES];
uint8_t data[MAX_DATA_SIZE];
uint8_t data[MAX_CRYPTO_REQUEST_SIZE];
uint8_t number;
int len = handle_request(chat->self_public_key, chat->self_secret_key, public_key, data, &number, packet, length);

View File

@ -25,8 +25,6 @@
#ifndef GROUP_CHATS_H
#define GROUP_CHATS_H
#include "net_crypto.h"
#define MAX_NICK_BYTES 128
typedef struct {

File diff suppressed because it is too large Load Diff

View File

@ -24,21 +24,62 @@
#ifndef NET_CRYPTO_H
#define NET_CRYPTO_H
#include "Lossless_UDP.h"
#define CRYPTO_PACKET_FRIEND_REQ 32 /* Friend request crypto packet ID. */
#define CRYPTO_PACKET_HARDENING 48 /* Hardening crypto packet ID. */
#define CRYPTO_PACKET_NAT_PING 254 /* NAT ping crypto packet ID. */
#define CRYPTO_PACKET_GROUP_CHAT_GET_NODES 48 /* Group chat get Nodes packet */
#define CRYPTO_PACKET_GROUP_CHAT_SEND_NODES 49 /* Group chat send Nodes packet */
#define CRYPTO_PACKET_GROUP_CHAT_BROADCAST 50 /* Group chat broadcast packet */
#define CRYPTO_HANDSHAKE_TIMEOUT (CONNECTION_TIMEOUT * 2)
#include "DHT.h"
#include "TCP_client.h"
#define CRYPTO_CONN_NO_CONNECTION 0
#define CRYPTO_CONN_HANDSHAKE_SENT 1
#define CRYPTO_CONN_NOT_CONFIRMED 2
#define CRYPTO_CONN_ESTABLISHED 3
#define CRYPTO_CONN_TIMED_OUT 4
#define CRYPTO_CONN_COOKIE_REQUESTING 1 //send cookie request packets
#define CRYPTO_CONN_HANDSHAKE_SENT 2 //send handshake packets
#define CRYPTO_CONN_NOT_CONFIRMED 3 //send handshake packets
#define CRYPTO_CONN_ESTABLISHED 4
#define CRYPTO_CONN_TIMED_OUT 5
#define CRYPTO_PACKET_BUFFER_SIZE 16384 /* Must be a power of 2 */
/* Minimum packet rate per second. */
#define CRYPTO_PACKET_MIN_RATE 40.0
/* Minimum packet queue max length. */
#define CRYPTO_MIN_QUEUE_LENGTH 8
#define MAX_CRYPTO_PACKET_SIZE 1400
#define CRYPTO_DATA_PACKET_MIN_SIZE (1 + sizeof(uint16_t) + (sizeof(uint32_t) + sizeof(uint32_t)) + crypto_box_MACBYTES)
/* Max size of data in packets TODO*/
#define MAX_CRYPTO_DATA_SIZE (MAX_CRYPTO_PACKET_SIZE - CRYPTO_DATA_PACKET_MIN_SIZE)
/* Interval in ms between sending cookie request/handshake packets. */
#define CRYPTO_SEND_PACKET_INTERVAL 500
/* The maximum number of times we try to send the cookie request and handshake
before giving up. */
#define MAX_NUM_SENDPACKET_TRIES 8
#define PACKET_ID_PADDING 0
#define PACKET_ID_REQUEST 1
#define PACKET_ID_KILL 2
#define CRYPTO_RESERVED_PACKETS 16
#define MAX_TCP_CONNECTIONS 32
#define MAX_TCP_RELAYS_PEER 4
#define STATUS_TCP_NULL 0
#define STATUS_TCP_OFFLINE 1
#define STATUS_TCP_INVISIBLE 2 /* we know the other peer is connected to this relay but he isn't appearing online */
#define STATUS_TCP_ONLINE 3
typedef struct {
uint64_t time;
uint16_t length;
uint8_t data[MAX_CRYPTO_DATA_SIZE];
} Packet_Data;
typedef struct {
Packet_Data *buffer[CRYPTO_PACKET_BUFFER_SIZE];
uint32_t buffer_start;
uint32_t buffer_end; /* packet numbers in array: {buffer_start, buffer_end) */
} Packets_Array;
typedef struct {
uint8_t public_key[crypto_box_PUBLICKEYBYTES]; /* The real public key of the peer. */
@ -48,27 +89,73 @@ typedef struct {
uint8_t sessionsecret_key[crypto_box_SECRETKEYBYTES]; /* Our private key for this session. */
uint8_t peersessionpublic_key[crypto_box_PUBLICKEYBYTES]; /* The public key of the peer. */
uint8_t shared_key[crypto_box_BEFORENMBYTES]; /* The precomputed shared key from encrypt_precompute. */
uint8_t status; /* 0 if no connection, 1 we have sent a handshake, 2 if connection is not confirmed yet
* (we have received a handshake but no empty data packet), 3 if the connection is established.
* 4 if the connection is timed out.
uint8_t status; /* 0 if no connection, 1 we are sending cookie request packets,
* 2 if we are sending handshake packets
* 3 if connection is not confirmed yet (we have received a handshake but no data packets yet),
* 4 if the connection is established.
* 5 if the connection is timed out.
*/
uint16_t number; /* Lossless_UDP connection number corresponding to this connection. */
uint64_t timeout;
uint64_t cookie_request_number; /* number used in the cookie request packets for this connection */
uint8_t dht_public_key[crypto_box_PUBLICKEYBYTES]; /* The dht public key of the peer */
uint8_t dht_public_key_set; /* True if the dht public key is set, false if it isn't. */
uint64_t dht_public_key_timestamp; /* Timestamp of the last time we confirmed the key was correct. */
uint8_t *temp_packet; /* Where the cookie request/handshake packet is stored while it is being sent. */
uint16_t temp_packet_length;
uint64_t temp_packet_sent_time; /* The time at which the last temp_packet was sent in ms. */
uint32_t temp_packet_num_sent;
IP_Port ip_port; /* The ip and port to contact this guy directly.*/
uint64_t direct_lastrecv_time; /* The Time at which we last received a direct packet in ms. */
Packets_Array send_array;
Packets_Array recv_array;
int (*connection_status_callback)(void *object, int id, uint8_t status);
void *connection_status_callback_object;
int connection_status_callback_id;
int (*connection_data_callback)(void *object, int id, uint8_t *data, uint16_t length);
void *connection_data_callback_object;
int connection_data_callback_id;
uint64_t last_request_packet_sent;
uint32_t packet_counter;
double packet_recv_rate;
uint64_t packet_counter_set;
double packet_send_rate;
uint32_t packets_left;
uint64_t last_packets_left_set;
uint8_t sending; /* indicates if data is being sent or not. */
uint8_t killed; /* set to 1 to kill the connection. */
uint8_t status_tcp[MAX_TCP_CONNECTIONS]; /* set to one of STATUS_TCP_* */
uint8_t con_number_tcp[MAX_TCP_CONNECTIONS];
Node_format tcp_relays[MAX_TCP_RELAYS_PEER];
uint16_t num_tcp_relays;
} Crypto_Connection;
typedef int (*cryptopacket_handler_callback)(void *object, IP_Port ip_port, uint8_t *source_pubkey, uint8_t *data,
uint32_t len);
typedef struct {
IP_Port source;
uint8_t public_key[crypto_box_PUBLICKEYBYTES]; /* The real public key of the peer. */
uint8_t dht_public_key[crypto_box_PUBLICKEYBYTES]; /* The dht public key of the peer. */
uint8_t recv_nonce[crypto_box_NONCEBYTES]; /* Nonce of received packets. */
uint8_t peersessionpublic_key[crypto_box_PUBLICKEYBYTES]; /* The public key of the peer. */
uint8_t *cookie;
uint8_t cookie_length;
} New_Connection;
typedef struct {
cryptopacket_handler_callback function;
void *object;
} Cryptopacket_Handles;
typedef struct {
Lossless_UDP *lossless_udp;
DHT *dht;
Crypto_Connection *crypto_connections;
TCP_Client_Connection *tcp_connections_new[MAX_TCP_CONNECTIONS];
TCP_Client_Connection *tcp_connections[MAX_TCP_CONNECTIONS];
uint32_t crypto_connections_length; /* Length of connections array. */
@ -76,154 +163,131 @@ typedef struct {
uint8_t self_public_key[crypto_box_PUBLICKEYBYTES];
uint8_t self_secret_key[crypto_box_SECRETKEYBYTES];
Cryptopacket_Handles cryptopackethandlers[256];
/* The secret key used for cookies */
uint8_t secret_symmetric_key[crypto_box_KEYBYTES];
int (*new_connection_callback)(void *object, New_Connection *n_c);
void *new_connection_callback_object;
} Net_Crypto;
#include "DHT.h"
/* return zero if the buffer contains only zeros. */
uint8_t crypto_iszero(uint8_t *buffer, uint32_t blen);
/* Encrypts plain of length length to encrypted of length + 16 using the
* public key(32 bytes) of the receiver and the secret key of the sender and a 24 byte nonce.
/* Set function to be called when someone requests a new connection to us.
*
* return -1 if there was a problem.
* return length of encrypted data if everything was fine.
*/
int encrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce,
uint8_t *plain, uint32_t length, uint8_t *encrypted);
/* Decrypts encrypted of length length to plain of length length - 16 using the
* public key(32 bytes) of the sender, the secret key of the receiver and a 24 byte nonce.
* The set function should return -1 on failure and 0 on success.
*
* return -1 if there was a problem (decryption failed).
* return length of plain data if everything was fine.
* n_c is only valid for the duration of the function call.
*/
int decrypt_data(uint8_t *public_key, uint8_t *secret_key, uint8_t *nonce,
uint8_t *encrypted, uint32_t length, uint8_t *plain);
void new_connection_handler(Net_Crypto *c, int (*new_connection_callback)(void *object, New_Connection *n_c),
void *object);
/* Fast encrypt/decrypt operations. Use if this is not a one-time communication.
encrypt_precompute does the shared-key generation once so it does not have
to be preformed on every encrypt/decrypt. */
void encrypt_precompute(uint8_t *public_key, uint8_t *secret_key, uint8_t *enc_key);
/* Fast encrypt. Depends on enc_key from encrypt_precompute. */
int encrypt_data_fast(uint8_t *enc_key, uint8_t *nonce,
uint8_t *plain, uint32_t length, uint8_t *encrypted);
/* Fast decrypt. Depends on enc_ley from encrypt_precompute. */
int decrypt_data_fast(uint8_t *enc_key, uint8_t *nonce,
uint8_t *encrypted, uint32_t length, uint8_t *plain);
/* Encrypts plain of length length to encrypted of length + 16 using a
* secret key crypto_secretbox_KEYBYTES big and a 24 byte nonce.
/* Accept a crypto connection.
*
* return -1 if there was a problem.
* return length of encrypted data if everything was fine.
* return -1 on failure.
* return connection id on success.
*/
int encrypt_data_symmetric(uint8_t *secret_key, uint8_t *nonce, uint8_t *plain, uint32_t length, uint8_t *encrypted);
int accept_crypto_connection(Net_Crypto *c, New_Connection *n_c);
/* Decrypts encrypted of length length to plain of length length - 16 using a
* secret key crypto_secretbox_KEYBYTES big and a 24 byte nonce.
/* Create a crypto connection.
* If one to that real public key already exists, return it.
*
* return -1 if there was a problem (decryption failed).
* return length of plain data if everything was fine.
* return -1 on failure.
* return connection id on success.
*/
int decrypt_data_symmetric(uint8_t *secret_key, uint8_t *nonce, uint8_t *encrypted, uint32_t length, uint8_t *plain);
int new_crypto_connection(Net_Crypto *c, uint8_t *real_public_key);
/* Increment the given nonce by 1. */
void increment_nonce(uint8_t *nonce);
/* Fill the given nonce with random bytes. */
void random_nonce(uint8_t *nonce);
/* Fill a key crypto_secretbox_KEYBYTES big with random bytes */
void new_symmetric_key(uint8_t *key);
/*Gives a nonce guaranteed to be different from previous ones.*/
void new_nonce(uint8_t *nonce);
/* return 0 if there is no received data in the buffer.
* return -1 if the packet was discarded.
* return length of received data if successful.
/* Copy friends DHT public key into dht_key.
*
* return 0 on failure (no key copied).
* return timestamp on success (key copied).
*/
int read_cryptpacket(Net_Crypto *c, int crypt_connection_id, uint8_t *data);
uint64_t get_connection_dht_key(Net_Crypto *c, int crypt_connection_id, uint8_t *dht_public_key);
/* Set the DHT public key of the crypto connection.
* timestamp is the time (current_time_monotonic()) at which the key was last confirmed belonging to
* the other peer.
*
* return -1 on failure.
* return 0 on success.
*/
int set_connection_dht_public_key(Net_Crypto *c, int crypt_connection_id, uint8_t *dht_public_key, uint64_t timestamp);
/* Set the direct ip of the crypto connection.
*
* return -1 on failure.
* return 0 on success.
*/
int set_direct_ip_port(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port);
/* Set function to be called when connection with crypt_connection_id goes connects/disconnects.
*
* The set function should return -1 on failure and 0 on success.
* Note that if this function is set, the connection will clear itself on disconnect.
* Object and id will be passed to this function untouched.
* status is 1 if the connection is going online, 0 if it is going offline.
*
* return -1 on failure.
* return 0 on success.
*/
int connection_status_handler(Net_Crypto *c, int crypt_connection_id, int (*connection_status_callback)(void *object,
int id, uint8_t status), void *object, int id);
/* Set function to be called when connection with crypt_connection_id receives a data packet of length.
*
* The set function should return -1 on failure and 0 on success.
* Object and id will be passed to this function untouched.
*
* return -1 on failure.
* return 0 on success.
*/
int connection_data_handler(Net_Crypto *c, int crypt_connection_id, int (*connection_data_callback)(void *object,
int id, uint8_t *data, uint16_t length), void *object, int id);
/* returns the number of packet slots left in the sendbuffer.
* return 0 if failure.
*/
uint32_t crypto_num_free_sendqueue_slots(Net_Crypto *c, int crypt_connection_id);
/* return 0 if data could not be put in packet queue.
* return 1 if data was put into the queue.
/* return -1 if data could not be put in packet queue.
* return positive packet number if data was put into the queue.
*/
int write_cryptpacket(Net_Crypto *c, int crypt_connection_id, uint8_t *data, uint32_t length);
int64_t write_cryptpacket(Net_Crypto *c, int crypt_connection_id, uint8_t *data, uint32_t length);
/* Create a request to peer.
* send_public_key and send_secret_key are the pub/secret keys of the sender.
* recv_public_key is public key of reciever.
* packet must be an array of MAX_DATA_SIZE big.
* Data represents the data we send with the request with length being the length of the data.
* request_id is the id of the request (32 = friend request, 254 = ping request).
/* Add a tcp relay, associating it to a crypt_connection_id.
*
* return -1 on failure.
* return the length of the created packet on success.
* return 0 if it was added.
* return -1 if it wasn't.
*/
int create_request(uint8_t *send_public_key, uint8_t *send_secret_key, uint8_t *packet, uint8_t *recv_public_key,
uint8_t *data, uint32_t length, uint8_t request_id);
int add_tcp_relay_peer(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port, uint8_t *public_key);
/* puts the senders public key in the request in public_key, the data from the request
in data if a friend or ping request was sent to us and returns the length of the data.
packet is the request packet and length is its length
return -1 if not valid request. */
int handle_request(uint8_t *self_public_key, uint8_t *self_secret_key, uint8_t *public_key, uint8_t *data,
uint8_t *request_id, uint8_t *packet, uint16_t length);
/* Function to call when request beginning with byte is received. */
void cryptopacket_registerhandler(Net_Crypto *c, uint8_t byte, cryptopacket_handler_callback cb, void *object);
/* Start a secure connection with other peer who has public_key and ip_port.
/* Add a tcp relay to the array.
*
* return -1 if failure.
* return crypt_connection_id of the initialized connection if everything went well.
* return 0 if it was added.
* return -1 if it wasn't.
*/
int crypto_connect(Net_Crypto *c, uint8_t *public_key, IP_Port ip_port);
int add_tcp_relay(Net_Crypto *c, IP_Port ip_port, uint8_t *public_key);
/* Copy a maximum of num TCP relays we are connected to to tcp_relays.
* NOTE that the family of the copied ip ports will be set to TCP_INET or TCP_INET6.
*
* return number of relays copied to tcp_relays on success.
* return 0 on failure.
*/
unsigned int copy_connected_tcp_relays(Net_Crypto *c, Node_format *tcp_relays, uint16_t num);
/* Kill a crypto connection.
*
* return 0 if killed successfully.
* return 1 if there was a problem.
* return -1 on failure.
* return 0 on success.
*/
int crypto_kill(Net_Crypto *c, int crypt_connection_id);
/* Handle an incoming connection.
*
* return -1 if no crypto inbound connection.
* return incoming connection id (Lossless_UDP one) if there is an incoming crypto connection.
*
* Put the public key of the peer in public_key, the secret_nonce from the handshake into secret_nonce
* and the session public key for the connection in session_key.
* to accept it see: accept_crypto_inbound(...).
* to refuse it just call kill_connection(...) on the connection id.
*/
int crypto_inbound(Net_Crypto *c, uint8_t *public_key, uint8_t *secret_nonce, uint8_t *session_key);
/* Accept an incoming connection using the parameters provided by crypto_inbound.
/* return one of CRYPTO_CONN_* values indicating the state of the connection.
*
* return -1 if not successful.
* return crypt_connection_id if successful.
* sets direct_connected to 1 if connection connects directly to other, 0 if it isn't.
*/
int accept_crypto_inbound(Net_Crypto *c, int connection_id, uint8_t *public_key, uint8_t *secret_nonce,
uint8_t *session_key);
/* return 0 if no connection.
* return 1 we have sent a handshake
* return 2 if connexion is not confirmed yet (we have received a handshake but no empty data packet).
* return 3 if the connection is established.
* return 4 if the connection is timed out and waiting to be killed.
*/
int is_cryptoconnected(Net_Crypto *c, int crypt_connection_id);
unsigned int crypto_connection_status(Net_Crypto *c, int crypt_connection_id, uint8_t *direct_connected);
/* Generate our public and private keys.
@ -244,15 +308,13 @@ void load_keys(Net_Crypto *c, uint8_t *keys);
/* Create new instance of Net_Crypto.
* Sets all the global connection variables to their default values.
*/
Net_Crypto *new_net_crypto(Networking_Core *net);
Net_Crypto *new_net_crypto(DHT *dht);
/* Main loop. */
void do_net_crypto(Net_Crypto *c);
void kill_net_crypto(Net_Crypto *c);
/* Initialize the cryptopacket handling. */
void init_cryptopackets(void *dht);
#endif

View File

@ -29,13 +29,17 @@
#include "config.h"
#endif
#define LOGGING
#include "logger.h"
#if !defined(_WIN32) && !defined(__WIN32__) && !defined (WIN32)
#include <errno.h>
#endif
#ifdef __APPLE__
#include <mach/clock.h>
#include <mach/mach.h>
#endif
#include "network.h"
#include "util.h"
@ -153,6 +157,21 @@ int set_socket_nonblock(sock_t sock)
#endif
}
/* Set socket to not emit SIGPIPE
*
* return 1 on success
* return 0 on failure
*/
int set_socket_nosigpipe(sock_t sock)
{
#if defined(__MACH__)
int set = 1;
return (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int)) == 0);
#else
return 1;
#endif
}
/* Set socket to dual (IPv4 + IPv6 socket)
*
* return 1 on success
@ -160,7 +179,7 @@ int set_socket_nonblock(sock_t sock)
*/
int set_socket_dualstack(sock_t sock)
{
char ipv6only = 0;
int ipv6only = 0;
socklen_t optsize = sizeof(ipv6only);
int res = getsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6only, &optsize);
@ -171,8 +190,9 @@ int set_socket_dualstack(sock_t sock)
return (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6only, sizeof(ipv6only)) == 0);
}
/* return current UNIX time in microseconds (us). */
uint64_t current_time(void)
static uint64_t current_time_actual(void)
{
uint64_t time;
#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
@ -192,29 +212,52 @@ uint64_t current_time(void)
#endif
}
/* return a random number.
*/
uint32_t random_int(void)
{
uint32_t randnum;
randombytes((uint8_t *)&randnum , sizeof(randnum));
return randnum;
}
uint64_t random_64b(void)
#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
static uint64_t last_monotime;
static uint64_t add_monotime;
#endif
/* return current monotonic time in milliseconds (ms). */
uint64_t current_time_monotonic(void)
{
uint64_t randnum;
randombytes((uint8_t *)&randnum, sizeof(randnum));
return randnum;
uint64_t time;
#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
time = (uint64_t)GetTickCount() + add_monotime;
if (time < last_monotime) { /* Prevent time from ever decreasing because of 32 bit wrap. */
uint32_t add = ~0;
add_monotime += add;
time += add;
}
last_monotime = time;
#else
struct timespec monotime;
#if defined(__linux__)
clock_gettime(CLOCK_MONOTONIC_RAW, &monotime);
#elif defined(__APPLE__)
clock_serv_t muhclock;
mach_timespec_t machtime;
host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &muhclock);
clock_get_time(muhclock, &machtime);
mach_port_deallocate(mach_task_self(), muhclock);
monotime.tv_sec = machtime.tv_sec;
monotime.tv_nsec = machtime.tv_nsec;
#else
clock_gettime(CLOCK_MONOTONIC, &monotime);
#endif
time = 1000ULL * monotime.tv_sec + (monotime.tv_nsec / 1000000ULL);
#endif
return time;
}
/* In case no logging */
#ifndef LOGGING
#define loglogdata(__message__, __buffer__, __buflen__, __ip_port__, __res__)
#else
#else
#define data_0(__buflen__, __buffer__) __buflen__ > 4 ? ntohl(*(uint32_t *)&__buffer__[1]) : 0
#define data_1(__buflen__, __buffer__) __buflen__ > 7 ? ntohl(*(uint32_t *)&__buffer__[5]) : 0
@ -299,7 +342,7 @@ int sendpacket(Networking_Core *net, IP_Port ip_port, uint8_t *data, uint32_t le
if ((res >= 0) && ((uint32_t)res == length))
net->send_fail_eagain = 0;
else if ((res < 0) && (errno == EWOULDBLOCK))
net->send_fail_eagain = current_time();
net->send_fail_eagain = current_time_monotonic();
return res;
}
@ -308,7 +351,6 @@ int sendpacket(Networking_Core *net, IP_Port ip_port, uint8_t *data, uint32_t le
* ip and port of sender is put into ip_port.
* Packet data is put into data.
* Packet length is put into length.
* Dump all empty packets.
*/
static int receivepacket(sock_t sock, IP_Port *ip_port, uint8_t *data, uint32_t *length)
{
@ -322,7 +364,7 @@ static int receivepacket(sock_t sock, IP_Port *ip_port, uint8_t *data, uint32_t
*length = 0;
int fail_or_len = recvfrom(sock, (char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen);
if (fail_or_len <= 0) {
if (fail_or_len < 0) {
LOGGER_SCOPE( if ((fail_or_len < 0) && (errno != EWOULDBLOCK))
LOGGER_ERROR("Unexpected error reading from socket: %u, %s\n", errno, strerror(errno)); );
@ -438,13 +480,13 @@ int networking_wait_execute(uint8_t *data, long seconds, long microseconds)
* that code)
*/
if (s->send_fail_eagain != 0) {
// current_time(): microseconds
uint64_t now = current_time();
// current_time(): milliseconds
uint64_t now = current_time_monotonic();
/* s->sendqueue_length: might be used to guess how long we keep checking */
/* for now, threshold is hardcoded to 250ms, too long for a really really
* fast link, but too short for a sloooooow link... */
if (now - s->send_fail_eagain < 250000) {
if (now - s->send_fail_eagain < 250) {
writefds_add = 1;
}
}
@ -508,6 +550,11 @@ int networking_wait_cleanup(Networking_Core *net, uint8_t *data)
return 1;
}
#ifndef VANILLA_NACL
/* Used for sodium_init() */
#include <sodium.h>
#endif
uint8_t at_startup_ran = 0;
int networking_at_startup(void)
{
@ -531,9 +578,9 @@ int networking_at_startup(void)
return -1;
#else
srandom((uint32_t)current_time());
srandom((uint32_t)current_time_actual());
#endif
srand((uint32_t)current_time());
srand((uint32_t)current_time_actual());
at_startup_ran = 1;
return 0;
}
@ -637,7 +684,6 @@ Networking_Core *new_networking(IP ip, uint16_t port)
}
if (ip.family == AF_INET6) {
#ifdef LOGGING
int is_dualstack =
#endif /* LOGGING */
@ -650,7 +696,6 @@ Networking_Core *new_networking(IP ip, uint16_t port)
mreq.ipv6mr_multiaddr.s6_addr[ 1] = 0x02;
mreq.ipv6mr_multiaddr.s6_addr[15] = 0x01;
mreq.ipv6mr_interface = 0;
#ifdef LOGGING
int res =
#endif /* LOGGING */
@ -829,6 +874,31 @@ void ipport_copy(IP_Port *target, IP_Port *source)
memcpy(target, source, sizeof(IP_Port));
};
/* packing and unpacking functions */
void ip_pack(uint8_t *data, IP *source)
{
data[0] = source->family;
memcpy(data + 1, &source->ip6, SIZE_IP6);
}
void ip_unpack(IP *target, uint8_t *data)
{
target->family = data[0];
memcpy(&target->ip6, data + 1, SIZE_IP6);
}
void ipport_pack(uint8_t *data, IP_Port *source)
{
ip_pack(data, &source->ip);
memcpy(data + SIZE_IP, &source->port, SIZE_PORT);
}
void ipport_unpack(IP_Port *target, uint8_t *data)
{
ip_unpack(&target->ip, data);
memcpy(&target->port, data + SIZE_IP, SIZE_PORT);
}
/* ip_ntoa
* converts ip into a string
* uses a static buffer, so mustn't used multiple times in the same output

View File

@ -89,7 +89,7 @@ typedef int sock_t;
#endif
#if defined(__sun__)
#define __EXTENSIONS__ 1 // SunOS!
#define __EXTENSIONS__ 1 // SunOS!
#if defined(__SunOS5_6__) || defined(__SunOS5_7__) || defined(__SunOS5_8__) || defined(__SunOS5_9__) || defined(__SunOS5_10__)
//Nothing needed
#else
@ -97,21 +97,6 @@ typedef int sock_t;
#endif
#endif
#ifndef VANILLA_NACL
/* We use libsodium by default. */
#include <sodium.h>
#else
#include <crypto_box.h>
#include <crypto_secretbox.h>
#include <randombytes.h>
#include <crypto_hash_sha256.h>
#define crypto_box_MACBYTES (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES)
#endif
#ifndef crypto_secretbox_MACBYTES
#define crypto_secretbox_MACBYTES (crypto_secretbox_ZEROBYTES - crypto_secretbox_BOXZEROBYTES)
#endif
#ifndef IPV6_ADD_MEMBERSHIP
#ifdef IPV6_JOIN_GROUP
#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
@ -129,6 +114,10 @@ typedef int sock_t;
#define NET_PACKET_HANDSHAKE 16 /* Handshake packet ID. */
#define NET_PACKET_SYNC 17 /* SYNC packet ID. */
#define NET_PACKET_DATA 18 /* Data packet ID. */
#define NET_PACKET_COOKIE_REQUEST 24 /* Cookie request packet */
#define NET_PACKET_COOKIE_RESPONSE 25 /* Cookie response packet */
#define NET_PACKET_CRYPTO_HS 26 /* Crypto handshake packet */
#define NET_PACKET_CRYPTO_DATA 27 /* Crypto data packet */
#define NET_PACKET_CRYPTO 32 /* Encrypted data packet ID. */
#define NET_PACKET_LAN_DISCOVERY 33 /* LAN discovery packet ID. */
#define NET_PACKET_GROUP_CHATS 48 /* Group chats packet ID. */
@ -161,8 +150,11 @@ typedef int sock_t;
#define TOX_PORTRANGE_TO 33545
#define TOX_PORT_DEFAULT TOX_PORTRANGE_FROM
/* TODO: remove padding bytes next time we need to break compatibility with old versions of core. */
/* TCP related */
#define TCP_ONION_FAMILY (AF_INET6 + 1)
#define TCP_INET (AF_INET6 + 2)
#define TCP_INET6 (AF_INET6 + 3)
#define TCP_FAMILY (AF_INET6 + 4)
typedef union __attribute__ ((__packed__))
{
@ -186,8 +178,6 @@ IP6;
typedef struct __attribute__ ((__packed__))
{
uint8_t family;
/* Not used for anything right now. */
uint8_t padding[3];
union {
IP4 ip4;
IP6 ip6;
@ -195,23 +185,19 @@ typedef struct __attribute__ ((__packed__))
}
IP;
typedef union __attribute__ ((__packed__))
typedef struct __attribute__ ((__packed__)) __attribute__((gcc_struct))
{
struct {
IP4 ip;
uint16_t port;
/* Not used for anything right now. */
uint16_t padding;
};
uint8_t uint8[8];
}
IP4_Port;
typedef struct __attribute__ ((__packed__)) IP_Port {
IP ip;
uint16_t port;
uint16_t padding;
} IP_Port;
}
IP_Port;
#define SIZE_IP4 4
#define SIZE_IP6 16
#define SIZE_IP (1 + SIZE_IP6)
#define SIZE_PORT 2
#define SIZE_IPPORT (SIZE_IP + SIZE_PORT)
#define TOX_ENABLE_IPV6_DEFAULT 1
@ -250,6 +236,16 @@ void ip_copy(IP *target, IP *source);
/* copies an ip_port structure */
void ipport_copy(IP_Port *target, IP_Port *source);
/* packs IP into data, writes SIZE_IP bytes to data */
void ip_pack(uint8_t *data, IP *source);
/* unpacks IP from data, reads SIZE_IP bytes from data */
void ip_unpack(IP *target, uint8_t *data);
/* packs IP_Port into data, writes SIZE_IPPORT bytes to data */
void ipport_pack(uint8_t *data, IP_Port *source);
/* unpacks IP_Port from data, reads SIZE_IPPORT bytes to data */
void ipport_unpack(IP_Port *target, uint8_t *data);
/*
* addr_resolve():
* uses getaddrinfo to resolve an address into an IP address
@ -332,6 +328,13 @@ void kill_sock(sock_t sock);
*/
int set_socket_nonblock(sock_t sock);
/* Set socket to not emit SIGPIPE
*
* return 1 on success
* return 0 on failure
*/
int set_socket_nosigpipe(sock_t sock);
/* Set socket to dual (IPv4 + IPv6 socket)
*
* return 1 on success
@ -339,13 +342,8 @@ int set_socket_nonblock(sock_t sock);
*/
int set_socket_dualstack(sock_t sock);
/* return current time in milleseconds since the epoch. */
uint64_t current_time(void);
/* return a random number.
*/
uint32_t random_int(void);
uint64_t random_64b(void);
/* return current monotonic time in milliseconds (ms). */
uint64_t current_time_monotonic(void);
/* Basic network functions: */

View File

@ -26,8 +26,6 @@
#include "onion.h"
#include "util.h"
#define MAX_ONION_SIZE MAX_DATA_SIZE
#define RETURN_1 ONION_RETURN_1
#define RETURN_2 ONION_RETURN_2
#define RETURN_3 ONION_RETURN_3
@ -89,41 +87,43 @@ int create_onion_path(DHT *dht, Onion_Path *new_path, Node_format *nodes)
/* Create and send a onion packet.
*
* Use Onion_Path path to send data of length to dest.
* Maximum length of data is ONION_MAX_DATA_SIZE.
*
* return -1 on failure.
* return 0 on success.
*/
int send_onion_packet(Networking_Core *net, Onion_Path *path, IP_Port dest, uint8_t *data, uint32_t length)
{
if (1 + length + SEND_1 > MAX_ONION_SIZE || length == 0)
if (1 + length + SEND_1 > ONION_MAX_PACKET_SIZE || length == 0)
return -1;
to_net_family(&dest.ip);
uint8_t step1[sizeof(IP_Port) + length];
uint8_t step1[SIZE_IPPORT + length];
memcpy(step1, &dest, sizeof(IP_Port));
memcpy(step1 + sizeof(IP_Port), data, length);
ipport_pack(step1, &dest);
memcpy(step1 + SIZE_IPPORT, data, length);
uint8_t nonce[crypto_box_NONCEBYTES];
random_nonce(nonce);
uint8_t step2[sizeof(IP_Port) + SEND_BASE + length];
memcpy(step2, &path->ip_port3, sizeof(IP_Port));
memcpy(step2 + sizeof(IP_Port), path->public_key3, crypto_box_PUBLICKEYBYTES);
uint8_t step2[SIZE_IPPORT + SEND_BASE + length];
ipport_pack(step2, &path->ip_port3);
memcpy(step2 + SIZE_IPPORT, path->public_key3, crypto_box_PUBLICKEYBYTES);
int len = encrypt_data_fast(path->shared_key3, nonce, step1, sizeof(step1),
step2 + sizeof(IP_Port) + crypto_box_PUBLICKEYBYTES);
int len = encrypt_data_symmetric(path->shared_key3, nonce, step1, sizeof(step1),
step2 + SIZE_IPPORT + crypto_box_PUBLICKEYBYTES);
if ((uint32_t)len != sizeof(IP_Port) + length + crypto_box_MACBYTES)
if ((uint32_t)len != SIZE_IPPORT + length + crypto_box_MACBYTES)
return -1;
uint8_t step3[sizeof(IP_Port) + SEND_BASE * 2 + length];
memcpy(step3, &path->ip_port2, sizeof(IP_Port));
memcpy(step3 + sizeof(IP_Port), path->public_key2, crypto_box_PUBLICKEYBYTES);
len = encrypt_data_fast(path->shared_key2, nonce, step2, sizeof(step2),
step3 + sizeof(IP_Port) + crypto_box_PUBLICKEYBYTES);
uint8_t step3[SIZE_IPPORT + SEND_BASE * 2 + length];
ipport_pack(step3, &path->ip_port2);
memcpy(step3 + SIZE_IPPORT, path->public_key2, crypto_box_PUBLICKEYBYTES);
len = encrypt_data_symmetric(path->shared_key2, nonce, step2, sizeof(step2),
step3 + SIZE_IPPORT + crypto_box_PUBLICKEYBYTES);
if ((uint32_t)len != sizeof(IP_Port) + SEND_BASE + length + crypto_box_MACBYTES)
if ((uint32_t)len != SIZE_IPPORT + SEND_BASE + length + crypto_box_MACBYTES)
return -1;
uint8_t packet[1 + length + SEND_1];
@ -131,10 +131,10 @@ int send_onion_packet(Networking_Core *net, Onion_Path *path, IP_Port dest, uint
memcpy(packet + 1, nonce, crypto_box_NONCEBYTES);
memcpy(packet + 1 + crypto_box_NONCEBYTES, path->public_key1, crypto_box_PUBLICKEYBYTES);
len = encrypt_data_fast(path->shared_key1, nonce, step3, sizeof(step3),
packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES);
len = encrypt_data_symmetric(path->shared_key1, nonce, step3, sizeof(step3),
packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES);
if ((uint32_t)len != sizeof(IP_Port) + SEND_BASE * 2 + length + crypto_box_MACBYTES)
if ((uint32_t)len != SIZE_IPPORT + SEND_BASE * 2 + length + crypto_box_MACBYTES)
return -1;
if ((uint32_t)sendpacket(net, path->ip_port1, packet, sizeof(packet)) != sizeof(packet))
@ -142,13 +142,18 @@ int send_onion_packet(Networking_Core *net, Onion_Path *path, IP_Port dest, uint
return 0;
}
/* Create and send a onion response sent initially to dest with.
* Maximum length of data is ONION_RESPONSE_MAX_DATA_SIZE.
*
* return -1 on failure.
* return 0 on success.
*/
int send_onion_response(Networking_Core *net, IP_Port dest, uint8_t *data, uint32_t length, uint8_t *ret)
{
if (length > ONION_RESPONSE_MAX_DATA_SIZE || length == 0)
return -1;
uint8_t packet[1 + RETURN_3 + length];
packet[0] = NET_PACKET_ONION_RECV_3;
memcpy(packet + 1, ret, RETURN_3);
@ -164,7 +169,7 @@ static int handle_send_initial(void *object, IP_Port source, uint8_t *packet, ui
{
Onion *onion = object;
if (length > MAX_ONION_SIZE)
if (length > ONION_MAX_PACKET_SIZE)
return 1;
if (length <= 1 + SEND_1)
@ -172,11 +177,11 @@ static int handle_send_initial(void *object, IP_Port source, uint8_t *packet, ui
change_symmetric_key(onion);
uint8_t plain[MAX_ONION_SIZE];
uint8_t plain[ONION_MAX_PACKET_SIZE];
uint8_t shared_key[crypto_box_BEFORENMBYTES];
get_shared_key(&onion->shared_keys_1, shared_key, onion->dht->self_secret_key, packet + 1 + crypto_box_NONCEBYTES);
int len = decrypt_data_fast(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES,
length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES), plain);
int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES,
length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES), plain);
if ((uint32_t)len != length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES))
return 1;
@ -187,23 +192,26 @@ static int handle_send_initial(void *object, IP_Port source, uint8_t *packet, ui
int onion_send_1(Onion *onion, uint8_t *plain, uint32_t len, IP_Port source, uint8_t *nonce)
{
IP_Port send_to;
memcpy(&send_to, plain, sizeof(IP_Port));
ipport_unpack(&send_to, plain);
to_host_family(&send_to.ip);
uint8_t data[MAX_ONION_SIZE];
uint8_t ip_port[SIZE_IPPORT];
ipport_pack(ip_port, &source);
uint8_t data[ONION_MAX_PACKET_SIZE];
data[0] = NET_PACKET_ONION_SEND_1;
memcpy(data + 1, nonce, crypto_box_NONCEBYTES);
memcpy(data + 1 + crypto_box_NONCEBYTES, plain + sizeof(IP_Port), len - sizeof(IP_Port));
uint32_t data_len = 1 + crypto_box_NONCEBYTES + (len - sizeof(IP_Port));
memcpy(data + 1 + crypto_box_NONCEBYTES, plain + SIZE_IPPORT, len - SIZE_IPPORT);
uint32_t data_len = 1 + crypto_box_NONCEBYTES + (len - SIZE_IPPORT);
uint8_t *ret_part = data + data_len;
new_nonce(ret_part);
len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, (uint8_t *)&source, sizeof(IP_Port),
ret_part + crypto_secretbox_NONCEBYTES);
len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ip_port, SIZE_IPPORT,
ret_part + crypto_box_NONCEBYTES);
if (len != sizeof(IP_Port) + crypto_secretbox_MACBYTES)
if (len != SIZE_IPPORT + crypto_box_MACBYTES)
return 1;
data_len += crypto_secretbox_NONCEBYTES + len;
data_len += crypto_box_NONCEBYTES + len;
if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len)
return 1;
@ -215,7 +223,7 @@ static int handle_send_1(void *object, IP_Port source, uint8_t *packet, uint32_t
{
Onion *onion = object;
if (length > MAX_ONION_SIZE)
if (length > ONION_MAX_PACKET_SIZE)
return 1;
if (length <= 1 + SEND_2)
@ -223,36 +231,36 @@ static int handle_send_1(void *object, IP_Port source, uint8_t *packet, uint32_t
change_symmetric_key(onion);
uint8_t plain[MAX_ONION_SIZE];
uint8_t plain[ONION_MAX_PACKET_SIZE];
uint8_t shared_key[crypto_box_BEFORENMBYTES];
get_shared_key(&onion->shared_keys_2, shared_key, onion->dht->self_secret_key, packet + 1 + crypto_box_NONCEBYTES);
int len = decrypt_data_fast(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES,
length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_1), plain);
int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES,
length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_1), plain);
if ((uint32_t)len != length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_1 + crypto_box_MACBYTES))
return 1;
IP_Port send_to;
memcpy(&send_to, plain, sizeof(IP_Port));
ipport_unpack(&send_to, plain);
to_host_family(&send_to.ip);
uint8_t data[MAX_ONION_SIZE];
uint8_t data[ONION_MAX_PACKET_SIZE];
data[0] = NET_PACKET_ONION_SEND_2;
memcpy(data + 1, packet + 1, crypto_box_NONCEBYTES);
memcpy(data + 1 + crypto_box_NONCEBYTES, plain + sizeof(IP_Port), len - sizeof(IP_Port));
uint32_t data_len = 1 + crypto_box_NONCEBYTES + (len - sizeof(IP_Port));
memcpy(data + 1 + crypto_box_NONCEBYTES, plain + SIZE_IPPORT, len - SIZE_IPPORT);
uint32_t data_len = 1 + crypto_box_NONCEBYTES + (len - SIZE_IPPORT);
uint8_t *ret_part = data + data_len;
new_nonce(ret_part);
uint8_t ret_data[RETURN_1 + sizeof(IP_Port)];
memcpy(ret_data, &source, sizeof(IP_Port));
memcpy(ret_data + sizeof(IP_Port), packet + (length - RETURN_1), RETURN_1);
uint8_t ret_data[RETURN_1 + SIZE_IPPORT];
ipport_pack(ret_data, &source);
memcpy(ret_data + SIZE_IPPORT, packet + (length - RETURN_1), RETURN_1);
len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ret_data, sizeof(ret_data),
ret_part + crypto_secretbox_NONCEBYTES);
ret_part + crypto_box_NONCEBYTES);
if (len != RETURN_2 - crypto_secretbox_NONCEBYTES)
if (len != RETURN_2 - crypto_box_NONCEBYTES)
return 1;
data_len += crypto_secretbox_NONCEBYTES + len;
data_len += crypto_box_NONCEBYTES + len;
if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len)
return 1;
@ -264,7 +272,7 @@ static int handle_send_2(void *object, IP_Port source, uint8_t *packet, uint32_t
{
Onion *onion = object;
if (length > MAX_ONION_SIZE)
if (length > ONION_MAX_PACKET_SIZE)
return 1;
if (length <= 1 + SEND_3)
@ -272,31 +280,31 @@ static int handle_send_2(void *object, IP_Port source, uint8_t *packet, uint32_t
change_symmetric_key(onion);
uint8_t plain[MAX_ONION_SIZE];
uint8_t plain[ONION_MAX_PACKET_SIZE];
uint8_t shared_key[crypto_box_BEFORENMBYTES];
get_shared_key(&onion->shared_keys_3, shared_key, onion->dht->self_secret_key, packet + 1 + crypto_box_NONCEBYTES);
int len = decrypt_data_fast(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES,
length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_2), plain);
int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES,
length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_2), plain);
if ((uint32_t)len != length - (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + RETURN_2 + crypto_box_MACBYTES))
return 1;
IP_Port send_to;
memcpy(&send_to, plain, sizeof(IP_Port));
ipport_unpack(&send_to, plain);
to_host_family(&send_to.ip);
uint8_t data[MAX_ONION_SIZE];
memcpy(data, plain + sizeof(IP_Port), len - sizeof(IP_Port));
uint32_t data_len = (len - sizeof(IP_Port));
uint8_t *ret_part = data + (len - sizeof(IP_Port));
uint8_t data[ONION_MAX_PACKET_SIZE];
memcpy(data, plain + SIZE_IPPORT, len - SIZE_IPPORT);
uint32_t data_len = (len - SIZE_IPPORT);
uint8_t *ret_part = data + (len - SIZE_IPPORT);
new_nonce(ret_part);
uint8_t ret_data[RETURN_2 + sizeof(IP_Port)];
memcpy(ret_data, &source, sizeof(IP_Port));
memcpy(ret_data + sizeof(IP_Port), packet + (length - RETURN_2), RETURN_2);
uint8_t ret_data[RETURN_2 + SIZE_IPPORT];
ipport_pack(ret_data, &source);
memcpy(ret_data + SIZE_IPPORT, packet + (length - RETURN_2), RETURN_2);
len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ret_data, sizeof(ret_data),
ret_part + crypto_secretbox_NONCEBYTES);
ret_part + crypto_box_NONCEBYTES);
if (len != RETURN_3 - crypto_secretbox_NONCEBYTES)
if (len != RETURN_3 - crypto_box_NONCEBYTES)
return 1;
data_len += RETURN_3;
@ -312,7 +320,7 @@ static int handle_recv_3(void *object, IP_Port source, uint8_t *packet, uint32_t
{
Onion *onion = object;
if (length > MAX_ONION_SIZE)
if (length > ONION_MAX_PACKET_SIZE)
return 1;
if (length <= 1 + RETURN_3)
@ -320,19 +328,19 @@ static int handle_recv_3(void *object, IP_Port source, uint8_t *packet, uint32_t
change_symmetric_key(onion);
uint8_t plain[sizeof(IP_Port) + RETURN_2];
int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_secretbox_NONCEBYTES,
sizeof(IP_Port) + RETURN_2 + crypto_secretbox_MACBYTES, plain);
uint8_t plain[SIZE_IPPORT + RETURN_2];
int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES,
SIZE_IPPORT + RETURN_2 + crypto_box_MACBYTES, plain);
if ((uint32_t)len != sizeof(plain))
return 1;
IP_Port send_to;
memcpy(&send_to, plain, sizeof(IP_Port));
ipport_unpack(&send_to, plain);
uint8_t data[MAX_ONION_SIZE];
uint8_t data[ONION_MAX_PACKET_SIZE];
data[0] = NET_PACKET_ONION_RECV_2;
memcpy(data + 1, plain + sizeof(IP_Port), RETURN_2);
memcpy(data + 1, plain + SIZE_IPPORT, RETURN_2);
memcpy(data + 1 + RETURN_2, packet + 1 + RETURN_3, length - (1 + RETURN_3));
uint32_t data_len = 1 + RETURN_2 + (length - (1 + RETURN_3));
@ -346,7 +354,7 @@ static int handle_recv_2(void *object, IP_Port source, uint8_t *packet, uint32_t
{
Onion *onion = object;
if (length > MAX_ONION_SIZE)
if (length > ONION_MAX_PACKET_SIZE)
return 1;
if (length <= 1 + RETURN_2)
@ -354,19 +362,19 @@ static int handle_recv_2(void *object, IP_Port source, uint8_t *packet, uint32_t
change_symmetric_key(onion);
uint8_t plain[sizeof(IP_Port) + RETURN_1];
int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_secretbox_NONCEBYTES,
sizeof(IP_Port) + RETURN_1 + crypto_secretbox_MACBYTES, plain);
uint8_t plain[SIZE_IPPORT + RETURN_1];
int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES,
SIZE_IPPORT + RETURN_1 + crypto_box_MACBYTES, plain);
if ((uint32_t)len != sizeof(plain))
return 1;
IP_Port send_to;
memcpy(&send_to, plain, sizeof(IP_Port));
ipport_unpack(&send_to, plain);
uint8_t data[MAX_ONION_SIZE];
uint8_t data[ONION_MAX_PACKET_SIZE];
data[0] = NET_PACKET_ONION_RECV_1;
memcpy(data + 1, plain + sizeof(IP_Port), RETURN_1);
memcpy(data + 1, plain + SIZE_IPPORT, RETURN_1);
memcpy(data + 1 + RETURN_1, packet + 1 + RETURN_2, length - (1 + RETURN_2));
uint32_t data_len = 1 + RETURN_1 + (length - (1 + RETURN_2));
@ -380,7 +388,7 @@ static int handle_recv_1(void *object, IP_Port source, uint8_t *packet, uint32_t
{
Onion *onion = object;
if (length > MAX_ONION_SIZE)
if (length > ONION_MAX_PACKET_SIZE)
return 1;
if (length <= 1 + RETURN_1)
@ -388,14 +396,16 @@ static int handle_recv_1(void *object, IP_Port source, uint8_t *packet, uint32_t
change_symmetric_key(onion);
IP_Port send_to;
uint8_t plain[SIZE_IPPORT];
int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES,
SIZE_IPPORT + crypto_box_MACBYTES, plain);
int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + crypto_secretbox_NONCEBYTES,
sizeof(IP_Port) + crypto_secretbox_MACBYTES, (uint8_t *) &send_to);
if ((uint32_t)len != sizeof(IP_Port))
if ((uint32_t)len != SIZE_IPPORT)
return 1;
IP_Port send_to;
ipport_unpack(&send_to, plain);
uint32_t data_len = length - (1 + RETURN_1);
if (onion->recv_1_function && send_to.ip.family != AF_INET && send_to.ip.family != AF_INET6)
@ -424,7 +434,7 @@ Onion *new_onion(DHT *dht)
return NULL;
onion->dht = dht;
onion->net = dht->c->lossless_udp->net;
onion->net = dht->net;
new_symmetric_key(onion->secret_symmetric_key);
onion->timestamp = unix_time();

View File

@ -28,7 +28,7 @@
typedef struct {
DHT *dht;
Networking_Core *net;
uint8_t secret_symmetric_key[crypto_secretbox_KEYBYTES];
uint8_t secret_symmetric_key[crypto_box_KEYBYTES];
uint64_t timestamp;
Shared_Keys shared_keys_1;
@ -39,15 +39,20 @@ typedef struct {
void *callback_object;
} Onion;
#define ONION_RETURN_1 (crypto_secretbox_NONCEBYTES + sizeof(IP_Port) + crypto_secretbox_MACBYTES)
#define ONION_RETURN_2 (crypto_secretbox_NONCEBYTES + sizeof(IP_Port) + crypto_secretbox_MACBYTES + ONION_RETURN_1)
#define ONION_RETURN_3 (crypto_secretbox_NONCEBYTES + sizeof(IP_Port) + crypto_secretbox_MACBYTES + ONION_RETURN_2)
#define ONION_MAX_PACKET_SIZE 1400
#define ONION_SEND_BASE (crypto_box_PUBLICKEYBYTES + sizeof(IP_Port) + crypto_box_MACBYTES)
#define ONION_RETURN_1 (crypto_box_NONCEBYTES + SIZE_IPPORT + crypto_box_MACBYTES)
#define ONION_RETURN_2 (crypto_box_NONCEBYTES + SIZE_IPPORT + crypto_box_MACBYTES + ONION_RETURN_1)
#define ONION_RETURN_3 (crypto_box_NONCEBYTES + SIZE_IPPORT + crypto_box_MACBYTES + ONION_RETURN_2)
#define ONION_SEND_BASE (crypto_box_PUBLICKEYBYTES + SIZE_IPPORT + crypto_box_MACBYTES)
#define ONION_SEND_3 (crypto_box_NONCEBYTES + ONION_SEND_BASE + ONION_RETURN_2)
#define ONION_SEND_2 (crypto_box_NONCEBYTES + ONION_SEND_BASE*2 + ONION_RETURN_1)
#define ONION_SEND_1 (crypto_box_NONCEBYTES + ONION_SEND_BASE*3)
#define ONION_MAX_DATA_SIZE (ONION_MAX_PACKET_SIZE - (ONION_SEND_1 + 1))
#define ONION_RESPONSE_MAX_DATA_SIZE (ONION_MAX_PACKET_SIZE - (1 + ONION_RETURN_3))
typedef struct {
uint8_t shared_key1[crypto_box_BEFORENMBYTES];
uint8_t shared_key2[crypto_box_BEFORENMBYTES];
@ -76,6 +81,7 @@ int create_onion_path(DHT *dht, Onion_Path *new_path, Node_format *nodes);
/* Create and send a onion packet.
*
* Use Onion_Path path to send data of length to dest.
* Maximum length of data is ONION_MAX_DATA_SIZE.
*
* return -1 on failure.
* return 0 on success.
@ -83,6 +89,7 @@ int create_onion_path(DHT *dht, Onion_Path *new_path, Node_format *nodes);
int send_onion_packet(Networking_Core *net, Onion_Path *path, IP_Port dest, uint8_t *data, uint32_t length);
/* Create and send a onion response sent initially to dest with.
* Maximum length of data is ONION_RESPONSE_MAX_DATA_SIZE.
*
* return -1 on failure.
* return 0 on success.

View File

@ -32,7 +32,7 @@
#define ANNOUNCE_REQUEST_SIZE (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_MACBYTES)
#define ANNOUNCE_REQUEST_SIZE_RECV (ANNOUNCE_REQUEST_SIZE + ONION_RETURN_3)
#define DATA_REQUEST_MIN_SIZE (1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES)
#define DATA_REQUEST_MIN_SIZE ONION_DATA_REQUEST_MIN_SIZE
#define DATA_REQUEST_MIN_SIZE_RECV (DATA_REQUEST_MIN_SIZE + ONION_RETURN_3)
/* Create and send an onion announce request packet.
@ -50,14 +50,14 @@
* return 0 on success.
*/
int send_announce_request(Networking_Core *net, Onion_Path *path, Node_format dest, uint8_t *public_key,
uint8_t *secret_key, uint8_t *ping_id, uint8_t *client_id, uint8_t *data_public_key, uint8_t *sendback_data)
uint8_t *secret_key, uint8_t *ping_id, uint8_t *client_id, uint8_t *data_public_key, uint64_t sendback_data)
{
uint8_t plain[ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH];
memcpy(plain, ping_id, ONION_PING_ID_SIZE);
memcpy(plain + ONION_PING_ID_SIZE, client_id, crypto_box_PUBLICKEYBYTES);
memcpy(plain + ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES, data_public_key, crypto_box_PUBLICKEYBYTES);
memcpy(plain + ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES, sendback_data,
ONION_ANNOUNCE_SENDBACK_DATA_LENGTH);
memcpy(plain + ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES, &sendback_data,
sizeof(sendback_data));
uint8_t packet[ANNOUNCE_REQUEST_SIZE];
packet[0] = NET_PACKET_ANNOUNCE_REQUEST;
random_nonce(packet + 1);
@ -90,6 +90,9 @@ int send_announce_request(Networking_Core *net, Onion_Path *path, Node_format de
int send_data_request(Networking_Core *net, Onion_Path *path, IP_Port dest, uint8_t *public_key,
uint8_t *encrypt_public_key, uint8_t *nonce, uint8_t *data, uint16_t length)
{
if ((unsigned int)DATA_REQUEST_MIN_SIZE + length > ONION_MAX_DATA_SIZE)
return -1;
uint8_t packet[DATA_REQUEST_MIN_SIZE + length];
packet[0] = NET_PACKET_ONION_DATA_REQUEST;
memcpy(packet + 1, public_key, crypto_box_PUBLICKEYBYTES);
@ -115,11 +118,11 @@ static void generate_ping_id(Onion_Announce *onion_a, uint64_t time, uint8_t *pu
uint8_t *ping_id)
{
time /= PING_ID_TIMEOUT;
uint8_t data[crypto_secretbox_KEYBYTES + sizeof(time) + crypto_box_PUBLICKEYBYTES + sizeof(ret_ip_port)];
memcpy(data, onion_a->secret_bytes, crypto_secretbox_KEYBYTES);
memcpy(data + crypto_secretbox_KEYBYTES, &time, sizeof(time));
memcpy(data + crypto_secretbox_KEYBYTES + sizeof(time), public_key, crypto_box_PUBLICKEYBYTES);
memcpy(data + crypto_secretbox_KEYBYTES + sizeof(time) + crypto_box_PUBLICKEYBYTES, &ret_ip_port, sizeof(ret_ip_port));
uint8_t data[crypto_box_KEYBYTES + sizeof(time) + crypto_box_PUBLICKEYBYTES + sizeof(ret_ip_port)];
memcpy(data, onion_a->secret_bytes, crypto_box_KEYBYTES);
memcpy(data + crypto_box_KEYBYTES, &time, sizeof(time));
memcpy(data + crypto_box_KEYBYTES + sizeof(time), public_key, crypto_box_PUBLICKEYBYTES);
memcpy(data + crypto_box_KEYBYTES + sizeof(time) + crypto_box_PUBLICKEYBYTES, &ret_ip_port, sizeof(ret_ip_port));
crypto_hash_sha256(ping_id, data, sizeof(data));
}
@ -221,9 +224,9 @@ static int handle_announce_request(void *object, IP_Port source, uint8_t *packet
get_shared_key(&onion_a->shared_keys_recv, shared_key, onion_a->dht->self_secret_key, packet_public_key);
uint8_t plain[ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH];
int len = decrypt_data_fast(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES,
ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH +
crypto_box_MACBYTES, plain);
int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES,
ONION_PING_ID_SIZE + crypto_box_PUBLICKEYBYTES + crypto_box_PUBLICKEYBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH +
crypto_box_MACBYTES, plain);
if ((uint32_t)len != sizeof(plain))
return 1;
@ -247,14 +250,8 @@ static int handle_announce_request(void *object, IP_Port source, uint8_t *packet
/*Respond with a announce response packet*/
Node_format nodes_list[MAX_SENT_NODES];
uint32_t num_nodes = get_close_nodes(onion_a->dht, plain + ONION_PING_ID_SIZE, nodes_list, source.ip.family,
LAN_ip(source.ip) == 0, 1);
uint32_t i;
for (i = 0; i < num_nodes; ++i)
to_net_family(&nodes_list[i].ip_port.ip);
uint32_t num_nodes = get_close_nodes(onion_a->dht, plain + ONION_PING_ID_SIZE, nodes_list, 0, LAN_ip(source.ip) == 0,
1);
uint8_t nonce[crypto_box_NONCEBYTES];
random_nonce(nonce);
@ -274,13 +271,20 @@ static int handle_announce_request(void *object, IP_Port source, uint8_t *packet
}
}
memcpy(pl + 1 + ONION_PING_ID_SIZE, nodes_list, num_nodes * sizeof(Node_format));
int nodes_length = 0;
if (num_nodes != 0) {
nodes_length = pack_nodes(pl + 1 + ONION_PING_ID_SIZE, sizeof(nodes_list), nodes_list, num_nodes);
if (nodes_length <= 0)
return 1;
}
uint8_t data[ONION_ANNOUNCE_RESPONSE_MAX_SIZE];
len = encrypt_data_fast(shared_key, nonce, pl, 1 + ONION_PING_ID_SIZE + num_nodes * sizeof(Node_format),
data + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_NONCEBYTES);
len = encrypt_data_symmetric(shared_key, nonce, pl, 1 + ONION_PING_ID_SIZE + nodes_length,
data + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_NONCEBYTES);
if ((uint32_t)len != 1 + ONION_PING_ID_SIZE + num_nodes * sizeof(Node_format) + crypto_box_MACBYTES)
if (len != 1 + ONION_PING_ID_SIZE + nodes_length + crypto_box_MACBYTES)
return 1;
data[0] = NET_PACKET_ANNOUNCE_RESPONSE;
@ -303,7 +307,7 @@ static int handle_data_request(void *object, IP_Port source, uint8_t *packet, ui
if (length <= DATA_REQUEST_MIN_SIZE_RECV)
return 1;
if (length >= MAX_DATA_SIZE)
if (length > ONION_MAX_PACKET_SIZE)
return 1;
int index = in_entries(onion_a, packet + 1);

View File

@ -29,7 +29,7 @@
#define ONION_ANNOUNCE_TIMEOUT 300
#define ONION_PING_ID_SIZE crypto_hash_sha256_BYTES
#define ONION_ANNOUNCE_SENDBACK_DATA_LENGTH (crypto_secretbox_NONCEBYTES + sizeof(uint32_t) + sizeof(uint64_t) + crypto_box_PUBLICKEYBYTES + sizeof(IP_Port) + crypto_secretbox_MACBYTES)
#define ONION_ANNOUNCE_SENDBACK_DATA_LENGTH (sizeof(uint64_t))
#define ONION_ANNOUNCE_RESPONSE_MIN_SIZE (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_NONCEBYTES + 1 + ONION_PING_ID_SIZE + crypto_box_MACBYTES)
#define ONION_ANNOUNCE_RESPONSE_MAX_SIZE (ONION_ANNOUNCE_RESPONSE_MIN_SIZE + sizeof(Node_format)*MAX_SENT_NODES)
@ -40,6 +40,9 @@
#error announce response packets assume that ONION_PING_ID_SIZE is equal to crypto_box_PUBLICKEYBYTES
#endif
#define ONION_DATA_REQUEST_MIN_SIZE (1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES)
#define MAX_DATA_REQUEST_SIZE (ONION_MAX_DATA_SIZE - ONION_DATA_REQUEST_MIN_SIZE)
typedef struct {
uint8_t public_key[crypto_box_PUBLICKEYBYTES];
IP_Port ret_ip_port;
@ -52,8 +55,8 @@ typedef struct {
DHT *dht;
Networking_Core *net;
Onion_Announce_Entry entries[ONION_ANNOUNCE_MAX_ENTRIES];
/* This is crypto_secretbox_KEYBYTES long just so we can use new_symmetric_key() to fill it */
uint8_t secret_bytes[crypto_secretbox_KEYBYTES];
/* This is crypto_box_KEYBYTES long just so we can use new_symmetric_key() to fill it */
uint8_t secret_bytes[crypto_box_KEYBYTES];
Shared_Keys shared_keys_recv;
} Onion_Announce;
@ -73,7 +76,7 @@ typedef struct {
* return 0 on success.
*/
int send_announce_request(Networking_Core *net, Onion_Path *path, Node_format dest, uint8_t *public_key,
uint8_t *secret_key, uint8_t *ping_id, uint8_t *client_id, uint8_t *data_public_key, uint8_t *sendback_data);
uint8_t *secret_key, uint8_t *ping_id, uint8_t *client_id, uint8_t *data_public_key, uint64_t sendback_data);
/* Create and send an onion data request packet.
*
@ -86,6 +89,8 @@ int send_announce_request(Networking_Core *net, Onion_Path *path, Node_format de
*
* nonce is the nonce to encrypt this packet with
*
* The maximum length of data is MAX_DATA_REQUEST_SIZE.
*
* return -1 on failure.
* return 0 on success.
*/

View File

@ -28,8 +28,37 @@
#include "util.h"
#include "LAN_discovery.h"
/* defines for the array size and
timeout for onion announce packets. */
#define ANNOUNCE_ARRAY_SIZE 256
#define ANNOUNCE_TIMEOUT 10
/*
* return -1 if nodes are suitable for creating a new path.
* return path number of already existing similar path if one already exists.
*/
static int is_path_used(Onion_Client_Paths *onion_paths, Node_format *nodes)
{
uint32_t i;
for (i = 0; i < NUMBER_ONION_PATHS; ++i) {
if (is_timeout(onion_paths->last_path_success[i], ONION_PATH_TIMEOUT)) {
continue;
}
if (is_timeout(onion_paths->path_creation_time[i], ONION_PATH_MAX_LIFETIME)) {
continue;
}
if (ipport_equal(&onion_paths->paths[i].ip_port1, &nodes[0].ip_port)) {
return i;
}
}
return -1;
}
/* Create a new path or use an old suitable one (if pathnum is valid)
* or a rondom one from onion_paths.
*
@ -51,11 +80,17 @@ static int random_path(DHT *dht, Onion_Client_Paths *onion_paths, uint32_t pathn
if (random_nodes_path(dht, nodes, 3) != 3)
return -1;
if (create_onion_path(dht, &onion_paths->paths[pathnum], nodes) == -1)
return -1;
int n = is_path_used(onion_paths, nodes);
onion_paths->last_path_success[pathnum] = unix_time() + ONION_PATH_FIRST_TIMEOUT - ONION_PATH_TIMEOUT;
onion_paths->path_creation_time[pathnum] = unix_time();
if (n == -1) {
if (create_onion_path(dht, &onion_paths->paths[pathnum], nodes) == -1)
return -1;
onion_paths->last_path_success[pathnum] = unix_time() + ONION_PATH_FIRST_TIMEOUT - ONION_PATH_TIMEOUT;
onion_paths->path_creation_time[pathnum] = unix_time();
} else {
pathnum = n;
}
}
memcpy(path, &onion_paths->paths[pathnum], sizeof(Onion_Path));
@ -105,20 +140,15 @@ static uint32_t set_path_timeouts(Onion_Client *onion_c, uint32_t num, IP_Port s
* return 0 on success
*
*/
static int new_sendback(Onion_Client *onion_c, uint32_t num, uint8_t *public_key, IP_Port ip_port, uint8_t *sendback)
static int new_sendback(Onion_Client *onion_c, uint32_t num, uint8_t *public_key, IP_Port ip_port, uint64_t *sendback)
{
uint8_t plain[sizeof(uint32_t) + sizeof(uint64_t) + crypto_box_PUBLICKEYBYTES + sizeof(IP_Port)];
uint64_t time = unix_time();
random_nonce(sendback);
memcpy(plain, &num, sizeof(uint32_t));
memcpy(plain + sizeof(uint32_t), &time, sizeof(uint64_t));
memcpy(plain + sizeof(uint32_t) + sizeof(uint64_t), public_key, crypto_box_PUBLICKEYBYTES);
memcpy(plain + sizeof(uint32_t) + sizeof(uint64_t) + crypto_box_PUBLICKEYBYTES, &ip_port, sizeof(IP_Port));
uint8_t data[sizeof(uint32_t) + crypto_box_PUBLICKEYBYTES + sizeof(IP_Port)];
memcpy(data, &num, sizeof(uint32_t));
memcpy(data + sizeof(uint32_t), public_key, crypto_box_PUBLICKEYBYTES);
memcpy(data + sizeof(uint32_t) + crypto_box_PUBLICKEYBYTES, &ip_port, sizeof(IP_Port));
*sendback = ping_array_add(&onion_c->announce_ping_array, data, sizeof(data));
int len = encrypt_data_symmetric(onion_c->secret_symmetric_key, sendback, plain, sizeof(plain),
sendback + crypto_secretbox_NONCEBYTES);
if ((uint32_t)len + crypto_secretbox_NONCEBYTES != ONION_ANNOUNCE_SENDBACK_DATA_LENGTH)
if (*sendback == 0)
return -1;
return 0;
@ -136,24 +166,17 @@ static int new_sendback(Onion_Client *onion_c, uint32_t num, uint8_t *public_key
*/
static uint32_t check_sendback(Onion_Client *onion_c, uint8_t *sendback, uint8_t *ret_pubkey, IP_Port *ret_ip_port)
{
uint8_t plain[sizeof(uint32_t) + sizeof(uint64_t) + crypto_box_PUBLICKEYBYTES + sizeof(IP_Port)];
int len = decrypt_data_symmetric(onion_c->secret_symmetric_key, sendback, sendback + crypto_secretbox_NONCEBYTES,
ONION_ANNOUNCE_SENDBACK_DATA_LENGTH - crypto_secretbox_NONCEBYTES, plain);
uint64_t sback;
memcpy(&sback, sendback, sizeof(uint64_t));
uint8_t data[sizeof(uint32_t) + crypto_box_PUBLICKEYBYTES + sizeof(IP_Port)];
if ((uint32_t)len != sizeof(plain))
if (ping_array_check(data, sizeof(data), &onion_c->announce_ping_array, sback) != sizeof(data))
return ~0;
uint64_t timestamp;
memcpy(&timestamp, plain + sizeof(uint32_t), sizeof(uint64_t));
uint64_t temp_time = unix_time();
if (timestamp + ANNOUNCE_TIMEOUT < temp_time || temp_time < timestamp)
return ~0;
memcpy(ret_pubkey, plain + sizeof(uint32_t) + sizeof(uint64_t), crypto_box_PUBLICKEYBYTES);
memcpy(ret_ip_port, plain + sizeof(uint32_t) + sizeof(uint64_t) + crypto_box_PUBLICKEYBYTES, sizeof(IP_Port));
memcpy(ret_pubkey, data + sizeof(uint32_t), crypto_box_PUBLICKEYBYTES);
memcpy(ret_ip_port, data + sizeof(uint32_t) + crypto_box_PUBLICKEYBYTES, sizeof(IP_Port));
uint32_t num;
memcpy(&num, plain, sizeof(uint32_t));
memcpy(&num, data, sizeof(uint32_t));
return num;
}
@ -163,9 +186,9 @@ static int client_send_announce_request(Onion_Client *onion_c, uint32_t num, IP_
if (num > onion_c->num_friends)
return -1;
uint8_t sendback[ONION_ANNOUNCE_SENDBACK_DATA_LENGTH];
uint64_t sendback;
if (new_sendback(onion_c, num, dest_pubkey, dest, sendback) == -1)
if (new_sendback(onion_c, num, dest_pubkey, dest, &sendback) == -1)
return -1;
uint8_t zero_ping_id[ONION_PING_ID_SIZE] = {0};
@ -183,9 +206,9 @@ static int client_send_announce_request(Onion_Client *onion_c, uint32_t num, IP_
if (random_path(onion_c->dht, &onion_c->onion_paths, pathnum, &path) == -1)
return -1;
return send_announce_request(onion_c->net, &path, dest_node, onion_c->dht->c->self_public_key,
onion_c->dht->c->self_secret_key, ping_id,
onion_c->dht->c->self_public_key, onion_c->temp_public_key, sendback);
return send_announce_request(onion_c->net, &path, dest_node, onion_c->c->self_public_key,
onion_c->c->self_secret_key, ping_id,
onion_c->c->self_public_key, onion_c->temp_public_key, sendback);
} else {
if (random_path(onion_c->dht, &onion_c->friends_list[num - 1].onion_paths, pathnum, &path) == -1)
return -1;
@ -236,7 +259,7 @@ static int client_add_to_list(Onion_Client *onion_c, uint32_t num, uint8_t *publ
if (num == 0) {
list_nodes = onion_c->clients_announce_list;
reference_id = onion_c->dht->c->self_public_key;
reference_id = onion_c->c->self_public_key;
if (is_stored && memcmp(pingid_or_key, onion_c->temp_public_key, crypto_box_PUBLICKEYBYTES) != 0) {
is_stored = 0;
@ -253,16 +276,9 @@ static int client_add_to_list(Onion_Client *onion_c, uint32_t num, uint8_t *publ
int index = -1;
uint32_t i;
for (i = 0; i < MAX_ONION_CLIENTS; ++i) {
if (is_timeout(list_nodes[i].timestamp, ONION_NODE_TIMEOUT)
|| id_closest(reference_id, list_nodes[i].client_id, public_key) == 2) {
index = i;
if (i != 0)
break;
} else {
break;
}
if (is_timeout(list_nodes[0].timestamp, ONION_NODE_TIMEOUT)
|| id_closest(reference_id, list_nodes[0].client_id, public_key) == 2) {
index = 0;
}
for (i = 0; i < MAX_ONION_CLIENTS; ++i) {
@ -286,7 +302,7 @@ static int client_add_to_list(Onion_Client *onion_c, uint32_t num, uint8_t *publ
list_nodes[index].is_stored = is_stored;
list_nodes[index].timestamp = unix_time();
list_nodes[index].last_pinged = unix_time();
list_nodes[index].last_pinged = 0;
list_nodes[index].path_used = set_path_timeouts(onion_c, num, source);
return 0;
}
@ -318,21 +334,18 @@ static int client_ping_nodes(Onion_Client *onion_c, uint32_t num, Node_format *n
Onion_Node *list_nodes = NULL;
uint8_t *reference_id = NULL;
uint32_t *ping_nodes_sent_second = NULL;
Last_Pinged *last_pinged = NULL;
uint8_t *last_pinged_index = NULL;
if (num == 0) {
list_nodes = onion_c->clients_announce_list;
reference_id = onion_c->dht->c->self_public_key;
ping_nodes_sent_second = &onion_c->ping_nodes_sent_second;
reference_id = onion_c->c->self_public_key;
last_pinged = onion_c->last_pinged;
last_pinged_index = &onion_c->last_pinged_index;
} else {
list_nodes = onion_c->friends_list[num - 1].clients_list;
reference_id = onion_c->friends_list[num - 1].real_client_id;
ping_nodes_sent_second = &onion_c->friends_list[num - 1].ping_nodes_sent_second;
last_pinged = onion_c->friends_list[num - 1].last_pinged;
last_pinged_index = &onion_c->friends_list[num - 1].last_pinged_index;
}
@ -342,11 +355,6 @@ static int client_ping_nodes(Onion_Client *onion_c, uint32_t num, Node_format *n
for (i = 0; i < num_nodes; ++i) {
if (*ping_nodes_sent_second > MAX_PING_NODES_SECOND_PEER)
return 0;
to_host_family(&nodes[i].ip_port.ip);
if (!lan_ips_accepted)
if (LAN_ip(nodes[i].ip_port.ip) == 0)
continue;
@ -361,8 +369,7 @@ static int client_ping_nodes(Onion_Client *onion_c, uint32_t num, Node_format *n
}
if (j == MAX_ONION_CLIENTS && good_to_ping(last_pinged, last_pinged_index, nodes[i].client_id)) {
if (client_send_announce_request(onion_c, num, nodes[i].ip_port, nodes[i].client_id, NULL, ~0) == 0)
++*ping_nodes_sent_second;
client_send_announce_request(onion_c, num, nodes[i].ip_port, nodes[i].client_id, NULL, ~0);
}
}
}
@ -377,10 +384,7 @@ static int handle_announce_response(void *object, IP_Port source, uint8_t *packe
if (length < ONION_ANNOUNCE_RESPONSE_MIN_SIZE || length > ONION_ANNOUNCE_RESPONSE_MAX_SIZE)
return 1;
if ((length - ONION_ANNOUNCE_RESPONSE_MIN_SIZE) % sizeof(Node_format) != 0)
return 1;
uint16_t num_nodes = (length - ONION_ANNOUNCE_RESPONSE_MIN_SIZE) / sizeof(Node_format);
uint16_t len_nodes = length - ONION_ANNOUNCE_RESPONSE_MIN_SIZE;
uint8_t public_key[crypto_box_PUBLICKEYBYTES];
IP_Port ip_port;
@ -389,11 +393,11 @@ static int handle_announce_response(void *object, IP_Port source, uint8_t *packe
if (num > onion_c->num_friends)
return 1;
uint8_t plain[1 + ONION_PING_ID_SIZE + num_nodes * sizeof(Node_format)];
uint8_t plain[1 + ONION_PING_ID_SIZE + len_nodes];
int len = -1;
if (num == 0) {
len = decrypt_data(public_key, onion_c->dht->c->self_secret_key, packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH,
len = decrypt_data(public_key, onion_c->c->self_secret_key, packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH,
packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_NONCEBYTES,
length - (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_NONCEBYTES), plain);
} else {
@ -409,20 +413,24 @@ static int handle_announce_response(void *object, IP_Port source, uint8_t *packe
if ((uint32_t)len != sizeof(plain))
return 1;
if (client_add_to_list(onion_c, num, public_key, ip_port, plain[0], plain + 1, source) == -1)
return 1;
Node_format nodes[MAX_SENT_NODES];
memcpy(nodes, plain + 1 + ONION_PING_ID_SIZE, num_nodes * sizeof(Node_format));
if (len_nodes != 0) {
Node_format nodes[MAX_SENT_NODES];
int num_nodes = unpack_nodes(nodes, MAX_SENT_NODES, 0, plain + 1 + ONION_PING_ID_SIZE, len_nodes, 0);
if (client_ping_nodes(onion_c, num, nodes, num_nodes, source) == -1)
return 1;
if (num_nodes <= 0)
return 1;
if (client_ping_nodes(onion_c, num, nodes, num_nodes, source) == -1)
return 1;
}
return 0;
}
#define DATA_IN_RESPONSE_MIN_SIZE (crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES)
#define DATA_IN_RESPONSE_MIN_SIZE ONION_DATA_IN_RESPONSE_MIN_SIZE
static int handle_data_response(void *object, IP_Port source, uint8_t *packet, uint32_t length)
{
@ -431,7 +439,7 @@ static int handle_data_response(void *object, IP_Port source, uint8_t *packet, u
if (length <= (ONION_DATA_RESPONSE_MIN_SIZE + DATA_IN_RESPONSE_MIN_SIZE))
return 1;
if (length > MAX_DATA_SIZE)
if (length > MAX_DATA_REQUEST_SIZE)
return 1;
uint8_t temp_plain[length - ONION_DATA_RESPONSE_MIN_SIZE];
@ -443,7 +451,7 @@ static int handle_data_response(void *object, IP_Port source, uint8_t *packet, u
return 1;
uint8_t plain[sizeof(temp_plain) - DATA_IN_RESPONSE_MIN_SIZE];
len = decrypt_data(temp_plain, onion_c->dht->c->self_secret_key, packet + 1, temp_plain + crypto_box_PUBLICKEYBYTES,
len = decrypt_data(temp_plain, onion_c->c->self_secret_key, packet + 1, temp_plain + crypto_box_PUBLICKEYBYTES,
sizeof(temp_plain) - crypto_box_PUBLICKEYBYTES, plain);
if ((uint32_t)len != sizeof(plain))
@ -469,9 +477,6 @@ static int handle_fakeid_announce(void *object, uint8_t *source_pubkey, uint8_t
if (length > FAKEID_DATA_MAX_LENGTH)
return 1;
if ((length - FAKEID_DATA_MIN_LENGTH) % sizeof(Node_format) != 0)
return 1;
int friend_num = onion_friend_num(onion_c, source_pubkey);
if (friend_num == -1)
@ -485,37 +490,42 @@ static int handle_fakeid_announce(void *object, uint8_t *source_pubkey, uint8_t
return 1;
onion_c->friends_list[friend_num].last_noreplay = no_replay;
onion_set_friend_DHT_pubkey(onion_c, friend_num, data + 1 + sizeof(uint64_t), current_time_monotonic());
onion_c->friends_list[friend_num].last_seen = unix_time();
if (memcmp(data + 1 + sizeof(uint64_t), onion_c->friends_list[friend_num].fake_client_id,
crypto_box_PUBLICKEYBYTES) != 0) {
DHT_delfriend(onion_c->dht, onion_c->friends_list[friend_num].fake_client_id);
uint16_t len_nodes = length - FAKEID_DATA_MIN_LENGTH;
onion_c->friends_list[friend_num].last_seen = unix_time();
if (len_nodes != 0) {
Node_format nodes[MAX_SENT_NODES];
int num_nodes = unpack_nodes(nodes, MAX_SENT_NODES, 0, data + 1 + sizeof(uint64_t) + crypto_box_PUBLICKEYBYTES,
len_nodes, 1);
if (DHT_addfriend(onion_c->dht, data + 1 + sizeof(uint64_t)) == 1) {
if (num_nodes <= 0)
return 1;
int i;
for (i = 0; i < num_nodes; ++i) {
uint8_t family = nodes[i].ip_port.ip.family;
if (family == AF_INET || family == AF_INET6) {
DHT_getnodes(onion_c->dht, &nodes[i].ip_port, nodes[i].client_id, onion_c->friends_list[friend_num].fake_client_id);
} else if (family == TCP_INET || family == TCP_INET6) {
if (onion_c->friends_list[friend_num].tcp_relay_node_callback) {
void *obj = onion_c->friends_list[friend_num].tcp_relay_node_callback_object;
uint32_t number = onion_c->friends_list[friend_num].tcp_relay_node_callback_number;
onion_c->friends_list[friend_num].tcp_relay_node_callback(obj, number, nodes[i].ip_port, nodes[i].client_id);
}
}
}
onion_c->friends_list[friend_num].is_fake_clientid = 1;
memcpy(onion_c->friends_list[friend_num].fake_client_id, data + 1 + sizeof(uint64_t), crypto_box_PUBLICKEYBYTES);
}
uint16_t num_nodes = (length - FAKEID_DATA_MIN_LENGTH) / sizeof(Node_format);
Node_format nodes[num_nodes];
memcpy(nodes, data + 1 + sizeof(uint64_t) + crypto_box_PUBLICKEYBYTES, sizeof(nodes));
uint32_t i;
for (i = 0; i < num_nodes; ++i) {
to_host_family(&nodes[i].ip_port.ip);
DHT_getnodes(onion_c->dht, &nodes[i].ip_port, nodes[i].client_id, onion_c->friends_list[friend_num].fake_client_id);
}
return 0;
}
/* Send data of length length to friendnum.
* This data will be recieved by the friend using the Onion_Data_Handlers callbacks.
* This data will be received by the friend using the Onion_Data_Handlers callbacks.
*
* Even if this function succeeds, the friend might not recieve any data.
* Even if this function succeeds, the friend might not receive any data.
*
* return the number of packets sent on success
* return -1 on failure.
@ -525,7 +535,7 @@ int send_onion_data(Onion_Client *onion_c, int friend_num, uint8_t *data, uint32
if ((uint32_t)friend_num >= onion_c->num_friends)
return -1;
if (length + DATA_IN_RESPONSE_MIN_SIZE + ONION_DATA_RESPONSE_MIN_SIZE + ONION_SEND_1 > MAX_DATA_SIZE)
if (length + DATA_IN_RESPONSE_MIN_SIZE > MAX_DATA_REQUEST_SIZE)
return -1;
if (length == 0)
@ -535,8 +545,8 @@ int send_onion_data(Onion_Client *onion_c, int friend_num, uint8_t *data, uint32
random_nonce(nonce);
uint8_t packet[DATA_IN_RESPONSE_MIN_SIZE + length];
memcpy(packet, onion_c->dht->c->self_public_key, crypto_box_PUBLICKEYBYTES);
int len = encrypt_data(onion_c->friends_list[friend_num].real_client_id, onion_c->dht->c->self_secret_key, nonce, data,
memcpy(packet, onion_c->c->self_public_key, crypto_box_PUBLICKEYBYTES);
int len = encrypt_data(onion_c->friends_list[friend_num].real_client_id, onion_c->c->self_secret_key, nonce, data,
length, packet + crypto_box_PUBLICKEYBYTES);
if ((uint32_t)len + crypto_box_PUBLICKEYBYTES != sizeof(packet))
@ -578,7 +588,7 @@ int send_onion_data(Onion_Client *onion_c, int friend_num, uint8_t *data, uint32
/* Try to send the fakeid via the DHT instead of onion
*
* Even if this function succeeds, the friend might not recieve any data.
* Even if this function succeeds, the friend might not receive any data.
*
* return the number of packets sent on success
* return -1 on failure.
@ -595,15 +605,15 @@ static int send_dht_fakeid(Onion_Client *onion_c, int friend_num, uint8_t *data,
new_nonce(nonce);
uint8_t temp[DATA_IN_RESPONSE_MIN_SIZE + crypto_box_NONCEBYTES + length];
memcpy(temp, onion_c->dht->c->self_public_key, crypto_box_PUBLICKEYBYTES);
memcpy(temp, onion_c->c->self_public_key, crypto_box_PUBLICKEYBYTES);
memcpy(temp + crypto_box_PUBLICKEYBYTES, nonce, crypto_box_NONCEBYTES);
int len = encrypt_data(onion_c->friends_list[friend_num].real_client_id, onion_c->dht->c->self_secret_key, nonce, data,
int len = encrypt_data(onion_c->friends_list[friend_num].real_client_id, onion_c->c->self_secret_key, nonce, data,
length, temp + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);
if ((uint32_t)len + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES != sizeof(temp))
return -1;
uint8_t packet[MAX_DATA_SIZE];
uint8_t packet[MAX_CRYPTO_REQUEST_SIZE];
len = create_request(onion_c->dht->self_public_key, onion_c->dht->self_secret_key, packet,
onion_c->friends_list[friend_num].fake_client_id, temp, sizeof(temp), FAKEID_DATA_ID);
@ -624,14 +634,14 @@ static int handle_dht_fakeid(void *object, IP_Port source, uint8_t *source_pubke
return 1;
uint8_t plain[FAKEID_DATA_MAX_LENGTH];
int len = decrypt_data(packet, onion_c->dht->c->self_secret_key, packet + crypto_box_PUBLICKEYBYTES,
int len = decrypt_data(packet, onion_c->c->self_secret_key, packet + crypto_box_PUBLICKEYBYTES,
packet + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES,
length - (crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES), plain);
if ((uint32_t)len != length - (DATA_IN_RESPONSE_MIN_SIZE + crypto_box_NONCEBYTES))
return 1;
if (memcpy(source_pubkey, packet, crypto_box_PUBLICKEYBYTES) != 0)
if (memcmp(source_pubkey, plain + 1 + sizeof(uint64_t), crypto_box_PUBLICKEYBYTES) != 0)
return 1;
return handle_fakeid_announce(onion_c, packet, plain, len);
@ -657,20 +667,26 @@ static int send_fakeid_announce(Onion_Client *onion_c, uint16_t friend_num, uint
memcpy(data + 1, &no_replay, sizeof(no_replay));
memcpy(data + 1 + sizeof(uint64_t), onion_c->dht->self_public_key, crypto_box_PUBLICKEYBYTES);
Node_format nodes[MAX_SENT_NODES];
uint16_t num_nodes = closelist_nodes(onion_c->dht, nodes, MAX_SENT_NODES);
uint32_t i;
uint16_t num_relays = copy_connected_tcp_relays(onion_c->c, nodes, (MAX_SENT_NODES / 2));
uint16_t num_nodes = closelist_nodes(onion_c->dht, &nodes[num_relays], MAX_SENT_NODES - num_relays);
num_nodes += num_relays;
int nodes_len = 0;
for (i = 0; i < num_nodes; ++i)
to_net_family(&nodes[i].ip_port.ip);
if (num_nodes != 0) {
nodes_len = pack_nodes(data + FAKEID_DATA_MIN_LENGTH, FAKEID_DATA_MAX_LENGTH - FAKEID_DATA_MIN_LENGTH, nodes,
num_nodes);
if (nodes_len <= 0)
return -1;
}
memcpy(data + FAKEID_DATA_MIN_LENGTH, nodes, sizeof(Node_format) * num_nodes);
int num1 = -1, num2 = -1;
if (onion_dht_both != 1)
num1 = send_onion_data(onion_c, friend_num, data, FAKEID_DATA_MIN_LENGTH + sizeof(Node_format) * num_nodes);
num1 = send_onion_data(onion_c, friend_num, data, FAKEID_DATA_MIN_LENGTH + nodes_len);
if (onion_dht_both != 0)
num2 = send_dht_fakeid(onion_c, friend_num, data, FAKEID_DATA_MIN_LENGTH + sizeof(Node_format) * num_nodes);
num2 = send_dht_fakeid(onion_c, friend_num, data, FAKEID_DATA_MIN_LENGTH + nodes_len);
if (num1 == -1)
return num2;
@ -788,6 +804,84 @@ int onion_delfriend(Onion_Client *onion_c, int friend_num)
return friend_num;
}
/* Set the function for this friend that will be callbacked with object and number
* when that friends gives us one of the TCP relays he is connected to.
*
* object and number will be passed as argument to this function.
*
* return -1 on failure.
* return 0 on success.
*/
int recv_tcp_relay_handler(Onion_Client *onion_c, int friend_num, int (*tcp_relay_node_callback)(void *object,
uint32_t number, IP_Port ip_port, uint8_t *public_key), void *object, uint32_t number)
{
if ((uint32_t)friend_num >= onion_c->num_friends)
return -1;
onion_c->friends_list[friend_num].tcp_relay_node_callback = tcp_relay_node_callback;
onion_c->friends_list[friend_num].tcp_relay_node_callback_object = object;
onion_c->friends_list[friend_num].tcp_relay_node_callback_number = number;
return 0;
}
/* Set a friends DHT public key.
* timestamp is the time (current_time_monotonic()) at which the key was last confirmed belonging to
* the other peer.
*
* return -1 on failure.
* return 0 on success.
*/
int onion_set_friend_DHT_pubkey(Onion_Client *onion_c, int friend_num, uint8_t *dht_key, uint64_t timestamp)
{
if ((uint32_t)friend_num >= onion_c->num_friends)
return -1;
if (onion_c->friends_list[friend_num].status == 0)
return -1;
if (onion_c->friends_list[friend_num].fake_client_id_timestamp >= timestamp)
return -1;
if (onion_c->friends_list[friend_num].is_fake_clientid) {
if (memcmp(dht_key, onion_c->friends_list[friend_num].fake_client_id, crypto_box_PUBLICKEYBYTES) == 0) {
return -1;
}
DHT_delfriend(onion_c->dht, onion_c->friends_list[friend_num].fake_client_id);
}
if (DHT_addfriend(onion_c->dht, dht_key) == 1) {
return -1;
}
onion_c->friends_list[friend_num].last_seen = unix_time();
onion_c->friends_list[friend_num].is_fake_clientid = 1;
onion_c->friends_list[friend_num].fake_client_id_timestamp = timestamp;
memcpy(onion_c->friends_list[friend_num].fake_client_id, dht_key, crypto_box_PUBLICKEYBYTES);
return 0;
}
/* Copy friends DHT public key into dht_key.
*
* return 0 on failure (no key copied).
* return timestamp on success (key copied).
*/
uint64_t onion_getfriend_DHT_pubkey(Onion_Client *onion_c, int friend_num, uint8_t *dht_key)
{
if ((uint32_t)friend_num >= onion_c->num_friends)
return 0;
if (onion_c->friends_list[friend_num].status == 0)
return 0;
if (!onion_c->friends_list[friend_num].is_fake_clientid)
return 0;
memcpy(dht_key, onion_c->friends_list[friend_num].fake_client_id, crypto_box_PUBLICKEYBYTES);
return onion_c->friends_list[friend_num].fake_client_id_timestamp;
}
/* Get the ip of friend friendnum and put it in ip_port
*
* return -1, -- if client_id does NOT refer to a friend
@ -797,18 +891,15 @@ int onion_delfriend(Onion_Client *onion_c, int friend_num)
*/
int onion_getfriendip(Onion_Client *onion_c, int friend_num, IP_Port *ip_port)
{
if ((uint32_t)friend_num >= onion_c->num_friends)
uint8_t dht_public_key[crypto_box_PUBLICKEYBYTES];
if (onion_getfriend_DHT_pubkey(onion_c, friend_num, dht_public_key) == 0)
return -1;
if (onion_c->friends_list[friend_num].status == 0)
return -1;
if (!onion_c->friends_list[friend_num].is_fake_clientid)
return -1;
return DHT_getfriendip(onion_c->dht, onion_c->friends_list[friend_num].fake_client_id, ip_port);
return DHT_getfriendip(onion_c->dht, dht_public_key, ip_port);
}
/* Set if friend is online or not.
* NOTE: This function is there and should be used so that we don't send useless packets to the friend if he is online.
*
@ -856,6 +947,11 @@ static void do_friend(Onion_Client *onion_c, uint16_t friendnum)
++count;
if (list_nodes[i].last_pinged == 0) {
list_nodes[i].last_pinged = unix_time();
continue;
}
if (is_timeout(list_nodes[i].last_pinged, ANNOUNCE_FRIEND)) {
if (client_send_announce_request(onion_c, friendnum + 1, list_nodes[i].ip_port, list_nodes[i].client_id, 0, ~0) == 0) {
list_nodes[i].last_pinged = unix_time();
@ -924,6 +1020,13 @@ static void do_announce(Onion_Client *onion_c)
continue;
++count;
/* Don't announce ourselves the first time this is run to new peers */
if (list_nodes[i].last_pinged == 0) {
list_nodes[i].last_pinged = 1;
continue;
}
uint32_t interval = ANNOUNCE_INTERVAL_NOT_ANNOUNCED;
if (list_nodes[i].is_stored) {
@ -941,7 +1044,7 @@ static void do_announce(Onion_Client *onion_c)
if (count != MAX_ONION_CLIENTS) {
if (count < (uint32_t)rand() % MAX_ONION_CLIENTS) {
Node_format nodes_list[MAX_SENT_NODES];
uint32_t num_nodes = get_close_nodes(onion_c->dht, onion_c->dht->c->self_public_key, nodes_list,
uint32_t num_nodes = get_close_nodes(onion_c->dht, onion_c->c->self_public_key, nodes_list,
rand() % 2 ? AF_INET : AF_INET6, 1, 0);
for (i = 0; i < num_nodes; ++i) {
@ -963,16 +1066,14 @@ void do_onion_client(Onion_Client *onion_c)
for (i = 0; i < onion_c->num_friends; ++i) {
do_friend(onion_c, i);
cleanup_friend(onion_c, i);
onion_c->friends_list[i].ping_nodes_sent_second = 0;
}
onion_c->ping_nodes_sent_second = 0;
onion_c->last_run = unix_time();
}
Onion_Client *new_onion_client(DHT *dht)
Onion_Client *new_onion_client(Net_Crypto *c)
{
if (dht == NULL)
if (c == NULL)
return NULL;
Onion_Client *onion_c = calloc(1, sizeof(Onion_Client));
@ -980,14 +1081,20 @@ Onion_Client *new_onion_client(DHT *dht)
if (onion_c == NULL)
return NULL;
onion_c->dht = dht;
onion_c->net = dht->c->lossless_udp->net;
if (ping_array_init(&onion_c->announce_ping_array, ANNOUNCE_ARRAY_SIZE, ANNOUNCE_TIMEOUT) != 0) {
free(onion_c);
return NULL;
}
onion_c->dht = c->dht;
onion_c->net = c->dht->net;
onion_c->c = c;
new_symmetric_key(onion_c->secret_symmetric_key);
crypto_box_keypair(onion_c->temp_public_key, onion_c->temp_secret_key);
networking_registerhandler(onion_c->net, NET_PACKET_ANNOUNCE_RESPONSE, &handle_announce_response, onion_c);
networking_registerhandler(onion_c->net, NET_PACKET_ONION_DATA_RESPONSE, &handle_data_response, onion_c);
oniondata_registerhandler(onion_c, FAKEID_DATA_ID, &handle_fakeid_announce, onion_c);
cryptopacket_registerhandler(onion_c->dht->c, FAKEID_DATA_ID, &handle_dht_fakeid, onion_c);
cryptopacket_registerhandler(onion_c->dht, FAKEID_DATA_ID, &handle_dht_fakeid, onion_c);
return onion_c;
}
@ -997,11 +1104,12 @@ void kill_onion_client(Onion_Client *onion_c)
if (onion_c == NULL)
return;
ping_array_free_all(&onion_c->announce_ping_array);
realloc_onion_friends(onion_c, 0);
networking_registerhandler(onion_c->net, NET_PACKET_ANNOUNCE_RESPONSE, NULL, NULL);
networking_registerhandler(onion_c->net, NET_PACKET_ONION_DATA_RESPONSE, NULL, NULL);
oniondata_registerhandler(onion_c, FAKEID_DATA_ID, NULL, NULL);
cryptopacket_registerhandler(onion_c->dht->c, FAKEID_DATA_ID, NULL, NULL);
cryptopacket_registerhandler(onion_c->dht, FAKEID_DATA_ID, NULL, NULL);
memset(onion_c, 0, sizeof(Onion_Client));
free(onion_c);
}

View File

@ -25,6 +25,8 @@
#define ONION_CLIENT_H
#include "onion_announce.h"
#include "net_crypto.h"
#include "ping_array.h"
#define MAX_ONION_CLIENTS 8
#define ONION_NODE_PING_INTERVAL 30
@ -42,11 +44,6 @@
#define ONION_PATH_TIMEOUT 30
#define ONION_PATH_MAX_LIFETIME 600
/* A cheap way of making it take less bandwidth at startup:
by limiting the number of ping packets we can send per
second per peer. */
#define MAX_PING_NODES_SECOND_PEER 5
#define MAX_STORED_PINGED_NODES 9
#define MIN_NODE_PING_TIME 10
@ -80,6 +77,7 @@ typedef struct {
uint8_t is_online; /* Set by the onion_set_friend_status function. */
uint8_t is_fake_clientid; /* 0 if we don't know the fake client id of the other 1 if we do. */
uint64_t fake_client_id_timestamp;
uint8_t fake_client_id[crypto_box_PUBLICKEYBYTES];
uint8_t real_client_id[crypto_box_PUBLICKEYBYTES];
@ -95,16 +93,20 @@ typedef struct {
uint64_t last_seen;
Onion_Client_Paths onion_paths;
uint32_t ping_nodes_sent_second;
Last_Pinged last_pinged[MAX_STORED_PINGED_NODES];
uint8_t last_pinged_index;
int (*tcp_relay_node_callback)(void *object, uint32_t number, IP_Port ip_port, uint8_t *public_key);
void *tcp_relay_node_callback_object;
uint32_t tcp_relay_node_callback_number;
} Onion_Friend;
typedef int (*oniondata_handler_callback)(void *object, uint8_t *source_pubkey, uint8_t *data, uint32_t len);
typedef struct {
DHT *dht;
Net_Crypto *c;
Networking_Core *net;
Onion_Friend *friends_list;
uint16_t num_friends;
@ -113,15 +115,15 @@ typedef struct {
Onion_Client_Paths onion_paths;
uint8_t secret_symmetric_key[crypto_secretbox_KEYBYTES];
uint8_t secret_symmetric_key[crypto_box_KEYBYTES];
uint64_t last_run;
uint8_t temp_public_key[crypto_box_PUBLICKEYBYTES];
uint8_t temp_secret_key[crypto_box_SECRETKEYBYTES];
uint32_t ping_nodes_sent_second;
Last_Pinged last_pinged[MAX_STORED_PINGED_NODES];
Ping_Array announce_ping_array;
uint8_t last_pinged_index;
struct {
oniondata_handler_callback function;
@ -170,11 +172,41 @@ int onion_set_friend_online(Onion_Client *onion_c, int friend_num, uint8_t is_on
*/
int onion_getfriendip(Onion_Client *onion_c, int friend_num, IP_Port *ip_port);
/* Set the function for this friend that will be callbacked with object and number
* when that friends gives us one of the TCP relays he is connected to.
*
* object and number will be passed as argument to this function.
*
* return -1 on failure.
* return 0 on success.
*/
int recv_tcp_relay_handler(Onion_Client *onion_c, int friend_num, int (*tcp_relay_node_callback)(void *object,
uint32_t number, IP_Port ip_port, uint8_t *public_key), void *object, uint32_t number);
/* Set a friends DHT public key.
* timestamp is the time (current_time_monotonic()) at which the key was last confirmed belonging to
* the other peer.
*
* return -1 on failure.
* return 0 on success.
*/
int onion_set_friend_DHT_pubkey(Onion_Client *onion_c, int friend_num, uint8_t *dht_key, uint64_t timestamp);
/* Copy friends DHT public key into dht_key.
*
* return 0 on failure (no key copied).
* return timestamp on success (key copied).
*/
uint64_t onion_getfriend_DHT_pubkey(Onion_Client *onion_c, int friend_num, uint8_t *dht_key);
#define ONION_DATA_IN_RESPONSE_MIN_SIZE (crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES)
#define ONION_CLIENT_MAX_DATA_SIZE (MAX_DATA_REQUEST_SIZE - ONION_DATA_IN_RESPONSE_MIN_SIZE)
/* Send data of length length to friendnum.
* This data will be recieved by the friend using the Onion_Data_Handlers callbacks.
* Maximum length of data is ONION_CLIENT_MAX_DATA_SIZE.
* This data will be received by the friend using the Onion_Data_Handlers callbacks.
*
* Even if this function succeeds, the friend might not recieve any data.
* Even if this function succeeds, the friend might not receive any data.
*
* return the number of packets sent on success
* return -1 on failure.
@ -186,7 +218,7 @@ void oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_ha
void do_onion_client(Onion_Client *onion_c);
Onion_Client *new_onion_client(DHT *dht);
Onion_Client *new_onion_client(Net_Crypto *c);
void kill_onion_client(Onion_Client *onion_c);

View File

@ -34,118 +34,29 @@
#include "network.h"
#include "util.h"
#include "ping_array.h"
#define PING_NUM_MAX 512
/* Maximum newly announced nodes to ping per TIME_TO_PING seconds. */
#define MAX_TO_PING 16
#define MAX_TO_PING 8
/* Ping newly announced nodes to ping per TIME_TO_PING seconds*/
#define TIME_TO_PING 5
#define TIME_TO_PING 8
typedef struct {
IP_Port ip_port;
uint64_t id;
uint64_t timestamp;
uint8_t shared_key[crypto_box_BEFORENMBYTES];
} pinged_t;
struct PING {
DHT *dht;
pinged_t pings[PING_NUM_MAX];
size_t num_pings;
size_t pos_pings;
Ping_Array ping_array;
Node_format to_ping[MAX_TO_PING];
uint64_t last_to_ping;
};
static int is_ping_timeout(uint64_t time)
{
return is_timeout(time, PING_TIMEOUT);
}
static void remove_timeouts(PING *ping) // O(n)
{
size_t i, id;
size_t new_pos = ping->pos_pings;
size_t new_num = ping->num_pings;
// Loop through buffer, oldest first.
for (i = 0; i < ping->num_pings; i++) {
id = (ping->pos_pings + i) % PING_NUM_MAX;
if (is_ping_timeout(ping->pings[id].timestamp)) {
new_pos++;
new_num--;
}
// Break here because list is sorted.
else {
break;
}
}
ping->num_pings = new_num;
ping->pos_pings = new_pos % PING_NUM_MAX;
}
static uint64_t add_ping(PING *ping, IP_Port ipp, uint8_t *shared_encryption_key) // O(n)
{
size_t p;
remove_timeouts(ping);
/* Remove oldest ping if full buffer. */
if (ping->num_pings == PING_NUM_MAX) {
ping->num_pings--;
ping->pos_pings = (ping->pos_pings + 1) % PING_NUM_MAX;
}
/* Insert new ping at end of list. */
p = (ping->pos_pings + ping->num_pings) % PING_NUM_MAX;
ping->pings[p].ip_port = ipp;
ping->pings[p].timestamp = unix_time();
ping->pings[p].id = random_64b();
memcpy(ping->pings[p].shared_key, shared_encryption_key, crypto_box_BEFORENMBYTES);
ping->num_pings++;
return ping->pings[p].id;
}
/* checks if ip/port or ping_id are already in the list to ping
* if both are set, both must match, otherwise the set must match
*
* returns 0 if neither is set or no match was found
* returns the (index + 1) of the match if one was found
*/
static int is_pinging(PING *ping, IP_Port ipp, uint64_t ping_id)
{
// O(n) TODO: Replace this with something else.
/* at least one MUST be set */
uint8_t ip_valid = ip_isset(&ipp.ip);
if (!ip_valid && !ping_id)
return 0;
size_t i;
remove_timeouts(ping);
for (i = 0; i < ping->num_pings; i++) {
size_t id = (ping->pos_pings + i) % PING_NUM_MAX;
if (!ping_id || (ping->pings[id].id == ping_id))
if (!ip_valid || ipport_equal(&ping->pings[id].ip_port, &ipp))
return id + 1;
}
return 0;
}
#define DHT_PING_SIZE (1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + sizeof(uint64_t) + crypto_box_MACBYTES)
#define PING_PLAIN_SIZE (1 + sizeof(uint64_t))
#define DHT_PING_SIZE (1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES + PING_PLAIN_SIZE + crypto_box_MACBYTES)
#define PING_DATA_SIZE (CLIENT_ID_SIZE + sizeof(IP_Port))
int send_ping_request(PING *ping, IP_Port ipp, uint8_t *client_id)
{
@ -153,7 +64,7 @@ int send_ping_request(PING *ping, IP_Port ipp, uint8_t *client_id)
int rc;
uint64_t ping_id;
if (is_pinging(ping, ipp, 0) || id_equal(client_id, ping->dht->self_public_key))
if (id_equal(client_id, ping->dht->self_public_key))
return 1;
uint8_t shared_key[crypto_box_BEFORENMBYTES];
@ -161,19 +72,29 @@ int send_ping_request(PING *ping, IP_Port ipp, uint8_t *client_id)
// generate key to encrypt ping_id with recipient privkey
DHT_get_shared_key_sent(ping->dht, shared_key, client_id);
// Generate random ping_id.
ping_id = add_ping(ping, ipp, shared_key);
uint8_t data[PING_DATA_SIZE];
id_copy(data, client_id);
memcpy(data + CLIENT_ID_SIZE, &ipp, sizeof(IP_Port));
ping_id = ping_array_add(&ping->ping_array, data, sizeof(data));
if (ping_id == 0)
return 1;
uint8_t ping_plain[PING_PLAIN_SIZE];
ping_plain[0] = NET_PACKET_PING_REQUEST;
memcpy(ping_plain + 1, &ping_id, sizeof(ping_id));
pk[0] = NET_PACKET_PING_REQUEST;
id_copy(pk + 1, ping->dht->self_public_key); // Our pubkey
new_nonce(pk + 1 + CLIENT_ID_SIZE); // Generate new nonce
rc = encrypt_data_fast(shared_key,
pk + 1 + CLIENT_ID_SIZE,
(uint8_t *) &ping_id, sizeof(ping_id),
pk + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES);
rc = encrypt_data_symmetric(shared_key,
pk + 1 + CLIENT_ID_SIZE,
ping_plain, sizeof(ping_plain),
pk + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES);
if (rc != sizeof(ping_id) + crypto_box_MACBYTES)
if (rc != PING_PLAIN_SIZE + crypto_box_MACBYTES)
return 1;
return sendpacket(ping->dht->net, ipp, pk, sizeof(pk));
@ -188,17 +109,21 @@ static int send_ping_response(PING *ping, IP_Port ipp, uint8_t *client_id, uint6
if (id_equal(client_id, ping->dht->self_public_key))
return 1;
uint8_t ping_plain[PING_PLAIN_SIZE];
ping_plain[0] = NET_PACKET_PING_RESPONSE;
memcpy(ping_plain + 1, &ping_id, sizeof(ping_id));
pk[0] = NET_PACKET_PING_RESPONSE;
id_copy(pk + 1, ping->dht->self_public_key); // Our pubkey
new_nonce(pk + 1 + CLIENT_ID_SIZE); // Generate new nonce
// Encrypt ping_id using recipient privkey
rc = encrypt_data_fast(shared_encryption_key,
pk + 1 + CLIENT_ID_SIZE,
(uint8_t *) &ping_id, sizeof(ping_id),
pk + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES );
rc = encrypt_data_symmetric(shared_encryption_key,
pk + 1 + CLIENT_ID_SIZE,
ping_plain, sizeof(ping_plain),
pk + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES );
if (rc != sizeof(ping_id) + crypto_box_MACBYTES)
if (rc != PING_PLAIN_SIZE + crypto_box_MACBYTES)
return 1;
return sendpacket(ping->dht->net, ipp, pk, sizeof(pk));
@ -208,7 +133,6 @@ static int handle_ping_request(void *_dht, IP_Port source, uint8_t *packet, uint
{
DHT *dht = _dht;
int rc;
uint64_t ping_id;
if (length != DHT_PING_SIZE)
return 1;
@ -220,17 +144,23 @@ static int handle_ping_request(void *_dht, IP_Port source, uint8_t *packet, uint
uint8_t shared_key[crypto_box_BEFORENMBYTES];
uint8_t ping_plain[PING_PLAIN_SIZE];
// Decrypt ping_id
DHT_get_shared_key_recv(dht, shared_key, packet + 1);
rc = decrypt_data_fast(shared_key,
packet + 1 + CLIENT_ID_SIZE,
packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES,
sizeof(ping_id) + crypto_box_MACBYTES,
(uint8_t *) &ping_id );
rc = decrypt_data_symmetric(shared_key,
packet + 1 + CLIENT_ID_SIZE,
packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES,
PING_PLAIN_SIZE + crypto_box_MACBYTES,
ping_plain );
if (rc != sizeof(ping_id))
if (rc != sizeof(ping_plain))
return 1;
if (ping_plain[0] != NET_PACKET_PING_REQUEST)
return 1;
uint64_t ping_id;
memcpy(&ping_id, ping_plain + 1, sizeof(ping_id));
// Send response
send_ping_response(ping, source, packet + 1, ping_id, shared_key);
add_to_ping(ping, packet + 1, source);
@ -242,7 +172,6 @@ static int handle_ping_response(void *_dht, IP_Port source, uint8_t *packet, uin
{
DHT *dht = _dht;
int rc;
uint64_t ping_id;
if (length != DHT_PING_SIZE)
return 1;
@ -252,30 +181,71 @@ static int handle_ping_response(void *_dht, IP_Port source, uint8_t *packet, uin
if (id_equal(packet + 1, ping->dht->self_public_key))
return 1;
int ping_index = is_pinging(ping, source, 0);
uint8_t shared_key[crypto_box_BEFORENMBYTES];
if (!ping_index)
return 1;
// generate key to encrypt ping_id with recipient privkey
DHT_get_shared_key_sent(ping->dht, shared_key, packet + 1);
--ping_index;
uint8_t ping_plain[PING_PLAIN_SIZE];
// Decrypt ping_id
rc = decrypt_data_fast(ping->pings[ping_index].shared_key,
packet + 1 + CLIENT_ID_SIZE,
packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES,
sizeof(ping_id) + crypto_box_MACBYTES,
(uint8_t *) &ping_id);
rc = decrypt_data_symmetric(shared_key,
packet + 1 + CLIENT_ID_SIZE,
packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES,
PING_PLAIN_SIZE + crypto_box_MACBYTES,
ping_plain);
if (rc != sizeof(ping_id))
if (rc != sizeof(ping_plain))
return 1;
if (ping->pings[ping_index].id != ping_id)
if (ping_plain[0] != NET_PACKET_PING_RESPONSE)
return 1;
uint64_t ping_id;
memcpy(&ping_id, ping_plain + 1, sizeof(ping_id));
uint8_t data[PING_DATA_SIZE];
if (ping_array_check(data, sizeof(data), &ping->ping_array, ping_id) != sizeof(data))
return 1;
if (!id_equal(packet + 1, data))
return 1;
IP_Port ipp;
memcpy(&ipp, data + CLIENT_ID_SIZE, sizeof(IP_Port));
if (!ipport_equal(&ipp, &source))
return 1;
addto_lists(dht, source, packet + 1);
return 0;
}
/* Check if client_id with ip_port is in the list.
*
* return 1 if it is.
* return 0 if it isn't.
*/
static int in_list(Client_data *list, uint32_t length, uint8_t *client_id, IP_Port ip_port)
{
uint32_t i;
for (i = 0; i < length; ++i) {
if (id_equal(list[i].client_id, client_id)) {
IPPTsPng *ipptp;
if (ip_port.ip.family == AF_INET) {
ipptp = &list[i].assoc4;
} else {
ipptp = &list[i].assoc6;
}
if (!is_timeout(ipptp->timestamp, BAD_NODE_TIMEOUT) && ipport_equal(&ipptp->ip_port, &ip_port))
return 1;
}
}
return 0;
}
/* Add nodes to the to_ping list.
* All nodes in this list are pinged every TIME_TO_PING seconds
@ -292,6 +262,9 @@ int add_to_ping(PING *ping, uint8_t *client_id, IP_Port ip_port)
if (!ip_isset(&ip_port.ip))
return -1;
if (in_list(ping->dht->close_clientlist, LCLIENT_LIST, client_id, ip_port))
return -1;
uint32_t i;
for (i = 0; i < MAX_TO_PING; ++i) {
@ -300,12 +273,18 @@ int add_to_ping(PING *ping, uint8_t *client_id, IP_Port ip_port)
ipport_copy(&ping->to_ping[i].ip_port, &ip_port);
return 0;
}
if (memcmp(ping->to_ping[i].client_id, client_id, CLIENT_ID_SIZE) == 0) {
return -1;
}
}
uint32_t r = rand();
for (i = 0; i < MAX_TO_PING; ++i) {
if (id_closest(ping->dht->self_public_key, ping->to_ping[i].client_id, client_id) == 2) {
memcpy(ping->to_ping[i].client_id, client_id, CLIENT_ID_SIZE);
ipport_copy(&ping->to_ping[i].ip_port, &ip_port);
if (id_closest(ping->dht->self_public_key, ping->to_ping[(i + r) % MAX_TO_PING].client_id, client_id) == 2) {
memcpy(ping->to_ping[(i + r) % MAX_TO_PING].client_id, client_id, CLIENT_ID_SIZE);
ipport_copy(&ping->to_ping[(i + r) % MAX_TO_PING].ip_port, &ip_port);
return 0;
}
}
@ -342,6 +321,11 @@ PING *new_ping(DHT *dht)
if (ping == NULL)
return NULL;
if (ping_array_init(&ping->ping_array, PING_NUM_MAX, PING_TIMEOUT) != 0) {
free(ping);
return NULL;
}
ping->dht = dht;
networking_registerhandler(ping->dht->net, NET_PACKET_PING_REQUEST, &handle_ping_request, dht);
networking_registerhandler(ping->dht->net, NET_PACKET_PING_RESPONSE, &handle_ping_response, dht);
@ -353,6 +337,7 @@ void kill_ping(PING *ping)
{
networking_registerhandler(ping->dht->net, NET_PACKET_PING_REQUEST, NULL, NULL);
networking_registerhandler(ping->dht->net, NET_PACKET_PING_RESPONSE, NULL, NULL);
ping_array_free_all(&ping->ping_array);
free(ping);
}

162
toxcore/ping_array.c Normal file
View File

@ -0,0 +1,162 @@
/* ping_array.c
*
* Implementation of an efficient array to store that we pinged something.
*
*
* Copyright (C) 2014 Tox project All Rights Reserved.
*
* This file is part of Tox.
*
* Tox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "ping_array.h"
#include "crypto_core.h"
#include "util.h"
static void clear_entry(Ping_Array *array, uint32_t index)
{
free(array->entries[index].data);
array->entries[index].data = NULL;
array->entries[index].length =
array->entries[index].time =
array->entries[index].ping_id = 0;
}
/* Clear timed out entries.
*/
static void ping_array_clear_timedout(Ping_Array *array)
{
while (array->last_deleted != array->last_added) {
uint32_t index = array->last_deleted % array->total_size;
if (!is_timeout(array->entries[index].time, array->timeout))
break;
clear_entry(array, index);
++array->last_deleted;
}
}
/* Add a data with length to the Ping_Array list and return a ping_id.
*
* return ping_id on success.
* return 0 on failure.
*/
uint64_t ping_array_add(Ping_Array *array, uint8_t *data, uint32_t length)
{
ping_array_clear_timedout(array);
uint32_t index = array->last_added % array->total_size;
if (array->entries[index].data != NULL) {
array->last_deleted = array->last_added - array->total_size;
clear_entry(array, index);
}
array->entries[index].data = malloc(length);
if (array->entries[index].data == NULL)
return 0;
memcpy(array->entries[index].data, data, length);
array->entries[index].length = length;
array->entries[index].time = unix_time();
++array->last_added;
uint64_t ping_id = random_64b();
ping_id /= array->total_size;
ping_id *= array->total_size;
ping_id += index;
if (ping_id == 0)
ping_id += array->total_size;
array->entries[index].ping_id = ping_id;
return ping_id;
}
/* Check if ping_id is valid and not timed out.
*
* On success, copies the data into data of length,
*
* return length of data copied on success.
* return -1 on failure.
*/
int ping_array_check(uint8_t *data, uint32_t length, Ping_Array *array, uint64_t ping_id)
{
if (ping_id == 0)
return -1;
uint32_t index = ping_id % array->total_size;
if (array->entries[index].ping_id != ping_id)
return -1;
if (is_timeout(array->entries[index].time, array->timeout))
return -1;
if (array->entries[index].length > length)
return -1;
if (array->entries[index].data == NULL)
return -1;
memcpy(data, array->entries[index].data, array->entries[index].length);
uint32_t len = array->entries[index].length;
clear_entry(array, index);
return len;
}
/* Initialize a Ping_Array.
* size represents the total size of the array and should be a power of 2.
* timeout represents the maximum timeout in seconds for the entry.
*
* return 0 on success.
* return -1 on failure.
*/
int ping_array_init(Ping_Array *empty_array, uint32_t size, uint32_t timeout)
{
if (size == 0 || timeout == 0 || empty_array == NULL)
return -1;
empty_array->entries = calloc(size * sizeof(Ping_Array_Entry), 1);
if (empty_array->entries == NULL)
return -1;
empty_array->last_deleted = empty_array->last_added = 0;
empty_array->total_size = size;
empty_array->timeout = timeout;
return 0;
}
/* Free all the allocated memory in a Ping_Array.
*/
void ping_array_free_all(Ping_Array *array)
{
while (array->last_deleted != array->last_added) {
uint32_t index = array->last_deleted % array->total_size;
clear_entry(array, index);
++array->last_deleted;
}
free(array->entries);
array->entries = NULL;
}

75
toxcore/ping_array.h Normal file
View File

@ -0,0 +1,75 @@
/* ping_array.h
*
* Implementation of an efficient array to store that we pinged something.
*
* Copyright (C) 2013 Tox project All Rights Reserved.
*
* This file is part of Tox.
*
* Tox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PING_ARRAY_H
#define PING_ARRAY_H
#include "network.h"
typedef struct {
void *data;
uint32_t length;
uint64_t time;
uint64_t ping_id;
} Ping_Array_Entry;
typedef struct {
Ping_Array_Entry *entries;
uint32_t last_deleted; /* number representing the next entry to be deleted. */
uint32_t last_added; /* number representing the last entry to be added. */
uint32_t total_size; /* The length of entries */
uint32_t timeout; /* The timeout after which entries are cleared. */
} Ping_Array;
/* Add a data with length to the Ping_Array list and return a ping_id.
*
* return ping_id on success.
* return 0 on failure.
*/
uint64_t ping_array_add(Ping_Array *array, uint8_t *data, uint32_t length);
/* Check if ping_id is valid and not timed out.
*
* On success, copies the data into data of length,
*
* return length of data copied on success.
* return -1 on failure.
*/
int ping_array_check(uint8_t *data, uint32_t length, Ping_Array *array, uint64_t ping_id);
/* Initialize a Ping_Array.
* size represents the total size of the array and should be a power of 2.
* timeout represents the maximum timeout in seconds for the entry.
*
* return 0 on success.
* return -1 on failure.
*/
int ping_array_init(Ping_Array *empty_array, uint32_t size, uint32_t timeout);
/* Free all the allocated memory in a Ping_Array.
*/
void ping_array_free_all(Ping_Array *array);
#endif

View File

@ -187,7 +187,7 @@ int tox_set_name(Tox *tox, uint8_t *name, uint16_t length)
}
/* Get your nickname.
* m - The messanger context to use.
* m - The messenger context to use.
* name - Pointer to a string for the name. (must be at least MAX_NAME_LENGTH)
*
* return length of the name.
@ -722,7 +722,7 @@ int tox_file_send_data(Tox *tox, int32_t friendnumber, uint8_t filenumber, uint8
*/
int tox_file_data_size(Tox *tox, int32_t friendnumber)
{
return MAX_DATA_SIZE - crypto_box_MACBYTES - 3;
return MAX_CRYPTO_DATA_SIZE - 2;
}
/* Give the number of bytes left to be sent/received.
@ -740,23 +740,38 @@ uint64_t tox_file_data_remaining(Tox *tox, int32_t friendnumber, uint8_t filenum
/***************END OF FILE SENDING FUNCTIONS******************/
/* Use these functions to bootstrap the client.
* Sends a get nodes request to the given node with ip port and public_key.
*/
void tox_bootstrap_from_ip(Tox *tox, tox_IP_Port _ip_port, uint8_t *public_key)
/* TODO: expose this properly. */
static int tox_add_tcp_relay(Tox *tox, const char *address, uint8_t ipv6enabled, uint16_t port, uint8_t *public_key)
{
Messenger *m = tox;
IP_Port ip_port;
memcpy(&ip_port, &_ip_port, sizeof(IP_Port));
DHT_bootstrap(m->dht, ip_port, public_key);
IP_Port ip_port_v64;
IP *ip_extra = NULL;
IP_Port ip_port_v4;
ip_init(&ip_port_v64.ip, ipv6enabled);
if (ipv6enabled) {
/* setup for getting BOTH: an IPv6 AND an IPv4 address */
ip_port_v64.ip.family = AF_UNSPEC;
ip_reset(&ip_port_v4.ip);
ip_extra = &ip_port_v4.ip;
}
if (addr_resolve_or_parse_ip(address, &ip_port_v64.ip, ip_extra)) {
ip_port_v64.port = port;
add_tcp_relay(m->net_crypto, ip_port_v64, public_key);
return 1;
} else {
return 0;
}
}
int tox_bootstrap_from_address(Tox *tox, const char *address,
uint8_t ipv6enabled, uint16_t port, uint8_t *public_key)
{
Messenger *m = tox;
tox_add_tcp_relay(tox, address, ipv6enabled, port, public_key);
return DHT_bootstrap_from_address(m->dht, address, ipv6enabled, port, public_key);
};
}
/* return 0 if we are not connected to the DHT.
* return 1 if we are.
@ -842,33 +857,3 @@ int tox_load(Tox *tox, uint8_t *data, uint32_t length)
Messenger *m = tox;
return messenger_load(m, data, length);
}
/* return the size of data to pass to messenger_save_encrypted(...)
*/
uint32_t tox_size_encrypted(Tox *tox)
{
Messenger *m = tox;
return messenger_size_encrypted(m);
}
/* Save the messenger, encrypting the data with key of length key_length
*
* return 0 on success.
* return -1 on failure.
*/
int tox_save_encrypted(Tox *tox, uint8_t *data, uint8_t *key, uint16_t key_length)
{
Messenger *m = tox;
return messenger_save_encrypted(m, data, key, key_length);
}
/* Load the messenger from data of size length encrypted with key of key_length.
*
* return 0 on success.
* return -1 on failure.
*/
int tox_load_encrypted(Tox *tox, uint8_t *data, uint32_t length, uint8_t *key, uint16_t key_length)
{
Messenger *m = tox;
return messenger_load_encrypted(m, data, length, key, key_length);
}

View File

@ -210,7 +210,7 @@ int tox_set_name(Tox *tox, uint8_t *name, uint16_t length);
/*
* Get your nickname.
* m - The messanger context to use.
* m - The messenger context to use.
* name - needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes.
*
* return length of name.
@ -515,11 +515,11 @@ uint32_t tox_get_chatlist(Tox *tox, int *out_list, uint32_t list_size);
* tox_file_data_remaining(...) can be used to know how many bytes are left to send/receive.
*
* If the connection breaks during file sending (The other person goes offline without pausing the sending and then comes back)
* the reciever must send a control packet with receive_send == 0 message_id = TOX_FILECONTROL_RESUME_BROKEN and the data being
* a uint64_t (in host byte order) containing the number of bytes recieved.
* the receiver must send a control packet with receive_send == 0 message_id = TOX_FILECONTROL_RESUME_BROKEN and the data being
* a uint64_t (in host byte order) containing the number of bytes received.
*
* If the sender recieves this packet, he must send a control packet with receive_send == 1 and control_type == TOX_FILECONTROL_ACCEPT
* then he must start sending file data from the position (data , uint64_t in host byte order) recieved in the TOX_FILECONTROL_RESUME_BROKEN packet.
* If the sender receives this packet, he must send a control packet with receive_send == 1 and control_type == TOX_FILECONTROL_ACCEPT
* then he must start sending file data from the position (data , uint64_t in host byte order) received in the TOX_FILECONTROL_RESUME_BROKEN packet.
*
* More to come...
*/
@ -601,43 +601,6 @@ uint64_t tox_file_data_remaining(Tox *tox, int32_t friendnumber, uint8_t filenum
/***************END OF FILE SENDING FUNCTIONS******************/
/* WARNING: DEPRECATED, DO NOT USE. */
typedef union {
uint8_t c[4];
uint16_t s[2];
uint32_t i;
} tox_IP4;
typedef union {
uint8_t uint8[16];
uint16_t uint16[8];
uint32_t uint32[4];
struct in6_addr in6_addr;
} tox_IP6;
typedef struct {
uint8_t family;
/* Not used for anything right now. */
uint8_t padding[3];
union {
tox_IP4 ip4;
tox_IP6 ip6;
};
} tox_IP;
/* will replace IP_Port as soon as the complete infrastructure is in place
* removed the unused union and padding also */
typedef struct {
tox_IP ip;
uint16_t port;
} tox_IP_Port;
/* WARNING: DEPRECATED, DO NOT USE. */
/* Sends a "get nodes" request to the given node with ip, port and public_key
* to setup connections
*/
void tox_bootstrap_from_ip(Tox *tox, tox_IP_Port ip_port, uint8_t *public_key);
/*
* Use this function to bootstrap the client.
*/
@ -739,32 +702,6 @@ void tox_save(Tox *tox, uint8_t *data);
*/
int tox_load(Tox *tox, uint8_t *data, uint32_t length);
/**/
/* return the size of data to pass to messenger_save_encrypted(...)
*/
uint32_t tox_size_encrypted(Tox *tox);
/* Save the messenger, encrypting the data with key of length key_length
*
* This functions simply calls and then encrypt the output of tox_save(..)
* with crypto_secretbox(...) from NaCl/libsodium with the key
* given to crypto_secretbox(...) being the SHA256 sum of the key
* passed to this function.
*
* return 0 on success.
* return -1 on failure.
*/
int tox_save_encrypted(Tox *tox, uint8_t *data, uint8_t *key, uint16_t key_length);
/* Load the messenger from data of size length encrypted with key of key_length.
*
* return 0 on success.
* return -1 on failure.
*/
int tox_load_encrypted(Tox *tox, uint8_t *data, uint32_t length, uint8_t *key, uint16_t key_length);
#ifdef __cplusplus
}
#endif

View File

@ -36,10 +36,14 @@
/* don't call into system billions of times for no reason */
static uint64_t unix_time_value;
static uint64_t unix_base_time_value;
void unix_time_update()
{
unix_time_value = (uint64_t)time(NULL);
if (unix_base_time_value == 0)
unix_base_time_value = ((uint64_t)time(NULL) - (current_time_monotonic() / 1000ULL));
unix_time_value = (current_time_monotonic() / 1000ULL) + unix_base_time_value;
}
uint64_t unix_time()
@ -49,7 +53,7 @@ uint64_t unix_time()
int is_timeout(uint64_t timestamp, uint64_t timeout)
{
return timestamp + timeout <= unix_time_value;
return timestamp + timeout <= unix_time();
}
@ -67,22 +71,17 @@ uint32_t id_copy(uint8_t *dest, uint8_t *src)
void host_to_net(uint8_t *num, uint16_t numbytes)
{
union {
uint32_t i;
uint8_t c[4];
} a;
a.i = 1;
#ifndef WORDS_BIGENDIAN
uint32_t i;
uint8_t buff[numbytes];
if (a.c[0] == 1) {
uint32_t i;
uint8_t buff[numbytes];
for (i = 0; i < numbytes; ++i) {
buff[i] = num[numbytes - i - 1];
}
memcpy(num, buff, numbytes);
for (i = 0; i < numbytes; ++i) {
buff[i] = num[numbytes - i - 1];
}
memcpy(num, buff, numbytes);
#endif
return;
}
/* state load/save */
@ -99,11 +98,11 @@ int load_state(load_state_callback_func load_state_callback, void *outer,
uint16_t type;
uint32_t length_sub, cookie_type;
uint32_t size32 = sizeof(uint32_t), size_head = size32 * 2;
uint32_t size_head = sizeof(uint32_t) * 2;
while (length >= size_head) {
length_sub = *(uint32_t *)data;
cookie_type = *(uint32_t *)(data + size32);
memcpy(&length_sub, data, sizeof(length_sub));
memcpy(&cookie_type, data + sizeof(length_sub), sizeof(cookie_type));
data += size_head;
length -= size_head;