diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 0e3033dcb47775a585d9b62ed0a6fd705abfdb79..19841ef96a7a972d8f68d25020f4f79f860f671d 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 1abe78b821797993387043e63f45c50792c264f9..61044fc19dacaed305308163c83219c539837bfd 100644 --- a/src/util/network.c +++ b/src/util/network.c @@ -287,6 +287,59 @@ int virSocketAddrIsNetmask(virSocketAddrPtr netmask) { return 0; } +/** + * 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 @@ -486,3 +539,63 @@ 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); + } + 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 521f466e2a3d0fc59fb015afaf658a0d7731eaa6..2fcee434d2d86d9837b01c107fc4cb9c316cb488 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__ */