Merge upstream fo real now?

This commit is contained in:
mannol 2014-05-20 00:27:02 +02:00
commit c9f1c6882d
24 changed files with 2142 additions and 172 deletions

View File

@ -9,6 +9,7 @@ With the rise of governmental monitoring programs, Tox, a FOSS initiative, aims
## The Complex Stuff:
### UDP vs. TCP
Tox must use UDP simply because [hole punching](http://en.wikipedia.org/wiki/UDP_hole_punching) with TCP is not as reliable.
However, Tox does use [TCP relays](https://github.com/irungentoo/ProjectTox-Core/blob/master/docs/TCP_Network.txt) as a fallback if it encounters a firewall that prevents UDP hole punching.
### Connecting & Communicating
Every peer is represented as a [byte string][String] (the public key [Tox ID] of the peer). By using torrent-style DHT, peers can find the IP of other peers by using their Tox ID. Once the IP is obtained, peers can initiate a [secure](https://github.com/irungentoo/ProjectTox-Core/wiki/Crypto) connection with each other. Once the connection is made, peers can exchange messages, send files, start video chats, etc. using encrypted communications.

View File

@ -89,7 +89,7 @@ START_TEST(test_basic)
uint8_t r_req[2 + 1 + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES];
uint16_t size = 1 + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES;
size = htons(size);
ret = encrypt_data_fast(f_shared_key, f_nonce, r_req_p, 1 + crypto_box_PUBLICKEYBYTES, r_req + 2);
ret = encrypt_data_symmetric(f_shared_key, f_nonce, r_req_p, 1 + crypto_box_PUBLICKEYBYTES, r_req + 2);
increment_nonce(f_nonce);
memcpy(r_req, &size, 2);
uint32_t i;
@ -110,7 +110,7 @@ START_TEST(test_basic)
memcpy(&size, packet_resp, 2);
ck_assert_msg(ntohs(size) == 2 + crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES, "Wrong packet size.");
uint8_t packet_resp_plain[4096];
ret = decrypt_data_fast(f_shared_key, f_nonce_r, packet_resp + 2, recv_data_len - 2, packet_resp_plain);
ret = decrypt_data_symmetric(f_shared_key, f_nonce_r, packet_resp + 2, recv_data_len - 2, packet_resp_plain);
ck_assert_msg(ret != -1, "decryption failed");
increment_nonce(f_nonce_r);
ck_assert_msg(packet_resp_plain[0] == 1, "wrong packet id %u", packet_resp_plain[0]);
@ -179,7 +179,7 @@ int write_packet_TCP_secure_connection(struct sec_TCP_con *con, uint8_t *data, u
uint16_t c_length = htons(length + crypto_box_MACBYTES);
memcpy(packet, &c_length, sizeof(uint16_t));
int len = encrypt_data_fast(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t));
int len = encrypt_data_symmetric(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t));
if ((unsigned int)len != (sizeof(packet) - sizeof(uint16_t)))
return -1;
@ -194,7 +194,7 @@ int read_packet_sec_TCP(struct sec_TCP_con *con, uint8_t *data, uint16_t length)
{
int len;
ck_assert_msg((len = recv(con->sock, data, length, 0)) == length, "wrong len %i\n", len);
ck_assert_msg((len = decrypt_data_fast(con->shared_key, con->recv_nonce, data + 2, length - 2, data)) != -1,
ck_assert_msg((len = decrypt_data_symmetric(con->shared_key, con->recv_nonce, data + 2, length - 2, data)) != -1,
"Decrypt failed");
increment_nonce(con->recv_nonce);
return len;
@ -291,6 +291,76 @@ START_TEST(test_some)
}
END_TEST
static int response_callback_good;
static uint8_t response_callback_connection_id;
static uint8_t response_callback_public_key[crypto_box_PUBLICKEYBYTES];
static int response_callback(void *object, uint8_t connection_id, uint8_t *public_key)
{
if (set_tcp_connection_number(object - 2, connection_id, 7) != 0)
return 1;
response_callback_connection_id = connection_id;
memcpy(response_callback_public_key, public_key, crypto_box_PUBLICKEYBYTES);
response_callback_good++;
return 0;
}
static int status_callback_good;
static uint8_t status_callback_connection_id;
static uint8_t status_callback_status;
static int status_callback(void *object, uint32_t number, uint8_t connection_id, uint8_t status)
{
if (object != (void *)2)
return 1;
if (number != 7)
return 1;
status_callback_connection_id = connection_id;
status_callback_status = status;
status_callback_good++;
return 0;
}
static int data_callback_good;
static int data_callback(void *object, uint32_t number, uint8_t connection_id, uint8_t *data, uint16_t length)
{
if (object != (void *)3)
return 1;
if (number != 7)
return 1;
if (length != 5)
return 1;
if (data[0] == 1 && data[1] == 2 && data[2] == 3 && data[3] == 4 && data[4] == 5) {
data_callback_good++;
return 0;
}
return 1;
}
static int oob_data_callback_good;
static uint8_t oob_pubkey[crypto_box_PUBLICKEYBYTES];
static int oob_data_callback(void *object, uint8_t *public_key, uint8_t *data, uint16_t length)
{
if (object != (void *)4)
return 1;
if (length != 5)
return 1;
if (memcmp(public_key, oob_pubkey, crypto_box_PUBLICKEYBYTES) != 0)
return 1;
if (data[0] == 1 && data[1] == 2 && data[2] == 3 && data[3] == 4 && data[4] == 5) {
oob_data_callback_good++;
return 0;
}
return 1;
}
START_TEST(test_client)
{
unix_time_update();
@ -320,6 +390,71 @@ START_TEST(test_client)
do_TCP_connection(conn);
ck_assert_msg(conn->status == TCP_CLIENT_CONFIRMED, "Wrong status. Expected: %u, is: %u", TCP_CLIENT_CONFIRMED,
conn->status);
c_sleep(500);
do_TCP_connection(conn);
ck_assert_msg(conn->status == TCP_CLIENT_CONFIRMED, "Wrong status. Expected: %u, is: %u", TCP_CLIENT_CONFIRMED,
conn->status);
c_sleep(500);
do_TCP_connection(conn);
ck_assert_msg(conn->status == TCP_CLIENT_CONFIRMED, "Wrong status. Expected: %u, is: %u", TCP_CLIENT_CONFIRMED,
conn->status);
do_TCP_server(tcp_s);
c_sleep(50);
ck_assert_msg(conn->status == TCP_CLIENT_CONFIRMED, "Wrong status. Expected: %u, is: %u", TCP_CLIENT_CONFIRMED,
conn->status);
uint8_t f2_public_key[crypto_box_PUBLICKEYBYTES];
uint8_t f2_secret_key[crypto_box_SECRETKEYBYTES];
crypto_box_keypair(f2_public_key, f2_secret_key);
TCP_Client_Connection *conn2 = new_TCP_connection(ip_port_tcp_s, self_public_key, f2_public_key, f2_secret_key);
routing_response_handler(conn, response_callback, ((void *)conn) + 2);
routing_status_handler(conn, status_callback, (void *)2);
routing_data_handler(conn, data_callback, (void *)3);
oob_data_handler(conn, oob_data_callback, (void *)4);
oob_data_callback_good = response_callback_good = status_callback_good = data_callback_good = 0;
c_sleep(50);
do_TCP_connection(conn);
do_TCP_connection(conn2);
c_sleep(50);
do_TCP_server(tcp_s);
c_sleep(50);
do_TCP_connection(conn);
do_TCP_connection(conn2);
c_sleep(50);
uint8_t data[5] = {1, 2, 3, 4, 5};
memcpy(oob_pubkey, f2_public_key, crypto_box_PUBLICKEYBYTES);
send_oob_packet(conn2, f_public_key, data, 5);
send_routing_request(conn, f2_public_key);
send_routing_request(conn2, f_public_key);
c_sleep(50);
do_TCP_server(tcp_s);
c_sleep(50);
do_TCP_connection(conn);
do_TCP_connection(conn2);
ck_assert_msg(oob_data_callback_good == 1, "oob callback not called");
ck_assert_msg(response_callback_good == 1, "response callback not called");
ck_assert_msg(memcmp(response_callback_public_key, f2_public_key, crypto_box_PUBLICKEYBYTES) == 0, "wrong public key");
ck_assert_msg(status_callback_good == 1, "status callback not called");
ck_assert_msg(status_callback_status == 2, "wrong status");
ck_assert_msg(status_callback_connection_id == response_callback_connection_id, "connection ids not equal");
c_sleep(50);
do_TCP_server(tcp_s);
ck_assert_msg(send_data(conn2, 0, data, 5) == 1, "send data failed");
c_sleep(50);
do_TCP_server(tcp_s);
c_sleep(50);
do_TCP_connection(conn);
do_TCP_connection(conn2);
ck_assert_msg(data_callback_good == 1, "data callback not called");
status_callback_good = 0;
send_disconnect_request(conn2, 0);
c_sleep(50);
do_TCP_server(tcp_s);
c_sleep(50);
do_TCP_connection(conn);
do_TCP_connection(conn2);
ck_assert_msg(status_callback_good == 1, "status callback not called");
ck_assert_msg(status_callback_status == 1, "wrong status");
}
END_TEST

View File

@ -9,12 +9,6 @@
#include <check.h>
#include <stdlib.h>
#include <time.h>
#ifndef VANILLA_NACL
#include <sodium.h>
#else
#include <crypto_box.h>
#define crypto_box_MACBYTES (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES)
#endif
void rand_bytes(uint8_t *b, size_t blen)
{
@ -126,12 +120,12 @@ START_TEST(test_fast_known)
ck_assert_msg(sizeof(test_c) == sizeof(c), "sanity check failed");
ck_assert_msg(sizeof(test_m) == sizeof(m), "sanity check failed");
clen = encrypt_data_fast(k, nonce, test_m, sizeof(test_m) / sizeof(unsigned char), c);
clen = encrypt_data_symmetric(k, nonce, test_m, sizeof(test_m) / sizeof(unsigned char), c);
ck_assert_msg(memcmp(test_c, c, sizeof(c)) == 0, "cyphertext doesn't match test vector");
ck_assert_msg(clen == sizeof(c) / sizeof(unsigned char), "wrong ciphertext length");
mlen = decrypt_data_fast(k, nonce, test_c, sizeof(test_c) / sizeof(unsigned char), m);
mlen = decrypt_data_symmetric(k, nonce, test_c, sizeof(test_c) / sizeof(unsigned char), m);
ck_assert_msg(memcmp(test_m, m, sizeof(m)) == 0, "decrypted text doesn't match test vector");
ck_assert_msg(mlen == sizeof(m) / sizeof(unsigned char), "wrong plaintext length");
@ -186,8 +180,8 @@ START_TEST(test_endtoend)
//Encrypt all four ways
c1len = encrypt_data(pk2, sk1, n, m, mlen, c1);
c2len = encrypt_data(pk1, sk2, n, m, mlen, c2);
c3len = encrypt_data_fast(k1, n, m, mlen, c3);
c4len = encrypt_data_fast(k2, n, m, mlen, c4);
c3len = encrypt_data_symmetric(k1, n, m, mlen, c3);
c4len = encrypt_data_symmetric(k2, n, m, mlen, c4);
ck_assert_msg(c1len == c2len && c1len == c3len && c1len == c4len, "cyphertext lengths differ");
ck_assert_msg(c1len == mlen + (int)crypto_box_MACBYTES, "wrong cyphertext length");
@ -197,8 +191,8 @@ START_TEST(test_endtoend)
//Decrypt all four ways
m1len = decrypt_data(pk2, sk1, n, c1, c1len, m1);
m2len = decrypt_data(pk1, sk2, n, c1, c1len, m2);
m3len = decrypt_data_fast(k1, n, c1, c1len, m3);
m4len = decrypt_data_fast(k2, n, c1, c1len, m4);
m3len = decrypt_data_symmetric(k1, n, c1, c1len, m3);
m4len = decrypt_data_symmetric(k2, n, c1, c1len, m4);
ck_assert_msg(m1len == m2len && m1len == m3len && m1len == m4len, "decrypted text lengths differ");
ck_assert_msg(m1len == mlen, "wrong decrypted text length");
@ -215,11 +209,11 @@ START_TEST(test_large_data)
unsigned char n[crypto_box_NONCEBYTES];
unsigned char m1[MAX_DATA_SIZE - crypto_box_MACBYTES];
unsigned char m1[MAX_CRYPTO_PACKET_SIZE - crypto_box_MACBYTES];
unsigned char c1[sizeof(m1) + crypto_box_MACBYTES];
unsigned char m1prime[sizeof(m1)];
unsigned char m2[MAX_DATA_SIZE];
unsigned char m2[MAX_CRYPTO_PACKET_SIZE];
unsigned char c2[sizeof(m2) + crypto_box_MACBYTES];
int c1len, c2len;
@ -233,13 +227,13 @@ START_TEST(test_large_data)
//Generate key
rand_bytes(k, crypto_box_BEFORENMBYTES);
c1len = encrypt_data_fast(k, n, m1, sizeof(m1), c1);
c2len = encrypt_data_fast(k, n, m2, sizeof(m2), c2);
c1len = encrypt_data_symmetric(k, n, m1, sizeof(m1), c1);
c2len = encrypt_data_symmetric(k, n, m2, sizeof(m2), c2);
ck_assert_msg(c1len == sizeof(m1) + crypto_box_MACBYTES, "could not encrypt max size");
ck_assert_msg(c2len == -1, "incorrectly succeeded encrypting massive size");
ck_assert_msg(c1len == sizeof(m1) + crypto_box_MACBYTES, "could not encrypt");
ck_assert_msg(c2len == sizeof(m2) + crypto_box_MACBYTES, "could not encrypt");
m1plen = decrypt_data_fast(k, n, c1, c1len, m1prime);
m1plen = decrypt_data_symmetric(k, n, c1, c1len, m1prime);
ck_assert_msg(m1plen == sizeof(m1), "decrypted text lengths differ");
ck_assert_msg(memcmp(m1prime, m1, sizeof(m1)) == 0, "decrypted texts differ");
@ -248,9 +242,9 @@ END_TEST
START_TEST(test_large_data_symmetric)
{
unsigned char k[crypto_secretbox_KEYBYTES];
unsigned char k[crypto_box_KEYBYTES];
unsigned char n[crypto_secretbox_NONCEBYTES];
unsigned char n[crypto_box_NONCEBYTES];
unsigned char m1[16 * 16 * 16];
unsigned char c1[sizeof(m1) + crypto_box_MACBYTES];
@ -276,6 +270,7 @@ START_TEST(test_large_data_symmetric)
}
END_TEST
#define DEFTESTCASE(NAME) \
TCase *NAME = tcase_create(#NAME); \
tcase_add_test(NAME, test_##NAME); \

View File

@ -16,7 +16,6 @@
#include "../testing/misc_tools.c" // hex_string_to_bin
#include "../toxcore/Messenger.h"
#include "../toxcore/Lossless_UDP.h"
#include <sys/types.h>
#include <stdint.h>
#include <string.h>
@ -46,7 +45,7 @@ START_TEST(test_m_sendmesage)
{
char *message = "h-hi :3";
int good_len = strlen(message);
int bad_len = MAX_DATA_SIZE;
int bad_len = MAX_CRYPTO_PACKET_SIZE;
ck_assert(m_sendmessage(m, -1, (uint8_t *)message, good_len) == 0);
@ -127,7 +126,7 @@ START_TEST(test_m_addfriend)
int good_len = strlen(good_data);
int bad_len = strlen(bad_data);
int really_bad_len = (MAX_DATA_SIZE - crypto_box_PUBLICKEYBYTES
int really_bad_len = (MAX_CRYPTO_PACKET_SIZE - crypto_box_PUBLICKEYBYTES
- crypto_box_NONCEBYTES - crypto_box_BOXZEROBYTES
+ crypto_box_ZEROBYTES + 100); */
/* TODO: Update this properly to latest master
@ -299,27 +298,6 @@ START_TEST(test_messenger_state_saveloadsave)
}
END_TEST
START_TEST(test_messenger_state_saveload_encrypted)
{
uint8_t addr[FRIEND_ADDRESS_SIZE];
getaddress(m, addr);
Messenger *m_temp = new_messenger(TOX_ENABLE_IPV6_DEFAULT);
size_t size = messenger_size_encrypted(m);
uint8_t buffer[size];
messenger_save_encrypted(m, buffer, "Gentoo", sizeof("Gentoo"));
ck_assert_msg(messenger_load_encrypted(m_temp, buffer, size, "Ubuntu", sizeof("Ubuntu")) == -1,
"Bad password didn't make the function fail.");
ck_assert_msg(messenger_load_encrypted(m_temp, buffer, size, "Gentoo", sizeof("Gentoo")) == 0,
"Good password didn't make the function succeed.");
uint8_t addr1[FRIEND_ADDRESS_SIZE];
getaddress(m_temp, addr1);
ck_assert_msg(memcmp(addr1, addr, FRIEND_ADDRESS_SIZE) == 0, "Didn't load messenger successfully");
kill_messenger(m_temp);
}
END_TEST
#define DEFTESTCASE(NAME) \
TCase *tc_##NAME = tcase_create(#NAME); \
tcase_add_test(tc_##NAME, test_##NAME); \
@ -331,7 +309,6 @@ Suite *messenger_suite(void)
DEFTESTCASE(dht_state_saveloadsave);
DEFTESTCASE(messenger_state_saveloadsave);
DEFTESTCASE(messenger_state_saveload_encrypted);
DEFTESTCASE(getself_name);
DEFTESTCASE(m_get_userstatus_size);

View File

@ -136,9 +136,8 @@ START_TEST(test_struct_sizes)
{
ck_assert_msg(sizeof(IP4) == 4, "sizeof(IP4): expected result 4, got %u.", sizeof(IP4));
ck_assert_msg(sizeof(IP6) == 16, "sizeof(IP6): expected result 16, got %u.", sizeof(IP6));
ck_assert_msg(sizeof(IP) == 20, "sizeof(IP): expected result 20, got %u.", sizeof(IP));
ck_assert_msg(sizeof(IP_Port) == 24, "sizeof(IP_Port): expected result 24, got %u.", sizeof(IP_Port));
ck_assert_msg(sizeof(IP4_Port) == 8, "sizeof(IP4_Port): expected result 8, got %u.", sizeof(IP4_Port));
ck_assert_msg(sizeof(IP) == 17, "sizeof(IP): expected result 17, got %u.", sizeof(IP));
ck_assert_msg(sizeof(IP_Port) == 19, "sizeof(IP_Port): expected result 19, got %u.", sizeof(IP_Port));
}
END_TEST

View File

@ -80,7 +80,7 @@ static int handle_test_3(void *object, IP_Port source, uint8_t *packet, uint32_t
uint8_t plain[1 + crypto_hash_sha256_BYTES];
//print_client_id(packet, length);
int len = decrypt_data(test_3_pub_key, onion->dht->c->self_secret_key, packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH,
int len = decrypt_data(test_3_pub_key, onion->dht->self_secret_key, packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH,
packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + crypto_box_NONCEBYTES,
1 + crypto_hash_sha256_BYTES + crypto_box_MACBYTES, plain);
@ -111,7 +111,7 @@ static int handle_test_4(void *object, IP_Port source, uint8_t *packet, uint32_t
if (memcmp(nonce, packet + 1, crypto_box_NONCEBYTES) != 0)
return 1;
int len = decrypt_data(packet + 1 + crypto_box_NONCEBYTES, onion->dht->c->self_secret_key, packet + 1,
int len = decrypt_data(packet + 1 + crypto_box_NONCEBYTES, onion->dht->self_secret_key, packet + 1,
packet + 1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES, sizeof("Install gentoo") + crypto_box_MACBYTES, plain);
if (len == -1)
@ -129,8 +129,8 @@ START_TEST(test_basic)
IP ip;
ip_init(&ip, 1);
ip.ip6.uint8[15] = 1;
Onion *onion1 = new_onion(new_DHT(new_net_crypto(new_networking(ip, 34567))));
Onion *onion2 = new_onion(new_DHT(new_net_crypto(new_networking(ip, 34568))));
Onion *onion1 = new_onion(new_DHT(new_networking(ip, 34567)));
Onion *onion2 = new_onion(new_DHT(new_networking(ip, 34568)));
ck_assert_msg((onion1 != NULL) && (onion2 != NULL), "Onion failed initializing.");
networking_registerhandler(onion2->net, 'I', &handle_test_1, onion2);
@ -176,26 +176,30 @@ START_TEST(test_basic)
ck_assert_msg((onion1_a != NULL) && (onion2_a != NULL), "Onion_Announce failed initializing.");
uint8_t zeroes[64] = {0};
randombytes(sb_data, sizeof(sb_data));
uint64_t s;
memcpy(&s, sb_data, sizeof(uint64_t));
memcpy(test_3_pub_key, nodes[3].client_id, crypto_box_PUBLICKEYBYTES);
ret = send_announce_request(onion1->net, &path, nodes[3], onion1->dht->c->self_public_key,
onion1->dht->c->self_secret_key,
zeroes, onion1->dht->c->self_public_key, onion1->dht->c->self_public_key, sb_data);
ret = send_announce_request(onion1->net, &path, nodes[3], onion1->dht->self_public_key,
onion1->dht->self_secret_key,
zeroes, onion1->dht->self_public_key, onion1->dht->self_public_key, s);
ck_assert_msg(ret == 0, "Failed to create/send onion announce_request packet.");
handled_test_3 = 0;
while (handled_test_3 == 0) {
do_onion(onion1);
do_onion(onion2);
c_sleep(50);
}
randombytes(sb_data, sizeof(sb_data));
memcpy(&s, sb_data, sizeof(uint64_t));
memcpy(onion2_a->entries[1].public_key, onion2->dht->self_public_key, crypto_box_PUBLICKEYBYTES);
onion2_a->entries[1].time = unix_time();
networking_registerhandler(onion1->net, NET_PACKET_ONION_DATA_RESPONSE, &handle_test_4, onion1);
send_announce_request(onion1->net, &path, nodes[3], onion1->dht->c->self_public_key, onion1->dht->c->self_secret_key,
test_3_ping_id, onion1->dht->c->self_public_key, onion1->dht->c->self_public_key, sb_data);
send_announce_request(onion1->net, &path, nodes[3], onion1->dht->self_public_key, onion1->dht->self_secret_key,
test_3_ping_id, onion1->dht->self_public_key, onion1->dht->self_public_key, s);
while (memcmp(onion2_a->entries[ONION_ANNOUNCE_MAX_ENTRIES - 2].public_key, onion1->dht->c->self_public_key,
while (memcmp(onion2_a->entries[ONION_ANNOUNCE_MAX_ENTRIES - 2].public_key, onion1->dht->self_public_key,
crypto_box_PUBLICKEYBYTES) != 0) {
do_onion(onion1);
do_onion(onion2);
@ -203,12 +207,12 @@ START_TEST(test_basic)
}
c_sleep(1000);
Onion *onion3 = new_onion(new_DHT(new_net_crypto(new_networking(ip, 34569))));
Onion *onion3 = new_onion(new_DHT(new_networking(ip, 34569)));
ck_assert_msg((onion3 != NULL), "Onion failed initializing.");
new_nonce(nonce);
ret = send_data_request(onion3->net, &path, nodes[3].ip_port, onion1->dht->c->self_public_key,
onion1->dht->c->self_public_key,
ret = send_data_request(onion3->net, &path, nodes[3].ip_port, onion1->dht->self_public_key,
onion1->dht->self_public_key,
nonce, (uint8_t *)"Install gentoo", sizeof("Install gentoo"));
ck_assert_msg(ret == 0, "Failed to create/send onion data_request packet.");
handled_test_4 = 0;
@ -233,10 +237,10 @@ Onions *new_onions(uint16_t port)
ip_init(&ip, 1);
ip.ip6.uint8[15] = 1;
Onions *on = malloc(sizeof(Onions));
DHT *dht = new_DHT(new_net_crypto(new_networking(ip, port)));
DHT *dht = new_DHT(new_networking(ip, port));
on->onion = new_onion(dht);
on->onion_a = new_onion_announce(dht);
on->onion_c = new_onion_client(dht);
on->onion_c = new_onion_client(new_net_crypto(dht));
if (on->onion && on->onion_a && on->onion_c)
return on;
@ -297,8 +301,8 @@ START_TEST(test_announce)
c_sleep(50);
}
onion_addfriend(onions[7]->onion_c, onions[37]->onion->dht->c->self_public_key);
int frnum = onion_addfriend(onions[37]->onion_c, onions[7]->onion->dht->c->self_public_key);
onion_addfriend(onions[7]->onion_c, onions[37]->onion_c->c->self_public_key);
int frnum = onion_addfriend(onions[37]->onion_c, onions[7]->onion_c->c->self_public_key);
int ok = -1;

View File

@ -96,21 +96,26 @@ void file_print_control(Tox *m, int friendnumber, uint8_t send_recieve, uint8_t
}
uint64_t size_recv;
uint8_t num;
void write_file(Tox *m, int friendnumber, uint8_t filenumber, uint8_t *data, uint16_t length, void *userdata)
{
if (*((uint32_t *)userdata) != 974536)
return;
uint8_t *f_data = malloc(length);
memset(f_data, 6, length);
memset(f_data, num, length);
++num;
if (memcmp(f_data, data, length) == 0)
if (memcmp(f_data, data, length) == 0) {
size_recv += length;
} else {
printf("FILE_CORRUPTED\n");
}
}
START_TEST(test_few_clients)
{
long long unsigned int cur_time = time(NULL);
long long unsigned int con_time, cur_time = time(NULL);
Tox *tox1 = tox_new(TOX_ENABLE_IPV6_DEFAULT);
Tox *tox2 = tox_new(TOX_ENABLE_IPV6_DEFAULT);
Tox *tox3 = tox_new(TOX_ENABLE_IPV6_DEFAULT);
@ -131,6 +136,7 @@ START_TEST(test_few_clients)
if (tox_isconnected(tox1) && tox_isconnected(tox2) && tox_isconnected(tox3) && off) {
printf("Toxes are online, took %llu seconds\n", time(NULL) - cur_time);
con_time = time(NULL);
off = 0;
}
@ -141,7 +147,7 @@ START_TEST(test_few_clients)
c_sleep(50);
}
printf("tox clients connected\n");
printf("tox clients connected took %llu seconds\n", time(NULL) - con_time);
to_compare = 974536;
tox_callback_friend_message(tox3, print_message, &to_compare);
tox_send_message(tox2, 0, (uint8_t *)"Install Gentoo", sizeof("Install Gentoo"));
@ -227,8 +233,8 @@ START_TEST(test_few_clients)
ck_assert_msg(fnum != -1, "tox_new_file_sender fail");
int fpiece_size = tox_file_data_size(tox2, 0);
uint8_t *f_data = malloc(fpiece_size);
memset(f_data, 6, fpiece_size);
uint8_t num = 0;
memset(f_data, num, fpiece_size);
while (1) {
file_sent = 0;
tox_do(tox1);
@ -241,6 +247,8 @@ START_TEST(test_few_clients)
sendf_ok = 0;
tox_file_send_control(tox2, 0, 0, fnum, TOX_FILECONTROL_FINISHED, NULL, 0);
}
++num;
memset(f_data, num, fpiece_size);
totalf_size -= fpiece_size;
}
@ -284,6 +292,12 @@ START_TEST(test_many_clients)
loop_top:
pairs[i].tox1 = rand() % NUM_TOXES;
pairs[i].tox2 = (pairs[i].tox1 + rand() % (NUM_TOXES - 1) + 1) % NUM_TOXES;
for (j = 0; j < i; ++j) {
if (pairs[j].tox2 == pairs[i].tox1 && pairs[j].tox1 == pairs[i].tox2)
goto loop_top;
}
tox_get_address(toxes[pairs[i].tox1], address);
int test = tox_add_friend(toxes[pairs[i].tox2], address, (uint8_t *)"Gentoo", 7);
@ -331,7 +345,7 @@ Suite *tox_suite(void)
Suite *s = suite_create("Tox");
DEFTESTCASE_SLOW(few_clients, 50);
DEFTESTCASE_SLOW(many_clients, 300);
DEFTESTCASE_SLOW(many_clients, 150);
return s;
}

View File

@ -21,18 +21,18 @@ See DHT, currently uses the IPv6 Node_format.
Get nodes (Request):
Packet contents:
```
[char with a value of 48][Bob's (The reciever's) Public key (client_id) (32 bytes))][Alice's (The sender's) Public key (client_id) (32 bytes)][Random nonce (24 bytes)][Encrypted with the nonce, private key of the sender and public key of the reciever:[char with a value of 48][random 8 byte (ping_id)]
[char with a value of 48][Bob's (The receiver's) Public key (client_id) (32 bytes))][Alice's (The sender's) Public key (client_id) (32 bytes)][Random nonce (24 bytes)][Encrypted with the nonce, private key of the sender and public key of the receiver:[char with a value of 48][random 8 byte (ping_id)]
```
Valid replies: a send_nodes packet
Send_nodes (response):
```
[char with a value of 48][Bob's (The reciever's) Public key (client_id) (32 bytes))][Alice's (The sender's) Public key (client_id) (32 bytes)][Random nonce (24 bytes)][Encrypted with the nonce, private key of the sender and public key of the reciever:[char with a value of 49][random 8 byte (ping_id)][Nodes in node format, length=40 * (number of nodes (maximum of 6 nodes)) bytes]]
[char with a value of 48][Bob's (The receiver's) Public key (client_id) (32 bytes))][Alice's (The sender's) Public key (client_id) (32 bytes)][Random nonce (24 bytes)][Encrypted with the nonce, private key of the sender and public key of the receiver:[char with a value of 49][random 8 byte (ping_id)][Nodes in node format, length=40 * (number of nodes (maximum of 6 nodes)) bytes]]
```
Broadcast packet:
```
[char with a value of 48][Bob's (The reciever's) Public key (client_id) (32 bytes))][Alice's (The sender's) Public key (client_id) (32 bytes)][nonce][Encrypted with the nonce, private key of the sender and public key of the reciever:[char with a value of 50][Data to send to everyone]]
[char with a value of 48][Bob's (The receiver's) Public key (client_id) (32 bytes))][Alice's (The sender's) Public key (client_id) (32 bytes)][nonce][Encrypted with the nonce, private key of the sender and public key of the receiver:[char with a value of 50][Data to send to everyone]]
```
@ -68,4 +68,4 @@ Ban a peer
[uint8_t message[messagelen]]
65 - action (/me)
[uint8_t message[messagelen]]
[uint8_t message[messagelen]]

View File

@ -110,7 +110,8 @@ encrypted with that temporary private key and the nonce and the public key from
(if Node D contains the ret data for the node, it sends the stuff in this packet as a data to route response packet to the right node)
The data in the previous packet is in format: [real public key of sender]
encrypted with real private key of the sender, the nonce in the data packet and the real public key of the reciever:[[uint8_t id][data (optional)]]
encrypted with real private key of the sender, the nonce in the data packet and
the real public key of the receiver:[[uint8_t id][data (optional)]]
Data sent to us:
announce response packet:
@ -153,5 +154,5 @@ Data packets:
To tell our friend what our DHT public key is so that he can connect to us we send a data packet
with id 156 and the data being:[uint64_t (in network byte order) no_replay, the packet will only be
accepted if this number is bigger than the last one recieved] [our dht public key][Node_Format * (
accepted if this number is bigger than the last one received] [our dht public key][Node_Format * (
maximum of 8) nodes closest to us so that the friend can find us faster]

View File

@ -81,7 +81,7 @@ received
client sent the server the public key and the public key we sent to the client,
the next with base nonce + 1...)
The connection is set to an unconfirmed state until a packet is recieved and
The connection is set to an unconfirmed state until a packet is received and
decrypted correctly using the information in the handshake.
each packet sent to/from the server has an id (the first byte of the plain text
@ -104,6 +104,10 @@ special ids and packets:
[uint8_t id (4)][uint64_t ping_id (0 is invalid)]
5 - ping response (pong)
[uint8_t id (5)][uint64_t ping_id (0 is invalid)]
6 - OOB send
[uint8_t id (6)][destination public key (32 bytes)][data]
7 - OOB recv
[uint8_t id (7)][senders public key (32 bytes)][data]
8 - onion packet (same format as initial onion packet (See: Prevent
tracking.txt) but packet id is 8 instead of 128)
9 - onion packet response (same format as onion packet with id 142 but id is 9
@ -135,11 +139,16 @@ responses must be sent to the proper client.
Ping responses must have the same ping_id as the request.
If the server recieves a ping packet he must respond with a ping response.
If the server receives a ping packet he must respond with a ping response.
The server will send a ping packet to clients every 30 seconds, they have 30
seconds to respond, if they don't the connection is deleted.
OOB send packets will be sent to the peer connected to the TCP server with the
destination public key as a OOB recv packet. The client sending this packet has
no way of knowing if the packet reached its destination.
Client:
Implementation details coming soon.

View File

@ -0,0 +1,118 @@
The TCP client and TCP server part are in a state that can be considered
feature complete. Why doesn't Tox support TCP yet even if those parts are
complete?
The answer is that a way to ensure a smooth switchover between the TCP and UDP
needs to be added. If Tox first connects to the other user using TCP but then
due to pure chance manages to connect using the faster direct UDP connection
Tox must switch seamlessly from the TCP to the UDP connection without there
being any data loss or the other user going offline and then back online. The
transition must be seamless whatever both connected users are doing be it
transferring files or simply chatting together.
Possible evil/bad or simply TCP relays going offline must not impact the
connection between both clients.
Typically Tox will use more than one TCP relay to connect to other peers for
maximum connection stability which means there must be a way for Tox to take
advantage of multiple relays in a way that the user will never be aware if one
of them goes offline/tries to slow down the connection/decides to corrupt
packets/etc..
To accomplish this Tox needs something between the low level protocol (TCP) and
high level Tox messaging protocol hence the name middle level.
The plan is to move some functionality from lossless_UDP to a higher level:
more specifically the functionality for detecting which packets a peer is
missing and the ability to request and send them again. lossless UDP uses plain
text packets to request missing packets from the other peer while Tox is
currently designed to kill the connection if any packet tampering is detected.
This works very well when connecting directly with someone because if the
attacker can modify packets it means he can kill your connection anyways. With
TCP relays however that is not the case as such the packets used to request
missing packets must be encrypted. If it is detected that a packet has been
tampered, the connection must stay intact while the evil relay must be
disconnected from and replaced with a good relay, the behavior must be the same
as if the relay had just suddenly gone online. Of course something to protect
from evil "friends" framing relays must also be implemented.
Detailed implementation details:
cookie request packet:
[uint8_t 24][Senders DHT Public key (32 bytes)][Random nonce (24
bytes)][Encrypted message containing: [Senders real public key (32
bytes)][padding (32 bytes)][uint64_t number (must be sent
back untouched in cookie response)]]
Encrypted message is encrypted with sender DHT private key, recievers DHT
public key and the nonce.
cookie response packet:
[uint8_t 25][Random nonce (24 bytes)][Encrypted message containing:
[Cookie][uint64_t number (that was sent in the request)]]
Encrypted message is encrypted with sender DHT private key, recievers DHT
public key and the nonce.
The Cookie should be basically:
[nonce][encrypted data:[uint64_t time][Senders real public key (32
bytes)][Senders dht public key (32 bytes)]]
Handshake packet:
[uint8_t 26][Cookie][nonce][Encrypted message containing: [random 24 bytes base
nonce][session public key of the peer (32 bytes)][sha512 hash of the entire
Cookie sitting outside the encrypted part][Other Cookie (used by the other to
respond to the handshake packet)]]
The handshake packet is encrypted using the real private key of the sender, the
real private key of the receiver and the nonce.
Alice wants to connect to bob.
Alice sends a cookie request packet to bob and gets a cookie response back.
Alice then generates a nonce and a temporary public/private keypair.
Alice then takes that nonce and just generated private key, the obtained
cookie, creates a new cookie and puts them in a handshake packet which she
sends to bob.
Bob gets the handshake packet, accepts the connection request, then generates a
nonce and a temporary public/private keypair and sends a handshake packet back
with this just generated information and with the cookie field being the Other
Cookie contained in the received handshake.
Both then use these temporary keys to generate the session key with which every
data packet sent and received will be encrypted and decrypted. The nonce sent
in the handshake will be used to encrypt the first data packet sent, the nonce
+ 1 the second, the nonce + 2 the third and so on.
Data packets:
[uint8_t 27][uint16_t (in network byte order) the last 2 bytes of the nonce
used to encrypt this][encrypted with the session key and a nonce:[plain data]]
Plain data in the data packets:
[uint32_t our recvbuffers buffer_start, (highest packet number handled +
1)][uint32_t packet number if lossless, our sendbuffer buffer_end if
lossy][data]
data ids:
0: padding (skipped until we hit a non zero (data id) byte)
1: packet request packet (lossy packet)
2: connection kill packet (lossy packet) (tells the other that the connection is over)
...
16+: reserved for Messenger usage (lossless packets).
packet request packet: [uint8_t (1)][uint8_t num][uint8_t num][uint8_t
num]...[uint8_t num]
the list of nums are a list of packet numbers the other is requesting.
to get the real packet numbers from this list take the recvbuffers buffer_start
from the packet, substract 1 to it and put it in packet_num then start from the
beggining of the num list: if num is zero, add 255 to packet_num then do the
next num. if num isn't zero, add its value to packet_num, note that the other
has requested we send this packet again to them then continue to the next num in
the list.

View File

@ -34,7 +34,7 @@ msi_session_t* - pointer to a newly created msi session handler.
###msi_session_t reference:
How to handle msi session:
Controling is done via callbacks and action handlers.
Controlling is done via callbacks and action handlers.
First register callbacks for every state/action received and make sure
NOT TO PLACE SOMETHING LIKE LOOPS THAT TAKES A LOT OF TIME TO EXECUTE; every callback is being called
directly from event loop. You can find examples in phone.c.

View File

@ -74,4 +74,4 @@ Crypto request packets
The encrypted message is encrypted with crypto_box() (using Bobs public key, Alice's private key and the nonce (randomly generated 24 bytes)) and is a message from Alice in which she tells Bob who she is.
Each node can route the request to the reciever if they are connected to him. This is to bypass bad NATs.
Each node can route the request to the receiver if they are connected to him. This is to bypass bad NATs.

View File

@ -79,18 +79,15 @@ Protocol
Node format:
```
[char array (node_id), length=32 bytes][ip (in network byte order), length=4 bytes][port (in network byte order), length=2 bytes][Padding , length=2 bytes]
[uint8_t family (2 == IPv4, 10 == IPv6, 130 == TCP IPv4, 138 == TCP IPv6)][ip (in network byte order), length=4 bytes if ipv4, 16 bytes if ipv6][port (in network byte order), length=2 bytes][char array (node_id), length=32 bytes]
```
see also: DHT.h (Node4_format struct)
IPv6 Node format:
see: DHT.h (Node_format struct)
see also: DHT.h (pack_nodes() and unpack_nodes())
Valid queries and Responses:
Ping(Request and response):
```
[byte with value: 00 for request, 01 for response][char array (client node_id), length=32 bytes][random 24 byte nonce][Encrypted with the nonce and private key of the sender: [random 8 byte (ping_id)]]
[byte with value: 00 for request, 01 for response][char array (client node_id), length=32 bytes][random 24 byte nonce][Encrypted with the nonce and private key of the sender: [1 byte type (0 for request, 1 for response)][random 8 byte (ping_id)]]
```
ping_id = a random integer, the response must contain the exact same number as the request
@ -98,16 +95,11 @@ ping_id = a random integer, the response must contain the exact same number as t
Get nodes (Request):
Packet contents:
```
[byte with value: 02][char array (client node_id), length=32 bytes][random 24 byte nonce][Encrypted with the nonce and private key of the sender:[char array: requested_node_id (node_id of which we want the ip), length=32 bytes][Encrypted data (must be sent back unmodified by in the response), length=NODES_ENCRYPTED_MESSAGE_LENGTH bytes]]
[byte with value: 02][char array (client node_id), length=32 bytes][random 24 byte nonce][Encrypted with the nonce and private key of the sender:[char array: requested_node_id (node_id of which we want the ip), length=32 bytes][Sendback data (must be sent back unmodified by in the response), length=1 to NODES_ENCRYPTED_MESSAGE_LENGTH bytes]]
```
Valid replies: a send_nodes packet
Send_nodes (response (for ipv4 addresses)):
Send_nodes (response (for all addresses)):
```
[byte with value: 03][char array (client node_id), length=32 bytes][random 24 byte nonce][Encrypted with the nonce and private key of the sender:[Nodes in node format, length=40 * (number of nodes (maximum of 8 nodes)) bytes][Encrypted data, length=NODES_ENCRYPTED_MESSAGE_LENGTH bytes]]
```
Send_nodes_IPv6 (response (for ipv6 addresses)):
```
[byte with value: 04][char array (client node_id), length=32 bytes][random 24 byte nonce][Encrypted with the nonce and private key of the sender:[Nodes in ipv6_node format, length=56 * (number of nodes (maximum of 8 nodes)) bytes][Encrypted data, length=NODES_ENCRYPTED_MESSAGE_LENGTH bytes]]
[byte with value: 04][char array (client node_id), length=32 bytes][random 24 byte nonce][Encrypted with the nonce and private key of the sender:[uint8_t number of nodes in this packet][Nodes in node format, length=?? * (number of nodes (maximum of 8 nodes)) bytes][Sendback data, length=1 to NODES_ENCRYPTED_MESSAGE_LENGTH bytes]]
```

View File

@ -53,7 +53,7 @@ fi[]dnl
# to PKG_CHECK_MODULES(), but does not set variables or print errors.
#
# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
# only at the first occurence in configure.ac, so if the first place
# only at the first occurrence in configure.ac, so if the first place
# it's called might be skipped (such as if it is within an "if", you
# have to call PKG_CHECK_EXISTS manually
# --------------------------------------------------------------

View File

@ -3,16 +3,16 @@
// Listening port.
port = 33445
// The key file is like a password, so keep it where no one can read it.
// A key file is like a password, so keep it where no one can read it.
// The daemon should have permission to read/write to it.
// Remember to replace the provided example with your own path.
keys_file_path = "/home/tom/.tox_bootstrap_daemon/keys"
keys_file_path = "/home/tom/.tox_bootstrap_daemon/.tox_bootstrap_daemon.keys"
// The PID file written to by daemon.
// Make sure that the user who runs the daemon has permissions to write to the
// PID file.
// Remember to replace the provided example with your own path.
pid_file_path = "/home/tom/.tox_bootstrap_daemon/pid"
pid_file_path = "/home/tom/.tox_bootstrap_daemon/.tox_bootstrap_daemon.pid"
// Enable IPv6.
enable_ipv6 = false
@ -20,6 +20,18 @@ enable_ipv6 = false
// Automatically bootstrap with nodes on local area network.
enable_lan_discovery = true
enable_tcp_relay = true
// Tox uses 443, 3389 and 33445 ports by default, so it's highly recommended to keep
// them.
tcp_relay_ports = [443, 3389, 33445]
// It's planned to use message of the day as a convenient method of checking
// whether a node is up or not, though there are other methods of doing that.
enable_motd = true
motd = "tox_bootstrap_daemon"
// Any number of nodes the daemon will bootstrap itself from.
// Remember to replace the provided example with your own node list.
// There is a maintained list of bootstrap nodes on Tox's wiki, if you need it.
@ -28,8 +40,8 @@ enable_lan_discovery = true
// from anyone.
bootstrap_nodes = (
{ // Node 1
// Any ipv4 or ipv6, depending if `enable_ipv6` is set or not, and also
// any US-ASCII domain name.
// Any ipv4 or ipv6, depending on whether `enable_ipv6` is set or not, and
// also any US-ASCII domain name.
address = "198.46.136.167"
port = 33445
public_key = "728925473812C7AAC482BE7250BCCAD0B8CB9F737BF3D42ABD34459C1768F854"

View File

@ -21,37 +21,56 @@
*
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
// system provided
#include <arpa/inet.h>
#include <syslog.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
// C
#include <stdio.h>
#include <stdlib.h>
#include <libconfig.h>
#include <arpa/inet.h>
#include <string.h>
// 3rd party
#include <libconfig.h>
// ./configure
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../../toxcore/DHT.h"
#include "../../toxcore/friend_requests.h"
// toxcore
#include "../../toxcore/LAN_discovery.h"
#include "../../toxcore/onion_announce.h"
#include "../../toxcore/TCP_server.h"
#include "../../toxcore/util.h"
// misc
#include "../bootstrap_node_packets.c"
#include "../../testing/misc_tools.c"
#define DAEMON_NAME "tox_bootstrap_daemon"
#define DAEMON_VERSION_NUMBER 2014051800UL // yyyymmmddvv format: yyyy year, mm month, dd day, vv version change count for that day
#define SLEEP_TIME_MILLISECONDS 30
#define sleep usleep(1000*SLEEP_TIME_MILLISECONDS)
#define DEFAULT_PID_FILE_PATH ".tox_bootstrap_daemon.pid"
#define DEFAULT_KEYS_FILE_PATH ".tox_bootstrap_daemon.keys"
#define DEFAULT_PORT 33445
#define DEFAULT_ENABLE_IPV6 0 // 1 - true, 0 - false
#define DEFAULT_ENABLE_LAN_DISCOVERY 1 // 1 - true, 0 - false
#define DEFAULT_PID_FILE_PATH ".tox_bootstrap_daemon.pid"
#define DEFAULT_KEYS_FILE_PATH ".tox_bootstrap_daemon.keys"
#define DEFAULT_PORT 33445
#define DEFAULT_ENABLE_IPV6 0 // 1 - true, 0 - false
#define DEFAULT_ENABLE_LAN_DISCOVERY 1 // 1 - true, 0 - false
#define DEFAULT_ENABLE_TCP_RELAY 1 // 1 - true, 0 - false
#define DEFAULT_TCP_RELAY_PORTS 443, 3389, 33445 // comma-separated list of ports. make sure to adjust DEFAULT_TCP_RELAY_PORTS_COUNT accordingly
#define DEFAULT_TCP_RELAY_PORTS_COUNT 3
#define DEFAULT_ENABLE_MOTD 1 // 1 - true, 0 - false
#define DEFAULT_MOTD DAEMON_NAME
#define MIN_ALLOWED_PORT 1
#define MAX_ALLOWED_PORT 65535
// Uses the already existing key or creates one if it didn't exist
@ -75,11 +94,12 @@ int manage_keys(DHT *dht, char *keys_file_path)
return 0;
}
load_keys(dht->c, keys);
memcpy(dht->self_public_key, keys, crypto_box_PUBLICKEYBYTES);
memcpy(dht->self_secret_key, keys + crypto_box_PUBLICKEYBYTES, crypto_box_SECRETKEYBYTES);
} else {
// Otherwise save new keys
new_keys(dht->c);
save_keys(dht->c, keys);
memcpy(keys, dht->self_public_key, crypto_box_PUBLICKEYBYTES);
memcpy(keys + crypto_box_PUBLICKEYBYTES, dht->self_secret_key, crypto_box_SECRETKEYBYTES);
keys_file = fopen(keys_file_path, "w");
@ -92,22 +112,111 @@ int manage_keys(DHT *dht, char *keys_file_path)
fclose(keys_file);
// We want our DHT public key to be the same as our internal one since this is a bootstrap node
memcpy(dht->self_public_key, dht->c->self_public_key, crypto_box_PUBLICKEYBYTES);
memcpy(dht->self_secret_key, dht->c->self_secret_key, crypto_box_SECRETKEYBYTES);
return 1;
}
// Parses tcp relay ports from `cfg` and puts them into `tcp_relay_ports` array
//
// Supposed to be called from get_general_config only
//
// Important: iff `tcp_relay_port_count` > 0, then you are responsible for freeing `tcp_relay_ports`
void parse_tcp_relay_ports_config(config_t *cfg, uint16_t **tcp_relay_ports, int *tcp_relay_port_count)
{
const char *NAME_TCP_RELAY_PORTS = "tcp_relay_ports";
*tcp_relay_port_count = 0;
config_setting_t *ports_array = config_lookup(cfg, NAME_TCP_RELAY_PORTS);
if (ports_array == NULL) {
syslog(LOG_WARNING, "No '%s' setting in the configuration file.\n", NAME_TCP_RELAY_PORTS);
syslog(LOG_WARNING, "Using default '%s':\n", NAME_TCP_RELAY_PORTS);
uint16_t default_ports[DEFAULT_TCP_RELAY_PORTS_COUNT] = {DEFAULT_TCP_RELAY_PORTS};
int i;
for (i = 0; i < DEFAULT_TCP_RELAY_PORTS_COUNT; i ++) {
syslog(LOG_WARNING, "Port #%d: %u\n", i, default_ports[i]);
}
// similar procedure to the one of reading config file below
*tcp_relay_ports = malloc(DEFAULT_TCP_RELAY_PORTS_COUNT * sizeof(uint16_t));
for (i = 0; i < DEFAULT_TCP_RELAY_PORTS_COUNT; i ++) {
(*tcp_relay_ports)[*tcp_relay_port_count] = default_ports[i];
if ((*tcp_relay_ports)[*tcp_relay_port_count] < MIN_ALLOWED_PORT || (*tcp_relay_ports)[*tcp_relay_port_count] > MAX_ALLOWED_PORT) {
syslog(LOG_WARNING, "Port #%d: Invalid port: %u, should be in [%d, %d]. Skipping.\n", i, (*tcp_relay_ports)[*tcp_relay_port_count], MIN_ALLOWED_PORT, MAX_ALLOWED_PORT);
continue;
}
(*tcp_relay_port_count) ++;
}
// the loop above skips invalid ports, so we adjust the allocated memory size
*tcp_relay_ports = realloc(*tcp_relay_ports, (*tcp_relay_port_count) * sizeof(uint16_t));
return;
}
if (config_setting_is_array(ports_array) == CONFIG_FALSE) {
syslog(LOG_WARNING, "'%s' setting should be an array. Array syntax: 'setting = [value1, value2, ...]'.\n", NAME_TCP_RELAY_PORTS);
return;
}
int config_port_count = config_setting_length(ports_array);
if (config_port_count == 0) {
syslog(LOG_WARNING, "'%s' is empty.\n", NAME_TCP_RELAY_PORTS);
return;
}
*tcp_relay_ports = malloc(config_port_count * sizeof(uint16_t));
config_setting_t *elem;
int i;
for (i = 0; i < config_port_count; i ++) {
elem = config_setting_get_elem(ports_array, i);
if (elem == NULL) {
// it's NULL if `ports_array` is not an array (we have that check ealier) or if `i` is out of range, which should not be
syslog(LOG_WARNING, "Port #%d: Something went wrong while parsing the port. Stopping reading ports.\n", i);
break;
}
if (config_setting_is_number(elem) == CONFIG_FALSE) {
syslog(LOG_WARNING, "Port #%d: Not a number. Skipping.\n", i);
continue;
}
(*tcp_relay_ports)[*tcp_relay_port_count] = config_setting_get_int(elem);
if ((*tcp_relay_ports)[*tcp_relay_port_count] < MIN_ALLOWED_PORT || (*tcp_relay_ports)[*tcp_relay_port_count] > MAX_ALLOWED_PORT) {
syslog(LOG_WARNING, "Port #%d: Invalid port: %u, should be in [%d, %d]. Skipping.\n", i, (*tcp_relay_ports)[*tcp_relay_port_count], MIN_ALLOWED_PORT, MAX_ALLOWED_PORT);
continue;
}
(*tcp_relay_port_count) ++;
}
// the loop above skips invalid ports, so we adjust the allocated memory size
*tcp_relay_ports = realloc(*tcp_relay_ports, (*tcp_relay_port_count) * sizeof(uint16_t));
}
// Gets general config options
//
// Important: you are responsible for freeing `pid_file_path` and `keys_file_path`
// also, iff `tcp_relay_ports_count` > 0, then you are responsible for freeing `tcp_relay_ports`
// and also `motd` iff `enable_motd` is set
//
// returns 1 on success
// 0 on failure, doesn't modify any data pointed by arguments
int get_general_config(char *cfg_file_path, char **pid_file_path, char **keys_file_path, int *port, int *enable_ipv6,
int *enable_lan_discovery)
int *enable_lan_discovery, int *enable_tcp_relay, uint16_t **tcp_relay_ports, int *tcp_relay_port_count,
int *enable_motd, char **motd)
{
config_t cfg;
@ -116,6 +225,9 @@ int get_general_config(char *cfg_file_path, char **pid_file_path, char **keys_fi
const char *NAME_KEYS_FILE_PATH = "keys_file_path";
const char *NAME_ENABLE_IPV6 = "enable_ipv6";
const char *NAME_ENABLE_LAN_DISCOVERY = "enable_lan_discovery";
const char *NAME_ENABLE_TCP_RELAY = "enable_tcp_relay";
const char *NAME_ENABLE_MOTD = "enable_motd";
const char *NAME_MOTD = "motd";
config_init(&cfg);
@ -172,6 +284,44 @@ int get_general_config(char *cfg_file_path, char **pid_file_path, char **keys_fi
*enable_lan_discovery = DEFAULT_ENABLE_LAN_DISCOVERY;
}
// Get TCP relay option
if (config_lookup_bool(&cfg, NAME_ENABLE_TCP_RELAY, enable_tcp_relay) == CONFIG_FALSE) {
syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_TCP_RELAY);
syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_ENABLE_TCP_RELAY,
DEFAULT_ENABLE_TCP_RELAY ? "true" : "false");
*enable_tcp_relay = DEFAULT_ENABLE_TCP_RELAY;
}
if (*enable_tcp_relay) {
parse_tcp_relay_ports_config(&cfg, tcp_relay_ports, tcp_relay_port_count);
} else {
*tcp_relay_port_count = 0;
}
// Get MOTD option
if (config_lookup_bool(&cfg, NAME_ENABLE_MOTD, enable_motd) == CONFIG_FALSE) {
syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_ENABLE_MOTD);
syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_ENABLE_MOTD,
DEFAULT_ENABLE_MOTD ? "true" : "false");
*enable_motd = DEFAULT_ENABLE_MOTD;
}
if (*enable_motd) {
// Get MOTD
const char *tmp_motd;
if (config_lookup_string(&cfg, NAME_MOTD, &tmp_motd) == CONFIG_FALSE) {
syslog(LOG_WARNING, "No '%s' setting in configuration file.\n", NAME_MOTD);
syslog(LOG_WARNING, "Using default '%s': %s\n", NAME_MOTD, DEFAULT_MOTD);
tmp_motd = DEFAULT_MOTD;
}
size_t tmp_motd_length = strlen(tmp_motd) + 1;
size_t motd_length = tmp_motd_length > MAX_MOTD_LENGTH ? MAX_MOTD_LENGTH : tmp_motd_length;
*motd = malloc(motd_length);
strncpy(*motd, tmp_motd, motd_length);
(*motd)[motd_length - 1] = '\0';
}
config_destroy(&cfg);
syslog(LOG_DEBUG, "Successfully read:\n");
@ -181,6 +331,25 @@ int get_general_config(char *cfg_file_path, char **pid_file_path, char **keys_fi
syslog(LOG_DEBUG, "'%s': %s\n", NAME_ENABLE_IPV6, *enable_ipv6 ? "true" : "false");
syslog(LOG_DEBUG, "'%s': %s\n", NAME_ENABLE_LAN_DISCOVERY, *enable_lan_discovery ? "true" : "false");
syslog(LOG_DEBUG, "'%s': %s\n", NAME_ENABLE_TCP_RELAY, *enable_tcp_relay ? "true" : "false");
// show info about tcp ports only if tcp relay is enabled
if (*enable_tcp_relay) {
if (*tcp_relay_port_count == 0) {
syslog(LOG_DEBUG, "No TCP ports could be read.\n");
} else {
syslog(LOG_DEBUG, "Read %d TCP ports:\n", *tcp_relay_port_count);
int i;
for (i = 0; i < *tcp_relay_port_count; i ++) {
syslog(LOG_DEBUG, "Port #%d: %u\n", i, (*tcp_relay_ports)[i]);
}
}
}
syslog(LOG_DEBUG, "'%s': %s\n", NAME_ENABLE_MOTD, *enable_motd ? "true" : "false");
if (*enable_motd) {
syslog(LOG_DEBUG, "'%s': %s\n", NAME_MOTD, *motd);
}
return 1;
}
@ -255,15 +424,14 @@ int bootstrap_from_config(char *cfg_file_path, DHT *dht, int enable_ipv6)
}
// Process settings
if (strlen(bs_public_key) != 64) {
if (strlen(bs_public_key) != crypto_box_PUBLICKEYBYTES*2) {
syslog(LOG_WARNING, "Bootstrap node #%d: Invalid '%s': %s. Skipping the node.\n", i, NAME_PUBLIC_KEY,
bs_public_key);
goto next;
}
// not (1 <= port <= 65535)
if (bs_port < 1 || bs_port > 65535) {
syslog(LOG_WARNING, "Bootstrap node #%d: Invalid '%s': %d. Skipping the node.\n", i, NAME_PORT, bs_port);
if (bs_port < MIN_ALLOWED_PORT || bs_port > MAX_ALLOWED_PORT) {
syslog(LOG_WARNING, "Bootstrap node #%d: Invalid '%s': %d, should be in [%d, %d]. Skipping the node.\n", i, NAME_PORT, bs_port, MIN_ALLOWED_PORT, MAX_ALLOWED_PORT);
goto next;
}
@ -280,9 +448,9 @@ int bootstrap_from_config(char *cfg_file_path, DHT *dht, int enable_ipv6)
syslog(LOG_DEBUG, "Successfully added bootstrap node #%d: %s:%d %s\n", i, bs_address, bs_port, bs_public_key);
next:
// config_setting_lookup_string() allocates string inside and doesn't allow us to free it
// so in order to reuse `bs_public_key` and `bs_address` we have to remove the element
// which will cause libconfig to free allocated strings
// config_setting_lookup_string() allocates string inside and doesn't allow us to free it direcly
// though it's freed when the element is removed, so we free it right away in order to keep memory
// consumption minimal
config_setting_remove_elem(node_list, 0);
i++;
}
@ -296,17 +464,13 @@ next:
void print_public_key(uint8_t *public_key)
{
char buffer[64 + 1];
char buffer[2*crypto_box_PUBLICKEYBYTES + 1];
int index = 0;
int i;
for (i = 0; i < 32; i++) {
if (public_key[i] < 16) {
index += sprintf(buffer + index, "0");
}
index += sprintf(buffer + index, "%hhX", public_key[i]);
for (i = 0; i < crypto_box_PUBLICKEYBYTES; i++) {
index += sprintf(buffer + index, "%02hhX", public_key[i]);
}
syslog(LOG_INFO, "Public Key: %s\n", buffer);
@ -318,6 +482,8 @@ int main(int argc, char *argv[])
{
openlog(DAEMON_NAME, LOG_NOWAIT | LOG_PID, LOG_DAEMON);
syslog(LOG_INFO, "Running \"%s\" version %lu.\n", DAEMON_NAME, DAEMON_VERSION_NUMBER);
if (argc < 2) {
syslog(LOG_ERR, "Please specify a path to a configuration file as the first argument. Exiting.\n");
return 1;
@ -328,30 +494,33 @@ int main(int argc, char *argv[])
int port;
int enable_ipv6;
int enable_lan_discovery;
int enable_tcp_relay;
uint16_t *tcp_relay_ports;
int tcp_relay_port_count;
int enable_motd;
char *motd;
if (get_general_config(cfg_file_path, &pid_file_path, &keys_file_path, &port, &enable_ipv6, &enable_lan_discovery)) {
if (get_general_config(cfg_file_path, &pid_file_path, &keys_file_path, &port, &enable_ipv6, &enable_lan_discovery, &enable_tcp_relay, &tcp_relay_ports, &tcp_relay_port_count, &enable_motd, &motd)) {
syslog(LOG_DEBUG, "General config read successfully\n");
} else {
syslog(LOG_ERR, "Couldn't read config file: %s. Exiting.\n", cfg_file_path);
return 1;
}
// not (1 <= port <= 65535)
if (port < 1 || port > 65535) {
syslog(LOG_ERR, "Invalid port: %d, must be 1 <= port <= 65535. Exiting.\n", port);
if (port < MIN_ALLOWED_PORT || port > MAX_ALLOWED_PORT) {
syslog(LOG_ERR, "Invalid port: %d, should be in [%d, %d]. Exiting.\n", port, MIN_ALLOWED_PORT, MAX_ALLOWED_PORT);
return 1;
}
// Check if the PID file exists
if (fopen(pid_file_path, "r")) {
syslog(LOG_ERR, "Another instance of the daemon is already running, PID file %s exists. Exiting.\n", pid_file_path);
return 1;
syslog(LOG_ERR, "Another instance of the daemon is already running, PID file %s exists.\n", pid_file_path);
}
IP ip;
ip_init(&ip, enable_ipv6);
DHT *dht = new_DHT(new_net_crypto(new_networking(ip, port)));
DHT *dht = new_DHT(new_networking(ip, port));
if (dht == NULL) {
syslog(LOG_ERR, "Couldn't initialize Tox DHT instance. Exiting.\n");
@ -366,31 +535,58 @@ int main(int argc, char *argv[])
return 1;
}
if (enable_lan_discovery) {
LANdiscovery_init(dht);
if (enable_motd) {
if (bootstrap_set_callbacks(dht->net, DAEMON_VERSION_NUMBER, (uint8_t*)motd, strlen(motd) + 1) == 0) {
syslog(LOG_DEBUG, "Set MOTD successfully.\n");
} else {
syslog(LOG_ERR, "Couldn't set MOTD: %s. Exiting.\n", motd);
return 1;
}
free(motd);
}
if (manage_keys(dht, keys_file_path)) {
syslog(LOG_DEBUG, "Keys are managed successfully\n");
syslog(LOG_DEBUG, "Keys are managed successfully.\n");
} else {
syslog(LOG_ERR, "Couldn't read/write: %s. Exiting.\n", keys_file_path);
return 1;
}
TCP_Server *tcp_server = NULL;
if (enable_tcp_relay) {
if (tcp_relay_port_count == 0) {
syslog(LOG_ERR, "No TCP relay ports read. Exiting.\n");
return 1;
}
tcp_server = new_TCP_server(enable_ipv6, tcp_relay_port_count, tcp_relay_ports, dht->self_public_key, dht->self_secret_key, onion);
// tcp_relay_port_count != 0 at this point
free(tcp_relay_ports);
if (tcp_server != NULL) {
syslog(LOG_DEBUG, "Initialized Tox TCP server successfully.\n");
} else {
syslog(LOG_ERR, "Couldn't initialize Tox TCP server. Exiting.\n");
return 1;
}
}
if (bootstrap_from_config(cfg_file_path, dht, enable_ipv6)) {
syslog(LOG_DEBUG, "List of bootstrap nodes read successfully\n");
syslog(LOG_DEBUG, "List of bootstrap nodes read successfully.\n");
} else {
syslog(LOG_ERR, "Couldn't read list of bootstrap nodes in %s. Exiting.\n", cfg_file_path);
return 1;
}
print_public_key(dht->c->self_public_key);
print_public_key(dht->self_public_key);
// Write the PID file
FILE *pidf = fopen(pid_file_path, "w");
FILE *pidf = fopen(pid_file_path, "a+");
if (pidf == NULL) {
syslog(LOG_ERR, "Can't open the PID file for writing: %s. Exiting.\n", pid_file_path);
syslog(LOG_ERR, "Couldn't open the PID file for writing: %s. Exiting.\n", pid_file_path);
return 1;
}
@ -407,7 +603,7 @@ int main(int argc, char *argv[])
}
if (pid > 0) {
fprintf(pidf, "%d\n", pid);
fprintf(pidf, "%d ", pid);
fclose(pidf);
syslog(LOG_DEBUG, "Forked successfully: PID: %d.\n", pid);
return 0;
@ -438,6 +634,11 @@ int main(int argc, char *argv[])
int waiting_for_dht_connection = 1;
if (enable_lan_discovery) {
LANdiscovery_init(dht);
syslog(LOG_DEBUG, "Initialized LAN discovery.\n");
}
while (1) {
do_DHT(dht);
@ -446,6 +647,10 @@ int main(int argc, char *argv[])
last_LANdiscovery = unix_time();
}
if (enable_tcp_relay) {
do_TCP_server(tcp_server);
}
networking_poll(dht->net);
if (waiting_for_dht_connection && DHT_isconnected(dht)) {

View File

@ -11,14 +11,14 @@
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="Tox DHT bootstrap server daemon"
DESC="Tox DHT bootstrap daemon"
NAME=tox_bootstrap_daemon
# You may want to change USER if you are using it anywhere else
USER=tom
CFG=/home/$USER/.$NAME/conf
DAEMON=/home/$USER/$NAME
DAEMON=/home/$USER/.$NAME/$NAME
DAEMON_ARGS="$CFG"
PIDFILE=/home/$USER/.$NAME/pid
PIDFILE=/home/$USER/.$NAME/."$NAME".pid
SCRIPTNAME=/etc/init.d/$NAME
# Exit if the package is not installed

View File

@ -32,7 +32,7 @@ void print_key(uint8_t *client_id)
int main(int argc, char *argv[])
{
if (argc < 2) {
printf("usage: ./cracker public_key(or beggining of one in hex format)\n");
printf("usage: ./cracker public_key(or beginning of one in hex format)\n");
return 0;
}

View File

@ -34,5 +34,4 @@ libtoxav_la_LIBADD = libtoxcore.la \
$(PTHREAD_LIBS) \
$(AV_LIBS)
endif

View File

@ -207,7 +207,22 @@ static inline__ const uint8_t *stringify_response ( MSIResponse response )
}
<<<<<<< HEAD
=======
#define ON_HEADER(iterator, header, descriptor, size_const) \
( memcmp(iterator, descriptor, size_const) == 0){ /* Okay */ \
iterator += size_const; /* Set iterator at beginning of value part */ \
if ( *iterator != value_byte ) { assert(0); return -1; }\
iterator ++;\
uint16_t _value_size = (uint16_t) *(iterator ) << 8 | \
(uint16_t) *(iterator + 1); \
header.header_value = calloc(sizeof(uint8_t), _value_size); \
header.size = _value_size; \
memcpy(header.header_value, iterator + 2, _value_size);\
iterator = iterator + 2 + _value_size; /* set iterator at new header or end_byte */ \
}
>>>>>>> upstream/master
/**
* @brief Parse raw 'data' received from socket into MSIMessage struct.
@ -1085,11 +1100,11 @@ int handle_recv_start ( MSISession *session, MSICall* call, MSIMessage *msg )
call->state = call_active;
call->key_peer = calloc ( sizeof ( uint8_t ), crypto_secretbox_KEYBYTES );
memcpy ( call->key_peer, msg->cryptokey.header_value, crypto_secretbox_KEYBYTES );
call->key_peer = calloc ( sizeof ( uint8_t ), crypto_box_KEYBYTES );
memcpy ( call->key_peer, msg->cryptokey.header_value, crypto_box_KEYBYTES );
call->nonce_peer = calloc ( sizeof ( uint8_t ), crypto_secretbox_NONCEBYTES );
memcpy ( call->nonce_peer, msg->nonce.header_value, crypto_secretbox_NONCEBYTES );
call->nonce_peer = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES );
memcpy ( call->nonce_peer, msg->nonce.header_value, crypto_box_NONCEBYTES );
flush_peer_type ( call, msg, 0 );
@ -1183,6 +1198,7 @@ int handle_recv_starting ( MSISession *session, MSICall* call, MSIMessage *msg )
}
/* Generate local key/nonce to send */
<<<<<<< HEAD
call->key_local = calloc ( sizeof ( uint8_t ), crypto_secretbox_KEYBYTES );
new_symmetric_key ( call->key_local );
@ -1195,13 +1211,33 @@ int handle_recv_starting ( MSISession *session, MSICall* call, MSIMessage *msg )
call->nonce_peer = calloc ( sizeof ( uint8_t ), crypto_secretbox_NONCEBYTES );
memcpy ( call->nonce_peer, msg->nonce.header_value, crypto_secretbox_NONCEBYTES );
=======
session->call->key_local = calloc ( sizeof ( uint8_t ), crypto_box_KEYBYTES );
new_symmetric_key ( session->call->key_local );
session->call->nonce_local = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES );
new_nonce ( session->call->nonce_local );
/* Save peer key/nonce */
session->call->key_peer = calloc ( sizeof ( uint8_t ), crypto_box_KEYBYTES );
memcpy ( session->call->key_peer, msg->cryptokey.header_value, crypto_box_KEYBYTES );
session->call->nonce_peer = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES );
memcpy ( session->call->nonce_peer, msg->nonce.header_value, crypto_box_NONCEBYTES );
>>>>>>> upstream/master
call->state = call_active;
MSIMessage *_msg_start = msi_new_message ( TYPE_REQUEST, stringify_request ( start ) );
<<<<<<< HEAD
msi_msg_set_cryptokey ( _msg_start, call->key_local, crypto_secretbox_KEYBYTES );
msi_msg_set_nonce ( _msg_start, call->nonce_local, crypto_secretbox_NONCEBYTES );
send_message ( session, call, _msg_start, msg->friend_id );
=======
msi_msg_set_cryptokey ( _msg_start, session->call->key_local, crypto_box_KEYBYTES );
msi_msg_set_nonce ( _msg_start, session->call->nonce_local, crypto_box_NONCEBYTES );
send_message ( session, _msg_start, msg->friend_id );
>>>>>>> upstream/master
free_message ( _msg_start );
flush_peer_type ( call, msg, 0 );
@ -1593,6 +1629,7 @@ int msi_answer ( MSISession* session, int32_t call_index, MSICallType call_type
/* Now set the local encryption key and pass it with STARTING message */
<<<<<<< HEAD
session->calls[call_index]->key_local = calloc ( sizeof ( uint8_t ), crypto_secretbox_KEYBYTES );
new_symmetric_key ( session->calls[call_index]->key_local );
@ -1601,6 +1638,16 @@ int msi_answer ( MSISession* session, int32_t call_index, MSICallType call_type
msi_msg_set_cryptokey ( _msg_starting, session->calls[call_index]->key_local, crypto_secretbox_KEYBYTES );
msi_msg_set_nonce ( _msg_starting, session->calls[call_index]->nonce_local, crypto_secretbox_NONCEBYTES );
=======
session->call->key_local = calloc ( sizeof ( uint8_t ), crypto_box_KEYBYTES );
new_symmetric_key ( session->call->key_local );
session->call->nonce_local = calloc ( sizeof ( uint8_t ), crypto_box_NONCEBYTES );
new_nonce ( session->call->nonce_local );
msi_msg_set_cryptokey ( _msg_starting, session->call->key_local, crypto_box_KEYBYTES );
msi_msg_set_nonce ( _msg_starting, session->call->nonce_local, crypto_box_NONCEBYTES );
>>>>>>> upstream/master
send_message ( session, session->calls[call_index], _msg_starting, session->calls[call_index]->peers[session->calls[call_index]->peer_count - 1] );
free_message ( _msg_starting );
@ -1689,4 +1736,4 @@ int msi_stopcall ( MSISession* session, int32_t call_index )
terminate_call ( session, session->calls[call_index] );
return 0;
}
}

View File

@ -72,21 +72,22 @@ typedef struct _MSICall { /* Call info structure */
uint8_t id[CALL_ID_LEN]; /* Random value identifying the call */
uint8_t *key_local; /* The key for encryption */
uint8_t *key_peer; /* The key for decryption */
uint8_t *key_local; /* The key for encryption */
uint8_t *key_peer; /* The key for decryption */
uint8_t *nonce_local; /* Local nonce */
uint8_t *nonce_peer; /* Peer nonce */
uint8_t *nonce_local; /* Local nonce */
uint8_t *nonce_peer; /* Peer nonce */
int ringing_tout_ms; /* Ringing timeout in ms */
int request_timer_id; /* Timer id for outgoing request/action */
int ringing_timer_id; /* Timer id for ringing timeout */
pthread_mutex_t mutex; /* It's to be assumed that call will have
* separate thread so add mutex
*/
uint32_t *peers;
uint32_t *peers;
uint16_t peer_count;
int32_t call_idx; /* Index of this call in MSISession */

1460
toxav/phone.c Executable file

File diff suppressed because it is too large Load Diff

View File

@ -2048,6 +2048,7 @@ static int handle_packet(void *object, int i, uint8_t *temp, uint16_t len)
if (m->friend_action)
(*m->friend_action)(m, i, action_terminated, action_length, m->friend_action_userdata);
break;
}
@ -2207,7 +2208,7 @@ void do_friends(Messenger *m)
m->friendlist[i].friendrequest_lastsent = temp_time;
}
}
if (m->friendlist[i].status == FRIEND_REQUESTED
|| m->friendlist[i].status == FRIEND_CONFIRMED) { /* friend is not online. */
if (m->friendlist[i].status == FRIEND_REQUESTED) {