The ACL test was failing on Mac OS X because it would convert the above invalid link-local address into fe80::1234 while reporting no error from getaddrinfo(). Linux does not do this. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@277872 65c4cc65-6c06-0410-ace0-fbb531ad65f3
382 lines
11 KiB
C
382 lines
11 KiB
C
/*
|
|
* 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"
|
|
#include "asterisk/netsock2.h"
|
|
#include "asterisk/config.h"
|
|
|
|
AST_TEST_DEFINE(invalid_acl)
|
|
{
|
|
const char * invalid_acls[] = {
|
|
/* Negative netmask */
|
|
"1.3.3.7/-1",
|
|
/* Netmask too large */
|
|
"1.3.3.7/33",
|
|
/* Netmask waaaay too large */
|
|
"1.3.3.7/92342348927389492307420",
|
|
/* Netmask non-numeric */
|
|
"1.3.3.7/California",
|
|
/* Too many octets in Netmask */
|
|
"1.3.3.7/255.255.255.255.255",
|
|
/* Octets in IP address exceed 255 */
|
|
"57.60.278.900/31",
|
|
/* Octets in IP address exceed 255 and are negative */
|
|
"400.32.201029.-6/24",
|
|
/* Invalidly formatted IP address */
|
|
"EGGSOFDEATH/4000",
|
|
/* Too many octets in IP address */
|
|
"33.4.7.8.3/300030",
|
|
/* Too many octets in Netmask */
|
|
"1.2.3.4/6.7.8.9.0",
|
|
/* Too many octets in IP address */
|
|
"3.1.4.1.5.9/3",
|
|
/* IPv6 address has multiple double colons */
|
|
"ff::ff::ff/3",
|
|
/* IPv6 address is too long */
|
|
"1234:5678:90ab:cdef:1234:5678:90ab:cdef:1234/56",
|
|
/* IPv6 netmask is too large */
|
|
"::ffff/129",
|
|
/* IPv4-mapped IPv6 address has too few octets */
|
|
"::ffff:255.255.255/128",
|
|
/* Leading and trailing colons for IPv6 address */
|
|
":1234:/15",
|
|
/* IPv6 address and IPv4 netmask */
|
|
"fe80::1234/255.255.255.0",
|
|
};
|
|
|
|
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;
|
|
};
|
|
|
|
/* These constants are defined for the sole purpose of being shorter
|
|
* than their real names. It makes lines in this test quite a bit shorter
|
|
*/
|
|
|
|
#define TACL_A AST_SENSE_ALLOW
|
|
#define TACL_D AST_SENSE_DENY
|
|
|
|
AST_TEST_DEFINE(acl)
|
|
{
|
|
struct acl permitallv4 = { "0.0.0.0/0", "permit" };
|
|
struct acl denyallv4 = { "0.0.0.0/0", "deny" };
|
|
struct acl permitallv6 = { "::/0", "permit" };
|
|
struct acl denyallv6 = { "::/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 acl acl3[] = {
|
|
{ "::/0", "deny" },
|
|
{ "fe80::/64", "permit" },
|
|
};
|
|
|
|
struct acl acl4[] = {
|
|
{ "::/0", "deny" },
|
|
{ "fe80::/64", "permit" },
|
|
{ "fe80::ffff:0:0:0/80", "deny" },
|
|
{ "fe80::ffff:0:ffff:0/112", "permit" },
|
|
};
|
|
|
|
struct {
|
|
const char *test_address;
|
|
int v4_permitall_result;
|
|
int v4_denyall_result;
|
|
int v6_permitall_result;
|
|
int v6_denyall_result;
|
|
int acl1_result;
|
|
int acl2_result;
|
|
int acl3_result;
|
|
int acl4_result;
|
|
} acl_tests[] = {
|
|
{ "10.1.1.5", TACL_A, TACL_D, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A },
|
|
{ "192.168.0.5", TACL_A, TACL_D, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A },
|
|
{ "192.168.1.5", TACL_A, TACL_D, TACL_A, TACL_A, TACL_D, TACL_A, TACL_A, TACL_A },
|
|
{ "10.0.0.1", TACL_A, TACL_D, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A, TACL_A },
|
|
{ "10.0.10.10", TACL_A, TACL_D, TACL_A, TACL_A, TACL_A, TACL_D, TACL_A, TACL_A },
|
|
{ "172.16.0.1", TACL_A, TACL_D, TACL_A, TACL_A, TACL_D, TACL_A, TACL_A, TACL_A },
|
|
{ "fe80::1234", TACL_A, TACL_A, TACL_A, TACL_D, TACL_A, TACL_A, TACL_A, TACL_A },
|
|
{ "fe80::ffff:1213:dead:beef", TACL_A, TACL_A, TACL_A, TACL_D, TACL_A, TACL_A, TACL_A, TACL_D },
|
|
{ "fe80::ffff:0:ffff:ABCD", TACL_A, TACL_A, TACL_A, TACL_D, TACL_A, TACL_A, TACL_A, TACL_A },
|
|
};
|
|
|
|
struct ast_ha *permit_hav4 = NULL;
|
|
struct ast_ha *deny_hav4 = NULL;
|
|
struct ast_ha *permit_hav6 = NULL;
|
|
struct ast_ha *deny_hav6 = NULL;
|
|
struct ast_ha *ha1 = NULL;
|
|
struct ast_ha *ha2 = NULL;
|
|
struct ast_ha *ha3 = NULL;
|
|
struct ast_ha *ha4 = 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_hav4 = ast_append_ha(permitallv4.access, permitallv4.host, permit_hav4, &err))) {
|
|
ast_test_status_update(test, "Failed to create permit_all ACL\n");
|
|
res = AST_TEST_FAIL;
|
|
goto acl_cleanup;
|
|
}
|
|
|
|
if (!(deny_hav4 = ast_append_ha(denyallv4.access, denyallv4.host, deny_hav4, &err))) {
|
|
ast_test_status_update(test, "Failed to create deny_all ACL\n");
|
|
res = AST_TEST_FAIL;
|
|
goto acl_cleanup;
|
|
}
|
|
|
|
if (!(permit_hav6 = ast_append_ha(permitallv6.access, permitallv6.host, permit_hav6, &err))) {
|
|
ast_test_status_update(test, "Failed to create permit_all ACL\n");
|
|
res = AST_TEST_FAIL;
|
|
goto acl_cleanup;
|
|
}
|
|
|
|
if (!(deny_hav6 = ast_append_ha(denyallv6.access, denyallv6.host, deny_hav6, &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(acl3); ++i) {
|
|
if (!(ha3 = ast_append_ha(acl3[i].access, acl3[i].host, ha3, &err))) {
|
|
ast_test_status_update(test, "Failed to add rule %s with access %s to ha3\n",
|
|
acl3[i].host, acl3[i].access);
|
|
res = AST_TEST_FAIL;
|
|
goto acl_cleanup;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_LEN(acl4); ++i) {
|
|
if (!(ha4 = ast_append_ha(acl4[i].access, acl4[i].host, ha4, &err))) {
|
|
ast_test_status_update(test, "Failed to add rule %s with access %s to ha4\n",
|
|
acl4[i].host, acl4[i].access);
|
|
res = AST_TEST_FAIL;
|
|
goto acl_cleanup;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_LEN(acl_tests); ++i) {
|
|
struct ast_sockaddr addr;
|
|
int permit_resv4;
|
|
int permit_resv6;
|
|
int deny_resv4;
|
|
int deny_resv6;
|
|
int acl1_res;
|
|
int acl2_res;
|
|
int acl3_res;
|
|
int acl4_res;
|
|
|
|
ast_sockaddr_parse(&addr, acl_tests[i].test_address, PARSE_PORT_FORBID);
|
|
|
|
permit_resv4 = ast_apply_ha(permit_hav4, &addr);
|
|
deny_resv4 = ast_apply_ha(deny_hav4, &addr);
|
|
permit_resv6 = ast_apply_ha(permit_hav6, &addr);
|
|
deny_resv6 = ast_apply_ha(deny_hav6, &addr);
|
|
acl1_res = ast_apply_ha(ha1, &addr);
|
|
acl2_res = ast_apply_ha(ha2, &addr);
|
|
acl3_res = ast_apply_ha(ha3, &addr);
|
|
acl4_res = ast_apply_ha(ha4, &addr);
|
|
|
|
if (permit_resv4 != acl_tests[i].v4_permitall_result) {
|
|
ast_test_status_update(test, "Access not as expected to %s on permitallv4. Expected %d but "
|
|
"got %d instead\n", acl_tests[i].test_address, acl_tests[i].v4_permitall_result, permit_resv4);
|
|
res = AST_TEST_FAIL;
|
|
goto acl_cleanup;
|
|
}
|
|
|
|
if (deny_resv4 != acl_tests[i].v4_denyall_result) {
|
|
ast_test_status_update(test, "Access not as expected to %s on denyallv4. Expected %d but "
|
|
"got %d instead\n", acl_tests[i].test_address, acl_tests[i].v4_denyall_result, deny_resv4);
|
|
res = AST_TEST_FAIL;
|
|
goto acl_cleanup;
|
|
}
|
|
|
|
if (permit_resv6 != acl_tests[i].v6_permitall_result) {
|
|
ast_test_status_update(test, "Access not as expected to %s on permitallv6. Expected %d but "
|
|
"got %d instead\n", acl_tests[i].test_address, acl_tests[i].v6_permitall_result, permit_resv6);
|
|
res = AST_TEST_FAIL;
|
|
goto acl_cleanup;
|
|
}
|
|
|
|
if (deny_resv6 != acl_tests[i].v6_denyall_result) {
|
|
ast_test_status_update(test, "Access not as expected to %s on denyallv6. Expected %d but "
|
|
"got %d instead\n", acl_tests[i].test_address, acl_tests[i].v6_denyall_result, deny_resv6);
|
|
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;
|
|
}
|
|
|
|
if (acl3_res != acl_tests[i].acl3_result) {
|
|
ast_test_status_update(test, "Access not as expected to %s on acl3. Expected %d but "
|
|
"got %d instead\n", acl_tests[i].test_address, acl_tests[i].acl3_result, acl3_res);
|
|
res = AST_TEST_FAIL;
|
|
goto acl_cleanup;
|
|
}
|
|
|
|
if (acl4_res != acl_tests[i].acl4_result) {
|
|
ast_test_status_update(test, "Access not as expected to %s on acl4. Expected %d but "
|
|
"got %d instead\n", acl_tests[i].test_address, acl_tests[i].acl4_result, acl4_res);
|
|
res = AST_TEST_FAIL;
|
|
goto acl_cleanup;
|
|
}
|
|
}
|
|
|
|
acl_cleanup:
|
|
if (permit_hav4) {
|
|
ast_free_ha(permit_hav4);
|
|
}
|
|
if (deny_hav4) {
|
|
ast_free_ha(deny_hav4);
|
|
}
|
|
if (permit_hav6) {
|
|
ast_free_ha(permit_hav6);
|
|
}
|
|
if (deny_hav6) {
|
|
ast_free_ha(deny_hav6);
|
|
}
|
|
if (ha1) {
|
|
ast_free_ha(ha1);
|
|
}
|
|
if (ha2) {
|
|
ast_free_ha(ha2);
|
|
}
|
|
if (ha3) {
|
|
ast_free_ha(ha3);
|
|
}
|
|
if (ha4) {
|
|
ast_free_ha(ha4);
|
|
}
|
|
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");
|