All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] tests: make IPv6 subtests optional on IPv4-only systems
@ 2026-07-10  8:25 Jan Onderka
  2026-07-10 17:55 ` Stephen Smalley
  2026-10-01 15:36 ` Brian Grech
  0 siblings, 2 replies; 7+ messages in thread
From: Jan Onderka @ 2026-07-10  8:25 UTC (permalink / raw)
  To: selinux; +Cc: jonderka

Skip or adapt IPv6-dependent subtests when the running system does not
have usable IPv6 on loopback.

Problem
-------
Several subtests assume IPv6 is available: they bind or connect to ::1,
load ip6tables/nftables IPv6 rules, or create AF_INET6/SCTP IPv6 sockets.
On IPv4-only systems (for example RHIVOS kernels built without usable
IPv6, or hosts with net.ipv6.conf.*.disable_ipv6=1), these subtests
hang or fail in ways that block the entire make test run.

Change
------
- Add tests/has_ipv6 helper that checks /proc/net/if_inet6 and the
  net.ipv6.conf.all/lo.disable_ipv6 sysctls.
- Wrap IPv6-only cases in inet_socket, extended_socket_class, and sctp
  Perl tests behind $test_ipv6 / ipv6_enabled() checks and reduce test
  counts accordingly.
- Make inet_socket/server.c fall back to AF_INET when IPv6 is absent.
- Split IPv6 firewall/load script rules into nftables-ipv6.load and only
  invoke ip6tables/nftables IPv6 setup from load scripts when has_ipv6
  succeeds.
- Add ipv6_enabled() to sctp_common for C helpers and SCTP bindx paths.

Justification
-------------
IPv6 is optional in many deployment targets. The testsuite should detect
runtime IPv6 usability and skip only the affected subtests instead of
assuming ::1 and ip6tables always work. This mirrors how other optional
features are handled in the tree and keeps the fix self-contained in
selinux-testsuite.

Testing
-------
Verified on RHIVOS (no /proc/net/if_inet6):

  - inet_socket/tcp and inet_socket/udp complete successfully
  - extended_socket_class IPv6 cases are skipped
  - make test progresses past former IPv6 hang points

Verified on a host with IPv6 enabled:

  - IPv6 subtests still run and pass

Signed-off-by: Jan Onderka <jonderka@redhat.com>
---
 tests/extended_socket_class/test      | 17 ++++++++++
 tests/has_ipv6                        | 19 +++++++++++
 tests/inet_socket/ipsec-load          |  4 +++
 tests/inet_socket/iptables-flush      |  9 +++--
 tests/inet_socket/iptables-load       |  5 +++
 tests/inet_socket/nftables-flush      |  1 -
 tests/inet_socket/nftables-ipv6-flush |  1 +
 tests/inet_socket/nftables-ipv6.load  | 35 +++++++++++++++++++
 tests/inet_socket/nftables-load       | 35 ++-----------------
 tests/inet_socket/server.c            | 19 ++++++++++-
 tests/inet_socket/test                | 49 +++++++++++++++++++++------
 tests/sctp/fb-deny-label-flush        |  5 +++
 tests/sctp/fb-deny-label-load         |  7 ++++
 tests/sctp/fb-label-flush             |  5 +++
 tests/sctp/fb-label-load              |  7 ++++
 tests/sctp/iptables-flush             |  5 +++
 tests/sctp/iptables-load              |  9 +++++
 tests/sctp/nftables-flush             |  1 -
 tests/sctp/nftables-ipv6-flush        |  1 +
 tests/sctp/nftables-ipv6.load         | 33 ++++++++++++++++++
 tests/sctp/nftables-load              | 33 ++----------------
 tests/sctp/sctp_bindx.c               | 46 +++++++++++++++++--------
 tests/sctp/sctp_common.c              | 15 ++++++++
 tests/sctp/sctp_common.h              |  2 ++
 tests/sctp/sctp_peeloff_server.c      |  2 +-
 tests/sctp/sctp_server.c              |  2 +-
 tests/sctp/test                       | 42 +++++++++++++++++++++++
 27 files changed, 312 insertions(+), 97 deletions(-)
 create mode 100755 tests/has_ipv6
 create mode 100644 tests/inet_socket/nftables-ipv6-flush
 create mode 100644 tests/inet_socket/nftables-ipv6.load
 create mode 100644 tests/sctp/nftables-ipv6-flush
 create mode 100644 tests/sctp/nftables-ipv6.load

diff --git a/tests/extended_socket_class/test b/tests/extended_socket_class/test
index 1e6299f..9a6ea16 100755
--- a/tests/extended_socket_class/test
+++ b/tests/extended_socket_class/test
@@ -26,6 +26,17 @@ BEGIN {
         $test_smc = 1;
     }
 
+    # Determine if IPv6 is enabled on loopback.
+    my $testdir = $0;
+    $testdir =~ s|(.*)/[^/]*|$1|;
+    $test_ipv6 = system("$testdir/../has_ipv6") == 0 ? 1 : 0;
+    if ( !$test_ipv6 ) {
+        $test_count -= 2;
+        if ($test_sctp) {
+            $test_count -= 4;
+        }
+    }
+
     plan tests => $test_count;
 }
 
@@ -46,6 +57,8 @@ $result = system(
 );
 ok($result);
 
+if ($test_ipv6) {
+
 # Verify that test_icmp_socket_t can create an ICMPv6 socket.
 $result = system(
 "runcon -t test_icmp_socket_t -- $basedir/sockcreate inet6 dgram icmpv6 2>&1"
@@ -57,6 +70,7 @@ $result = system(
 "runcon -t test_no_icmp_socket_t -- $basedir/sockcreate inet6 dgram icmpv6 2>&1"
 );
 ok($result);
+}
 
 # Restore to the kernel defaults - no one allowed to create ICMP sockets.
 system("echo 1 0 > /proc/sys/net/ipv4/ping_group_range");
@@ -87,6 +101,8 @@ if ($test_sctp) {
     );
     ok($result);
 
+    if ($test_ipv6) {
+
     # Verify that test_sctp_socket_t can create an IPv6 stream SCTP socket.
     $result = system(
 "runcon -t test_sctp_socket_t -- $basedir/sockcreate inet6 stream sctp 2>&1"
@@ -110,6 +126,7 @@ if ($test_sctp) {
 "runcon -t test_no_sctp_socket_t -- $basedir/sockcreate inet6 seqpacket sctp 2>&1"
     );
     ok($result);
+    }
 }
 
 if ($test_bluetooth) {
diff --git a/tests/has_ipv6 b/tests/has_ipv6
new file mode 100755
index 0000000..21f12e7
--- /dev/null
+++ b/tests/has_ipv6
@@ -0,0 +1,19 @@
+#!/bin/sh
+#
+# Return 0 if IPv6 is enabled and usable on loopback, 1 otherwise.
+#
+# IPv6 may be absent (ipv6.disable=1 on the kernel command line), disabled
+# globally (net.ipv6.conf.all.disable_ipv6=1), or disabled on loopback
+# (net.ipv6.conf.lo.disable_ipv6=1).  Following the LTP tst_net.sh approach,
+# check /proc/net/if_inet6 and the disable_ipv6 sysctls rather than module
+# parameters that may be blocked by SELinux policy.
+
+[ -f /proc/net/if_inet6 ] || exit 1
+
+disabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6 2>/dev/null) || exit 1
+[ "$disabled" = 1 ] && exit 1
+
+disabled=$(sysctl -n net.ipv6.conf.lo.disable_ipv6 2>/dev/null) || exit 1
+[ "$disabled" = 1 ] && exit 1
+
+exit 0
diff --git a/tests/inet_socket/ipsec-load b/tests/inet_socket/ipsec-load
index 21e2dfe..e286de3 100644
--- a/tests/inet_socket/ipsec-load
+++ b/tests/inet_socket/ipsec-load
@@ -10,8 +10,12 @@ ip xfrm state add src 127.0.0.1 dst 127.0.0.1 proto ah spi 0x250 ctx $badclientc
 ip xfrm policy add src 127.0.0.1 dst 127.0.0.1 proto tcp dir out ctx "system_u:object_r:test_spd_t:s0" tmpl proto ah mode transport level required
 ip xfrm policy add src 127.0.0.1 dst 127.0.0.1 proto udp dir out ctx "system_u:object_r:test_spd_t:s0" tmpl proto ah mode transport level required
 
+SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
+if "$HAS_IPV6"; then
 # IPv6 loopback
 ip xfrm state add src ::1 dst ::1 proto ah spi 0x200 ctx $goodclientcon auth sha1 0123456789012345
 ip xfrm state add src ::1 dst ::1 proto ah spi 0x250 ctx $badclientcon auth sha1 0123456789012345
 ip xfrm policy add src ::1 dst ::1 proto tcp dir out ctx "system_u:object_r:test_spd_t:s0" tmpl proto ah mode transport level required
 ip xfrm policy add src ::1 dst ::1 proto udp dir out ctx "system_u:object_r:test_spd_t:s0" tmpl proto ah mode transport level required
+fi
diff --git a/tests/inet_socket/iptables-flush b/tests/inet_socket/iptables-flush
index c168d89..198bb85 100644
--- a/tests/inet_socket/iptables-flush
+++ b/tests/inet_socket/iptables-flush
@@ -1,6 +1,11 @@
 #!/bin/sh
+SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
+
 # Flush the security table.
 iptables -t security -F
-iptables -t security -X NEWCONN
+iptables -t security -X NEWCONN 2>/dev/null
+if "$HAS_IPV6"; then
 ip6tables -t security -F
-ip6tables -t security -X NEWCONN
+ip6tables -t security -X NEWCONN 2>/dev/null
+fi
diff --git a/tests/inet_socket/iptables-load b/tests/inet_socket/iptables-load
index 5be94f4..d097ed7 100644
--- a/tests/inet_socket/iptables-load
+++ b/tests/inet_socket/iptables-load
@@ -8,6 +8,9 @@
 # - Specified the interface since the tests are only performed over loopback.
 # - Set the port number and context to the values used by the test script and policy.
 
+SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
+
 # Flush the security table.
 iptables -t security -F
 
@@ -28,6 +31,7 @@ iptables -t security -A OUTPUT -m state --state ESTABLISHED,RELATED -j CONNSECMA
 iptables -t security -A INPUT -i lo -p udp --dport 65535 -j SECMARK --selctx system_u:object_r:test_server_packet_t:s0
 iptables -t security -A OUTPUT -o lo -p udp --sport 65535 -j SECMARK --selctx system_u:object_r:test_server_packet_t:s0
 
+if "$HAS_IPV6"; then
 ##### IPv6 entries
 ip6tables -t security -F
 
@@ -47,3 +51,4 @@ ip6tables -t security -A OUTPUT -m state --state ESTABLISHED,RELATED -j CONNSECM
 # Label UDP packets similarly.
 ip6tables -t security -A INPUT -i lo -p udp --dport 65535 -j SECMARK --selctx system_u:object_r:test_server_packet_t:s0
 ip6tables -t security -A OUTPUT -o lo -p udp --sport 65535 -j SECMARK --selctx system_u:object_r:test_server_packet_t:s0
+fi
diff --git a/tests/inet_socket/nftables-flush b/tests/inet_socket/nftables-flush
index 7d62b8d..d0fee0c 100644
--- a/tests/inet_socket/nftables-flush
+++ b/tests/inet_socket/nftables-flush
@@ -1,2 +1 @@
 delete table ip security
-delete table ip6 security
diff --git a/tests/inet_socket/nftables-ipv6-flush b/tests/inet_socket/nftables-ipv6-flush
new file mode 100644
index 0000000..0c9b69a
--- /dev/null
+++ b/tests/inet_socket/nftables-ipv6-flush
@@ -0,0 +1 @@
+delete table ip6 security
diff --git a/tests/inet_socket/nftables-ipv6.load b/tests/inet_socket/nftables-ipv6.load
new file mode 100644
index 0000000..6116343
--- /dev/null
+++ b/tests/inet_socket/nftables-ipv6.load
@@ -0,0 +1,35 @@
+# IPv6 secmark rules for inet_socket tests (loaded only when IPv6 is enabled).
+
+add table ip6 security
+
+table ip6 security {
+
+	secmark inet_server {
+		"system_u:object_r:test_server_packet_t:s0"
+	}
+
+	map secmapping_in_out {
+		type inet_service : secmark
+		elements = { 65535 : "inet_server" }
+	}
+
+	chain input {
+		type filter hook input priority 0;
+
+		ct state new meta secmark set tcp dport map @secmapping_in_out
+		ct state new meta secmark set udp dport map @secmapping_in_out
+		ct state new ct secmark set meta secmark
+
+		ct state established,related meta secmark set ct secmark
+	}
+
+	chain output {
+		type filter hook output priority 0;
+
+		ct state new meta secmark set tcp dport map @secmapping_in_out
+		ct state established meta secmark set udp dport map @secmapping_in_out
+		ct state new ct secmark set meta secmark
+
+		ct state established,related meta secmark set ct secmark
+	}
+}
diff --git a/tests/inet_socket/nftables-load b/tests/inet_socket/nftables-load
index 11ec382..14d6efe 100644
--- a/tests/inet_socket/nftables-load
+++ b/tests/inet_socket/nftables-load
@@ -1,7 +1,8 @@
 # Based on NFT project example. Requires kernel >= 4.20 and nft >= 0.9.3
+#
+# IPv6 rules are in nftables-ipv6.load and loaded only when IPv6 is enabled.
 
 add table ip security
-add table ip6 security
 
 table ip security {
 
@@ -40,35 +41,3 @@ table ip security {
 		ct state established,related meta secmark set ct secmark
 	}
 }
-
-table ip6 security {
-
-	secmark inet_server {
-		"system_u:object_r:test_server_packet_t:s0"
-	}
-
-	map secmapping_in_out {
-		type inet_service : secmark
-		elements = { 65535 : "inet_server" }
-	}
-
-	chain input {
-		type filter hook input priority 0;
-
-		ct state new meta secmark set tcp dport map @secmapping_in_out
-		ct state new meta secmark set udp dport map @secmapping_in_out
-		ct state new ct secmark set meta secmark
-
-		ct state established,related meta secmark set ct secmark
-	}
-
-	chain output {
-		type filter hook output priority 0;
-
-		ct state new meta secmark set tcp dport map @secmapping_in_out
-		ct state established meta secmark set udp dport map @secmapping_in_out
-		ct state new ct secmark set meta secmark
-
-		ct state established,related meta secmark set ct secmark
-	}
-}
diff --git a/tests/inet_socket/server.c b/tests/inet_socket/server.c
index 63b6849..c4e4432 100644
--- a/tests/inet_socket/server.c
+++ b/tests/inet_socket/server.c
@@ -10,6 +10,8 @@
 #include <stdio.h>
 #include <stdbool.h>
 
+#include <unistd.h>
+
 #ifndef SO_PEERSEC
 #define SO_PEERSEC 31
 #endif
@@ -36,6 +38,21 @@ void usage(char *progname)
 	exit(1);
 }
 
+static bool ipv6_enabled(void)
+{
+	int fd;
+
+	if (access("/proc/net/if_inet6", F_OK) != 0)
+		return false;
+
+	fd = socket(AF_INET6, SOCK_DGRAM, 0);
+	if (fd < 0)
+		return false;
+
+	close(fd);
+	return true;
+}
+
 int main(int argc, char **argv)
 {
 	int sock, result, opt, sockprotocol, on = 1;
@@ -64,7 +81,7 @@ int main(int argc, char **argv)
 
 	memset(&hints, 0, sizeof(struct addrinfo));
 	hints.ai_flags = AI_PASSIVE;
-	hints.ai_family = AF_INET6;
+	hints.ai_family = ipv6_enabled() ? AF_INET6 : AF_INET;
 
 	if (!strcmp(argv[optind], "tcp")) {
 		hints.ai_socktype = SOCK_STREAM;
diff --git a/tests/inet_socket/test b/tests/inet_socket/test
index 4cc3852..01acf8a 100755
--- a/tests/inet_socket/test
+++ b/tests/inet_socket/test
@@ -63,6 +63,25 @@ BEGIN {
         $test_nft = 1;
     }
 
+    # Determine if IPv6 is enabled on loopback.
+    $test_ipv6 = system("$basedir/../has_ipv6") == 0 ? 1 : 0;
+
+    if ( !$test_ipv6 ) {
+        if ($test_ipsec) {
+            $test_count -= 2;
+        }
+        if ($test_calipso) {
+            $test_count -= $is_stream ? 3 : 2;
+            $test_calipso = 0;
+        }
+        if ($test_iptables) {
+            $test_count -= 2;
+        }
+        if ($test_nft) {
+            $test_count -= 2;
+        }
+    }
+
     plan tests => $test_count;
 }
 
@@ -329,7 +348,7 @@ if ($test_ipsec) {
 "runcon -t test_inet_bad_client_t -- $basedir/client $proto 127.0.0.1 65535 2>&1";
     ok( $result >> 8 eq $fail_value2 );
 
-    if ($is_stream) {
+    if ($is_stream && $test_ipv6) {
 
         # Verify that authorized client can communicate with the server.
         $result =
@@ -338,15 +357,18 @@ if ($test_ipsec) {
         ok( $result eq 0 );
     }
 
-    # Verify that unauthorized client cannot communicate with the server.
-    $result = system
+    if ($test_ipv6) {
+
+        # Verify that unauthorized client cannot communicate with the server.
+        $result = system
 "runcon -t test_inet_bad_client_t -- $basedir/client $proto ::1 65535 2>&1";
-    ok( $result >> 8 eq $fail_value2 );
+        ok( $result >> 8 eq $fail_value2 );
+    }
 
     # Kill the server.
     server_end($pid);
 
-    if ( not $is_stream ) {
+    if ( not $is_stream && $test_ipv6 ) {
 
    # Start the server for IPSEC test using IPv6 but do not request peer context.
         $pid = server_start( "-t test_inet_server_t", "-n $proto 65535" );
@@ -382,15 +404,18 @@ sub test_tables {
 "runcon -t test_inet_bad_client_t -- $basedir/client -e nopeer $proto 127.0.0.1 65535 2>&1";
     ok( $result >> 8 eq $fail_value2 );
 
-    # Verify that authorized client can communicate with the server.
-    $result = system
+    if ($test_ipv6) {
+
+        # Verify that authorized client can communicate with the server.
+        $result = system
 "runcon -t test_inet_client_t -- $basedir/client -e nopeer $proto ::1 65535";
-    ok( $result eq 0 );
+        ok( $result eq 0 );
 
-    # Verify that unauthorized client cannot communicate with the server.
-    $result = system
+        # Verify that unauthorized client cannot communicate with the server.
+        $result = system
 "runcon -t test_inet_bad_client_t -- $basedir/client -e nopeer $proto ::1 65535 2>&1";
-    ok( $result >> 8 eq $fail_value2 );
+        ok( $result >> 8 eq $fail_value2 );
+    }
 
     # Kill the server.
     server_end($pid);
@@ -406,7 +431,9 @@ if ($test_iptables) {
 if ($test_nft) {
     print "Testing nftables (IPv4/IPv6).\n";
     system "nft -f $basedir/nftables-load";
+    system "nft -f $basedir/nftables-ipv6.load" if $test_ipv6;
     test_tables();
+    system "nft -f $basedir/nftables-ipv6-flush" if $test_ipv6;
     system "nft -f $basedir/nftables-flush";
 }
 
diff --git a/tests/sctp/fb-deny-label-flush b/tests/sctp/fb-deny-label-flush
index 059e0b7..41e76e6 100644
--- a/tests/sctp/fb-deny-label-flush
+++ b/tests/sctp/fb-deny-label-flush
@@ -1,6 +1,11 @@
 #!/bin/sh
 
+SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
+
 netlabelctl map del default
 netlabelctl map add default protocol:unlbl
 netlabelctl unlbl del interface:lo address:127.0.0.0/8 label:system_u:object_r:netlabel_sctp_peer_t:s0
+if "$HAS_IPV6"; then
 netlabelctl unlbl del interface:lo address:::1/128 label:system_u:object_r:deny_assoc_sctp_peer_t:s0
+fi
diff --git a/tests/sctp/fb-deny-label-load b/tests/sctp/fb-deny-label-load
index 7c0bd87..647399b 100644
--- a/tests/sctp/fb-deny-label-load
+++ b/tests/sctp/fb-deny-label-load
@@ -1,7 +1,14 @@
 #!/bin/sh
 
+SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
+
 netlabelctl map del default
 netlabelctl map add default address:0.0.0.0/0 protocol:unlbl
+if "$HAS_IPV6"; then
 netlabelctl map add default address:::/0 protocol:unlbl
+fi
 netlabelctl unlbl add interface:lo address:127.0.0.0/8 label:system_u:object_r:netlabel_sctp_peer_t:s0
+if "$HAS_IPV6"; then
 netlabelctl unlbl add interface:lo address:::1/128 label:system_u:object_r:deny_assoc_sctp_peer_t:s0
+fi
diff --git a/tests/sctp/fb-label-flush b/tests/sctp/fb-label-flush
index 13573a8..c1ceeb5 100644
--- a/tests/sctp/fb-label-flush
+++ b/tests/sctp/fb-label-flush
@@ -1,6 +1,11 @@
 #!/bin/sh
 
+SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
+
 netlabelctl map del default
 netlabelctl map add default protocol:unlbl
 netlabelctl unlbl del interface:lo address:127.0.0.0/8 label:system_u:object_r:netlabel_sctp_peer_t:s0
+if "$HAS_IPV6"; then
 netlabelctl unlbl del interface:lo address:::1/128 label:system_u:object_r:netlabel_sctp_peer_t:s0
+fi
diff --git a/tests/sctp/fb-label-load b/tests/sctp/fb-label-load
index a501515..065ec34 100644
--- a/tests/sctp/fb-label-load
+++ b/tests/sctp/fb-label-load
@@ -1,8 +1,15 @@
 #!/bin/sh
 
+SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
+
 netlabelctl map del default
 netlabelctl map add default address:0.0.0.0/0 protocol:unlbl
+if "$HAS_IPV6"; then
 netlabelctl map add default address:::/0 protocol:unlbl
+fi
 netlabelctl unlbl add interface:lo address:127.0.0.0/8 label:system_u:object_r:netlabel_sctp_peer_t:s0
+if "$HAS_IPV6"; then
 netlabelctl unlbl add interface:lo address:::1/128 label:system_u:object_r:netlabel_sctp_peer_t:s0
+fi
 #netlabelctl -p unlbl list
diff --git a/tests/sctp/iptables-flush b/tests/sctp/iptables-flush
index e74271a..112ae79 100644
--- a/tests/sctp/iptables-flush
+++ b/tests/sctp/iptables-flush
@@ -1,4 +1,9 @@
 #!/bin/sh
 # Flush the security table after IPv4 and IPv6 tests.
+SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
+
 iptables -t security -F
+if "$HAS_IPV6"; then
 ip6tables -t security -F
+fi
diff --git a/tests/sctp/iptables-load b/tests/sctp/iptables-load
index 9dac576..1a91e19 100644
--- a/tests/sctp/iptables-load
+++ b/tests/sctp/iptables-load
@@ -1,9 +1,14 @@
 #!/bin/sh
 ############################ SECMARK IPTABLE ENTRIES ########################
 #
+SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
+
 # Flush the security table first:
 iptables -t security -F
+if "$HAS_IPV6"; then
 ip6tables -t security -F
+fi
 
 #-------------- INPUT IP Stream --------------------#
 # These rules will replace the above context if sctp ports 1024:1035 are found in the packets:
@@ -11,9 +16,11 @@ iptables -t security -A INPUT -i lo -p sctp -m multiport --port 1024:1035 -j SEC
 
 iptables -t security -A INPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --save
 
+if "$HAS_IPV6"; then
 ip6tables -t security -A INPUT -i lo -p sctp -m multiport --port 1024:1035 -j SECMARK --selctx system_u:object_r:test_sctp_server_packet_t:s0
 
 ip6tables -t security -A INPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --save
+fi
 
 #-------------- OUTPUT IP Stream --------------------#
 # These rules will replace the above context if sctp ports 1024:1035 are found in the packets:
@@ -21,7 +28,9 @@ iptables -t security -A OUTPUT -o lo -p sctp -m multiport --port 1024:1035 -j SE
 
 iptables -t security -A OUTPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --save
 
+if "$HAS_IPV6"; then
 ip6tables -t security -A OUTPUT -o lo -p sctp -m multiport --port 1024:1035 -j SECMARK --selctx system_u:object_r:test_sctp_server_packet_t:s0
 
 ip6tables -t security -A OUTPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --save
+fi
 
diff --git a/tests/sctp/nftables-flush b/tests/sctp/nftables-flush
index 7d62b8d..d0fee0c 100644
--- a/tests/sctp/nftables-flush
+++ b/tests/sctp/nftables-flush
@@ -1,2 +1 @@
 delete table ip security
-delete table ip6 security
diff --git a/tests/sctp/nftables-ipv6-flush b/tests/sctp/nftables-ipv6-flush
new file mode 100644
index 0000000..0c9b69a
--- /dev/null
+++ b/tests/sctp/nftables-ipv6-flush
@@ -0,0 +1 @@
+delete table ip6 security
diff --git a/tests/sctp/nftables-ipv6.load b/tests/sctp/nftables-ipv6.load
new file mode 100644
index 0000000..1268140
--- /dev/null
+++ b/tests/sctp/nftables-ipv6.load
@@ -0,0 +1,33 @@
+# IPv6 secmark rules for SCTP tests (loaded only when IPv6 is enabled).
+
+add table ip6 security
+
+table ip6 security {
+
+	secmark sctp_server {
+		"system_u:object_r:test_sctp_server_packet_t:s0"
+	}
+
+	map secmapping_in_out {
+		type inet_service : secmark
+		elements = { 1035 : "sctp_server" }
+	}
+
+	chain input {
+		type filter hook input priority 0;
+
+		ct state new meta secmark set sctp dport map @secmapping_in_out
+		ct state new ct secmark set meta secmark
+
+		ct state established,related meta secmark set ct secmark
+	}
+
+	chain output {
+		type filter hook output priority 0;
+
+		ct state new meta secmark set sctp dport map @secmapping_in_out
+		ct state new ct secmark set meta secmark
+
+		ct state established,related meta secmark set ct secmark
+	}
+}
diff --git a/tests/sctp/nftables-load b/tests/sctp/nftables-load
index 2cac3bb..56803b6 100644
--- a/tests/sctp/nftables-load
+++ b/tests/sctp/nftables-load
@@ -1,7 +1,8 @@
 # Based on NFT project example. Requires kernel >= 4.20 and nft >= 0.9.3
+#
+# IPv6 rules are in nftables-ipv6.load and loaded only when IPv6 is enabled.
 
 add table ip security
-add table ip6 security
 
 table ip security {
 
@@ -36,33 +37,3 @@ table ip security {
 		ct state established,related meta secmark set ct secmark
 	}
 }
-
-table ip6 security {
-
-	secmark sctp_server {
-		"system_u:object_r:test_sctp_server_packet_t:s0"
-	}
-
-	map secmapping_in_out {
-		type inet_service : secmark
-		elements = { 1035 : "sctp_server" }
-	}
-
-	chain input {
-		type filter hook input priority 0;
-
-		ct state new meta secmark set sctp dport map @secmapping_in_out
-		ct state new ct secmark set meta secmark
-
-		ct state established,related meta secmark set ct secmark
-	}
-
-	chain output {
-		type filter hook output priority 0;
-
-		ct state new meta secmark set sctp dport map @secmapping_in_out
-		ct state new ct secmark set meta secmark
-
-		ct state established,related meta secmark set ct secmark
-	}
-}
diff --git a/tests/sctp/sctp_bindx.c b/tests/sctp/sctp_bindx.c
index 74bf985..2240404 100644
--- a/tests/sctp/sctp_bindx.c
+++ b/tests/sctp/sctp_bindx.c
@@ -1,4 +1,5 @@
 #include "sctp_common.h"
+#include <errno.h>
 
 static void usage(char *progname)
 {
@@ -22,6 +23,7 @@ int main(int argc, char **argv)
 	unsigned short port;
 	bool rem = false;
 	bool verbose = false;
+	bool ipv6_bound = false;
 	char *context;
 
 	while ((opt = getopt(argc, argv, "rv")) != -1) {
@@ -58,7 +60,7 @@ int main(int argc, char **argv)
 		free(context);
 	}
 
-	sock = socket(PF_INET6, type, IPPROTO_SCTP);
+	sock = socket(ipv6_enabled() ? PF_INET6 : PF_INET, type, IPPROTO_SCTP);
 	if (sock < 0) {
 		perror("socket");
 		exit(1);
@@ -88,27 +90,41 @@ int main(int argc, char **argv)
 	ipv6.sin6_port = htons(port);
 	ipv6.sin6_addr = in6addr_loopback;
 
+	if (ipv6_enabled()) {
 	result = sctp_bindx(sock, (struct sockaddr *)&ipv6, 1,
 			    SCTP_BINDX_ADD_ADDR);
 	if (result < 0) {
-		perror("sctp_bindx ADD - ipv6");
-		close(sock);
-		exit(3);
+		if (verbose)
+			printf("sctp_bindx ADD - ipv6 not available\n");
+	} else {
+		ipv6_bound = true;
+		if (verbose)
+			printf("sctp_bindx ADD - ipv6\n");
+	}
 	}
-
-	if (verbose)
-		printf("sctp_bindx ADD - ipv6\n");
 
 	if (rem) {
-		result = sctp_bindx(sock, (struct sockaddr *)&ipv6, 1,
-				    SCTP_BINDX_REM_ADDR);
-		if (result < 0) {
-			perror("sctp_bindx - REM");
-			close(sock);
-			exit(4);
+		if (ipv6_bound) {
+			result = sctp_bindx(sock, (struct sockaddr *)&ipv6, 1,
+					    SCTP_BINDX_REM_ADDR);
+			if (result < 0) {
+				perror("sctp_bindx - REM");
+				close(sock);
+				exit(4);
+			}
+			if (verbose)
+				printf("sctp_bindx REM - ipv6\n");
+		} else {
+			result = sctp_bindx(sock, (struct sockaddr *)&ipv4, 1,
+					    SCTP_BINDX_REM_ADDR);
+			if (result < 0) {
+				perror("sctp_bindx - REM");
+				close(sock);
+				exit(4);
+			}
+			if (verbose)
+				printf("sctp_bindx REM - ipv4\n");
 		}
-		if (verbose)
-			printf("sctp_bindx REM - ipv6\n");
 	}
 
 	close(sock);
diff --git a/tests/sctp/sctp_common.c b/tests/sctp/sctp_common.c
index d10225c..3adce02 100644
--- a/tests/sctp/sctp_common.c
+++ b/tests/sctp/sctp_common.c
@@ -344,3 +344,18 @@ int handle_event(void *buf, char *cmp_addr, sctp_assoc_t *assoc_id,
 
 	return EVENT_OK;
 }
+
+bool ipv6_enabled(void)
+{
+	int fd;
+
+	if (access("/proc/net/if_inet6", F_OK) != 0)
+		return false;
+
+	fd = socket(AF_INET6, SOCK_DGRAM, 0);
+	if (fd < 0)
+		return false;
+
+	close(fd);
+	return true;
+}
diff --git a/tests/sctp/sctp_common.h b/tests/sctp/sctp_common.h
index 3a2545a..9f21d3e 100644
--- a/tests/sctp/sctp_common.h
+++ b/tests/sctp/sctp_common.h
@@ -36,3 +36,5 @@ void print_ip_option(int fd, bool ipv4, char *text);
 int set_subscr_events(int fd, int data_io, int assoc, int addr, int shutd);
 int handle_event(void *buf, char *cmp_addr, sctp_assoc_t *assoc_id,
 		 bool verbose, char *text);
+
+bool ipv6_enabled(void);
diff --git a/tests/sctp/sctp_peeloff_server.c b/tests/sctp/sctp_peeloff_server.c
index 3e48df7..e7b33c5 100644
--- a/tests/sctp/sctp_peeloff_server.c
+++ b/tests/sctp/sctp_peeloff_server.c
@@ -59,7 +59,7 @@ int main(int argc, char **argv)
 	if (ipv4)
 		hints.ai_family = AF_INET;
 	else
-		hints.ai_family = AF_INET6;
+		hints.ai_family = ipv6_enabled() ? AF_INET6 : AF_INET;
 
 	/* sctp_peeloff(3) must be from 1 to Many style socket */
 	hints.ai_socktype = SOCK_SEQPACKET;
diff --git a/tests/sctp/sctp_server.c b/tests/sctp/sctp_server.c
index a7832eb..6edadcf 100644
--- a/tests/sctp/sctp_server.c
+++ b/tests/sctp/sctp_server.c
@@ -74,7 +74,7 @@ int main(int argc, char **argv)
 	if (ipv4)
 		hints.ai_family = AF_INET;
 	else
-		hints.ai_family = AF_INET6;
+		hints.ai_family = ipv6_enabled() ? AF_INET6 : AF_INET;
 
 	if (!strcmp(argv[optind], "stream"))
 		hints.ai_socktype = SOCK_STREAM;
diff --git a/tests/sctp/test b/tests/sctp/test
index 5626ab8..1e547a3 100755
--- a/tests/sctp/test
+++ b/tests/sctp/test
@@ -104,6 +104,27 @@ BEGIN {
             $test_count += 8;
             $test_nft = 1;
         }
+
+        # Determine if IPv6 is enabled on loopback.
+        $test_ipv6 = system("$basedir/../has_ipv6") == 0 ? 1 : 0;
+
+        if ( !$test_ipv6 ) {
+            $test_count -= 12;
+
+            if ($test_calipso) {
+                $test_count -= 13;
+                if ($test_clpeeloff) {
+                    $test_count -= 6;
+                }
+                $test_calipso = 0;
+            }
+            if ($test_iptables) {
+                $test_count -= 4;
+            }
+            if ($test_nft) {
+                $test_count -= 4;
+            }
+        }
     }
 
     plan tests => $test_count;
@@ -164,6 +185,8 @@ $result = system
 "runcon -t test_sctp_client_t $basedir/sctp_client $v -n -e nopeer seq 127.0.0.1 1035";
 ok( $result eq 0 );
 
+if ($test_ipv6) {
+
 # Verify that authorized client can communicate with the server SEQ->STREAM.
 $result = system
   "runcon -t test_sctp_client_t $basedir/sctp_client $v -e nopeer seq ::1 1035";
@@ -174,6 +197,7 @@ ok( $result eq 0 );
 $result = system
 "runcon -t test_sctp_client_t -- $basedir/sctp_client $v -e nopeer stream ::1 1023 2>&1";
 ok( $result >> 8 eq 8 );
+}
 
 # Kill the stream server.
 server_end($pid);
@@ -194,6 +218,7 @@ $result = system
 "runcon -t test_sctp_connectx_t $basedir/sctp_connectx $v stream 127.0.0.1 1035";
 ok( $result eq 0 );
 
+if ($test_ipv6) {
 $result =
   system
   "runcon -t test_sctp_connectx_t $basedir/sctp_connectx $v seq ::1 1035";
@@ -203,6 +228,7 @@ $result =
   system
 "runcon -t test_sctp_deny_connectx_t $basedir/sctp_connectx $v seq ::1 1035 2>&1";
 ok( $result >> 8 eq 7 );
+}
 
 #
 ########################### SCTP_SENDMSG_CONNECT #############################
@@ -215,10 +241,12 @@ $result =
 "runcon -t test_sctp_connectx_t $basedir/sctp_connectx $v -n seq 127.0.0.1 1035";
 ok( $result eq 0 );
 
+if ($test_ipv6) {
 $result =
   system
 "runcon -t test_sctp_deny_connectx_t $basedir/sctp_connectx $v -n seq ::1 1035 2>&1";
 ok( $result >> 8 eq 8 );
+}
 
 #
 ################################ BINDX #######################################
@@ -351,6 +379,8 @@ server_end($pid);
 # Start seq server.
 $pid = server_start( "-t test_sctp_server_t", "sctp_server", "$v seq 1035" );
 
+if ($test_ipv6) {
+
 # Verify that authorized client can communicate with the server SEQ->SEQ.
 $result = system
 "runcon -t test_sctp_client_t $basedir/sctp_client $v -e system_u:object_r:netlabel_sctp_peer_t:s0 seq ::1 1035";
@@ -375,6 +405,7 @@ ok( $result >> 8 eq 6 );
 $result = system
 "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -n -e system_u:object_r:netlabel_sctp_peer_t:s0 seq ::1 1035 2>&1";
 ok( $result >> 8 eq 13 );
+}
 
 # Kill the seq server.
 server_end($pid);
@@ -396,10 +427,13 @@ $result = system
 "runcon -t test_sctp_client_t $basedir/sctp_client $v -e system_u:object_r:netlabel_sctp_peer_t:s0 stream 127.0.0.1 1035";
 ok( $result eq 0 );
 
+if ($test_ipv6) {
+
 # Verify that the server is denied this association as the client will timeout on connect.
 $result = system
 "runcon -t test_sctp_client_t -- $basedir/sctp_client $v -e system_u:object_r:deny_assoc_sctp_peer_t:s0 stream ::1 1035 2>&1";
 ok( $result >> 8 eq 6 );
+}
 
 # Kill the seq server.
 server_end($pid);
@@ -1141,6 +1175,8 @@ sub test_tables {
 "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -e nopeer stream 127.0.0.1 1035 2>&1";
     ok( $result >> 8 eq 6 );
 
+    if ($test_ipv6) {
+
  # Verify that authorized client can communicate with the server STREAM->STREAM.
     $result = system
 "runcon -t test_sctp_client_t $basedir/sctp_client $v -e nopeer stream ::1 1035";
@@ -1150,6 +1186,7 @@ sub test_tables {
     $result = system
 "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -e nopeer stream ::1 1035 2>&1";
     ok( $result >> 8 eq 6 );
+    }
 
     # Kill the stream server.
     server_end($pid);
@@ -1168,6 +1205,8 @@ sub test_tables {
 "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -e nopeer seq 127.0.0.1 1035 2>&1";
     ok( $result >> 8 eq 6 );
 
+    if ($test_ipv6) {
+
     # Verify that authorized client can communicate with the server SEQ->SEQ.
     $result = system
 "runcon -t test_sctp_client_t $basedir/sctp_client $v -e nopeer seq ::1 1035";
@@ -1177,6 +1216,7 @@ sub test_tables {
     $result = system
 "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -e nopeer seq ::1 1035 2>&1";
     ok( $result >> 8 eq 6 );
+    }
 
     # Kill the seq server.
     server_end($pid);
@@ -1192,7 +1232,9 @@ if ($test_iptables) {
 if ($test_nft) {
     print "# Testing nftables (IPv4/IPv6).\n";
     system "nft -f $basedir/nftables-load";
+    system "nft -f $basedir/nftables-ipv6.load" if $test_ipv6;
     test_tables();
+    system "nft -f $basedir/nftables-ipv6-flush" if $test_ipv6;
     system "nft -f $basedir/nftables-flush";
 }
 
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH] tests: make IPv6 subtests optional on IPv4-only systems
  2026-07-10  8:25 [PATCH] tests: make IPv6 subtests optional on IPv4-only systems Jan Onderka
@ 2026-07-10 17:55 ` Stephen Smalley
  2026-10-01 15:36 ` Brian Grech
  1 sibling, 0 replies; 7+ messages in thread
From: Stephen Smalley @ 2026-07-10 17:55 UTC (permalink / raw)
  To: Jan Onderka; +Cc: selinux

On Fri, Jul 10, 2026 at 4:37 AM Jan Onderka <jonderka@redhat.com> wrote:
>
> Skip or adapt IPv6-dependent subtests when the running system does not
> have usable IPv6 on loopback.
>
> Problem
> -------
> Several subtests assume IPv6 is available: they bind or connect to ::1,
> load ip6tables/nftables IPv6 rules, or create AF_INET6/SCTP IPv6 sockets.
> On IPv4-only systems (for example RHIVOS kernels built without usable
> IPv6, or hosts with net.ipv6.conf.*.disable_ipv6=1), these subtests
> hang or fail in ways that block the entire make test run.
>
> Change
> ------
> - Add tests/has_ipv6 helper that checks /proc/net/if_inet6 and the
>   net.ipv6.conf.all/lo.disable_ipv6 sysctls.
> - Wrap IPv6-only cases in inet_socket, extended_socket_class, and sctp
>   Perl tests behind $test_ipv6 / ipv6_enabled() checks and reduce test
>   counts accordingly.
> - Make inet_socket/server.c fall back to AF_INET when IPv6 is absent.
> - Split IPv6 firewall/load script rules into nftables-ipv6.load and only
>   invoke ip6tables/nftables IPv6 setup from load scripts when has_ipv6
>   succeeds.
> - Add ipv6_enabled() to sctp_common for C helpers and SCTP bindx paths.
>
> Justification
> -------------
> IPv6 is optional in many deployment targets. The testsuite should detect
> runtime IPv6 usability and skip only the affected subtests instead of
> assuming ::1 and ip6tables always work. This mirrors how other optional
> features are handled in the tree and keeps the fix self-contained in
> selinux-testsuite.
>
> Testing
> -------
> Verified on RHIVOS (no /proc/net/if_inet6):
>
>   - inet_socket/tcp and inet_socket/udp complete successfully
>   - extended_socket_class IPv6 cases are skipped
>   - make test progresses past former IPv6 hang points
>
> Verified on a host with IPv6 enabled:
>
>   - IPv6 subtests still run and pass
>
> Signed-off-by: Jan Onderka <jonderka@redhat.com>

I haven't looked into the cause yet but this breaks the tests on Fedora 44,
and it also isn't formatted properly via tools/check-syntax -f.

inet_socket/tcp/test ........ 21/34 connect: Connection refused

#   Failed test at inet_socket/tcp/test line 357.
inet_socket/tcp/test ........ 25/34 connect: Operation now in progress
inet_socket/tcp/test ........ 26/34
#   Failed test at inet_socket/tcp/test line 412.
inet_socket/tcp/test ........ 28/34 connect: Operation now in progress
inet_socket/tcp/test ........ 30/34
#   Failed test at inet_socket/tcp/test line 412.
connect: Connection refused

#   Failed test at inet_socket/tcp/test line 454.
connect: Connection refused

#   Failed test at inet_socket/tcp/test line 459.
inet_socket/tcp/test ........ 34/34 # Looks like you failed 5 tests of 34.
inet_socket/tcp/test ........ Dubious, test returned 5 (wstat 1280, 0x500)
Failed 5/34 subtests
inet_socket/udp/test ........ 13/25
#   Failed test at inet_socket/udp/test line 365.
read: Connection refused
inet_socket/udp/test ........ 15/25
#   Failed test at inet_socket/udp/test line 379.
inet_socket/udp/test ........ 17/25 read: Connection refused

#   Failed test at inet_socket/udp/test line 412.

#   Failed test at inet_socket/udp/test line 417.
inet_socket/udp/test ........ 21/25
/home/test/selinux-testsuite/tests/inet_socket/udp/client: no reply
from server
inet_socket/udp/test ........ 22/25
#   Failed test at inet_socket/udp/test line 412.
inet_socket/udp/test ........ 23/25 read: Connection refused

#   Failed test at inet_socket/udp/test line 473.

#   Failed test at inet_socket/udp/test line 479.
# Looks like you failed 7 tests of 25.
inet_socket/udp/test ........ Dubious, test returned 7 (wstat 1792, 0x700)
Failed 7/25 subtests

> ---
>  tests/extended_socket_class/test      | 17 ++++++++++
>  tests/has_ipv6                        | 19 +++++++++++
>  tests/inet_socket/ipsec-load          |  4 +++
>  tests/inet_socket/iptables-flush      |  9 +++--
>  tests/inet_socket/iptables-load       |  5 +++
>  tests/inet_socket/nftables-flush      |  1 -
>  tests/inet_socket/nftables-ipv6-flush |  1 +
>  tests/inet_socket/nftables-ipv6.load  | 35 +++++++++++++++++++
>  tests/inet_socket/nftables-load       | 35 ++-----------------
>  tests/inet_socket/server.c            | 19 ++++++++++-
>  tests/inet_socket/test                | 49 +++++++++++++++++++++------
>  tests/sctp/fb-deny-label-flush        |  5 +++
>  tests/sctp/fb-deny-label-load         |  7 ++++
>  tests/sctp/fb-label-flush             |  5 +++
>  tests/sctp/fb-label-load              |  7 ++++
>  tests/sctp/iptables-flush             |  5 +++
>  tests/sctp/iptables-load              |  9 +++++
>  tests/sctp/nftables-flush             |  1 -
>  tests/sctp/nftables-ipv6-flush        |  1 +
>  tests/sctp/nftables-ipv6.load         | 33 ++++++++++++++++++
>  tests/sctp/nftables-load              | 33 ++----------------
>  tests/sctp/sctp_bindx.c               | 46 +++++++++++++++++--------
>  tests/sctp/sctp_common.c              | 15 ++++++++
>  tests/sctp/sctp_common.h              |  2 ++
>  tests/sctp/sctp_peeloff_server.c      |  2 +-
>  tests/sctp/sctp_server.c              |  2 +-
>  tests/sctp/test                       | 42 +++++++++++++++++++++++
>  27 files changed, 312 insertions(+), 97 deletions(-)
>  create mode 100755 tests/has_ipv6
>  create mode 100644 tests/inet_socket/nftables-ipv6-flush
>  create mode 100644 tests/inet_socket/nftables-ipv6.load
>  create mode 100644 tests/sctp/nftables-ipv6-flush
>  create mode 100644 tests/sctp/nftables-ipv6.load
>
> diff --git a/tests/extended_socket_class/test b/tests/extended_socket_class/test
> index 1e6299f..9a6ea16 100755
> --- a/tests/extended_socket_class/test
> +++ b/tests/extended_socket_class/test
> @@ -26,6 +26,17 @@ BEGIN {
>          $test_smc = 1;
>      }
>
> +    # Determine if IPv6 is enabled on loopback.
> +    my $testdir = $0;
> +    $testdir =~ s|(.*)/[^/]*|$1|;
> +    $test_ipv6 = system("$testdir/../has_ipv6") == 0 ? 1 : 0;
> +    if ( !$test_ipv6 ) {
> +        $test_count -= 2;
> +        if ($test_sctp) {
> +            $test_count -= 4;
> +        }
> +    }
> +
>      plan tests => $test_count;
>  }
>
> @@ -46,6 +57,8 @@ $result = system(
>  );
>  ok($result);
>
> +if ($test_ipv6) {
> +
>  # Verify that test_icmp_socket_t can create an ICMPv6 socket.
>  $result = system(
>  "runcon -t test_icmp_socket_t -- $basedir/sockcreate inet6 dgram icmpv6 2>&1"
> @@ -57,6 +70,7 @@ $result = system(
>  "runcon -t test_no_icmp_socket_t -- $basedir/sockcreate inet6 dgram icmpv6 2>&1"
>  );
>  ok($result);
> +}
>
>  # Restore to the kernel defaults - no one allowed to create ICMP sockets.
>  system("echo 1 0 > /proc/sys/net/ipv4/ping_group_range");
> @@ -87,6 +101,8 @@ if ($test_sctp) {
>      );
>      ok($result);
>
> +    if ($test_ipv6) {
> +
>      # Verify that test_sctp_socket_t can create an IPv6 stream SCTP socket.
>      $result = system(
>  "runcon -t test_sctp_socket_t -- $basedir/sockcreate inet6 stream sctp 2>&1"
> @@ -110,6 +126,7 @@ if ($test_sctp) {
>  "runcon -t test_no_sctp_socket_t -- $basedir/sockcreate inet6 seqpacket sctp 2>&1"
>      );
>      ok($result);
> +    }
>  }
>
>  if ($test_bluetooth) {
> diff --git a/tests/has_ipv6 b/tests/has_ipv6
> new file mode 100755
> index 0000000..21f12e7
> --- /dev/null
> +++ b/tests/has_ipv6
> @@ -0,0 +1,19 @@
> +#!/bin/sh
> +#
> +# Return 0 if IPv6 is enabled and usable on loopback, 1 otherwise.
> +#
> +# IPv6 may be absent (ipv6.disable=1 on the kernel command line), disabled
> +# globally (net.ipv6.conf.all.disable_ipv6=1), or disabled on loopback
> +# (net.ipv6.conf.lo.disable_ipv6=1).  Following the LTP tst_net.sh approach,
> +# check /proc/net/if_inet6 and the disable_ipv6 sysctls rather than module
> +# parameters that may be blocked by SELinux policy.
> +
> +[ -f /proc/net/if_inet6 ] || exit 1
> +
> +disabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6 2>/dev/null) || exit 1
> +[ "$disabled" = 1 ] && exit 1
> +
> +disabled=$(sysctl -n net.ipv6.conf.lo.disable_ipv6 2>/dev/null) || exit 1
> +[ "$disabled" = 1 ] && exit 1
> +
> +exit 0
> diff --git a/tests/inet_socket/ipsec-load b/tests/inet_socket/ipsec-load
> index 21e2dfe..e286de3 100644
> --- a/tests/inet_socket/ipsec-load
> +++ b/tests/inet_socket/ipsec-load
> @@ -10,8 +10,12 @@ ip xfrm state add src 127.0.0.1 dst 127.0.0.1 proto ah spi 0x250 ctx $badclientc
>  ip xfrm policy add src 127.0.0.1 dst 127.0.0.1 proto tcp dir out ctx "system_u:object_r:test_spd_t:s0" tmpl proto ah mode transport level required
>  ip xfrm policy add src 127.0.0.1 dst 127.0.0.1 proto udp dir out ctx "system_u:object_r:test_spd_t:s0" tmpl proto ah mode transport level required
>
> +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
> +HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
> +if "$HAS_IPV6"; then
>  # IPv6 loopback
>  ip xfrm state add src ::1 dst ::1 proto ah spi 0x200 ctx $goodclientcon auth sha1 0123456789012345
>  ip xfrm state add src ::1 dst ::1 proto ah spi 0x250 ctx $badclientcon auth sha1 0123456789012345
>  ip xfrm policy add src ::1 dst ::1 proto tcp dir out ctx "system_u:object_r:test_spd_t:s0" tmpl proto ah mode transport level required
>  ip xfrm policy add src ::1 dst ::1 proto udp dir out ctx "system_u:object_r:test_spd_t:s0" tmpl proto ah mode transport level required
> +fi
> diff --git a/tests/inet_socket/iptables-flush b/tests/inet_socket/iptables-flush
> index c168d89..198bb85 100644
> --- a/tests/inet_socket/iptables-flush
> +++ b/tests/inet_socket/iptables-flush
> @@ -1,6 +1,11 @@
>  #!/bin/sh
> +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
> +HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
> +
>  # Flush the security table.
>  iptables -t security -F
> -iptables -t security -X NEWCONN
> +iptables -t security -X NEWCONN 2>/dev/null
> +if "$HAS_IPV6"; then
>  ip6tables -t security -F
> -ip6tables -t security -X NEWCONN
> +ip6tables -t security -X NEWCONN 2>/dev/null
> +fi
> diff --git a/tests/inet_socket/iptables-load b/tests/inet_socket/iptables-load
> index 5be94f4..d097ed7 100644
> --- a/tests/inet_socket/iptables-load
> +++ b/tests/inet_socket/iptables-load
> @@ -8,6 +8,9 @@
>  # - Specified the interface since the tests are only performed over loopback.
>  # - Set the port number and context to the values used by the test script and policy.
>
> +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
> +HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
> +
>  # Flush the security table.
>  iptables -t security -F
>
> @@ -28,6 +31,7 @@ iptables -t security -A OUTPUT -m state --state ESTABLISHED,RELATED -j CONNSECMA
>  iptables -t security -A INPUT -i lo -p udp --dport 65535 -j SECMARK --selctx system_u:object_r:test_server_packet_t:s0
>  iptables -t security -A OUTPUT -o lo -p udp --sport 65535 -j SECMARK --selctx system_u:object_r:test_server_packet_t:s0
>
> +if "$HAS_IPV6"; then
>  ##### IPv6 entries
>  ip6tables -t security -F
>
> @@ -47,3 +51,4 @@ ip6tables -t security -A OUTPUT -m state --state ESTABLISHED,RELATED -j CONNSECM
>  # Label UDP packets similarly.
>  ip6tables -t security -A INPUT -i lo -p udp --dport 65535 -j SECMARK --selctx system_u:object_r:test_server_packet_t:s0
>  ip6tables -t security -A OUTPUT -o lo -p udp --sport 65535 -j SECMARK --selctx system_u:object_r:test_server_packet_t:s0
> +fi
> diff --git a/tests/inet_socket/nftables-flush b/tests/inet_socket/nftables-flush
> index 7d62b8d..d0fee0c 100644
> --- a/tests/inet_socket/nftables-flush
> +++ b/tests/inet_socket/nftables-flush
> @@ -1,2 +1 @@
>  delete table ip security
> -delete table ip6 security
> diff --git a/tests/inet_socket/nftables-ipv6-flush b/tests/inet_socket/nftables-ipv6-flush
> new file mode 100644
> index 0000000..0c9b69a
> --- /dev/null
> +++ b/tests/inet_socket/nftables-ipv6-flush
> @@ -0,0 +1 @@
> +delete table ip6 security
> diff --git a/tests/inet_socket/nftables-ipv6.load b/tests/inet_socket/nftables-ipv6.load
> new file mode 100644
> index 0000000..6116343
> --- /dev/null
> +++ b/tests/inet_socket/nftables-ipv6.load
> @@ -0,0 +1,35 @@
> +# IPv6 secmark rules for inet_socket tests (loaded only when IPv6 is enabled).
> +
> +add table ip6 security
> +
> +table ip6 security {
> +
> +       secmark inet_server {
> +               "system_u:object_r:test_server_packet_t:s0"
> +       }
> +
> +       map secmapping_in_out {
> +               type inet_service : secmark
> +               elements = { 65535 : "inet_server" }
> +       }
> +
> +       chain input {
> +               type filter hook input priority 0;
> +
> +               ct state new meta secmark set tcp dport map @secmapping_in_out
> +               ct state new meta secmark set udp dport map @secmapping_in_out
> +               ct state new ct secmark set meta secmark
> +
> +               ct state established,related meta secmark set ct secmark
> +       }
> +
> +       chain output {
> +               type filter hook output priority 0;
> +
> +               ct state new meta secmark set tcp dport map @secmapping_in_out
> +               ct state established meta secmark set udp dport map @secmapping_in_out
> +               ct state new ct secmark set meta secmark
> +
> +               ct state established,related meta secmark set ct secmark
> +       }
> +}
> diff --git a/tests/inet_socket/nftables-load b/tests/inet_socket/nftables-load
> index 11ec382..14d6efe 100644
> --- a/tests/inet_socket/nftables-load
> +++ b/tests/inet_socket/nftables-load
> @@ -1,7 +1,8 @@
>  # Based on NFT project example. Requires kernel >= 4.20 and nft >= 0.9.3
> +#
> +# IPv6 rules are in nftables-ipv6.load and loaded only when IPv6 is enabled.
>
>  add table ip security
> -add table ip6 security
>
>  table ip security {
>
> @@ -40,35 +41,3 @@ table ip security {
>                 ct state established,related meta secmark set ct secmark
>         }
>  }
> -
> -table ip6 security {
> -
> -       secmark inet_server {
> -               "system_u:object_r:test_server_packet_t:s0"
> -       }
> -
> -       map secmapping_in_out {
> -               type inet_service : secmark
> -               elements = { 65535 : "inet_server" }
> -       }
> -
> -       chain input {
> -               type filter hook input priority 0;
> -
> -               ct state new meta secmark set tcp dport map @secmapping_in_out
> -               ct state new meta secmark set udp dport map @secmapping_in_out
> -               ct state new ct secmark set meta secmark
> -
> -               ct state established,related meta secmark set ct secmark
> -       }
> -
> -       chain output {
> -               type filter hook output priority 0;
> -
> -               ct state new meta secmark set tcp dport map @secmapping_in_out
> -               ct state established meta secmark set udp dport map @secmapping_in_out
> -               ct state new ct secmark set meta secmark
> -
> -               ct state established,related meta secmark set ct secmark
> -       }
> -}
> diff --git a/tests/inet_socket/server.c b/tests/inet_socket/server.c
> index 63b6849..c4e4432 100644
> --- a/tests/inet_socket/server.c
> +++ b/tests/inet_socket/server.c
> @@ -10,6 +10,8 @@
>  #include <stdio.h>
>  #include <stdbool.h>
>
> +#include <unistd.h>
> +
>  #ifndef SO_PEERSEC
>  #define SO_PEERSEC 31
>  #endif
> @@ -36,6 +38,21 @@ void usage(char *progname)
>         exit(1);
>  }
>
> +static bool ipv6_enabled(void)
> +{
> +       int fd;
> +
> +       if (access("/proc/net/if_inet6", F_OK) != 0)
> +               return false;
> +
> +       fd = socket(AF_INET6, SOCK_DGRAM, 0);
> +       if (fd < 0)
> +               return false;
> +
> +       close(fd);
> +       return true;
> +}
> +
>  int main(int argc, char **argv)
>  {
>         int sock, result, opt, sockprotocol, on = 1;
> @@ -64,7 +81,7 @@ int main(int argc, char **argv)
>
>         memset(&hints, 0, sizeof(struct addrinfo));
>         hints.ai_flags = AI_PASSIVE;
> -       hints.ai_family = AF_INET6;
> +       hints.ai_family = ipv6_enabled() ? AF_INET6 : AF_INET;
>
>         if (!strcmp(argv[optind], "tcp")) {
>                 hints.ai_socktype = SOCK_STREAM;
> diff --git a/tests/inet_socket/test b/tests/inet_socket/test
> index 4cc3852..01acf8a 100755
> --- a/tests/inet_socket/test
> +++ b/tests/inet_socket/test
> @@ -63,6 +63,25 @@ BEGIN {
>          $test_nft = 1;
>      }
>
> +    # Determine if IPv6 is enabled on loopback.
> +    $test_ipv6 = system("$basedir/../has_ipv6") == 0 ? 1 : 0;
> +
> +    if ( !$test_ipv6 ) {
> +        if ($test_ipsec) {
> +            $test_count -= 2;
> +        }
> +        if ($test_calipso) {
> +            $test_count -= $is_stream ? 3 : 2;
> +            $test_calipso = 0;
> +        }
> +        if ($test_iptables) {
> +            $test_count -= 2;
> +        }
> +        if ($test_nft) {
> +            $test_count -= 2;
> +        }
> +    }
> +
>      plan tests => $test_count;
>  }
>
> @@ -329,7 +348,7 @@ if ($test_ipsec) {
>  "runcon -t test_inet_bad_client_t -- $basedir/client $proto 127.0.0.1 65535 2>&1";
>      ok( $result >> 8 eq $fail_value2 );
>
> -    if ($is_stream) {
> +    if ($is_stream && $test_ipv6) {
>
>          # Verify that authorized client can communicate with the server.
>          $result =
> @@ -338,15 +357,18 @@ if ($test_ipsec) {
>          ok( $result eq 0 );
>      }
>
> -    # Verify that unauthorized client cannot communicate with the server.
> -    $result = system
> +    if ($test_ipv6) {
> +
> +        # Verify that unauthorized client cannot communicate with the server.
> +        $result = system
>  "runcon -t test_inet_bad_client_t -- $basedir/client $proto ::1 65535 2>&1";
> -    ok( $result >> 8 eq $fail_value2 );
> +        ok( $result >> 8 eq $fail_value2 );
> +    }
>
>      # Kill the server.
>      server_end($pid);
>
> -    if ( not $is_stream ) {
> +    if ( not $is_stream && $test_ipv6 ) {
>
>     # Start the server for IPSEC test using IPv6 but do not request peer context.
>          $pid = server_start( "-t test_inet_server_t", "-n $proto 65535" );
> @@ -382,15 +404,18 @@ sub test_tables {
>  "runcon -t test_inet_bad_client_t -- $basedir/client -e nopeer $proto 127.0.0.1 65535 2>&1";
>      ok( $result >> 8 eq $fail_value2 );
>
> -    # Verify that authorized client can communicate with the server.
> -    $result = system
> +    if ($test_ipv6) {
> +
> +        # Verify that authorized client can communicate with the server.
> +        $result = system
>  "runcon -t test_inet_client_t -- $basedir/client -e nopeer $proto ::1 65535";
> -    ok( $result eq 0 );
> +        ok( $result eq 0 );
>
> -    # Verify that unauthorized client cannot communicate with the server.
> -    $result = system
> +        # Verify that unauthorized client cannot communicate with the server.
> +        $result = system
>  "runcon -t test_inet_bad_client_t -- $basedir/client -e nopeer $proto ::1 65535 2>&1";
> -    ok( $result >> 8 eq $fail_value2 );
> +        ok( $result >> 8 eq $fail_value2 );
> +    }
>
>      # Kill the server.
>      server_end($pid);
> @@ -406,7 +431,9 @@ if ($test_iptables) {
>  if ($test_nft) {
>      print "Testing nftables (IPv4/IPv6).\n";
>      system "nft -f $basedir/nftables-load";
> +    system "nft -f $basedir/nftables-ipv6.load" if $test_ipv6;
>      test_tables();
> +    system "nft -f $basedir/nftables-ipv6-flush" if $test_ipv6;
>      system "nft -f $basedir/nftables-flush";
>  }
>
> diff --git a/tests/sctp/fb-deny-label-flush b/tests/sctp/fb-deny-label-flush
> index 059e0b7..41e76e6 100644
> --- a/tests/sctp/fb-deny-label-flush
> +++ b/tests/sctp/fb-deny-label-flush
> @@ -1,6 +1,11 @@
>  #!/bin/sh
>
> +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
> +HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
> +
>  netlabelctl map del default
>  netlabelctl map add default protocol:unlbl
>  netlabelctl unlbl del interface:lo address:127.0.0.0/8 label:system_u:object_r:netlabel_sctp_peer_t:s0
> +if "$HAS_IPV6"; then
>  netlabelctl unlbl del interface:lo address:::1/128 label:system_u:object_r:deny_assoc_sctp_peer_t:s0
> +fi
> diff --git a/tests/sctp/fb-deny-label-load b/tests/sctp/fb-deny-label-load
> index 7c0bd87..647399b 100644
> --- a/tests/sctp/fb-deny-label-load
> +++ b/tests/sctp/fb-deny-label-load
> @@ -1,7 +1,14 @@
>  #!/bin/sh
>
> +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
> +HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
> +
>  netlabelctl map del default
>  netlabelctl map add default address:0.0.0.0/0 protocol:unlbl
> +if "$HAS_IPV6"; then
>  netlabelctl map add default address:::/0 protocol:unlbl
> +fi
>  netlabelctl unlbl add interface:lo address:127.0.0.0/8 label:system_u:object_r:netlabel_sctp_peer_t:s0
> +if "$HAS_IPV6"; then
>  netlabelctl unlbl add interface:lo address:::1/128 label:system_u:object_r:deny_assoc_sctp_peer_t:s0
> +fi
> diff --git a/tests/sctp/fb-label-flush b/tests/sctp/fb-label-flush
> index 13573a8..c1ceeb5 100644
> --- a/tests/sctp/fb-label-flush
> +++ b/tests/sctp/fb-label-flush
> @@ -1,6 +1,11 @@
>  #!/bin/sh
>
> +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
> +HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
> +
>  netlabelctl map del default
>  netlabelctl map add default protocol:unlbl
>  netlabelctl unlbl del interface:lo address:127.0.0.0/8 label:system_u:object_r:netlabel_sctp_peer_t:s0
> +if "$HAS_IPV6"; then
>  netlabelctl unlbl del interface:lo address:::1/128 label:system_u:object_r:netlabel_sctp_peer_t:s0
> +fi
> diff --git a/tests/sctp/fb-label-load b/tests/sctp/fb-label-load
> index a501515..065ec34 100644
> --- a/tests/sctp/fb-label-load
> +++ b/tests/sctp/fb-label-load
> @@ -1,8 +1,15 @@
>  #!/bin/sh
>
> +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
> +HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
> +
>  netlabelctl map del default
>  netlabelctl map add default address:0.0.0.0/0 protocol:unlbl
> +if "$HAS_IPV6"; then
>  netlabelctl map add default address:::/0 protocol:unlbl
> +fi
>  netlabelctl unlbl add interface:lo address:127.0.0.0/8 label:system_u:object_r:netlabel_sctp_peer_t:s0
> +if "$HAS_IPV6"; then
>  netlabelctl unlbl add interface:lo address:::1/128 label:system_u:object_r:netlabel_sctp_peer_t:s0
> +fi
>  #netlabelctl -p unlbl list
> diff --git a/tests/sctp/iptables-flush b/tests/sctp/iptables-flush
> index e74271a..112ae79 100644
> --- a/tests/sctp/iptables-flush
> +++ b/tests/sctp/iptables-flush
> @@ -1,4 +1,9 @@
>  #!/bin/sh
>  # Flush the security table after IPv4 and IPv6 tests.
> +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
> +HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
> +
>  iptables -t security -F
> +if "$HAS_IPV6"; then
>  ip6tables -t security -F
> +fi
> diff --git a/tests/sctp/iptables-load b/tests/sctp/iptables-load
> index 9dac576..1a91e19 100644
> --- a/tests/sctp/iptables-load
> +++ b/tests/sctp/iptables-load
> @@ -1,9 +1,14 @@
>  #!/bin/sh
>  ############################ SECMARK IPTABLE ENTRIES ########################
>  #
> +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
> +HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
> +
>  # Flush the security table first:
>  iptables -t security -F
> +if "$HAS_IPV6"; then
>  ip6tables -t security -F
> +fi
>
>  #-------------- INPUT IP Stream --------------------#
>  # These rules will replace the above context if sctp ports 1024:1035 are found in the packets:
> @@ -11,9 +16,11 @@ iptables -t security -A INPUT -i lo -p sctp -m multiport --port 1024:1035 -j SEC
>
>  iptables -t security -A INPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --save
>
> +if "$HAS_IPV6"; then
>  ip6tables -t security -A INPUT -i lo -p sctp -m multiport --port 1024:1035 -j SECMARK --selctx system_u:object_r:test_sctp_server_packet_t:s0
>
>  ip6tables -t security -A INPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --save
> +fi
>
>  #-------------- OUTPUT IP Stream --------------------#
>  # These rules will replace the above context if sctp ports 1024:1035 are found in the packets:
> @@ -21,7 +28,9 @@ iptables -t security -A OUTPUT -o lo -p sctp -m multiport --port 1024:1035 -j SE
>
>  iptables -t security -A OUTPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --save
>
> +if "$HAS_IPV6"; then
>  ip6tables -t security -A OUTPUT -o lo -p sctp -m multiport --port 1024:1035 -j SECMARK --selctx system_u:object_r:test_sctp_server_packet_t:s0
>
>  ip6tables -t security -A OUTPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --save
> +fi
>
> diff --git a/tests/sctp/nftables-flush b/tests/sctp/nftables-flush
> index 7d62b8d..d0fee0c 100644
> --- a/tests/sctp/nftables-flush
> +++ b/tests/sctp/nftables-flush
> @@ -1,2 +1 @@
>  delete table ip security
> -delete table ip6 security
> diff --git a/tests/sctp/nftables-ipv6-flush b/tests/sctp/nftables-ipv6-flush
> new file mode 100644
> index 0000000..0c9b69a
> --- /dev/null
> +++ b/tests/sctp/nftables-ipv6-flush
> @@ -0,0 +1 @@
> +delete table ip6 security
> diff --git a/tests/sctp/nftables-ipv6.load b/tests/sctp/nftables-ipv6.load
> new file mode 100644
> index 0000000..1268140
> --- /dev/null
> +++ b/tests/sctp/nftables-ipv6.load
> @@ -0,0 +1,33 @@
> +# IPv6 secmark rules for SCTP tests (loaded only when IPv6 is enabled).
> +
> +add table ip6 security
> +
> +table ip6 security {
> +
> +       secmark sctp_server {
> +               "system_u:object_r:test_sctp_server_packet_t:s0"
> +       }
> +
> +       map secmapping_in_out {
> +               type inet_service : secmark
> +               elements = { 1035 : "sctp_server" }
> +       }
> +
> +       chain input {
> +               type filter hook input priority 0;
> +
> +               ct state new meta secmark set sctp dport map @secmapping_in_out
> +               ct state new ct secmark set meta secmark
> +
> +               ct state established,related meta secmark set ct secmark
> +       }
> +
> +       chain output {
> +               type filter hook output priority 0;
> +
> +               ct state new meta secmark set sctp dport map @secmapping_in_out
> +               ct state new ct secmark set meta secmark
> +
> +               ct state established,related meta secmark set ct secmark
> +       }
> +}
> diff --git a/tests/sctp/nftables-load b/tests/sctp/nftables-load
> index 2cac3bb..56803b6 100644
> --- a/tests/sctp/nftables-load
> +++ b/tests/sctp/nftables-load
> @@ -1,7 +1,8 @@
>  # Based on NFT project example. Requires kernel >= 4.20 and nft >= 0.9.3
> +#
> +# IPv6 rules are in nftables-ipv6.load and loaded only when IPv6 is enabled.
>
>  add table ip security
> -add table ip6 security
>
>  table ip security {
>
> @@ -36,33 +37,3 @@ table ip security {
>                 ct state established,related meta secmark set ct secmark
>         }
>  }
> -
> -table ip6 security {
> -
> -       secmark sctp_server {
> -               "system_u:object_r:test_sctp_server_packet_t:s0"
> -       }
> -
> -       map secmapping_in_out {
> -               type inet_service : secmark
> -               elements = { 1035 : "sctp_server" }
> -       }
> -
> -       chain input {
> -               type filter hook input priority 0;
> -
> -               ct state new meta secmark set sctp dport map @secmapping_in_out
> -               ct state new ct secmark set meta secmark
> -
> -               ct state established,related meta secmark set ct secmark
> -       }
> -
> -       chain output {
> -               type filter hook output priority 0;
> -
> -               ct state new meta secmark set sctp dport map @secmapping_in_out
> -               ct state new ct secmark set meta secmark
> -
> -               ct state established,related meta secmark set ct secmark
> -       }
> -}
> diff --git a/tests/sctp/sctp_bindx.c b/tests/sctp/sctp_bindx.c
> index 74bf985..2240404 100644
> --- a/tests/sctp/sctp_bindx.c
> +++ b/tests/sctp/sctp_bindx.c
> @@ -1,4 +1,5 @@
>  #include "sctp_common.h"
> +#include <errno.h>
>
>  static void usage(char *progname)
>  {
> @@ -22,6 +23,7 @@ int main(int argc, char **argv)
>         unsigned short port;
>         bool rem = false;
>         bool verbose = false;
> +       bool ipv6_bound = false;
>         char *context;
>
>         while ((opt = getopt(argc, argv, "rv")) != -1) {
> @@ -58,7 +60,7 @@ int main(int argc, char **argv)
>                 free(context);
>         }
>
> -       sock = socket(PF_INET6, type, IPPROTO_SCTP);
> +       sock = socket(ipv6_enabled() ? PF_INET6 : PF_INET, type, IPPROTO_SCTP);
>         if (sock < 0) {
>                 perror("socket");
>                 exit(1);
> @@ -88,27 +90,41 @@ int main(int argc, char **argv)
>         ipv6.sin6_port = htons(port);
>         ipv6.sin6_addr = in6addr_loopback;
>
> +       if (ipv6_enabled()) {
>         result = sctp_bindx(sock, (struct sockaddr *)&ipv6, 1,
>                             SCTP_BINDX_ADD_ADDR);
>         if (result < 0) {
> -               perror("sctp_bindx ADD - ipv6");
> -               close(sock);
> -               exit(3);
> +               if (verbose)
> +                       printf("sctp_bindx ADD - ipv6 not available\n");
> +       } else {
> +               ipv6_bound = true;
> +               if (verbose)
> +                       printf("sctp_bindx ADD - ipv6\n");
> +       }
>         }
> -
> -       if (verbose)
> -               printf("sctp_bindx ADD - ipv6\n");
>
>         if (rem) {
> -               result = sctp_bindx(sock, (struct sockaddr *)&ipv6, 1,
> -                                   SCTP_BINDX_REM_ADDR);
> -               if (result < 0) {
> -                       perror("sctp_bindx - REM");
> -                       close(sock);
> -                       exit(4);
> +               if (ipv6_bound) {
> +                       result = sctp_bindx(sock, (struct sockaddr *)&ipv6, 1,
> +                                           SCTP_BINDX_REM_ADDR);
> +                       if (result < 0) {
> +                               perror("sctp_bindx - REM");
> +                               close(sock);
> +                               exit(4);
> +                       }
> +                       if (verbose)
> +                               printf("sctp_bindx REM - ipv6\n");
> +               } else {
> +                       result = sctp_bindx(sock, (struct sockaddr *)&ipv4, 1,
> +                                           SCTP_BINDX_REM_ADDR);
> +                       if (result < 0) {
> +                               perror("sctp_bindx - REM");
> +                               close(sock);
> +                               exit(4);
> +                       }
> +                       if (verbose)
> +                               printf("sctp_bindx REM - ipv4\n");
>                 }
> -               if (verbose)
> -                       printf("sctp_bindx REM - ipv6\n");
>         }
>
>         close(sock);
> diff --git a/tests/sctp/sctp_common.c b/tests/sctp/sctp_common.c
> index d10225c..3adce02 100644
> --- a/tests/sctp/sctp_common.c
> +++ b/tests/sctp/sctp_common.c
> @@ -344,3 +344,18 @@ int handle_event(void *buf, char *cmp_addr, sctp_assoc_t *assoc_id,
>
>         return EVENT_OK;
>  }
> +
> +bool ipv6_enabled(void)
> +{
> +       int fd;
> +
> +       if (access("/proc/net/if_inet6", F_OK) != 0)
> +               return false;
> +
> +       fd = socket(AF_INET6, SOCK_DGRAM, 0);
> +       if (fd < 0)
> +               return false;
> +
> +       close(fd);
> +       return true;
> +}
> diff --git a/tests/sctp/sctp_common.h b/tests/sctp/sctp_common.h
> index 3a2545a..9f21d3e 100644
> --- a/tests/sctp/sctp_common.h
> +++ b/tests/sctp/sctp_common.h
> @@ -36,3 +36,5 @@ void print_ip_option(int fd, bool ipv4, char *text);
>  int set_subscr_events(int fd, int data_io, int assoc, int addr, int shutd);
>  int handle_event(void *buf, char *cmp_addr, sctp_assoc_t *assoc_id,
>                  bool verbose, char *text);
> +
> +bool ipv6_enabled(void);
> diff --git a/tests/sctp/sctp_peeloff_server.c b/tests/sctp/sctp_peeloff_server.c
> index 3e48df7..e7b33c5 100644
> --- a/tests/sctp/sctp_peeloff_server.c
> +++ b/tests/sctp/sctp_peeloff_server.c
> @@ -59,7 +59,7 @@ int main(int argc, char **argv)
>         if (ipv4)
>                 hints.ai_family = AF_INET;
>         else
> -               hints.ai_family = AF_INET6;
> +               hints.ai_family = ipv6_enabled() ? AF_INET6 : AF_INET;
>
>         /* sctp_peeloff(3) must be from 1 to Many style socket */
>         hints.ai_socktype = SOCK_SEQPACKET;
> diff --git a/tests/sctp/sctp_server.c b/tests/sctp/sctp_server.c
> index a7832eb..6edadcf 100644
> --- a/tests/sctp/sctp_server.c
> +++ b/tests/sctp/sctp_server.c
> @@ -74,7 +74,7 @@ int main(int argc, char **argv)
>         if (ipv4)
>                 hints.ai_family = AF_INET;
>         else
> -               hints.ai_family = AF_INET6;
> +               hints.ai_family = ipv6_enabled() ? AF_INET6 : AF_INET;
>
>         if (!strcmp(argv[optind], "stream"))
>                 hints.ai_socktype = SOCK_STREAM;
> diff --git a/tests/sctp/test b/tests/sctp/test
> index 5626ab8..1e547a3 100755
> --- a/tests/sctp/test
> +++ b/tests/sctp/test
> @@ -104,6 +104,27 @@ BEGIN {
>              $test_count += 8;
>              $test_nft = 1;
>          }
> +
> +        # Determine if IPv6 is enabled on loopback.
> +        $test_ipv6 = system("$basedir/../has_ipv6") == 0 ? 1 : 0;
> +
> +        if ( !$test_ipv6 ) {
> +            $test_count -= 12;
> +
> +            if ($test_calipso) {
> +                $test_count -= 13;
> +                if ($test_clpeeloff) {
> +                    $test_count -= 6;
> +                }
> +                $test_calipso = 0;
> +            }
> +            if ($test_iptables) {
> +                $test_count -= 4;
> +            }
> +            if ($test_nft) {
> +                $test_count -= 4;
> +            }
> +        }
>      }
>
>      plan tests => $test_count;
> @@ -164,6 +185,8 @@ $result = system
>  "runcon -t test_sctp_client_t $basedir/sctp_client $v -n -e nopeer seq 127.0.0.1 1035";
>  ok( $result eq 0 );
>
> +if ($test_ipv6) {
> +
>  # Verify that authorized client can communicate with the server SEQ->STREAM.
>  $result = system
>    "runcon -t test_sctp_client_t $basedir/sctp_client $v -e nopeer seq ::1 1035";
> @@ -174,6 +197,7 @@ ok( $result eq 0 );
>  $result = system
>  "runcon -t test_sctp_client_t -- $basedir/sctp_client $v -e nopeer stream ::1 1023 2>&1";
>  ok( $result >> 8 eq 8 );
> +}
>
>  # Kill the stream server.
>  server_end($pid);
> @@ -194,6 +218,7 @@ $result = system
>  "runcon -t test_sctp_connectx_t $basedir/sctp_connectx $v stream 127.0.0.1 1035";
>  ok( $result eq 0 );
>
> +if ($test_ipv6) {
>  $result =
>    system
>    "runcon -t test_sctp_connectx_t $basedir/sctp_connectx $v seq ::1 1035";
> @@ -203,6 +228,7 @@ $result =
>    system
>  "runcon -t test_sctp_deny_connectx_t $basedir/sctp_connectx $v seq ::1 1035 2>&1";
>  ok( $result >> 8 eq 7 );
> +}
>
>  #
>  ########################### SCTP_SENDMSG_CONNECT #############################
> @@ -215,10 +241,12 @@ $result =
>  "runcon -t test_sctp_connectx_t $basedir/sctp_connectx $v -n seq 127.0.0.1 1035";
>  ok( $result eq 0 );
>
> +if ($test_ipv6) {
>  $result =
>    system
>  "runcon -t test_sctp_deny_connectx_t $basedir/sctp_connectx $v -n seq ::1 1035 2>&1";
>  ok( $result >> 8 eq 8 );
> +}
>
>  #
>  ################################ BINDX #######################################
> @@ -351,6 +379,8 @@ server_end($pid);
>  # Start seq server.
>  $pid = server_start( "-t test_sctp_server_t", "sctp_server", "$v seq 1035" );
>
> +if ($test_ipv6) {
> +
>  # Verify that authorized client can communicate with the server SEQ->SEQ.
>  $result = system
>  "runcon -t test_sctp_client_t $basedir/sctp_client $v -e system_u:object_r:netlabel_sctp_peer_t:s0 seq ::1 1035";
> @@ -375,6 +405,7 @@ ok( $result >> 8 eq 6 );
>  $result = system
>  "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -n -e system_u:object_r:netlabel_sctp_peer_t:s0 seq ::1 1035 2>&1";
>  ok( $result >> 8 eq 13 );
> +}
>
>  # Kill the seq server.
>  server_end($pid);
> @@ -396,10 +427,13 @@ $result = system
>  "runcon -t test_sctp_client_t $basedir/sctp_client $v -e system_u:object_r:netlabel_sctp_peer_t:s0 stream 127.0.0.1 1035";
>  ok( $result eq 0 );
>
> +if ($test_ipv6) {
> +
>  # Verify that the server is denied this association as the client will timeout on connect.
>  $result = system
>  "runcon -t test_sctp_client_t -- $basedir/sctp_client $v -e system_u:object_r:deny_assoc_sctp_peer_t:s0 stream ::1 1035 2>&1";
>  ok( $result >> 8 eq 6 );
> +}
>
>  # Kill the seq server.
>  server_end($pid);
> @@ -1141,6 +1175,8 @@ sub test_tables {
>  "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -e nopeer stream 127.0.0.1 1035 2>&1";
>      ok( $result >> 8 eq 6 );
>
> +    if ($test_ipv6) {
> +
>   # Verify that authorized client can communicate with the server STREAM->STREAM.
>      $result = system
>  "runcon -t test_sctp_client_t $basedir/sctp_client $v -e nopeer stream ::1 1035";
> @@ -1150,6 +1186,7 @@ sub test_tables {
>      $result = system
>  "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -e nopeer stream ::1 1035 2>&1";
>      ok( $result >> 8 eq 6 );
> +    }
>
>      # Kill the stream server.
>      server_end($pid);
> @@ -1168,6 +1205,8 @@ sub test_tables {
>  "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -e nopeer seq 127.0.0.1 1035 2>&1";
>      ok( $result >> 8 eq 6 );
>
> +    if ($test_ipv6) {
> +
>      # Verify that authorized client can communicate with the server SEQ->SEQ.
>      $result = system
>  "runcon -t test_sctp_client_t $basedir/sctp_client $v -e nopeer seq ::1 1035";
> @@ -1177,6 +1216,7 @@ sub test_tables {
>      $result = system
>  "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -e nopeer seq ::1 1035 2>&1";
>      ok( $result >> 8 eq 6 );
> +    }
>
>      # Kill the seq server.
>      server_end($pid);
> @@ -1192,7 +1232,9 @@ if ($test_iptables) {
>  if ($test_nft) {
>      print "# Testing nftables (IPv4/IPv6).\n";
>      system "nft -f $basedir/nftables-load";
> +    system "nft -f $basedir/nftables-ipv6.load" if $test_ipv6;
>      test_tables();
> +    system "nft -f $basedir/nftables-ipv6-flush" if $test_ipv6;
>      system "nft -f $basedir/nftables-flush";
>  }
>
> --
> 2.55.0
>
>

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH] tests: make IPv6 subtests optional on IPv4-only systems
  2026-07-10  8:25 [PATCH] tests: make IPv6 subtests optional on IPv4-only systems Jan Onderka
  2026-07-10 17:55 ` Stephen Smalley
@ 2026-10-01 15:36 ` Brian Grech
  2026-10-02 15:01   ` Stephen Smalley
  1 sibling, 1 reply; 7+ messages in thread
From: Brian Grech @ 2026-10-01 15:36 UTC (permalink / raw)
  To: selinux, stephen.smalley.work; +Cc: jonderka, Brian Grech

Skip or adapt IPv6-dependent subtests when the running system does not
have usable IPv6 on loopback.

- Add tests/has_ipv6 helper that checks /proc/net/if_inet6 and the
  net.ipv6.conf.all/lo.disable_ipv6 sysctls.
- Wrap IPv6-only cases in inet_socket, extended_socket_class, and sctp
  Perl tests behind $test_ipv6 / ipv6_enabled() checks and reduce test
  counts accordingly.
- Make inet_socket/server.c fall back to AF_INET when IPv6 is absent.
- Split IPv6 firewall/load script rules into nftables-ipv6.load and only
  invoke ip6tables/nftables IPv6 setup from load scripts when has_ipv6
  succeeds.
- Add ipv6_enabled() to sctp_common for C helpers and SCTP bindx paths.
- Select the socket address family from has_ipv6 before entering
  confined test domains, instead of probing IPv6 from inside them: the
  probe can itself be denied by SELinux policy in a confined domain,
  which silently selected IPv4 while the test runner kept executing
  IPv6-only cases, and could otherwise misreport IPv6 as unavailable.

Signed-off-by: Jan Onderka <jonderka@redhat.com>

Co-developed-by: Jan Onderka <jonderka@redhat.com>
Signed-off-by: Brian Grech <bgrech@redhat.com>
---
 tests/extended_socket_class/test      |  61 +++++++-----
 tests/has_ipv6                        |  23 +++++
 tests/inet_socket/ipsec-load          |   4 +
 tests/inet_socket/iptables-flush      |   9 +-
 tests/inet_socket/iptables-load       |   5 +
 tests/inet_socket/nftables-flush      |   1 -
 tests/inet_socket/nftables-ipv6-flush |   1 +
 tests/inet_socket/nftables-ipv6.load  |  35 +++++++
 tests/inet_socket/nftables-load       |  35 +------
 tests/inet_socket/server.c            |  12 ++-
 tests/inet_socket/test                |  51 +++++++---
 tests/sctp/fb-deny-label-flush        |   5 +
 tests/sctp/fb-deny-label-load         |   7 ++
 tests/sctp/fb-label-flush             |   5 +
 tests/sctp/fb-label-load              |   7 ++
 tests/sctp/iptables-flush             |   5 +
 tests/sctp/iptables-load              |   9 ++
 tests/sctp/nftables-flush             |   1 -
 tests/sctp/nftables-ipv6-flush        |   1 +
 tests/sctp/nftables-ipv6.load         |  33 +++++++
 tests/sctp/nftables-load              |  33 +------
 tests/sctp/sctp_bindx.c               |  33 +++++--
 tests/sctp/test                       | 136 ++++++++++++++++++--------
 tmt/tests.fmf                         |   2 -
 24 files changed, 355 insertions(+), 159 deletions(-)
 create mode 100755 tests/has_ipv6
 create mode 100644 tests/inet_socket/nftables-ipv6-flush
 create mode 100644 tests/inet_socket/nftables-ipv6.load
 create mode 100644 tests/sctp/nftables-ipv6-flush
 create mode 100644 tests/sctp/nftables-ipv6.load

diff --git a/tests/extended_socket_class/test b/tests/extended_socket_class/test
index 1e6299f..16457bc 100755
--- a/tests/extended_socket_class/test
+++ b/tests/extended_socket_class/test
@@ -26,6 +26,17 @@ BEGIN {
         $test_smc = 1;
     }
 
+    # Determine if IPv6 is enabled on loopback.
+    my $testdir = $0;
+    $testdir =~ s|(.*)/[^/]*|$1|;
+    $test_ipv6 = system("$testdir/../has_ipv6") == 0 ? 1 : 0;
+    if ( !$test_ipv6 ) {
+        $test_count -= 2;
+        if ($test_sctp) {
+            $test_count -= 4;
+        }
+    }
+
     plan tests => $test_count;
 }
 
@@ -46,17 +57,20 @@ $result = system(
 );
 ok($result);
 
-# Verify that test_icmp_socket_t can create an ICMPv6 socket.
-$result = system(
+if ($test_ipv6) {
+
+    # Verify that test_icmp_socket_t can create an ICMPv6 socket.
+    $result = system(
 "runcon -t test_icmp_socket_t -- $basedir/sockcreate inet6 dgram icmpv6 2>&1"
-);
-ok( $result, 0 );
+    );
+    ok( $result, 0 );
 
-# Verify that test_no_icmp_socket_t cannot create an ICMPv6 socket.
-$result = system(
+    # Verify that test_no_icmp_socket_t cannot create an ICMPv6 socket.
+    $result = system(
 "runcon -t test_no_icmp_socket_t -- $basedir/sockcreate inet6 dgram icmpv6 2>&1"
-);
-ok($result);
+    );
+    ok($result);
+}
 
 # Restore to the kernel defaults - no one allowed to create ICMP sockets.
 system("echo 1 0 > /proc/sys/net/ipv4/ping_group_range");
@@ -87,29 +101,32 @@ if ($test_sctp) {
     );
     ok($result);
 
-    # Verify that test_sctp_socket_t can create an IPv6 stream SCTP socket.
-    $result = system(
+    if ($test_ipv6) {
+
+        # Verify that test_sctp_socket_t can create an IPv6 stream SCTP socket.
+        $result = system(
 "runcon -t test_sctp_socket_t -- $basedir/sockcreate inet6 stream sctp 2>&1"
-    );
-    ok( $result, 0 );
+        );
+        ok( $result, 0 );
 
    # Verify that test_no_sctp_socket_t cannot create an IPv6 stream SCTP socket.
-    $result = system(
+        $result = system(
 "runcon -t test_no_sctp_socket_t -- $basedir/sockcreate inet6 stream sctp 2>&1"
-    );
-    ok($result);
+        );
+        ok($result);
 
-    # Verify that test_sctp_socket_t can create an IPv6 seqpacket SCTP socket.
-    $result = system(
+      # Verify that test_sctp_socket_t can create an IPv6 seqpacket SCTP socket.
+        $result = system(
 "runcon -t test_sctp_socket_t -- $basedir/sockcreate inet6 seqpacket sctp 2>&1"
-    );
-    ok( $result, 0 );
+        );
+        ok( $result, 0 );
 
 # Verify that test_no_sctp_socket_t cannot create an IPv6 seqpacket SCTP socket.
-    $result = system(
+        $result = system(
 "runcon -t test_no_sctp_socket_t -- $basedir/sockcreate inet6 seqpacket sctp 2>&1"
-    );
-    ok($result);
+        );
+        ok($result);
+    }
 }
 
 if ($test_bluetooth) {
diff --git a/tests/has_ipv6 b/tests/has_ipv6
new file mode 100755
index 0000000..1c8061f
--- /dev/null
+++ b/tests/has_ipv6
@@ -0,0 +1,23 @@
+#!/bin/sh
+#
+# Return 0 if IPv6 is enabled and usable on loopback, 1 otherwise.
+#
+# IPv6 may be absent (ipv6.disable=1 on the kernel command line), disabled
+# globally (net.ipv6.conf.all.disable_ipv6=1), or disabled on loopback
+# (net.ipv6.conf.lo.disable_ipv6=1).  Following the LTP tst_net.sh approach,
+# check /proc/net/if_inet6 and the disable_ipv6 sysctls rather than module
+# parameters that may be blocked by SELinux policy.
+
+[ -f /proc/net/if_inet6 ] || exit 1
+
+disabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6 2>/dev/null) || exit 1
+[ "$disabled" = 1 ] && exit 1
+
+disabled=$(sysctl -n net.ipv6.conf.lo.disable_ipv6 2>/dev/null) || exit 1
+[ "$disabled" = 1 ] && exit 1
+
+# An existing proc file does not guarantee that ::1 is configured on lo.
+awk '$1 == "00000000000000000000000000000001" && $6 == "lo" {
+    found = 1
+}
+END { exit !found }' /proc/net/if_inet6
diff --git a/tests/inet_socket/ipsec-load b/tests/inet_socket/ipsec-load
index 21e2dfe..e286de3 100644
--- a/tests/inet_socket/ipsec-load
+++ b/tests/inet_socket/ipsec-load
@@ -10,8 +10,12 @@ ip xfrm state add src 127.0.0.1 dst 127.0.0.1 proto ah spi 0x250 ctx $badclientc
 ip xfrm policy add src 127.0.0.1 dst 127.0.0.1 proto tcp dir out ctx "system_u:object_r:test_spd_t:s0" tmpl proto ah mode transport level required
 ip xfrm policy add src 127.0.0.1 dst 127.0.0.1 proto udp dir out ctx "system_u:object_r:test_spd_t:s0" tmpl proto ah mode transport level required
 
+SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
+if "$HAS_IPV6"; then
 # IPv6 loopback
 ip xfrm state add src ::1 dst ::1 proto ah spi 0x200 ctx $goodclientcon auth sha1 0123456789012345
 ip xfrm state add src ::1 dst ::1 proto ah spi 0x250 ctx $badclientcon auth sha1 0123456789012345
 ip xfrm policy add src ::1 dst ::1 proto tcp dir out ctx "system_u:object_r:test_spd_t:s0" tmpl proto ah mode transport level required
 ip xfrm policy add src ::1 dst ::1 proto udp dir out ctx "system_u:object_r:test_spd_t:s0" tmpl proto ah mode transport level required
+fi
diff --git a/tests/inet_socket/iptables-flush b/tests/inet_socket/iptables-flush
index c168d89..198bb85 100644
--- a/tests/inet_socket/iptables-flush
+++ b/tests/inet_socket/iptables-flush
@@ -1,6 +1,11 @@
 #!/bin/sh
+SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
+
 # Flush the security table.
 iptables -t security -F
-iptables -t security -X NEWCONN
+iptables -t security -X NEWCONN 2>/dev/null
+if "$HAS_IPV6"; then
 ip6tables -t security -F
-ip6tables -t security -X NEWCONN
+ip6tables -t security -X NEWCONN 2>/dev/null
+fi
diff --git a/tests/inet_socket/iptables-load b/tests/inet_socket/iptables-load
index 5be94f4..d097ed7 100644
--- a/tests/inet_socket/iptables-load
+++ b/tests/inet_socket/iptables-load
@@ -8,6 +8,9 @@
 # - Specified the interface since the tests are only performed over loopback.
 # - Set the port number and context to the values used by the test script and policy.
 
+SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
+
 # Flush the security table.
 iptables -t security -F
 
@@ -28,6 +31,7 @@ iptables -t security -A OUTPUT -m state --state ESTABLISHED,RELATED -j CONNSECMA
 iptables -t security -A INPUT -i lo -p udp --dport 65535 -j SECMARK --selctx system_u:object_r:test_server_packet_t:s0
 iptables -t security -A OUTPUT -o lo -p udp --sport 65535 -j SECMARK --selctx system_u:object_r:test_server_packet_t:s0
 
+if "$HAS_IPV6"; then
 ##### IPv6 entries
 ip6tables -t security -F
 
@@ -47,3 +51,4 @@ ip6tables -t security -A OUTPUT -m state --state ESTABLISHED,RELATED -j CONNSECM
 # Label UDP packets similarly.
 ip6tables -t security -A INPUT -i lo -p udp --dport 65535 -j SECMARK --selctx system_u:object_r:test_server_packet_t:s0
 ip6tables -t security -A OUTPUT -o lo -p udp --sport 65535 -j SECMARK --selctx system_u:object_r:test_server_packet_t:s0
+fi
diff --git a/tests/inet_socket/nftables-flush b/tests/inet_socket/nftables-flush
index 7d62b8d..d0fee0c 100644
--- a/tests/inet_socket/nftables-flush
+++ b/tests/inet_socket/nftables-flush
@@ -1,2 +1 @@
 delete table ip security
-delete table ip6 security
diff --git a/tests/inet_socket/nftables-ipv6-flush b/tests/inet_socket/nftables-ipv6-flush
new file mode 100644
index 0000000..0c9b69a
--- /dev/null
+++ b/tests/inet_socket/nftables-ipv6-flush
@@ -0,0 +1 @@
+delete table ip6 security
diff --git a/tests/inet_socket/nftables-ipv6.load b/tests/inet_socket/nftables-ipv6.load
new file mode 100644
index 0000000..6116343
--- /dev/null
+++ b/tests/inet_socket/nftables-ipv6.load
@@ -0,0 +1,35 @@
+# IPv6 secmark rules for inet_socket tests (loaded only when IPv6 is enabled).
+
+add table ip6 security
+
+table ip6 security {
+
+	secmark inet_server {
+		"system_u:object_r:test_server_packet_t:s0"
+	}
+
+	map secmapping_in_out {
+		type inet_service : secmark
+		elements = { 65535 : "inet_server" }
+	}
+
+	chain input {
+		type filter hook input priority 0;
+
+		ct state new meta secmark set tcp dport map @secmapping_in_out
+		ct state new meta secmark set udp dport map @secmapping_in_out
+		ct state new ct secmark set meta secmark
+
+		ct state established,related meta secmark set ct secmark
+	}
+
+	chain output {
+		type filter hook output priority 0;
+
+		ct state new meta secmark set tcp dport map @secmapping_in_out
+		ct state established meta secmark set udp dport map @secmapping_in_out
+		ct state new ct secmark set meta secmark
+
+		ct state established,related meta secmark set ct secmark
+	}
+}
diff --git a/tests/inet_socket/nftables-load b/tests/inet_socket/nftables-load
index 11ec382..14d6efe 100644
--- a/tests/inet_socket/nftables-load
+++ b/tests/inet_socket/nftables-load
@@ -1,7 +1,8 @@
 # Based on NFT project example. Requires kernel >= 4.20 and nft >= 0.9.3
+#
+# IPv6 rules are in nftables-ipv6.load and loaded only when IPv6 is enabled.
 
 add table ip security
-add table ip6 security
 
 table ip security {
 
@@ -40,35 +41,3 @@ table ip security {
 		ct state established,related meta secmark set ct secmark
 	}
 }
-
-table ip6 security {
-
-	secmark inet_server {
-		"system_u:object_r:test_server_packet_t:s0"
-	}
-
-	map secmapping_in_out {
-		type inet_service : secmark
-		elements = { 65535 : "inet_server" }
-	}
-
-	chain input {
-		type filter hook input priority 0;
-
-		ct state new meta secmark set tcp dport map @secmapping_in_out
-		ct state new meta secmark set udp dport map @secmapping_in_out
-		ct state new ct secmark set meta secmark
-
-		ct state established,related meta secmark set ct secmark
-	}
-
-	chain output {
-		type filter hook output priority 0;
-
-		ct state new meta secmark set tcp dport map @secmapping_in_out
-		ct state established meta secmark set udp dport map @secmapping_in_out
-		ct state new ct secmark set meta secmark
-
-		ct state established,related meta secmark set ct secmark
-	}
-}
diff --git a/tests/inet_socket/server.c b/tests/inet_socket/server.c
index 63b6849..e235f8d 100644
--- a/tests/inet_socket/server.c
+++ b/tests/inet_socket/server.c
@@ -25,8 +25,9 @@
 void usage(char *progname)
 {
 	fprintf(stderr,
-		"usage:  %s [-f file] [-n] protocol port\n"
+		"usage:  %s [-4] [-f file] [-n] protocol port\n"
 		"\nWhere:\n\t"
+		"-4        Listen on IPv4 addresses only.\n\t"
 		"-f        Write a line to the file when listening starts.\n\t"
 		"-n        No peer context will be available therefore send\n\t"
 		"          \"nopeer\" message to client, otherwise the peer context\n\t"
@@ -43,11 +44,14 @@ int main(int argc, char **argv)
 	struct sockaddr_storage sin;
 	struct addrinfo hints, *res;
 	char byte;
-	bool nopeer = false;
+	bool nopeer = false, ipv4 = false;
 	char *flag_file = NULL;
 
-	while ((opt = getopt(argc, argv, "f:n")) != -1) {
+	while ((opt = getopt(argc, argv, "4f:n")) != -1) {
 		switch (opt) {
+		case '4':
+			ipv4 = true;
+			break;
 		case 'f':
 			flag_file = optarg;
 			break;
@@ -64,7 +68,7 @@ int main(int argc, char **argv)
 
 	memset(&hints, 0, sizeof(struct addrinfo));
 	hints.ai_flags = AI_PASSIVE;
-	hints.ai_family = AF_INET6;
+	hints.ai_family = ipv4 ? AF_INET : AF_INET6;
 
 	if (!strcmp(argv[optind], "tcp")) {
 		hints.ai_socktype = SOCK_STREAM;
diff --git a/tests/inet_socket/test b/tests/inet_socket/test
index 9f846bd..3a1c992 100755
--- a/tests/inet_socket/test
+++ b/tests/inet_socket/test
@@ -63,6 +63,25 @@ BEGIN {
         $test_nft = 1;
     }
 
+    # Determine if IPv6 is enabled on loopback.
+    $test_ipv6 = system("$basedir/../has_ipv6") == 0 ? 1 : 0;
+
+    if ( !$test_ipv6 ) {
+        if ($test_ipsec) {
+            $test_count -= 2;
+        }
+        if ($test_calipso) {
+            $test_count -= $is_stream ? 3 : 2;
+            $test_calipso = 0;
+        }
+        if ($test_iptables) {
+            $test_count -= 2;
+        }
+        if ($test_nft) {
+            $test_count -= 2;
+        }
+    }
+
     plan tests => $test_count;
 }
 
@@ -70,6 +89,8 @@ sub server_start {
     my ( $runcon_args, $args ) = @_;
     my $pid;
 
+    $args = "-4 $args" unless $test_ipv6;
+
     system("mkfifo $basedir/flag");
 
     if ( ( $pid = fork() ) == 0 ) {
@@ -340,7 +361,7 @@ if ($test_ipsec) {
 "runcon -t test_inet_bad_client_t -- $basedir/client $proto 127.0.0.1 65535 2>&1";
     ok( $result >> 8 eq $fail_value2 );
 
-    if ($is_stream) {
+    if ( $is_stream && $test_ipv6 ) {
 
         # Verify that authorized client can communicate with the server.
         $result =
@@ -349,15 +370,18 @@ if ($test_ipsec) {
         ok( $result eq 0 );
     }
 
-    # Verify that unauthorized client cannot communicate with the server.
-    $result = system
+    if ($test_ipv6) {
+
+        # Verify that unauthorized client cannot communicate with the server.
+        $result = system
 "runcon -t test_inet_bad_client_t -- $basedir/client $proto ::1 65535 2>&1";
-    ok( $result >> 8 eq $fail_value2 );
+        ok( $result >> 8 eq $fail_value2 );
+    }
 
     # Kill the server.
     server_end($pid);
 
-    if ( not $is_stream ) {
+    if ( !$is_stream && $test_ipv6 ) {
 
    # Start the server for IPSEC test using IPv6 but do not request peer context.
         $pid = server_start( "-t test_inet_server_t", "-n $proto 65535" );
@@ -393,15 +417,18 @@ sub test_tables {
 "runcon -t test_inet_bad_client_t -- $basedir/client -e nopeer $proto 127.0.0.1 65535 2>&1";
     ok( $result >> 8 eq $fail_value2 );
 
-    # Verify that authorized client can communicate with the server.
-    $result = system
+    if ($test_ipv6) {
+
+        # Verify that authorized client can communicate with the server.
+        $result = system
 "runcon -t test_inet_client_t -- $basedir/client -e nopeer $proto ::1 65535";
-    ok( $result eq 0 );
+        ok( $result eq 0 );
 
-    # Verify that unauthorized client cannot communicate with the server.
-    $result = system
+        # Verify that unauthorized client cannot communicate with the server.
+        $result = system
 "runcon -t test_inet_bad_client_t -- $basedir/client -e nopeer $proto ::1 65535 2>&1";
-    ok( $result >> 8 eq $fail_value2 );
+        ok( $result >> 8 eq $fail_value2 );
+    }
 
     # Kill the server.
     server_end($pid);
@@ -417,7 +444,9 @@ if ($test_iptables) {
 if ($test_nft) {
     print "Testing nftables (IPv4/IPv6).\n";
     system "nft -f $basedir/nftables-load";
+    system "nft -f $basedir/nftables-ipv6.load" if $test_ipv6;
     test_tables();
+    system "nft -f $basedir/nftables-ipv6-flush" if $test_ipv6;
     system "nft -f $basedir/nftables-flush";
 }
 
diff --git a/tests/sctp/fb-deny-label-flush b/tests/sctp/fb-deny-label-flush
index 059e0b7..41e76e6 100644
--- a/tests/sctp/fb-deny-label-flush
+++ b/tests/sctp/fb-deny-label-flush
@@ -1,6 +1,11 @@
 #!/bin/sh
 
+SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
+
 netlabelctl map del default
 netlabelctl map add default protocol:unlbl
 netlabelctl unlbl del interface:lo address:127.0.0.0/8 label:system_u:object_r:netlabel_sctp_peer_t:s0
+if "$HAS_IPV6"; then
 netlabelctl unlbl del interface:lo address:::1/128 label:system_u:object_r:deny_assoc_sctp_peer_t:s0
+fi
diff --git a/tests/sctp/fb-deny-label-load b/tests/sctp/fb-deny-label-load
index 7c0bd87..647399b 100644
--- a/tests/sctp/fb-deny-label-load
+++ b/tests/sctp/fb-deny-label-load
@@ -1,7 +1,14 @@
 #!/bin/sh
 
+SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
+
 netlabelctl map del default
 netlabelctl map add default address:0.0.0.0/0 protocol:unlbl
+if "$HAS_IPV6"; then
 netlabelctl map add default address:::/0 protocol:unlbl
+fi
 netlabelctl unlbl add interface:lo address:127.0.0.0/8 label:system_u:object_r:netlabel_sctp_peer_t:s0
+if "$HAS_IPV6"; then
 netlabelctl unlbl add interface:lo address:::1/128 label:system_u:object_r:deny_assoc_sctp_peer_t:s0
+fi
diff --git a/tests/sctp/fb-label-flush b/tests/sctp/fb-label-flush
index 13573a8..c1ceeb5 100644
--- a/tests/sctp/fb-label-flush
+++ b/tests/sctp/fb-label-flush
@@ -1,6 +1,11 @@
 #!/bin/sh
 
+SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
+
 netlabelctl map del default
 netlabelctl map add default protocol:unlbl
 netlabelctl unlbl del interface:lo address:127.0.0.0/8 label:system_u:object_r:netlabel_sctp_peer_t:s0
+if "$HAS_IPV6"; then
 netlabelctl unlbl del interface:lo address:::1/128 label:system_u:object_r:netlabel_sctp_peer_t:s0
+fi
diff --git a/tests/sctp/fb-label-load b/tests/sctp/fb-label-load
index a501515..065ec34 100644
--- a/tests/sctp/fb-label-load
+++ b/tests/sctp/fb-label-load
@@ -1,8 +1,15 @@
 #!/bin/sh
 
+SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
+
 netlabelctl map del default
 netlabelctl map add default address:0.0.0.0/0 protocol:unlbl
+if "$HAS_IPV6"; then
 netlabelctl map add default address:::/0 protocol:unlbl
+fi
 netlabelctl unlbl add interface:lo address:127.0.0.0/8 label:system_u:object_r:netlabel_sctp_peer_t:s0
+if "$HAS_IPV6"; then
 netlabelctl unlbl add interface:lo address:::1/128 label:system_u:object_r:netlabel_sctp_peer_t:s0
+fi
 #netlabelctl -p unlbl list
diff --git a/tests/sctp/iptables-flush b/tests/sctp/iptables-flush
index e74271a..112ae79 100644
--- a/tests/sctp/iptables-flush
+++ b/tests/sctp/iptables-flush
@@ -1,4 +1,9 @@
 #!/bin/sh
 # Flush the security table after IPv4 and IPv6 tests.
+SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
+
 iptables -t security -F
+if "$HAS_IPV6"; then
 ip6tables -t security -F
+fi
diff --git a/tests/sctp/iptables-load b/tests/sctp/iptables-load
index 9dac576..1a91e19 100644
--- a/tests/sctp/iptables-load
+++ b/tests/sctp/iptables-load
@@ -1,9 +1,14 @@
 #!/bin/sh
 ############################ SECMARK IPTABLE ENTRIES ########################
 #
+SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
+
 # Flush the security table first:
 iptables -t security -F
+if "$HAS_IPV6"; then
 ip6tables -t security -F
+fi
 
 #-------------- INPUT IP Stream --------------------#
 # These rules will replace the above context if sctp ports 1024:1035 are found in the packets:
@@ -11,9 +16,11 @@ iptables -t security -A INPUT -i lo -p sctp -m multiport --port 1024:1035 -j SEC
 
 iptables -t security -A INPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --save
 
+if "$HAS_IPV6"; then
 ip6tables -t security -A INPUT -i lo -p sctp -m multiport --port 1024:1035 -j SECMARK --selctx system_u:object_r:test_sctp_server_packet_t:s0
 
 ip6tables -t security -A INPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --save
+fi
 
 #-------------- OUTPUT IP Stream --------------------#
 # These rules will replace the above context if sctp ports 1024:1035 are found in the packets:
@@ -21,7 +28,9 @@ iptables -t security -A OUTPUT -o lo -p sctp -m multiport --port 1024:1035 -j SE
 
 iptables -t security -A OUTPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --save
 
+if "$HAS_IPV6"; then
 ip6tables -t security -A OUTPUT -o lo -p sctp -m multiport --port 1024:1035 -j SECMARK --selctx system_u:object_r:test_sctp_server_packet_t:s0
 
 ip6tables -t security -A OUTPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --save
+fi
 
diff --git a/tests/sctp/nftables-flush b/tests/sctp/nftables-flush
index 7d62b8d..d0fee0c 100644
--- a/tests/sctp/nftables-flush
+++ b/tests/sctp/nftables-flush
@@ -1,2 +1 @@
 delete table ip security
-delete table ip6 security
diff --git a/tests/sctp/nftables-ipv6-flush b/tests/sctp/nftables-ipv6-flush
new file mode 100644
index 0000000..0c9b69a
--- /dev/null
+++ b/tests/sctp/nftables-ipv6-flush
@@ -0,0 +1 @@
+delete table ip6 security
diff --git a/tests/sctp/nftables-ipv6.load b/tests/sctp/nftables-ipv6.load
new file mode 100644
index 0000000..1268140
--- /dev/null
+++ b/tests/sctp/nftables-ipv6.load
@@ -0,0 +1,33 @@
+# IPv6 secmark rules for SCTP tests (loaded only when IPv6 is enabled).
+
+add table ip6 security
+
+table ip6 security {
+
+	secmark sctp_server {
+		"system_u:object_r:test_sctp_server_packet_t:s0"
+	}
+
+	map secmapping_in_out {
+		type inet_service : secmark
+		elements = { 1035 : "sctp_server" }
+	}
+
+	chain input {
+		type filter hook input priority 0;
+
+		ct state new meta secmark set sctp dport map @secmapping_in_out
+		ct state new ct secmark set meta secmark
+
+		ct state established,related meta secmark set ct secmark
+	}
+
+	chain output {
+		type filter hook output priority 0;
+
+		ct state new meta secmark set sctp dport map @secmapping_in_out
+		ct state new ct secmark set meta secmark
+
+		ct state established,related meta secmark set ct secmark
+	}
+}
diff --git a/tests/sctp/nftables-load b/tests/sctp/nftables-load
index 2cac3bb..56803b6 100644
--- a/tests/sctp/nftables-load
+++ b/tests/sctp/nftables-load
@@ -1,7 +1,8 @@
 # Based on NFT project example. Requires kernel >= 4.20 and nft >= 0.9.3
+#
+# IPv6 rules are in nftables-ipv6.load and loaded only when IPv6 is enabled.
 
 add table ip security
-add table ip6 security
 
 table ip security {
 
@@ -36,33 +37,3 @@ table ip security {
 		ct state established,related meta secmark set ct secmark
 	}
 }
-
-table ip6 security {
-
-	secmark sctp_server {
-		"system_u:object_r:test_sctp_server_packet_t:s0"
-	}
-
-	map secmapping_in_out {
-		type inet_service : secmark
-		elements = { 1035 : "sctp_server" }
-	}
-
-	chain input {
-		type filter hook input priority 0;
-
-		ct state new meta secmark set sctp dport map @secmapping_in_out
-		ct state new ct secmark set meta secmark
-
-		ct state established,related meta secmark set ct secmark
-	}
-
-	chain output {
-		type filter hook output priority 0;
-
-		ct state new meta secmark set sctp dport map @secmapping_in_out
-		ct state new ct secmark set meta secmark
-
-		ct state established,related meta secmark set ct secmark
-	}
-}
diff --git a/tests/sctp/sctp_bindx.c b/tests/sctp/sctp_bindx.c
index 74bf985..a37a458 100644
--- a/tests/sctp/sctp_bindx.c
+++ b/tests/sctp/sctp_bindx.c
@@ -3,8 +3,9 @@
 static void usage(char *progname)
 {
 	fprintf(stderr,
-		"usage:  %s [-r] [-v] stream|seq port\n"
+		"usage:  %s [-4] [-r] [-v] stream|seq port\n"
 		"\nWhere:\n\t"
+		"-4      Use two IPv4 loopback addresses.\n\t"
 		"-r      After two bindx ADDs, remove one with bindx REM.\n\t"
 		"-v      Print context information.\n\t"
 		"        The default is to add IPv4 and IPv6 loopback addrs.\n\t"
@@ -17,15 +18,19 @@ static void usage(char *progname)
 int main(int argc, char **argv)
 {
 	int opt, type, sock, result;
-	struct sockaddr_in ipv4;
+	struct sockaddr_in ipv4, ipv4_extra;
+	struct sockaddr *extra_addr;
 	struct sockaddr_in6 ipv6;
 	unsigned short port;
-	bool rem = false;
+	bool rem = false, ipv4_only = false;
 	bool verbose = false;
 	char *context;
 
-	while ((opt = getopt(argc, argv, "rv")) != -1) {
+	while ((opt = getopt(argc, argv, "4rv")) != -1) {
 		switch (opt) {
+		case '4':
+			ipv4_only = true;
+			break;
 		case 'v':
 			verbose = true;
 			break;
@@ -58,7 +63,7 @@ int main(int argc, char **argv)
 		free(context);
 	}
 
-	sock = socket(PF_INET6, type, IPPROTO_SCTP);
+	sock = socket(ipv4_only ? PF_INET : PF_INET6, type, IPPROTO_SCTP);
 	if (sock < 0) {
 		perror("socket");
 		exit(1);
@@ -88,19 +93,27 @@ int main(int argc, char **argv)
 	ipv6.sin6_port = htons(port);
 	ipv6.sin6_addr = in6addr_loopback;
 
-	result = sctp_bindx(sock, (struct sockaddr *)&ipv6, 1,
+	if (ipv4_only) {
+		ipv4_extra = ipv4;
+		ipv4_extra.sin_addr.s_addr = htonl(0x7f000002);
+		extra_addr = (struct sockaddr *)&ipv4_extra;
+	} else {
+		extra_addr = (struct sockaddr *)&ipv6;
+	}
+
+	result = sctp_bindx(sock, extra_addr, 1,
 			    SCTP_BINDX_ADD_ADDR);
 	if (result < 0) {
-		perror("sctp_bindx ADD - ipv6");
+		perror("sctp_bindx ADD - second address");
 		close(sock);
 		exit(3);
 	}
 
 	if (verbose)
-		printf("sctp_bindx ADD - ipv6\n");
+		printf("sctp_bindx ADD - %s\n", ipv4_only ? "127.0.0.2" : "::1");
 
 	if (rem) {
-		result = sctp_bindx(sock, (struct sockaddr *)&ipv6, 1,
+		result = sctp_bindx(sock, extra_addr, 1,
 				    SCTP_BINDX_REM_ADDR);
 		if (result < 0) {
 			perror("sctp_bindx - REM");
@@ -108,7 +121,7 @@ int main(int argc, char **argv)
 			exit(4);
 		}
 		if (verbose)
-			printf("sctp_bindx REM - ipv6\n");
+			printf("sctp_bindx REM - %s\n", ipv4_only ? "127.0.0.2" : "::1");
 	}
 
 	close(sock);
diff --git a/tests/sctp/test b/tests/sctp/test
index 5626ab8..21b636e 100755
--- a/tests/sctp/test
+++ b/tests/sctp/test
@@ -104,6 +104,27 @@ BEGIN {
             $test_count += 8;
             $test_nft = 1;
         }
+
+        # Determine if IPv6 is enabled on loopback.
+        $test_ipv6 = system("$basedir/../has_ipv6") == 0 ? 1 : 0;
+
+        if ( !$test_ipv6 ) {
+            $test_count -= 12;
+
+            if ($test_calipso) {
+                $test_count -= 13;
+                if ($test_clpeeloff) {
+                    $test_count -= 6;
+                }
+                $test_calipso = 0;
+            }
+            if ($test_iptables) {
+                $test_count -= 4;
+            }
+            if ($test_nft) {
+                $test_count -= 4;
+            }
+        }
     }
 
     plan tests => $test_count;
@@ -113,6 +134,13 @@ sub server_start {
     my ( $runcon_args, $prog, $args ) = @_;
     my $pid;
 
+    # Select the family before entering the confined server domain.
+    if ( !$test_ipv6
+        && ( $prog eq "sctp_server" || $prog eq "sctp_peeloff_server" ) )
+    {
+        $args = "-4 $args";
+    }
+
     system("mkfifo $basedir/flag");
 
     if ( ( $pid = fork() ) == 0 ) {
@@ -164,16 +192,19 @@ $result = system
 "runcon -t test_sctp_client_t $basedir/sctp_client $v -n -e nopeer seq 127.0.0.1 1035";
 ok( $result eq 0 );
 
-# Verify that authorized client can communicate with the server SEQ->STREAM.
-$result = system
-  "runcon -t test_sctp_client_t $basedir/sctp_client $v -e nopeer seq ::1 1035";
-ok( $result eq 0 );
+if ($test_ipv6) {
+
+    # Verify that authorized client can communicate with the server SEQ->STREAM.
+    $result = system
+"runcon -t test_sctp_client_t $basedir/sctp_client $v -e nopeer seq ::1 1035";
+    ok( $result eq 0 );
 
 # Verify that the client cannot communicate with server when using port < 1024 STREAM->STREAM.
 # deny sctp_socket { name_connect }
-$result = system
+    $result = system
 "runcon -t test_sctp_client_t -- $basedir/sctp_client $v -e nopeer stream ::1 1023 2>&1";
-ok( $result >> 8 eq 8 );
+    ok( $result >> 8 eq 8 );
+}
 
 # Kill the stream server.
 server_end($pid);
@@ -194,15 +225,17 @@ $result = system
 "runcon -t test_sctp_connectx_t $basedir/sctp_connectx $v stream 127.0.0.1 1035";
 ok( $result eq 0 );
 
-$result =
-  system
-  "runcon -t test_sctp_connectx_t $basedir/sctp_connectx $v seq ::1 1035";
-ok( $result eq 0 );
+if ($test_ipv6) {
+    $result =
+      system
+      "runcon -t test_sctp_connectx_t $basedir/sctp_connectx $v seq ::1 1035";
+    ok( $result eq 0 );
 
-$result =
-  system
+    $result =
+      system
 "runcon -t test_sctp_deny_connectx_t $basedir/sctp_connectx $v seq ::1 1035 2>&1";
-ok( $result >> 8 eq 7 );
+    ok( $result >> 8 eq 7 );
+}
 
 #
 ########################### SCTP_SENDMSG_CONNECT #############################
@@ -215,28 +248,33 @@ $result =
 "runcon -t test_sctp_connectx_t $basedir/sctp_connectx $v -n seq 127.0.0.1 1035";
 ok( $result eq 0 );
 
-$result =
-  system
+if ($test_ipv6) {
+    $result =
+      system
 "runcon -t test_sctp_deny_connectx_t $basedir/sctp_connectx $v -n seq ::1 1035 2>&1";
-ok( $result >> 8 eq 8 );
+    ok( $result >> 8 eq 8 );
+}
 
 #
 ################################ BINDX #######################################
 #
 # net/sctp/socket.c sctp_setsockopt_bindx() SCTP_SOCKOPT_BINDX_ADD
 print "# Testing bindx.\n";
+$bindx_family = $test_ipv6 ? "" : "-4";
 
 $result =
-  system "runcon -t test_sctp_bindx_t $basedir/sctp_bindx $v -r stream 1035";
+  system
+"runcon -t test_sctp_bindx_t $basedir/sctp_bindx $bindx_family $v -r stream 1035";
 ok( $result eq 0 );
 
 $result =
-  system "runcon -t test_sctp_bindx_t $basedir/sctp_bindx $v -r seq 1035";
+  system
+"runcon -t test_sctp_bindx_t $basedir/sctp_bindx $bindx_family $v -r seq 1035";
 ok( $result eq 0 );
 
 $result =
   system
-  "runcon -t test_sctp_deny_bindx_t $basedir/sctp_bindx $v -r seq 1035 2>&1";
+"runcon -t test_sctp_deny_bindx_t $basedir/sctp_bindx $bindx_family $v -r seq 1035 2>&1";
 ok( $result >> 8 eq 2 );
 
 #
@@ -351,30 +389,33 @@ server_end($pid);
 # Start seq server.
 $pid = server_start( "-t test_sctp_server_t", "sctp_server", "$v seq 1035" );
 
-# Verify that authorized client can communicate with the server SEQ->SEQ.
-$result = system
+if ($test_ipv6) {
+
+    # Verify that authorized client can communicate with the server SEQ->SEQ.
+    $result = system
 "runcon -t test_sctp_client_t $basedir/sctp_client $v -e system_u:object_r:netlabel_sctp_peer_t:s0 seq ::1 1035";
-ok( $result eq 0 );
+    ok( $result eq 0 );
 
-# Verify that authorized client can communicate with the server STREAM->SEQ.
-$result = system
+    # Verify that authorized client can communicate with the server STREAM->SEQ.
+    $result = system
 "runcon -t test_sctp_client_t $basedir/sctp_client $v -e system_u:object_r:netlabel_sctp_peer_t:s0 stream ::1 1035";
-ok( $result eq 0 );
+    ok( $result eq 0 );
 
 # Verify that a client using connect(2) without peer { recv } permission cannot communicate with the server SEQ->SEQ.
-$result = system
+    $result = system
 "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -e system_u:object_r:netlabel_sctp_peer_t:s0 seq ::1 1035 2>&1";
-ok( $result >> 8 eq 6 );
+    ok( $result >> 8 eq 6 );
 
 # Verify that a client using sctp_connectx(3) without peer { recv } permission cannot communicate with the server SEQ->SEQ.
-$result = system
+    $result = system
 "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -x -e system_u:object_r:netlabel_sctp_peer_t:s0 seq ::1 1035 2>&1";
-ok( $result >> 8 eq 6 );
+    ok( $result >> 8 eq 6 );
 
 # Verify that a client not using any connect without peer { recv } permission cannot communicate with the server SEQ->SEQ.
-$result = system
+    $result = system
 "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -n -e system_u:object_r:netlabel_sctp_peer_t:s0 seq ::1 1035 2>&1";
-ok( $result >> 8 eq 13 );
+    ok( $result >> 8 eq 13 );
+}
 
 # Kill the seq server.
 server_end($pid);
@@ -396,10 +437,13 @@ $result = system
 "runcon -t test_sctp_client_t $basedir/sctp_client $v -e system_u:object_r:netlabel_sctp_peer_t:s0 stream 127.0.0.1 1035";
 ok( $result eq 0 );
 
+if ($test_ipv6) {
+
 # Verify that the server is denied this association as the client will timeout on connect.
-$result = system
+    $result = system
 "runcon -t test_sctp_client_t -- $basedir/sctp_client $v -e system_u:object_r:deny_assoc_sctp_peer_t:s0 stream ::1 1035 2>&1";
-ok( $result >> 8 eq 6 );
+    ok( $result >> 8 eq 6 );
+}
 
 # Kill the seq server.
 server_end($pid);
@@ -1141,15 +1185,18 @@ sub test_tables {
 "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -e nopeer stream 127.0.0.1 1035 2>&1";
     ok( $result >> 8 eq 6 );
 
+    if ($test_ipv6) {
+
  # Verify that authorized client can communicate with the server STREAM->STREAM.
-    $result = system
+        $result = system
 "runcon -t test_sctp_client_t $basedir/sctp_client $v -e nopeer stream ::1 1035";
-    ok( $result eq 0 );
+        ok( $result eq 0 );
 
 # Verify that a client without packet { recv } permission cannot communicate with the server STREAM->STREAM.
-    $result = system
+        $result = system
 "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -e nopeer stream ::1 1035 2>&1";
-    ok( $result >> 8 eq 6 );
+        ok( $result >> 8 eq 6 );
+    }
 
     # Kill the stream server.
     server_end($pid);
@@ -1168,15 +1215,18 @@ sub test_tables {
 "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -e nopeer seq 127.0.0.1 1035 2>&1";
     ok( $result >> 8 eq 6 );
 
-    # Verify that authorized client can communicate with the server SEQ->SEQ.
-    $result = system
+    if ($test_ipv6) {
+
+       # Verify that authorized client can communicate with the server SEQ->SEQ.
+        $result = system
 "runcon -t test_sctp_client_t $basedir/sctp_client $v -e nopeer seq ::1 1035";
-    ok( $result eq 0 );
+        ok( $result eq 0 );
 
 # Verify that a client without packet { recv } permission cannot communicate with the server SEQ->SEQ.
-    $result = system
+        $result = system
 "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -e nopeer seq ::1 1035 2>&1";
-    ok( $result >> 8 eq 6 );
+        ok( $result >> 8 eq 6 );
+    }
 
     # Kill the seq server.
     server_end($pid);
@@ -1192,7 +1242,9 @@ if ($test_iptables) {
 if ($test_nft) {
     print "# Testing nftables (IPv4/IPv6).\n";
     system "nft -f $basedir/nftables-load";
+    system "nft -f $basedir/nftables-ipv6.load" if $test_ipv6;
     test_tables();
+    system "nft -f $basedir/nftables-ipv6-flush" if $test_ipv6;
     system "nft -f $basedir/nftables-flush";
 }
 
diff --git a/tmt/tests.fmf b/tmt/tests.fmf
index 08bd129..c9be59d 100644
--- a/tmt/tests.fmf
+++ b/tmt/tests.fmf
@@ -121,8 +121,6 @@
     - xfsprogs-devel
     - libuuid-devel
     - e2fsprogs
-    - f2fs-tools
-    - jfsutils
     - dosfstools
     - btrfs-progs
     - rdma-core-devel
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH] tests: make IPv6 subtests optional on IPv4-only systems
  2026-10-01 15:36 ` Brian Grech
@ 2026-10-02 15:01   ` Stephen Smalley
  2026-10-05 13:31     ` Brian Grech
  0 siblings, 1 reply; 7+ messages in thread
From: Stephen Smalley @ 2026-10-02 15:01 UTC (permalink / raw)
  To: Brian Grech; +Cc: selinux, jonderka

On Thu, Oct 1, 2026 at 11:36 AM Brian Grech <bgrech@redhat.com> wrote:
>
> Skip or adapt IPv6-dependent subtests when the running system does not
> have usable IPv6 on loopback.
>

> - Add ipv6_enabled() to sctp_common for C helpers and SCTP bindx paths.

This isn't in the diff, possible leftover from prior version.

> Signed-off-by: Jan Onderka <jonderka@redhat.com>
>
> Co-developed-by: Jan Onderka <jonderka@redhat.com>
> Signed-off-by: Brian Grech <bgrech@redhat.com>

Normally Co-developed-by: would come first, then both Signed-off-by:
lines, with no empty lines in between them.

> diff --git a/tests/sctp/test b/tests/sctp/test
> index 5626ab8..21b636e 100755
> --- a/tests/sctp/test
> +++ b/tests/sctp/test
> @@ -104,6 +104,27 @@ BEGIN {
>              $test_count += 8;
>              $test_nft = 1;
>          }
> +
> +        # Determine if IPv6 is enabled on loopback.
> +        $test_ipv6 = system("$basedir/../has_ipv6") == 0 ? 1 : 0;
> +
> +        if ( !$test_ipv6 ) {
> +            $test_count -= 12;

I count 11 ok() calls wrapped by if ($test_ipv6) outside of the
calipso/iptables/nft blocks 2 in the base-config block, 2 in connectx,
1 in sendmsg_connect, 5 in the fb-label seq-server block, 1 in the
fb-deny-label block), so this over-subtracted by one. On an IPv4-only
system Test::More will report "planned N but ran N+1" and fail the
whole file.

> diff --git a/tmt/tests.fmf b/tmt/tests.fmf
> index 08bd129..c9be59d 100644
> --- a/tmt/tests.fmf
> +++ b/tmt/tests.fmf
> @@ -121,8 +121,6 @@
>      - xfsprogs-devel
>      - libuuid-devel
>      - e2fsprogs
> -    - f2fs-tools
> -    - jfsutils
>      - dosfstools
>      - btrfs-progs
>      - rdma-core-devel

This doesn't belong in this patch.

Also, please re-base on your next version since it no longer applies
cleanly to latest main branch.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH] tests: make IPv6 subtests optional on IPv4-only systems
  2026-10-02 15:01   ` Stephen Smalley
@ 2026-10-05 13:31     ` Brian Grech
  2026-10-05 14:41       ` Stephen Smalley
  0 siblings, 1 reply; 7+ messages in thread
From: Brian Grech @ 2026-10-05 13:31 UTC (permalink / raw)
  To: stephen.smalley.work; +Cc: bgrech, jonderka, selinux

Skip or adapt IPv6-dependent subtests (inet_socket, extended_socket_class,
sctp) when the system has no usable IPv6 on loopback, instead of
assuming ::1 and ip6tables always work.

- Add tests/has_ipv6, checking /proc/net/if_inet6 and disable_ipv6
  sysctls.
- Gate IPv6-only cases behind $test_ipv6 and adjust test counts.
- inet_socket/server.c falls back to AF_INET when IPv6 is absent.
- Split IPv6 firewall rules into nftables-ipv6.load, invoked only when
  has_ipv6 succeeds.
- Select address family via has_ipv6 before entering confined test
  domains, rather than probing IPv6 from inside them: that probe can
  itself be denied by policy, silently selecting IPv4 while the runner
  keeps executing IPv6-only cases.

Co-developed-by: Jan Onderka <jonderka@redhat.com>
Signed-off-by: Jan Onderka <jonderka@redhat.com>
Signed-off-by: Brian Grech <bgrech@redhat.com>
---
 tests/extended_socket_class/test      |  61 +++++++-----
 tests/has_ipv6                        |  23 +++++
 tests/inet_socket/ipsec-load          |   4 +
 tests/inet_socket/iptables-flush      |   9 +-
 tests/inet_socket/iptables-load       |   5 +
 tests/inet_socket/nftables-flush      |   1 -
 tests/inet_socket/nftables-ipv6-flush |   1 +
 tests/inet_socket/nftables-ipv6.load  |  35 +++++++
 tests/inet_socket/nftables-load       |  35 +------
 tests/inet_socket/server.c            |  12 ++-
 tests/inet_socket/test                |  51 +++++++---
 tests/sctp/fb-deny-label-flush        |   5 +
 tests/sctp/fb-deny-label-load         |   7 ++
 tests/sctp/fb-label-flush             |   5 +
 tests/sctp/fb-label-load              |   7 ++
 tests/sctp/iptables-flush             |   5 +
 tests/sctp/iptables-load              |   9 ++
 tests/sctp/nftables-flush             |   1 -
 tests/sctp/nftables-ipv6-flush        |   1 +
 tests/sctp/nftables-ipv6.load         |  33 +++++++
 tests/sctp/nftables-load              |  33 +------
 tests/sctp/sctp_bindx.c               |  33 +++++--
 tests/sctp/test                       | 136 ++++++++++++++++++--------
 23 files changed, 355 insertions(+), 157 deletions(-)
 create mode 100755 tests/has_ipv6
 create mode 100644 tests/inet_socket/nftables-ipv6-flush
 create mode 100644 tests/inet_socket/nftables-ipv6.load
 create mode 100644 tests/sctp/nftables-ipv6-flush
 create mode 100644 tests/sctp/nftables-ipv6.load

diff --git a/tests/extended_socket_class/test b/tests/extended_socket_class/test
index f85243a..a449b74 100755
--- a/tests/extended_socket_class/test
+++ b/tests/extended_socket_class/test
@@ -33,6 +33,17 @@ BEGIN {
         $test_alg = 1;
     }
 
+    # Determine if IPv6 is enabled on loopback.
+    my $testdir = $0;
+    $testdir =~ s|(.*)/[^/]*|$1|;
+    $test_ipv6 = system("$testdir/../has_ipv6") == 0 ? 1 : 0;
+    if ( !$test_ipv6 ) {
+        $test_count -= 2;
+        if ($test_sctp) {
+            $test_count -= 4;
+        }
+    }
+
     plan tests => $test_count;
 }
 
@@ -53,17 +64,20 @@ $result = system(
 );
 ok($result);
 
-# Verify that test_icmp_socket_t can create an ICMPv6 socket.
-$result = system(
+if ($test_ipv6) {
+
+    # Verify that test_icmp_socket_t can create an ICMPv6 socket.
+    $result = system(
 "runcon -t test_icmp_socket_t -- $basedir/sockcreate inet6 dgram icmpv6 2>&1"
-);
-ok( $result, 0 );
+    );
+    ok( $result, 0 );
 
-# Verify that test_no_icmp_socket_t cannot create an ICMPv6 socket.
-$result = system(
+    # Verify that test_no_icmp_socket_t cannot create an ICMPv6 socket.
+    $result = system(
 "runcon -t test_no_icmp_socket_t -- $basedir/sockcreate inet6 dgram icmpv6 2>&1"
-);
-ok($result);
+    );
+    ok($result);
+}
 
 # Restore to the kernel defaults - no one allowed to create ICMP sockets.
 system("echo 1 0 > /proc/sys/net/ipv4/ping_group_range");
@@ -94,29 +108,32 @@ if ($test_sctp) {
     );
     ok($result);
 
-    # Verify that test_sctp_socket_t can create an IPv6 stream SCTP socket.
-    $result = system(
+    if ($test_ipv6) {
+
+        # Verify that test_sctp_socket_t can create an IPv6 stream SCTP socket.
+        $result = system(
 "runcon -t test_sctp_socket_t -- $basedir/sockcreate inet6 stream sctp 2>&1"
-    );
-    ok( $result, 0 );
+        );
+        ok( $result, 0 );
 
    # Verify that test_no_sctp_socket_t cannot create an IPv6 stream SCTP socket.
-    $result = system(
+        $result = system(
 "runcon -t test_no_sctp_socket_t -- $basedir/sockcreate inet6 stream sctp 2>&1"
-    );
-    ok($result);
+        );
+        ok($result);
 
-    # Verify that test_sctp_socket_t can create an IPv6 seqpacket SCTP socket.
-    $result = system(
+      # Verify that test_sctp_socket_t can create an IPv6 seqpacket SCTP socket.
+        $result = system(
 "runcon -t test_sctp_socket_t -- $basedir/sockcreate inet6 seqpacket sctp 2>&1"
-    );
-    ok( $result, 0 );
+        );
+        ok( $result, 0 );
 
 # Verify that test_no_sctp_socket_t cannot create an IPv6 seqpacket SCTP socket.
-    $result = system(
+        $result = system(
 "runcon -t test_no_sctp_socket_t -- $basedir/sockcreate inet6 seqpacket sctp 2>&1"
-    );
-    ok($result);
+        );
+        ok($result);
+    }
 }
 
 if ($test_bluetooth) {
diff --git a/tests/has_ipv6 b/tests/has_ipv6
new file mode 100755
index 0000000..1c8061f
--- /dev/null
+++ b/tests/has_ipv6
@@ -0,0 +1,23 @@
+#!/bin/sh
+#
+# Return 0 if IPv6 is enabled and usable on loopback, 1 otherwise.
+#
+# IPv6 may be absent (ipv6.disable=1 on the kernel command line), disabled
+# globally (net.ipv6.conf.all.disable_ipv6=1), or disabled on loopback
+# (net.ipv6.conf.lo.disable_ipv6=1).  Following the LTP tst_net.sh approach,
+# check /proc/net/if_inet6 and the disable_ipv6 sysctls rather than module
+# parameters that may be blocked by SELinux policy.
+
+[ -f /proc/net/if_inet6 ] || exit 1
+
+disabled=$(sysctl -n net.ipv6.conf.all.disable_ipv6 2>/dev/null) || exit 1
+[ "$disabled" = 1 ] && exit 1
+
+disabled=$(sysctl -n net.ipv6.conf.lo.disable_ipv6 2>/dev/null) || exit 1
+[ "$disabled" = 1 ] && exit 1
+
+# An existing proc file does not guarantee that ::1 is configured on lo.
+awk '$1 == "00000000000000000000000000000001" && $6 == "lo" {
+    found = 1
+}
+END { exit !found }' /proc/net/if_inet6
diff --git a/tests/inet_socket/ipsec-load b/tests/inet_socket/ipsec-load
index 21e2dfe..e286de3 100644
--- a/tests/inet_socket/ipsec-load
+++ b/tests/inet_socket/ipsec-load
@@ -10,8 +10,12 @@ ip xfrm state add src 127.0.0.1 dst 127.0.0.1 proto ah spi 0x250 ctx $badclientc
 ip xfrm policy add src 127.0.0.1 dst 127.0.0.1 proto tcp dir out ctx "system_u:object_r:test_spd_t:s0" tmpl proto ah mode transport level required
 ip xfrm policy add src 127.0.0.1 dst 127.0.0.1 proto udp dir out ctx "system_u:object_r:test_spd_t:s0" tmpl proto ah mode transport level required
 
+SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
+if "$HAS_IPV6"; then
 # IPv6 loopback
 ip xfrm state add src ::1 dst ::1 proto ah spi 0x200 ctx $goodclientcon auth sha1 0123456789012345
 ip xfrm state add src ::1 dst ::1 proto ah spi 0x250 ctx $badclientcon auth sha1 0123456789012345
 ip xfrm policy add src ::1 dst ::1 proto tcp dir out ctx "system_u:object_r:test_spd_t:s0" tmpl proto ah mode transport level required
 ip xfrm policy add src ::1 dst ::1 proto udp dir out ctx "system_u:object_r:test_spd_t:s0" tmpl proto ah mode transport level required
+fi
diff --git a/tests/inet_socket/iptables-flush b/tests/inet_socket/iptables-flush
index c168d89..198bb85 100644
--- a/tests/inet_socket/iptables-flush
+++ b/tests/inet_socket/iptables-flush
@@ -1,6 +1,11 @@
 #!/bin/sh
+SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
+
 # Flush the security table.
 iptables -t security -F
-iptables -t security -X NEWCONN
+iptables -t security -X NEWCONN 2>/dev/null
+if "$HAS_IPV6"; then
 ip6tables -t security -F
-ip6tables -t security -X NEWCONN
+ip6tables -t security -X NEWCONN 2>/dev/null
+fi
diff --git a/tests/inet_socket/iptables-load b/tests/inet_socket/iptables-load
index 5be94f4..d097ed7 100644
--- a/tests/inet_socket/iptables-load
+++ b/tests/inet_socket/iptables-load
@@ -8,6 +8,9 @@
 # - Specified the interface since the tests are only performed over loopback.
 # - Set the port number and context to the values used by the test script and policy.
 
+SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
+
 # Flush the security table.
 iptables -t security -F
 
@@ -28,6 +31,7 @@ iptables -t security -A OUTPUT -m state --state ESTABLISHED,RELATED -j CONNSECMA
 iptables -t security -A INPUT -i lo -p udp --dport 65535 -j SECMARK --selctx system_u:object_r:test_server_packet_t:s0
 iptables -t security -A OUTPUT -o lo -p udp --sport 65535 -j SECMARK --selctx system_u:object_r:test_server_packet_t:s0
 
+if "$HAS_IPV6"; then
 ##### IPv6 entries
 ip6tables -t security -F
 
@@ -47,3 +51,4 @@ ip6tables -t security -A OUTPUT -m state --state ESTABLISHED,RELATED -j CONNSECM
 # Label UDP packets similarly.
 ip6tables -t security -A INPUT -i lo -p udp --dport 65535 -j SECMARK --selctx system_u:object_r:test_server_packet_t:s0
 ip6tables -t security -A OUTPUT -o lo -p udp --sport 65535 -j SECMARK --selctx system_u:object_r:test_server_packet_t:s0
+fi
diff --git a/tests/inet_socket/nftables-flush b/tests/inet_socket/nftables-flush
index 7d62b8d..d0fee0c 100644
--- a/tests/inet_socket/nftables-flush
+++ b/tests/inet_socket/nftables-flush
@@ -1,2 +1 @@
 delete table ip security
-delete table ip6 security
diff --git a/tests/inet_socket/nftables-ipv6-flush b/tests/inet_socket/nftables-ipv6-flush
new file mode 100644
index 0000000..0c9b69a
--- /dev/null
+++ b/tests/inet_socket/nftables-ipv6-flush
@@ -0,0 +1 @@
+delete table ip6 security
diff --git a/tests/inet_socket/nftables-ipv6.load b/tests/inet_socket/nftables-ipv6.load
new file mode 100644
index 0000000..6116343
--- /dev/null
+++ b/tests/inet_socket/nftables-ipv6.load
@@ -0,0 +1,35 @@
+# IPv6 secmark rules for inet_socket tests (loaded only when IPv6 is enabled).
+
+add table ip6 security
+
+table ip6 security {
+
+	secmark inet_server {
+		"system_u:object_r:test_server_packet_t:s0"
+	}
+
+	map secmapping_in_out {
+		type inet_service : secmark
+		elements = { 65535 : "inet_server" }
+	}
+
+	chain input {
+		type filter hook input priority 0;
+
+		ct state new meta secmark set tcp dport map @secmapping_in_out
+		ct state new meta secmark set udp dport map @secmapping_in_out
+		ct state new ct secmark set meta secmark
+
+		ct state established,related meta secmark set ct secmark
+	}
+
+	chain output {
+		type filter hook output priority 0;
+
+		ct state new meta secmark set tcp dport map @secmapping_in_out
+		ct state established meta secmark set udp dport map @secmapping_in_out
+		ct state new ct secmark set meta secmark
+
+		ct state established,related meta secmark set ct secmark
+	}
+}
diff --git a/tests/inet_socket/nftables-load b/tests/inet_socket/nftables-load
index 11ec382..14d6efe 100644
--- a/tests/inet_socket/nftables-load
+++ b/tests/inet_socket/nftables-load
@@ -1,7 +1,8 @@
 # Based on NFT project example. Requires kernel >= 4.20 and nft >= 0.9.3
+#
+# IPv6 rules are in nftables-ipv6.load and loaded only when IPv6 is enabled.
 
 add table ip security
-add table ip6 security
 
 table ip security {
 
@@ -40,35 +41,3 @@ table ip security {
 		ct state established,related meta secmark set ct secmark
 	}
 }
-
-table ip6 security {
-
-	secmark inet_server {
-		"system_u:object_r:test_server_packet_t:s0"
-	}
-
-	map secmapping_in_out {
-		type inet_service : secmark
-		elements = { 65535 : "inet_server" }
-	}
-
-	chain input {
-		type filter hook input priority 0;
-
-		ct state new meta secmark set tcp dport map @secmapping_in_out
-		ct state new meta secmark set udp dport map @secmapping_in_out
-		ct state new ct secmark set meta secmark
-
-		ct state established,related meta secmark set ct secmark
-	}
-
-	chain output {
-		type filter hook output priority 0;
-
-		ct state new meta secmark set tcp dport map @secmapping_in_out
-		ct state established meta secmark set udp dport map @secmapping_in_out
-		ct state new ct secmark set meta secmark
-
-		ct state established,related meta secmark set ct secmark
-	}
-}
diff --git a/tests/inet_socket/server.c b/tests/inet_socket/server.c
index 63b6849..e235f8d 100644
--- a/tests/inet_socket/server.c
+++ b/tests/inet_socket/server.c
@@ -25,8 +25,9 @@
 void usage(char *progname)
 {
 	fprintf(stderr,
-		"usage:  %s [-f file] [-n] protocol port\n"
+		"usage:  %s [-4] [-f file] [-n] protocol port\n"
 		"\nWhere:\n\t"
+		"-4        Listen on IPv4 addresses only.\n\t"
 		"-f        Write a line to the file when listening starts.\n\t"
 		"-n        No peer context will be available therefore send\n\t"
 		"          \"nopeer\" message to client, otherwise the peer context\n\t"
@@ -43,11 +44,14 @@ int main(int argc, char **argv)
 	struct sockaddr_storage sin;
 	struct addrinfo hints, *res;
 	char byte;
-	bool nopeer = false;
+	bool nopeer = false, ipv4 = false;
 	char *flag_file = NULL;
 
-	while ((opt = getopt(argc, argv, "f:n")) != -1) {
+	while ((opt = getopt(argc, argv, "4f:n")) != -1) {
 		switch (opt) {
+		case '4':
+			ipv4 = true;
+			break;
 		case 'f':
 			flag_file = optarg;
 			break;
@@ -64,7 +68,7 @@ int main(int argc, char **argv)
 
 	memset(&hints, 0, sizeof(struct addrinfo));
 	hints.ai_flags = AI_PASSIVE;
-	hints.ai_family = AF_INET6;
+	hints.ai_family = ipv4 ? AF_INET : AF_INET6;
 
 	if (!strcmp(argv[optind], "tcp")) {
 		hints.ai_socktype = SOCK_STREAM;
diff --git a/tests/inet_socket/test b/tests/inet_socket/test
index 3627f63..1b62842 100755
--- a/tests/inet_socket/test
+++ b/tests/inet_socket/test
@@ -69,6 +69,25 @@ BEGIN {
         $test_nft = 1;
     }
 
+    # Determine if IPv6 is enabled on loopback.
+    $test_ipv6 = system("$basedir/../has_ipv6") == 0 ? 1 : 0;
+
+    if ( !$test_ipv6 ) {
+        if ($test_ipsec) {
+            $test_count -= 2;
+        }
+        if ($test_calipso) {
+            $test_count -= $is_stream ? 3 : 2;
+            $test_calipso = 0;
+        }
+        if ($test_iptables) {
+            $test_count -= 2;
+        }
+        if ($test_nft) {
+            $test_count -= 2;
+        }
+    }
+
     plan tests => $test_count;
 }
 
@@ -76,6 +95,8 @@ sub server_start {
     my ( $runcon_args, $args ) = @_;
     my $pid;
 
+    $args = "-4 $args" unless $test_ipv6;
+
     system("mkfifo $basedir/flag");
 
     if ( ( $pid = fork() ) == 0 ) {
@@ -346,7 +367,7 @@ if ($test_ipsec) {
 "runcon -t test_inet_bad_client_t -- $basedir/client $proto 127.0.0.1 65535 2>&1";
     ok( $result >> 8 eq $fail_value2 );
 
-    if ($is_stream) {
+    if ( $is_stream && $test_ipv6 ) {
 
         # Verify that authorized client can communicate with the server.
         $result =
@@ -355,15 +376,18 @@ if ($test_ipsec) {
         ok( $result eq 0 );
     }
 
-    # Verify that unauthorized client cannot communicate with the server.
-    $result = system
+    if ($test_ipv6) {
+
+        # Verify that unauthorized client cannot communicate with the server.
+        $result = system
 "runcon -t test_inet_bad_client_t -- $basedir/client $proto ::1 65535 2>&1";
-    ok( $result >> 8 eq $fail_value2 );
+        ok( $result >> 8 eq $fail_value2 );
+    }
 
     # Kill the server.
     server_end($pid);
 
-    if ( not $is_stream ) {
+    if ( !$is_stream && $test_ipv6 ) {
 
    # Start the server for IPSEC test using IPv6 but do not request peer context.
         $pid = server_start( "-t test_inet_server_t", "-n $proto 65535" );
@@ -399,15 +423,18 @@ sub test_tables {
 "runcon -t test_inet_bad_client_t -- $basedir/client -e nopeer $proto 127.0.0.1 65535 2>&1";
     ok( $result >> 8 eq $fail_value2 );
 
-    # Verify that authorized client can communicate with the server.
-    $result = system
+    if ($test_ipv6) {
+
+        # Verify that authorized client can communicate with the server.
+        $result = system
 "runcon -t test_inet_client_t -- $basedir/client -e nopeer $proto ::1 65535";
-    ok( $result eq 0 );
+        ok( $result eq 0 );
 
-    # Verify that unauthorized client cannot communicate with the server.
-    $result = system
+        # Verify that unauthorized client cannot communicate with the server.
+        $result = system
 "runcon -t test_inet_bad_client_t -- $basedir/client -e nopeer $proto ::1 65535 2>&1";
-    ok( $result >> 8 eq $fail_value2 );
+        ok( $result >> 8 eq $fail_value2 );
+    }
 
     # Kill the server.
     server_end($pid);
@@ -423,7 +450,9 @@ if ($test_iptables) {
 if ($test_nft) {
     print "Testing nftables (IPv4/IPv6).\n";
     system "nft -f $basedir/nftables-load";
+    system "nft -f $basedir/nftables-ipv6.load" if $test_ipv6;
     test_tables();
+    system "nft -f $basedir/nftables-ipv6-flush" if $test_ipv6;
     system "nft -f $basedir/nftables-flush";
 }
 
diff --git a/tests/sctp/fb-deny-label-flush b/tests/sctp/fb-deny-label-flush
index 059e0b7..41e76e6 100644
--- a/tests/sctp/fb-deny-label-flush
+++ b/tests/sctp/fb-deny-label-flush
@@ -1,6 +1,11 @@
 #!/bin/sh
 
+SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
+
 netlabelctl map del default
 netlabelctl map add default protocol:unlbl
 netlabelctl unlbl del interface:lo address:127.0.0.0/8 label:system_u:object_r:netlabel_sctp_peer_t:s0
+if "$HAS_IPV6"; then
 netlabelctl unlbl del interface:lo address:::1/128 label:system_u:object_r:deny_assoc_sctp_peer_t:s0
+fi
diff --git a/tests/sctp/fb-deny-label-load b/tests/sctp/fb-deny-label-load
index 7c0bd87..647399b 100644
--- a/tests/sctp/fb-deny-label-load
+++ b/tests/sctp/fb-deny-label-load
@@ -1,7 +1,14 @@
 #!/bin/sh
 
+SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
+
 netlabelctl map del default
 netlabelctl map add default address:0.0.0.0/0 protocol:unlbl
+if "$HAS_IPV6"; then
 netlabelctl map add default address:::/0 protocol:unlbl
+fi
 netlabelctl unlbl add interface:lo address:127.0.0.0/8 label:system_u:object_r:netlabel_sctp_peer_t:s0
+if "$HAS_IPV6"; then
 netlabelctl unlbl add interface:lo address:::1/128 label:system_u:object_r:deny_assoc_sctp_peer_t:s0
+fi
diff --git a/tests/sctp/fb-label-flush b/tests/sctp/fb-label-flush
index 13573a8..c1ceeb5 100644
--- a/tests/sctp/fb-label-flush
+++ b/tests/sctp/fb-label-flush
@@ -1,6 +1,11 @@
 #!/bin/sh
 
+SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
+
 netlabelctl map del default
 netlabelctl map add default protocol:unlbl
 netlabelctl unlbl del interface:lo address:127.0.0.0/8 label:system_u:object_r:netlabel_sctp_peer_t:s0
+if "$HAS_IPV6"; then
 netlabelctl unlbl del interface:lo address:::1/128 label:system_u:object_r:netlabel_sctp_peer_t:s0
+fi
diff --git a/tests/sctp/fb-label-load b/tests/sctp/fb-label-load
index a501515..065ec34 100644
--- a/tests/sctp/fb-label-load
+++ b/tests/sctp/fb-label-load
@@ -1,8 +1,15 @@
 #!/bin/sh
 
+SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
+
 netlabelctl map del default
 netlabelctl map add default address:0.0.0.0/0 protocol:unlbl
+if "$HAS_IPV6"; then
 netlabelctl map add default address:::/0 protocol:unlbl
+fi
 netlabelctl unlbl add interface:lo address:127.0.0.0/8 label:system_u:object_r:netlabel_sctp_peer_t:s0
+if "$HAS_IPV6"; then
 netlabelctl unlbl add interface:lo address:::1/128 label:system_u:object_r:netlabel_sctp_peer_t:s0
+fi
 #netlabelctl -p unlbl list
diff --git a/tests/sctp/iptables-flush b/tests/sctp/iptables-flush
index e74271a..112ae79 100644
--- a/tests/sctp/iptables-flush
+++ b/tests/sctp/iptables-flush
@@ -1,4 +1,9 @@
 #!/bin/sh
 # Flush the security table after IPv4 and IPv6 tests.
+SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
+
 iptables -t security -F
+if "$HAS_IPV6"; then
 ip6tables -t security -F
+fi
diff --git a/tests/sctp/iptables-load b/tests/sctp/iptables-load
index 9dac576..1a91e19 100644
--- a/tests/sctp/iptables-load
+++ b/tests/sctp/iptables-load
@@ -1,9 +1,14 @@
 #!/bin/sh
 ############################ SECMARK IPTABLE ENTRIES ########################
 #
+SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+HAS_IPV6="$SCRIPT_DIR/../has_ipv6"
+
 # Flush the security table first:
 iptables -t security -F
+if "$HAS_IPV6"; then
 ip6tables -t security -F
+fi
 
 #-------------- INPUT IP Stream --------------------#
 # These rules will replace the above context if sctp ports 1024:1035 are found in the packets:
@@ -11,9 +16,11 @@ iptables -t security -A INPUT -i lo -p sctp -m multiport --port 1024:1035 -j SEC
 
 iptables -t security -A INPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --save
 
+if "$HAS_IPV6"; then
 ip6tables -t security -A INPUT -i lo -p sctp -m multiport --port 1024:1035 -j SECMARK --selctx system_u:object_r:test_sctp_server_packet_t:s0
 
 ip6tables -t security -A INPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --save
+fi
 
 #-------------- OUTPUT IP Stream --------------------#
 # These rules will replace the above context if sctp ports 1024:1035 are found in the packets:
@@ -21,7 +28,9 @@ iptables -t security -A OUTPUT -o lo -p sctp -m multiport --port 1024:1035 -j SE
 
 iptables -t security -A OUTPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --save
 
+if "$HAS_IPV6"; then
 ip6tables -t security -A OUTPUT -o lo -p sctp -m multiport --port 1024:1035 -j SECMARK --selctx system_u:object_r:test_sctp_server_packet_t:s0
 
 ip6tables -t security -A OUTPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --save
+fi
 
diff --git a/tests/sctp/nftables-flush b/tests/sctp/nftables-flush
index 7d62b8d..d0fee0c 100644
--- a/tests/sctp/nftables-flush
+++ b/tests/sctp/nftables-flush
@@ -1,2 +1 @@
 delete table ip security
-delete table ip6 security
diff --git a/tests/sctp/nftables-ipv6-flush b/tests/sctp/nftables-ipv6-flush
new file mode 100644
index 0000000..0c9b69a
--- /dev/null
+++ b/tests/sctp/nftables-ipv6-flush
@@ -0,0 +1 @@
+delete table ip6 security
diff --git a/tests/sctp/nftables-ipv6.load b/tests/sctp/nftables-ipv6.load
new file mode 100644
index 0000000..1268140
--- /dev/null
+++ b/tests/sctp/nftables-ipv6.load
@@ -0,0 +1,33 @@
+# IPv6 secmark rules for SCTP tests (loaded only when IPv6 is enabled).
+
+add table ip6 security
+
+table ip6 security {
+
+	secmark sctp_server {
+		"system_u:object_r:test_sctp_server_packet_t:s0"
+	}
+
+	map secmapping_in_out {
+		type inet_service : secmark
+		elements = { 1035 : "sctp_server" }
+	}
+
+	chain input {
+		type filter hook input priority 0;
+
+		ct state new meta secmark set sctp dport map @secmapping_in_out
+		ct state new ct secmark set meta secmark
+
+		ct state established,related meta secmark set ct secmark
+	}
+
+	chain output {
+		type filter hook output priority 0;
+
+		ct state new meta secmark set sctp dport map @secmapping_in_out
+		ct state new ct secmark set meta secmark
+
+		ct state established,related meta secmark set ct secmark
+	}
+}
diff --git a/tests/sctp/nftables-load b/tests/sctp/nftables-load
index 2cac3bb..56803b6 100644
--- a/tests/sctp/nftables-load
+++ b/tests/sctp/nftables-load
@@ -1,7 +1,8 @@
 # Based on NFT project example. Requires kernel >= 4.20 and nft >= 0.9.3
+#
+# IPv6 rules are in nftables-ipv6.load and loaded only when IPv6 is enabled.
 
 add table ip security
-add table ip6 security
 
 table ip security {
 
@@ -36,33 +37,3 @@ table ip security {
 		ct state established,related meta secmark set ct secmark
 	}
 }
-
-table ip6 security {
-
-	secmark sctp_server {
-		"system_u:object_r:test_sctp_server_packet_t:s0"
-	}
-
-	map secmapping_in_out {
-		type inet_service : secmark
-		elements = { 1035 : "sctp_server" }
-	}
-
-	chain input {
-		type filter hook input priority 0;
-
-		ct state new meta secmark set sctp dport map @secmapping_in_out
-		ct state new ct secmark set meta secmark
-
-		ct state established,related meta secmark set ct secmark
-	}
-
-	chain output {
-		type filter hook output priority 0;
-
-		ct state new meta secmark set sctp dport map @secmapping_in_out
-		ct state new ct secmark set meta secmark
-
-		ct state established,related meta secmark set ct secmark
-	}
-}
diff --git a/tests/sctp/sctp_bindx.c b/tests/sctp/sctp_bindx.c
index 74bf985..a37a458 100644
--- a/tests/sctp/sctp_bindx.c
+++ b/tests/sctp/sctp_bindx.c
@@ -3,8 +3,9 @@
 static void usage(char *progname)
 {
 	fprintf(stderr,
-		"usage:  %s [-r] [-v] stream|seq port\n"
+		"usage:  %s [-4] [-r] [-v] stream|seq port\n"
 		"\nWhere:\n\t"
+		"-4      Use two IPv4 loopback addresses.\n\t"
 		"-r      After two bindx ADDs, remove one with bindx REM.\n\t"
 		"-v      Print context information.\n\t"
 		"        The default is to add IPv4 and IPv6 loopback addrs.\n\t"
@@ -17,15 +18,19 @@ static void usage(char *progname)
 int main(int argc, char **argv)
 {
 	int opt, type, sock, result;
-	struct sockaddr_in ipv4;
+	struct sockaddr_in ipv4, ipv4_extra;
+	struct sockaddr *extra_addr;
 	struct sockaddr_in6 ipv6;
 	unsigned short port;
-	bool rem = false;
+	bool rem = false, ipv4_only = false;
 	bool verbose = false;
 	char *context;
 
-	while ((opt = getopt(argc, argv, "rv")) != -1) {
+	while ((opt = getopt(argc, argv, "4rv")) != -1) {
 		switch (opt) {
+		case '4':
+			ipv4_only = true;
+			break;
 		case 'v':
 			verbose = true;
 			break;
@@ -58,7 +63,7 @@ int main(int argc, char **argv)
 		free(context);
 	}
 
-	sock = socket(PF_INET6, type, IPPROTO_SCTP);
+	sock = socket(ipv4_only ? PF_INET : PF_INET6, type, IPPROTO_SCTP);
 	if (sock < 0) {
 		perror("socket");
 		exit(1);
@@ -88,19 +93,27 @@ int main(int argc, char **argv)
 	ipv6.sin6_port = htons(port);
 	ipv6.sin6_addr = in6addr_loopback;
 
-	result = sctp_bindx(sock, (struct sockaddr *)&ipv6, 1,
+	if (ipv4_only) {
+		ipv4_extra = ipv4;
+		ipv4_extra.sin_addr.s_addr = htonl(0x7f000002);
+		extra_addr = (struct sockaddr *)&ipv4_extra;
+	} else {
+		extra_addr = (struct sockaddr *)&ipv6;
+	}
+
+	result = sctp_bindx(sock, extra_addr, 1,
 			    SCTP_BINDX_ADD_ADDR);
 	if (result < 0) {
-		perror("sctp_bindx ADD - ipv6");
+		perror("sctp_bindx ADD - second address");
 		close(sock);
 		exit(3);
 	}
 
 	if (verbose)
-		printf("sctp_bindx ADD - ipv6\n");
+		printf("sctp_bindx ADD - %s\n", ipv4_only ? "127.0.0.2" : "::1");
 
 	if (rem) {
-		result = sctp_bindx(sock, (struct sockaddr *)&ipv6, 1,
+		result = sctp_bindx(sock, extra_addr, 1,
 				    SCTP_BINDX_REM_ADDR);
 		if (result < 0) {
 			perror("sctp_bindx - REM");
@@ -108,7 +121,7 @@ int main(int argc, char **argv)
 			exit(4);
 		}
 		if (verbose)
-			printf("sctp_bindx REM - ipv6\n");
+			printf("sctp_bindx REM - %s\n", ipv4_only ? "127.0.0.2" : "::1");
 	}
 
 	close(sock);
diff --git a/tests/sctp/test b/tests/sctp/test
index 5626ab8..5c44ec7 100755
--- a/tests/sctp/test
+++ b/tests/sctp/test
@@ -104,6 +104,27 @@ BEGIN {
             $test_count += 8;
             $test_nft = 1;
         }
+
+        # Determine if IPv6 is enabled on loopback.
+        $test_ipv6 = system("$basedir/../has_ipv6") == 0 ? 1 : 0;
+
+        if ( !$test_ipv6 ) {
+            $test_count -= 11;
+
+            if ($test_calipso) {
+                $test_count -= 13;
+                if ($test_clpeeloff) {
+                    $test_count -= 6;
+                }
+                $test_calipso = 0;
+            }
+            if ($test_iptables) {
+                $test_count -= 4;
+            }
+            if ($test_nft) {
+                $test_count -= 4;
+            }
+        }
     }
 
     plan tests => $test_count;
@@ -113,6 +134,13 @@ sub server_start {
     my ( $runcon_args, $prog, $args ) = @_;
     my $pid;
 
+    # Select the family before entering the confined server domain.
+    if ( !$test_ipv6
+        && ( $prog eq "sctp_server" || $prog eq "sctp_peeloff_server" ) )
+    {
+        $args = "-4 $args";
+    }
+
     system("mkfifo $basedir/flag");
 
     if ( ( $pid = fork() ) == 0 ) {
@@ -164,16 +192,19 @@ $result = system
 "runcon -t test_sctp_client_t $basedir/sctp_client $v -n -e nopeer seq 127.0.0.1 1035";
 ok( $result eq 0 );
 
-# Verify that authorized client can communicate with the server SEQ->STREAM.
-$result = system
-  "runcon -t test_sctp_client_t $basedir/sctp_client $v -e nopeer seq ::1 1035";
-ok( $result eq 0 );
+if ($test_ipv6) {
+
+    # Verify that authorized client can communicate with the server SEQ->STREAM.
+    $result = system
+"runcon -t test_sctp_client_t $basedir/sctp_client $v -e nopeer seq ::1 1035";
+    ok( $result eq 0 );
 
 # Verify that the client cannot communicate with server when using port < 1024 STREAM->STREAM.
 # deny sctp_socket { name_connect }
-$result = system
+    $result = system
 "runcon -t test_sctp_client_t -- $basedir/sctp_client $v -e nopeer stream ::1 1023 2>&1";
-ok( $result >> 8 eq 8 );
+    ok( $result >> 8 eq 8 );
+}
 
 # Kill the stream server.
 server_end($pid);
@@ -194,15 +225,17 @@ $result = system
 "runcon -t test_sctp_connectx_t $basedir/sctp_connectx $v stream 127.0.0.1 1035";
 ok( $result eq 0 );
 
-$result =
-  system
-  "runcon -t test_sctp_connectx_t $basedir/sctp_connectx $v seq ::1 1035";
-ok( $result eq 0 );
+if ($test_ipv6) {
+    $result =
+      system
+      "runcon -t test_sctp_connectx_t $basedir/sctp_connectx $v seq ::1 1035";
+    ok( $result eq 0 );
 
-$result =
-  system
+    $result =
+      system
 "runcon -t test_sctp_deny_connectx_t $basedir/sctp_connectx $v seq ::1 1035 2>&1";
-ok( $result >> 8 eq 7 );
+    ok( $result >> 8 eq 7 );
+}
 
 #
 ########################### SCTP_SENDMSG_CONNECT #############################
@@ -215,28 +248,33 @@ $result =
 "runcon -t test_sctp_connectx_t $basedir/sctp_connectx $v -n seq 127.0.0.1 1035";
 ok( $result eq 0 );
 
-$result =
-  system
+if ($test_ipv6) {
+    $result =
+      system
 "runcon -t test_sctp_deny_connectx_t $basedir/sctp_connectx $v -n seq ::1 1035 2>&1";
-ok( $result >> 8 eq 8 );
+    ok( $result >> 8 eq 8 );
+}
 
 #
 ################################ BINDX #######################################
 #
 # net/sctp/socket.c sctp_setsockopt_bindx() SCTP_SOCKOPT_BINDX_ADD
 print "# Testing bindx.\n";
+$bindx_family = $test_ipv6 ? "" : "-4";
 
 $result =
-  system "runcon -t test_sctp_bindx_t $basedir/sctp_bindx $v -r stream 1035";
+  system
+"runcon -t test_sctp_bindx_t $basedir/sctp_bindx $bindx_family $v -r stream 1035";
 ok( $result eq 0 );
 
 $result =
-  system "runcon -t test_sctp_bindx_t $basedir/sctp_bindx $v -r seq 1035";
+  system
+"runcon -t test_sctp_bindx_t $basedir/sctp_bindx $bindx_family $v -r seq 1035";
 ok( $result eq 0 );
 
 $result =
   system
-  "runcon -t test_sctp_deny_bindx_t $basedir/sctp_bindx $v -r seq 1035 2>&1";
+"runcon -t test_sctp_deny_bindx_t $basedir/sctp_bindx $bindx_family $v -r seq 1035 2>&1";
 ok( $result >> 8 eq 2 );
 
 #
@@ -351,30 +389,33 @@ server_end($pid);
 # Start seq server.
 $pid = server_start( "-t test_sctp_server_t", "sctp_server", "$v seq 1035" );
 
-# Verify that authorized client can communicate with the server SEQ->SEQ.
-$result = system
+if ($test_ipv6) {
+
+    # Verify that authorized client can communicate with the server SEQ->SEQ.
+    $result = system
 "runcon -t test_sctp_client_t $basedir/sctp_client $v -e system_u:object_r:netlabel_sctp_peer_t:s0 seq ::1 1035";
-ok( $result eq 0 );
+    ok( $result eq 0 );
 
-# Verify that authorized client can communicate with the server STREAM->SEQ.
-$result = system
+    # Verify that authorized client can communicate with the server STREAM->SEQ.
+    $result = system
 "runcon -t test_sctp_client_t $basedir/sctp_client $v -e system_u:object_r:netlabel_sctp_peer_t:s0 stream ::1 1035";
-ok( $result eq 0 );
+    ok( $result eq 0 );
 
 # Verify that a client using connect(2) without peer { recv } permission cannot communicate with the server SEQ->SEQ.
-$result = system
+    $result = system
 "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -e system_u:object_r:netlabel_sctp_peer_t:s0 seq ::1 1035 2>&1";
-ok( $result >> 8 eq 6 );
+    ok( $result >> 8 eq 6 );
 
 # Verify that a client using sctp_connectx(3) without peer { recv } permission cannot communicate with the server SEQ->SEQ.
-$result = system
+    $result = system
 "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -x -e system_u:object_r:netlabel_sctp_peer_t:s0 seq ::1 1035 2>&1";
-ok( $result >> 8 eq 6 );
+    ok( $result >> 8 eq 6 );
 
 # Verify that a client not using any connect without peer { recv } permission cannot communicate with the server SEQ->SEQ.
-$result = system
+    $result = system
 "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -n -e system_u:object_r:netlabel_sctp_peer_t:s0 seq ::1 1035 2>&1";
-ok( $result >> 8 eq 13 );
+    ok( $result >> 8 eq 13 );
+}
 
 # Kill the seq server.
 server_end($pid);
@@ -396,10 +437,13 @@ $result = system
 "runcon -t test_sctp_client_t $basedir/sctp_client $v -e system_u:object_r:netlabel_sctp_peer_t:s0 stream 127.0.0.1 1035";
 ok( $result eq 0 );
 
+if ($test_ipv6) {
+
 # Verify that the server is denied this association as the client will timeout on connect.
-$result = system
+    $result = system
 "runcon -t test_sctp_client_t -- $basedir/sctp_client $v -e system_u:object_r:deny_assoc_sctp_peer_t:s0 stream ::1 1035 2>&1";
-ok( $result >> 8 eq 6 );
+    ok( $result >> 8 eq 6 );
+}
 
 # Kill the seq server.
 server_end($pid);
@@ -1141,15 +1185,18 @@ sub test_tables {
 "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -e nopeer stream 127.0.0.1 1035 2>&1";
     ok( $result >> 8 eq 6 );
 
+    if ($test_ipv6) {
+
  # Verify that authorized client can communicate with the server STREAM->STREAM.
-    $result = system
+        $result = system
 "runcon -t test_sctp_client_t $basedir/sctp_client $v -e nopeer stream ::1 1035";
-    ok( $result eq 0 );
+        ok( $result eq 0 );
 
 # Verify that a client without packet { recv } permission cannot communicate with the server STREAM->STREAM.
-    $result = system
+        $result = system
 "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -e nopeer stream ::1 1035 2>&1";
-    ok( $result >> 8 eq 6 );
+        ok( $result >> 8 eq 6 );
+    }
 
     # Kill the stream server.
     server_end($pid);
@@ -1168,15 +1215,18 @@ sub test_tables {
 "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -e nopeer seq 127.0.0.1 1035 2>&1";
     ok( $result >> 8 eq 6 );
 
-    # Verify that authorized client can communicate with the server SEQ->SEQ.
-    $result = system
+    if ($test_ipv6) {
+
+       # Verify that authorized client can communicate with the server SEQ->SEQ.
+        $result = system
 "runcon -t test_sctp_client_t $basedir/sctp_client $v -e nopeer seq ::1 1035";
-    ok( $result eq 0 );
+        ok( $result eq 0 );
 
 # Verify that a client without packet { recv } permission cannot communicate with the server SEQ->SEQ.
-    $result = system
+        $result = system
 "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client $v -e nopeer seq ::1 1035 2>&1";
-    ok( $result >> 8 eq 6 );
+        ok( $result >> 8 eq 6 );
+    }
 
     # Kill the seq server.
     server_end($pid);
@@ -1192,7 +1242,9 @@ if ($test_iptables) {
 if ($test_nft) {
     print "# Testing nftables (IPv4/IPv6).\n";
     system "nft -f $basedir/nftables-load";
+    system "nft -f $basedir/nftables-ipv6.load" if $test_ipv6;
     test_tables();
+    system "nft -f $basedir/nftables-ipv6-flush" if $test_ipv6;
     system "nft -f $basedir/nftables-flush";
 }
 
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH] tests: make IPv6 subtests optional on IPv4-only systems
  2026-10-05 13:31     ` Brian Grech
@ 2026-10-05 14:41       ` Stephen Smalley
  2026-10-06 12:55         ` Stephen Smalley
  0 siblings, 1 reply; 7+ messages in thread
From: Stephen Smalley @ 2026-10-05 14:41 UTC (permalink / raw)
  To: Brian Grech; +Cc: jonderka, selinux

On Mon, Oct 5, 2026 at 9:31 AM Brian Grech <bgrech@redhat.com> wrote:
>
> Skip or adapt IPv6-dependent subtests (inet_socket, extended_socket_class,
> sctp) when the system has no usable IPv6 on loopback, instead of
> assuming ::1 and ip6tables always work.
>
> - Add tests/has_ipv6, checking /proc/net/if_inet6 and disable_ipv6
>   sysctls.
> - Gate IPv6-only cases behind $test_ipv6 and adjust test counts.
> - inet_socket/server.c falls back to AF_INET when IPv6 is absent.
> - Split IPv6 firewall rules into nftables-ipv6.load, invoked only when
>   has_ipv6 succeeds.
> - Select address family via has_ipv6 before entering confined test
>   domains, rather than probing IPv6 from inside them: that probe can
>   itself be denied by policy, silently selecting IPv4 while the runner
>   keeps executing IPv6-only cases.
>
> Co-developed-by: Jan Onderka <jonderka@redhat.com>
> Signed-off-by: Jan Onderka <jonderka@redhat.com>
> Signed-off-by: Brian Grech <bgrech@redhat.com>
> ---

For future reference, normally one would add a "v2" (or "v3", "v4",
...) to the subject line and put a short changelog after the "---"
before the diffstat describing what changed from the previous version.
No need to re-spin this one though.

Reviewed-by: Stephen Smalley <stephen.smalley.work@gmail.com>

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] tests: make IPv6 subtests optional on IPv4-only systems
  2026-10-05 14:41       ` Stephen Smalley
@ 2026-10-06 12:55         ` Stephen Smalley
  0 siblings, 0 replies; 7+ messages in thread
From: Stephen Smalley @ 2026-10-06 12:55 UTC (permalink / raw)
  To: Brian Grech; +Cc: jonderka, selinux

On Mon, Oct 5, 2026 at 10:41 AM Stephen Smalley
<stephen.smalley.work@gmail.com> wrote:
>
> On Mon, Oct 5, 2026 at 9:31 AM Brian Grech <bgrech@redhat.com> wrote:
> >
> > Skip or adapt IPv6-dependent subtests (inet_socket, extended_socket_class,
> > sctp) when the system has no usable IPv6 on loopback, instead of
> > assuming ::1 and ip6tables always work.
> >
> > - Add tests/has_ipv6, checking /proc/net/if_inet6 and disable_ipv6
> >   sysctls.
> > - Gate IPv6-only cases behind $test_ipv6 and adjust test counts.
> > - inet_socket/server.c falls back to AF_INET when IPv6 is absent.
> > - Split IPv6 firewall rules into nftables-ipv6.load, invoked only when
> >   has_ipv6 succeeds.
> > - Select address family via has_ipv6 before entering confined test
> >   domains, rather than probing IPv6 from inside them: that probe can
> >   itself be denied by policy, silently selecting IPv4 while the runner
> >   keeps executing IPv6-only cases.
> >
> > Co-developed-by: Jan Onderka <jonderka@redhat.com>
> > Signed-off-by: Jan Onderka <jonderka@redhat.com>
> > Signed-off-by: Brian Grech <bgrech@redhat.com>
> > ---
>
> For future reference, normally one would add a "v2" (or "v3", "v4",
> ...) to the subject line and put a short changelog after the "---"
> before the diffstat describing what changed from the previous version.
> No need to re-spin this one though.
>
> Reviewed-by: Stephen Smalley <stephen.smalley.work@gmail.com>

This has been merged.

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-10-06 12:55 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-10  8:25 [PATCH] tests: make IPv6 subtests optional on IPv4-only systems Jan Onderka
2026-07-10 17:55 ` Stephen Smalley
2026-10-01 15:36 ` Brian Grech
2026-10-02 15:01   ` Stephen Smalley
2026-10-05 13:31     ` Brian Grech
2026-10-05 14:41       ` Stephen Smalley
2026-10-06 12:55         ` Stephen Smalley

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.