[CRIU] [PATCH 2/2] inet: set IP_FREEBIND before binding socket to an ipv6 address

Andrey Vagin avagin at openvz.org
Wed Nov 18 07:58:10 PST 2015


From: Andrew Vagin <avagin at virtuozzo.com>

When we restore ipv6 addresses, they go through a “tentative” phase
and sockets could not be bound to them in this moment.

Reported-by: Ross Boucher <boucher at gmail.com>
Signed-off-by: Andrew Vagin <avagin at virtuozzo.com>
---
 sk-inet.c | 29 ++++++++++++++++++++++++-----
 1 file changed, 24 insertions(+), 5 deletions(-)

diff --git a/sk-inet.c b/sk-inet.c
index 779a1bd..a973000 100644
--- a/sk-inet.c
+++ b/sk-inet.c
@@ -633,17 +633,29 @@ static int restore_sockaddr(union sockaddr_inet *sa,
 
 int inet_bind(int sk, struct inet_sk_info *ii)
 {
+	bool rst_freebind = false;
 	union sockaddr_inet addr;
 	int addr_size;
-	int val;
 
 	addr_size = restore_sockaddr(&addr, ii->ie->family,
 			ii->ie->src_port, ii->ie->src_addr);
 
-	val = 1;
-	if (setsockopt(sk, SOL_IP, IP_FREEBIND, &val, sizeof(int))) {
-		pr_perror("Unable to set IP_FREEBIND");
-		return -1;
+	/*
+	 * ipv6 addresses go through a “tentative” phase and
+	 * sockets could not be bound to them in this moment
+	 * without setting IP_FREEBIND.
+	 */
+	if (ii->ie->family == AF_INET6) {
+		int yes = 1;
+
+		if (restore_opt(sk, SOL_IP, IP_FREEBIND, &yes))
+			return -1;
+
+		if (ii->ie->ip_opts && ii->ie->ip_opts->freebind)
+			/* don't restore freebind in restore_ip_opts() */
+			ii->ie->ip_opts->has_freebind = false;
+		else
+			rst_freebind = true;
 	}
 
 	if (bind(sk, (struct sockaddr *)&addr, addr_size) == -1) {
@@ -651,6 +663,13 @@ int inet_bind(int sk, struct inet_sk_info *ii)
 		return -1;
 	}
 
+	if (rst_freebind) {
+		int no = 0;
+
+		if (restore_opt(sk, SOL_IP, IP_FREEBIND, &no))
+			return -1;
+	}
+
 	return 0;
 }
 
-- 
2.4.3



More information about the CRIU mailing list