diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a2ae40..43a1e20 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.12) find_program(CCACHE_PROGRAM ccache) if(CCACHE_PROGRAM) @@ -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}) diff --git a/build_test.sh b/build_test.sh index eed8df1..6631d80 100755 --- a/build_test.sh +++ b/build_test.sh @@ -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}." diff --git a/fuzz.c b/fuzz.c new file mode 100644 index 0000000..94c2399 --- /dev/null +++ b/fuzz.c @@ -0,0 +1,135 @@ +#include +#include +#include +#include +#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; +} diff --git a/test.c b/test.c index 310241b..15d7d4a 100644 --- a/test.c +++ b/test.c @@ -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); @@ -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)); @@ -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)); @@ -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)); @@ -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 @@ -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); @@ -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() } }