--- /dev/null
+/*
+ * 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 <veillard@redhat.com>
+ */
+
+#include <config.h>
+
+#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);
+}
--- /dev/null
+/*
+ * 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 <veillard@redhat.com>
+ */
+
+#ifndef __VIR_NETWORK_H__
+#define __VIR_NETWORK_H__
+
+#include "internal.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+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__ */