iscsi: disallow netmask prefix of 0 bits

Netmasks with 0 bits of prefix do not make sense.  For example,
192.168.1.2/0 would allow hosts from any address, but this is
indicated with a special "ANY" value rather than a normal netmask.

Netmask prefixes of the full address size (e.g. 32 for IPv4 and 128 for
IPv6) are still allowed, since this represents a valid configuration
that matches a single specific address.

This also allows the IPv4 netmask math to be done entirely in uint32_t
instead of promoting to unsigned long long to avoid undefined behavior
when bits == 0 (shift count would have been 32 in that case).

Change-Id: I021b718e6a46f628c96a358edae816de81cd8929
Signed-off-by: Daniel Verkamp <daniel.verkamp@intel.com>
Reviewed-on: https://review.gerrithub.io/392969
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: <shuhei.matsumoto.xt@hitachi.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Daniel Verkamp 2017-12-26 09:39:17 -07:00 committed by Jim Harris
parent c315d8e8eb
commit 61c1493785
2 changed files with 81 additions and 3 deletions

View File

@ -79,7 +79,7 @@ spdk_iscsi_ipv6_netmask_allow_addr(const char *netmask, const char *addr)
if (p[0] == '/') {
bits = (int) strtol(p + 1, NULL, 10);
if (bits < 0 || bits > 128) {
if (bits <= 0 || bits > 128) {
return false;
}
} else {
@ -139,7 +139,7 @@ spdk_iscsi_ipv4_netmask_allow_addr(const char *netmask, const char *addr)
if (p[0] == '/') {
bits = (int) strtol(p + 1, NULL, 10);
if (bits < 0 || bits > 32) {
if (bits <= 0 || bits > 32) {
return false;
}
} else {
@ -153,7 +153,7 @@ spdk_iscsi_ipv4_netmask_allow_addr(const char *netmask, const char *addr)
}
/* check 32bits */
bmask = (0xffffffffULL << (32 - bits)) & 0xffffffffU;
bmask = (0xffffffffU << (32 - bits)) & 0xffffffffU;
if ((ntohl(in4_mask.s_addr) & bmask) != (ntohl(in4_addr.s_addr) & bmask)) {
return false;
}

View File

@ -157,6 +157,12 @@ allow_ipv6_allowed(void)
result = spdk_iscsi_netmask_allow_addr(netmask, addr);
CU_ASSERT(result == true);
/* Netmask prefix bits == 128 (all bits must match) */
netmask = "[2001:ad6:1234:5678:9abc::1]/128";
addr = "2001:ad6:1234:5678:9abc::1";
result = spdk_iscsi_ipv6_netmask_allow_addr(netmask, addr);
CU_ASSERT(result == true);
}
static void
@ -174,6 +180,38 @@ allow_ipv6_denied(void)
result = spdk_iscsi_netmask_allow_addr(netmask, addr);
CU_ASSERT(result == false);
/* Netmask prefix bits == 128 (all bits must match) */
netmask = "[2001:ad6:1234:5678:9abc::1]/128";
addr = "2001:ad6:1234:5678:9abc::2";
result = spdk_iscsi_ipv6_netmask_allow_addr(netmask, addr);
CU_ASSERT(result == false);
}
static void
allow_ipv6_invalid(void)
{
bool result;
char *netmask;
char *addr;
/* Netmask prefix bits > 128 */
netmask = "[2001:ad6:1234::]/129";
addr = "2001:ad6:1234:5678:9abc::";
result = spdk_iscsi_ipv6_netmask_allow_addr(netmask, addr);
CU_ASSERT(result == false);
/* Netmask prefix bits == 0 */
netmask = "[2001:ad6:1234::]/0";
addr = "2001:ad6:1234:5678:9abc::";
result = spdk_iscsi_ipv6_netmask_allow_addr(netmask, addr);
CU_ASSERT(result == false);
/* Netmask prefix bits < 0 */
netmask = "[2001:ad6:1234::]/-1";
addr = "2001:ad6:1234:5678:9abc::";
result = spdk_iscsi_ipv6_netmask_allow_addr(netmask, addr);
CU_ASSERT(result == false);
}
static void
@ -191,6 +229,12 @@ allow_ipv4_allowed(void)
result = spdk_iscsi_netmask_allow_addr(netmask, addr);
CU_ASSERT(result == true);
/* Netmask prefix == 32 (all bits must match) */
netmask = "192.168.2.1/32";
addr = "192.168.2.1";
result = spdk_iscsi_ipv4_netmask_allow_addr(netmask, addr);
CU_ASSERT(result == true);
}
static void
@ -208,6 +252,38 @@ allow_ipv4_denied(void)
result = spdk_iscsi_netmask_allow_addr(netmask, addr);
CU_ASSERT(result == false);
/* Netmask prefix == 32 (all bits must match) */
netmask = "192.168.2.1/32";
addr = "192.168.2.2";
result = spdk_iscsi_ipv4_netmask_allow_addr(netmask, addr);
CU_ASSERT(result == false);
}
static void
allow_ipv4_invalid(void)
{
bool result;
char *netmask;
char *addr;
/* Netmask prefix bits > 32 */
netmask = "192.168.2.0/33";
addr = "192.168.2.1";
result = spdk_iscsi_ipv4_netmask_allow_addr(netmask, addr);
CU_ASSERT(result == false);
/* Netmask prefix bits == 0 */
netmask = "192.168.2.0/0";
addr = "192.168.2.1";
result = spdk_iscsi_ipv4_netmask_allow_addr(netmask, addr);
CU_ASSERT(result == false);
/* Netmask prefix bits < 0 */
netmask = "192.168.2.0/-1";
addr = "192.168.2.1";
result = spdk_iscsi_ipv4_netmask_allow_addr(netmask, addr);
CU_ASSERT(result == false);
}
static void
@ -683,8 +759,10 @@ main(int argc, char **argv)
|| CU_add_test(suite, "allow any allowed case", allow_any_allowed) == NULL
|| CU_add_test(suite, "allow ipv6 allowed case", allow_ipv6_allowed) == NULL
|| CU_add_test(suite, "allow ipv6 denied case", allow_ipv6_denied) == NULL
|| CU_add_test(suite, "allow ipv6 invalid case", allow_ipv6_invalid) == NULL
|| CU_add_test(suite, "allow ipv4 allowed case", allow_ipv4_allowed) == NULL
|| CU_add_test(suite, "allow ipv4 denied case", allow_ipv4_denied) == NULL
|| CU_add_test(suite, "allow ipv4 invalid case", allow_ipv4_invalid) == NULL
|| CU_add_test(suite, "node access allowed case", node_access_allowed) == NULL
|| CU_add_test(suite, "node access denied case (empty netmask)",
node_access_denied_by_empty_netmask) == NULL