Some changes to net crypto.

Should fix certain connection issues that sometimes happen.

The dht public key of the peer must be known to create the connection.

If the dht pk of the peer changes when a connection is active, it is
killed to make way for the new one.
This commit is contained in:
irungentoo 2015-04-18 22:14:37 -04:00
parent b4fc0809a7
commit 1a2fa1b7e6
No known key found for this signature in database
GPG Key ID: 10349DC9BED89E98
3 changed files with 139 additions and 178 deletions

View File

@ -160,7 +160,7 @@ int friend_add_tcp_relay(Friend_Connections *fr_c, int friendcon_id, IP_Port ip_
unsigned int i;
uint16_t index = friend_con->tcp_relay_counter;
uint16_t index = friend_con->tcp_relay_counter % FRIEND_MAX_STORED_TCP_RELAYS;
for (i = 0; i < FRIEND_MAX_STORED_TCP_RELAYS; ++i) {
if (friend_con->tcp_relays[i].ip_port.ip.family != 0
@ -169,8 +169,8 @@ int friend_add_tcp_relay(Friend_Connections *fr_c, int friendcon_id, IP_Port ip_
}
}
friend_con->tcp_relays[index % FRIEND_MAX_STORED_TCP_RELAYS].ip_port = ip_port;
memcpy(friend_con->tcp_relays[index % FRIEND_MAX_STORED_TCP_RELAYS].public_key, public_key, crypto_box_PUBLICKEYBYTES);
friend_con->tcp_relays[index].ip_port = ip_port;
memcpy(friend_con->tcp_relays[index].public_key, public_key, crypto_box_PUBLICKEYBYTES);
++friend_con->tcp_relay_counter;
return add_tcp_relay_peer(fr_c->net_crypto, friend_con->crypt_connection_id, ip_port, public_key);
@ -233,20 +233,15 @@ static void dht_ip_callback(void *object, int32_t number, IP_Port ip_port)
friend_con->dht_ip_port_lastrecv = unix_time();
}
/* Callback for dht public key changes. */
static void dht_pk_callback(void *object, int32_t number, const uint8_t *dht_public_key)
static void change_dht_pk(Friend_Connections *fr_c, int friendcon_id, const uint8_t *dht_public_key)
{
Friend_Connections *fr_c = object;
Friend_Conn *friend_con = get_conn(fr_c, number);
Friend_Conn *friend_con = get_conn(fr_c, friendcon_id);
if (!friend_con)
return;
friend_con->dht_pk_lastrecv = unix_time();
if (memcmp(friend_con->dht_temp_pk, dht_public_key, crypto_box_PUBLICKEYBYTES) == 0)
return;
if (friend_con->dht_lock) {
if (DHT_delfriend(fr_c->dht, friend_con->dht_temp_pk, friend_con->dht_lock) != 0) {
printf("a. Could not delete dht peer. Please report this.\n");
@ -256,16 +251,32 @@ static void dht_pk_callback(void *object, int32_t number, const uint8_t *dht_pub
friend_con->dht_lock = 0;
}
DHT_addfriend(fr_c->dht, dht_public_key, dht_ip_callback, object, number, &friend_con->dht_lock);
DHT_addfriend(fr_c->dht, dht_public_key, dht_ip_callback, fr_c, friendcon_id, &friend_con->dht_lock);
memcpy(friend_con->dht_temp_pk, dht_public_key, crypto_box_PUBLICKEYBYTES);
}
if (friend_con->crypt_connection_id == -1) {
friend_new_connection(fr_c, number);
/* Callback for dht public key changes. */
static void dht_pk_callback(void *object, int32_t number, const uint8_t *dht_public_key)
{
Friend_Connections *fr_c = object;
Friend_Conn *friend_con = get_conn(fr_c, number);
if (!friend_con)
return;
if (memcmp(friend_con->dht_temp_pk, dht_public_key, crypto_box_PUBLICKEYBYTES) == 0)
return;
change_dht_pk(fr_c, number, dht_public_key);
/* if pk changed, create a new connection.*/
if (friend_con->crypt_connection_id != -1) {
crypto_kill(fr_c->net_crypto, friend_con->crypt_connection_id);
friend_con->crypt_connection_id = -1;
}
set_connection_dht_public_key(fr_c->net_crypto, friend_con->crypt_connection_id, dht_public_key);
friend_new_connection(fr_c, number);
onion_set_friend_DHT_pubkey(fr_c->onion_c, friend_con->onion_friendnum, dht_public_key);
memcpy(friend_con->dht_temp_pk, dht_public_key, crypto_box_PUBLICKEYBYTES);
}
static int handle_status(void *object, int number, uint8_t status)
@ -385,6 +396,11 @@ static int handle_new_connections(void *object, New_Connection *n_c)
return -1;
int id = accept_crypto_connection(fr_c->net_crypto, n_c);
if (id == -1) {
return -1;
}
connection_status_handler(fr_c->net_crypto, id, &handle_status, fr_c, friendcon_id);
connection_data_handler(fr_c->net_crypto, id, &handle_packet, fr_c, friendcon_id);
connection_lossy_data_handler(fr_c->net_crypto, id, &handle_lossy_packet, fr_c, friendcon_id);
@ -397,7 +413,9 @@ static int handle_new_connections(void *object, New_Connection *n_c)
friend_con->dht_ip_port_lastrecv = unix_time();
}
dht_pk_callback(fr_c, friendcon_id, n_c->dht_public_key);
if (memcmp(friend_con->dht_temp_pk, n_c->dht_public_key, crypto_box_PUBLICKEYBYTES) != 0) {
change_dht_pk(fr_c, friendcon_id, n_c->dht_public_key);
}
nc_dht_pk_callback(fr_c->net_crypto, id, &dht_pk_callback, fr_c, friendcon_id);
return 0;
@ -417,7 +435,12 @@ static int friend_new_connection(Friend_Connections *fr_c, int friendcon_id)
return -1;
}
int id = new_crypto_connection(fr_c->net_crypto, friend_con->real_public_key);
/* If dht_temp_pk does not contains a pk. */
if (!friend_con->dht_lock) {
return -1;
}
int id = new_crypto_connection(fr_c->net_crypto, friend_con->real_public_key, friend_con->dht_temp_pk);
if (id == -1)
return -1;
@ -712,7 +735,6 @@ void do_friend_connections(Friend_Connections *fr_c)
if (friend_con->dht_lock) {
if (friend_new_connection(fr_c, i) == 0) {
set_connection_dht_public_key(fr_c->net_crypto, friend_con->crypt_connection_id, friend_con->dht_temp_pk);
set_direct_ip_port(fr_c->net_crypto, friend_con->crypt_connection_id, friend_con->dht_ip_port);
connect_to_saved_tcp_relays(fr_c, i, (MAX_FRIEND_TCP_CONNECTIONS / 2)); /* Only fill it half up. */
}

View File

@ -35,7 +35,16 @@
static uint8_t crypt_connection_id_not_valid(const Net_Crypto *c, int crypt_connection_id)
{
return (uint32_t)crypt_connection_id >= c->crypto_connections_length;
if ((uint32_t)crypt_connection_id >= c->crypto_connections_length)
return 1;
if (c->crypto_connections == NULL)
return 1;
if (c->crypto_connections[crypt_connection_id].status == CRYPTO_CONN_NO_CONNECTION)
return 1;
return 0;
}
/* cookie timeout in seconds */
@ -1085,13 +1094,26 @@ static int send_kill_packet(Net_Crypto *c, int crypt_connection_id)
&kill_packet, sizeof(kill_packet));
}
static void connection_kill(Net_Crypto *c, int crypt_connection_id)
{
Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);
if (conn == 0)
return;
if (conn->connection_status_callback) {
conn->connection_status_callback(conn->connection_status_callback_object, conn->connection_status_callback_id, 0);
}
crypto_kill(c, crypt_connection_id);
}
/* Handle a received data packet.
*
* return -1 on failure.
* return 0 on success.
*/
static int handle_data_packet_helper(const Net_Crypto *c, int crypt_connection_id, const uint8_t *packet,
uint16_t length)
static int handle_data_packet_helper(Net_Crypto *c, int crypt_connection_id, const uint8_t *packet, uint16_t length)
{
if (length > MAX_CRYPTO_PACKET_SIZE || length <= CRYPTO_DATA_PACKET_MIN_SIZE)
return -1;
@ -1128,7 +1150,7 @@ static int handle_data_packet_helper(const Net_Crypto *c, int crypt_connection_i
}
if (real_data[0] == PACKET_ID_KILL) {
conn->killed = 1;
connection_kill(c, crypt_connection_id);
return 0;
}
@ -1243,20 +1265,20 @@ static int handle_packet_connection(Net_Crypto *c, int crypt_connection_id, cons
packet, length, conn->public_key) != 0)
return -1;
encrypt_precompute(conn->peersessionpublic_key, conn->sessionsecret_key, conn->shared_key);
if (public_key_cmp(dht_public_key, conn->dht_public_key) == 0) {
encrypt_precompute(conn->peersessionpublic_key, conn->sessionsecret_key, conn->shared_key);
if (conn->status == CRYPTO_CONN_COOKIE_REQUESTING) {
if (create_send_handshake(c, crypt_connection_id, cookie, dht_public_key) != 0)
return -1;
if (conn->status == CRYPTO_CONN_COOKIE_REQUESTING) {
if (create_send_handshake(c, crypt_connection_id, cookie, dht_public_key) != 0)
return -1;
}
conn->status = CRYPTO_CONN_NOT_CONFIRMED;
} else {
if (conn->dht_pk_callback)
conn->dht_pk_callback(conn->dht_pk_callback_object, conn->dht_pk_callback_number, dht_public_key);
}
conn->status = CRYPTO_CONN_NOT_CONFIRMED;
/* Status needs to be CRYPTO_CONN_NOT_CONFIRMED for this to work. */
set_connection_dht_public_key(c, crypt_connection_id, dht_public_key);
if (conn->dht_pk_callback)
conn->dht_pk_callback(conn->dht_pk_callback_object, conn->dht_pk_callback_number, dht_public_key);
} else {
return -1;
}
@ -1397,24 +1419,6 @@ static int getcryptconnection_id(const Net_Crypto *c, const uint8_t *public_key)
return -1;
}
/* Get crypto connection id from public key of peer.
*
* return -1 if there are no connections like we are looking for.
* return id if it found it.
*/
static int getcryptconnection_id_dht_pubkey(const Net_Crypto *c, const uint8_t *dht_public_key)
{
uint32_t i;
for (i = 0; i < c->crypto_connections_length; ++i) {
if (c->crypto_connections[i].status != CRYPTO_CONN_NO_CONNECTION && c->crypto_connections[i].dht_public_key_set)
if (memcmp(dht_public_key, c->crypto_connections[i].dht_public_key, crypto_box_PUBLICKEYBYTES) == 0)
return i;
}
return -1;
}
/* Add a source to the crypto connection.
* This is to be used only when we have received a packet from that source.
*
@ -1488,30 +1492,28 @@ static int handle_new_connection_handshake(Net_Crypto *c, IP_Port source, const
int crypt_connection_id = getcryptconnection_id(c, n_c.public_key);
if (crypt_connection_id != -1) {
int ret = -1;
Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);
if (conn != 0 && (conn->status == CRYPTO_CONN_COOKIE_REQUESTING || conn->status == CRYPTO_CONN_HANDSHAKE_SENT)) {
memcpy(conn->recv_nonce, n_c.recv_nonce, crypto_box_NONCEBYTES);
memcpy(conn->peersessionpublic_key, n_c.peersessionpublic_key, crypto_box_PUBLICKEYBYTES);
encrypt_precompute(conn->peersessionpublic_key, conn->sessionsecret_key, conn->shared_key);
if (public_key_cmp(n_c.dht_public_key, conn->dht_public_key) != 0) {
connection_kill(c, crypt_connection_id);
} else {
int ret = -1;
crypto_connection_add_source(c, crypt_connection_id, source);
if (conn && (conn->status == CRYPTO_CONN_COOKIE_REQUESTING || conn->status == CRYPTO_CONN_HANDSHAKE_SENT)) {
memcpy(conn->recv_nonce, n_c.recv_nonce, crypto_box_NONCEBYTES);
memcpy(conn->peersessionpublic_key, n_c.peersessionpublic_key, crypto_box_PUBLICKEYBYTES);
encrypt_precompute(conn->peersessionpublic_key, conn->sessionsecret_key, conn->shared_key);
if (create_send_handshake(c, crypt_connection_id, n_c.cookie, n_c.dht_public_key) == 0) {
conn->status = CRYPTO_CONN_NOT_CONFIRMED;
/* Status needs to be CRYPTO_CONN_NOT_CONFIRMED for this to work. */
set_connection_dht_public_key(c, crypt_connection_id, n_c.dht_public_key);
crypto_connection_add_source(c, crypt_connection_id, source);
if (conn->dht_pk_callback)
conn->dht_pk_callback(conn->dht_pk_callback_object, conn->dht_pk_callback_number, n_c.dht_public_key);
ret = 0;
if (create_send_handshake(c, crypt_connection_id, n_c.cookie, n_c.dht_public_key) == 0) {
ret = 0;
}
}
}
free(n_c.cookie);
return ret;
free(n_c.cookie);
return ret;
}
}
int ret = c->new_connection_callback(c->new_connection_callback_object, &n_c);
@ -1534,28 +1536,33 @@ int accept_crypto_connection(Net_Crypto *c, New_Connection *n_c)
if (crypt_connection_id == -1)
return -1;
Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);
Crypto_Connection *conn = &c->crypto_connections[crypt_connection_id];
if (conn == 0)
if (n_c->cookie_length != COOKIE_LENGTH)
return -1;
pthread_mutex_lock(&c->tcp_mutex);
conn->connection_number_tcp = new_tcp_connection_to(c->tcp_c, n_c->dht_public_key, crypt_connection_id);
pthread_mutex_unlock(&c->tcp_mutex);
if (conn->connection_number_tcp == -1)
return -1;
conn->connection_number_tcp = -1;
memcpy(conn->public_key, n_c->public_key, crypto_box_PUBLICKEYBYTES);
memcpy(conn->recv_nonce, n_c->recv_nonce, crypto_box_NONCEBYTES);
memcpy(conn->peersessionpublic_key, n_c->peersessionpublic_key, crypto_box_PUBLICKEYBYTES);
random_nonce(conn->sent_nonce);
crypto_box_keypair(conn->sessionpublic_key, conn->sessionsecret_key);
encrypt_precompute(conn->peersessionpublic_key, conn->sessionsecret_key, conn->shared_key);
if (n_c->cookie_length != COOKIE_LENGTH)
return -1;
if (create_send_handshake(c, crypt_connection_id, n_c->cookie, n_c->dht_public_key) != 0)
return -1;
conn->status = CRYPTO_CONN_NOT_CONFIRMED;
/* Status needs to be CRYPTO_CONN_NOT_CONFIRMED for this to work. */
set_connection_dht_public_key(c, crypt_connection_id, n_c->dht_public_key);
if (create_send_handshake(c, crypt_connection_id, n_c->cookie, n_c->dht_public_key) != 0) {
pthread_mutex_lock(&c->tcp_mutex);
kill_tcp_connection_to(c->tcp_c, conn->connection_number_tcp);
pthread_mutex_unlock(&c->tcp_mutex);
return -1;
}
memcpy(conn->dht_public_key, n_c->dht_public_key, crypto_box_PUBLICKEYBYTES);
conn->packet_send_rate = CRYPTO_PACKET_MIN_RATE;
conn->packets_left = CRYPTO_MIN_QUEUE_LENGTH;
crypto_connection_add_source(c, crypt_connection_id, n_c->source);
@ -1568,7 +1575,7 @@ int accept_crypto_connection(Net_Crypto *c, New_Connection *n_c)
* return -1 on failure.
* return connection id on success.
*/
int new_crypto_connection(Net_Crypto *c, const uint8_t *real_public_key)
int new_crypto_connection(Net_Crypto *c, const uint8_t *real_public_key, const uint8_t *dht_public_key)
{
int crypt_connection_id = getcryptconnection_id(c, real_public_key);
@ -1580,82 +1587,40 @@ int new_crypto_connection(Net_Crypto *c, const uint8_t *real_public_key)
if (crypt_connection_id == -1)
return -1;
Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);
Crypto_Connection *conn = &c->crypto_connections[crypt_connection_id];
if (conn == 0)
return -1;
conn->connection_number_tcp = -1;
pthread_mutex_lock(&c->tcp_mutex);
conn->connection_number_tcp = new_tcp_connection_to(c->tcp_c, dht_public_key, crypt_connection_id);
pthread_mutex_unlock(&c->tcp_mutex);
if (conn->connection_number_tcp == -1)
return -1;
memcpy(conn->public_key, real_public_key, crypto_box_PUBLICKEYBYTES);
random_nonce(conn->sent_nonce);
crypto_box_keypair(conn->sessionpublic_key, conn->sessionsecret_key);
conn->status = CRYPTO_CONN_COOKIE_REQUESTING;
conn->packet_send_rate = CRYPTO_PACKET_MIN_RATE;
conn->packets_left = CRYPTO_MIN_QUEUE_LENGTH;
return crypt_connection_id;
}
memcpy(conn->dht_public_key, dht_public_key, crypto_box_PUBLICKEYBYTES);
/* Copy friends DHT public key into dht_key.
*
* return 0 on failure (no key copied).
* return 1 on success (key copied).
*/
unsigned int get_connection_dht_key(const Net_Crypto *c, int crypt_connection_id, uint8_t *dht_public_key)
{
Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);
conn->cookie_request_number = random_64b();
uint8_t cookie_request[COOKIE_REQUEST_LENGTH];
if (conn == 0)
return 0;
if (conn->dht_public_key_set == 0)
return 0;
memcpy(dht_public_key, conn->dht_public_key, crypto_box_PUBLICKEYBYTES);
return 1;
}
/* Set the DHT public key of the crypto connection.
*
* return -1 on failure.
* return 0 on success.
*/
int set_connection_dht_public_key(Net_Crypto *c, int crypt_connection_id, const uint8_t *dht_public_key)
{
Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id);
if (conn == 0)
return -1;
if (conn->dht_public_key_set == 1 && memcmp(conn->dht_public_key, dht_public_key, crypto_box_PUBLICKEYBYTES) == 0)
return -1;
if (conn->dht_public_key_set == 1) {
if (create_cookie_request(c, cookie_request, conn->dht_public_key, conn->cookie_request_number,
conn->shared_key) != sizeof(cookie_request)
|| new_temp_packet(c, crypt_connection_id, cookie_request, sizeof(cookie_request)) != 0) {
pthread_mutex_lock(&c->tcp_mutex);
kill_tcp_connection_to(c->tcp_c, conn->connection_number_tcp);
pthread_mutex_unlock(&c->tcp_mutex);
conn->connection_number_tcp = -1;
conn->status = CRYPTO_CONN_NO_CONNECTION;
return -1;
}
memcpy(conn->dht_public_key, dht_public_key, crypto_box_PUBLICKEYBYTES);
conn->dht_public_key_set = 1;
if (conn->status == CRYPTO_CONN_COOKIE_REQUESTING) {
conn->cookie_request_number = random_64b();
uint8_t cookie_request[COOKIE_REQUEST_LENGTH];
if (create_cookie_request(c, cookie_request, conn->dht_public_key, conn->cookie_request_number,
conn->shared_key) != sizeof(cookie_request))
return -1;
if (new_temp_packet(c, crypt_connection_id, cookie_request, sizeof(cookie_request)) != 0)
return -1;
}//TODO
pthread_mutex_lock(&c->tcp_mutex);
conn->connection_number_tcp = new_tcp_connection_to(c->tcp_c, conn->dht_public_key, crypt_connection_id);
pthread_mutex_unlock(&c->tcp_mutex);
return 0;
return crypt_connection_id;
}
/* Set the direct ip of the crypto connection.
@ -1899,8 +1864,10 @@ int connection_lossy_data_handler(Net_Crypto *c, int crypt_connection_id,
}
/* Set the function for this friend that will be callbacked with object and number
* when that friend gives us his DHT temporary public key.
/* Set the function for this friend that will be callbacked with object and number if
* the friend sends us a different dht public key than we have associated to him.
*
* If this function is called, the connection should be recreated with the new public key.
*
* object and number will be passed as argument to this function.
*
@ -2391,7 +2358,7 @@ static void kill_timedout(Net_Crypto *c)
if (conn == 0)
return;
if (conn->status == CRYPTO_CONN_NO_CONNECTION || conn->status == CRYPTO_CONN_TIMED_OUT)
if (conn->status == CRYPTO_CONN_NO_CONNECTION)
continue;
if (conn->status == CRYPTO_CONN_COOKIE_REQUESTING || conn->status == CRYPTO_CONN_HANDSHAKE_SENT
@ -2399,21 +2366,10 @@ static void kill_timedout(Net_Crypto *c)
if (conn->temp_packet_num_sent < MAX_NUM_SENDPACKET_TRIES)
continue;
conn->killed = 1;
connection_kill(c, i);
}
if (conn->killed) {
if (conn->connection_status_callback) {
conn->connection_status_callback(conn->connection_status_callback_object, conn->connection_status_callback_id, 0);
crypto_kill(c, i);
continue;
}
conn->status = CRYPTO_CONN_TIMED_OUT;
continue;
}
if (conn->status == CRYPTO_CONN_ESTABLISHED) {
//TODO: add a timeout here?
}

View File

@ -34,7 +34,6 @@
#define CRYPTO_CONN_HANDSHAKE_SENT 2 //send handshake packets
#define CRYPTO_CONN_NOT_CONFIRMED 3 //send handshake packets, we have received one from the other
#define CRYPTO_CONN_ESTABLISHED 4
#define CRYPTO_CONN_TIMED_OUT 5
/* Maximum size of receiving and sending packet buffers. */
#define CRYPTO_PACKET_BUFFER_SIZE 16384 /* Must be a power of 2 */
@ -107,11 +106,9 @@ typedef struct {
* 2 if we are sending handshake packets
* 3 if connection is not confirmed yet (we have received a handshake but no data packets yet),
* 4 if the connection is established.
* 5 if the connection is timed out.
*/
uint64_t cookie_request_number; /* number used in the cookie request packets for this connection */
uint8_t dht_public_key[crypto_box_PUBLICKEYBYTES]; /* The dht public key of the peer */
uint8_t dht_public_key_set; /* True if the dht public key is set, false if it isn't. */
uint8_t *temp_packet; /* Where the cookie request/handshake packet is stored while it is being sent. */
uint16_t temp_packet_length;
@ -150,8 +147,6 @@ typedef struct {
long signed int last_num_packets_sent[CONGESTION_QUEUE_ARRAY_SIZE];
uint32_t packets_sent;
uint8_t killed; /* set to 1 to kill the connection. */
/* TCP_connection connection_number */
unsigned int connection_number_tcp;
@ -225,21 +220,7 @@ int accept_crypto_connection(Net_Crypto *c, New_Connection *n_c);
* return -1 on failure.
* return connection id on success.
*/
int new_crypto_connection(Net_Crypto *c, const uint8_t *real_public_key);
/* Copy friends DHT public key into dht_key.
*
* return 0 on failure (no key copied).
* return 1 on success (key copied).
*/
unsigned int get_connection_dht_key(const Net_Crypto *c, int crypt_connection_id, uint8_t *dht_public_key);
/* Set the DHT public key of the crypto connection.
*
* return -1 on failure.
* return 0 on success.
*/
int set_connection_dht_public_key(Net_Crypto *c, int crypt_connection_id, const uint8_t *dht_public_key);
int new_crypto_connection(Net_Crypto *c, const uint8_t *real_public_key, const uint8_t *dht_public_key);
/* Set the direct ip of the crypto connection.
*
@ -285,8 +266,10 @@ int connection_lossy_data_handler(Net_Crypto *c, int crypt_connection_id,
int (*connection_lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length), void *object,
int id);
/* Set the function for this friend that will be callbacked with object and number
* when that friend gives us his DHT temporary public key.
/* Set the function for this friend that will be callbacked with object and number if
* the friend sends us a different dht public key than we have associated to him.
*
* If this function is called, the connection should be recreated with the new public key.
*
* object and number will be passed as argument to this function.
*