From acd547dc9510224250a6237545f28e5b290f45f3 Mon Sep 17 00:00:00 2001 From: Jiri Denemark Date: Thu, 8 Dec 2016 22:21:39 +0100 Subject: [PATCH] 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 --- 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 5c82e4a0e6..4c0170c030 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 33b1e9e1f0..41f75d5c24 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 @@ -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; +} diff --git a/src/util/virsocketaddr.h b/src/util/virsocketaddr.h index 7ee993b1a6..43a370620e 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__ */