|
|
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 |
|