mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
Crypto done(still need to test it a bit more thought)
Replaced chars with uint8_t Added a new test program. Added some functions to Lossless UDP. And some other stuff.
This commit is contained in:
parent
358f46f648
commit
a480c0195a
44
core/DHT.c
44
core/DHT.c
|
@ -27,13 +27,13 @@
|
|||
|
||||
#include "DHT.h"
|
||||
|
||||
char self_client_id[CLIENT_ID_SIZE];
|
||||
uint8_t self_client_id[CLIENT_ID_SIZE];
|
||||
|
||||
//Compares client_id1 and client_id2 with client_id
|
||||
//return 0 if both are same distance
|
||||
//return 1 if client_id1 is closer.
|
||||
//return 2 if client_id2 is closer.
|
||||
int id_closest(char * client_id, char * client_id1, char * client_id2)//tested
|
||||
int id_closest(uint8_t * client_id, uint8_t * client_id1, uint8_t * client_id2)//tested
|
||||
{
|
||||
uint32_t i;
|
||||
for(i = 0; i < CLIENT_ID_SIZE; i++)
|
||||
|
@ -58,7 +58,7 @@ int id_closest(char * client_id, char * client_id1, char * client_id2)//tested
|
|||
//if the ip_port is already in the list but associated to a different ip, change it.
|
||||
//return True(1) or False(0)
|
||||
//TODO: maybe optimize this.
|
||||
int client_in_list(Client_data * list, uint32_t length, char * client_id, IP_Port ip_port)
|
||||
int client_in_list(Client_data * list, uint32_t length, uint8_t * client_id, IP_Port ip_port)
|
||||
{
|
||||
uint32_t i, j;
|
||||
uint32_t temp_time = unix_time();
|
||||
|
@ -92,7 +92,7 @@ int client_in_list(Client_data * list, uint32_t length, char * client_id, IP_Por
|
|||
|
||||
//check if client with client_id is already in node format list of length length.
|
||||
//return True(1) or False(0)
|
||||
int client_in_nodelist(Node_format * list, uint32_t length, char * client_id)
|
||||
int client_in_nodelist(Node_format * list, uint32_t length, uint8_t * client_id)
|
||||
{
|
||||
uint32_t i, j;
|
||||
for(i = 0; i < length; i++)
|
||||
|
@ -126,7 +126,7 @@ int client_in_nodelist(Node_format * list, uint32_t length, char * client_id)
|
|||
//Find MAX_SENT_NODES nodes closest to the client_id for the send nodes request:
|
||||
//put them in the nodes_list and return how many were found.
|
||||
//TODO: Make this function much more efficient.
|
||||
int get_close_nodes(char * client_id, Node_format * nodes_list)
|
||||
int get_close_nodes(uint8_t * client_id, Node_format * nodes_list)
|
||||
{
|
||||
uint32_t i, j, k;
|
||||
int num_nodes=0;
|
||||
|
@ -191,7 +191,7 @@ int get_close_nodes(char * client_id, Node_format * nodes_list)
|
|||
//replace first bad (or empty) node with this one
|
||||
//return 0 if successfull
|
||||
//return 1 if not (list contains no bad nodes)
|
||||
int replace_bad(Client_data * list, uint32_t length, char * client_id, IP_Port ip_port)//tested
|
||||
int replace_bad(Client_data * list, uint32_t length, uint8_t * client_id, IP_Port ip_port)//tested
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t temp_time = unix_time();
|
||||
|
@ -210,7 +210,7 @@ int replace_bad(Client_data * list, uint32_t length, char * client_id, IP_Port i
|
|||
}
|
||||
|
||||
//replace the first good node that is further to the comp_client_id than that of the client_id in the list
|
||||
int replace_good(Client_data * list, uint32_t length, char * client_id, IP_Port ip_port, char * comp_client_id)
|
||||
int replace_good(Client_data * list, uint32_t length, uint8_t * client_id, IP_Port ip_port, uint8_t * comp_client_id)
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t temp_time = unix_time();
|
||||
|
@ -230,7 +230,7 @@ int replace_good(Client_data * list, uint32_t length, char * client_id, IP_Port
|
|||
}
|
||||
|
||||
//Attempt to add client with ip_port and client_id to the friends client list and close_clientlist
|
||||
void addto_lists(IP_Port ip_port, char * client_id)
|
||||
void addto_lists(IP_Port ip_port, uint8_t * client_id)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
|
@ -414,7 +414,7 @@ int pingreq(IP_Port ip_port)
|
|||
return 1;
|
||||
}
|
||||
|
||||
char data[5 + CLIENT_ID_SIZE];
|
||||
uint8_t data[5 + CLIENT_ID_SIZE];
|
||||
data[0] = 0;
|
||||
memcpy(data + 1, &ping_id, 4);
|
||||
memcpy(data + 5, self_client_id, CLIENT_ID_SIZE);
|
||||
|
@ -427,7 +427,7 @@ int pingreq(IP_Port ip_port)
|
|||
//send a ping response
|
||||
int pingres(IP_Port ip_port, uint32_t ping_id)
|
||||
{
|
||||
char data[5 + CLIENT_ID_SIZE];
|
||||
uint8_t data[5 + CLIENT_ID_SIZE];
|
||||
data[0] = 1;
|
||||
|
||||
memcpy(data + 1, &ping_id, 4);
|
||||
|
@ -438,7 +438,7 @@ int pingres(IP_Port ip_port, uint32_t ping_id)
|
|||
}
|
||||
|
||||
//send a getnodes request
|
||||
int getnodes(IP_Port ip_port, char * client_id)
|
||||
int getnodes(IP_Port ip_port, uint8_t * client_id)
|
||||
{
|
||||
if(is_gettingnodes(ip_port, 0))
|
||||
{
|
||||
|
@ -452,7 +452,7 @@ int getnodes(IP_Port ip_port, char * client_id)
|
|||
return 1;
|
||||
}
|
||||
|
||||
char data[5 + CLIENT_ID_SIZE*2];
|
||||
uint8_t data[5 + CLIENT_ID_SIZE*2];
|
||||
data[0] = 2;
|
||||
|
||||
memcpy(data + 1, &ping_id, 4);
|
||||
|
@ -465,9 +465,9 @@ int getnodes(IP_Port ip_port, char * client_id)
|
|||
|
||||
|
||||
//send a send nodes response
|
||||
int sendnodes(IP_Port ip_port, char * client_id, uint32_t ping_id)
|
||||
int sendnodes(IP_Port ip_port, uint8_t * client_id, uint32_t ping_id)
|
||||
{
|
||||
char data[5 + CLIENT_ID_SIZE + (CLIENT_ID_SIZE + sizeof(IP_Port))*MAX_SENT_NODES];
|
||||
uint8_t data[5 + CLIENT_ID_SIZE + (CLIENT_ID_SIZE + sizeof(IP_Port))*MAX_SENT_NODES];
|
||||
Node_format nodes_list[MAX_SENT_NODES];
|
||||
|
||||
int num_nodes = get_close_nodes(client_id, nodes_list);
|
||||
|
@ -493,7 +493,7 @@ int sendnodes(IP_Port ip_port, char * client_id, uint32_t ping_id)
|
|||
//Packet handling functions
|
||||
//One to handle each types of packets we recieve
|
||||
//return 0 if handled correctly, 1 if packet is bad.
|
||||
int handle_pingreq(char * packet, uint32_t length, IP_Port source)//tested
|
||||
int handle_pingreq(uint8_t * packet, uint32_t length, IP_Port source)//tested
|
||||
{
|
||||
if(length != 5 + CLIENT_ID_SIZE)
|
||||
{
|
||||
|
@ -518,7 +518,7 @@ int handle_pingreq(char * packet, uint32_t length, IP_Port source)//tested
|
|||
|
||||
}
|
||||
|
||||
int handle_pingres(char * packet, uint32_t length, IP_Port source)
|
||||
int handle_pingres(uint8_t * packet, uint32_t length, IP_Port source)
|
||||
{
|
||||
if(length != (5 + CLIENT_ID_SIZE))
|
||||
{
|
||||
|
@ -536,7 +536,7 @@ int handle_pingres(char * packet, uint32_t length, IP_Port source)
|
|||
|
||||
}
|
||||
|
||||
int handle_getnodes(char * packet, uint32_t length, IP_Port source)
|
||||
int handle_getnodes(uint8_t * packet, uint32_t length, IP_Port source)
|
||||
{
|
||||
if(length != (5 + CLIENT_ID_SIZE*2))
|
||||
{
|
||||
|
@ -559,7 +559,7 @@ int handle_getnodes(char * packet, uint32_t length, IP_Port source)
|
|||
|
||||
}
|
||||
|
||||
int handle_sendnodes(char * packet, uint32_t length, IP_Port source)//tested
|
||||
int handle_sendnodes(uint8_t * packet, uint32_t length, IP_Port source)//tested
|
||||
{
|
||||
if(length > (5 + CLIENT_ID_SIZE + MAX_SENT_NODES * (CLIENT_ID_SIZE + sizeof(IP_Port))) ||
|
||||
(length - 5 - CLIENT_ID_SIZE) % (CLIENT_ID_SIZE + sizeof(IP_Port)) != 0)
|
||||
|
@ -593,7 +593,7 @@ int handle_sendnodes(char * packet, uint32_t length, IP_Port source)//tested
|
|||
|
||||
|
||||
|
||||
int addfriend(char * client_id)
|
||||
int addfriend(uint8_t * client_id)
|
||||
{
|
||||
//TODO:Maybe make the array of friends dynamic instead of a static array with MAX_FRIENDS
|
||||
if(MAX_FRIENDS > num_friends)
|
||||
|
@ -610,7 +610,7 @@ int addfriend(char * client_id)
|
|||
|
||||
|
||||
|
||||
int delfriend(char * client_id)
|
||||
int delfriend(uint8_t * client_id)
|
||||
{
|
||||
uint32_t i;
|
||||
for(i = 0; i < num_friends; i++)
|
||||
|
@ -630,7 +630,7 @@ int delfriend(char * client_id)
|
|||
|
||||
|
||||
//TODO: Optimize this.
|
||||
IP_Port getfriendip(char * client_id)
|
||||
IP_Port getfriendip(uint8_t * client_id)
|
||||
{
|
||||
uint32_t i, j;
|
||||
IP_Port empty = {{{0}}, 0};
|
||||
|
@ -660,7 +660,7 @@ IP_Port getfriendip(char * client_id)
|
|||
|
||||
|
||||
|
||||
int DHT_handlepacket(char * packet, uint32_t length, IP_Port source)
|
||||
int DHT_handlepacket(uint8_t * packet, uint32_t length, IP_Port source)
|
||||
{
|
||||
switch (packet[0]) {
|
||||
case 0:
|
||||
|
|
16
core/DHT.h
16
core/DHT.h
|
@ -36,7 +36,7 @@
|
|||
|
||||
typedef struct
|
||||
{
|
||||
char client_id[CLIENT_ID_SIZE];
|
||||
uint8_t client_id[CLIENT_ID_SIZE];
|
||||
IP_Port ip_port;
|
||||
uint32_t timestamp;
|
||||
uint32_t last_pinged;
|
||||
|
@ -45,7 +45,7 @@ typedef struct
|
|||
#define MAX_FRIEND_CLIENTS 8
|
||||
typedef struct
|
||||
{
|
||||
char client_id[CLIENT_ID_SIZE];
|
||||
uint8_t client_id[CLIENT_ID_SIZE];
|
||||
Client_data client_list[MAX_FRIEND_CLIENTS];
|
||||
|
||||
}Friend;
|
||||
|
@ -53,7 +53,7 @@ typedef struct
|
|||
|
||||
typedef struct
|
||||
{
|
||||
char client_id[CLIENT_ID_SIZE];
|
||||
uint8_t client_id[CLIENT_ID_SIZE];
|
||||
IP_Port ip_port;
|
||||
}Node_format;
|
||||
|
||||
|
@ -70,13 +70,13 @@ typedef struct
|
|||
//client_id must be CLIENT_ID_SIZE bytes long.
|
||||
//returns 0 if success
|
||||
//returns 1 if failure (friends list is full)
|
||||
int addfriend(char * client_id);
|
||||
int addfriend(uint8_t * client_id);
|
||||
|
||||
//Delete a friend from the friends list
|
||||
//client_id must be CLIENT_ID_SIZE bytes long.
|
||||
//returns 0 if success
|
||||
//returns 1 if failure (client_id not in friends list)
|
||||
int delfriend(char * client_id);
|
||||
int delfriend(uint8_t * client_id);
|
||||
|
||||
|
||||
//Get ip of friend
|
||||
|
@ -86,7 +86,7 @@ int delfriend(char * client_id);
|
|||
//returns ip if success
|
||||
//returns ip of 0 if failure (This means the friend is either offline or we have not found him yet.)
|
||||
//returns ip of 1 if friend is not in list.
|
||||
IP_Port getfriendip(char * client_id);
|
||||
IP_Port getfriendip(uint8_t * client_id);
|
||||
|
||||
|
||||
//Run this function at least a couple times per second (It's the main loop)
|
||||
|
@ -95,7 +95,7 @@ void doDHT();
|
|||
//if we recieve a DHT packet we call this function so it can be handled.
|
||||
//Return 0 if packet is handled correctly.
|
||||
//return 1 if it didn't handle the packet or if the packet was shit.
|
||||
int DHT_handlepacket(char * packet, uint32_t length, IP_Port source);
|
||||
int DHT_handlepacket(uint8_t * packet, uint32_t length, IP_Port source);
|
||||
|
||||
//Use this function to bootstrap the client
|
||||
//Sends a get nodes request to the given ip port
|
||||
|
@ -109,7 +109,7 @@ void bootstrap(IP_Port ip_port);
|
|||
//Global variables
|
||||
|
||||
//Our client id
|
||||
extern char self_client_id[CLIENT_ID_SIZE];
|
||||
extern uint8_t self_client_id[CLIENT_ID_SIZE];
|
||||
|
||||
|
||||
//TODO: Move these out of here and put them into the .c file.
|
||||
|
|
|
@ -47,18 +47,19 @@
|
|||
|
||||
typedef struct
|
||||
{
|
||||
char data[MAX_DATA_SIZE];
|
||||
uint8_t data[MAX_DATA_SIZE];
|
||||
uint16_t size;
|
||||
}Data;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
IP_Port ip_port;
|
||||
char status;//0 if connection is dead, 1 if attempting handshake,
|
||||
uint8_t status;//0 if connection is dead, 1 if attempting handshake,
|
||||
//2 if handshake is done (we start sending SYNC packets)
|
||||
//3 if we are sending SYNC packets and can send data
|
||||
//4 if the connection has timed out.
|
||||
|
||||
char inbound; //1 or 2 if connection was initiated by someone else, 0 if not.
|
||||
uint8_t inbound; //1 or 2 if connection was initiated by someone else, 0 if not.
|
||||
//2 if incoming_connection() has not returned it yet, 1 if it has.
|
||||
|
||||
uint16_t SYNC_rate;//current SYNC packet send rate packets per second.
|
||||
|
@ -66,6 +67,7 @@ typedef struct
|
|||
uint64_t last_SYNC; //time at which our last SYNC packet was sent.
|
||||
uint64_t last_sent; //time at which our last data or handshake packet was sent.
|
||||
uint64_t last_recv; //time at which we last recieved something from the other
|
||||
uint64_t killat; //time at which to kill the connection
|
||||
Data sendbuffer[MAX_QUEUE_NUM];//packet send buffer.
|
||||
Data recvbuffer[MAX_QUEUE_NUM];//packet recieve buffer.
|
||||
uint32_t handshake_id1;
|
||||
|
@ -160,6 +162,7 @@ int new_connection(IP_Port ip_port)
|
|||
connections[i].SYNC_rate = SYNC_RATE;
|
||||
connections[i].data_rate = DATA_SYNC_RATE;
|
||||
connections[i].last_recv = current_time();
|
||||
connections[i].killat = ~0;
|
||||
connections[i].send_counter = 0;
|
||||
return i;
|
||||
}
|
||||
|
@ -187,6 +190,7 @@ int new_inconnection(IP_Port ip_port)
|
|||
connections[i].SYNC_rate = SYNC_RATE;
|
||||
connections[i].data_rate = DATA_SYNC_RATE;
|
||||
connections[i].last_recv = current_time();
|
||||
connections[i].killat = ~0;
|
||||
connections[i].send_counter = 127;
|
||||
return i;
|
||||
}
|
||||
|
@ -225,11 +229,28 @@ int kill_connection(int connection_id)
|
|||
return -1;
|
||||
}
|
||||
|
||||
//kill connection in seconds seconds.
|
||||
//return -1 if it can not kill the connection.
|
||||
//return 0 if it will kill it
|
||||
int kill_connection_in(int connection_id, uint32_t seconds)
|
||||
{
|
||||
if(connection_id >= 0 && connection_id < MAX_CONNECTIONS)
|
||||
{
|
||||
if(connections[connection_id].status > 0)
|
||||
{
|
||||
connections[connection_id].killat = current_time() + 1000000UL*seconds;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//check if connection is connected
|
||||
//return 0 no.
|
||||
//return 1 if attempting handshake
|
||||
//return 2 if handshake is done
|
||||
//return 3 if fully connected
|
||||
//return 4 if timed out and wating to be killed
|
||||
int is_connected(int connection_id)
|
||||
{
|
||||
if(connection_id >= 0 && connection_id < MAX_CONNECTIONS)
|
||||
|
@ -262,9 +283,19 @@ uint32_t recvqueue(int connection_id)
|
|||
return connections[connection_id].recv_packetnum - connections[connection_id].successful_read;
|
||||
}
|
||||
|
||||
//returns the id of the next packet in the queue
|
||||
//return -1 if no packet in queue
|
||||
char id_packet(int connection_id)
|
||||
{
|
||||
if(recvqueue(connection_id) != 0 && connections[connection_id].status != 0)
|
||||
{
|
||||
return connections[connection_id].recvbuffer[connections[connection_id].successful_read % MAX_QUEUE_NUM].data[0];
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
//return 0 if there is no received data in the buffer.
|
||||
//return length of received packet if successful
|
||||
int read_packet(int connection_id, char * data)
|
||||
int read_packet(int connection_id, uint8_t * data)
|
||||
{
|
||||
if(recvqueue(connection_id) != 0)
|
||||
{
|
||||
|
@ -280,7 +311,7 @@ int read_packet(int connection_id, char * data)
|
|||
|
||||
//return 0 if data could not be put in packet queue
|
||||
//return 1 if data was put into the queue
|
||||
int write_packet(int connection_id, char * data, uint32_t length)
|
||||
int write_packet(int connection_id, uint8_t * data, uint32_t length)
|
||||
{
|
||||
if(length > MAX_DATA_SIZE)
|
||||
{
|
||||
|
@ -338,7 +369,7 @@ uint32_t missing_packets(int connection_id, uint32_t * requested)
|
|||
|
||||
int send_handshake(IP_Port ip_port, uint32_t handshake_id1, uint32_t handshake_id2)
|
||||
{
|
||||
char packet[1 + 4 + 4];
|
||||
uint8_t packet[1 + 4 + 4];
|
||||
uint32_t temp;
|
||||
|
||||
packet[0] = 16;
|
||||
|
@ -354,7 +385,7 @@ int send_handshake(IP_Port ip_port, uint32_t handshake_id1, uint32_t handshake_i
|
|||
int send_SYNC(uint32_t connection_id)
|
||||
{
|
||||
|
||||
char packet[(BUFFER_PACKET_NUM*4 + 4 + 4 + 2)];
|
||||
uint8_t packet[(BUFFER_PACKET_NUM*4 + 4 + 4 + 2)];
|
||||
uint16_t index = 0;
|
||||
|
||||
IP_Port ip_port = connections[connection_id].ip_port;
|
||||
|
@ -382,7 +413,7 @@ int send_data_packet(uint32_t connection_id, uint32_t packet_num)
|
|||
{
|
||||
uint32_t index = packet_num % MAX_QUEUE_NUM;
|
||||
uint32_t temp;
|
||||
char packet[1 + 4 + MAX_DATA_SIZE];
|
||||
uint8_t packet[1 + 4 + MAX_DATA_SIZE];
|
||||
packet[0] = 18;
|
||||
temp = htonl(packet_num);
|
||||
memcpy(packet + 1, &temp, 4);
|
||||
|
@ -421,7 +452,7 @@ int send_DATA(uint32_t connection_id)
|
|||
//Packet handling functions
|
||||
//One to handle each type of packets we recieve
|
||||
//return 0 if handled correctly, 1 if packet is bad.
|
||||
int handle_handshake(char * packet, uint32_t length, IP_Port source)
|
||||
int handle_handshake(uint8_t * packet, uint32_t length, IP_Port source)
|
||||
{
|
||||
if(length != (1 + 4 + 4))
|
||||
{
|
||||
|
@ -538,7 +569,7 @@ int handle_SYNC3(int connection_id, uint8_t counter, uint32_t recv_packetnum, ui
|
|||
return 1;
|
||||
}
|
||||
|
||||
int handle_SYNC(char * packet, uint32_t length, IP_Port source)
|
||||
int handle_SYNC(uint8_t * packet, uint32_t length, IP_Port source)
|
||||
{
|
||||
|
||||
if(!SYNC_valid(length))
|
||||
|
@ -578,7 +609,7 @@ int handle_SYNC(char * packet, uint32_t length, IP_Port source)
|
|||
|
||||
//add a packet to the recieved buffer and set the recv_packetnum of the connection to its proper value.
|
||||
//return 1 if data was too big, 0 if not.
|
||||
int add_recv(int connection_id, uint32_t data_num, char * data, uint16_t size)
|
||||
int add_recv(int connection_id, uint32_t data_num, uint8_t * data, uint16_t size)
|
||||
{
|
||||
if(size > MAX_DATA_SIZE)
|
||||
{
|
||||
|
@ -616,7 +647,7 @@ int add_recv(int connection_id, uint32_t data_num, char * data, uint16_t size)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int handle_data(char * packet, uint32_t length, IP_Port source)
|
||||
int handle_data(uint8_t * packet, uint32_t length, IP_Port source)
|
||||
{
|
||||
int connection = getconnection_id(source);
|
||||
|
||||
|
@ -641,7 +672,7 @@ int handle_data(char * packet, uint32_t length, IP_Port source)
|
|||
//END of packet handling functions
|
||||
|
||||
|
||||
int LosslessUDP_handlepacket(char * packet, uint32_t length, IP_Port source)
|
||||
int LosslessUDP_handlepacket(uint8_t * packet, uint32_t length, IP_Port source)
|
||||
{
|
||||
|
||||
switch (packet[0]) {
|
||||
|
@ -681,7 +712,13 @@ void doNew()
|
|||
|
||||
}
|
||||
//kill all timed out connections
|
||||
if( connections[i].status > 0 && (connections[i].last_recv + CONNEXION_TIMEOUT * 1000000UL) < temp_time)
|
||||
if( connections[i].status > 0 && (connections[i].last_recv + CONNEXION_TIMEOUT * 1000000UL) < temp_time &&
|
||||
connections[i].status != 4)
|
||||
{
|
||||
//kill_connection(i);
|
||||
connections[i].status = 4;
|
||||
}
|
||||
if(connections[i].status > 0 && connections[i].killat < temp_time)
|
||||
{
|
||||
kill_connection(i);
|
||||
}
|
||||
|
|
|
@ -41,6 +41,10 @@
|
|||
//if there already was an existing connection to that ip_port return its number.
|
||||
int new_connection(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(IP_Port ip_port);
|
||||
|
||||
//returns an integer corresponding to the next connection in our imcoming connection list
|
||||
//return -1 if there are no new incoming connections in the list.
|
||||
|
@ -51,20 +55,28 @@ int incoming_connection();
|
|||
//return 0 if killed successfully
|
||||
int kill_connection(int connection_id);
|
||||
|
||||
//kill connection in seconds seconds.
|
||||
//return -1 if it can not kill the connection.
|
||||
//return 0 if it will kill it
|
||||
int kill_connection_in(int connection_id, uint32_t seconds);
|
||||
|
||||
//returns the ip_port of the corresponding connection.
|
||||
//return 0 if there is no such connection.
|
||||
IP_Port connection_ip(int connection_id);
|
||||
|
||||
//returns the id of the next packet in the queue
|
||||
//return -1 if no packet in queue
|
||||
char id_packet(int connection_id);
|
||||
|
||||
//return 0 if there is no received data in the buffer.
|
||||
//return length of recieved packet if successful
|
||||
int read_packet(int connection_id, char * data);
|
||||
int read_packet(int connection_id, uint8_t * data);
|
||||
|
||||
|
||||
//return 0 if data could not be put in packet queue
|
||||
//return 1 if data was put into the queue
|
||||
int write_packet(int connection_id, char * data, uint32_t length);
|
||||
int write_packet(int connection_id, uint8_t * data, uint32_t length);
|
||||
|
||||
|
||||
|
||||
//returns the number of packets in the queue waiting to be successfully sent.
|
||||
|
@ -80,6 +92,7 @@ uint32_t recvqueue(int connection_id);
|
|||
//return 1 if attempting handshake
|
||||
//return 2 if handshake is done
|
||||
//return 3 if fully connected
|
||||
//return 4 if timed out and wating to be killed
|
||||
int is_connected(int connection_id);
|
||||
|
||||
|
||||
|
@ -91,6 +104,6 @@ void doLossless_UDP();
|
|||
//if we receive a Lossless_UDP packet we call this function so it can be handled.
|
||||
//Return 0 if packet is handled correctly.
|
||||
//return 1 if it didn't handle the packet or if the packet was shit.
|
||||
int LosslessUDP_handlepacket(char * packet, uint32_t length, IP_Port source);
|
||||
int LosslessUDP_handlepacket(uint8_t * packet, uint32_t length, IP_Port source);
|
||||
|
||||
#endif
|
||||
|
|
622
core/net_crypto.c
Normal file
622
core/net_crypto.c
Normal file
|
@ -0,0 +1,622 @@
|
|||
/* net_crypto.c
|
||||
*
|
||||
* Functions for the core network crypto.
|
||||
* See also: docs/Crypto.txt
|
||||
*
|
||||
* NOTE: This code has to be perfect. We don't mess around with encryption.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "net_crypto.h"
|
||||
|
||||
|
||||
//Our public and secret keys.
|
||||
uint8_t self_public_key[crypto_box_PUBLICKEYBYTES];
|
||||
uint8_t self_secret_key[crypto_box_SECRETKEYBYTES];
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t public_key[crypto_box_PUBLICKEYBYTES];
|
||||
uint8_t recv_nonce[crypto_box_NONCEBYTES];//nonce of recieved packets
|
||||
uint8_t sent_nonce[crypto_box_NONCEBYTES];//nonce of sent packets.
|
||||
uint8_t status;//0 if no connection, 1 we have sent a handshake, 2 if connexion is not confirmed yet
|
||||
//(we have recieved a hanshake but no empty data packet), 3 if the connection is established.
|
||||
//4 if the connection is timed out.
|
||||
uint16_t number; //Lossless_UDP connection number corresponding to this connection.
|
||||
|
||||
}Crypto_Connection;
|
||||
|
||||
#define MAX_CRYPTO_CONNECTIONS 256
|
||||
|
||||
Crypto_Connection crypto_connections[MAX_CRYPTO_CONNECTIONS];
|
||||
|
||||
#define MAX_FRIEND_REQUESTS 32
|
||||
|
||||
//keeps track of the connection numbers for friends request so we can check later if they were sent
|
||||
int outbound_friendrequests[MAX_FRIEND_REQUESTS];
|
||||
|
||||
#define MAX_INCOMING 64
|
||||
|
||||
//keeps track of the connection numbers for friends request so we can check later if they were sent
|
||||
int incoming_connections[MAX_INCOMING];
|
||||
|
||||
//encrypts plain of length length to encrypted of length + 16 using the
|
||||
//public key(32 bytes) of the reciever 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 * nonce, uint8_t * plain, uint32_t length, uint8_t * encrypted)
|
||||
{
|
||||
if(length - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES > MAX_DATA_SIZE || length == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t temp_plain[MAX_DATA_SIZE + crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES] = {0};
|
||||
uint8_t temp_encrypted[MAX_DATA_SIZE + crypto_box_ZEROBYTES];
|
||||
uint8_t zeroes[crypto_box_BOXZEROBYTES] = {0};
|
||||
|
||||
memcpy(temp_plain + crypto_box_ZEROBYTES, plain, length);//pad the message with 32 0 bytes.
|
||||
|
||||
crypto_box(temp_encrypted, temp_plain, length + crypto_box_ZEROBYTES, nonce, public_key, self_secret_key);
|
||||
|
||||
//if encryption is successful the first crypto_box_BOXZEROBYTES of the message will be zero
|
||||
if(memcmp(temp_encrypted, zeroes, crypto_box_BOXZEROBYTES) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
//unpad the encrypted message
|
||||
memcpy(encrypted, temp_encrypted + crypto_box_BOXZEROBYTES, length - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES);
|
||||
return length - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES;
|
||||
}
|
||||
|
||||
//decrypts encrypted of length length to plain of length length - 16 using the
|
||||
//public key(32 bytes) of the sender 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 * nonce, uint8_t * encrypted, uint32_t length, uint8_t * plain)
|
||||
{
|
||||
if(length > MAX_DATA_SIZE || length <= crypto_box_BOXZEROBYTES)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
uint8_t temp_plain[MAX_DATA_SIZE - crypto_box_ZEROBYTES + crypto_box_BOXZEROBYTES];
|
||||
uint8_t temp_encrypted[MAX_DATA_SIZE + crypto_box_ZEROBYTES] = {0};
|
||||
uint8_t zeroes[crypto_box_ZEROBYTES] = {0};
|
||||
|
||||
memcpy(temp_encrypted + crypto_box_BOXZEROBYTES, encrypted, length);//pad the message with 16 0 bytes.
|
||||
|
||||
if(crypto_box_open(temp_plain, temp_encrypted, length + crypto_box_BOXZEROBYTES,
|
||||
nonce, public_key, self_secret_key) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
//if decryption is successful the first crypto_box_ZEROBYTES of the message will be zero
|
||||
if(memcmp(temp_plain, zeroes, crypto_box_ZEROBYTES) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
//unpad the plain message
|
||||
memcpy(plain, temp_plain + crypto_box_ZEROBYTES, length - crypto_box_ZEROBYTES + crypto_box_BOXZEROBYTES);
|
||||
return length - crypto_box_ZEROBYTES + crypto_box_BOXZEROBYTES;
|
||||
}
|
||||
|
||||
//increment the given nonce by 1
|
||||
void increment_nonce(uint8_t * nonce)
|
||||
{
|
||||
uint32_t i;
|
||||
for(i = 0; i < crypto_box_NONCEBYTES; i++)
|
||||
{
|
||||
nonce[i]++;
|
||||
if(nonce[i] != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//fill the given nonce with random bytes.
|
||||
//TODO: make this more optimized
|
||||
void random_nonce(uint8_t * nonce)
|
||||
{
|
||||
uint32_t i;
|
||||
for(i = 0; i < crypto_box_NONCEBYTES; i++)
|
||||
{
|
||||
nonce[i] = random_int() % 256;
|
||||
}
|
||||
}
|
||||
|
||||
//return 0 if there is no received data in the buffer
|
||||
//return -1 if the packet was discarded.
|
||||
//return length of recieved data if successful
|
||||
int read_cryptpacket(int crypt_connection_id, uint8_t * data)
|
||||
{
|
||||
if(crypto_connections[crypt_connection_id].status != 3)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
uint8_t temp_data[MAX_DATA_SIZE];
|
||||
int length = read_packet(crypto_connections[crypt_connection_id].number, temp_data);
|
||||
if(length == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if(temp_data[0] != 3)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
int len = decrypt_data(crypto_connections[crypt_connection_id].public_key,
|
||||
crypto_connections[crypt_connection_id].recv_nonce, temp_data + 1, length - 1, data);
|
||||
if(len != -1)
|
||||
{
|
||||
increment_nonce(crypto_connections[crypt_connection_id].recv_nonce);
|
||||
return len;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//return 0 if data could not be put in packet queue
|
||||
//return 1 if data was put into the queue
|
||||
int write_cryptpacket(int crypt_connection_id, uint8_t * data, uint32_t length)
|
||||
{
|
||||
if(length - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES > MAX_DATA_SIZE - 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if(crypto_connections[crypt_connection_id].status != 3)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
uint8_t temp_data[MAX_DATA_SIZE];
|
||||
int len = encrypt_data(crypto_connections[crypt_connection_id].public_key,
|
||||
crypto_connections[crypt_connection_id].sent_nonce, data, length, temp_data + 1);
|
||||
if(len == -1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
temp_data[0] = 3;
|
||||
if(write_packet(crypto_connections[crypt_connection_id].number, temp_data, len + 1) == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
increment_nonce(crypto_connections[crypt_connection_id].sent_nonce);
|
||||
return 1;
|
||||
}
|
||||
|
||||
//send a friend request to peer with public_key and ip_port.
|
||||
//Data represents the data we send with the friends request.
|
||||
//returns -1 on failure
|
||||
//returns a positive friend request id that can be used later to see if it was sent correctly on success.
|
||||
int send_friendrequest(uint8_t * public_key, IP_Port ip_port, uint8_t * data, uint32_t length)
|
||||
{
|
||||
if(length > MAX_DATA_SIZE - 1 - crypto_box_PUBLICKEYBYTES - crypto_box_NONCEBYTES)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
uint32_t i;
|
||||
for(i = 0; i < MAX_FRIEND_REQUESTS; i++)
|
||||
{
|
||||
if(outbound_friendrequests[i] == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(i == MAX_FRIEND_REQUESTS)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
uint8_t temp_data[MAX_DATA_SIZE];
|
||||
uint8_t nonce[crypto_box_NONCEBYTES];
|
||||
random_nonce(nonce);
|
||||
int len = encrypt_data(public_key, nonce, data, length, 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + temp_data);
|
||||
if(len == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
temp_data[0] = 1;
|
||||
memcpy(temp_data + 1, self_public_key, crypto_box_PUBLICKEYBYTES);
|
||||
memcpy(temp_data + 1 + crypto_box_PUBLICKEYBYTES, nonce, crypto_box_NONCEBYTES);
|
||||
int id = new_connection(ip_port);
|
||||
if(id == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if(write_packet(id, temp_data, len + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES) == 1)
|
||||
{
|
||||
outbound_friendrequests[i] = id;
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//return -1 if failure
|
||||
//return 0 if connection is still trying to send the request.
|
||||
//return 1 if sent correctly
|
||||
//return 2 if connection timed out
|
||||
int check_friendrequest(int friend_request)
|
||||
{
|
||||
if(friend_request < 0 || friend_request > MAX_FRIEND_REQUESTS)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if(outbound_friendrequests[friend_request] == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if(sendqueue(outbound_friendrequests[friend_request]) == 0)
|
||||
{
|
||||
kill_connection(outbound_friendrequests[friend_request]);
|
||||
outbound_friendrequests[friend_request] = -1;
|
||||
return 1;
|
||||
}
|
||||
int status = is_connected(outbound_friendrequests[friend_request]);
|
||||
if(status == 4)
|
||||
{
|
||||
kill_connection(outbound_friendrequests[friend_request]);
|
||||
outbound_friendrequests[friend_request] = -1;
|
||||
return 2;
|
||||
}
|
||||
if(status == 0)
|
||||
{
|
||||
outbound_friendrequests[friend_request] = -1;
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Send a crypto handshake packet containing an encrypted secret nonce to peer with connection_id and public_key
|
||||
//the packet is encrypted with a random nonce which is sent in plain text with the packet
|
||||
int send_cryptohandshake(int connection_id, uint8_t * public_key, uint8_t * secret_nonce)
|
||||
{
|
||||
uint8_t temp_data[MAX_DATA_SIZE];
|
||||
uint8_t nonce[crypto_box_NONCEBYTES];
|
||||
random_nonce(nonce);
|
||||
int len = encrypt_data(public_key, nonce, secret_nonce, crypto_box_NONCEBYTES,
|
||||
1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + temp_data);
|
||||
if(len == -1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
temp_data[0] = 2;
|
||||
memcpy(temp_data + 1, self_public_key, crypto_box_PUBLICKEYBYTES);
|
||||
memcpy(temp_data + 1 + crypto_box_PUBLICKEYBYTES, nonce, crypto_box_NONCEBYTES);
|
||||
return write_packet(connection_id, temp_data, len + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);
|
||||
}
|
||||
|
||||
//Extract secret nonce and public_key from a packet(data) with length length
|
||||
//return 1 if successful
|
||||
//return 0 if failure
|
||||
int handle_cryptohandshake(uint8_t * public_key, uint8_t * secret_nonce, uint8_t * data, uint16_t length)
|
||||
{
|
||||
int pad = (- crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES);
|
||||
if(length != 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + crypto_box_NONCEBYTES + pad)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if(data[0] != 2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
memcpy(public_key, data + 1, crypto_box_PUBLICKEYBYTES);
|
||||
int len = decrypt_data(public_key, data + 1 + crypto_box_PUBLICKEYBYTES,
|
||||
data + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, crypto_box_NONCEBYTES + pad, secret_nonce);
|
||||
if(len != crypto_box_NONCEBYTES)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//puts the public key of the friend if public_key, the data from the request
|
||||
//in data if a friend request was sent to us and returns the length of the data.
|
||||
//return -1 if no valid friend requests.
|
||||
int handle_friendrequest(uint8_t * public_key, uint8_t * data)
|
||||
{
|
||||
uint32_t i;
|
||||
for(i = 0; i < MAX_INCOMING; i++)
|
||||
{
|
||||
if(incoming_connections[i] != -1)
|
||||
{
|
||||
if(id_packet(incoming_connections[i]) == 1)
|
||||
{
|
||||
uint8_t temp_data[MAX_DATA_SIZE];
|
||||
uint16_t len = read_packet(incoming_connections[i], temp_data);
|
||||
if(len > crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + 1
|
||||
- crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES)
|
||||
{
|
||||
memcpy(public_key, temp_data + 1, crypto_box_PUBLICKEYBYTES);
|
||||
uint8_t nonce[crypto_box_NONCEBYTES];
|
||||
memcpy(nonce, temp_data + 1 + crypto_box_PUBLICKEYBYTES, crypto_box_NONCEBYTES);
|
||||
int len1 = decrypt_data(public_key, nonce, temp_data + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES,
|
||||
len - (crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES + 1), data);
|
||||
if(len1 != -1)
|
||||
{
|
||||
kill_connection_in(incoming_connections[i], 1); //conection is useless now, kill it in 1 seconds
|
||||
incoming_connections[i] = -1;
|
||||
return len1;
|
||||
}
|
||||
}
|
||||
kill_connection(incoming_connections[i]); //conection is useless now, kill it.
|
||||
incoming_connections[i] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//Start a secure connection with other peer who has public_key and ip_port
|
||||
//returns -1 if failure
|
||||
//returns crypt_connection_id of the initialized connection if everything went well.
|
||||
int crypto_connect(uint8_t * public_key, IP_Port ip_port)
|
||||
{
|
||||
uint32_t i;
|
||||
if(getconnection_id(ip_port) != -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
for(i = 0; i < MAX_CRYPTO_CONNECTIONS; i++)
|
||||
{
|
||||
if(crypto_connections[i].status == 0)
|
||||
{
|
||||
int id = new_connection(ip_port);
|
||||
if(id == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
crypto_connections[i].number = id;
|
||||
crypto_connections[i].status = 1;
|
||||
random_nonce(crypto_connections[i].recv_nonce);
|
||||
memcpy(crypto_connections[i].public_key, public_key, crypto_box_PUBLICKEYBYTES);
|
||||
if(send_cryptohandshake(id, public_key, crypto_connections[i].recv_nonce) == 1)
|
||||
{
|
||||
increment_nonce(crypto_connections[i].recv_nonce);
|
||||
return i;
|
||||
}
|
||||
return -1;//this should never happen.
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//handle an incoming connection
|
||||
//return -1 if no crypto inbound connection
|
||||
//return incomming connection id (Lossless_UDP one) if there is an incomming crypto connection
|
||||
//Put the public key of the peer in public_key and the secret_nonce from the handshake into secret_nonce
|
||||
//to accept it see: accept_crypto_inbound(...)
|
||||
//to refuse it just call kill_connection(...) on the connection id
|
||||
int crypto_inbound(uint8_t * public_key, uint8_t * secret_nonce)
|
||||
{
|
||||
uint32_t i;
|
||||
for(i = 0; i < MAX_INCOMING; i++)
|
||||
{
|
||||
if(incoming_connections[i] != -1)
|
||||
{
|
||||
if(id_packet(incoming_connections[i]) == 2)
|
||||
{
|
||||
uint8_t temp_data[MAX_DATA_SIZE];
|
||||
uint16_t len = read_packet(incoming_connections[i], temp_data);
|
||||
if(handle_cryptohandshake(public_key, secret_nonce, temp_data, len))
|
||||
{
|
||||
int connection_id = incoming_connections[i];
|
||||
incoming_connections[i] = -1;//remove this connection from the incoming connection list.
|
||||
return connection_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//kill a crypto connection
|
||||
//return 0 if killed successfully
|
||||
//return 1 if there was a problem.
|
||||
int crypto_kill(int crypt_connection_id)
|
||||
{
|
||||
if(crypt_connection_id < 0 || crypt_connection_id >= MAX_CRYPTO_CONNECTIONS)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if(crypto_connections[crypt_connection_id].status != 0)
|
||||
{
|
||||
crypto_connections[crypt_connection_id].status = 0;
|
||||
kill_connection(crypto_connections[crypt_connection_id].number);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//accept an incoming connection using the parameters provided by crypto_inbound
|
||||
//return -1 if not successful
|
||||
//returns the crypt_connection_id if successful
|
||||
int accept_crypto_inbound(int connection_id, uint8_t * public_key, uint8_t * secret_nonce)
|
||||
{
|
||||
uint32_t i;
|
||||
if(connection_id == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
for(i = 0; i < MAX_CRYPTO_CONNECTIONS; i++)
|
||||
{
|
||||
if(crypto_connections[i].status == 0)
|
||||
{
|
||||
crypto_connections[i].number = connection_id;
|
||||
crypto_connections[i].status = 2;
|
||||
random_nonce(crypto_connections[i].recv_nonce);
|
||||
memcpy(crypto_connections[i].sent_nonce, secret_nonce, crypto_box_NONCEBYTES);
|
||||
increment_nonce(crypto_connections[i].sent_nonce);
|
||||
memcpy(crypto_connections[i].public_key, public_key, crypto_box_PUBLICKEYBYTES);
|
||||
if(send_cryptohandshake(connection_id, public_key, crypto_connections[i].recv_nonce) == 1)
|
||||
{
|
||||
increment_nonce(crypto_connections[i].recv_nonce);
|
||||
uint32_t zero = 0;
|
||||
crypto_connections[i].status = 3;//connection status needs to be 3 for write_cryptpacket() to work
|
||||
write_cryptpacket(i, ((uint8_t *)&zero), sizeof(zero));
|
||||
crypto_connections[i].status = 2;//set it to its proper value right after.
|
||||
return i;
|
||||
}
|
||||
return -1;//this should never happen.
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//return 0 if no connection, 1 we have sent a handshake, 2 if connexion is not confirmed yet
|
||||
//(we have recieved a hanshake but no empty data packet), 3 if the connection is established.
|
||||
//4 if the connection is timed out and wating to be killed
|
||||
int is_cryptoconnected(int crypt_connection_id)
|
||||
{
|
||||
if(crypt_connection_id >= 0 && crypt_connection_id < MAX_CRYPTO_CONNECTIONS)
|
||||
{
|
||||
return crypto_connections[crypt_connection_id].status;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//Generate our public and private keys
|
||||
//Only call this function the first time the program starts.
|
||||
void new_keys()
|
||||
{
|
||||
crypto_box_keypair(self_public_key,self_secret_key);
|
||||
}
|
||||
|
||||
//TODO: optimize this
|
||||
//adds an incoming connection to the incoming_connection list.
|
||||
//returns 0 if successful
|
||||
//returns 1 if failure
|
||||
int new_incoming(int id)
|
||||
{
|
||||
uint32_t i;
|
||||
for(i = 0; i < MAX_INCOMING; i++)
|
||||
{
|
||||
if(incoming_connections[i] == -1)
|
||||
{
|
||||
incoming_connections[i] = id;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//TODO: optimize this
|
||||
//handle all new incoming connections.
|
||||
void handle_incomings()
|
||||
{
|
||||
int income;
|
||||
while(1)
|
||||
{
|
||||
income = incoming_connection();
|
||||
if(income == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if(new_incoming(income))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//handle recieved packets for not yet established crypto connections.
|
||||
void recieve_crypto()
|
||||
{
|
||||
uint32_t i;
|
||||
for(i = 0; i < MAX_CRYPTO_CONNECTIONS; i++)
|
||||
{
|
||||
if(crypto_connections[i].status == 1)
|
||||
{
|
||||
if(id_packet(crypto_connections[i].number) == 2)//handle handshake packet.
|
||||
{
|
||||
uint8_t temp_data[MAX_DATA_SIZE];
|
||||
uint8_t secret_nonce[crypto_box_NONCEBYTES];
|
||||
uint8_t public_key[crypto_box_PUBLICKEYBYTES];
|
||||
uint16_t len = read_packet(crypto_connections[i].number, temp_data);
|
||||
if(handle_cryptohandshake(public_key, secret_nonce, temp_data, len))
|
||||
{
|
||||
if(memcmp(public_key, crypto_connections[i].public_key, crypto_box_PUBLICKEYBYTES) == 0)
|
||||
{
|
||||
memcpy(crypto_connections[i].sent_nonce, secret_nonce, crypto_box_NONCEBYTES);
|
||||
increment_nonce(crypto_connections[i].sent_nonce);
|
||||
uint32_t zero = 0;
|
||||
crypto_connections[i].status = 3;//connection status needs to be 3 for write_cryptpacket() to work
|
||||
write_cryptpacket(i, ((uint8_t *)&zero), sizeof(zero));
|
||||
crypto_connections[i].status = 2;//set it to its proper value right after.
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(id_packet(crypto_connections[i].number) != -1)
|
||||
{
|
||||
//This should not happen
|
||||
//kill the connection if it does
|
||||
crypto_kill(crypto_connections[i].number);
|
||||
}
|
||||
|
||||
}
|
||||
if(crypto_connections[i].status == 2)
|
||||
{
|
||||
if(id_packet(crypto_connections[i].number) == 3)
|
||||
{
|
||||
uint8_t temp_data[MAX_DATA_SIZE];
|
||||
uint8_t data[MAX_DATA_SIZE];
|
||||
int length = read_packet(crypto_connections[i].number, temp_data);
|
||||
int len = decrypt_data(crypto_connections[i].public_key,
|
||||
crypto_connections[i].recv_nonce, temp_data + 1, length - 1, data);
|
||||
uint32_t zero = 0;
|
||||
if(len == sizeof(uint32_t) && memcmp(((uint8_t *)&zero), data, sizeof(uint32_t)) == 0)
|
||||
{
|
||||
increment_nonce(crypto_connections[i].recv_nonce);
|
||||
crypto_connections[i].status = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
//This should not happen
|
||||
//kill the connection if it does
|
||||
crypto_kill(crypto_connections[i].number);
|
||||
}
|
||||
}
|
||||
else if(id_packet(crypto_connections[i].number) != -1)
|
||||
{
|
||||
//This should not happen
|
||||
//kill the connection if it does
|
||||
crypto_kill(crypto_connections[i].number);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//run this to (re)initialize net_crypto
|
||||
//sets all the global connection variables to their default values.
|
||||
void initNetCrypto()
|
||||
{
|
||||
memset(crypto_connections, 0 ,sizeof(crypto_connections));
|
||||
memset(outbound_friendrequests, -1 ,sizeof(outbound_friendrequests));
|
||||
memset(incoming_connections, -1 ,sizeof(incoming_connections));
|
||||
}
|
||||
|
||||
void killTimedout()
|
||||
{
|
||||
uint32_t i;
|
||||
for(i = 0; i < MAX_CRYPTO_CONNECTIONS; i++)
|
||||
{
|
||||
if(is_connected(crypto_connections[i].number) == 4)
|
||||
{
|
||||
crypto_connections[i].status = 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//main loop
|
||||
void doNetCrypto()
|
||||
{
|
||||
//TODO:check if friend requests were sent correctly
|
||||
//handle new incoming connections
|
||||
//handle friend requests
|
||||
handle_incomings();
|
||||
recieve_crypto();
|
||||
killTimedout();
|
||||
}
|
108
core/net_crypto.h
Normal file
108
core/net_crypto.h
Normal file
|
@ -0,0 +1,108 @@
|
|||
/* net_crypto.h
|
||||
*
|
||||
* Functions for the core network crypto.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef NET_CRYPTO_H
|
||||
#define NET_CRYPTO_H
|
||||
|
||||
#include "Lossless_UDP.h"
|
||||
|
||||
//TODO: move this to network.h
|
||||
#ifndef WIN32
|
||||
#include "../nacl/build/Linux/include/amd64/crypto_box.h"
|
||||
#endif
|
||||
//Our public key.
|
||||
extern uint8_t self_public_key[crypto_box_PUBLICKEYBYTES];
|
||||
|
||||
|
||||
|
||||
//encrypts plain of length length to encrypted of length + 16 using the
|
||||
//public key(32 bytes) of the reciever 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 * 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 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 * nonce, uint8_t * encrypted, uint32_t length, uint8_t * plain);
|
||||
|
||||
|
||||
//return 0 if there is no received data in the buffer
|
||||
//return -1 if the packet was discarded.
|
||||
//return length of recieved data if successful
|
||||
int read_cryptpacket(int crypt_connection_id, uint8_t * data);
|
||||
|
||||
|
||||
//return 0 if data could not be put in packet queue
|
||||
//return 1 if data was put into the queue
|
||||
int write_cryptpacket(int crypt_connection_id, uint8_t * data, uint32_t length);
|
||||
|
||||
//send a friend request to peer with public_key and ip_port.
|
||||
//Data represents the data we send with the friends request.
|
||||
//returns -1 on failure
|
||||
//returns a positive friend request id that can be used later to see if it was sent correctly on success.
|
||||
int send_friendrequest(uint8_t * public_key, IP_Port ip_port, uint8_t * data, uint32_t length);
|
||||
|
||||
|
||||
//return -1 if failure
|
||||
//return 0 if connection is still trying to send the request.
|
||||
//return 1 if sent correctly
|
||||
//return 2 if connection timed out
|
||||
int check_friendrequest(int friend_request);
|
||||
|
||||
|
||||
//puts the public key of the friend if public_key, the data from the request
|
||||
//in data if a friend request was sent to us and returns the length of the data.
|
||||
//return -1 if no valid friend requests.
|
||||
int handle_friendrequest(uint8_t * public_key, uint8_t * data);
|
||||
|
||||
|
||||
//Start a secure connection with other peer who has public_key and ip_port
|
||||
//returns -1 if failure
|
||||
//returns crypt_connection_id of the initialized connection if everything went well.
|
||||
int crypto_connect(uint8_t * public_key, IP_Port ip_port);
|
||||
|
||||
|
||||
//kill a crypto connection
|
||||
//return 0 if killed successfully
|
||||
//return 1 if there was a problem.
|
||||
int crypto_kill(int crypt_connection_id);
|
||||
|
||||
//handle an incoming connection
|
||||
//return -1 if no crypto inbound connection
|
||||
//return incomming connection id (Lossless_UDP one) if there is an incomming crypto connection
|
||||
//Put the public key of the peer in public_key and the secret_nonce from the handshake into secret_nonce
|
||||
//to accept it see: accept_crypto_inbound(...)
|
||||
//to refuse it just call kill_connection(...) on the connection id
|
||||
int crypto_inbound(uint8_t * public_key, uint8_t * secret_nonce);
|
||||
|
||||
|
||||
//accept an incoming connection using the parameters provided by crypto_inbound
|
||||
//return -1 if not successful
|
||||
//returns the crypt_connection_id if successful
|
||||
int accept_crypto_inbound(int connection_id, uint8_t * public_key, uint8_t * secret_nonce);
|
||||
|
||||
//return 0 if no connection, 1 we have sent a handshake, 2 if connexion is not confirmed yet
|
||||
//(we have recieved a hanshake but no empty data packet), 3 if the connection is established.
|
||||
//4 if the connection is timed out and wating to be killed
|
||||
int is_cryptoconnected(int crypt_connection_id);
|
||||
|
||||
|
||||
//Generate our public and private keys
|
||||
//Only call this function the first time the program starts.
|
||||
void new_keys();
|
||||
|
||||
//run this to (re)initialize net_crypto
|
||||
//sets all the global connection variables to their default values.
|
||||
void initNetCrypto();
|
||||
|
||||
//main loop
|
||||
void doNetCrypto();
|
||||
|
||||
|
||||
#endif
|
|
@ -63,10 +63,10 @@ static int sock;
|
|||
|
||||
//Basic network functions:
|
||||
//Function to send packet(data) of length length to ip_port
|
||||
int sendpacket(IP_Port ip_port, char * data, uint32_t length)
|
||||
int sendpacket(IP_Port ip_port, uint8_t * data, uint32_t length)
|
||||
{
|
||||
ADDR addr = {AF_INET, ip_port.port, ip_port.ip};
|
||||
return sendto(sock, data, length, 0, (struct sockaddr *)&addr, sizeof(addr));
|
||||
return sendto(sock,(char *) data, length, 0, (struct sockaddr *)&addr, sizeof(addr));
|
||||
|
||||
}
|
||||
|
||||
|
@ -74,7 +74,7 @@ int sendpacket(IP_Port ip_port, char * data, uint32_t length)
|
|||
//the packet data into data
|
||||
//the packet length into length.
|
||||
//dump all empty packets.
|
||||
int recievepacket(IP_Port * ip_port, char * data, uint32_t * length)
|
||||
int recievepacket(IP_Port * ip_port, uint8_t * data, uint32_t * length)
|
||||
{
|
||||
ADDR addr;
|
||||
#ifdef WIN32
|
||||
|
@ -82,7 +82,7 @@ int recievepacket(IP_Port * ip_port, char * data, uint32_t * length)
|
|||
#else
|
||||
uint32_t addrlen = sizeof(addr);
|
||||
#endif
|
||||
(*(int32_t *)length) = recvfrom(sock, data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen);
|
||||
(*(int32_t *)length) = recvfrom(sock,(char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen);
|
||||
if(*(int32_t *)length <= 0)
|
||||
{
|
||||
//nothing received
|
||||
|
|
|
@ -95,12 +95,12 @@ uint32_t random_int();
|
|||
//Basic network functions:
|
||||
|
||||
//Function to send packet(data) of length length to ip_port
|
||||
int sendpacket(IP_Port ip_port, char * data, uint32_t length);
|
||||
int sendpacket(IP_Port ip_port, uint8_t * data, uint32_t length);
|
||||
|
||||
//Function to recieve data, ip and port of sender is put into ip_port
|
||||
//the packet data into data
|
||||
//the packet length into length.
|
||||
int recievepacket(IP_Port * ip_port, char * data, uint32_t * length);
|
||||
int recievepacket(IP_Port * ip_port, uint8_t * data, uint32_t * length);
|
||||
|
||||
//initialize networking
|
||||
//bind to ip and port
|
||||
|
|
251
testing/DHT_cryptosendfiletest.c
Normal file
251
testing/DHT_cryptosendfiletest.c
Normal file
|
@ -0,0 +1,251 @@
|
|||
/* DHT cryptosendfiletest
|
||||
*
|
||||
* This program sends or recieves a friend request.
|
||||
*
|
||||
* it also sends the encrypted data from a file to another client.
|
||||
* Receives the file data that that client sends us.
|
||||
*
|
||||
* NOTE: this program simulates 33% packet loss.
|
||||
*
|
||||
* This is how I compile it: gcc -O2 -Wall -o test ../core/Lossless_UDP.c ../core/network.c ../core/net_crypto.c ../core/DHT.c ../nacl/build/Linux/lib/amd64/* DHT_cryptosendfiletest.c
|
||||
*
|
||||
*
|
||||
* Command line arguments are the ip and port of a node (for bootstrapping).
|
||||
*
|
||||
* Saves all received data to: received.txt
|
||||
*
|
||||
* EX: ./test 127.0.0.1 33445 filename.txt
|
||||
*/
|
||||
#include "../core/network.h"
|
||||
#include "../core/DHT.h"
|
||||
#include "../core/net_crypto.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
//Sleep function (x = milliseconds)
|
||||
#ifdef 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 printip(IP_Port ip_port)
|
||||
{
|
||||
printf("\nIP: %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));
|
||||
}
|
||||
|
||||
|
||||
//horrible function from one of my first C programs.
|
||||
//only here because I was too lazy to write a proper one.
|
||||
unsigned char * hex_string_to_bin(char hex_string[])
|
||||
{
|
||||
unsigned char * val = malloc(strlen(hex_string));
|
||||
char * pos = hex_string;
|
||||
int i=0;
|
||||
while(i < strlen(hex_string))
|
||||
{
|
||||
sscanf(pos,"%2hhx",&val[i]);
|
||||
pos+=2;
|
||||
i++;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
uint8_t self_public_key[crypto_box_PUBLICKEYBYTES];
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 4) {
|
||||
printf("usage %s ip port filename(of file to send)\n", argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
new_keys();
|
||||
printf("OUR ID: ");
|
||||
uint32_t i;
|
||||
for(i = 0; i < 32; i++)
|
||||
{
|
||||
if(self_public_key[i] < 16)
|
||||
printf("0");
|
||||
printf("%hhX",self_public_key[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
memcpy(self_client_id, self_public_key, 32);
|
||||
|
||||
char temp_id[128];
|
||||
printf("Enter the client_id of the friend to connect to (32 bytes HEX format):\n");
|
||||
scanf("%s", temp_id);
|
||||
|
||||
uint8_t friend_id[32];
|
||||
memcpy(friend_id, hex_string_to_bin(temp_id), 32);
|
||||
|
||||
|
||||
//memcpy(self_client_id, "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", 32);
|
||||
|
||||
|
||||
addfriend(friend_id);
|
||||
IP_Port friend_ip;
|
||||
int connection = -1;
|
||||
int inconnection = -1;
|
||||
|
||||
uint8_t acceptedfriend_public_key[crypto_box_PUBLICKEYBYTES];
|
||||
int friendrequest = -1;
|
||||
uint8_t request_data[512];
|
||||
|
||||
//initialize networking
|
||||
//bind to ip 0.0.0.0:PORT
|
||||
IP ip;
|
||||
ip.i = 0;
|
||||
init_networking(ip, PORT);
|
||||
initNetCrypto();
|
||||
|
||||
|
||||
|
||||
perror("Initialization");
|
||||
IP_Port bootstrap_ip_port;
|
||||
bootstrap_ip_port.port = htons(atoi(argv[2]));
|
||||
bootstrap_ip_port.ip.i = inet_addr(argv[1]);
|
||||
bootstrap(bootstrap_ip_port);
|
||||
|
||||
IP_Port ip_port;
|
||||
uint8_t data[MAX_UDP_PACKET_SIZE];
|
||||
uint32_t length;
|
||||
|
||||
uint8_t buffer1[128];
|
||||
int read1 = 0;
|
||||
uint8_t buffer2[128];
|
||||
int read2 = 0;
|
||||
FILE *file1 = fopen(argv[3], "rb");
|
||||
if ( file1==NULL ){printf("Error opening file.\n");return 1;}
|
||||
FILE *file2 = fopen("received.txt", "wb");
|
||||
if ( file2==NULL ){return 1;}
|
||||
read1 = fread(buffer1, 1, 128, file1);
|
||||
|
||||
while(1)
|
||||
{
|
||||
|
||||
while(recievepacket(&ip_port, data, &length) != -1)
|
||||
{
|
||||
if(rand() % 3 != 1)//simulate packet loss
|
||||
{
|
||||
if(DHT_handlepacket(data, length, ip_port) && LosslessUDP_handlepacket(data, length, ip_port))
|
||||
{
|
||||
//if packet is not recognized
|
||||
printf("Received unhandled packet with length: %u\n", length);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Received handled packet with length: %u\n", length);
|
||||
}
|
||||
}
|
||||
}
|
||||
friend_ip = getfriendip((uint8_t *)friend_id);
|
||||
if(friend_ip.ip.i != 0)
|
||||
{
|
||||
if(connection == -1 && friendrequest == -1)
|
||||
{
|
||||
printf("Sending friend request to peer:");
|
||||
printip(friend_ip);
|
||||
friendrequest = send_friendrequest(friend_id, friend_ip, "Hello World", 12);
|
||||
//connection = crypto_connect((uint8_t *)friend_id, friend_ip);
|
||||
//connection = new_connection(friend_ip);
|
||||
}
|
||||
if(check_friendrequest(friendrequest) == 1)
|
||||
{
|
||||
printf("Started connecting to friend:");
|
||||
connection = crypto_connect((uint8_t *)friend_id, friend_ip);
|
||||
}
|
||||
}
|
||||
if(inconnection == -1)
|
||||
{
|
||||
uint8_t secret_nonce[crypto_box_NONCEBYTES];
|
||||
uint8_t public_key[crypto_box_PUBLICKEYBYTES];
|
||||
inconnection = crypto_inbound(public_key, secret_nonce);
|
||||
inconnection = accept_crypto_inbound(inconnection, acceptedfriend_public_key, secret_nonce);
|
||||
//inconnection = incoming_connection();
|
||||
if(inconnection != -1)
|
||||
{
|
||||
printf("Someone connected to us:\n");
|
||||
// printip(connection_ip(inconnection));
|
||||
}
|
||||
}
|
||||
if(handle_friendrequest(acceptedfriend_public_key, request_data) > 1)
|
||||
{
|
||||
printf("RECIEVED FRIEND REQUEST: %s\n", request_data);
|
||||
}
|
||||
|
||||
//if someone connected to us write what he sends to a file
|
||||
//also send him our file.
|
||||
if(inconnection != -1)
|
||||
{
|
||||
if(write_cryptpacket(inconnection, buffer1, read1))
|
||||
{
|
||||
printf("Wrote data1.\n");
|
||||
read1 = fread(buffer1, 1, 128, file1);
|
||||
}
|
||||
read2 = read_cryptpacket(inconnection, buffer2);
|
||||
if(read2 != 0)
|
||||
{
|
||||
printf("Received data1.\n");
|
||||
if(!fwrite(buffer2, read2, 1, file2))
|
||||
{
|
||||
printf("file write error1\n");
|
||||
}
|
||||
if(read2 < 128)
|
||||
{
|
||||
printf("Closed file1 %u\n", read2);
|
||||
fclose(file2);
|
||||
}
|
||||
}
|
||||
else if(is_cryptoconnected(inconnection) == 4)//if buffer is empty and the connection timed out.
|
||||
{
|
||||
crypto_kill(inconnection);
|
||||
}
|
||||
}
|
||||
//if we are connected to a friend send him data from the file.
|
||||
//also put what he sends us in a file.
|
||||
if(is_cryptoconnected(connection) >= 3)
|
||||
{
|
||||
if(write_cryptpacket(0, buffer1, read1))
|
||||
{
|
||||
printf("Wrote data2.\n");
|
||||
read1 = fread(buffer1, 1, 128, file1);
|
||||
}
|
||||
read2 = read_cryptpacket(0, buffer2);
|
||||
if(read2 != 0)
|
||||
{
|
||||
printf("Received data2.\n");
|
||||
if(!fwrite(buffer2, read2, 1, file2))
|
||||
{
|
||||
printf("file write error2\n");
|
||||
}
|
||||
if(read2 < 128)
|
||||
{
|
||||
printf("Closed file2 %u\n", read2);
|
||||
fclose(file2);
|
||||
}
|
||||
}
|
||||
else if(is_cryptoconnected(connection) == 4)//if buffer is empty and the connection timed out.
|
||||
{
|
||||
crypto_kill(connection);
|
||||
}
|
||||
}
|
||||
doDHT();
|
||||
doLossless_UDP();
|
||||
doNetCrypto();
|
||||
//print_clientlist();
|
||||
//print_friendlist();
|
||||
//c_sleep(300);
|
||||
c_sleep(1);
|
||||
}
|
||||
|
||||
shutdown_networking();
|
||||
return 0;
|
||||
}
|
|
@ -80,7 +80,7 @@ void print_friendlist()
|
|||
}
|
||||
}
|
||||
|
||||
void printpacket(char * data, uint32_t length, IP_Port ip_port)
|
||||
void printpacket(uint8_t * data, uint32_t length, IP_Port ip_port)
|
||||
{
|
||||
uint32_t i;
|
||||
printf("UNHANDLED PACKET RECEIVED\nLENGTH:%u\nCONTENTS:\n", length);
|
||||
|
@ -102,7 +102,7 @@ int main(int argc, char *argv[])
|
|||
printf("usage %s ip port client_id(of friend to find ip_port of)\n", argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
addfriend(argv[3]);
|
||||
addfriend((uint8_t *)argv[3]);
|
||||
|
||||
//initialize networking
|
||||
//bind to ip 0.0.0.0:PORT
|
||||
|
@ -125,7 +125,7 @@ int main(int argc, char *argv[])
|
|||
bootstrap(bootstrap_ip_port);
|
||||
|
||||
IP_Port ip_port;
|
||||
char data[MAX_UDP_PACKET_SIZE];
|
||||
uint8_t data[MAX_UDP_PACKET_SIZE];
|
||||
uint32_t length;
|
||||
|
||||
while(1)
|
||||
|
|
Loading…
Reference in New Issue
Block a user