[1/2,criu] soccr: c/r ipv6 sockets which handles ipv4 connections

Submitted by Andrei Vagin on Nov. 1, 2017, 10:03 p.m.

Details

Message ID 20171101220318.6590-1-avagin@openvz.org
State New
Series "Series without cover letter"
Headers show

Commit Message

Andrei Vagin Nov. 1, 2017, 10:03 p.m.
From: Andrei Vagin <avagin@virtuozzo.com>

IPv6 listening sockets can accept both ipv4 and ipv6 connections,
in both cases a family of an accepted socket will be AF_INET6.

But we have to send tcp packets accoding with a connection type.

------------------------ grep Error ------------------------
(00.002320)     53: Debug: 		Will set rcv_wscale to 7
(00.002325)     53: Debug: 		Will turn timestamps on
(00.002331)     53: Debug: Will set mss clamp to 65495
(00.002338)     53: Debug: 	Restoring TCP 1 queue data 2 bytes
(00.002403)     53: Error (soccr/soccr.c:673): Unable to send a fin packet: libnet_write_raw_ipv6(): -1 bytes written (Network is unreachable)

(00.002434)     53: Error (criu/files.c:1191): Unable to open fd=3 id=0x6
(00.002506) Error (criu/cr-restore.c:2171): Restoring FAILED.
------------------------ ERROR OVER ------------------------

Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>

Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
---
 soccr/soccr.c | 29 +++++++++++++++++++++++------
 1 file changed, 23 insertions(+), 6 deletions(-)

Patch hide | download patch | download mbox

diff --git a/soccr/soccr.c b/soccr/soccr.c
index 394095f00..2d49766dc 100644
--- a/soccr/soccr.c
+++ b/soccr/soccr.c
@@ -580,16 +580,33 @@  static int libsoccr_set_sk_data_noq(struct libsoccr_sk *sk,
 	return 0;
 }
 
+/* IPv4-Mapped IPv6 Addresses */
+static int ipv6_addr_mapped(union libsoccr_addr *addr)
+{
+	return (addr->v6.sin6_addr.s6_addr32[2] == htonl(0x0000ffff));
+}
+
 static int send_fin(struct libsoccr_sk *sk, struct libsoccr_sk_data *data,
 		unsigned data_size, uint8_t flags)
 {
-	int ret, exit_code = -1;
+	uint32_t src_v4 = sk->src_addr->v4.sin_addr.s_addr;
+	uint32_t dst_v4 = sk->dst_addr->v4.sin_addr.s_addr;
+	int ret, exit_code = -1, family;
 	char errbuf[LIBNET_ERRBUF_SIZE];
 	int mark = SOCCR_MARK;;
 	int libnet_type;
 	libnet_t *l;
 
-	if (sk->dst_addr->sa.sa_family == AF_INET6)
+	family = sk->dst_addr->sa.sa_family;
+
+	if (family == AF_INET6 && ipv6_addr_mapped(sk->dst_addr)) {
+		/* TCP over IPv4 */
+		family = AF_INET;
+		dst_v4 = sk->dst_addr->v6.sin6_addr.s6_addr32[3];
+		src_v4 = sk->src_addr->v6.sin6_addr.s6_addr32[3];
+	}
+
+	if (family == AF_INET6)
 		libnet_type = LIBNET_RAW6;
 	else
 		libnet_type = LIBNET_RAW4;
@@ -627,7 +644,7 @@  static int send_fin(struct libsoccr_sk *sk, struct libsoccr_sk_data *data,
 		goto err;
 	}
 
-	if (sk->dst_addr->sa.sa_family == AF_INET6) {
+	if (family == AF_INET6) {
 		struct libnet_in6_addr src, dst;
 
 		memcpy(&dst, &sk->dst_addr->v6.sin6_addr, sizeof(dst));
@@ -644,7 +661,7 @@  static int send_fin(struct libsoccr_sk *sk, struct libsoccr_sk_data *data,
 			0,		/* payload size */
 			l,		/* libnet handle */
 			0);		/* libnet id */
-	} else if (sk->dst_addr->sa.sa_family == AF_INET)
+	} else if (family == AF_INET)
 		ret = libnet_build_ipv4(
 			LIBNET_IPV4_H + LIBNET_TCP_H + 20,	/* length */
 			0,			/* TOS */
@@ -653,8 +670,8 @@  static int send_fin(struct libsoccr_sk *sk, struct libsoccr_sk_data *data,
 			64,			/* TTL */
 			IPPROTO_TCP,		/* protocol */
 			0,			/* checksum */
-			sk->dst_addr->v4.sin_addr.s_addr,	/* source IP */
-			sk->src_addr->v4.sin_addr.s_addr,	/* destination IP */
+			dst_v4,			/* source IP */
+			src_v4,			/* destination IP */
 			NULL,			/* payload */
 			0,			/* payload size */
 			l,			/* libnet handle */