mrc0mmand / rpms / libguestfs

Forked from rpms/libguestfs 3 years ago
Clone

Blame SOURCES/0088-p2v-avoid-connecting-to-ourself-while-probing-qemu-n.patch

0d20ef
From f0e55ad5672f8c8425cef1a355ef330e4e2bf8d0 Mon Sep 17 00:00:00 2001
0d20ef
From: John Eckersberg <jeckersb@redhat.com>
0d20ef
Date: Mon, 15 Dec 2014 13:19:06 -0500
0d20ef
Subject: [PATCH] p2v: avoid connecting to ourself while probing qemu-nbd
0d20ef
 (RHBZ#1167774)
0d20ef
0d20ef
(cherry picked from commit 09080a28878a17b991c812e2b93a8d8394383d04)
0d20ef
---
0d20ef
 p2v/conversion.c | 43 +++++++++++++++++++++++++++++++++++++------
0d20ef
 1 file changed, 37 insertions(+), 6 deletions(-)
0d20ef
0d20ef
diff --git a/p2v/conversion.c b/p2v/conversion.c
0d20ef
index 4ff7ecc..14e7b3b 100644
0d20ef
--- a/p2v/conversion.c
0d20ef
+++ b/p2v/conversion.c
0d20ef
@@ -398,7 +398,8 @@ wait_qemu_nbd (int nbd_local_port, int timeout_seconds)
0d20ef
 {
0d20ef
   int sockfd;
0d20ef
   int result = -1;
0d20ef
-  struct sockaddr_in addr;
0d20ef
+  int reuseaddr = 1;
0d20ef
+  struct sockaddr_in src_addr, dst_addr;
0d20ef
   time_t start_t, now_t;
0d20ef
   struct timeval timeout = { .tv_usec = 0 };
0d20ef
   char magic[8]; /* NBDMAGIC */
0d20ef
@@ -413,10 +414,40 @@ wait_qemu_nbd (int nbd_local_port, int timeout_seconds)
0d20ef
     return -1;
0d20ef
   }
0d20ef
 
0d20ef
-  memset (&addr, 0, sizeof addr);
0d20ef
-  addr.sin_family = AF_INET;
0d20ef
-  addr.sin_port = htons (nbd_local_port);
0d20ef
-  inet_pton (AF_INET, "localhost", &addr.sin_addr);
0d20ef
+  memset (&src_addr, 0, sizeof src_addr);
0d20ef
+  src_addr.sin_family = AF_INET;
0d20ef
+  /* Source port for probing qemu-nbd should be one greater than
0d20ef
+   * nbd_local_port.  It's not guaranteed to always bind to this port,
0d20ef
+   * but it will hint the kernel to start there and try incrementally
0d20ef
+   * higher ports if needed.  This avoids the case where the kernel
0d20ef
+   * selects nbd_local_port as our source port, and we immediately
0d20ef
+   * connect to ourself.  See:
0d20ef
+   * https://bugzilla.redhat.com/show_bug.cgi?id=1167774#c9
0d20ef
+   */
0d20ef
+  src_addr.sin_port = htons (nbd_local_port+1);
0d20ef
+  inet_pton (AF_INET, "localhost", &src_addr.sin_addr);
0d20ef
+
0d20ef
+  memset (&dst_addr, 0, sizeof dst_addr);
0d20ef
+  dst_addr.sin_family = AF_INET;
0d20ef
+  dst_addr.sin_port = htons (nbd_local_port);
0d20ef
+  inet_pton (AF_INET, "localhost", &dst_addr.sin_addr);
0d20ef
+
0d20ef
+  /* If we run p2v repeatedly (say, running the tests in a loop),
0d20ef
+   * there's a decent chance we'll end up trying to bind() to a port
0d20ef
+   * that is in TIME_WAIT from a prior run.  Handle that gracefully
0d20ef
+   * with SO_REUSEADDR.
0d20ef
+   */
0d20ef
+  if (setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR,
0d20ef
+                  &reuseaddr, sizeof reuseaddr) == -1) {
0d20ef
+    set_conversion_error ("waiting for qemu-nbd to start: setsockopt: %m");
0d20ef
+    goto cleanup;
0d20ef
+  }
0d20ef
+
0d20ef
+  if (bind (sockfd, (struct sockaddr *) &src_addr, sizeof src_addr) == -1) {
0d20ef
+    set_conversion_error ("waiting for qemu-nbd to start: bind(%d): %m",
0d20ef
+                          ntohs (src_addr.sin_port));
0d20ef
+    goto cleanup;
0d20ef
+  }
0d20ef
 
0d20ef
   for (;;) {
0d20ef
     time (&now_t);
0d20ef
@@ -426,7 +457,7 @@ wait_qemu_nbd (int nbd_local_port, int timeout_seconds)
0d20ef
       goto cleanup;
0d20ef
     }
0d20ef
 
0d20ef
-    if (connect (sockfd, (struct sockaddr *) &addr, sizeof addr) == 0)
0d20ef
+    if (connect (sockfd, (struct sockaddr *) &dst_addr, sizeof dst_addr) == 0)
0d20ef
       break;
0d20ef
   }
0d20ef
 
0d20ef
-- 
0d20ef
1.8.3.1
0d20ef