Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[test] add fuzzing #13

Merged
merged 1 commit into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.1)
cmake_minimum_required(VERSION 3.12)

find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
Expand Down Expand Up @@ -95,20 +95,25 @@ if (NOT IPV6_PARSE_LIBRARY_ONLY)
set(IPV6_TEST_CONFIG_HEADER_PATH ${CMAKE_CURRENT_BINARY_DIR})

add_executable(ipv6-test ${ipv6_sources} "test.c")
add_executable(ipv6-fuzz ${ipv6_sources} "fuzz.c")
add_executable(ipv6-cmd ${ipv6_sources} "cmdline.c")

set_target_properties(ipv6-test PROPERTIES COMPILE_FLAGS ${ipv6_target_compile_flags})
set_target_properties(ipv6-fuzz PROPERTIES COMPILE_FLAGS ${ipv6_target_compile_flags})
set_target_properties(ipv6-cmd PROPERTIES COMPILE_FLAGS ${ipv6_target_compile_flags})

target_include_directories(ipv6-test PRIVATE ${IPV6_CONFIG_HEADER_PATH} ${IPV6_TEST_CONFIG_HEADER_PATH})
target_include_directories(ipv6-fuzz PRIVATE ${IPV6_CONFIG_HEADER_PATH} ${IPV6_TEST_CONFIG_HEADER_PATH})
target_include_directories(ipv6-cmd PRIVATE ${IPV6_CONFIG_HEADER_PATH})

if (MSVC)
target_link_libraries(ipv6-test ws2_32)
target_link_libraries(ipv6-fuzz ws2_32)
target_link_libraries(ipv6-cmd ws2_32)
endif ()
enable_testing()
add_test(NAME verification COMMAND bin/ipv6-test)
add_test(NAME fuzz COMMAND bin/ipv6-fuzz)
endif ()

add_library(ipv6-parse ${ipv6_sources})
Expand Down
24 changes: 17 additions & 7 deletions build_test.sh
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
#!/bin/bash

set -e
set -x
set -eof pipefail

# Generate the build_gmake folder
if [ ! -d build_gmake ]; then
./cmake_gmake.sh
fi
./cmake_gmake.sh

# Create the test application
pushd build_gmake
make all
make ipv6-test ipv6-fuzz


# Run the tests collecting failures
bin/ipv6-test > test_results.md
pushd bin

echo "running test with results in test_results.md"
./ipv6-test > test_results.md
failures=`grep -c FAIL test_results.md`

# Run the fuzzer
echo "fuzzing with results in fuzz_results.md"
./ipv6-test > fuzz_results.md
fuzz_result=$?

popd
popd

echo "Completed test pass, ${failures} failures. See build_gmake/test_results.md"
echo "Completed test pass, ${failures} failures. Fuzzer result: ${fuzz_result}."
135 changes: 135 additions & 0 deletions fuzz.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "ipv6.h"

#define MAX_INPUT_LENGTH 100
#define MAX_OUTPUT_LENGTH 200
#define NUM_ITERATIONS 1000

char* generate_random_string(int length) {
const char* chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789:.";
char* str = (char*)malloc((length + 1) * sizeof(char));
for (int i = 0; i < length; i++) {
int index = rand() % (int)strlen(chars);
str[i] = chars[index];
}
str[length] = '\0';
return str;
}

void fuzz_ipv6_from_str(int num_iterations) {
printf("Fuzzing ipv6_from_str:\n");
for (int i = 0; i < num_iterations; i++) {
int input_length = rand() % (MAX_INPUT_LENGTH + 1);
char* input_string = generate_random_string(input_length);
size_t input_bytes = strlen(input_string);

ipv6_address_full_t ipv6_address;
memset(&ipv6_address, 0, sizeof(ipv6_address_full_t));

bool result = ipv6_from_str(input_string, input_bytes, &ipv6_address);

printf("Input: %s\n", input_string);
printf("Parsing result: %s\n", result ? "true" : "false");
printf("Parsed address: ");
for (int j = 0; j < IPV6_NUM_COMPONENTS; j++) {
printf("%x ", ipv6_address.address.components[j]);
}
printf("\n");
printf("Mask: %u\n", ipv6_address.mask);
printf("Port: %u\n", ipv6_address.port);
printf("Flags: %u\n", ipv6_address.flags);
printf("---\n");

free(input_string);
}
printf("\n");
}

void fuzz_ipv6_to_str(int num_iterations) {
printf("Fuzzing ipv6_to_str:\n");
for (int i = 0; i < num_iterations; i++) {
ipv6_address_full_t ipv6_address;
for (int j = 0; j < IPV6_NUM_COMPONENTS; j++) {
ipv6_address.address.components[j] = rand() % 0xFFFF;
}
ipv6_address.mask = rand() % 129;
ipv6_address.port = rand() % 0xFFFF;
ipv6_address.flags = rand() % 0xFF;

char output_string[MAX_OUTPUT_LENGTH];
size_t output_bytes = ipv6_to_str(&ipv6_address, output_string, sizeof(output_string));

printf("Generated address:\n");
for (int j = 0; j < IPV6_NUM_COMPONENTS; j++) {
printf("%x ", ipv6_address.address.components[j]);
}
printf("\n");
printf("Mask: %u\n", ipv6_address.mask);
printf("Port: %u\n", ipv6_address.port);
printf("Flags: %u\n", ipv6_address.flags);
printf("Output string: %s\n", output_string);
printf("Output bytes: %zu\n", output_bytes);
printf("---\n");
}
printf("\n");
}

void fuzz_ipv6_compare(int num_iterations) {
printf("Fuzzing ipv6_compare:\n");
for (int i = 0; i < num_iterations; i++) {
ipv6_address_full_t ipv6_address1;
ipv6_address_full_t ipv6_address2;
for (int j = 0; j < IPV6_NUM_COMPONENTS; j++) {
ipv6_address1.address.components[j] = rand() % 0xFFFF;
ipv6_address2.address.components[j] = rand() % 0xFFFF;
}
ipv6_address1.mask = rand() % 129;
ipv6_address2.mask = rand() % 129;
ipv6_address1.port = rand() % 0xFFFF;
ipv6_address2.port = rand() % 0xFFFF;
ipv6_address1.flags = rand() % 0xFF;
ipv6_address2.flags = rand() % 0xFF;

uint32_t ignore_flags = rand() % 0xFF;

ipv6_compare_result_t result = ipv6_compare(&ipv6_address1, &ipv6_address2, ignore_flags);

printf("Address 1: ");
for (int j = 0; j < IPV6_NUM_COMPONENTS; j++) {
printf("%x ", ipv6_address1.address.components[j]);
}
printf("\n");
printf("Mask 1: %u\n", ipv6_address1.mask);
printf("Port 1: %u\n", ipv6_address1.port);
printf("Flags 1: %u\n", ipv6_address1.flags);

printf("Address 2: ");
for (int j = 0; j < IPV6_NUM_COMPONENTS; j++) {
printf("%x ", ipv6_address2.address.components[j]);
}
printf("\n");
printf("Mask 2: %u\n", ipv6_address2.mask);
printf("Port 2: %u\n", ipv6_address2.port);
printf("Flags 2: %u\n", ipv6_address2.flags);

printf("Ignore flags: %u\n", ignore_flags);
printf("Comparison result: %d\n", result);
printf("---\n");
}
printf("\n");
}

int main(int argc, const char **argv) {
(void)argc; (void)argv;

srand(time(NULL));

fuzz_ipv6_from_str(NUM_ITERATIONS);
fuzz_ipv6_to_str(NUM_ITERATIONS);
fuzz_ipv6_compare(NUM_ITERATIONS);

return 0;
}
8 changes: 1 addition & 7 deletions test.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,6 @@ typedef struct {
#define TEST_FAILED(...) \
printf(" FAILED %s:%d", (const char *)__FILE__, (int32_t)__LINE__); \
printf(__VA_ARGS__); \
failed = true; \
status->failed_count++; \
status->total_tests++; \
assert(false);
Expand Down Expand Up @@ -301,7 +300,6 @@ static void test_parsing (test_status_t* status) {
for (uint32_t i = 0; i < LENGTHOF(tests); ++i) {
ipv6_address_full_t test;
ipv6_address_full_t parsed;
bool failed = false;

memset(&test, 0, sizeof(test));
memset(&parsed, 0, sizeof(parsed));
Expand Down Expand Up @@ -407,7 +405,6 @@ static void test_parsing_diag (test_status_t* status) {
for (uint32_t i = 0; i < LENGTHOF(tests); ++i) {
ipv6_address_full_t addr;
diag_test_capture_t capture;
bool failed = false;

memset(&addr, 0, sizeof(addr));
memset(&capture, 0, sizeof(capture));
Expand Down Expand Up @@ -522,7 +519,6 @@ static void test_comparisons(test_status_t* status) {
for (uint32_t i = 0; i < LENGTHOF(tests); ++i) {
ipv6_address_full_t left, right;
diag_test_capture_t capture;
bool failed = false;

memset(&left, 0, sizeof(left));
memset(&right, 0, sizeof(right));
Expand Down Expand Up @@ -573,7 +569,6 @@ static void test_comparisons(test_status_t* status) {

static void test_api_use_loopback_const (test_status_t* status) {
// Just treat all of the checks in this function as a single test
bool failed = false;
status->total_tests = 1;

// test using the host order network constant directly in an ipv6_address_full_t
Expand Down Expand Up @@ -643,7 +638,6 @@ static void test_api_use_loopback_const (test_status_t* status) {
static void test_invalid_to_str(test_status_t* status) {
ipv6_address_full_t address;
const char* test_str = "::1:2:3:4:5";
bool failed;

if (!ipv6_from_str_diag(test_str, strlen(test_str), &address, test_output_diag_fn, NULL)) {
TEST_FAILED(" ipv6_from_str failed for %s\n", test_str);
Expand All @@ -666,7 +660,7 @@ static void test_invalid_to_str(test_status_t* status) {
TEST_FAILED(" ipv6_to_str should not silently truncate");
}
else {
TEST_PASSED();
TEST_PASSED()
}
}

Expand Down