Multiplatform Makefile Update
[asterisk/asterisk.git] / tests / test_acl.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2010, Digium, Inc.
5  *
6  * Mark Michelson <mmichelson@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*!
20  * \file
21  * \brief ACL unit tests
22  *
23  * \author Mark Michelson <mmichelson@digium.com>
24  *
25  */
26
27 /*** MODULEINFO
28         <depend>TEST_FRAMEWORK</depend>
29         <support_level>core</support_level>
30  ***/
31
32 #include "asterisk.h"
33
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
35
36 #include "asterisk/test.h"
37 #include "asterisk/acl.h"
38 #include "asterisk/module.h"
39 #include "asterisk/netsock2.h"
40 #include "asterisk/config.h"
41
42 AST_TEST_DEFINE(invalid_acl)
43 {
44         const char * invalid_acls[] = {
45                 /* Negative netmask */
46                 "1.3.3.7/-1",
47                 /* Netmask too large */
48                 "1.3.3.7/33",
49                 /* Netmask waaaay too large */
50                 "1.3.3.7/92342348927389492307420",
51                 /* Netmask non-numeric */
52                 "1.3.3.7/California",
53                 /* Too many octets in Netmask */
54                 "1.3.3.7/255.255.255.255.255",
55                 /* Octets in IP address exceed 255 */
56                 "57.60.278.900/31",
57                 /* Octets in IP address exceed 255 and are negative */
58                 "400.32.201029.-6/24",
59                 /* Invalidly formatted IP address */
60                 "EGGSOFDEATH/4000",
61                 /* Too many octets in IP address */
62                 "33.4.7.8.3/300030",
63                 /* Too many octets in Netmask */
64                 "1.2.3.4/6.7.8.9.0",
65                 /* Too many octets in IP address */
66                 "3.1.4.1.5.9/3",
67                 /* IPv6 address has multiple double colons */
68                 "ff::ff::ff/3",
69                 /* IPv6 address is too long */
70                 "1234:5678:90ab:cdef:1234:5678:90ab:cdef:1234/56",
71                 /* IPv6 netmask is too large */
72                 "::ffff/129",
73                 /* IPv4-mapped IPv6 address has too few octets */
74                 "::ffff:255.255.255/128",
75                 /* Leading and trailing colons for IPv6 address */
76                 ":1234:/15",
77                 /* IPv6 address and IPv4 netmask */
78                 "fe80::1234/255.255.255.0",
79         };
80
81         enum ast_test_result_state res = AST_TEST_PASS;
82         struct ast_ha *ha = NULL;
83         int i;
84
85         switch (cmd) {
86         case TEST_INIT:
87                 info->name = "invalid_acl";
88                 info->category = "/main/acl/";
89                 info->summary = "Invalid ACL unit test";
90                 info->description =
91                         "Ensures that garbage ACL values are not accepted";
92                 return AST_TEST_NOT_RUN;
93         case TEST_EXECUTE:
94                 break;
95         }
96
97         for (i = 0; i < ARRAY_LEN(invalid_acls); ++i) {
98                 int err = 0;
99                 ha = ast_append_ha("permit", invalid_acls[i], ha, &err);
100                 if (ha || !err) {
101                         ast_test_status_update(test, "ACL %s accepted even though it is total garbage.\n",
102                                         invalid_acls[i]);
103                         if (ha) {
104                                 ast_free_ha(ha);
105                         }
106                         res = AST_TEST_FAIL;
107                 }
108         }
109
110         return res;
111 }
112
113 struct acl {
114         const char *host;
115         const char *access;
116 };
117
118 /* These constants are defined for the sole purpose of being shorter
119  * than their real names. It makes lines in this test quite a bit shorter
120  */
121
122 #define TACL_A AST_SENSE_ALLOW
123 #define TACL_D AST_SENSE_DENY
124
125 AST_TEST_DEFINE(acl)
126 {
127         struct acl permitallv4 = { "0.0.0.0/0", "permit" };
128         struct acl denyallv4 = { "0.0.0.0/0", "deny" };
129         struct acl permitallv6 = { "::/0", "permit" };
130         struct acl denyallv6 = { "::/0", "deny" };
131
132         struct acl acl1[] = {
133                 { "0.0.0.0/0.0.0.0", "deny" },
134                 { "10.0.0.0/255.0.0.0", "permit" },
135                 { "192.168.0.0/255.255.255.0", "permit" },
136         };
137
138         struct acl acl2[] = {
139                 { "10.0.0.0/8", "deny" },
140                 { "10.0.0.0/8", "permit" },
141                 { "10.0.0.0/16", "deny" },
142                 { "10.0.0.0/24", "permit" },
143         };
144
145         struct acl acl3[] = {
146                 { "::/0", "deny" },
147                 { "fe80::/64", "permit" },
148         };
149
150         struct acl acl4[] = {
151                 { "::/0", "deny" },
152                 { "fe80::/64", "permit" },
153                 { "fe80::ffff:0:0:0/80", "deny" },
154                 { "fe80::ffff:0:ffff:0/112", "permit" },
155         };
156
157         struct acl acl5[] = {
158                 { "0.0.0.0/0.0.0.0", "deny" },
159                 { "10.0.0.0/255.0.0.0,192.168.0.0/255.255.255.0", "permit" },
160         };
161
162         struct acl acl6[] = {
163                 { "10.0.0.0/8", "deny" },
164                 { "10.0.0.0/8", "permit" },
165                 { "10.0.0.0/16,!10.0.0.0/24", "deny" },
166         };
167
168         struct acl acl7[] = {
169                 { "::/0,!fe80::/64", "deny" },
170                 { "fe80::ffff:0:0:0/80", "deny" },
171                 { "fe80::ffff:0:ffff:0/112", "permit" },
172         };
173
174         struct {
175                 const char *test_address;
176                 int v4_permitall_result;
177                 int v4_denyall_result;
178                 int v6_permitall_result;
179                 int v6_denyall_result;
180                 int acl1_result;
181                 int acl2_result;
182                 int acl3_result;
183                 int acl4_result;
184                 int acl5_result;
185                 int acl6_result;
186                 int acl7_result;
187         } acl_tests[] = {
188                 { "10.1.1.5",                  TACL_A, TACL_D, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A },
189                 { "192.168.0.5",               TACL_A, TACL_D, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A },
190                 { "192.168.1.5",               TACL_A, TACL_D, TACL_A, TACL_A, TACL_D, TACL_A, TACL_A, TACL_A, TACL_D, TACL_A, TACL_A },
191                 { "10.0.0.1",                  TACL_A, TACL_D, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A },
192                 { "10.0.10.10",                TACL_A, TACL_D, TACL_A, TACL_A, TACL_A, TACL_D, TACL_A, TACL_A, TACL_A, TACL_D, TACL_A },
193                 { "172.16.0.1",                TACL_A, TACL_D, TACL_A, TACL_A, TACL_D, TACL_A, TACL_A, TACL_A, TACL_D, TACL_A, TACL_A },
194                 { "fe80::1234",                TACL_A, TACL_A, TACL_A, TACL_D, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A },
195                 { "fe80::ffff:1213:dead:beef", TACL_A, TACL_A, TACL_A, TACL_D, TACL_A, TACL_A, TACL_A, TACL_D, TACL_A, TACL_A, TACL_D },
196                 { "fe80::ffff:0:ffff:ABCD",    TACL_A, TACL_A, TACL_A, TACL_D, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A },
197         };
198
199         struct ast_ha *permit_hav4 = NULL;
200         struct ast_ha *deny_hav4 = NULL;
201         struct ast_ha *permit_hav6 = NULL;
202         struct ast_ha *deny_hav6 = NULL;
203         struct ast_ha *ha1 = NULL;
204         struct ast_ha *ha2 = NULL;
205         struct ast_ha *ha3 = NULL;
206         struct ast_ha *ha4 = NULL;
207         struct ast_ha *ha5 = NULL;
208         struct ast_ha *ha6 = NULL;
209         struct ast_ha *ha7 = NULL;
210         enum ast_test_result_state res = AST_TEST_PASS;
211         int err = 0;
212         int i;
213
214         auto int build_ha(const struct acl *acl, size_t len, struct ast_ha **ha, const char *acl_name);
215         auto int build_ha(const struct acl *acl, size_t len, struct ast_ha **ha, const char *acl_name) {
216                 size_t i;
217
218                 for (i = 0; i < len; ++i) {
219                         if (!(*ha = ast_append_ha(acl[i].access, acl[i].host, *ha, &err))) {
220                                 ast_test_status_update(test, "Failed to add rule %s with access %s to %s\n",
221                                                        acl[i].host, acl[i].access, acl_name);
222                                 res = AST_TEST_FAIL;
223                                 return -1;
224                         }
225                 }
226
227                 return 0;
228         }
229
230         switch (cmd) {
231         case TEST_INIT:
232                 info->name = "acl";
233                 info->category = "/main/acl/";
234                 info->summary = "ACL unit test";
235                 info->description =
236                         "Tests that hosts are properly permitted or denied";
237                 return AST_TEST_NOT_RUN;
238         case TEST_EXECUTE:
239                 break;
240         }
241
242         if (!(permit_hav4 = ast_append_ha(permitallv4.access, permitallv4.host, permit_hav4, &err))) {
243                 ast_test_status_update(test, "Failed to create permit_all ACL\n");
244                 res = AST_TEST_FAIL;
245                 goto acl_cleanup;
246         }
247
248         if (!(deny_hav4 = ast_append_ha(denyallv4.access, denyallv4.host, deny_hav4, &err))) {
249                 ast_test_status_update(test, "Failed to create deny_all ACL\n");
250                 res = AST_TEST_FAIL;
251                 goto acl_cleanup;
252         }
253
254         if (!(permit_hav6 = ast_append_ha(permitallv6.access, permitallv6.host, permit_hav6, &err))) {
255                 ast_test_status_update(test, "Failed to create permit_all ACL\n");
256                 res = AST_TEST_FAIL;
257                 goto acl_cleanup;
258         }
259
260         if (!(deny_hav6 = ast_append_ha(denyallv6.access, denyallv6.host, deny_hav6, &err))) {
261                 ast_test_status_update(test, "Failed to create deny_all ACL\n");
262                 res = AST_TEST_FAIL;
263                 goto acl_cleanup;
264         }
265
266         if (build_ha(acl1, ARRAY_LEN(acl1), &ha1, "ha1") != 0) {
267                 goto acl_cleanup;
268         }
269
270         if (build_ha(acl2, ARRAY_LEN(acl2), &ha2, "ha2") != 0) {
271                 goto acl_cleanup;
272         }
273
274         if (build_ha(acl3, ARRAY_LEN(acl3), &ha3, "ha3") != 0) {
275                 goto acl_cleanup;
276         }
277
278         if (build_ha(acl4, ARRAY_LEN(acl4), &ha4, "ha4") != 0) {
279                 goto acl_cleanup;
280         }
281
282         if (build_ha(acl5, ARRAY_LEN(acl5), &ha5, "ha5") != 0) {
283                 goto acl_cleanup;
284         }
285
286         if (build_ha(acl6, ARRAY_LEN(acl6), &ha6, "ha6") != 0) {
287                 goto acl_cleanup;
288         }
289
290         if (build_ha(acl7, ARRAY_LEN(acl7), &ha7, "ha7") != 0) {
291                 goto acl_cleanup;
292         }
293
294         for (i = 0; i < ARRAY_LEN(acl_tests); ++i) {
295                 struct ast_sockaddr addr;
296                 int permit_resv4;
297                 int permit_resv6;
298                 int deny_resv4;
299                 int deny_resv6;
300                 int acl1_res;
301                 int acl2_res;
302                 int acl3_res;
303                 int acl4_res;
304                 int acl5_res;
305                 int acl6_res;
306                 int acl7_res;
307
308                 ast_sockaddr_parse(&addr, acl_tests[i].test_address, PARSE_PORT_FORBID);
309
310                 permit_resv4 = ast_apply_ha(permit_hav4, &addr);
311                 deny_resv4 = ast_apply_ha(deny_hav4, &addr);
312                 permit_resv6 = ast_apply_ha(permit_hav6, &addr);
313                 deny_resv6 = ast_apply_ha(deny_hav6, &addr);
314                 acl1_res = ast_apply_ha(ha1, &addr);
315                 acl2_res = ast_apply_ha(ha2, &addr);
316                 acl3_res = ast_apply_ha(ha3, &addr);
317                 acl4_res = ast_apply_ha(ha4, &addr);
318                 acl5_res = ast_apply_ha(ha5, &addr);
319                 acl6_res = ast_apply_ha(ha6, &addr);
320                 acl7_res = ast_apply_ha(ha7, &addr);
321
322                 if (permit_resv4 != acl_tests[i].v4_permitall_result) {
323                         ast_test_status_update(test, "Access not as expected to %s on permitallv4. Expected %d but "
324                                         "got %d instead\n", acl_tests[i].test_address, acl_tests[i].v4_permitall_result, permit_resv4);
325                         res = AST_TEST_FAIL;
326                         goto acl_cleanup;
327                 }
328
329                 if (deny_resv4 != acl_tests[i].v4_denyall_result) {
330                         ast_test_status_update(test, "Access not as expected to %s on denyallv4. Expected %d but "
331                                         "got %d instead\n", acl_tests[i].test_address, acl_tests[i].v4_denyall_result, deny_resv4);
332                         res = AST_TEST_FAIL;
333                         goto acl_cleanup;
334                 }
335
336                 if (permit_resv6 != acl_tests[i].v6_permitall_result) {
337                         ast_test_status_update(test, "Access not as expected to %s on permitallv6. Expected %d but "
338                                         "got %d instead\n", acl_tests[i].test_address, acl_tests[i].v6_permitall_result, permit_resv6);
339                         res = AST_TEST_FAIL;
340                         goto acl_cleanup;
341                 }
342
343                 if (deny_resv6 != acl_tests[i].v6_denyall_result) {
344                         ast_test_status_update(test, "Access not as expected to %s on denyallv6. Expected %d but "
345                                         "got %d instead\n", acl_tests[i].test_address, acl_tests[i].v6_denyall_result, deny_resv6);
346                         res = AST_TEST_FAIL;
347                         goto acl_cleanup;
348                 }
349
350                 if (acl1_res != acl_tests[i].acl1_result) {
351                         ast_test_status_update(test, "Access not as expected to %s on acl1. Expected %d but "
352                                         "got %d instead\n", acl_tests[i].test_address, acl_tests[i].acl1_result, acl1_res);
353                         res = AST_TEST_FAIL;
354                         goto acl_cleanup;
355                 }
356
357                 if (acl2_res != acl_tests[i].acl2_result) {
358                         ast_test_status_update(test, "Access not as expected to %s on acl2. Expected %d but "
359                                         "got %d instead\n", acl_tests[i].test_address, acl_tests[i].acl2_result, acl2_res);
360                         res = AST_TEST_FAIL;
361                         goto acl_cleanup;
362                 }
363
364                 if (acl3_res != acl_tests[i].acl3_result) {
365                         ast_test_status_update(test, "Access not as expected to %s on acl3. Expected %d but "
366                                         "got %d instead\n", acl_tests[i].test_address, acl_tests[i].acl3_result, acl3_res);
367                         res = AST_TEST_FAIL;
368                         goto acl_cleanup;
369                 }
370
371                 if (acl4_res != acl_tests[i].acl4_result) {
372                         ast_test_status_update(test, "Access not as expected to %s on acl4. Expected %d but "
373                                         "got %d instead\n", acl_tests[i].test_address, acl_tests[i].acl4_result, acl4_res);
374                         res = AST_TEST_FAIL;
375                         goto acl_cleanup;
376                 }
377
378                 if (acl5_res != acl_tests[i].acl5_result) {
379                         ast_test_status_update(test, "Access not as expected to %s on acl5. Expected %d but "
380                                         "got %d instead\n", acl_tests[i].test_address, acl_tests[i].acl5_result, acl5_res);
381                         res = AST_TEST_FAIL;
382                         goto acl_cleanup;
383                 }
384
385                 if (acl6_res != acl_tests[i].acl6_result) {
386                         ast_test_status_update(test, "Access not as expected to %s on acl6. Expected %d but "
387                                         "got %d instead\n", acl_tests[i].test_address, acl_tests[i].acl6_result, acl6_res);
388                         res = AST_TEST_FAIL;
389                         goto acl_cleanup;
390                 }
391
392                 if (acl7_res != acl_tests[i].acl7_result) {
393                         ast_test_status_update(test, "Access not as expected to %s on acl7. Expected %d but "
394                                         "got %d instead\n", acl_tests[i].test_address, acl_tests[i].acl7_result, acl7_res);
395                         res = AST_TEST_FAIL;
396                         goto acl_cleanup;
397                 }
398         }
399
400 acl_cleanup:
401         if (permit_hav4) {
402                 ast_free_ha(permit_hav4);
403         }
404         if (deny_hav4) {
405                 ast_free_ha(deny_hav4);
406         }
407         if (permit_hav6) {
408                 ast_free_ha(permit_hav6);
409         }
410         if (deny_hav6) {
411                 ast_free_ha(deny_hav6);
412         }
413         if (ha1) {
414                 ast_free_ha(ha1);
415         }
416         if (ha2) {
417                 ast_free_ha(ha2);
418         }
419         if (ha3) {
420                 ast_free_ha(ha3);
421         }
422         if (ha4) {
423                 ast_free_ha(ha4);
424         }
425         if (ha5) {
426                 ast_free_ha(ha5);
427         }
428         if (ha6) {
429                 ast_free_ha(ha6);
430         }
431         if (ha7) {
432                 ast_free_ha(ha7);
433         }
434         return res;
435 }
436
437 static int unload_module(void)
438 {
439         AST_TEST_UNREGISTER(invalid_acl);
440         AST_TEST_UNREGISTER(acl);
441         return 0;
442 }
443
444 static int load_module(void)
445 {
446         AST_TEST_REGISTER(invalid_acl);
447         AST_TEST_REGISTER(acl);
448         return AST_MODULE_LOAD_SUCCESS;
449 }
450
451 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "ACL test module");