2009-10-22 14:34:43 +00:00
|
|
|
/*
|
|
|
|
* network.c: network helper APIs for libvirt
|
|
|
|
*
|
2010-04-07 15:12:02 +00:00
|
|
|
* Copyright (C) 2009-2010 Red Hat, Inc.
|
2009-10-22 14:34:43 +00:00
|
|
|
*
|
|
|
|
* See COPYING.LIB for the License of this software
|
|
|
|
*
|
|
|
|
* Daniel Veillard <veillard@redhat.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
2009-11-02 14:42:47 +00:00
|
|
|
#include <arpa/inet.h>
|
2009-10-22 14:34:43 +00:00
|
|
|
|
|
|
|
#include "memory.h"
|
|
|
|
#include "network.h"
|
2010-10-20 14:13:00 +00:00
|
|
|
#include "util.h"
|
|
|
|
#include "virterror_internal.h"
|
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_NONE
|
|
|
|
#define virSocketError(code, ...) \
|
|
|
|
virReportErrorHelper(NULL, VIR_FROM_THIS, code, __FILE__, \
|
|
|
|
__FUNCTION__, __LINE__, __VA_ARGS__)
|
2009-10-22 14:34:43 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
|
2010-10-20 13:21:15 +00:00
|
|
|
if ((addr == NULL) || (tab == NULL) || (addr->data.stor.ss_family != AF_INET))
|
2009-10-22 14:34:43 +00:00
|
|
|
return(-1);
|
|
|
|
|
2010-10-20 13:21:15 +00:00
|
|
|
val = ntohl(addr->data.inet4.sin_addr.s_addr);
|
2009-10-22 14:34:43 +00:00
|
|
|
|
|
|
|
for (i = 0;i < 4;i++) {
|
2009-11-06 16:47:45 +00:00
|
|
|
(*tab)[3 - i] = val & 0xFF;
|
2009-10-22 14:34:43 +00:00
|
|
|
val >>= 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int getIPv6Addr(virSocketAddrPtr addr, virIPv6AddrPtr tab) {
|
|
|
|
int i;
|
|
|
|
|
2010-10-20 13:21:15 +00:00
|
|
|
if ((addr == NULL) || (tab == NULL) || (addr->data.stor.ss_family != AF_INET6))
|
2009-10-22 14:34:43 +00:00
|
|
|
return(-1);
|
|
|
|
|
|
|
|
for (i = 0;i < 8;i++) {
|
2010-10-20 13:21:15 +00:00
|
|
|
(*tab)[i] = ((addr->data.inet6.sin6_addr.s6_addr[2 * i] << 8) |
|
|
|
|
addr->data.inet6.sin6_addr.s6_addr[2 * i + 1]);
|
2009-10-22 14:34:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virSocketParseAddr:
|
|
|
|
* @val: a numeric network address IPv4 or IPv6
|
2010-08-10 13:00:15 +00:00
|
|
|
* @addr: where to store the return value, optional.
|
2010-10-20 13:26:30 +00:00
|
|
|
* @family: address family to pass down to getaddrinfo
|
2009-10-22 14:34:43 +00:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*
|
2009-11-02 14:42:47 +00:00
|
|
|
* Returns the length of the network address or -1 in case of error.
|
2009-10-22 14:34:43 +00:00
|
|
|
*/
|
|
|
|
int
|
2010-10-20 13:26:30 +00:00
|
|
|
virSocketParseAddr(const char *val, virSocketAddrPtr addr, int family) {
|
2009-10-22 14:34:43 +00:00
|
|
|
int len;
|
|
|
|
struct addrinfo hints;
|
|
|
|
struct addrinfo *res = NULL;
|
2010-10-20 14:20:37 +00:00
|
|
|
int err;
|
2009-10-22 14:34:43 +00:00
|
|
|
|
2010-10-20 14:20:37 +00:00
|
|
|
if (val == NULL) {
|
2010-11-02 08:47:22 +00:00
|
|
|
virSocketError(VIR_ERR_INVALID_ARG, "%s", _("Missing address"));
|
2010-10-20 14:20:37 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2009-10-22 14:34:43 +00:00
|
|
|
|
|
|
|
memset(&hints, 0, sizeof(hints));
|
2010-10-20 13:26:30 +00:00
|
|
|
hints.ai_family = family;
|
|
|
|
hints.ai_flags = AI_NUMERICHOST;
|
2010-10-20 14:20:37 +00:00
|
|
|
if ((err = getaddrinfo(val, NULL, &hints, &res)) != 0) {
|
|
|
|
virSocketError(VIR_ERR_SYSTEM_ERROR,
|
|
|
|
_("Cannot parse socket address '%s': %s"),
|
|
|
|
val, gai_strerror(err));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (res == NULL) {
|
|
|
|
virSocketError(VIR_ERR_SYSTEM_ERROR,
|
|
|
|
_("No socket addresses found for '%s'"),
|
|
|
|
val);
|
|
|
|
return -1;
|
2009-10-22 14:34:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
len = res->ai_addrlen;
|
2010-10-20 13:21:15 +00:00
|
|
|
if (addr != NULL) {
|
|
|
|
memcpy(&addr->data.stor, res->ai_addr, len);
|
|
|
|
addr->len = res->ai_addrlen;
|
|
|
|
}
|
2009-10-22 14:34:43 +00:00
|
|
|
|
|
|
|
freeaddrinfo(res);
|
|
|
|
return(len);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* virSocketParseIpv4Addr:
|
|
|
|
* @val: an IPv4 numeric address
|
2009-10-30 15:39:57 +00:00
|
|
|
* @addr: the location to store the result
|
2009-10-22 14:34:43 +00:00
|
|
|
*
|
|
|
|
* Extract the address storage from an IPv4 numeric address
|
|
|
|
*
|
2009-10-30 15:39:57 +00:00
|
|
|
* Returns the length of the network address or -1 in case of error.
|
2009-10-22 14:34:43 +00:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
virSocketParseIpv4Addr(const char *val, virSocketAddrPtr addr) {
|
|
|
|
return(virSocketParseAddr(val, addr, AF_INET));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* virSocketParseIpv6Addr:
|
|
|
|
* @val: an IPv6 numeric address
|
2009-10-30 15:39:57 +00:00
|
|
|
* @addr: the location to store the result
|
2009-10-22 14:34:43 +00:00
|
|
|
*
|
|
|
|
* Extract the address storage from an IPv6 numeric address
|
|
|
|
*
|
2009-10-30 15:39:57 +00:00
|
|
|
* Returns the length of the network address or -1 in case of error.
|
2009-10-22 14:34:43 +00:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
virSocketParseIpv6Addr(const char *val, virSocketAddrPtr addr) {
|
|
|
|
return(virSocketParseAddr(val, addr, AF_INET6));
|
|
|
|
}
|
|
|
|
|
2009-11-02 14:42:47 +00:00
|
|
|
/*
|
|
|
|
* virSocketFormatAddr:
|
2010-04-07 15:12:02 +00:00
|
|
|
* @addr: an initialized virSocketAddrPtr
|
2009-11-02 14:42:47 +00:00
|
|
|
*
|
|
|
|
* Returns a string representation of the given address
|
|
|
|
* Returns NULL on any error
|
|
|
|
* Caller must free the returned string
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
virSocketFormatAddr(virSocketAddrPtr addr) {
|
2010-10-20 14:13:00 +00:00
|
|
|
return virSocketFormatAddrFull(addr, false, NULL);
|
|
|
|
}
|
2009-11-02 14:42:47 +00:00
|
|
|
|
|
|
|
|
2010-10-20 14:13:00 +00:00
|
|
|
/*
|
|
|
|
* virSocketFormatAddrFull:
|
|
|
|
* @addr: an initialized virSocketAddrPtr
|
|
|
|
* @withService: if true, then service info is appended
|
|
|
|
* @separator: separator between hostname & service.
|
|
|
|
*
|
|
|
|
* Returns a string representation of the given address
|
|
|
|
* Returns NULL on any error
|
|
|
|
* Caller must free the returned string
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
virSocketFormatAddrFull(virSocketAddrPtr addr,
|
|
|
|
bool withService,
|
|
|
|
const char *separator)
|
|
|
|
{
|
|
|
|
char host[NI_MAXHOST], port[NI_MAXSERV];
|
|
|
|
char *addrstr;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (addr == NULL) {
|
2010-11-02 08:47:22 +00:00
|
|
|
virSocketError(VIR_ERR_INVALID_ARG, "%s", _("Missing address"));
|
2010-10-20 14:13:00 +00:00
|
|
|
return NULL;
|
2009-11-02 14:42:47 +00:00
|
|
|
}
|
|
|
|
|
2010-10-20 14:13:00 +00:00
|
|
|
/* Short-circuit since getnameinfo doesn't work
|
|
|
|
* nicely for UNIX sockets */
|
|
|
|
if (addr->data.sa.sa_family == AF_UNIX) {
|
|
|
|
if (withService) {
|
|
|
|
if (virAsprintf(&addrstr, "127.0.0.1%s0",
|
|
|
|
separator ? separator : ":") < 0)
|
|
|
|
goto no_memory;
|
|
|
|
} else {
|
|
|
|
if (!(addrstr = strdup("127.0.0.1")))
|
|
|
|
goto no_memory;
|
|
|
|
}
|
|
|
|
return addrstr;
|
2009-11-02 14:42:47 +00:00
|
|
|
}
|
|
|
|
|
2010-10-20 14:13:00 +00:00
|
|
|
if ((err = getnameinfo(&addr->data.sa,
|
|
|
|
addr->len,
|
|
|
|
host, sizeof(host),
|
|
|
|
port, sizeof(port),
|
|
|
|
NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
|
|
|
|
virSocketError(VIR_ERR_SYSTEM_ERROR,
|
|
|
|
_("Cannot convert socket address to string: %s"),
|
|
|
|
gai_strerror(err));
|
2009-11-02 14:42:47 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-10-20 14:13:00 +00:00
|
|
|
if (withService) {
|
|
|
|
if (virAsprintf(&addrstr, "%s%s%s", host, separator, port) == -1)
|
|
|
|
goto no_memory;
|
|
|
|
} else {
|
|
|
|
if (!(addrstr = strdup(host)))
|
|
|
|
goto no_memory;
|
2009-11-02 14:42:47 +00:00
|
|
|
}
|
|
|
|
|
2010-10-20 14:13:00 +00:00
|
|
|
return addrstr;
|
|
|
|
|
|
|
|
no_memory:
|
|
|
|
virReportOOMError();
|
|
|
|
return NULL;
|
2009-11-02 14:42:47 +00:00
|
|
|
}
|
|
|
|
|
2010-10-20 14:13:00 +00:00
|
|
|
|
2009-11-02 14:42:47 +00:00
|
|
|
/*
|
|
|
|
* virSocketSetPort:
|
2010-04-07 15:12:02 +00:00
|
|
|
* @addr: an initialized virSocketAddrPtr
|
2009-11-02 14:42:47 +00:00
|
|
|
* @port: the port number to set
|
|
|
|
*
|
|
|
|
* Set the transport layer port of the given virtSocketAddr
|
|
|
|
*
|
|
|
|
* Returns 0 on success, -1 on failure
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virSocketSetPort(virSocketAddrPtr addr, int port) {
|
|
|
|
if (addr == NULL)
|
|
|
|
return -1;
|
|
|
|
|
2009-11-05 16:56:08 +00:00
|
|
|
port = htons(port);
|
|
|
|
|
2010-10-20 13:21:15 +00:00
|
|
|
if(addr->data.stor.ss_family == AF_INET) {
|
|
|
|
addr->data.inet4.sin_port = port;
|
2009-11-02 14:42:47 +00:00
|
|
|
}
|
|
|
|
|
2010-10-20 13:21:15 +00:00
|
|
|
else if(addr->data.stor.ss_family == AF_INET6) {
|
|
|
|
addr->data.inet6.sin6_port = port;
|
2009-11-02 14:42:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* virSocketGetPort:
|
2010-04-07 15:12:02 +00:00
|
|
|
* @addr: an initialized virSocketAddrPtr
|
2009-11-02 14:42:47 +00:00
|
|
|
*
|
|
|
|
* Returns the transport layer port of the given virtSocketAddr
|
|
|
|
* Returns -1 if @addr is invalid
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virSocketGetPort(virSocketAddrPtr addr) {
|
|
|
|
if (addr == NULL)
|
|
|
|
return -1;
|
|
|
|
|
2010-10-20 13:21:15 +00:00
|
|
|
if(addr->data.stor.ss_family == AF_INET) {
|
|
|
|
return ntohs(addr->data.inet4.sin_port);
|
2009-11-02 14:42:47 +00:00
|
|
|
}
|
|
|
|
|
2010-10-20 13:21:15 +00:00
|
|
|
else if(addr->data.stor.ss_family == AF_INET6) {
|
|
|
|
return ntohs(addr->data.inet6.sin6_port);
|
2009-11-02 14:42:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-10-22 14:34:43 +00:00
|
|
|
/**
|
|
|
|
* 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) {
|
2010-03-30 15:18:04 +00:00
|
|
|
int n = virSocketGetNumNetmaskBits(netmask);
|
|
|
|
if (n < 0)
|
|
|
|
return -1;
|
|
|
|
return 0;
|
2009-10-22 14:34:43 +00:00
|
|
|
}
|
|
|
|
|
2010-11-26 18:51:44 +00:00
|
|
|
/**
|
|
|
|
* 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);
|
|
|
|
}
|
|
|
|
|
2010-12-31 02:33:24 +00:00
|
|
|
/**
|
|
|
|
* virSocketAddrBroadcast:
|
|
|
|
* @addr: address that needs to be turned into broadcast address (IPv4 only)
|
|
|
|
* @netmask: the netmask address
|
|
|
|
* @broadcast: virSocketAddr to recieve the broadcast address
|
|
|
|
*
|
|
|
|
* Mask ON the host bits of @addr according to @netmask, turning it
|
|
|
|
* into a broadcast address.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success, or -1 on error.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
virSocketAddrBroadcast(const virSocketAddrPtr addr,
|
|
|
|
const virSocketAddrPtr netmask,
|
|
|
|
virSocketAddrPtr broadcast)
|
|
|
|
{
|
|
|
|
if ((addr->data.stor.ss_family != AF_INET) ||
|
|
|
|
(netmask->data.stor.ss_family != AF_INET)) {
|
|
|
|
broadcast->data.stor.ss_family = AF_UNSPEC;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
broadcast->data.stor.ss_family = AF_INET;
|
|
|
|
broadcast->len = addr->len;
|
|
|
|
broadcast->data.inet4.sin_addr.s_addr
|
|
|
|
= (addr->data.inet4.sin_addr.s_addr
|
|
|
|
| ~netmask->data.inet4.sin_addr.s_addr);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virSocketAddrBroadcastByPrefix:
|
|
|
|
* @addr: address that needs to be turned into broadcast address (IPv4 only)
|
|
|
|
* @prefix: prefix (# of 1 bits) of netmask to apply
|
|
|
|
* @broadcast: virSocketAddr to recieve the broadcast address
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
virSocketAddrBroadcastByPrefix(const virSocketAddrPtr addr,
|
|
|
|
unsigned int prefix,
|
|
|
|
virSocketAddrPtr broadcast)
|
|
|
|
{
|
|
|
|
virSocketAddr netmask;
|
|
|
|
|
|
|
|
if (virSocketAddrPrefixToNetmask(prefix, &netmask,
|
|
|
|
addr->data.stor.ss_family) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return virSocketAddrBroadcast(addr, &netmask, broadcast);
|
|
|
|
}
|
|
|
|
|
2009-10-22 14:34:43 +00:00
|
|
|
/**
|
|
|
|
* 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);
|
2010-10-20 13:21:15 +00:00
|
|
|
if ((addr1->data.stor.ss_family != addr2->data.stor.ss_family) ||
|
|
|
|
(addr1->data.stor.ss_family != netmask->data.stor.ss_family))
|
2009-10-22 14:34:43 +00:00
|
|
|
return(-1);
|
|
|
|
|
|
|
|
if (virSocketAddrIsNetmask(netmask) != 0)
|
|
|
|
return(-1);
|
|
|
|
|
2010-10-20 13:21:15 +00:00
|
|
|
if (addr1->data.stor.ss_family == AF_INET) {
|
2009-10-22 14:34:43 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2010-10-20 13:28:55 +00:00
|
|
|
} else if (addr1->data.stor.ss_family == AF_INET6) {
|
2009-10-22 14:34:43 +00:00
|
|
|
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);
|
2010-10-20 13:21:15 +00:00
|
|
|
if (start->data.stor.ss_family != end->data.stor.ss_family)
|
2009-10-22 14:34:43 +00:00
|
|
|
return(-1);
|
|
|
|
|
2010-10-20 13:21:15 +00:00
|
|
|
if (start->data.stor.ss_family == AF_INET) {
|
2009-10-22 14:34:43 +00:00
|
|
|
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++;
|
2010-10-20 13:21:15 +00:00
|
|
|
} else if (start->data.stor.ss_family == AF_INET6) {
|
2009-10-22 14:34:43 +00:00
|
|
|
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);
|
|
|
|
}
|
2010-03-30 15:18:04 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virGetNumNetmaskBits
|
|
|
|
* @netmask: the presumed netmask
|
|
|
|
*
|
|
|
|
* Get the number of netmask bits in a netmask.
|
|
|
|
*
|
|
|
|
* Returns the number of bits in the netmask or -1 if an error occurred
|
|
|
|
* or the netmask is invalid.
|
|
|
|
*/
|
|
|
|
int virSocketGetNumNetmaskBits(const virSocketAddrPtr netmask)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
int c = 0;
|
|
|
|
|
2010-10-20 13:21:15 +00:00
|
|
|
if (netmask->data.stor.ss_family == AF_INET) {
|
2010-03-30 15:18:04 +00:00
|
|
|
virIPv4Addr tm;
|
|
|
|
uint8_t bit;
|
|
|
|
|
|
|
|
if (getIPv4Addr(netmask, &tm) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
if (tm[i] == 0xff)
|
|
|
|
c += 8;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (c == 8 * 4)
|
|
|
|
return c;
|
|
|
|
|
|
|
|
j = i << 3;
|
|
|
|
while (j < (8 * 4)) {
|
|
|
|
bit = 1 << (7 - (j & 7));
|
|
|
|
if ((tm[j >> 3] & bit)) {
|
|
|
|
c++;
|
|
|
|
} else
|
|
|
|
break;
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (j < (8 * 4)) {
|
|
|
|
bit = 1 << (7 - (j & 7));
|
|
|
|
if ((tm[j >> 3] & bit))
|
|
|
|
return -1;
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return c;
|
2010-10-20 13:21:15 +00:00
|
|
|
} else if (netmask->data.stor.ss_family == AF_INET6) {
|
2010-03-30 15:18:04 +00:00
|
|
|
virIPv6Addr tm;
|
|
|
|
uint16_t bit;
|
|
|
|
|
|
|
|
if (getIPv6Addr(netmask, &tm) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
for (i = 0; i < 8; i++)
|
|
|
|
if (tm[i] == 0xffff)
|
|
|
|
c += 16;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (c == 16 * 8)
|
|
|
|
return c;
|
|
|
|
|
|
|
|
j = i << 4;
|
|
|
|
while (j < (16 * 8)) {
|
|
|
|
bit = 1 << (15 - (j & 0xf));
|
|
|
|
if ((tm[j >> 4] & bit)) {
|
|
|
|
c++;
|
|
|
|
} else
|
|
|
|
break;
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (j < (16 * 8)) {
|
|
|
|
bit = 1 << (15 - (j & 0xf));
|
|
|
|
if ((tm[j >> 4]) & bit)
|
|
|
|
return -1;
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
2010-11-26 18:51:44 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
}
|