test_notenforced_lists.c revision 48e27400d23e2586530cf943524e50c74d79a915
/**
* The contents of this file are subject to the terms of the Common Development and
* Distribution License (the License). You may not use this file except in compliance with the
* License.
*
* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
* specific language governing permission and limitations under the License.
*
* When distributing Covered Software, include this CDDL Header Notice in each file and include
* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
* Header, with the fields enclosed by brackets [] replaced by your own identifying
* information: "Portions copyright [year] [name of copyright owner]".
*
* Copyright 2014 - 2015 ForgeRock AS.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <setjmp.h>
#include <cmocka.h>
#include "am.h"
#include "utility.h"
int ip_address_match(const char *ip, const char **list, unsigned int listsize, unsigned long instance_id);
/*
* This is reference code that correctly matches ip v4 and v6 addresses, as well as unit tests for matching
* ip addresses in notenforced lists.
*
* A reference implementation for ip matching from the linux kernel is: http://fxr.watson.org/fxr/ident?v=linux-2.6;i=addr4_match ( see: addr_match(), addr4_match() )
*
*
*/
// NOTE: this only works for an array, not a pointer derived from an array
#define array_len(a) ( (&a) [1] - a )
// NOTE: only to simplify the macro below - a typed null pointer
// the number of 32 bit words (quads) in the network format of an ip v6 address (which will just be 4)
// the number of 32 bit words (quads) in the network format of an ip v4 address
#define IP4_QUADS 1
/*
* test equivalence masked bits in two ipv4 addresses in network form
*/
{
if (bits == 0) {
// the range is all inclusive - uint32_t << 32 is undefined
return 1;
}
// here and in the function below, we are comparing quads (uint32_t) represented in the network byte
// order. Xor (^) is used to identify differences between the quads, and then << is used to remove the
// differences outside of the network masks' number of bits.
return 0;
}
return 1;
}
/**
* test masked bits in two ipv6 addresses in network form.
*
* see above for an explanation of the bit twiddling code here.
*/
{
if (quads)
{
return 0;
}
if (remainder)
{
return 0;
}
return 1;
}
/**
* tests wether the first argument is in the (inclusive) range of V6 addresses from adr_lo to addr_hi
* return 0 if the address is in the range.
*/
static int cmp_ip_range(const struct in_addr * addr, const struct in_addr * addr_lo, const struct in_addr * addr_hi)
{
}
/**
* compares two uint32 arrays in network format (requiring ntohl translation)
* returns negative if a < b, positive if a > b, 0 if they are equal
*/
{
int i;
int c = 0;
for (i = IP6_QUADS; 0 < i--;)
{
if (c)
break;
}
return c;
}
/**
* tests wether the first argument is in the (inclusive) range of V6 addresses from adr_lo to addr_hi
* return 0 if the address is in the range, negative if below the range, positive if its above
*/
static int cmp_ip6_range(const struct in6_addr * addr, const struct in6_addr * addr_lo, const struct in6_addr * addr_hi)
{
int c;
if (0 < c)
return -1;
if (0 < c)
return 1;
return 0;
}
/*
* initialise and read an ip v4 presentation, returning in bpits the number of bits on
* returns 0 if the presentation cannot be read as an ip v4 address in CIDR notation
*/
{
if (* pbits == -1)
{
return 0;
}
return 1;
}
/*
* read an ip v4 presentation p, expecting all bits to be masked, i.e. not a range
* returns 0 if the presentation is not ip v4, or if it is a CIDR range
*/
static int read_full_ip(const char * p, struct in_addr * n)
{
int mask;
{
return 1;
printf("range not expected for ip %s\n", p);
}
return 0;
}
/*
* initialise and read the ip v6 presentation, returning in pbits the number of masked (on) bits
* returns 0 if the presentation form cannot be parsed as an ip v6 address in CIDR notation
*/
{
if (* pbits == -1)
{
return 0;
}
return 1;
}
/*
* read the presentation form of an ip v6 address, expecting all bits to be masked (on)
* returns true if all bits are masked (on).
*/
{
int mask;
return 1;
}
}
return 0;
}
/*
* test whether an ip address falls within two inclusive boundaries, ensuring that
* all addresses are of the same family, v4 or v6, and are not ranges.
*
* returns 0 on success, and -1 on address parse error
*/
{
}
}
}
}
return -1;
}
/**
* parse a <LO>-<HI> ip address range, and test that an ip address is in that range
*/
{
if (p == 0) {
return -1;
}
int c;
} else {
// memory failure
c = -1;
}
// free or ignore allocated strings
return c;
}
/**
* test that an ip address is within a range specified by a CIDR in the same address family (v4 or v6).
*
* returns 0 on match, -1 on address parse error.
*/
{
int bits;
}
}
int bits;
}
}
return -1;
}
#define array_of(a) ((const char *[]){ a })
{ \
assert_int_equal(ip_address_match(addr, array_of(range), 1, 0l), expect ? AM_SUCCESS : AM_NOT_FOUND); \
} while (0)
{ \
assert_int_equal(ip_address_match(addr, array_of(range), 1, 0l), expect ? AM_SUCCESS : AM_NOT_FOUND); \
} while (0)
void test_ip_ranges(void **state) {
(void)state;
// V4
// V6
}
static void test_range_ip4_notenforced(void **state) {
(void)state;
am_state_func_t const * func_array = 0;
int array_len = 0;
struct am_config_map not_enforced_ips [] = {
{ "", "192.153.0.0-192.168.0.23" },
};
struct {
} ctx;
am_config_t config = {
.notif_enable = AM_TRUE,
.not_enforced_fetch_attr = 0,
.not_enforced_map_sz = 0,
.not_enforced_ext_map_sz = 0,
.logout_map_sz = 0,
};
am_request_t request = {
.token = 0,
};
}
void test_cidr_ip6_notenforced_fetch_attr(void **state) {
(void)state;
am_state_func_t const * func_array = 0;
int array_len = 0;
struct am_config_map not_enforced_ips [] = {
{ "", "2001:5c0:9168:0:0:0:0:1-2001:5c0:9168:0:0:0:0:2" },
{ "", "2001:5c0:9168:/48" },
};
struct {
} ctx;
am_config_t config = {
.notif_enable = AM_TRUE,
.not_enforced_fetch_attr = 1,
.not_enforced_map_sz = 0,
.not_enforced_ext_map_sz = 0,
.logout_map_sz = 0,
};
am_request_t request = {
.token = 0,
};
}
void test_cidr_ip6_notenforced_get(void **state) {
(void)state;
am_state_func_t const * func_array = 0;
int array_len = 0;
struct am_config_map not_enforced_ips[] = {
{ "GET,", "2001:5c0:9168:0:0:0:0:1-2001:5c0:9168:0:0:0:0:2" },
{ "POST,", "2001:6c0:9168:/48" },
};
struct {
} ctx;
am_config_t config = {
.notif_enable = AM_TRUE,
.not_enforced_fetch_attr = 1,
.not_enforced_map_sz = 0,
.not_enforced_ext_map_sz = 0,
.logout_map_sz = 0,
};
am_request_t request = {
.token = 0,
};
}
void test_url_notenforced_get(void **state) {
(void)state;
am_state_func_t const * func_array = 0;
int array_len = 0;
struct am_config_map not_enforced_ips[] = {
{ "GET,0", "2001:5c0:9168:0:0:0:0:1-2001:5c0:9168:0:0:0:0:2" },
{ "POST,0", "2001:5c0:9168:/48" },
};
struct am_config_map not_enforced_map[] = {
{ "GET,0", ".+://\\.+" },
{ "POST,0", "https://www\\..+/path.*" },
};
struct {
} ctx;
am_config_t config = {
.notif_enable = AM_TRUE,
.not_enforced_fetch_attr = 1,
.not_enforced_invert = 0,
.not_enforced_ext_map_sz = 0,
.logout_map_sz = 0,
};
am_request_t request = {
.token = 0,
};
}
void test_deny_url_notenforced_get(void **state) {
(void)state;
am_state_func_t const * func_array = 0;
int array_len = 0;
struct am_config_map not_enforced_ips[] = {
{ "GET,0", "2001:5c0:9168:0:0:0:0:1-2001:5c0:9168:0:0:0:0:2" },
{ "POST,0", "2001:5c0:9168:/48" },
};
struct am_config_map not_enforced_map[] = {
{ "GET,0", "https://www.url.com:90/path" },
{ "POST,0", "https://www.url.com/path" },
};
struct {
} ctx;
am_config_t config = {
.notif_enable = AM_TRUE,
.not_enforced_fetch_attr = 1,
.not_enforced_invert = 0,
.not_enforced_ext_map_sz = 0,
.logout_map_sz = 0,
};
am_request_t request = {
.token = 0,
};
}