summaryrefslogblamecommitdiffstats
path: root/tests/tests.c
blob: a403bc4a65cc0bb084413ada79a27f1a3eb1f978 (plain) (tree)
1
2
3
4
5
6
7
8
9
                  

                             


                            
           
   
               
 






















                                                                 
         











                                                      

         














                                                                                                   

         















                                                                                                   
 




























                                                                                                   
                                                                                                   









                                                     

         




                                

 

                       
 

























                                                     
         





                                                              
                                       

















                                                             
         






                                                              


   


















































































































































































                                                                                                   

                            

                       
                                       

                                        


                                                                                                 
 
#include <stdio.h>
#include "../src/wireguard.h"
#include "util.h"

extern char *malloc_options;

/* TESTS */
int
test_standard()
{
	struct wg_peer a, b;
	setup_peer_pair(&a, &b, &g_upcall);

	/* Setup initial packet */
	struct mbuf_list ml; ml_init(&ml);
	struct mbuf *m = m_gethdr(0, 0);
	m->m_len = 30;
	*mtod(m, u_int32_t *) = 0xdeadbeef;

	/* Encrypt one packet, expect it to generate initation */
	PRINT("SEND: peer a -> b 30 bytes\n");
	wg_peer_tx(&a, m, &ml);
	assert(task_set(WG_TASK_REKEY, 5, 0));
	assert(task_done());
	assert(ml.ml_len == 1);
	assert(mtod(ml.ml_head, u_int8_t *)[0] == 1);

	/* Foreign peer receive */
	struct mbuf_list mli, mlo; ml_init(&mli); ml_init(&mlo);
	PRINT("RECV: peer a -> b\n");
	print_mbuf_list(&ml);
	while ((m = ml_dequeue(&ml)) != NULL) {
		wg_peer_rx(&b, m, &mli, &mlo);
	}
	assert(task_done());
	assert(mli.ml_len == 0);
	assert(mlo.ml_len == 1);
	assert(mtod(mlo.ml_head, u_int8_t *)[0] == 2);

	/* Local peer receive */
	ml = mlo;
	ml_init(&mli); ml_init(&mlo);
	PRINT("RECV: peer b -> a\n");
	print_mbuf_list(&ml);
	while ((m = ml_dequeue(&ml)) != NULL) {
		wg_peer_rx(&a, m, &mli, &mlo);
	}

	assert(task_set(WG_TASK_KEEPALIVE, 10, 0)); /* initiator, so check for broken connection */
	assert(task_set(WG_TASK_CLEANUP, 540, 0)); /* session setup, cleanup required */
	assert(task_set(WG_TASK_BROKEN, 15, 0)); /* initiator, so check for broken connection */
	assert(task_done());
	assert(mli.ml_len == 0);
	assert(mlo.ml_len == 1);
	assert(mtod(mlo.ml_head, u_int8_t *)[0] == 4);

	/* Foreign peer receive */
	ml = mlo;
	ml_init(&mli); ml_init(&mlo);
	PRINT("RECV: peer a -> b\n");
	print_mbuf_list(&ml);
	while ((m = ml_dequeue(&ml)) != NULL) {
		wg_peer_rx(&b, m, &mli, &mlo);
	}

	assert(task_set(WG_TASK_KEEPALIVE, 10, 0)); /* initiator, so check for broken connection */
	assert(task_set(WG_TASK_CLEANUP, 540, 0)); /* session setup, cleanup required */
	assert(task_set(WG_TASK_BROKEN, 15, 0)); /* initiator, so check for broken connection */
	assert(task_done());
	assert(mli.ml_len == 1);
	assert(mlo.ml_len == 0);
	assert(*mtod(mli.ml_head, u_int32_t *) == 0xdeadbeef);

	/* Run first timeout */
	struct timespec ts = { 5, 0 };
	set_time(&ts);

	ml_init(&ml);
	wg_task_fn[WG_TASK_REKEY](&a, &ml);
	assert(task_done());
	assert(ml.ml_len == 0);


	/* run keepalive timeout, should not trigger at all because calling early */
	ts.tv_sec = 7;
	set_time(&ts);

	ml_init(&ml);
	wg_task_fn[WG_TASK_KEEPALIVE](&a, &ml);
	assert(task_set(WG_TASK_KEEPALIVE, 3, 0)); /* initiator, so check for broken connection */
	assert(task_done());
	assert(ml.ml_len == 0);

	ml_init(&ml);
	wg_task_fn[WG_TASK_KEEPALIVE](&b, &ml);
	assert(task_set(WG_TASK_KEEPALIVE, 3, 0)); /* initiator, so check for broken connection */
	assert(task_done());
	assert(ml.ml_len == 0);

	/* run keepalive timeout, should trigger for b */
	ts.tv_sec = 10;
	set_time(&ts);

	ml_init(&ml);
	wg_task_fn[WG_TASK_KEEPALIVE](&a, &ml);
	assert(task_set(WG_TASK_KEEPALIVE, 10, 0)); /* initiator, so check for broken connection */
	assert(task_done());
	assert(ml.ml_len == 0);

	ml_init(&ml);
	wg_task_fn[WG_TASK_KEEPALIVE](&b, &ml);
	assert(task_set(WG_TASK_KEEPALIVE, 10, 0)); /* initiator, so check for broken connection */
	assert(task_done());
	assert(ml.ml_len == 1);
	assert(mtod(ml.ml_head, u_int8_t *)[0] == 4);

	/* peer recv keepalive */
	ml_init(&mli); ml_init(&mlo);
	PRINT("RECV: peer b -> a\n");
	print_mbuf_list(&ml);
	while ((m = ml_dequeue(&ml)) != NULL) {
		wg_peer_rx(&a, m, &mli, &mlo);
	}

	assert(task_done());
	assert(mli.ml_len == 0);
	assert(mlo.ml_len == 0);

	return 0;
}

int
test_session_timeout1()
{
	struct mbuf *m;
	struct timespec ts;
	struct mbuf_list ml, mli, mlo;
	struct wg_peer a, b;
	setup_peer_session(&a, &b, &g_upcall);

	PRINT("testing 119 seconds\n");
	timespecclear(&ts);

	/* Send packet at 119 seconds */
	ts.tv_sec = 119;
	set_time(&ts);

	m = m_gethdr(0, 0);
	m->m_len = 30;
	*mtod(m, u_int32_t *) = 0xdeadbeef;
	ml_init(&ml);
	wg_peer_tx(&a, m, &ml);
	assert(task_done());
	assert(ml.ml_len == 1);
	assert(mtod(ml.ml_head, u_int8_t *)[0] == 4);

	ml_init(&mli); ml_init(&mlo);
	print_mbuf_list(&ml);
	while ((m = ml_dequeue(&ml)) != NULL) {
		wg_peer_rx(&b, m, &mli, &mlo);
	}
	assert(task_done());
	assert(mli.ml_len == 1);
	assert(mlo.ml_len == 0);
	assert(*mtod(mli.ml_head, u_int32_t *) == 0xdeadbeef);

	/* Send packet at 120 seconds */
	PRINT("testing 120 seconds\n");
	ts.tv_sec = 120;
	set_time(&ts);

	m = m_gethdr(0, 0);
	m->m_len = 30;
	*mtod(m, u_int32_t *) = 0xfeedbeef;
	ml_init(&ml);
	wg_peer_tx(&a, m, &ml);
	assert(task_set(WG_TASK_REKEY, 5, 0));
	assert(task_done());
	assert(ml.ml_len == 2);
	assert(mtod(ml.ml_head, u_int8_t *)[0] == 4);
	assert(mtod(ml.ml_head->m_next, u_int8_t *)[0] == 1);

	ml_init(&mli); ml_init(&mlo);
	print_mbuf_list(&ml);
	while ((m = ml_dequeue(&ml)) != NULL) {
		wg_peer_rx(&b, m, &mli, &mlo);
	}
	assert(task_done());
	assert(mli.ml_len == 1);
	assert(mlo.ml_len == 1);
	assert(*mtod(mli.ml_head, u_int32_t *) == 0xfeedbeef);
	assert(mtod(mlo.ml_head, u_int8_t *)[0] == 2);

	return 0;
}

int
test_packet_sizes()
{
	struct mbuf *m;
	struct mbuf_list ml, mli, mlo;
	struct wg_peer a, b;
	setup_peer_session(&a, &b, &g_upcall);

	PRINT("testing 119 seconds\n");

	ml_init(&ml);
	u_int32_t i;
	for (i = 4; i < 2048; i++) {
		m = m_clget(NULL, 0, i);
		m->m_len = i;
		*mtod(m, u_int32_t *) = ~i;
		wg_peer_tx(&a, m, &ml);
	}

	/* Send packet at 119 seconds */
	assert(task_done());
	assert(ml.ml_len == i - 4 );

	ml_init(&mli); ml_init(&mlo);
	print_mbuf_list(&ml);
	while ((m = ml_dequeue(&ml)) != NULL) {
		wg_peer_rx(&b, m, &mli, &mlo);
	}
	assert(task_done());
	assert(mli.ml_len == i - 4);
	assert(mlo.ml_len == 0);
	return 0;
}

int
test_cookie()
{
	struct wg_peer a, b;
	setup_peer_pair(&a, &b, &g_upcall);

	/* set high cpu! */
	g_high_cpu = true;

	/* Setup initial packet */
	struct mbuf_list ml; ml_init(&ml);
	struct mbuf *m = m_gethdr(0, 0);
	m->m_len = 30;
	*mtod(m, u_int32_t *) = 0xdeadbeef;

	/* Encrypt one packet, expect it to generate initation */
	PRINT("SEND: peer a -> b 30 bytes\n");
	wg_peer_tx(&a, m, &ml);
	assert(task_set(WG_TASK_REKEY, 5, 0));
	assert(task_done());
	assert(ml.ml_len == 1);
	assert(mtod(ml.ml_head, u_int8_t *)[0] == 1);

	/* Foreign peer receive */
	struct mbuf_list mli, mlo; ml_init(&mli); ml_init(&mlo);
	print_mbuf_list(&ml);
	while ((m = ml_dequeue(&ml)) != NULL) {
		wg_peer_rx(&b, m, &mli, &mlo);
	}
	assert(task_done());
	assert(mli.ml_len == 0);
	assert(mlo.ml_len == 1);
	assert(mtod(mlo.ml_head, u_int8_t *)[0] == 3); /* cookie msg */

	/* Local peer receive */
	ml = mlo;
	ml_init(&mli); ml_init(&mlo);
	print_mbuf_list(&ml);
	while ((m = ml_dequeue(&ml)) != NULL) {
		wg_peer_rx(&a, m, &mli, &mlo);
	}

	assert(task_done());
	assert(mli.ml_len == 0);
	assert(mlo.ml_len == 0);

	/* Run timeout, expect another initiation */
	struct timespec ts = { 5, 0 };
	set_time(&ts);

	ml_init(&ml);
	wg_task_fn[WG_TASK_REKEY](&a, &ml);
	assert(task_set(WG_TASK_REKEY, 5, 0));
	assert(task_done());
	assert(ml.ml_len == 1);
	assert(mtod(ml.ml_head, u_int8_t *)[0] == 1);

	ml_init(&mli); ml_init(&mlo);
	print_mbuf_list(&ml);
	while ((m = ml_dequeue(&ml)) != NULL) {
		wg_peer_rx(&b, m, &mli, &mlo);
	}
	assert(task_done());
	assert(mli.ml_len == 0);
	assert(mlo.ml_len == 1);
	assert(mtod(mlo.ml_head, u_int8_t *)[0] == 2); /* response msg */

	/* Local peer receive */
	ml = mlo;
	ml_init(&mli); ml_init(&mlo);
	print_mbuf_list(&ml);
	while ((m = ml_dequeue(&ml)) != NULL) {
		wg_peer_rx(&a, m, &mli, &mlo);
	}

	assert(task_done());
	assert(mli.ml_len == 0);
	assert(mlo.ml_len == 1);
	assert(mtod(mlo.ml_head, u_int8_t *)[0] == 3); /* cookie msg */

	ml = mlo;
	ml_init(&mli); ml_init(&mlo);
	print_mbuf_list(&ml);
	while ((m = ml_dequeue(&ml)) != NULL) {
		wg_peer_rx(&b, m, &mli, &mlo);
	}
	assert(task_done());
	assert(mli.ml_len == 0);
	assert(mlo.ml_len == 0);

	/* Run next timeout */
	ts.tv_sec = 10;
	set_time(&ts);

	ml_init(&ml);
	wg_task_fn[WG_TASK_REKEY](&a, &ml);
	assert(task_set(WG_TASK_REKEY, 5, 0));
	assert(task_done());
	assert(ml.ml_len == 1);
	assert(mtod(ml.ml_head, u_int8_t *)[0] == 1);

	ml_init(&mli); ml_init(&mlo);
	print_mbuf_list(&ml);
	while ((m = ml_dequeue(&ml)) != NULL) {
		wg_peer_rx(&b, m, &mli, &mlo);
	}
	assert(task_done());
	assert(mli.ml_len == 0);
	assert(mlo.ml_len == 1);
	assert(mtod(mlo.ml_head, u_int8_t *)[0] == 2); /* response msg */

	/* Local peer receive */
	ml = mlo;
	ml_init(&mli); ml_init(&mlo);
	print_mbuf_list(&ml);
	while ((m = ml_dequeue(&ml)) != NULL) {
		wg_peer_rx(&a, m, &mli, &mlo);
	}

	assert(task_set(WG_TASK_KEEPALIVE, 10, 0)); /* initiator, so check for broken connection */
	assert(task_set(WG_TASK_CLEANUP, 540, 0)); /* session setup, cleanup required */
	assert(task_set(WG_TASK_BROKEN, 15, 0)); /* initiator, so check for broken connection */
	assert(task_done());
	assert(mli.ml_len == 0);
	assert(mlo.ml_len == 1);
	assert(mtod(mlo.ml_head, u_int8_t *)[0] == 4); /* cookie msg */

	ml = mlo;
	ml_init(&mli); ml_init(&mlo);
	print_mbuf_list(&ml);
	while ((m = ml_dequeue(&ml)) != NULL) {
		wg_peer_rx(&b, m, &mli, &mlo);
	}

	assert(task_set(WG_TASK_KEEPALIVE, 10, 0)); /* initiator, so check for broken connection */
	assert(task_set(WG_TASK_CLEANUP, 540, 0)); /* session setup, cleanup required */
	assert(task_set(WG_TASK_BROKEN, 15, 0)); /* initiator, so check for broken connection */
	assert(task_done());
	assert(mli.ml_len == 1);
	assert(mlo.ml_len == 0);
	assert(*mtod(mli.ml_head, u_int32_t *) == 0xdeadbeef);

	return 0;
}

int
main(int argc, char *argv[])
{
	int failed = 0;
	int passed = 0;
	malloc_options = "CFGJJJJRSUX";
	run_test(test_standard);
	run_test(test_session_timeout1);
	run_test(test_packet_sizes);
	run_test(test_cookie);
	APRINT("Tests completed: %d, passed: %d, failed: %d\n", passed + failed, passed, failed);
}