[libvirt] [PATCH 2/2] Bind to both IPv4 and v6 when checking port availability

Ján Tomko jtomko at redhat.com
Tue Oct 1 09:01:37 UTC 2013


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




More information about the libvir-list mailing list