Make ACLs IPv6-capable.
[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  ***/
30
31 #include "asterisk.h"
32
33 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
34
35 #include "asterisk/test.h"
36 #include "asterisk/acl.h"
37 #include "asterisk/module.h"
38 #include "asterisk/netsock2.h"
39 #include "asterisk/config.h"
40
41 AST_TEST_DEFINE(invalid_acl)
42 {
43         const char * invalid_acls[] = {
44                 /* Negative netmask */
45                 "1.3.3.7/-1",
46                 /* Netmask too large */
47                 "1.3.3.7/33",
48                 /* Netmask waaaay too large */
49                 "1.3.3.7/92342348927389492307420",
50                 /* Netmask non-numeric */
51                 "1.3.3.7/California",
52                 /* Too many octets in Netmask */
53                 "1.3.3.7/255.255.255.255.255",
54                 /* Octets in IP address exceed 255 */
55                 "57.60.278.900/31",
56                 /* Octets in IP address exceed 255 and are negative */
57                 "400.32.201029.-6/24",
58                 /* Invalidly formatted IP address */
59                 "EGGSOFDEATH/4000",
60                 /* Too many octets in IP address */
61                 "33.4.7.8.3/300030",
62                 /* Too many octets in Netmask */
63                 "1.2.3.4/6.7.8.9.0",
64                 /* Too many octets in IP address */
65                 "3.1.4.1.5.9/3",
66                 /* IPv6 address has multiple double colons */
67                 "ff::ff::ff/3",
68                 /* IPv6 address is too long */
69                 "1234:5678:90ab:cdef:1234:5678:90ab:cdef:1234/56",
70                 /* IPv6 netmask is too large */
71                 "::ffff/129",
72                 /* IPv4-mapped IPv6 address has too few octets */
73                 "::ffff:255.255.255/128",
74                 /* Leading and trailing colons for IPv6 address */
75                 ":1234:/15",
76                 /* IPv6 address and IPv4 netmask */
77                 "fe80::1234/255.255.255.0",
78         };
79
80         enum ast_test_result_state res = AST_TEST_PASS;
81         struct ast_ha *ha = NULL;
82         int i;
83
84         switch (cmd) {
85         case TEST_INIT:
86                 info->name = "invalid_acl";
87                 info->category = "/main/acl/";
88                 info->summary = "Invalid ACL unit test";
89                 info->description =
90                         "Ensures that garbage ACL values are not accepted";
91                 return AST_TEST_NOT_RUN;
92         case TEST_EXECUTE:
93                 break;
94         }
95
96         for (i = 0; i < ARRAY_LEN(invalid_acls); ++i) {
97                 int err = 0;
98                 ha = ast_append_ha("permit", invalid_acls[i], ha, &err);
99                 if (ha || !err) {
100                         ast_test_status_update(test, "ACL %s accepted even though it is total garbage.\n",
101                                         invalid_acls[i]);
102                         if (ha) {
103                                 ast_free_ha(ha);
104                         }
105                         res = AST_TEST_FAIL;
106                 }
107         }
108
109         return res;
110 }
111
112 struct acl {
113         const char *host;
114         const char *access;
115 };
116
117 /* These constants are defined for the sole purpose of being shorter
118  * than their real names. It makes lines in this test quite a bit shorter
119  */
120
121 #define TACL_A AST_SENSE_ALLOW
122 #define TACL_D AST_SENSE_DENY
123
124 AST_TEST_DEFINE(acl)
125 {
126         struct acl permitallv4 = { "0.0.0.0/0", "permit" };
127         struct acl denyallv4 = { "0.0.0.0/0", "deny" };
128         struct acl permitallv6 = { "::/0", "permit" };
129         struct acl denyallv6 = { "::/0", "deny" };
130         struct acl acl1[] = {
131                 { "0.0.0.0/0.0.0.0", "deny" },
132                 { "10.0.0.0/255.0.0.0", "permit" },
133                 { "192.168.0.0/255.255.255.0", "permit" },
134         };
135         struct acl acl2[] = {
136                 { "10.0.0.0/8", "deny" },
137                 { "10.0.0.0/8", "permit" },
138                 { "10.0.0.0/16", "deny" },
139                 { "10.0.0.0/24", "permit" },
140         };
141
142         struct acl acl3[] = {
143                 { "::/0", "deny" },
144                 { "fe80::/64", "permit" },
145         };
146
147         struct acl acl4[] = {
148                 { "::/0", "deny" },
149                 { "fe80::/64", "permit" },
150                 { "fe80::ffff:0:0:0/80", "deny" },
151                 { "fe80::ffff:0:ffff:0/112", "permit" },
152         };
153
154         struct {
155                 const char *test_address;
156                 int v4_permitall_result;
157                 int v4_denyall_result;
158                 int v6_permitall_result;
159                 int v6_denyall_result;
160                 int acl1_result;
161                 int acl2_result;
162                 int acl3_result;
163                 int acl4_result;
164         } acl_tests[] = {
165                 { "10.1.1.5", TACL_A, TACL_D, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A },
166                 { "192.168.0.5", TACL_A, TACL_D, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A },
167                 { "192.168.1.5", TACL_A, TACL_D, TACL_A, TACL_A, TACL_D, TACL_A, TACL_A, TACL_A },
168                 { "10.0.0.1", TACL_A, TACL_D, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A },
169                 { "10.0.10.10", TACL_A, TACL_D, TACL_A, TACL_A, TACL_A, TACL_D, TACL_A, TACL_A },
170                 { "172.16.0.1", TACL_A, TACL_D, TACL_A, TACL_A, TACL_D, TACL_A, TACL_A, TACL_A },
171                 { "fe80::1234", TACL_A, TACL_A, TACL_A, TACL_D, TACL_A, TACL_A, TACL_A, TACL_A },
172                 { "fe80:1234::1234", TACL_A, TACL_A, TACL_A, TACL_D, TACL_A, TACL_A, TACL_D, TACL_D, },
173                 { "fe80::ffff:1213:dead:beef", TACL_A, TACL_A, TACL_A, TACL_D, TACL_A, TACL_A, TACL_A, TACL_D },
174                 { "fe80::ffff:0:ffff:ABCD", TACL_A, TACL_A, TACL_A, TACL_D, TACL_A, TACL_A, TACL_A, TACL_A },
175         };
176
177         struct ast_ha *permit_hav4 = NULL;
178         struct ast_ha *deny_hav4 = NULL;
179         struct ast_ha *permit_hav6 = NULL;
180         struct ast_ha *deny_hav6 = NULL;
181         struct ast_ha *ha1 = NULL;
182         struct ast_ha *ha2 = NULL;
183         struct ast_ha *ha3 = NULL;
184         struct ast_ha *ha4 = NULL;
185         enum ast_test_result_state res = AST_TEST_PASS;
186         int err = 0;
187         int i;
188
189         switch (cmd) {
190         case TEST_INIT:
191                 info->name = "acl";
192                 info->category = "/main/acl/";
193                 info->summary = "ACL unit test";
194                 info->description =
195                         "Tests that hosts are properly permitted or denied";
196                 return AST_TEST_NOT_RUN;
197         case TEST_EXECUTE:
198                 break;
199         }
200
201         if (!(permit_hav4 = ast_append_ha(permitallv4.access, permitallv4.host, permit_hav4, &err))) {
202                 ast_test_status_update(test, "Failed to create permit_all ACL\n");
203                 res = AST_TEST_FAIL;
204                 goto acl_cleanup;
205         }
206
207         if (!(deny_hav4 = ast_append_ha(denyallv4.access, denyallv4.host, deny_hav4, &err))) {
208                 ast_test_status_update(test, "Failed to create deny_all ACL\n");
209                 res = AST_TEST_FAIL;
210                 goto acl_cleanup;
211         }
212
213         if (!(permit_hav6 = ast_append_ha(permitallv6.access, permitallv6.host, permit_hav6, &err))) {
214                 ast_test_status_update(test, "Failed to create permit_all ACL\n");
215                 res = AST_TEST_FAIL;
216                 goto acl_cleanup;
217         }
218
219         if (!(deny_hav6 = ast_append_ha(denyallv6.access, denyallv6.host, deny_hav6, &err))) {
220                 ast_test_status_update(test, "Failed to create deny_all ACL\n");
221                 res = AST_TEST_FAIL;
222                 goto acl_cleanup;
223         }
224
225         for (i = 0; i < ARRAY_LEN(acl1); ++i) {
226                 if (!(ha1 = ast_append_ha(acl1[i].access, acl1[i].host, ha1, &err))) {
227                         ast_test_status_update(test, "Failed to add rule %s with access %s to ha1\n",
228                                         acl1[i].host, acl1[i].access);
229                         res = AST_TEST_FAIL;
230                         goto acl_cleanup;
231                 }
232         }
233
234         for (i = 0; i < ARRAY_LEN(acl2); ++i) {
235                 if (!(ha2 = ast_append_ha(acl2[i].access, acl2[i].host, ha2, &err))) {
236                         ast_test_status_update(test, "Failed to add rule %s with access %s to ha2\n",
237                                         acl2[i].host, acl2[i].access);
238                         res = AST_TEST_FAIL;
239                         goto acl_cleanup;
240                 }
241         }
242
243         for (i = 0; i < ARRAY_LEN(acl3); ++i) {
244                 if (!(ha3 = ast_append_ha(acl3[i].access, acl3[i].host, ha3, &err))) {
245                         ast_test_status_update(test, "Failed to add rule %s with access %s to ha3\n",
246                                         acl3[i].host, acl3[i].access);
247                         res = AST_TEST_FAIL;
248                         goto acl_cleanup;
249                 }
250         }
251
252         for (i = 0; i < ARRAY_LEN(acl4); ++i) {
253                 if (!(ha4 = ast_append_ha(acl4[i].access, acl4[i].host, ha4, &err))) {
254                         ast_test_status_update(test, "Failed to add rule %s with access %s to ha4\n",
255                                         acl4[i].host, acl4[i].access);
256                         res = AST_TEST_FAIL;
257                         goto acl_cleanup;
258                 }
259         }
260
261         for (i = 0; i < ARRAY_LEN(acl_tests); ++i) {
262                 struct ast_sockaddr addr;
263                 int permit_resv4;
264                 int permit_resv6;
265                 int deny_resv4;
266                 int deny_resv6;
267                 int acl1_res;
268                 int acl2_res;
269                 int acl3_res;
270                 int acl4_res;
271
272                 ast_sockaddr_parse(&addr, acl_tests[i].test_address, PARSE_PORT_FORBID);
273
274                 permit_resv4 = ast_apply_ha(permit_hav4, &addr);
275                 deny_resv4 = ast_apply_ha(deny_hav4, &addr);
276                 permit_resv6 = ast_apply_ha(permit_hav6, &addr);
277                 deny_resv6 = ast_apply_ha(deny_hav6, &addr);
278                 acl1_res = ast_apply_ha(ha1, &addr);
279                 acl2_res = ast_apply_ha(ha2, &addr);
280                 acl3_res = ast_apply_ha(ha3, &addr);
281                 acl4_res = ast_apply_ha(ha4, &addr);
282
283                 if (permit_resv4 != acl_tests[i].v4_permitall_result) {
284                         ast_test_status_update(test, "Access not as expected to %s on permitallv4. Expected %d but "
285                                         "got %d instead\n", acl_tests[i].test_address, acl_tests[i].v4_permitall_result, permit_resv4);
286                         res = AST_TEST_FAIL;
287                         goto acl_cleanup;
288                 }
289
290                 if (deny_resv4 != acl_tests[i].v4_denyall_result) {
291                         ast_test_status_update(test, "Access not as expected to %s on denyallv4. Expected %d but "
292                                         "got %d instead\n", acl_tests[i].test_address, acl_tests[i].v4_denyall_result, deny_resv4);
293                         res = AST_TEST_FAIL;
294                         goto acl_cleanup;
295                 }
296
297                 if (permit_resv6 != acl_tests[i].v6_permitall_result) {
298                         ast_test_status_update(test, "Access not as expected to %s on permitallv6. Expected %d but "
299                                         "got %d instead\n", acl_tests[i].test_address, acl_tests[i].v6_permitall_result, permit_resv6);
300                         res = AST_TEST_FAIL;
301                         goto acl_cleanup;
302                 }
303
304                 if (deny_resv6 != acl_tests[i].v6_denyall_result) {
305                         ast_test_status_update(test, "Access not as expected to %s on denyallv6. Expected %d but "
306                                         "got %d instead\n", acl_tests[i].test_address, acl_tests[i].v6_denyall_result, deny_resv6);
307                         res = AST_TEST_FAIL;
308                         goto acl_cleanup;
309                 }
310
311                 if (acl1_res != acl_tests[i].acl1_result) {
312                         ast_test_status_update(test, "Access not as expected to %s on acl1. Expected %d but "
313                                         "got %d instead\n", acl_tests[i].test_address, acl_tests[i].acl1_result, acl1_res);
314                         res = AST_TEST_FAIL;
315                         goto acl_cleanup;
316                 }
317
318                 if (acl2_res != acl_tests[i].acl2_result) {
319                         ast_test_status_update(test, "Access not as expected to %s on acl2. Expected %d but "
320                                         "got %d instead\n", acl_tests[i].test_address, acl_tests[i].acl2_result, acl2_res);
321                         res = AST_TEST_FAIL;
322                         goto acl_cleanup;
323                 }
324
325                 if (acl3_res != acl_tests[i].acl3_result) {
326                         ast_test_status_update(test, "Access not as expected to %s on acl3. Expected %d but "
327                                         "got %d instead\n", acl_tests[i].test_address, acl_tests[i].acl3_result, acl3_res);
328                         res = AST_TEST_FAIL;
329                         goto acl_cleanup;
330                 }
331
332                 if (acl4_res != acl_tests[i].acl4_result) {
333                         ast_test_status_update(test, "Access not as expected to %s on acl4. Expected %d but "
334                                         "got %d instead\n", acl_tests[i].test_address, acl_tests[i].acl4_result, acl4_res);
335                         res = AST_TEST_FAIL;
336                         goto acl_cleanup;
337                 }
338         }
339
340 acl_cleanup:
341         if (permit_hav4) {
342                 ast_free_ha(permit_hav4);
343         }
344         if (deny_hav4) {
345                 ast_free_ha(deny_hav4);
346         }
347         if (permit_hav6) {
348                 ast_free_ha(permit_hav6);
349         }
350         if (deny_hav6) {
351                 ast_free_ha(deny_hav6);
352         }
353         if (ha1) {
354                 ast_free_ha(ha1);
355         }
356         if (ha2) {
357                 ast_free_ha(ha2);
358         }
359         if (ha3) {
360                 ast_free_ha(ha3);
361         }
362         if (ha4) {
363                 ast_free_ha(ha4);
364         }
365         return res;
366 }
367
368 static int unload_module(void)
369 {
370         AST_TEST_UNREGISTER(invalid_acl);
371         AST_TEST_UNREGISTER(acl);
372         return 0;
373 }
374
375 static int load_module(void)
376 {
377         AST_TEST_REGISTER(invalid_acl);
378         AST_TEST_REGISTER(acl);
379         return AST_MODULE_LOAD_SUCCESS;
380 }
381
382 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "ACL test module");