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(a)redhat.com>
---
Notes:
ACKed in v2
src/libvirt_private.syms | 1 +
src/util/virsocketaddr.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++
src/util/virsocketaddr.h | 9 +++++
3 files changed, 95 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 7beebbf27..1391a4282 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2403,6 +2403,7 @@ virSocketAddrParse;
virSocketAddrParseIPv4;
virSocketAddrParseIPv6;
virSocketAddrPrefixToNetmask;
+virSocketAddrPTRDomain;
virSocketAddrSetIPv4Addr;
virSocketAddrSetIPv4AddrNetOrder;
virSocketAddrSetIPv6Addr;
diff --git a/src/util/virsocketaddr.c b/src/util/virsocketaddr.c
index 33b1e9e1f..41f75d5c2 100644
--- a/src/util/virsocketaddr.c
+++ b/src/util/virsocketaddr.c
@@ -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,
@@ -78,6 +81,23 @@ virSocketAddrGetIPv6Addr(const virSocketAddr *addr,
virSocketAddrIPv6Ptr tab)
}
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,
int family,
@@ -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;
+}
diff --git a/src/util/virsocketaddr.h b/src/util/virsocketaddr.h
index 7ee993b1a..43a370620 100644
--- a/src/util/virsocketaddr.h
+++ b/src/util/virsocketaddr.h
@@ -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__ */
--
2.11.0