criu icon indicating copy to clipboard operation
criu copied to clipboard

sk-inet: Support IP_TRANSPARENT and IPV6_TRANSPARENT socket options

Open juntongdeng opened this issue 1 year ago • 6 comments

Support for IP_TRANSPARENT and IPV6_TRANSPARENT socket options is useful for restoring transparent proxies.

juntongdeng avatar Mar 02 '24 22:03 juntongdeng

Codecov Report

All modified and coverable lines are covered by tests :white_check_mark:

Project coverage is 70.72%. Comparing base (cb39c62) to head (85842b2).

:exclamation: Current head 85842b2 differs from pull request most recent head 7c2c8a8. Consider uploading reports for the commit 7c2c8a8 to get more accurate results

Additional details and impacted files
@@             Coverage Diff              @@
##           criu-dev    #2357      +/-   ##
============================================
+ Coverage     70.21%   70.72%   +0.50%     
============================================
  Files           132      135       +3     
  Lines         34372    32907    -1465     
============================================
- Hits          24134    23272     -862     
+ Misses        10238     9635     -603     

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

codecov-commenter avatar Mar 10 '24 14:03 codecov-commenter

Please reorder patches, c/r support must be first patch and a test for it must be second patch. This way you would not break tests on bisect.

Snorch avatar Mar 27 '24 06:03 Snorch

This PR tries to do a good thing. But actually there it misses a bigger problem with IP_TRANSPARENT option, this option allows to bind to non-local address, so if we modify the test a bit to actually do the bind to non-local address:

--- a/test/zdtm/static/sock_ip_opts00.c
+++ b/test/zdtm/static/sock_ip_opts00.c
@@ -5,6 +5,7 @@
 #include <linux/in.h>
 #include <linux/ip.h>
 #include <linux/in6.h>
+#include <arpa/inet.h>
 
 #include "zdtmtst.h"
 
@@ -83,6 +84,21 @@ int main(int argc, char **argv)
                                goto close;
                        }
                }
+
+               if (sk_confs[i].domain == AF_INET) {
+                       socklen_t len = sizeof(struct sockaddr_in);
+                       struct sockaddr_in addr;
+
+                       memset(&addr, 0, sizeof(addr));
+                       addr.sin_family = AF_INET;
+                       addr.sin_addr.s_addr = inet_addr("5.5.5.5");
+                       addr.sin_port = htons(5555);
+
+                       if (bind(sk_confs[i].sk, (struct sockaddr *)&addr, len) < 0) {
+                               pr_perror("bind on 5.5.5.5:5555 failed");
+                               goto close;
+                       }
+               }
        }
 
        test_daemon();

We see that nothing works:

[root@turmoil criu]# ./test/zdtm.py run -t zdtm/static/sock_ip_opts00
userns is supported
Checking feature ipv6_freebind
ipv6_freebind is supported
=== Run 1/1 ================ zdtm/static/sock_ip_opts00
===================== Run zdtm/static/sock_ip_opts00 in ns =====================
 DEP       sock_ip_opts00.d
 DEP       sock_ip_opts01.d
 CC        sock_ip_opts00.o
 LINK      sock_ip_opts00
Start test
Test is SUID
./sock_ip_opts00 --pidfile=sock_ip_opts00.pid --outfile=sock_ip_opts00.out
Run criu dump
Run criu restore
=[log]=> dump/zdtm/static/sock_ip_opts00/104/1/restore.log
------------------------ grep Error ------------------------
b'(00.002868)      1: No ipcns-sem-11.img image'
b'(00.003590)      1: net: Try to restore a link 10:1:lo'
b'(00.003707)      1: net: Restoring link lo type 1'
b'(00.004127)      1: net: \tRunning ip addr restore'
b'Error: ipv4: Address already assigned.'
b'Error: ipv6: address already assigned.'
b'(00.030163)      4: \t\tCreate fd for 3'
b'(00.030170)      1: `- render 1 iovs (0x7f09c5a79000:8192...)'
b'(00.030177)      4: inet: \tRestore: family AF_INET    type SOCK_DGRAM     proto IPPROTO_UDP      port 5555 state TCP_CLOSE        src_addr 5.5.5.5'
b'(00.030182)      1: Restore via sigreturn'
b"(00.030217)      4: Error (criu/sk-inet.c:1033): inet: Can't bind inet socket (id 12): Cannot assign requested address"
b'(00.030229)      4: Error (criu/files.c:1213): Unable to open fd=4 id=0xc'
b'(00.030838)      1: Error (criu/cr-restore.c:1518): 4 exited, status=1'
b'(00.031589) mnt: Switching to new ns to clean ghosts'
b'(00.031695) Error (criu/cr-restore.c:2572): Restoring FAILED.'
------------------------ ERROR OVER ------------------------
############# Test zdtm/static/sock_ip_opts00 FAIL at CRIU restore #############
Test output: ================================

 <<< ================================
##################################### FAIL #####################################

Just dumping and restoring IP_TRANSPARENT is not enough, it should be properly integrated with the bind stage (I doubt that any app which uses it uses it without bind to non-local adress). Note that we have exactly the same problem with IP_FREEBIND (on ipv4) and to actually check IP_TRANSPARENT you need to:

--- a/test/zdtm/static/sock_ip_opts00.c
+++ b/test/zdtm/static/sock_ip_opts00.c
@@ -25,7 +25,6 @@ struct sk_opt {
 };
 
 struct sk_opt sk_opts_v4[] = {
-       { SOL_IP, IP_FREEBIND, IP_OPT_VAL },
        { SOL_IP, IP_PKTINFO, IP_OPT_VAL },
        { SOL_IP, IP_TTL, 32 },
        { SOL_IP, IP_TOS, IPTOS_TOS(IPTOS_THROUGHPUT) },
@@ -37,7 +36,6 @@ struct sk_opt sk_opts_v4[] = {
 #endif
 
 struct sk_opt sk_opts_v6[] = {
-       { SOL_IPV6, IPV6_FREEBIND, IP_OPT_VAL },
        { SOL_IPV6, IPV6_RECVPKTINFO, IP_OPT_VAL },
        { SOL_IPV6, IPV6_TRANSPARENT, IP_OPT_VAL },
 };

Snorch avatar Mar 27 '24 08:03 Snorch

This PR tries to do a good thing. But actually there it misses a bigger problem with IP_TRANSPARENT option, this option allows to bind to non-local address, so if we modify the test a bit to actually do the bind to non-local address:

Just dumping and restoring IP_TRANSPARENT is not enough, it should be properly integrated with the bind stage (I doubt that any app which uses it uses it without bind to non-local adress). Note that we have exactly the same problem with IP_FREEBIND (on ipv4) and to actually check IP_TRANSPARENT you need to:

I think the cause of this problem is that in the current open_inet_sk() of sk-inet.c, the socket options are restored at the end, and listen(), connect(), bind() are all called before setsockopt().

I think we should change this order and set all socket options after creating the socket, before listen(), connect(), bind().

What do you think? If you agree, I can create a new pull request.

juntongdeng avatar Apr 02 '24 16:04 juntongdeng

set all socket options after creating the socket, before listen(), connect(), bind(). What do you think? If you agree, I can create a new pull request.

~~Looks like a good idea.~~

Also one more possible complication: 1) set IP_TRANSPARENT 2) bind to non-local ip 3) unset IP_TRANSPARENT, this way we somehow need to guess to set this before bind and then unset it to restore properly.

So maybe we just need to extend 73a739b8d ("inet: set IP_FREEBIND before binding socket to an ipv6 address (v2)") to ipv4 to fix that.

Snorch avatar Apr 16 '24 08:04 Snorch

A friendly reminder that this PR had no activity for 30 days.

github-actions[bot] avatar May 18 '24 00:05 github-actions[bot]