1 /* -*- coding: utf-8 -*-
2  * ----------------------------------------------------------------------
3  * Copyright © 2009-2012, RedJack, LLC.
4  * All rights reserved.
5  *
6  * Please see the LICENSE.txt file in this distribution for license
7  * details.
8  * ----------------------------------------------------------------------
9  */
10 
11 #include <stdlib.h>
12 
13 #include <check.h>
14 #include <libcork/core.h>
15 
16 #include "ipset/ipset.h"
17 
18 
19 #define IPV4_BIT_SIZE  32
20 #define IPV6_BIT_SIZE  128
21 
22 
23 /*-----------------------------------------------------------------------
24  * Iterators
25  */
26 
START_TEST(test_iterate_empty)27 START_TEST(test_iterate_empty)
28 {
29     struct ip_set  set;
30     ipset_init(&set);
31     struct ipset_iterator  *it = ipset_iterate(&set, true);
32     fail_if(it == NULL,
33             "IP set iterator is NULL");
34     fail_unless(it->finished,
35                 "IP set should be empty");
36     ipset_iterator_free(it);
37     ipset_done(&set);
38 }
39 END_TEST
40 
41 
START_TEST(test_ipv4_iterate_01)42 START_TEST(test_ipv4_iterate_01)
43 {
44     struct ip_set  set;
45     ipset_init(&set);
46 
47     struct cork_ip  ip1;
48     cork_ip_init(&ip1, "192.168.0.1");
49 
50     fail_if(ipset_ip_add(&set, &ip1),
51             "Element should not be present");
52 
53     struct ipset_iterator  *it = ipset_iterate(&set, true);
54     fail_if(it == NULL,
55             "IP set iterator is NULL");
56 
57     fail_if(it->finished,
58             "IP set shouldn't be empty");
59     fail_unless(cork_ip_equal(&ip1, &it->addr),
60                 "IP address 0 doesn't match");
61     fail_unless(it->cidr_prefix == IPV4_BIT_SIZE,
62                 "IP CIDR prefix 0 doesn't match");
63 
64     ipset_iterator_advance(it);
65     fail_unless(it->finished,
66                 "IP set should contain 1 element");
67 
68     ipset_iterator_free(it);
69 
70     ipset_done(&set);
71 }
72 END_TEST
73 
74 
START_TEST(test_ipv4_iterate_network_01)75 START_TEST(test_ipv4_iterate_network_01)
76 {
77     struct ip_set  set;
78     ipset_init(&set);
79 
80     struct cork_ip  ip1;
81     cork_ip_init(&ip1, "192.168.0.0");
82 
83     fail_if(ipset_ip_add_network(&set, &ip1, 31),
84             "Element should not be present");
85 
86     struct ipset_iterator  *it = ipset_iterate_networks(&set, true);
87     fail_if(it == NULL,
88             "IP set iterator is NULL");
89 
90     fail_if(it->finished,
91             "IP set shouldn't be empty");
92     fail_unless(cork_ip_equal(&ip1, &it->addr),
93                 "IP address 0 doesn't match");
94     fail_unless(it->cidr_prefix == 31,
95                 "IP CIDR prefix 0 doesn't match");
96 
97     ipset_iterator_advance(it);
98     fail_unless(it->finished,
99                 "IP set should contain 1 elements");
100 
101     ipset_iterator_free(it);
102 
103     ipset_done(&set);
104 }
105 END_TEST
106 
107 
START_TEST(test_ipv4_iterate_network_02)108 START_TEST(test_ipv4_iterate_network_02)
109 {
110     struct ip_set  set;
111     ipset_init(&set);
112 
113     struct cork_ip  ip1;
114     cork_ip_init(&ip1, "192.168.0.0");
115 
116     fail_if(ipset_ip_add_network(&set, &ip1, 16),
117             "Element should not be present");
118 
119     struct ipset_iterator  *it = ipset_iterate_networks(&set, true);
120     fail_if(it == NULL,
121             "IP set iterator is NULL");
122 
123     fail_if(it->finished,
124             "IP set shouldn't be empty");
125     fail_unless(cork_ip_equal(&ip1, &it->addr),
126                 "IP address 0 doesn't match");
127     fail_unless(it->cidr_prefix == 16,
128                 "IP CIDR prefix 0 doesn't match");
129 
130     ipset_iterator_advance(it);
131     fail_unless(it->finished,
132                 "IP set should contain 1 elements");
133 
134     ipset_iterator_free(it);
135 
136     ipset_done(&set);
137 }
138 END_TEST
139 
140 
START_TEST(test_ipv4_iterate_network_03)141 START_TEST(test_ipv4_iterate_network_03)
142 {
143     struct ip_set  set;
144     ipset_init(&set);
145 
146     /*
147      * If we add all of the IP addresses in a network individually, we
148      * should still get the network as a whole from the iterator.
149      */
150 
151     struct cork_ip  ip1;
152     cork_ip_init(&ip1, "192.168.0.0");
153 
154     struct cork_ip  ip2;
155     cork_ip_init(&ip2, "192.168.0.1");
156 
157     fail_if(ipset_ip_add(&set, &ip1),
158             "Element should not be present");
159 
160     fail_if(ipset_ip_add(&set, &ip2),
161             "Element should not be present");
162 
163     struct ipset_iterator  *it = ipset_iterate_networks(&set, true);
164     fail_if(it == NULL,
165             "IP set iterator is NULL");
166 
167     fail_if(it->finished,
168             "IP set shouldn't be empty");
169     fail_unless(cork_ip_equal(&ip1, &it->addr),
170                 "IP address 0 doesn't match");
171     fail_unless(it->cidr_prefix == 31,
172                 "IP CIDR prefix 0 doesn't match");
173 
174     ipset_iterator_advance(it);
175     fail_unless(it->finished,
176                 "IP set should contain 1 elements");
177 
178     ipset_iterator_free(it);
179 
180     ipset_done(&set);
181 }
182 END_TEST
183 
184 
START_TEST(test_ipv6_iterate_01)185 START_TEST(test_ipv6_iterate_01)
186 {
187     struct ip_set  set;
188     ipset_init(&set);
189 
190     struct cork_ip  ip1;
191     cork_ip_init(&ip1, "fe80::1");
192 
193     fail_if(ipset_ip_add(&set, &ip1),
194             "Element should not be present");
195 
196     struct ipset_iterator  *it = ipset_iterate(&set, true);
197     fail_if(it == NULL,
198             "IP set iterator is NULL");
199 
200     fail_if(it->finished,
201             "IP set shouldn't be empty");
202     fail_unless(cork_ip_equal(&ip1, &it->addr),
203                 "IP address 0 doesn't match");
204     fail_unless(it->cidr_prefix == IPV6_BIT_SIZE,
205                 "IP CIDR prefix 0 doesn't match");
206 
207     ipset_iterator_advance(it);
208     fail_unless(it->finished,
209                 "IP set should contain 1 element");
210 
211     ipset_iterator_free(it);
212 
213     ipset_done(&set);
214 }
215 END_TEST
216 
217 
START_TEST(test_ipv6_iterate_network_01)218 START_TEST(test_ipv6_iterate_network_01)
219 {
220     struct ip_set  set;
221     ipset_init(&set);
222 
223     struct cork_ip  ip1;
224     cork_ip_init(&ip1, "fe80::");
225 
226     fail_if(ipset_ip_add_network(&set, &ip1, 127),
227             "Element should not be present");
228 
229     struct ipset_iterator  *it = ipset_iterate_networks(&set, true);
230     fail_if(it == NULL,
231             "IP set iterator is NULL");
232 
233     fail_if(it->finished,
234             "IP set shouldn't be empty");
235     fail_unless(cork_ip_equal(&ip1, &it->addr),
236                 "IP address 0 doesn't match");
237     fail_unless(it->cidr_prefix == 127,
238                 "IP CIDR prefix 0 doesn't match (%u)", it->cidr_prefix);
239 
240     ipset_iterator_advance(it);
241     fail_unless(it->finished,
242                 "IP set should contain 1 element");
243 
244     ipset_iterator_free(it);
245 
246     ipset_done(&set);
247 }
248 END_TEST
249 
250 
START_TEST(test_ipv6_iterate_network_02)251 START_TEST(test_ipv6_iterate_network_02)
252 {
253     struct ip_set  set;
254     ipset_init(&set);
255 
256     struct cork_ip  ip1;
257     cork_ip_init(&ip1, "fe80::");
258 
259     fail_if(ipset_ip_add_network(&set, &ip1, 16),
260             "Element should not be present");
261 
262     struct ipset_iterator  *it = ipset_iterate_networks(&set, true);
263     fail_if(it == NULL,
264             "IP set iterator is NULL");
265 
266     fail_if(it->finished,
267             "IP set shouldn't be empty");
268     fail_unless(cork_ip_equal(&ip1, &it->addr),
269                 "IP address 0 doesn't match");
270     fail_unless(it->cidr_prefix == 16,
271                 "IP CIDR prefix 0 doesn't match (%u)", it->cidr_prefix);
272 
273     ipset_iterator_advance(it);
274     fail_unless(it->finished,
275                 "IP set should contain 1 element");
276 
277     ipset_iterator_free(it);
278 
279     ipset_done(&set);
280 }
281 END_TEST
282 
283 
START_TEST(test_ipv6_iterate_network_03)284 START_TEST(test_ipv6_iterate_network_03)
285 {
286     struct ip_set  set;
287     ipset_init(&set);
288 
289     /*
290      * If we add all of the IP addresses in a network individually, we
291      * should still get the network as a whole from the iterator.
292      */
293 
294     struct cork_ip  ip1;
295     cork_ip_init(&ip1, "fe80::");
296 
297     struct cork_ip  ip2;
298     cork_ip_init(&ip2, "fe80::1");
299 
300     fail_if(ipset_ip_add(&set, &ip1),
301             "Element should not be present");
302 
303     fail_if(ipset_ip_add(&set, &ip2),
304             "Element should not be present");
305 
306     struct ipset_iterator  *it = ipset_iterate_networks(&set, true);
307     fail_if(it == NULL,
308             "IP set iterator is NULL");
309 
310     fail_if(it->finished,
311             "IP set shouldn't be empty");
312     fail_unless(cork_ip_equal(&ip1, &it->addr),
313                 "IP address 0 doesn't match");
314     fail_unless(it->cidr_prefix == 127,
315                 "IP CIDR prefix 0 doesn't match");
316 
317     ipset_iterator_advance(it);
318     fail_unless(it->finished,
319                 "IP set should contain 1 elements");
320 
321     ipset_iterator_free(it);
322 
323     ipset_done(&set);
324 }
325 END_TEST
326 
327 
START_TEST(test_generic_ip_iterate_01)328 START_TEST(test_generic_ip_iterate_01)
329 {
330     struct ip_set  set;
331     ipset_init(&set);
332 
333     struct cork_ip  ip1;
334     cork_ip_init(&ip1, "0.0.0.0");
335 
336     struct cork_ip  ip2;
337     cork_ip_init(&ip2, "::");
338 
339     struct ipset_iterator  *it = ipset_iterate_networks(&set, false);
340     fail_if(it == NULL,
341             "IP set iterator is NULL");
342 
343     fail_if(it->finished,
344             "IP set shouldn't be empty");
345     fail_unless(cork_ip_equal(&ip1, &it->addr),
346                 "IP address 0 doesn't match");
347     fail_unless(it->cidr_prefix == 0,
348                 "IP CIDR prefix 0 doesn't match");
349 
350     ipset_iterator_advance(it);
351     fail_if(it->finished,
352             "IP set should have more than 1 element");
353     fail_unless(cork_ip_equal(&ip2, &it->addr),
354                 "IP address 1 doesn't match");
355     fail_unless(it->cidr_prefix == 0,
356                 "IP CIDR prefix 1 doesn't match");
357 
358     ipset_iterator_advance(it);
359     fail_unless(it->finished,
360                 "IP set should contain 2 elements");
361 
362     ipset_iterator_free(it);
363 
364     ipset_done(&set);
365 }
366 END_TEST
367 
368 
START_TEST(test_generic_ip_iterate_02)369 START_TEST(test_generic_ip_iterate_02)
370 {
371     struct ip_set  set;
372     ipset_init(&set);
373 
374     /*
375      * These addresses are carefully constructed so that the same BDD
376      * variable assignments are used to store both, apart from the
377      * IPv4/v6 discriminator variable.  The goal is get a BDD that has
378      * EITHER in the assignment for variable 0, but isn't simply the
379      * empty or full set.
380      */
381 
382     struct cork_ip  ip1;
383     cork_ip_init(&ip1, "192.168.0.1"); /* 0xc0a80001 */
384 
385     struct cork_ip  ip2;
386     cork_ip_init(&ip2, "c0a8:0001::");
387 
388     fail_if(ipset_ip_add(&set, &ip1),
389             "Element should not be present");
390     fail_if(ipset_ip_add_network(&set, &ip2, 32),
391             "Element should not be present");
392 
393     struct ipset_iterator  *it = ipset_iterate_networks(&set, true);
394     fail_if(it == NULL,
395             "IP set iterator is NULL");
396 
397     fail_if(it->finished,
398             "IP set shouldn't be empty");
399     fail_unless(cork_ip_equal(&ip1, &it->addr),
400                 "IP address 0 doesn't match");
401     fail_unless(it->cidr_prefix == 32,
402                 "IP CIDR prefix 0 doesn't match");
403 
404     ipset_iterator_advance(it);
405     fail_if(it->finished,
406             "IP set should have more than 1 element");
407     fail_unless(cork_ip_equal(&ip2, &it->addr),
408                 "IP address 1 doesn't match");
409     fail_unless(it->cidr_prefix == 32,
410                 "IP CIDR prefix 1 doesn't match");
411 
412     ipset_iterator_advance(it);
413     fail_unless(it->finished,
414                 "IP set should contain 2 elements");
415 
416     ipset_iterator_free(it);
417 
418     ipset_done(&set);
419 }
420 END_TEST
421 
422 
423 /*-----------------------------------------------------------------------
424  * Testing harness
425  */
426 
427 Suite *
ipset_suite()428 ipset_suite()
429 {
430     Suite  *s = suite_create("ipset");
431 
432     TCase  *tc_iterator = tcase_create("iterator");
433     tcase_add_test(tc_iterator, test_iterate_empty);
434     tcase_add_test(tc_iterator, test_ipv4_iterate_01);
435     tcase_add_test(tc_iterator, test_ipv4_iterate_network_01);
436     tcase_add_test(tc_iterator, test_ipv4_iterate_network_02);
437     tcase_add_test(tc_iterator, test_ipv4_iterate_network_03);
438     tcase_add_test(tc_iterator, test_ipv6_iterate_01);
439     tcase_add_test(tc_iterator, test_ipv6_iterate_network_01);
440     tcase_add_test(tc_iterator, test_ipv6_iterate_network_02);
441     tcase_add_test(tc_iterator, test_ipv6_iterate_network_03);
442     tcase_add_test(tc_iterator, test_generic_ip_iterate_01);
443     tcase_add_test(tc_iterator, test_generic_ip_iterate_02);
444     suite_add_tcase(s, tc_iterator);
445 
446     return s;
447 }
448 
449 
450 int
main(int argc,const char ** argv)451 main(int argc, const char **argv)
452 {
453     int  number_failed;
454     Suite  *suite = ipset_suite();
455     SRunner  *runner = srunner_create(suite);
456 
457     ipset_init_library();
458 
459     srunner_run_all(runner, CK_NORMAL);
460     number_failed = srunner_ntests_failed(runner);
461     srunner_free(runner);
462 
463     return (number_failed == 0)? EXIT_SUCCESS: EXIT_FAILURE;
464 }
465