util: Introduce virSocketAddrPTRDomain

The API creates PTR domain which corresponds to a given addr/prefix.
Both IPv4 and IPv6 addresses are supported, but the prefix must be
divisible by 8 for IPv4 and divisible by 4 for IPv6.

The generated PTR domain has the following format

IPv4: 1.2.3.4.in-addr.arpa
IPv6: 0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.ip6.arpa

Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
This commit is contained in:
Jiri Denemark 2016-12-08 22:21:39 +01:00
parent 770b1d2b56
commit acd547dc95
3 changed files with 95 additions and 0 deletions

View File

@ -2403,6 +2403,7 @@ virSocketAddrParse;
virSocketAddrParseIPv4;
virSocketAddrParseIPv6;
virSocketAddrPrefixToNetmask;
virSocketAddrPTRDomain;
virSocketAddrSetIPv4Addr;
virSocketAddrSetIPv4AddrNetOrder;
virSocketAddrSetIPv6Addr;

View File

@ -27,6 +27,7 @@
#include "virerror.h"
#include "virstring.h"
#include "viralloc.h"
#include "virbuffer.h"
#include <netdb.h>
@ -40,6 +41,8 @@ typedef unsigned char virSocketAddrIPv4[4];
typedef virSocketAddrIPv4 *virSocketAddrIPv4Ptr;
typedef unsigned short virSocketAddrIPv6[8];
typedef virSocketAddrIPv6 *virSocketAddrIPv6Ptr;
typedef unsigned char virSocketAddrIPv6Nibbles[32];
typedef virSocketAddrIPv6Nibbles *virSocketAddrIPv6NibblesPtr;
static int
virSocketAddrGetIPv4Addr(const virSocketAddr *addr,
@ -77,6 +80,23 @@ virSocketAddrGetIPv6Addr(const virSocketAddr *addr, virSocketAddrIPv6Ptr tab)
return 0;
}
static int
virSocketAddrGetIPv6Nibbles(const virSocketAddr *addr,
virSocketAddrIPv6NibblesPtr tab)
{
size_t i;
if (!addr || !tab || addr->data.stor.ss_family != AF_INET6)
return -1;
for (i = 0; i < 16; i++) {
(*tab)[2 * i] = addr->data.inet6.sin6_addr.s6_addr[i] >> 4;
(*tab)[2 * i + 1] = addr->data.inet6.sin6_addr.s6_addr[i] & 0xF;
}
return 0;
}
static int
virSocketAddrParseInternal(struct addrinfo **res,
const char *val,
@ -1118,3 +1138,68 @@ virSocketAddrIsNumericLocalhost(const char *addr)
return false;
}
/**
* virSocketAddrPTRDomain:
*
* Create PTR domain which corresponds to @addr/@prefix. Both IPv4 and IPv6
* addresses are supported, but @prefix must be divisible by 8 for IPv4 and
* divisible by 4 for IPv6, otherwise -2 will be returned.
*
* Returns -2 if the PTR record cannot be automatically created,
* -1 on error,
* 0 on success.
*/
int
virSocketAddrPTRDomain(const virSocketAddr *addr,
unsigned int prefix,
char **ptr)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
size_t i;
int ret = -1;
if (VIR_SOCKET_ADDR_IS_FAMILY(addr, AF_INET)) {
virSocketAddrIPv4 ip;
if (prefix == 0 || prefix >= 32 || prefix % 8 != 0)
goto unsupported;
if (virSocketAddrGetIPv4Addr(addr, &ip) < 0)
goto cleanup;
for (i = prefix / 8; i > 0; i--)
virBufferAsprintf(&buf, "%u.", ip[i - 1]);
virBufferAddLit(&buf, VIR_SOCKET_ADDR_IPV4_ARPA);
} else if (VIR_SOCKET_ADDR_IS_FAMILY(addr, AF_INET6)) {
virSocketAddrIPv6Nibbles ip;
if (prefix == 0 || prefix >= 128 || prefix % 4 != 0)
goto unsupported;
if (virSocketAddrGetIPv6Nibbles(addr, &ip) < 0)
goto cleanup;
for (i = prefix / 4; i > 0; i--)
virBufferAsprintf(&buf, "%x.", ip[i - 1]);
virBufferAddLit(&buf, VIR_SOCKET_ADDR_IPV6_ARPA);
} else {
goto unsupported;
}
if (!(*ptr = virBufferContentAndReset(&buf)))
goto cleanup;
ret = 0;
cleanup:
virBufferFreeAndReset(&buf);
return ret;
unsupported:
ret = -2;
goto cleanup;
}

View File

@ -57,6 +57,9 @@ typedef struct {
# define VIR_SOCKET_ADDR_IPV4_ALL "0.0.0.0"
# define VIR_SOCKET_ADDR_IPV6_ALL "::"
# define VIR_SOCKET_ADDR_IPV4_ARPA "in-addr.arpa"
# define VIR_SOCKET_ADDR_IPV6_ARPA "ip6.arpa"
typedef virSocketAddr *virSocketAddrPtr;
typedef struct _virSocketAddrRange virSocketAddrRange;
@ -136,4 +139,10 @@ bool virSocketAddrIsWildcard(const virSocketAddr *addr);
int virSocketAddrNumericFamily(const char *address);
bool virSocketAddrIsNumericLocalhost(const char *addr);
int virSocketAddrPTRDomain(const virSocketAddr *addr,
unsigned int prefix,
char **ptr)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3);
#endif /* __VIR_SOCKETADDR_H__ */