toxcore/auto_tests/onion_test.c
iphydf ad26560516
Improve static and const correctness.
- Any non-externally-visible declarations should be `static`.
- Casting away the `const` qualifier from pointers-to-const is
  dangerous. All but one instance of this are now correct. The one
  instance where we can't keep `const` is one where toxav code actually
  writes to a chunk of memory marked as `const`. This code also assumes
  4 byte alignment of data packets. I don't know whether that is a valid
  assumption, but it's likely unportable, and *not* obviously correct.
- Replaced empty parameter lists with `(void)` to avoid passing
  parameters to it. Empty parameter lists are old style declarations for
  unknown number and type of arguments.
- Commented out (as `#if DHT_HARDENING` block) the hardening code that
  was never executed.
- Minor style fix: don't use `default` in enum-switches unless the number
  of enumerators in the default case is very large. In this case, it was
  2, so we want to list them both explicitly to be warned about missing
  one if we add one in the future.
- Removed the only two function declarations from nTox.h and put them
  into nTox.c. They are not used outside and nTox is not a library.
2016-09-06 11:54:37 +01:00

488 lines
14 KiB
C

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <check.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#include "../toxcore/onion.h"
#include "../toxcore/onion_announce.h"
#include "../toxcore/onion_client.h"
#include "../toxcore/util.h"
#include "helpers.h"
#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
#define c_sleep(x) Sleep(1*x)
#else
#include <unistd.h>
#define c_sleep(x) usleep(1000*x)
#endif
static void do_onion(Onion *onion)
{
networking_poll(onion->net, NULL);
do_DHT(onion->dht);
}
static int handled_test_1;
static int handle_test_1(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata)
{
Onion *onion = object;
if (memcmp(packet, "Install Gentoo", sizeof("Install Gentoo")) != 0) {
return 1;
}
if (send_onion_response(onion->net, source, (const uint8_t *)"install gentoo", sizeof("install gentoo"),
packet + sizeof("Install Gentoo")) == -1) {
return 1;
}
handled_test_1 = 1;
return 0;
}
static int handled_test_2;
static int handle_test_2(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata)
{
if (length != sizeof("install Gentoo")) {
return 1;
}
if (memcmp(packet, (const uint8_t *)"install gentoo", sizeof("install gentoo")) != 0) {
return 1;
}
handled_test_2 = 1;
return 0;
}
#if 0
void print_client_id(uint8_t *client_id, uint32_t length)
{
uint32_t j;
for (j = 0; j < length; j++) {
printf("%02hhX", client_id[j]);
}
printf("\n");
}
#endif
static uint8_t sb_data[ONION_ANNOUNCE_SENDBACK_DATA_LENGTH];
static int handled_test_3;
static uint8_t test_3_pub_key[crypto_box_PUBLICKEYBYTES];
static uint8_t test_3_ping_id[crypto_hash_sha256_BYTES];
static int handle_test_3(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata)
{
Onion *onion = object;
if (length != (1 + crypto_box_NONCEBYTES + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + 1 + crypto_hash_sha256_BYTES +
crypto_box_MACBYTES)) {
return 1;
}
uint8_t plain[1 + crypto_hash_sha256_BYTES];
//print_client_id(packet, 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);
if (len == -1) {
return 1;
}
if (memcmp(packet + 1, sb_data, ONION_ANNOUNCE_SENDBACK_DATA_LENGTH) != 0) {
return 1;
}
memcpy(test_3_ping_id, plain + 1, crypto_hash_sha256_BYTES);
//print_client_id(test_3_ping_id, sizeof(test_3_ping_id));
handled_test_3 = 1;
return 0;
}
static uint8_t nonce[crypto_box_NONCEBYTES];
static int handled_test_4;
static int handle_test_4(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata)
{
Onion *onion = object;
if (length != (1 + crypto_box_NONCEBYTES + crypto_box_PUBLICKEYBYTES + sizeof("Install gentoo") +
crypto_box_MACBYTES)) {
return 1;
}
uint8_t plain[sizeof("Install gentoo")] = {0};
if (memcmp(nonce, packet + 1, crypto_box_NONCEBYTES) != 0) {
return 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) {
return 1;
}
if (memcmp(plain, "Install gentoo", sizeof("Install gentoo")) != 0) {
return 1;
}
handled_test_4 = 1;
return 0;
}
START_TEST(test_basic)
{
IP ip;
ip_init(&ip, 1);
ip.ip6.uint8[15] = 1;
Onion *onion1 = new_onion(new_DHT(NULL, new_networking(NULL, ip, 34567)));
Onion *onion2 = new_onion(new_DHT(NULL, new_networking(NULL, ip, 34568)));
ck_assert_msg((onion1 != NULL) && (onion2 != NULL), "Onion failed initializing.");
networking_registerhandler(onion2->net, 'I', &handle_test_1, onion2);
IP_Port on1 = {ip, onion1->net->port};
Node_format n1;
memcpy(n1.public_key, onion1->dht->self_public_key, crypto_box_PUBLICKEYBYTES);
n1.ip_port = on1;
IP_Port on2 = {ip, onion2->net->port};
Node_format n2;
memcpy(n2.public_key, onion2->dht->self_public_key, crypto_box_PUBLICKEYBYTES);
n2.ip_port = on2;
Node_format nodes[4];
nodes[0] = n1;
nodes[1] = n2;
nodes[2] = n1;
nodes[3] = n2;
Onion_Path path;
create_onion_path(onion1->dht, &path, nodes);
int ret = send_onion_packet(onion1->net, &path, nodes[3].ip_port, (const uint8_t *)"Install Gentoo",
sizeof("Install Gentoo"));
ck_assert_msg(ret == 0, "Failed to create/send onion packet.");
handled_test_1 = 0;
while (handled_test_1 == 0) {
do_onion(onion1);
do_onion(onion2);
}
networking_registerhandler(onion1->net, 'i', &handle_test_2, onion1);
handled_test_2 = 0;
while (handled_test_2 == 0) {
do_onion(onion1);
do_onion(onion2);
}
Onion_Announce *onion1_a = new_onion_announce(onion1->dht);
Onion_Announce *onion2_a = new_onion_announce(onion2->dht);
networking_registerhandler(onion1->net, NET_PACKET_ANNOUNCE_RESPONSE, &handle_test_3, onion1);
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].public_key, crypto_box_PUBLICKEYBYTES);
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->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->self_public_key,
crypto_box_PUBLICKEYBYTES) != 0) {
do_onion(onion1);
do_onion(onion2);
c_sleep(50);
}
c_sleep(1000);
Onion *onion3 = new_onion(new_DHT(NULL, new_networking(NULL, 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->self_public_key,
onion1->dht->self_public_key,
nonce, (const uint8_t *)"Install gentoo", sizeof("Install gentoo"));
ck_assert_msg(ret == 0, "Failed to create/send onion data_request packet.");
handled_test_4 = 0;
while (handled_test_4 == 0) {
do_onion(onion1);
do_onion(onion2);
c_sleep(50);
}
kill_onion_announce(onion1_a);
kill_onion_announce(onion2_a);
{
Onion *onion = onion1;
Networking_Core *net = onion->dht->net;
DHT *dht = onion->dht;
kill_onion(onion);
kill_DHT(dht);
kill_networking(net);
}
{
Onion *onion = onion2;
Networking_Core *net = onion->dht->net;
DHT *dht = onion->dht;
kill_onion(onion);
kill_DHT(dht);
kill_networking(net);
}
{
Onion *onion = onion3;
Networking_Core *net = onion->dht->net;
DHT *dht = onion->dht;
kill_onion(onion);
kill_DHT(dht);
kill_networking(net);
}
}
END_TEST
typedef struct {
Onion *onion;
Onion_Announce *onion_a;
Onion_Client *onion_c;
} Onions;
static Onions *new_onions(uint16_t port)
{
IP ip;
ip_init(&ip, 1);
ip.ip6.uint8[15] = 1;
Onions *on = malloc(sizeof(Onions));
DHT *dht = new_DHT(NULL, new_networking(NULL, ip, port));
on->onion = new_onion(dht);
on->onion_a = new_onion_announce(dht);
TCP_Proxy_Info inf = {{{0}}};
on->onion_c = new_onion_client(new_net_crypto(NULL, dht, &inf));
if (on->onion && on->onion_a && on->onion_c) {
return on;
}
return NULL;
}
static void do_onions(Onions *on)
{
networking_poll(on->onion->net, NULL);
do_DHT(on->onion->dht);
do_onion_client(on->onion_c);
}
static void kill_onions(Onions *on)
{
Networking_Core *net = on->onion->dht->net;
DHT *dht = on->onion->dht;
Net_Crypto *c = on->onion_c->c;
kill_onion_client(on->onion_c);
kill_onion_announce(on->onion_a);
kill_onion(on->onion);
kill_net_crypto(c);
kill_DHT(dht);
kill_networking(net);
free(on);
}
#define NUM_ONIONS 50
#define NUM_FIRST 7
#define NUM_LAST 37
static _Bool first_ip, last_ip;
static void dht_ip_callback(void *object, int32_t number, IP_Port ip_port)
{
if (NUM_FIRST == number) {
first_ip = 1;
return;
}
if (NUM_LAST == number) {
last_ip = 1;
return;
}
ck_abort_msg("Error.");
}
static _Bool first, last;
static uint8_t first_dht_pk[crypto_box_PUBLICKEYBYTES];
static uint8_t last_dht_pk[crypto_box_PUBLICKEYBYTES];
static void dht_pk_callback(void *object, int32_t number, const uint8_t *dht_public_key, void *userdata)
{
if ((NUM_FIRST == number && !first) || (NUM_LAST == number && !last)) {
Onions *on = object;
uint16_t count = 0;
int ret = DHT_addfriend(on->onion->dht, dht_public_key, &dht_ip_callback, object, number, &count);
ck_assert_msg(ret == 0, "DHT_addfriend() did not return 0");
ck_assert_msg(count == 1, "Count not 1, count is %u", count);
if (NUM_FIRST == number && !first) {
first = 1;
if (memcmp(dht_public_key, last_dht_pk, crypto_box_PUBLICKEYBYTES) != 0) {
ck_abort_msg("Error wrong dht key.");
}
return;
}
if (NUM_LAST == number && !last) {
last = 1;
if (memcmp(dht_public_key, first_dht_pk, crypto_box_PUBLICKEYBYTES) != 0) {
ck_abort_msg("Error wrong dht key.");
}
return;
}
ck_abort_msg("Error.");
}
}
START_TEST(test_announce)
{
uint32_t i, j;
Onions *onions[NUM_ONIONS];
for (i = 0; i < NUM_ONIONS; ++i) {
onions[i] = new_onions(i + 34655);
ck_assert_msg(onions[i] != 0, "Failed to create onions. %u");
}
IP ip;
ip_init(&ip, 1);
ip.ip6.uint8[15] = 1;
for (i = 3; i < NUM_ONIONS; ++i) {
IP_Port ip_port = {ip, onions[i - 1]->onion->net->port};
DHT_bootstrap(onions[i]->onion->dht, ip_port, onions[i - 1]->onion->dht->self_public_key);
IP_Port ip_port1 = {ip, onions[i - 2]->onion->net->port};
DHT_bootstrap(onions[i]->onion->dht, ip_port1, onions[i - 2]->onion->dht->self_public_key);
IP_Port ip_port2 = {ip, onions[i - 3]->onion->net->port};
DHT_bootstrap(onions[i]->onion->dht, ip_port2, onions[i - 3]->onion->dht->self_public_key);
}
uint32_t connected = 0;
while (connected != NUM_ONIONS) {
connected = 0;
for (i = 0; i < NUM_ONIONS; ++i) {
do_onions(onions[i]);
connected += DHT_isconnected(onions[i]->onion->dht);
}
c_sleep(50);
}
printf("connected\n");
for (i = 0; i < 25 * 2; ++i) {
for (j = 0; j < NUM_ONIONS; ++j) {
do_onions(onions[j]);
}
c_sleep(50);
}
memcpy(first_dht_pk, onions[NUM_FIRST]->onion->dht->self_public_key, crypto_box_PUBLICKEYBYTES);
memcpy(last_dht_pk, onions[NUM_LAST]->onion->dht->self_public_key, crypto_box_PUBLICKEYBYTES);
printf("adding friend\n");
int frnum_f = onion_addfriend(onions[NUM_FIRST]->onion_c, onions[NUM_LAST]->onion_c->c->self_public_key);
int frnum = onion_addfriend(onions[NUM_LAST]->onion_c, onions[NUM_FIRST]->onion_c->c->self_public_key);
onion_dht_pk_callback(onions[NUM_FIRST]->onion_c, frnum_f, &dht_pk_callback, onions[NUM_FIRST], NUM_FIRST);
onion_dht_pk_callback(onions[NUM_LAST]->onion_c, frnum, &dht_pk_callback, onions[NUM_LAST], NUM_LAST);
IP_Port ip_port;
while (!first || !last) {
for (i = 0; i < NUM_ONIONS; ++i) {
do_onions(onions[i]);
}
c_sleep(50);
}
printf("Waiting for ips\n");
while (!first_ip || !last_ip) {
for (i = 0; i < NUM_ONIONS; ++i) {
do_onions(onions[i]);
}
c_sleep(50);
}
onion_getfriendip(onions[NUM_LAST]->onion_c, frnum, &ip_port);
ck_assert_msg(ip_port.port == onions[NUM_FIRST]->onion->net->port, "Port in returned ip not correct.");
for (i = 0; i < NUM_ONIONS; ++i) {
kill_onions(onions[i]);
}
}
END_TEST
static Suite *onion_suite(void)
{
Suite *s = suite_create("Onion");
DEFTESTCASE_SLOW(basic, 5);
DEFTESTCASE_SLOW(announce, 70);
return s;
}
int main(int argc, char *argv[])
{
srand((unsigned int) time(NULL));
Suite *onion = onion_suite();
SRunner *test_runner = srunner_create(onion);
int number_failed = 0;
srunner_run_all(test_runner, CK_NORMAL);
number_failed = srunner_ntests_failed(test_runner);
srunner_free(test_runner);
return number_failed;
}