diff options
author | Jerry Jelinek <jerry.jelinek@joyent.com> | 2013-08-20 12:46:33 +0000 |
---|---|---|
committer | Jerry Jelinek <jerry.jelinek@joyent.com> | 2013-08-20 12:46:33 +0000 |
commit | 8302f394821111c3580a65235587303036ff42d9 (patch) | |
tree | acbe4e08936204a9766a9b212deb27330ce9b10e /usr/src/lib/libdladm | |
parent | 1fbda5aea84129b7604f310ec37f429deda7f045 (diff) | |
download | illumos-joyent-8302f394821111c3580a65235587303036ff42d9.tar.gz |
OS-1535 allowed-ips should let you specify prefixes
Diffstat (limited to 'usr/src/lib/libdladm')
-rw-r--r-- | usr/src/lib/libdladm/common/linkprop.c | 70 |
1 files changed, 69 insertions, 1 deletions
diff --git a/usr/src/lib/libdladm/common/linkprop.c b/usr/src/lib/libdladm/common/linkprop.c index d46054e686..8c0a5daf9f 100644 --- a/usr/src/lib/libdladm/common/linkprop.c +++ b/usr/src/lib/libdladm/common/linkprop.c @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, Joyent, Inc. All rights reserved. + * Copyright (c) 2013, Joyent, Inc. All rights reserved. */ #include <stdlib.h> @@ -2333,6 +2333,33 @@ get_protection(dladm_handle_t handle, prop_desc_t *pdp, return (DLADM_STATUS_OK); } +static uint32_t +nbits_to_mask(int nbits) +{ + int i; + uint_t mask = 0; + + for (i = 0; i < nbits; i++) { + mask >>= 1; + mask |= 0x80000000; + } + + return (mask); +} + +static uint32_t +mask_to_nbits(uint32_t mask) +{ + uint_t nbits = 0; + + while (mask != 0) { + nbits++; + mask <<= 1; + } + + return (nbits); +} + /* ARGSUSED */ static dladm_status_t get_allowedips(dladm_handle_t handle, prop_desc_t *pdp, @@ -2360,9 +2387,16 @@ get_allowedips(dladm_handle_t handle, prop_desc_t *pdp, for (i = 0; i < p->mp_ipaddrcnt; i++) { if (p->mp_ipaddrs[i].ip_version == IPV4_VERSION) { ipaddr_t v4addr; + uint32_t mask; v4addr = V4_PART_OF_V6(p->mp_ipaddrs[i].ip_addr); + mask = p->mp_ipaddrs[i].ip_v4netmask; (void) dladm_ipv4addr2str(&v4addr, prop_val[i]); + if (mask != 0) { + int len = strlen(prop_val[i]); + (void)sprintf(prop_val[i] + len, "/%d", + mask_to_nbits(mask)); + } } else { (void) dladm_ipv6addr2str(&p->mp_ipaddrs[i].ip_addr, prop_val[i]); @@ -2414,6 +2448,28 @@ check_single_ip(char *buf, mac_ipaddr_t *addr) ipaddr_t v4addr; in6_addr_t v6addr; boolean_t isv4 = B_TRUE; + char *p; + uint32_t mask; + + /* + * If the IP address is in CIDR format, parse the bits component + * seperately. An address in this style will be used to indicate an + * entire subnet, so it must be a network number with no host address. + */ + if ((p = strchr(buf, '/')) != NULL) { + char *end = NULL; + long msk; + + *p++ = '\0'; + if (!isdigit(*p)) + return (DLADM_STATUS_INVALID_IP); + msk = strtol(p, &end, 10); + if (end != NULL && *end != '\0') + return (DLADM_STATUS_INVALID_IP); + if (msk > 32 || msk < 1) + return (DLADM_STATUS_INVALID_IP); + mask = nbits_to_mask((int)msk); + } status = dladm_str2ipv4addr(buf, &v4addr); if (status == DLADM_STATUS_INVALID_IP) { @@ -2430,10 +2486,22 @@ check_single_ip(char *buf, mac_ipaddr_t *addr) IN6_IPADDR_TO_V4MAPPED(v4addr, &addr->ip_addr); addr->ip_version = IPV4_VERSION; + if (p != NULL) { + /* + * We have a CIDR style address, confirm that only the + * network number is set. + */ + if (htonl(v4addr) & ~mask) + return (DLADM_STATUS_INVALID_IP); + addr->ip_v4netmask = mask; + } } else { if (IN6_IS_ADDR_UNSPECIFIED(&v6addr)) return (DLADM_STATUS_INVALID_IP); + if (p != NULL) + return (DLADM_STATUS_INVALID_IP); + addr->ip_addr = v6addr; addr->ip_version = IPV6_VERSION; } |