Input: vmmouse - disable vmmouse before entering suspend mode
[platform/kernel/linux-starfive.git] / tools / testing / selftests / netfilter / nft_nat.sh
1 #!/bin/bash
2 #
3 # This test is for basic NAT functionality: snat, dnat, redirect, masquerade.
4 #
5
6 # Kselftest framework requirement - SKIP code is 4.
7 ksft_skip=4
8 ret=0
9 test_inet_nat=true
10
11 sfx=$(mktemp -u "XXXXXXXX")
12 ns0="ns0-$sfx"
13 ns1="ns1-$sfx"
14 ns2="ns2-$sfx"
15
16 cleanup()
17 {
18         for i in 0 1 2; do ip netns del ns$i-"$sfx";done
19 }
20
21 nft --version > /dev/null 2>&1
22 if [ $? -ne 0 ];then
23         echo "SKIP: Could not run test without nft tool"
24         exit $ksft_skip
25 fi
26
27 ip -Version > /dev/null 2>&1
28 if [ $? -ne 0 ];then
29         echo "SKIP: Could not run test without ip tool"
30         exit $ksft_skip
31 fi
32
33 ip netns add "$ns0"
34 if [ $? -ne 0 ];then
35         echo "SKIP: Could not create net namespace $ns0"
36         exit $ksft_skip
37 fi
38
39 trap cleanup EXIT
40
41 ip netns add "$ns1"
42 if [ $? -ne 0 ];then
43         echo "SKIP: Could not create net namespace $ns1"
44         exit $ksft_skip
45 fi
46
47 ip netns add "$ns2"
48 if [ $? -ne 0 ];then
49         echo "SKIP: Could not create net namespace $ns2"
50         exit $ksft_skip
51 fi
52
53 ip link add veth0 netns "$ns0" type veth peer name eth0 netns "$ns1" > /dev/null 2>&1
54 if [ $? -ne 0 ];then
55     echo "SKIP: No virtual ethernet pair device support in kernel"
56     exit $ksft_skip
57 fi
58 ip link add veth1 netns "$ns0" type veth peer name eth0 netns "$ns2"
59
60 ip -net "$ns0" link set lo up
61 ip -net "$ns0" link set veth0 up
62 ip -net "$ns0" addr add 10.0.1.1/24 dev veth0
63 ip -net "$ns0" addr add dead:1::1/64 dev veth0
64
65 ip -net "$ns0" link set veth1 up
66 ip -net "$ns0" addr add 10.0.2.1/24 dev veth1
67 ip -net "$ns0" addr add dead:2::1/64 dev veth1
68
69 for i in 1 2; do
70   ip -net ns$i-$sfx link set lo up
71   ip -net ns$i-$sfx link set eth0 up
72   ip -net ns$i-$sfx addr add 10.0.$i.99/24 dev eth0
73   ip -net ns$i-$sfx route add default via 10.0.$i.1
74   ip -net ns$i-$sfx addr add dead:$i::99/64 dev eth0
75   ip -net ns$i-$sfx route add default via dead:$i::1
76 done
77
78 bad_counter()
79 {
80         local ns=$1
81         local counter=$2
82         local expect=$3
83         local tag=$4
84
85         echo "ERROR: $counter counter in $ns has unexpected value (expected $expect) at $tag" 1>&2
86         ip netns exec $ns nft list counter inet filter $counter 1>&2
87 }
88
89 check_counters()
90 {
91         ns=$1
92         local lret=0
93
94         cnt=$(ip netns exec $ns nft list counter inet filter ns0in | grep -q "packets 1 bytes 84")
95         if [ $? -ne 0 ]; then
96                 bad_counter $ns ns0in "packets 1 bytes 84" "check_counters 1"
97                 lret=1
98         fi
99         cnt=$(ip netns exec $ns nft list counter inet filter ns0out | grep -q "packets 1 bytes 84")
100         if [ $? -ne 0 ]; then
101                 bad_counter $ns ns0out "packets 1 bytes 84" "check_counters 2"
102                 lret=1
103         fi
104
105         expect="packets 1 bytes 104"
106         cnt=$(ip netns exec $ns nft list counter inet filter ns0in6 | grep -q "$expect")
107         if [ $? -ne 0 ]; then
108                 bad_counter $ns ns0in6 "$expect" "check_counters 3"
109                 lret=1
110         fi
111         cnt=$(ip netns exec $ns nft list counter inet filter ns0out6 | grep -q "$expect")
112         if [ $? -ne 0 ]; then
113                 bad_counter $ns ns0out6 "$expect" "check_counters 4"
114                 lret=1
115         fi
116
117         return $lret
118 }
119
120 check_ns0_counters()
121 {
122         local ns=$1
123         local lret=0
124
125         cnt=$(ip netns exec "$ns0" nft list counter inet filter ns0in | grep -q "packets 0 bytes 0")
126         if [ $? -ne 0 ]; then
127                 bad_counter "$ns0" ns0in "packets 0 bytes 0" "check_ns0_counters 1"
128                 lret=1
129         fi
130
131         cnt=$(ip netns exec "$ns0" nft list counter inet filter ns0in6 | grep -q "packets 0 bytes 0")
132         if [ $? -ne 0 ]; then
133                 bad_counter "$ns0" ns0in6 "packets 0 bytes 0"
134                 lret=1
135         fi
136
137         cnt=$(ip netns exec "$ns0" nft list counter inet filter ns0out | grep -q "packets 0 bytes 0")
138         if [ $? -ne 0 ]; then
139                 bad_counter "$ns0" ns0out "packets 0 bytes 0" "check_ns0_counters 2"
140                 lret=1
141         fi
142         cnt=$(ip netns exec "$ns0" nft list counter inet filter ns0out6 | grep -q "packets 0 bytes 0")
143         if [ $? -ne 0 ]; then
144                 bad_counter "$ns0" ns0out6 "packets 0 bytes 0" "check_ns0_counters3 "
145                 lret=1
146         fi
147
148         for dir in "in" "out" ; do
149                 expect="packets 1 bytes 84"
150                 cnt=$(ip netns exec "$ns0" nft list counter inet filter ${ns}${dir} | grep -q "$expect")
151                 if [ $? -ne 0 ]; then
152                         bad_counter "$ns0" $ns$dir "$expect" "check_ns0_counters 4"
153                         lret=1
154                 fi
155
156                 expect="packets 1 bytes 104"
157                 cnt=$(ip netns exec "$ns0" nft list counter inet filter ${ns}${dir}6 | grep -q "$expect")
158                 if [ $? -ne 0 ]; then
159                         bad_counter "$ns0" $ns$dir6 "$expect" "check_ns0_counters 5"
160                         lret=1
161                 fi
162         done
163
164         return $lret
165 }
166
167 reset_counters()
168 {
169         for i in 0 1 2;do
170                 ip netns exec ns$i-$sfx nft reset counters inet > /dev/null
171         done
172 }
173
174 test_local_dnat6()
175 {
176         local family=$1
177         local lret=0
178         local IPF=""
179
180         if [ $family = "inet" ];then
181                 IPF="ip6"
182         fi
183
184 ip netns exec "$ns0" nft -f /dev/stdin <<EOF
185 table $family nat {
186         chain output {
187                 type nat hook output priority 0; policy accept;
188                 ip6 daddr dead:1::99 dnat $IPF to dead:2::99
189         }
190 }
191 EOF
192         if [ $? -ne 0 ]; then
193                 echo "SKIP: Could not add add $family dnat hook"
194                 return $ksft_skip
195         fi
196
197         # ping netns1, expect rewrite to netns2
198         ip netns exec "$ns0" ping -q -c 1 dead:1::99 > /dev/null
199         if [ $? -ne 0 ]; then
200                 lret=1
201                 echo "ERROR: ping6 failed"
202                 return $lret
203         fi
204
205         expect="packets 0 bytes 0"
206         for dir in "in6" "out6" ; do
207                 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns1${dir} | grep -q "$expect")
208                 if [ $? -ne 0 ]; then
209                         bad_counter "$ns0" ns1$dir "$expect" "test_local_dnat6 1"
210                         lret=1
211                 fi
212         done
213
214         expect="packets 1 bytes 104"
215         for dir in "in6" "out6" ; do
216                 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns2${dir} | grep -q "$expect")
217                 if [ $? -ne 0 ]; then
218                         bad_counter "$ns0" ns2$dir "$expect" "test_local_dnat6 2"
219                         lret=1
220                 fi
221         done
222
223         # expect 0 count in ns1
224         expect="packets 0 bytes 0"
225         for dir in "in6" "out6" ; do
226                 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns0${dir} | grep -q "$expect")
227                 if [ $? -ne 0 ]; then
228                         bad_counter "$ns1" ns0$dir "$expect" "test_local_dnat6 3"
229                         lret=1
230                 fi
231         done
232
233         # expect 1 packet in ns2
234         expect="packets 1 bytes 104"
235         for dir in "in6" "out6" ; do
236                 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns0${dir} | grep -q "$expect")
237                 if [ $? -ne 0 ]; then
238                         bad_counter "$ns2" ns0$dir "$expect" "test_local_dnat6 4"
239                         lret=1
240                 fi
241         done
242
243         test $lret -eq 0 && echo "PASS: ipv6 ping to $ns1 was $family NATted to $ns2"
244         ip netns exec "$ns0" nft flush chain ip6 nat output
245
246         return $lret
247 }
248
249 test_local_dnat()
250 {
251         local family=$1
252         local lret=0
253         local IPF=""
254
255         if [ $family = "inet" ];then
256                 IPF="ip"
257         fi
258
259 ip netns exec "$ns0" nft -f /dev/stdin <<EOF 2>/dev/null
260 table $family nat {
261         chain output {
262                 type nat hook output priority 0; policy accept;
263                 ip daddr 10.0.1.99 dnat $IPF to 10.0.2.99
264         }
265 }
266 EOF
267         if [ $? -ne 0 ]; then
268                 if [ $family = "inet" ];then
269                         echo "SKIP: inet nat tests"
270                         test_inet_nat=false
271                         return $ksft_skip
272                 fi
273                 echo "SKIP: Could not add add $family dnat hook"
274                 return $ksft_skip
275         fi
276
277         # ping netns1, expect rewrite to netns2
278         ip netns exec "$ns0" ping -q -c 1 10.0.1.99 > /dev/null
279         if [ $? -ne 0 ]; then
280                 lret=1
281                 echo "ERROR: ping failed"
282                 return $lret
283         fi
284
285         expect="packets 0 bytes 0"
286         for dir in "in" "out" ; do
287                 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns1${dir} | grep -q "$expect")
288                 if [ $? -ne 0 ]; then
289                         bad_counter "$ns0" ns1$dir "$expect" "test_local_dnat 1"
290                         lret=1
291                 fi
292         done
293
294         expect="packets 1 bytes 84"
295         for dir in "in" "out" ; do
296                 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns2${dir} | grep -q "$expect")
297                 if [ $? -ne 0 ]; then
298                         bad_counter "$ns0" ns2$dir "$expect" "test_local_dnat 2"
299                         lret=1
300                 fi
301         done
302
303         # expect 0 count in ns1
304         expect="packets 0 bytes 0"
305         for dir in "in" "out" ; do
306                 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns0${dir} | grep -q "$expect")
307                 if [ $? -ne 0 ]; then
308                         bad_counter "$ns1" ns0$dir "$expect" "test_local_dnat 3"
309                         lret=1
310                 fi
311         done
312
313         # expect 1 packet in ns2
314         expect="packets 1 bytes 84"
315         for dir in "in" "out" ; do
316                 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns0${dir} | grep -q "$expect")
317                 if [ $? -ne 0 ]; then
318                         bad_counter "$ns2" ns0$dir "$expect" "test_local_dnat 4"
319                         lret=1
320                 fi
321         done
322
323         test $lret -eq 0 && echo "PASS: ping to $ns1 was $family NATted to $ns2"
324
325         ip netns exec "$ns0" nft flush chain $family nat output
326
327         reset_counters
328         ip netns exec "$ns0" ping -q -c 1 10.0.1.99 > /dev/null
329         if [ $? -ne 0 ]; then
330                 lret=1
331                 echo "ERROR: ping failed"
332                 return $lret
333         fi
334
335         expect="packets 1 bytes 84"
336         for dir in "in" "out" ; do
337                 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns1${dir} | grep -q "$expect")
338                 if [ $? -ne 0 ]; then
339                         bad_counter "$ns1" ns1$dir "$expect" "test_local_dnat 5"
340                         lret=1
341                 fi
342         done
343         expect="packets 0 bytes 0"
344         for dir in "in" "out" ; do
345                 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns2${dir} | grep -q "$expect")
346                 if [ $? -ne 0 ]; then
347                         bad_counter "$ns0" ns2$dir "$expect" "test_local_dnat 6"
348                         lret=1
349                 fi
350         done
351
352         # expect 1 count in ns1
353         expect="packets 1 bytes 84"
354         for dir in "in" "out" ; do
355                 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns0${dir} | grep -q "$expect")
356                 if [ $? -ne 0 ]; then
357                         bad_counter "$ns0" ns0$dir "$expect" "test_local_dnat 7"
358                         lret=1
359                 fi
360         done
361
362         # expect 0 packet in ns2
363         expect="packets 0 bytes 0"
364         for dir in "in" "out" ; do
365                 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns0${dir} | grep -q "$expect")
366                 if [ $? -ne 0 ]; then
367                         bad_counter "$ns2" ns0$dir "$expect" "test_local_dnat 8"
368                         lret=1
369                 fi
370         done
371
372         test $lret -eq 0 && echo "PASS: ping to $ns1 OK after $family nat output chain flush"
373
374         return $lret
375 }
376
377
378 test_masquerade6()
379 {
380         local family=$1
381         local natflags=$2
382         local lret=0
383
384         ip netns exec "$ns0" sysctl net.ipv6.conf.all.forwarding=1 > /dev/null
385
386         ip netns exec "$ns2" ping -q -c 1 dead:1::99 > /dev/null # ping ns2->ns1
387         if [ $? -ne 0 ] ; then
388                 echo "ERROR: cannot ping $ns1 from $ns2 via ipv6"
389                 return 1
390                 lret=1
391         fi
392
393         expect="packets 1 bytes 104"
394         for dir in "in6" "out6" ; do
395                 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect")
396                 if [ $? -ne 0 ]; then
397                         bad_counter "$ns1" ns2$dir "$expect" "test_masquerade6 1"
398                         lret=1
399                 fi
400
401                 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns1${dir} | grep -q "$expect")
402                 if [ $? -ne 0 ]; then
403                         bad_counter "$ns2" ns1$dir "$expect" "test_masquerade6 2"
404                         lret=1
405                 fi
406         done
407
408         reset_counters
409
410 # add masquerading rule
411 ip netns exec "$ns0" nft -f /dev/stdin <<EOF
412 table $family nat {
413         chain postrouting {
414                 type nat hook postrouting priority 0; policy accept;
415                 meta oif veth0 masquerade $natflags
416         }
417 }
418 EOF
419         if [ $? -ne 0 ]; then
420                 echo "SKIP: Could not add add $family masquerade hook"
421                 return $ksft_skip
422         fi
423
424         ip netns exec "$ns2" ping -q -c 1 dead:1::99 > /dev/null # ping ns2->ns1
425         if [ $? -ne 0 ] ; then
426                 echo "ERROR: cannot ping $ns1 from $ns2 with active $family masquerade $natflags"
427                 lret=1
428         fi
429
430         # ns1 should have seen packets from ns0, due to masquerade
431         expect="packets 1 bytes 104"
432         for dir in "in6" "out6" ; do
433                 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns0${dir} | grep -q "$expect")
434                 if [ $? -ne 0 ]; then
435                         bad_counter "$ns1" ns0$dir "$expect" "test_masquerade6 3"
436                         lret=1
437                 fi
438
439                 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns1${dir} | grep -q "$expect")
440                 if [ $? -ne 0 ]; then
441                         bad_counter "$ns2" ns1$dir "$expect" "test_masquerade6 4"
442                         lret=1
443                 fi
444         done
445
446         # ns1 should not have seen packets from ns2, due to masquerade
447         expect="packets 0 bytes 0"
448         for dir in "in6" "out6" ; do
449                 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect")
450                 if [ $? -ne 0 ]; then
451                         bad_counter "$ns1" ns0$dir "$expect" "test_masquerade6 5"
452                         lret=1
453                 fi
454
455                 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns1${dir} | grep -q "$expect")
456                 if [ $? -ne 0 ]; then
457                         bad_counter "$ns0" ns1$dir "$expect" "test_masquerade6 6"
458                         lret=1
459                 fi
460         done
461
462         ip netns exec "$ns2" ping -q -c 1 dead:1::99 > /dev/null # ping ns2->ns1
463         if [ $? -ne 0 ] ; then
464                 echo "ERROR: cannot ping $ns1 from $ns2 with active ipv6 masquerade $natflags (attempt 2)"
465                 lret=1
466         fi
467
468         ip netns exec "$ns0" nft flush chain $family nat postrouting
469         if [ $? -ne 0 ]; then
470                 echo "ERROR: Could not flush $family nat postrouting" 1>&2
471                 lret=1
472         fi
473
474         test $lret -eq 0 && echo "PASS: $family IPv6 masquerade $natflags for $ns2"
475
476         return $lret
477 }
478
479 test_masquerade()
480 {
481         local family=$1
482         local natflags=$2
483         local lret=0
484
485         ip netns exec "$ns0" sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null
486         ip netns exec "$ns0" sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null
487
488         ip netns exec "$ns2" ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1
489         if [ $? -ne 0 ] ; then
490                 echo "ERROR: cannot ping $ns1 from "$ns2" $natflags"
491                 lret=1
492         fi
493
494         expect="packets 1 bytes 84"
495         for dir in "in" "out" ; do
496                 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect")
497                 if [ $? -ne 0 ]; then
498                         bad_counter "$ns1" ns2$dir "$expect" "test_masquerade 1"
499                         lret=1
500                 fi
501
502                 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns1${dir} | grep -q "$expect")
503                 if [ $? -ne 0 ]; then
504                         bad_counter "$ns2" ns1$dir "$expect" "test_masquerade 2"
505                         lret=1
506                 fi
507         done
508
509         reset_counters
510
511 # add masquerading rule
512 ip netns exec "$ns0" nft -f /dev/stdin <<EOF
513 table $family nat {
514         chain postrouting {
515                 type nat hook postrouting priority 0; policy accept;
516                 meta oif veth0 masquerade $natflags
517         }
518 }
519 EOF
520         if [ $? -ne 0 ]; then
521                 echo "SKIP: Could not add add $family masquerade hook"
522                 return $ksft_skip
523         fi
524
525         ip netns exec "$ns2" ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1
526         if [ $? -ne 0 ] ; then
527                 echo "ERROR: cannot ping $ns1 from $ns2 with active $family masquerade $natflags"
528                 lret=1
529         fi
530
531         # ns1 should have seen packets from ns0, due to masquerade
532         expect="packets 1 bytes 84"
533         for dir in "in" "out" ; do
534                 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns0${dir} | grep -q "$expect")
535                 if [ $? -ne 0 ]; then
536                         bad_counter "$ns1" ns0$dir "$expect" "test_masquerade 3"
537                         lret=1
538                 fi
539
540                 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns1${dir} | grep -q "$expect")
541                 if [ $? -ne 0 ]; then
542                         bad_counter "$ns2" ns1$dir "$expect" "test_masquerade 4"
543                         lret=1
544                 fi
545         done
546
547         # ns1 should not have seen packets from ns2, due to masquerade
548         expect="packets 0 bytes 0"
549         for dir in "in" "out" ; do
550                 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect")
551                 if [ $? -ne 0 ]; then
552                         bad_counter "$ns1" ns0$dir "$expect" "test_masquerade 5"
553                         lret=1
554                 fi
555
556                 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns1${dir} | grep -q "$expect")
557                 if [ $? -ne 0 ]; then
558                         bad_counter "$ns0" ns1$dir "$expect" "test_masquerade 6"
559                         lret=1
560                 fi
561         done
562
563         ip netns exec "$ns2" ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1
564         if [ $? -ne 0 ] ; then
565                 echo "ERROR: cannot ping $ns1 from $ns2 with active ip masquerade $natflags (attempt 2)"
566                 lret=1
567         fi
568
569         ip netns exec "$ns0" nft flush chain $family nat postrouting
570         if [ $? -ne 0 ]; then
571                 echo "ERROR: Could not flush $family nat postrouting" 1>&2
572                 lret=1
573         fi
574
575         test $lret -eq 0 && echo "PASS: $family IP masquerade $natflags for $ns2"
576
577         return $lret
578 }
579
580 test_redirect6()
581 {
582         local family=$1
583         local lret=0
584
585         ip netns exec "$ns0" sysctl net.ipv6.conf.all.forwarding=1 > /dev/null
586
587         ip netns exec "$ns2" ping -q -c 1 dead:1::99 > /dev/null # ping ns2->ns1
588         if [ $? -ne 0 ] ; then
589                 echo "ERROR: cannnot ping $ns1 from $ns2 via ipv6"
590                 lret=1
591         fi
592
593         expect="packets 1 bytes 104"
594         for dir in "in6" "out6" ; do
595                 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect")
596                 if [ $? -ne 0 ]; then
597                         bad_counter "$ns1" ns2$dir "$expect" "test_redirect6 1"
598                         lret=1
599                 fi
600
601                 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns1${dir} | grep -q "$expect")
602                 if [ $? -ne 0 ]; then
603                         bad_counter "$ns2" ns1$dir "$expect" "test_redirect6 2"
604                         lret=1
605                 fi
606         done
607
608         reset_counters
609
610 # add redirect rule
611 ip netns exec "$ns0" nft -f /dev/stdin <<EOF
612 table $family nat {
613         chain prerouting {
614                 type nat hook prerouting priority 0; policy accept;
615                 meta iif veth1 meta l4proto icmpv6 ip6 saddr dead:2::99 ip6 daddr dead:1::99 redirect
616         }
617 }
618 EOF
619         if [ $? -ne 0 ]; then
620                 echo "SKIP: Could not add add $family redirect hook"
621                 return $ksft_skip
622         fi
623
624         ip netns exec "$ns2" ping -q -c 1 dead:1::99 > /dev/null # ping ns2->ns1
625         if [ $? -ne 0 ] ; then
626                 echo "ERROR: cannot ping $ns1 from $ns2 via ipv6 with active $family redirect"
627                 lret=1
628         fi
629
630         # ns1 should have seen no packets from ns2, due to redirection
631         expect="packets 0 bytes 0"
632         for dir in "in6" "out6" ; do
633                 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect")
634                 if [ $? -ne 0 ]; then
635                         bad_counter "$ns1" ns0$dir "$expect" "test_redirect6 3"
636                         lret=1
637                 fi
638         done
639
640         # ns0 should have seen packets from ns2, due to masquerade
641         expect="packets 1 bytes 104"
642         for dir in "in6" "out6" ; do
643                 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns2${dir} | grep -q "$expect")
644                 if [ $? -ne 0 ]; then
645                         bad_counter "$ns1" ns0$dir "$expect" "test_redirect6 4"
646                         lret=1
647                 fi
648         done
649
650         ip netns exec "$ns0" nft delete table $family nat
651         if [ $? -ne 0 ]; then
652                 echo "ERROR: Could not delete $family nat table" 1>&2
653                 lret=1
654         fi
655
656         test $lret -eq 0 && echo "PASS: $family IPv6 redirection for $ns2"
657
658         return $lret
659 }
660
661 test_redirect()
662 {
663         local family=$1
664         local lret=0
665
666         ip netns exec "$ns0" sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null
667         ip netns exec "$ns0" sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null
668
669         ip netns exec "$ns2" ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1
670         if [ $? -ne 0 ] ; then
671                 echo "ERROR: cannot ping $ns1 from $ns2"
672                 lret=1
673         fi
674
675         expect="packets 1 bytes 84"
676         for dir in "in" "out" ; do
677                 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect")
678                 if [ $? -ne 0 ]; then
679                         bad_counter "$ns1" $ns2$dir "$expect" "test_redirect 1"
680                         lret=1
681                 fi
682
683                 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns1${dir} | grep -q "$expect")
684                 if [ $? -ne 0 ]; then
685                         bad_counter "$ns2" ns1$dir "$expect" "test_redirect 2"
686                         lret=1
687                 fi
688         done
689
690         reset_counters
691
692 # add redirect rule
693 ip netns exec "$ns0" nft -f /dev/stdin <<EOF
694 table $family nat {
695         chain prerouting {
696                 type nat hook prerouting priority 0; policy accept;
697                 meta iif veth1 ip protocol icmp ip saddr 10.0.2.99 ip daddr 10.0.1.99 redirect
698         }
699 }
700 EOF
701         if [ $? -ne 0 ]; then
702                 echo "SKIP: Could not add add $family redirect hook"
703                 return $ksft_skip
704         fi
705
706         ip netns exec "$ns2" ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1
707         if [ $? -ne 0 ] ; then
708                 echo "ERROR: cannot ping $ns1 from $ns2 with active $family ip redirect"
709                 lret=1
710         fi
711
712         # ns1 should have seen no packets from ns2, due to redirection
713         expect="packets 0 bytes 0"
714         for dir in "in" "out" ; do
715
716                 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect")
717                 if [ $? -ne 0 ]; then
718                         bad_counter "$ns1" ns0$dir "$expect" "test_redirect 3"
719                         lret=1
720                 fi
721         done
722
723         # ns0 should have seen packets from ns2, due to masquerade
724         expect="packets 1 bytes 84"
725         for dir in "in" "out" ; do
726                 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns2${dir} | grep -q "$expect")
727                 if [ $? -ne 0 ]; then
728                         bad_counter "$ns0" ns0$dir "$expect" "test_redirect 4"
729                         lret=1
730                 fi
731         done
732
733         ip netns exec "$ns0" nft delete table $family nat
734         if [ $? -ne 0 ]; then
735                 echo "ERROR: Could not delete $family nat table" 1>&2
736                 lret=1
737         fi
738
739         test $lret -eq 0 && echo "PASS: $family IP redirection for $ns2"
740
741         return $lret
742 }
743
744 # test port shadowing.
745 # create two listening services, one on router (ns0), one
746 # on client (ns2), which is masqueraded from ns1 point of view.
747 # ns2 sends udp packet coming from service port to ns1, on a highport.
748 # Later, if n1 uses same highport to connect to ns0:service, packet
749 # might be port-forwarded to ns2 instead.
750
751 # second argument tells if we expect the 'fake-entry' to take effect
752 # (CLIENT) or not (ROUTER).
753 test_port_shadow()
754 {
755         local test=$1
756         local expect=$2
757         local daddrc="10.0.1.99"
758         local daddrs="10.0.1.1"
759         local result=""
760         local logmsg=""
761
762         # make shadow entry, from client (ns2), going to (ns1), port 41404, sport 1405.
763         echo "fake-entry" | ip netns exec "$ns2" timeout 1 socat -u STDIN UDP:"$daddrc":41404,sourceport=1405
764
765         echo ROUTER | ip netns exec "$ns0" timeout 5 socat -u STDIN UDP4-LISTEN:1405 &
766         sc_r=$!
767
768         echo CLIENT | ip netns exec "$ns2" timeout 5 socat -u STDIN UDP4-LISTEN:1405,reuseport &
769         sc_c=$!
770
771         sleep 0.3
772
773         # ns1 tries to connect to ns0:1405.  With default settings this should connect
774         # to client, it matches the conntrack entry created above.
775
776         result=$(echo "data" | ip netns exec "$ns1" timeout 1 socat - UDP:"$daddrs":1405,sourceport=41404)
777
778         if [ "$result" = "$expect" ] ;then
779                 echo "PASS: portshadow test $test: got reply from ${expect}${logmsg}"
780         else
781                 echo "ERROR: portshadow test $test: got reply from \"$result\", not $expect as intended"
782                 ret=1
783         fi
784
785         kill $sc_r $sc_c 2>/dev/null
786
787         # flush udp entries for next test round, if any
788         ip netns exec "$ns0" conntrack -F >/dev/null 2>&1
789 }
790
791 # This prevents port shadow of router service via packet filter,
792 # packets claiming to originate from service port from internal
793 # network are dropped.
794 test_port_shadow_filter()
795 {
796         local family=$1
797
798 ip netns exec "$ns0" nft -f /dev/stdin <<EOF
799 table $family filter {
800         chain forward {
801                 type filter hook forward priority 0; policy accept;
802                 meta iif veth1 udp sport 1405 drop
803         }
804 }
805 EOF
806         test_port_shadow "port-filter" "ROUTER"
807
808         ip netns exec "$ns0" nft delete table $family filter
809 }
810
811 # This prevents port shadow of router service via notrack.
812 test_port_shadow_notrack()
813 {
814         local family=$1
815
816 ip netns exec "$ns0" nft -f /dev/stdin <<EOF
817 table $family raw {
818         chain prerouting {
819                 type filter hook prerouting priority -300; policy accept;
820                 meta iif veth0 udp dport 1405 notrack
821         }
822         chain output {
823                 type filter hook output priority -300; policy accept;
824                 meta oif veth0 udp sport 1405 notrack
825         }
826 }
827 EOF
828         test_port_shadow "port-notrack" "ROUTER"
829
830         ip netns exec "$ns0" nft delete table $family raw
831 }
832
833 # This prevents port shadow of router service via sport remap.
834 test_port_shadow_pat()
835 {
836         local family=$1
837
838 ip netns exec "$ns0" nft -f /dev/stdin <<EOF
839 table $family pat {
840         chain postrouting {
841                 type nat hook postrouting priority -1; policy accept;
842                 meta iif veth1 udp sport <= 1405 masquerade to : 1406-65535 random
843         }
844 }
845 EOF
846         test_port_shadow "pat" "ROUTER"
847
848         ip netns exec "$ns0" nft delete table $family pat
849 }
850
851 test_port_shadowing()
852 {
853         local family="ip"
854
855         conntrack -h >/dev/null 2>&1
856         if [ $? -ne 0 ];then
857                 echo "SKIP: Could not run nat port shadowing test without conntrack tool"
858                 return
859         fi
860
861         socat -h > /dev/null 2>&1
862         if [ $? -ne 0 ];then
863                 echo "SKIP: Could not run nat port shadowing test without socat tool"
864                 return
865         fi
866
867         ip netns exec "$ns0" sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null
868         ip netns exec "$ns0" sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null
869
870         ip netns exec "$ns0" nft -f /dev/stdin <<EOF
871 table $family nat {
872         chain postrouting {
873                 type nat hook postrouting priority 0; policy accept;
874                 meta oif veth0 masquerade
875         }
876 }
877 EOF
878         if [ $? -ne 0 ]; then
879                 echo "SKIP: Could not add add $family masquerade hook"
880                 return $ksft_skip
881         fi
882
883         # test default behaviour. Packet from ns1 to ns0 is not redirected
884         # due to automatic port translation.
885         test_port_shadow "default" "ROUTER"
886
887         # test packet filter based mitigation: prevent forwarding of
888         # packets claiming to come from the service port.
889         test_port_shadow_filter "$family"
890
891         # test conntrack based mitigation: connections going or coming
892         # from router:service bypass connection tracking.
893         test_port_shadow_notrack "$family"
894
895         # test nat based mitigation: fowarded packets coming from service port
896         # are masqueraded with random highport.
897         test_port_shadow_pat "$family"
898
899         ip netns exec "$ns0" nft delete table $family nat
900 }
901
902 test_stateless_nat_ip()
903 {
904         local lret=0
905
906         ip netns exec "$ns0" sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null
907         ip netns exec "$ns0" sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null
908
909         ip netns exec "$ns2" ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1
910         if [ $? -ne 0 ] ; then
911                 echo "ERROR: cannot ping $ns1 from $ns2 before loading stateless rules"
912                 return 1
913         fi
914
915 ip netns exec "$ns0" nft -f /dev/stdin <<EOF
916 table ip stateless {
917         map xlate_in {
918                 typeof meta iifname . ip saddr . ip daddr : ip daddr
919                 elements = {
920                         "veth1" . 10.0.2.99 . 10.0.1.99 : 10.0.2.2,
921                 }
922         }
923         map xlate_out {
924                 typeof meta iifname . ip saddr . ip daddr : ip daddr
925                 elements = {
926                         "veth0" . 10.0.1.99 . 10.0.2.2 : 10.0.2.99
927                 }
928         }
929
930         chain prerouting {
931                 type filter hook prerouting priority -400; policy accept;
932                 ip saddr set meta iifname . ip saddr . ip daddr map @xlate_in
933                 ip daddr set meta iifname . ip saddr . ip daddr map @xlate_out
934         }
935 }
936 EOF
937         if [ $? -ne 0 ]; then
938                 echo "SKIP: Could not add ip statless rules"
939                 return $ksft_skip
940         fi
941
942         reset_counters
943
944         ip netns exec "$ns2" ping -q -c 1 10.0.1.99 > /dev/null # ping ns2->ns1
945         if [ $? -ne 0 ] ; then
946                 echo "ERROR: cannot ping $ns1 from $ns2 with stateless rules"
947                 lret=1
948         fi
949
950         # ns1 should have seen packets from .2.2, due to stateless rewrite.
951         expect="packets 1 bytes 84"
952         cnt=$(ip netns exec "$ns1" nft list counter inet filter ns0insl | grep -q "$expect")
953         if [ $? -ne 0 ]; then
954                 bad_counter "$ns1" ns0insl "$expect" "test_stateless 1"
955                 lret=1
956         fi
957
958         for dir in "in" "out" ; do
959                 cnt=$(ip netns exec "$ns2" nft list counter inet filter ns1${dir} | grep -q "$expect")
960                 if [ $? -ne 0 ]; then
961                         bad_counter "$ns2" ns1$dir "$expect" "test_stateless 2"
962                         lret=1
963                 fi
964         done
965
966         # ns1 should not have seen packets from ns2, due to masquerade
967         expect="packets 0 bytes 0"
968         for dir in "in" "out" ; do
969                 cnt=$(ip netns exec "$ns1" nft list counter inet filter ns2${dir} | grep -q "$expect")
970                 if [ $? -ne 0 ]; then
971                         bad_counter "$ns1" ns0$dir "$expect" "test_stateless 3"
972                         lret=1
973                 fi
974
975                 cnt=$(ip netns exec "$ns0" nft list counter inet filter ns1${dir} | grep -q "$expect")
976                 if [ $? -ne 0 ]; then
977                         bad_counter "$ns0" ns1$dir "$expect" "test_stateless 4"
978                         lret=1
979                 fi
980         done
981
982         reset_counters
983
984         socat -h > /dev/null 2>&1
985         if [ $? -ne 0 ];then
986                 echo "SKIP: Could not run stateless nat frag test without socat tool"
987                 if [ $lret -eq 0 ]; then
988                         return $ksft_skip
989                 fi
990
991                 ip netns exec "$ns0" nft delete table ip stateless
992                 return $lret
993         fi
994
995         local tmpfile=$(mktemp)
996         dd if=/dev/urandom of=$tmpfile bs=4096 count=1 2>/dev/null
997
998         local outfile=$(mktemp)
999         ip netns exec "$ns1" timeout 3 socat -u UDP4-RECV:4233 OPEN:$outfile < /dev/null &
1000         sc_r=$!
1001
1002         sleep 1
1003         # re-do with large ping -> ip fragmentation
1004         ip netns exec "$ns2" timeout 3 socat - UDP4-SENDTO:"10.0.1.99:4233" < "$tmpfile" > /dev/null
1005         if [ $? -ne 0 ] ; then
1006                 echo "ERROR: failed to test udp $ns1 to $ns2 with stateless ip nat" 1>&2
1007                 lret=1
1008         fi
1009
1010         wait
1011
1012         cmp "$tmpfile" "$outfile"
1013         if [ $? -ne 0 ]; then
1014                 ls -l "$tmpfile" "$outfile"
1015                 echo "ERROR: in and output file mismatch when checking udp with stateless nat" 1>&2
1016                 lret=1
1017         fi
1018
1019         rm -f "$tmpfile" "$outfile"
1020
1021         # ns1 should have seen packets from 2.2, due to stateless rewrite.
1022         expect="packets 3 bytes 4164"
1023         cnt=$(ip netns exec "$ns1" nft list counter inet filter ns0insl | grep -q "$expect")
1024         if [ $? -ne 0 ]; then
1025                 bad_counter "$ns1" ns0insl "$expect" "test_stateless 5"
1026                 lret=1
1027         fi
1028
1029         ip netns exec "$ns0" nft delete table ip stateless
1030         if [ $? -ne 0 ]; then
1031                 echo "ERROR: Could not delete table ip stateless" 1>&2
1032                 lret=1
1033         fi
1034
1035         test $lret -eq 0 && echo "PASS: IP statless for $ns2"
1036
1037         return $lret
1038 }
1039
1040 # ip netns exec "$ns0" ping -c 1 -q 10.0.$i.99
1041 for i in 0 1 2; do
1042 ip netns exec ns$i-$sfx nft -f /dev/stdin <<EOF
1043 table inet filter {
1044         counter ns0in {}
1045         counter ns1in {}
1046         counter ns2in {}
1047
1048         counter ns0out {}
1049         counter ns1out {}
1050         counter ns2out {}
1051
1052         counter ns0in6 {}
1053         counter ns1in6 {}
1054         counter ns2in6 {}
1055
1056         counter ns0out6 {}
1057         counter ns1out6 {}
1058         counter ns2out6 {}
1059
1060         map nsincounter {
1061                 type ipv4_addr : counter
1062                 elements = { 10.0.1.1 : "ns0in",
1063                              10.0.2.1 : "ns0in",
1064                              10.0.1.99 : "ns1in",
1065                              10.0.2.99 : "ns2in" }
1066         }
1067
1068         map nsincounter6 {
1069                 type ipv6_addr : counter
1070                 elements = { dead:1::1 : "ns0in6",
1071                              dead:2::1 : "ns0in6",
1072                              dead:1::99 : "ns1in6",
1073                              dead:2::99 : "ns2in6" }
1074         }
1075
1076         map nsoutcounter {
1077                 type ipv4_addr : counter
1078                 elements = { 10.0.1.1 : "ns0out",
1079                              10.0.2.1 : "ns0out",
1080                              10.0.1.99: "ns1out",
1081                              10.0.2.99: "ns2out" }
1082         }
1083
1084         map nsoutcounter6 {
1085                 type ipv6_addr : counter
1086                 elements = { dead:1::1 : "ns0out6",
1087                              dead:2::1 : "ns0out6",
1088                              dead:1::99 : "ns1out6",
1089                              dead:2::99 : "ns2out6" }
1090         }
1091
1092         chain input {
1093                 type filter hook input priority 0; policy accept;
1094                 counter name ip saddr map @nsincounter
1095                 icmpv6 type { "echo-request", "echo-reply" } counter name ip6 saddr map @nsincounter6
1096         }
1097         chain output {
1098                 type filter hook output priority 0; policy accept;
1099                 counter name ip daddr map @nsoutcounter
1100                 icmpv6 type { "echo-request", "echo-reply" } counter name ip6 daddr map @nsoutcounter6
1101         }
1102 }
1103 EOF
1104 done
1105
1106 # special case for stateless nat check, counter needs to
1107 # be done before (input) ip defragmentation
1108 ip netns exec ns1-$sfx nft -f /dev/stdin <<EOF
1109 table inet filter {
1110         counter ns0insl {}
1111
1112         chain pre {
1113                 type filter hook prerouting priority -400; policy accept;
1114                 ip saddr 10.0.2.2 counter name "ns0insl"
1115         }
1116 }
1117 EOF
1118
1119 sleep 3
1120 # test basic connectivity
1121 for i in 1 2; do
1122   ip netns exec "$ns0" ping -c 1 -q 10.0.$i.99 > /dev/null
1123   if [ $? -ne 0 ];then
1124         echo "ERROR: Could not reach other namespace(s)" 1>&2
1125         ret=1
1126   fi
1127
1128   ip netns exec "$ns0" ping -c 1 -q dead:$i::99 > /dev/null
1129   if [ $? -ne 0 ];then
1130         echo "ERROR: Could not reach other namespace(s) via ipv6" 1>&2
1131         ret=1
1132   fi
1133   check_counters ns$i-$sfx
1134   if [ $? -ne 0 ]; then
1135         ret=1
1136   fi
1137
1138   check_ns0_counters ns$i
1139   if [ $? -ne 0 ]; then
1140         ret=1
1141   fi
1142   reset_counters
1143 done
1144
1145 if [ $ret -eq 0 ];then
1146         echo "PASS: netns routing/connectivity: $ns0 can reach $ns1 and $ns2"
1147 fi
1148
1149 reset_counters
1150 test_local_dnat ip
1151 test_local_dnat6 ip6
1152 reset_counters
1153 $test_inet_nat && test_local_dnat inet
1154 $test_inet_nat && test_local_dnat6 inet
1155
1156 for flags in "" "fully-random"; do
1157 reset_counters
1158 test_masquerade ip $flags
1159 test_masquerade6 ip6 $flags
1160 reset_counters
1161 $test_inet_nat && test_masquerade inet $flags
1162 $test_inet_nat && test_masquerade6 inet $flags
1163 done
1164
1165 reset_counters
1166 test_redirect ip
1167 test_redirect6 ip6
1168 reset_counters
1169 $test_inet_nat && test_redirect inet
1170 $test_inet_nat && test_redirect6 inet
1171
1172 test_port_shadowing
1173 test_stateless_nat_ip
1174
1175 if [ $ret -ne 0 ];then
1176         echo -n "FAIL: "
1177         nft --version
1178 fi
1179
1180 exit $ret