diff --git a/core/DHT.c b/core/DHT.c index 5c63146f..d5af3a08 100644 --- a/core/DHT.c +++ b/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: diff --git a/core/DHT.h b/core/DHT.h index 3238191c..be8b8722 100644 --- a/core/DHT.h +++ b/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. diff --git a/core/Lossless_UDP.c b/core/Lossless_UDP.c index bcbfb18a..b249760a 100644 --- a/core/Lossless_UDP.c +++ b/core/Lossless_UDP.c @@ -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); } diff --git a/core/Lossless_UDP.h b/core/Lossless_UDP.h index 8bdeb43e..18224088 100644 --- a/core/Lossless_UDP.h +++ b/core/Lossless_UDP.h @@ -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 diff --git a/core/net_crypto.c b/core/net_crypto.c new file mode 100644 index 00000000..38a72205 --- /dev/null +++ b/core/net_crypto.c @@ -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(); +} diff --git a/core/net_crypto.h b/core/net_crypto.h new file mode 100644 index 00000000..850bcd13 --- /dev/null +++ b/core/net_crypto.h @@ -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 diff --git a/core/network.c b/core/network.c index 601066cd..6b5f9970 100644 --- a/core/network.c +++ b/core/network.c @@ -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 diff --git a/core/network.h b/core/network.h index c8fdce5c..9606d237 100644 --- a/core/network.h +++ b/core/network.h @@ -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 diff --git a/testing/DHT_cryptosendfiletest.c b/testing/DHT_cryptosendfiletest.c new file mode 100644 index 00000000..787e279e --- /dev/null +++ b/testing/DHT_cryptosendfiletest.c @@ -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 + +//Sleep function (x = milliseconds) +#ifdef WIN32 + +#define c_sleep(x) Sleep(1*x) + +#else +#include +#include +#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; +} \ No newline at end of file diff --git a/testing/DHT_test.c b/testing/DHT_test.c index 4c1a9cd8..9100c01a 100644 --- a/testing/DHT_test.c +++ b/testing/DHT_test.c @@ -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)