If IPv6 is enabled on the host, bind to :: with IPV6_V6ONLY disabled
to check for ports available on both IPv6 and IPv4.
---
src/util/virportallocator.c | 34 +++++++++++++++++++++++++++-------
1 file changed, 27 insertions(+), 7 deletions(-)
diff --git a/src/util/virportallocator.c b/src/util/virportallocator.c
index 5b7ad41..246f6cd 100644
--- a/src/util/virportallocator.c
+++ b/src/util/virportallocator.c
@@ -99,14 +99,25 @@ int virPortAllocatorAcquire(virPortAllocatorPtr pa,
int ret = -1;
size_t i;
int fd = -1;
+ bool ipv6 = virHostHasIPv6();
*port = 0;
virObjectLock(pa);
for (i = pa->start; i <= pa->end && !*port; i++) {
- int reuse = 1;
- struct sockaddr_in addr;
+ int reuse = 1, v6only = 0;
+ struct sockaddr_in addr = {
+ .sin_family = AF_INET,
+ .sin_port = htons(i),
+ .sin_addr.s_addr = htonl(INADDR_ANY)
+ };
+ struct sockaddr_in6 addr6 = {
+ .sin6_family = AF_INET6,
+ .sin6_port = htons(i),
+ .sin6_addr = IN6ADDR_ANY_INIT
+ };
bool used = false;
+ int rc;
if (virBitmapGetBit(pa->bitmap,
i - pa->start, &used) < 0) {
@@ -118,10 +129,7 @@ int virPortAllocatorAcquire(virPortAllocatorPtr pa,
if (used)
continue;
- addr.sin_family = AF_INET;
- addr.sin_port = htons(i);
- addr.sin_addr.s_addr = htonl(INADDR_ANY);
- fd = socket(PF_INET, SOCK_STREAM, 0);
+ fd = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_STREAM, 0);
if (fd < 0) {
virReportSystemError(errno, "%s",
_("Unable to open test socket"));
@@ -134,7 +142,19 @@ int virPortAllocatorAcquire(virPortAllocatorPtr pa,
goto cleanup;
}
- if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+ if (ipv6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
(void*)&v6only,
+ sizeof(v6only)) < 0) {
+ virReportSystemError(errno, "%s",
+ _("Unable to unset socket IPV6_V6ONLY
flag"));
+ goto cleanup;
+ }
+
+ if (ipv6)
+ rc = bind(fd, (struct sockaddr*)&addr6, sizeof(addr6));
+ else
+ rc = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
+
+ if (rc < 0) {
if (errno != EADDRINUSE) {
virReportSystemError(errno,
_("Unable to bind to port %zu"), i);
--
1.8.1.5