X-Git-Url: http://git.pk910.de/?p=ircu2.10.12-pk.git;a=blobdiff_plain;f=ircd%2Ftest%2Fircd_in_addr_t.c;fp=ircd%2Ftest%2Fircd_in_addr_t.c;h=381460789508a7cb0911744a1b4b571ca9efae7e;hp=0000000000000000000000000000000000000000;hb=0400a5a6479398d82526785c18c0df8bc8b92dce;hpb=d17e10da972ce5776c60b4c317267c6abe0e1ead diff --git a/ircd/test/ircd_in_addr_t.c b/ircd/test/ircd_in_addr_t.c new file mode 100644 index 0000000..3814607 --- /dev/null +++ b/ircd/test/ircd_in_addr_t.c @@ -0,0 +1,175 @@ +/* ircd_in_addr_t.c - Test file for IP address manipulation */ + +#include "ircd_log.h" +#include "ircd_string.h" +#include "numnicks.h" +#include "res.h" +#include +#include +#include + +/** Structure to describe a test for IP address parsing and unparsing. */ +struct address_test { + const char *text; /**< Textual address to parse. */ + const char *canonical; /**< Canonical form of address. */ + struct irc_in_addr expected; /**< Parsed address. */ + const char *base64_v4; /**< v4-only compatible base64 encoding. */ + const char *base64_v6; /**< v6-compatible base64 encoding. */ + unsigned int is_valid : 1; /**< is address valid? */ + unsigned int is_ipv4 : 1; /**< is address ipv4? */ + unsigned int is_loopback : 1; /**< is address loopback? */ +}; + +/** Array of addresses to test with. */ +static struct address_test test_addrs[] = { + { "::", "0::", + {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, + "AAAAAA", "_", 0, 0, 0 }, + { "::1", "0::1", + {{ 0, 0, 0, 0, 0, 0, 0, 1 }}, + "AAAAAA", "_AAB", 1, 0, 1 }, + { "127.0.0.1", "127.0.0.1", + {{ 0, 0, 0, 0, 0, 0xffff, 0x7f00, 1 }}, + "B]AAAB", "B]AAAB", 1, 1, 1 }, + { "::ffff:127.0.0.3", "127.0.0.3", + {{ 0, 0, 0, 0, 0, 0xffff, 0x7f00, 3 }}, + "B]AAAD", "B]AAAD", 1, 1, 1 }, + { "::127.0.0.1", "127.0.0.1", + {{ 0, 0, 0, 0, 0, 0, 0x7f00, 1 }}, + "B]AAAB", "B]AAAB", 1, 1, 1 }, + { "2002:7f00:3::1", "2002:7f00:3::1", + {{ 0x2002, 0x7f00, 3, 0, 0, 0, 0, 1 }}, + "B]AAAD", "CACH8AAAD_AAB", 1, 0, 0 }, + { "8352:0344:0:0:0:0:2001:1204", "8352:344::2001:1204", + {{ 0x8352, 0x344, 0, 0, 0, 0, 0x2001, 0x1204 }}, + "AAAAAA", "INSANE_CABBIE", 1, 0, 0 }, + { "1:2:3:4:5:6:7:8", "1:2:3:4:5:6:7:8", + {{ 1, 2, 3, 4, 5, 6, 7, 8 }}, + "AAAAAA", "AABAACAADAAEAAFAAGAAHAAI", 1, 0, 0 }, + { 0 }, +}; + +/** Perform tests for a single IP address. + * @param[in] addr Address test structure. + */ +static void +test_address(struct address_test *addr) +{ + struct irc_in_addr parsed; + unsigned int ii, len, val; + char unparsed[64], base64_v4[64], base64_v6[64]; + + /* Convert expected address to network order. */ + for (ii = 0; ii < 8; ++ii) + addr->expected.in6_16[ii] = htons(addr->expected.in6_16[ii]); + /* Make sure the text form is parsed as expected. */ + len = ircd_aton(&parsed, addr->text); + assert(len == strlen(addr->text)); + assert(!irc_in_addr_cmp(&parsed, &addr->expected)); + /* Make sure it converts back to ASCII. */ + ircd_ntoa_r(unparsed, &parsed); + assert(!strcmp(unparsed, addr->canonical)); + /* Check IP-to-base64 conversion. */ + iptobase64(base64_v4, &parsed, sizeof(base64_v4), 0); + iptobase64(base64_v6, &parsed, sizeof(base64_v6), 1); + if (addr->base64_v4) + assert(!strcmp(base64_v4, addr->base64_v4)); + if (addr->base64_v6) + assert(!strcmp(base64_v6, addr->base64_v6)); + /* Check testable attributes. */ + val = irc_in_addr_valid(&parsed); + assert(!!val == addr->is_valid); + val = irc_in_addr_is_ipv4(&parsed); + assert(!!val == addr->is_ipv4); + val = irc_in_addr_is_loopback(&parsed); + assert(!!val == addr->is_loopback); + /* Check base64-to-IP conversion. */ + if (addr->is_ipv4) { + base64toip(addr->base64_v4, &parsed); + assert(!memcmp(parsed.in6_16+6, addr->expected.in6_16+6, 4)); + } else { + base64toip(addr->base64_v6, &parsed); + assert(!memcmp(&parsed, &addr->expected, sizeof(parsed))); + } + /* Tests completed. */ + printf("Passed: %s (%s/%s)\n", addr->text, base64_v4, base64_v6); +} + +/** Structure to describe a test for IP mask parsing. */ +struct ipmask_test { + const char *text; /**< Textual IP mask to parse. */ + struct irc_in_addr expected; /**< Canonical form of address. */ + unsigned int is_ipmask : 1; /**< Parse as an ipmask? */ + unsigned int is_parseable : 1; /**< Is address parseable? */ + unsigned int exp_bits : 8; /**< Number of bits expected in netmask */ +}; + +/** Array of ipmasks to test with. */ +static struct ipmask_test test_masks[] = { + { "::", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 1, 128 }, + { "::/0", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 1, 0 }, + { "::10.0.0.0", {{ 0, 0, 0, 0, 0, 0, 0xa00, 0 }}, 1, 1, 128 }, + { "192.168/16", {{ 0, 0, 0, 0, 0, 0xffff, 0xc0a8, 0 }}, 1, 1, 112 }, + { "192.*", {{ 0, 0, 0, 0, 0, 0xffff, 0xc000, 0 }}, 1, 1, 104 }, + { "192.*.*.*", {{ 0, 0, 0, 0, 0, 0xffff, 0xc000, 0 }}, 1, 1, 104 }, + { "192.*/8", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 0, 0 }, + { "192*", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 0, 0 }, + { "192.168.0.0/16", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0, 0, 0 }, + { "ab.*", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 0, 0 }, + { "a*", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 0, 0 }, + { "*", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 1, 0 }, + { "a:b", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 0, 0 }, + { "a::*", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 0, 0 }, + { "a:*", {{ 0xa, 0, 0, 0, 0, 0, 0, 0 }}, 1, 1, 16 }, + { "a:*:*", {{ 0xa, 0, 0, 0, 0, 0, 0, 0 }}, 1, 1, 16 }, + { "a:/16", {{ 0xa, 0, 0, 0, 0, 0, 0, 0 }}, 1, 1, 16 }, + { "0.0.0.0.0/1", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0, 0, 0 }, + { "2607:3f00:1:30c:9999*", + {{ 0x2607, 0x3f00, 1, 0x30c, 0x9999, 0, 0, 0 }}, 1, 1, 80 }, + { "1234:5678:9abc:def0:feed:abba:cabb:1e55::", + {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 0, 0 }, + { 0 } +}; + +/** Perform tests for a single IP mask. + * @param[in] mask IP mask test structure. + */ +static void +test_ipmask(struct ipmask_test *mask) +{ + struct irc_in_addr parsed; + unsigned int len, ii; + unsigned char bits = 0; + + /* Convert expected address to network order. */ + for (ii = 0; ii < 8; ++ii) + mask->expected.in6_16[ii] = htons(mask->expected.in6_16[ii]); + /* Try to parse; make sure its parseability and netmask length are + * as expected. */ + len = ipmask_parse(mask->text, &parsed, mask->is_ipmask ? &bits : 0); + assert(!!len == mask->is_parseable); + if (!len) { + printf("X-Fail: %s\n", mask->text); + return; + } + if (mask->is_ipmask) + assert(bits == mask->exp_bits); + assert(!memcmp(&parsed, &mask->expected, sizeof(parsed))); + printf("Passed: %s (%s/%u)\n", mask->text, ircd_ntoa(&parsed), bits); +} + +int +main(int argc, char *argv[]) +{ + unsigned int ii; + + printf("Testing address parsing..\n"); + for (ii = 0; test_addrs[ii].text; ++ii) + test_address(&test_addrs[ii]); + + printf("\nTesting ipmask parsing..\n"); + for (ii = 0; test_masks[ii].text; ++ii) + test_ipmask(&test_masks[ii]); + + return 0; +}