]>
Commit | Line | Data |
---|---|---|
189935b1 | 1 | /* ircd_in_addr_t.c - Test file for IP address manipulation */ |
2 | ||
3 | #include "ircd_log.h" | |
4 | #include "ircd_string.h" | |
5 | #include "numnicks.h" | |
6 | #include "res.h" | |
7 | #include <stdio.h> | |
8 | #include <string.h> | |
9 | #include <netinet/in.h> | |
10 | ||
11 | /** Structure to describe a test for IP address parsing and unparsing. */ | |
12 | struct address_test { | |
13 | const char *text; /**< Textual address to parse. */ | |
14 | const char *canonical; /**< Canonical form of address. */ | |
15 | struct irc_in_addr expected; /**< Parsed address. */ | |
16 | const char *base64_v4; /**< v4-only compatible base64 encoding. */ | |
17 | const char *base64_v6; /**< v6-compatible base64 encoding. */ | |
18 | unsigned int is_valid : 1; /**< is address valid? */ | |
19 | unsigned int is_ipv4 : 1; /**< is address ipv4? */ | |
20 | unsigned int is_loopback : 1; /**< is address loopback? */ | |
21 | }; | |
22 | ||
23 | /** Array of addresses to test with. */ | |
24 | static struct address_test test_addrs[] = { | |
25 | { "::", "0::", | |
26 | {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, | |
27 | "AAAAAA", "_", 0, 0, 0 }, | |
28 | { "::1", "0::1", | |
29 | {{ 0, 0, 0, 0, 0, 0, 0, 1 }}, | |
30 | "AAAAAA", "_AAB", 1, 0, 1 }, | |
31 | { "127.0.0.1", "127.0.0.1", | |
32 | {{ 0, 0, 0, 0, 0, 0, 0x7f00, 1 }}, | |
33 | "B]AAAB", "B]AAAB", 1, 1, 1 }, | |
34 | { "::ffff:127.0.0.3", "127.0.0.3", | |
35 | {{ 0, 0, 0, 0, 0, 0xffff, 0x7f00, 3 }}, | |
36 | "B]AAAD", "B]AAAD", 1, 1, 1 }, | |
37 | { "::127.0.0.1", "127.0.0.1", | |
38 | {{ 0, 0, 0, 0, 0, 0, 0x7f00, 1 }}, | |
39 | "B]AAAB", "B]AAAB", 1, 1, 1 }, | |
40 | { "2002:7f00:3::1", "2002:7f00:3::1", | |
41 | {{ 0x2002, 0x7f00, 3, 0, 0, 0, 0, 1 }}, | |
42 | "B]AAAD", "CACH8AAAD_AAB", 1, 0, 0 }, | |
43 | { "8352:0344:0:0:0:0:2001:1204", "8352:344::2001:1204", | |
44 | {{ 0x8352, 0x344, 0, 0, 0, 0, 0x2001, 0x1204 }}, | |
45 | "AAAAAA", "INSANE_CABBIE", 1, 0, 0 }, | |
46 | { "1:2:3:4:5:6:7:8", "1:2:3:4:5:6:7:8", | |
47 | {{ 1, 2, 3, 4, 5, 6, 7, 8 }}, | |
48 | "AAAAAA", "AABAACAADAAEAAFAAGAAHAAI", 1, 0, 0 }, | |
49 | { 0 }, | |
50 | }; | |
51 | ||
52 | /** Perform tests for a single IP address. | |
53 | * @param[in] addr Address test structure. | |
54 | */ | |
55 | static void | |
56 | test_address(struct address_test *addr) | |
57 | { | |
58 | struct irc_in_addr parsed; | |
59 | unsigned int ii, len, val; | |
60 | char unparsed[64], base64_v4[64], base64_v6[64]; | |
61 | ||
62 | /* Convert expected address to network order. */ | |
63 | for (ii = 0; ii < 8; ++ii) | |
64 | addr->expected.in6_16[ii] = htons(addr->expected.in6_16[ii]); | |
65 | /* Make sure the text form is parsed as expected. */ | |
66 | len = ircd_aton(&parsed, addr->text); | |
67 | assert(len == strlen(addr->text)); | |
68 | assert(!irc_in_addr_cmp(&parsed, &addr->expected)); | |
69 | /* Make sure it converts back to ASCII. */ | |
70 | ircd_ntoa_r(unparsed, &parsed); | |
71 | assert(!strcmp(unparsed, addr->canonical)); | |
72 | /* Check IP-to-base64 conversion. */ | |
73 | iptobase64(base64_v4, &parsed, sizeof(base64_v4), 0); | |
74 | iptobase64(base64_v6, &parsed, sizeof(base64_v6), 1); | |
75 | if (addr->base64_v4) | |
76 | assert(!strcmp(base64_v4, addr->base64_v4)); | |
77 | if (addr->base64_v6) | |
78 | assert(!strcmp(base64_v6, addr->base64_v6)); | |
79 | /* Check testable attributes. */ | |
80 | val = irc_in_addr_valid(&parsed); | |
81 | assert(!!val == addr->is_valid); | |
82 | val = irc_in_addr_is_ipv4(&parsed); | |
83 | assert(!!val == addr->is_ipv4); | |
84 | val = irc_in_addr_is_loopback(&parsed); | |
85 | assert(!!val == addr->is_loopback); | |
86 | /* Check base64-to-IP conversion. */ | |
87 | if (addr->is_ipv4) { | |
88 | base64toip(addr->base64_v4, &parsed); | |
89 | assert(!memcmp(parsed.in6_16+6, addr->expected.in6_16+6, 4)); | |
90 | } else { | |
91 | base64toip(addr->base64_v6, &parsed); | |
92 | assert(!memcmp(&parsed, &addr->expected, sizeof(parsed))); | |
93 | } | |
94 | /* Tests completed. */ | |
95 | printf("Passed: %s (%s/%s)\n", addr->text, base64_v4, base64_v6); | |
96 | } | |
97 | ||
98 | /** Structure to describe a test for IP mask parsing. */ | |
99 | struct ipmask_test { | |
100 | const char *text; /**< Textual IP mask to parse. */ | |
101 | struct irc_in_addr expected; /**< Canonical form of address. */ | |
102 | unsigned int is_ipmask : 1; /**< Parse as an ipmask? */ | |
103 | unsigned int is_parseable : 1; /**< Is address parseable? */ | |
104 | unsigned int exp_bits : 8; /**< Number of bits expected in netmask */ | |
105 | }; | |
106 | ||
107 | /** Array of ipmasks to test with. */ | |
108 | static struct ipmask_test test_masks[] = { | |
109 | { "::", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 1, 128 }, | |
110 | { "::/0", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 1, 0 }, | |
111 | { "::10.0.0.0", {{ 0, 0, 0, 0, 0, 0, 0xa00, 0 }}, 1, 1, 128 }, | |
112 | { "192.168/16", {{ 0, 0, 0, 0, 0, 0xffff, 0xc0a8, 0 }}, 1, 1, 112 }, | |
113 | { "192.*", {{ 0, 0, 0, 0, 0, 0xffff, 0xc000, 0 }}, 1, 1, 104 }, | |
114 | { "192.*/8", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 0, 0 }, | |
115 | { "192*", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 0, 0 }, | |
116 | { "192.168.0.0/16", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0, 0, 0 }, | |
117 | { "ab.*", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 0, 0 }, | |
118 | { "a*", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 0, 0 }, | |
119 | { "*", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 1, 0 }, | |
120 | { "a:b", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 0, 0 }, | |
121 | { "a::*", {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 1, 0, 0 }, | |
122 | { "a:*", {{ 0xa, 0, 0, 0, 0, 0, 0, 0 }}, 1, 1, 16 }, | |
123 | { "a:/16", {{ 0xa, 0, 0, 0, 0, 0, 0, 0 }}, 1, 1, 16 }, | |
124 | { 0 } | |
125 | }; | |
126 | ||
127 | /** Perform tests for a single IP mask. | |
128 | * @param[in] mask IP mask test structure. | |
129 | */ | |
130 | static void | |
131 | test_ipmask(struct ipmask_test *mask) | |
132 | { | |
133 | struct irc_in_addr parsed; | |
134 | unsigned int len, ii; | |
135 | unsigned char bits = 0; | |
136 | ||
137 | /* Convert expected address to network order. */ | |
138 | for (ii = 0; ii < 8; ++ii) | |
139 | mask->expected.in6_16[ii] = htons(mask->expected.in6_16[ii]); | |
140 | /* Try to parse; make sure its parseability and netmask length are | |
141 | * as expected. */ | |
142 | len = ipmask_parse(mask->text, &parsed, mask->is_ipmask ? &bits : 0); | |
143 | assert(!!len == mask->is_parseable); | |
144 | if (!len) { | |
145 | printf("X-Fail: %s\n", mask->text); | |
146 | return; | |
147 | } | |
148 | if (mask->is_ipmask) | |
149 | assert(bits == mask->exp_bits); | |
150 | assert(!memcmp(&parsed, &mask->expected, sizeof(parsed))); | |
151 | printf("Passed: %s (%s/%u)\n", mask->text, ircd_ntoa(&parsed), bits); | |
152 | } | |
153 | ||
154 | int | |
155 | main(int argc, char *argv[]) | |
156 | { | |
157 | unsigned int ii; | |
158 | ||
159 | printf("Testing address parsing..\n"); | |
160 | for (ii = 0; test_addrs[ii].text; ++ii) | |
161 | test_address(&test_addrs[ii]); | |
162 | ||
163 | printf("\nTesting ipmask parsing..\n"); | |
164 | for (ii = 0; test_masks[ii].text; ++ii) | |
165 | test_ipmask(&test_masks[ii]); | |
166 | ||
167 | return 0; | |
168 | } |