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