virSocketAddrSetIPv6Addr;
virSocketAddrSetIPv6AddrNetOrder;
virSocketAddrSetPort;
+virSocketAddrSubnetToPrefix;
# util/virstoragefile.h
#include "virsocketaddr.h"
#include "virerror.h"
#include "virbuffer.h"
+#include "virstring.h"
#define VIR_FROM_THIS VIR_FROM_NONE
return family;
}
+/**
+ * virSocketAddrSubnetToPrefix:
+ * @subnet: address to convert
+ *
+ * Converts subnet mask to prefix. If @subnet is of an IPv4
+ * format (NNN.NNN.NNN.NNN) then corresponding prefix length is
+ * returned (i.e. number of leading bits.). If @subnet is just a
+ * number (optionally prefixed with '/') then the number is
+ * parsed and returned. There is a corner case: if @subnet is
+ * valid IPv4 address but not valid subnet mask then a positive
+ * value is returned, but obviously it is not valid prefix.
+ *
+ * Returns: prefix corresponding to @subnet,
+ * -1 otherwise.
+ */
+int
+virSocketAddrSubnetToPrefix(const char *subnet)
+{
+ struct addrinfo *ai = NULL;
+ unsigned int prefix = 0;
+ struct sockaddr_in in;
+ int ret = -1;
+
+ if (*subnet == '/') {
+ /* /NN format */
+ if (virStrToLong_ui(subnet + 1, NULL, 10, &prefix) < 0)
+ return -1;
+ return prefix;
+ }
+
+ if (virStrToLong_ui(subnet, NULL, 10, &prefix) >= 0) {
+ /* plain NN format */
+ return prefix;
+ }
+
+ if (virSocketAddrParseInternal(&ai, subnet, AF_INET, AI_NUMERICHOST, false) < 0)
+ return -1;
+
+ if (ai->ai_family != AF_INET) {
+ /* huh? */
+ goto cleanup;
+ }
+
+ memcpy(&in, ai->ai_addr, sizeof(in));
+ prefix = __builtin_popcount(in.sin_addr.s_addr);
+
+ ret = prefix;
+ cleanup:
+ freeaddrinfo(ai);
+ return ret;
+}
+
/**
* virSocketAddrIsNumericLocalhost:
* @address: address to check
int virSocketAddrNumericFamily(const char *address);
+int virSocketAddrSubnetToPrefix(const char *subnet);
+
bool virSocketAddrIsNumericLocalhost(const char *addr);
int virSocketAddrPTRDomain(const virSocketAddr *addr,
return 0;
}
+struct testSubnetToPrefixData {
+ const char *addr;
+ int prefix;
+};
+
+static int
+testSubnetToPrefixHelper(const void *opaque)
+{
+ const struct testSubnetToPrefixData *data = opaque;
+ int val = virSocketAddrSubnetToPrefix(data->addr);
+
+ if (val != data->prefix) {
+ fprintf(stderr, "actual: '%d', expected: '%d'", val, data->prefix);
+ return -1;
+ }
+
+ return 0;
+}
+
static int
mymain(void)
{
ret = -1; \
} while (0)
+#define DO_TEST_SUBNET_TO_PREFIX(addr, prefix) \
+ do { \
+ struct testSubnetToPrefixData data = { addr, prefix }; \
+ if (virTestRun("Test subnet to prefix " addr, \
+ testSubnetToPrefixHelper, &data) < 0) \
+ ret = -1; \
+ } while (0)
+
DO_TEST_PARSE_AND_FORMAT("127.0.0.1", AF_UNSPEC, true);
DO_TEST_PARSE_AND_FORMAT("127.0.0.1", AF_INET, true);
DO_TEST_PARSE_AND_FORMAT("127.0.0.1", AF_INET6, false);
DO_TEST_LOCALHOST("hello", false);
DO_TEST_LOCALHOST("fe80::1:1", false);
+ DO_TEST_SUBNET_TO_PREFIX("0.0.0.0", 0);
+ DO_TEST_SUBNET_TO_PREFIX("255.0.0.0", 8);
+ DO_TEST_SUBNET_TO_PREFIX("255.255.255.254", 31);
+ DO_TEST_SUBNET_TO_PREFIX("64", 64);
+ DO_TEST_SUBNET_TO_PREFIX("/64", 64);
+
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}