From 24c8fc5dff27fc310bae13105bf35d12dd9b1b59 Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Thu, 22 Oct 2009 16:34:43 +0200 Subject: [PATCH] Set of new network related utilities * src/util/network.h src/util/network.c: utilities to parse network addresses, check netmask and compute ranges --- src/Makefile.am | 1 + src/util/network.c | 323 +++++++++++++++++++++++++++++++++++++++++++++ src/util/network.h | 49 +++++++ 3 files changed, 373 insertions(+) create mode 100644 src/util/network.c create mode 100644 src/util/network.h diff --git a/src/Makefile.am b/src/Makefile.am index 8e27ea7324..8fbfb5f0a6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -55,6 +55,7 @@ UTIL_SOURCES = \ util/memory.c util/memory.h \ util/pci.c util/pci.h \ util/hostusb.c util/hostusb.h \ + util/network.c util/network.h \ util/qparams.c util/qparams.h \ util/stats_linux.c util/stats_linux.h \ util/storage_file.c util/storage_file.h \ diff --git a/src/util/network.c b/src/util/network.c new file mode 100644 index 0000000000..8581cdc345 --- /dev/null +++ b/src/util/network.c @@ -0,0 +1,323 @@ +/* + * network.c: network helper APIs for libvirt + * + * Copyright (C) 2009-2009 Red Hat, Inc. + * + * See COPYING.LIB for the License of this software + * + * Daniel Veillard + */ + +#include + +#include "memory.h" +#include "network.h" + +/* + * Helpers to extract the IP arrays from the virSocketAddrPtr + * That part is the less portable of the module + */ +typedef unsigned char virIPv4Addr[4]; +typedef virIPv4Addr *virIPv4AddrPtr; +typedef unsigned short virIPv6Addr[8]; +typedef virIPv6Addr *virIPv6AddrPtr; + +static int getIPv4Addr(virSocketAddrPtr addr, virIPv4AddrPtr tab) { + unsigned long val; + int i; + + if ((addr == NULL) || (tab == NULL) || (addr->stor.ss_family != AF_INET)) + return(-1); + + val = ntohl(addr->inet4.sin_addr.s_addr); + + for (i = 0;i < 4;i++) { + (*tab)[i] = val & 0xFF; + val >>= 8; + } + + return(0); +} + +static int getIPv6Addr(virSocketAddrPtr addr, virIPv6AddrPtr tab) { + virIPv6AddrPtr val; + int i; + + if ((addr == NULL) || (tab == NULL) || (addr->stor.ss_family != AF_INET6)) + return(-1); + + val = (virIPv6AddrPtr) &(addr->inet6.sin6_addr.__in6_u.__u6_addr16); + + for (i = 0;i < 8;i++) { + (*tab)[i] = ntohs((*val)[i]); + } + + return(0); +} + +/** + * virSocketParseAddr: + * @val: a numeric network address IPv4 or IPv6 + * @addr: where to store the return value. + * @hint: optional hint to pass down to getaddrinfo + * + * Mostly a wrapper for getaddrinfo() extracting the address storage + * from the numeric string like 1.2.3.4 or 2001:db8:85a3:0:0:8a2e:370:7334 + * + * Returns the lenght of the network address or -1 in case of error. + */ +int +virSocketParseAddr(const char *val, virSocketAddrPtr addr, int hint) { + int len; + struct addrinfo hints; + struct addrinfo *res = NULL; + + if ((val == NULL) || (addr == NULL)) + return(-1); + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_NUMERICHOST | hint; + if ((getaddrinfo(val, NULL, &hints, &res) != 0) || (res == NULL)) { + return(-1); + } + + len = res->ai_addrlen; + memcpy(&addr->stor, res->ai_addr, len); + + freeaddrinfo(res); + return(len); +} + +/* + * virSocketParseIpv4Addr: + * @val: an IPv4 numeric address + * @addr: the loacation to store the result + * + * Extract the address storage from an IPv4 numeric address + * + * Returns the lenght of the network address or -1 in case of error. + */ +int +virSocketParseIpv4Addr(const char *val, virSocketAddrPtr addr) { + return(virSocketParseAddr(val, addr, AF_INET)); +} + +/* + * virSocketParseIpv6Addr: + * @val: an IPv6 numeric address + * @addr: the loacation to store the result + * + * Extract the address storage from an IPv6 numeric address + * + * Returns the lenght of the network address or -1 in case of error. + */ +int +virSocketParseIpv6Addr(const char *val, virSocketAddrPtr addr) { + return(virSocketParseAddr(val, addr, AF_INET6)); +} + +/** + * virSocketAddrIsNetmask: + * @netmask: the netmask address + * + * Check that @netmask is a proper network mask + * + * Returns 0 in case of success and -1 in case of error + */ +int virSocketAddrIsNetmask(virSocketAddrPtr netmask) { + int i; + + if (netmask == NULL) + return(-1); + + if (netmask->stor.ss_family == AF_INET) { + virIPv4Addr tm; + unsigned char tmp; + int ok = 0; + + if (getIPv4Addr(netmask, &tm) < 0) + return(-1); + + for (i = 0;i < 4;i++) { + if (tm[i] != 0) + break; + } + + if (i >= 4) + return(0); + + tmp = 0xFF; + do { + if (tm[i] == tmp) { + ok = 1; + break; + } + tmp <<= 1; + } while (tmp != 0); + if (ok == 0) + return(-1); + i++; + + if (i >= 4) + return(0); + + for (;i < 4;i++) { + if (tm[i] != 0xFF) + return(-1); + } + } else if (netmask->stor.ss_family == AF_INET6) { + virIPv6Addr tm; + unsigned short tmp; + int ok = 0; + + /* + * Hum, on IPv6 people use prefixes instead of netmask + */ + if (getIPv6Addr(netmask, &tm) < 0) + return(-1); + + for (i = 0;i < 8;i++) { + if (tm[i] != 0) + break; + } + + if (i >= 8) + return(0); + + tmp = 0xFFFF; + do { + if (tm[i] == tmp) { + ok = 1; + break; + } + tmp <<= 1; + } while (tmp != 0); + if (ok == 0) + return(-1); + i++; + + if (i >= 8) + return(0); + + for (;i < 8;i++) { + if (tm[i] != 0xFFFF) + return(-1); + } + } else { + return(-1); + } + return(0); +} + +/** + * virSocketCheckNetmask: + * @addr1: a first network address + * @addr2: a second network address + * @netmask: the netmask address + * + * Check that @addr1 and @addr2 pertain to the same @netmask address + * range and returns the size of the range + * + * Returns 1 in case of success and 0 in case of failure and + * -1 in case of error + */ +int virSocketCheckNetmask(virSocketAddrPtr addr1, virSocketAddrPtr addr2, + virSocketAddrPtr netmask) { + int i; + + if ((addr1 == NULL) || (addr2 == NULL) || (netmask == NULL)) + return(-1); + if ((addr1->stor.ss_family != addr2->stor.ss_family) || + (addr1->stor.ss_family != netmask->stor.ss_family)) + return(-1); + + if (virSocketAddrIsNetmask(netmask) != 0) + return(-1); + + if (addr1->stor.ss_family == AF_INET) { + virIPv4Addr t1, t2, tm; + + if ((getIPv4Addr(addr1, &t1) < 0) || + (getIPv4Addr(addr2, &t2) < 0) || + (getIPv4Addr(netmask, &tm) < 0)) + return(-1); + + for (i = 0;i < 4;i++) { + if ((t1[i] & tm[i]) != (t2[i] & tm[i])) + return(0); + } + + } else if (addr1->stor.ss_family == AF_INET) { + virIPv6Addr t1, t2, tm; + + if ((getIPv6Addr(addr1, &t1) < 0) || + (getIPv6Addr(addr2, &t2) < 0) || + (getIPv6Addr(netmask, &tm) < 0)) + return(-1); + + for (i = 0;i < 8;i++) { + if ((t1[i] & tm[i]) != (t2[i] & tm[i])) + return(0); + } + + } else { + return(-1); + } + return(1); +} + +/** + * virSocketGetRange: + * @start: start of an IP range + * @end: end of an IP range + * + * Check the order of the 2 addresses and compute the range, this + * will return 1 for identical addresses. Errors can come from incompatible + * addresses type, excessive range (>= 2^^16) where the two addresses are + * unrelated or inverted start and end. + * + * Returns the size of the range or -1 in case of failure + */ +int virSocketGetRange(virSocketAddrPtr start, virSocketAddrPtr end) { + int ret = 0, i; + + if ((start == NULL) || (end == NULL)) + return(-1); + if (start->stor.ss_family != end->stor.ss_family) + return(-1); + + if (start->stor.ss_family == AF_INET) { + virIPv4Addr t1, t2; + + if ((getIPv4Addr(start, &t1) < 0) || + (getIPv4Addr(end, &t2) < 0)) + return(-1); + + for (i = 0;i < 2;i++) { + if (t1[i] != t2[i]) + return(-1); + } + ret = (t2[2] - t1[2]) * 256 + (t2[3] - t1[3]); + if (ret < 0) + return(-1); + ret++; + } else if (start->stor.ss_family == AF_INET6) { + virIPv6Addr t1, t2; + + if ((getIPv6Addr(start, &t1) < 0) || + (getIPv6Addr(end, &t2) < 0)) + return(-1); + + for (i = 0;i < 7;i++) { + if (t1[i] != t2[i]) + return(-1); + } + ret = t2[7] - t1[7]; + if (ret < 0) + return(-1); + ret++; + } else { + return(-1); + } + return(ret); +} diff --git a/src/util/network.h b/src/util/network.h new file mode 100644 index 0000000000..e5907478ef --- /dev/null +++ b/src/util/network.h @@ -0,0 +1,49 @@ +/* + * network.h: network helper APIs for libvirt + * + * Copyright (C) 2009-2009 Red Hat, Inc. + * + * See COPYING.LIB for the License of this software + * + * Daniel Veillard + */ + +#ifndef __VIR_NETWORK_H__ +#define __VIR_NETWORK_H__ + +#include "internal.h" + +#include +#include +#include + +typedef union { + struct sockaddr_storage stor; + struct sockaddr_in inet4; + struct sockaddr_in6 inet6; +} virSocketAddr; +typedef virSocketAddr *virSocketAddrPtr; + +int virSocketParseAddr (const char *val, + virSocketAddrPtr addr, + int hint); + +int virSocketParseIpv4Addr(const char *val, + virSocketAddrPtr addr); + +int virSocketParseIpv6Addr(const char *val, + virSocketAddrPtr addr); + +int virSocketAddrInNetwork(virSocketAddrPtr addr1, + virSocketAddrPtr addr2, + virSocketAddrPtr netmask); + +int virSocketGetRange (virSocketAddrPtr start, + virSocketAddrPtr end); + +int virSocketAddrIsNetmask(virSocketAddrPtr netmask); + +int virSocketCheckNetmask (virSocketAddrPtr addr1, + virSocketAddrPtr addr2, + virSocketAddrPtr netmask); +#endif /* __VIR_NETWORK_H__ */