diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index cdeb8e06e6de672a1ae8450518f99ba4853faf5e..844ca29d7abeee99047cd2b015768b4b212a9f5e 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1683,6 +1683,7 @@ virSocketAddrGetIpPrefix; virSocketAddrGetPort; virSocketAddrGetRange; virSocketAddrIsNetmask; +virSocketAddrIsNumeric; virSocketAddrIsPrivate; virSocketAddrIsWildcard; virSocketAddrMask; diff --git a/src/util/virsocketaddr.c b/src/util/virsocketaddr.c index 3e01baf1907031871f7bdbe2f6188855d92f0d6a..6df9205976b8a70870b5fa515f2cc4d7e73ffae4 100644 --- a/src/util/virsocketaddr.c +++ b/src/util/virsocketaddr.c @@ -71,6 +71,35 @@ static int virSocketAddrGetIPv6Addr(virSocketAddrPtr addr, virSocketAddrIPv6Ptr return 0; } +static int +virSocketAddrParseInternal(struct addrinfo **res, + const char *val, + int family, + bool reportError) +{ + struct addrinfo hints; + int err; + + if (val == NULL) { + virReportError(VIR_ERR_INVALID_ARG, "%s", _("Missing address")); + return -1; + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = family; + hints.ai_flags = AI_NUMERICHOST; + if ((err = getaddrinfo(val, NULL, &hints, res)) != 0) { + if (reportError) + virReportError(VIR_ERR_SYSTEM_ERROR, + _("Cannot parse socket address '%s': %s"), + val, gai_strerror(err)); + + return -1; + } + + return 0; +} + /** * virSocketAddrParse: * @val: a numeric network address IPv4 or IPv6 @@ -84,24 +113,10 @@ static int virSocketAddrGetIPv6Addr(virSocketAddrPtr addr, virSocketAddrIPv6Ptr */ int virSocketAddrParse(virSocketAddrPtr addr, const char *val, int family) { int len; - struct addrinfo hints; - struct addrinfo *res = NULL; - int err; + struct addrinfo *res; - if (val == NULL) { - virReportError(VIR_ERR_INVALID_ARG, "%s", _("Missing address")); + if (virSocketAddrParseInternal(&res, val, family, true) < 0) return -1; - } - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = family; - hints.ai_flags = AI_NUMERICHOST; - if ((err = getaddrinfo(val, NULL, &hints, &res)) != 0) { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("Cannot parse socket address '%s': %s"), - val, gai_strerror(err)); - return -1; - } if (res == NULL) { virReportError(VIR_ERR_SYSTEM_ERROR, @@ -824,3 +839,28 @@ virSocketAddrGetIpPrefix(const virSocketAddrPtr address, */ return 0; } + +/** + * virSocketAddrIsNumeric: + * @address: address to check + * + * Check if passed address is an IP address in numeric format. For + * instance, for 0.0.0.0 true is returned, for 'examplehost" + * false is returned. + * + * Returns: true if @address is an IP address, + * false otherwise + */ +bool +virSocketAddrIsNumeric(const char *address) +{ + struct addrinfo *res; + unsigned short family; + + if (virSocketAddrParseInternal(&res, address, AF_UNSPEC, false) < 0) + return false; + + family = res->ai_addr->sa_family; + freeaddrinfo(res); + return family == AF_INET || family == AF_INET6; +} diff --git a/src/util/virsocketaddr.h b/src/util/virsocketaddr.h index b28fe6c7d5fd0ad5b0fbbc15a95b05669655a54d..d844914657082a9296cb960669343e88c59d4f4b 100644 --- a/src/util/virsocketaddr.h +++ b/src/util/virsocketaddr.h @@ -124,4 +124,6 @@ bool virSocketAddrEqual(const virSocketAddrPtr s1, bool virSocketAddrIsPrivate(const virSocketAddrPtr addr); bool virSocketAddrIsWildcard(const virSocketAddrPtr addr); + +bool virSocketAddrIsNumeric(const char *address); #endif /* __VIR_SOCKETADDR_H__ */ diff --git a/tests/sockettest.c b/tests/sockettest.c index 4b38cdf016dee570d967610d6844ca48025458d1..f98955d6f0c1bd9959f9b00a485b282ed2ed4660 100644 --- a/tests/sockettest.c +++ b/tests/sockettest.c @@ -174,6 +174,21 @@ static int testWildcardHelper(const void *opaque) return testWildcard(data->addr, data->pass); } +struct testIsNumericData { + const char *addr; + bool pass; +}; + +static int +testIsNumericHelper(const void *opaque) +{ + const struct testIsNumericData *data = opaque; + + if (virSocketAddrIsNumeric(data->addr)) + return data->pass ? 0 : -1; + return data->pass ? -1 : 0; +} + static int mymain(void) { @@ -246,6 +261,14 @@ mymain(void) ret = -1; \ } while (0) +#define DO_TEST_IS_NUMERIC(addr, pass) \ + do { \ + struct testIsNumericData data = { addr, pass}; \ + if (virtTestRun("Test isNumeric " addr, \ + testIsNumericHelper, &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); @@ -307,6 +330,12 @@ mymain(void) DO_TEST_WILDCARD("1", false); DO_TEST_WILDCARD("0.1", false); + DO_TEST_IS_NUMERIC("0.0.0.0", true); + DO_TEST_IS_NUMERIC("::", true); + DO_TEST_IS_NUMERIC("1", true); + DO_TEST_IS_NUMERIC("::ffff", true); + DO_TEST_IS_NUMERIC("examplehost", false); + return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE; }