virSocketPrefixToNetmask: Given a 'prefix', which is the number of 1 bits in a netmask, fill in a virSocketAddr object with a netmask as an IP address (IPv6 or IPv4). virSocketAddrMask: Mask off the host bits in one virSocketAddr according to the netmask in another virSocketAddr. virSocketAddrMaskByPrefix, Mask off the host bits in a virSocketAddr according to a prefix (number of 1 bits in netmask). VIR_SOCKET_FAMILY: return the family of a virSocketAddr --- V2 changes: * Simplify virSocketAddrMaskByPrefix by calling virSocketAddrMask instead of duplicating code. * do bitwise operations arithmetically rather than in loops * prefix is now unsigned when it is a function arg. src/libvirt_private.syms | 3 + src/util/network.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++ src/util/network.h | 10 ++++ 3 files changed, 127 insertions(+), 0 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 0e3033d..19841ef 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -559,6 +559,9 @@ virShrinkN; # network.h virSocketAddrIsNetmask; +virSocketAddrMask; +virSocketAddrMaskByPrefix; +virSocketAddrPrefixToNetmask; virSocketCheckNetmask; virSocketFormatAddr; virSocketFormatAddrFull; diff --git a/src/util/network.c b/src/util/network.c index 1abe78b..12b56ea 100644 --- a/src/util/network.c +++ b/src/util/network.c @@ -288,6 +288,59 @@ int virSocketAddrIsNetmask(virSocketAddrPtr netmask) { } /** + * virSocketAddrMask: + * @addr: address that needs to be masked + * @netmask: the netmask address + * + * Mask off the host bits of @addr according to @netmask, turning it + * into a network address. + * + * Returns 0 in case of success, or -1 on error. + */ +int +virSocketAddrMask(virSocketAddrPtr addr, const virSocketAddrPtr netmask) +{ + if (addr->data.stor.ss_family != netmask->data.stor.ss_family) + return -1; + + if (addr->data.stor.ss_family == AF_INET) { + addr->data.inet4.sin_addr.s_addr + &= netmask->data.inet4.sin_addr.s_addr; + return 0; + } + if (addr->data.stor.ss_family == AF_INET6) { + int ii; + for (ii = 0; ii < 16; ii++) + addr->data.inet6.sin6_addr.s6_addr[ii] + &= netmask->data.inet6.sin6_addr.s6_addr[ii]; + return 0; + } + return -1; +} + +/** + * virSocketAddrMaskByPrefix: + * @addr: address that needs to be masked + * @prefix: prefix (# of 1 bits) of netmask to apply + * + * Mask off the host bits of @addr according to @prefix, turning it + * into a network address. + * + * Returns 0 in case of success, or -1 on error. + */ +int +virSocketAddrMaskByPrefix(virSocketAddrPtr addr, unsigned int prefix) +{ + virSocketAddr netmask; + + if (virSocketAddrPrefixToNetmask(prefix, &netmask, + addr->data.stor.ss_family) < 0) + return -1; + + return virSocketAddrMask(addr, &netmask); +} + +/** * virSocketCheckNetmask: * @addr1: a first network address * @addr2: a second network address @@ -486,3 +539,64 @@ int virSocketGetNumNetmaskBits(const virSocketAddrPtr netmask) } return -1; } + +/** + * virSocketPrefixToNetmask: + * @prefix: number of 1 bits to put in the netmask + * @netmask: address to fill in with the desired netmask + * @family: family of the address (AF_INET or AF_INET6 only) + * + * given @prefix and @family, fill in @netmask with a netmask + * (eg 255.255.255.0). + * + * Returns 0 on success or -1 on error. + */ + +int +virSocketAddrPrefixToNetmask(unsigned int prefix, + virSocketAddrPtr netmask, + int family) +{ + int result = -1; + + netmask->data.stor.ss_family = AF_UNSPEC; /* assume failure */ + + if (family == AF_INET) { + int ip; + + if (prefix > 32) + goto error; + + ip = prefix ? ~((1 << (32 - prefix)) - 1) : 0; + netmask->data.inet4.sin_addr.s_addr = htonl(ip); + netmask->data.stor.ss_family = AF_INET; + result = 0; + + } else if (family == AF_INET6) { + int ii = 0; + + if (prefix > 128) + goto error; + + while (prefix >= 8) { + /* do as much as possible an entire byte at a time */ + netmask->data.inet6.sin6_addr.s6_addr[ii++] = 0xff; + prefix -= 8; + } + if (prefix > 0) { + /* final partial byte */ + netmask->data.inet6.sin6_addr.s6_addr[ii++] + = ~((1 << (8 - prefix)) -1); + } + ii++; + while (ii < 16) { + /* zerofill remainder in case it wasn't initialized */ + netmask->data.inet6.sin6_addr.s6_addr[ii++] = 0; + } + netmask->data.stor.ss_family = AF_INET6; + result = 0; + } + +error: + return result; +} diff --git a/src/util/network.h b/src/util/network.h index 521f466..2fcee43 100644 --- a/src/util/network.h +++ b/src/util/network.h @@ -41,6 +41,9 @@ typedef struct { # define VIR_SOCKET_IS_FAMILY(s, f) \ ((s)->data.sa.sa_family == f) +# define VIR_SOCKET_FAMILY(s) \ + ((s)->data.sa.sa_family) + typedef virSocketAddr *virSocketAddrPtr; int virSocketParseAddr (const char *val, @@ -70,7 +73,14 @@ int virSocketAddrIsNetmask(virSocketAddrPtr netmask); int virSocketCheckNetmask (virSocketAddrPtr addr1, virSocketAddrPtr addr2, virSocketAddrPtr netmask); +int virSocketAddrMask (virSocketAddrPtr addr, + const virSocketAddrPtr netmask); +int virSocketAddrMaskByPrefix(virSocketAddrPtr addr, + unsigned int prefix); int virSocketGetNumNetmaskBits(const virSocketAddrPtr netmask); +int virSocketAddrPrefixToNetmask(unsigned int prefix, + virSocketAddrPtr netmask, + int family); #endif /* __VIR_NETWORK_H__ */ -- 1.7.3.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list