Add unit test for testing ACL functionality.
authorMark Michelson <mmichelson@digium.com>
Thu, 25 Mar 2010 17:52:20 +0000 (17:52 +0000)
committerMark Michelson <mmichelson@digium.com>
Thu, 25 Mar 2010 17:52:20 +0000 (17:52 +0000)
There are two unit tests contained here.

1. "Invalid ACL" This attempts to read a bunch of badly formatted ACL entries
and add them to a host access rule. The goal of this test is to be sure that
all invalid entries are rejected as they should be.

2. "ACL" This sets up four ACLs. One is a permit all, one is a deny all, and
the other two have specific rules about which subnets are allowed and which
are not. Then a set of test addresses is used to determine whether we would
allow those addresses to access us when each ACL is applied. This test, by the
way, was what resulted in AST-2010-003's creation.

Review: https://reviewboard.asterisk.org/r/532

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@254557 65c4cc65-6c06-0410-ace0-fbb531ad65f3

tests/test_acl.c [new file with mode: 0644]

diff --git a/tests/test_acl.c b/tests/test_acl.c
new file mode 100644 (file)
index 0000000..61bffe5
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * Mark Michelson <mmichelson@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief ACL unit tests
+ *
+ * \author Mark Michelson <mmichelson@digium.com>
+ *
+ */
+
+/*** MODULEINFO
+       <depend>TEST_FRAMEWORK</depend>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/test.h"
+#include "asterisk/acl.h"
+#include "asterisk/module.h"
+
+AST_TEST_DEFINE(invalid_acl)
+{
+       const char * invalid_acls[] = {
+               "1.3.3.7/-1",
+               "1.3.3.7/33",
+               "1.3.3.7/92342348927389492307420",
+               "1.3.3.7/California",
+               "1.3.3.7/255.255.255.255.255",
+               "57.60.278.900/31",
+               "400.32.201029.-6/24",
+               "EGGSOFDEATH/4000",
+               "33.4.7.8.3/300030",
+               "1.2.3.4/6.7.8.9.0",
+               "3.1.4.1.5.9/3",
+       };
+
+       enum ast_test_result_state res = AST_TEST_PASS;
+       struct ast_ha *ha = NULL;
+       int i;
+
+       switch (cmd) {
+       case TEST_INIT:
+               info->name = "invalid_acl";
+               info->category = "main/acl/";
+               info->summary = "Invalid ACL unit test";
+               info->description =
+                       "Ensures that garbage ACL values are not accepted";
+               return AST_TEST_NOT_RUN;
+       case TEST_EXECUTE:
+               break;
+       }
+
+       for (i = 0; i < ARRAY_LEN(invalid_acls); ++i) {
+               int err = 0;
+               ha = ast_append_ha("permit", invalid_acls[i], ha, &err);
+               if (ha || !err) {
+                       ast_test_status_update(test, "ACL %s accepted even though it is total garbage.\n",
+                                       invalid_acls[i]);
+                       if (ha) {
+                               ast_free_ha(ha);
+                       }
+                       res = AST_TEST_FAIL;
+               }
+       }
+
+       return res;
+}
+
+struct acl {
+       const char *host;
+       const char *access;
+};
+
+AST_TEST_DEFINE(acl)
+{
+       struct acl permitall = { "0.0.0.0/0", "permit" };
+       struct acl denyall = { "0.0.0.0/0", "deny" };
+       struct acl acl1[] = {
+               { "0.0.0.0/0.0.0.0", "deny" },
+               { "10.0.0.0/255.0.0.0", "permit" },
+               { "192.168.0.0/255.255.255.0", "permit" },
+       };
+       struct acl acl2[] = {
+               { "10.0.0.0/8", "deny" },
+               { "10.0.0.0/8", "permit" },
+               { "10.0.0.0/16", "deny" },
+               { "10.0.0.0/24", "permit" },
+       };
+
+       struct {
+               const char *test_address;
+               int acl1_result;
+               int acl2_result;
+       } acl_tests[] = {
+               { "10.1.1.5", AST_SENSE_ALLOW, AST_SENSE_ALLOW },
+               { "192.168.0.5", AST_SENSE_ALLOW, AST_SENSE_ALLOW },
+               { "192.168.1.5", AST_SENSE_DENY, AST_SENSE_ALLOW },
+               { "10.0.0.1", AST_SENSE_ALLOW, AST_SENSE_ALLOW },
+               { "10.0.10.10", AST_SENSE_ALLOW, AST_SENSE_DENY },
+               { "172.16.0.1", AST_SENSE_DENY, AST_SENSE_ALLOW },
+       };
+
+       struct ast_ha *permit_ha = NULL;
+       struct ast_ha *deny_ha = NULL;
+       struct ast_ha *ha1 = NULL;
+       struct ast_ha *ha2 = NULL;
+       enum ast_test_result_state res = AST_TEST_PASS;
+       int err = 0;
+       int i;
+
+       switch (cmd) {
+       case TEST_INIT:
+               info->name = "acl";
+               info->category = "main/acl/";
+               info->summary = "ACL unit test";
+               info->description =
+                       "Tests that hosts are properly permitted or denied";
+               return AST_TEST_NOT_RUN;
+       case TEST_EXECUTE:
+               break;
+       }
+
+       if (!(permit_ha = ast_append_ha(permitall.access, permitall.host, permit_ha, &err))) {
+               ast_test_status_update(test, "Failed to create permit_all ACL\n");
+               res = AST_TEST_FAIL;
+               goto acl_cleanup;
+       }
+
+       if (!(deny_ha = ast_append_ha(denyall.access, denyall.host, deny_ha, &err))) {
+               ast_test_status_update(test, "Failed to create deny_all ACL\n");
+               res = AST_TEST_FAIL;
+               goto acl_cleanup;
+       }
+
+       for (i = 0; i < ARRAY_LEN(acl1); ++i) {
+               if (!(ha1 = ast_append_ha(acl1[i].access, acl1[i].host, ha1, &err))) {
+                       ast_test_status_update(test, "Failed to add rule %s with access %s to ha1\n",
+                                       acl1[i].host, acl1[i].access);
+                       res = AST_TEST_FAIL;
+                       goto acl_cleanup;
+               }
+       }
+
+       for (i = 0; i < ARRAY_LEN(acl2); ++i) {
+               if (!(ha2 = ast_append_ha(acl2[i].access, acl2[i].host, ha2, &err))) {
+                       ast_test_status_update(test, "Failed to add rule %s with access %s to ha2\n",
+                                       acl2[i].host, acl2[i].access);
+                       res = AST_TEST_FAIL;
+                       goto acl_cleanup;
+               }
+       }
+
+       for (i = 0; i < ARRAY_LEN(acl_tests); ++i) {
+               struct sockaddr_in sin;
+               int permit_res;
+               int deny_res;
+               int acl1_res;
+               int acl2_res;
+
+               inet_aton(acl_tests[i].test_address, &sin.sin_addr);
+
+               permit_res = ast_apply_ha(permit_ha, &sin);
+               deny_res = ast_apply_ha(deny_ha, &sin);
+               acl1_res = ast_apply_ha(ha1, &sin);
+               acl2_res = ast_apply_ha(ha2, &sin);
+
+               if (permit_res != AST_SENSE_ALLOW) {
+                       ast_test_status_update(test, "Access denied to %s on permit_all ACL\n",
+                                       acl_tests[i].test_address);
+                       res = AST_TEST_FAIL;
+                       goto acl_cleanup;
+               }
+
+               if (deny_res != AST_SENSE_DENY) {
+                       ast_test_status_update(test, "Access allowed to %s on deny_all ACL\n",
+                                       acl_tests[i].test_address);
+                       res = AST_TEST_FAIL;
+                       goto acl_cleanup;
+               }
+
+               if (acl1_res != acl_tests[i].acl1_result) {
+                       ast_test_status_update(test, "Access not as expected to %s on acl1. Expected %d but"
+                                       "got %d instead\n", acl_tests[i].test_address, acl_tests[i].acl1_result, acl1_res);
+                       res = AST_TEST_FAIL;
+                       goto acl_cleanup;
+               }
+
+               if (acl2_res != acl_tests[i].acl2_result) {
+                       ast_test_status_update(test, "Access not as expected to %s on acl2. Expected %d but"
+                                       "got %d instead\n", acl_tests[i].test_address, acl_tests[i].acl2_result, acl2_res);
+                       res = AST_TEST_FAIL;
+                       goto acl_cleanup;
+               }
+       }
+
+acl_cleanup:
+       if (permit_ha) {
+               ast_free_ha(permit_ha);
+       }
+       if (deny_ha) {
+               ast_free_ha(deny_ha);
+       }
+       if (ha1) {
+               ast_free_ha(ha1);
+       }
+       if (ha1) {
+               ast_free_ha(ha2);
+       }
+       return res;
+}
+
+static int unload_module(void)
+{
+       AST_TEST_UNREGISTER(invalid_acl);
+       AST_TEST_UNREGISTER(acl);
+       return 0;
+}
+
+static int load_module(void)
+{
+       AST_TEST_REGISTER(invalid_acl);
+       AST_TEST_REGISTER(acl);
+       return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "ACL test module");