diff mbox series

[V2,testsuite] tests/inet_socket: Add socket transition tests

Message ID 20211125085755.3230-1-richard_c_haines@btinternet.com (mailing list archive)
State New, archived
Delegated to: Ondrej Mosnáček
Headers show
Series [V2,testsuite] tests/inet_socket: Add socket transition tests | expand

Commit Message

Richard Haines Nov. 25, 2021, 8:57 a.m. UTC
Add setsockcreatecon(3) and type_transition tests. Also test cipso
netlabelctl(8) domain:<domain> and label translation services, netlabel
fallback for ipv4 & ipv6 plus calipso domain:<domain>.

Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
---
V2 Changes: Add additional tests for Netlabel Fallback IPv4 & IPv6 plus
CALIPSO domain:<domain> service.

 policy/test_inet_socket.te             |  81 ++++++++
 tests/inet_socket/calipso-domain-flush |   8 +
 tests/inet_socket/calipso-domain-load  |  10 +
 tests/inet_socket/cipso-domain-flush   |   8 +
 tests/inet_socket/cipso-domain-load    |  10 +
 tests/inet_socket/cipso-trans-flush    |   6 +
 tests/inet_socket/cipso-trans-load     |  10 +
 tests/inet_socket/client.c             | 226 ++++++++++++++++++++-
 tests/inet_socket/fb-deny-label-flush  |   6 +
 tests/inet_socket/fb-deny-label-load   |   8 +
 tests/inet_socket/fb-label-flush       |   6 +
 tests/inet_socket/fb-label-load        |   8 +
 tests/inet_socket/test                 | 262 ++++++++++++++++++++++++-
 13 files changed, 640 insertions(+), 9 deletions(-)
 create mode 100644 tests/inet_socket/calipso-domain-flush
 create mode 100644 tests/inet_socket/calipso-domain-load
 create mode 100644 tests/inet_socket/cipso-domain-flush
 create mode 100644 tests/inet_socket/cipso-domain-load
 create mode 100644 tests/inet_socket/cipso-trans-flush
 create mode 100644 tests/inet_socket/cipso-trans-load
 create mode 100644 tests/inet_socket/fb-deny-label-flush
 create mode 100644 tests/inet_socket/fb-deny-label-load
 create mode 100644 tests/inet_socket/fb-label-flush
 create mode 100644 tests/inet_socket/fb-label-load
diff mbox series

Patch

diff --git a/policy/test_inet_socket.te b/policy/test_inet_socket.te
index 0fff2da..f65464e 100644
--- a/policy/test_inet_socket.te
+++ b/policy/test_inet_socket.te
@@ -15,9 +15,23 @@  corenet_inout_generic_node(netlabel_peer_t)
 # Do not break NFS when we load NetLabel configuration.
 gen_require(`
 	type kernel_t;
+	type nfsd_t;
 ')
+allow kernel_t netlabel_inet_peer_t:peer recv;
+allow kernel_t netlabel_deny_inet_peer_t:peer recv;
+allow nfsd_t netlabel_inet_peer_t:peer recv;
+allow nfsd_t netlabel_deny_inet_peer_t:peer recv;
 corenet_all_recvfrom_unlabeled(kernel_t)
 
+# Fallback labeling:
+type netlabel_inet_peer_t;
+corenet_in_generic_node(netlabel_inet_peer_t)
+corenet_in_generic_if(netlabel_inet_peer_t)
+# Deny Fallback:
+type netlabel_deny_inet_peer_t;
+corenet_inout_generic_node(netlabel_deny_inet_peer_t)
+corenet_inout_generic_if(netlabel_deny_inet_peer_t)
+
 # Domain for server process.
 type test_inet_server_t;
 domain_type(test_inet_server_t)
@@ -32,6 +46,8 @@  corenet_tcp_bind_all_nodes(test_inet_server_t)
 corenet_udp_bind_all_nodes(test_inet_server_t)
 corenet_inout_generic_if(test_inet_server_t)
 corenet_inout_generic_node(test_inet_server_t)
+#
+allow test_inet_server_t netlabel_inet_peer_t:peer recv;
 
 # For writing to flag file:
 allow test_inet_server_t test_file_t:fifo_file rw_file_perms;
@@ -57,6 +73,8 @@  allow test_inet_client_t self:udp_socket create_socket_perms;
 corenet_tcp_connect_all_unreserved_ports(test_inet_client_t)
 corenet_inout_generic_if(test_inet_client_t)
 corenet_inout_generic_node(test_inet_client_t)
+#
+allow test_inet_client_t netlabel_inet_peer_t:peer recv;
 
 # The server can receive labeled packets from the client.
 allow test_inet_server_t test_inet_client_t:peer recv;
@@ -167,6 +185,69 @@  allow unconfined_t test_server_packet_t:packet relabelto;
 allow test_inet_server_t test_server_packet_t:packet { send recv };
 allow test_inet_client_t test_server_packet_t:packet { send recv };
 
+#
+# Test client setting new socket context using setsockcreatecon(3) and
+# type_transition rules.
+#
+
+# Set new client socket context using setsockcreatecon(3):
+type inet_client_setsockcreatecon_t;
+domain_type(inet_client_setsockcreatecon_t)
+unconfined_runs_test(inet_client_setsockcreatecon_t)
+typeattribute inet_client_setsockcreatecon_t testdomain;
+typeattribute inet_client_setsockcreatecon_t inetsocketdomain;
+allow test_inet_client_t inet_client_setsockcreatecon_t:tcp_socket create_stream_socket_perms;
+allow test_inet_client_t inet_client_setsockcreatecon_t:udp_socket create_stream_socket_perms;
+corenet_tcp_connect_all_unreserved_ports(inet_client_setsockcreatecon_t)
+corenet_inout_generic_if(inet_client_setsockcreatecon_t)
+corenet_inout_generic_node(inet_client_setsockcreatecon_t)
+# The server can receive labeled packets from the client.
+allow test_inet_server_t inet_client_setsockcreatecon_t:peer recv;
+# And vice versa.
+allow inet_client_setsockcreatecon_t test_inet_server_t:peer recv;
+allow inet_client_setsockcreatecon_t netlabel_inet_peer_t:peer recv;
+
+# Set new client socket context using a type_transition rule:
+type test_inet_new_type_client_t;
+domain_type(test_inet_new_type_client_t)
+unconfined_runs_test(test_inet_new_type_client_t)
+typeattribute test_inet_new_type_client_t testdomain;
+typeattribute test_inet_new_type_client_t inetsocketdomain;
+
+type inet_client_type_transition_t;
+type_transition test_inet_new_type_client_t test_inet_new_type_client_t:tcp_socket inet_client_type_transition_t;
+type_transition test_inet_new_type_client_t test_inet_new_type_client_t:udp_socket inet_client_type_transition_t;
+unconfined_runs_test(inet_client_type_transition_t)
+typeattribute inet_client_type_transition_t inetsocketdomain;
+
+allow test_inet_new_type_client_t inet_client_type_transition_t:tcp_socket create_stream_socket_perms;
+allow test_inet_new_type_client_t inet_client_type_transition_t:udp_socket create_stream_socket_perms;
+corenet_tcp_connect_all_unreserved_ports(inet_client_type_transition_t)
+corenet_inout_generic_if(inet_client_type_transition_t)
+corenet_inout_generic_node(inet_client_type_transition_t)
+# The server can receive labeled packets from the client.
+allow test_inet_server_t inet_client_type_transition_t:peer recv;
+# And vice versa.
+allow inet_client_type_transition_t test_inet_server_t:peer recv;
+allow inet_client_type_transition_t netlabel_peer_t:peer recv;
+allow inet_client_type_transition_t netlabel_inet_peer_t:peer recv;
+
+# Test deny socket { create } after setsockcreatecon(3):
+type test_inet_deny_setsockcreatecon_t;
+domain_type(test_inet_deny_setsockcreatecon_t)
+unconfined_runs_test(test_inet_deny_setsockcreatecon_t)
+typeattribute test_inet_deny_setsockcreatecon_t testdomain;
+typeattribute test_inet_deny_setsockcreatecon_t inetsocketdomain;
+
+# Test deny socket { create } after type_transition rule:
+type test_inet_deny_type_transition_t;
+domain_type(test_inet_deny_type_transition_t)
+unconfined_runs_test(test_inet_deny_type_transition_t)
+typeattribute test_inet_deny_type_transition_t testdomain;
+typeattribute test_inet_deny_type_transition_t inetsocketdomain;
+type_transition test_inet_deny_type_transition_t test_inet_deny_type_transition_t:tcp_socket inet_client_type_transition_t;
+type_transition test_inet_deny_type_transition_t test_inet_deny_type_transition_t:udp_socket inet_client_type_transition_t;
+
 #
 # Common rules for all inet socket test domains.
 #
diff --git a/tests/inet_socket/calipso-domain-flush b/tests/inet_socket/calipso-domain-flush
new file mode 100644
index 0000000..1ef5969
--- /dev/null
+++ b/tests/inet_socket/calipso-domain-flush
@@ -0,0 +1,8 @@ 
+#!/bin/sh
+
+netlabelctl map del default
+netlabelctl calipso del doi:1
+netlabelctl map del domain:test_inet_client_t
+netlabelctl map del domain:inet_client_setsockcreatecon_t
+netlabelctl map del domain:inet_client_type_transition_t
+netlabelctl map add default protocol:unlbl
diff --git a/tests/inet_socket/calipso-domain-load b/tests/inet_socket/calipso-domain-load
new file mode 100644
index 0000000..2eab65e
--- /dev/null
+++ b/tests/inet_socket/calipso-domain-load
@@ -0,0 +1,10 @@ 
+#!/bin/sh
+
+netlabelctl calipso add pass doi:1
+netlabelctl map del default
+netlabelctl map add default address:0.0.0.0/0 protocol:unlbl
+netlabelctl map add default address:::/0 protocol:unlbl
+netlabelctl map add domain:test_inet_client_t address:::1 protocol:calipso,1
+# Note that it is the socket context that matters here not process context:
+netlabelctl map add domain:inet_client_setsockcreatecon_t address:::1 protocol:calipso,1
+netlabelctl map add domain:inet_client_type_transition_t address:::1 protocol:calipso,1
diff --git a/tests/inet_socket/cipso-domain-flush b/tests/inet_socket/cipso-domain-flush
new file mode 100644
index 0000000..f391c08
--- /dev/null
+++ b/tests/inet_socket/cipso-domain-flush
@@ -0,0 +1,8 @@ 
+#!/bin/sh
+
+netlabelctl map del default
+netlabelctl cipso del doi:65535
+netlabelctl map del domain:test_inet_client_t
+netlabelctl map del domain:inet_client_setsockcreatecon_t
+netlabelctl map del domain:inet_client_type_transition_t
+netlabelctl map add default protocol:unlbl
diff --git a/tests/inet_socket/cipso-domain-load b/tests/inet_socket/cipso-domain-load
new file mode 100644
index 0000000..81575c7
--- /dev/null
+++ b/tests/inet_socket/cipso-domain-load
@@ -0,0 +1,10 @@ 
+#!/bin/sh
+
+netlabelctl cipso add pass doi:65535 tags:1
+netlabelctl map del default
+netlabelctl map add default address:0.0.0.0/0 protocol:unlbl
+netlabelctl map add default address:::/0 protocol:unlbl
+netlabelctl map add domain:test_inet_client_t address:127.0.0.1 protocol:cipso,65535
+# Note that it is the socket context that matters here not process context:
+netlabelctl map add domain:inet_client_setsockcreatecon_t address:127.0.0.1 protocol:cipso,65535
+netlabelctl map add domain:inet_client_type_transition_t address:127.0.0.1 protocol:cipso,65535
diff --git a/tests/inet_socket/cipso-trans-flush b/tests/inet_socket/cipso-trans-flush
new file mode 100644
index 0000000..6b517df
--- /dev/null
+++ b/tests/inet_socket/cipso-trans-flush
@@ -0,0 +1,6 @@ 
+#!/bin/sh
+
+netlabelctl map del default
+netlabelctl cipso del doi:16
+netlabelctl cipso del doi:4294967295
+netlabelctl map add default protocol:unlbl
diff --git a/tests/inet_socket/cipso-trans-load b/tests/inet_socket/cipso-trans-load
new file mode 100644
index 0000000..964c178
--- /dev/null
+++ b/tests/inet_socket/cipso-trans-load
@@ -0,0 +1,10 @@ 
+#!/bin/sh
+
+netlabelctl cipso add trans doi:16 tags:1 levels:0=0 categories:0=1,2=3
+# Use the largest DOI possible:
+netlabelctl cipso add pass doi:4294967295 tags:1
+netlabelctl map del default
+netlabelctl map add default address:0.0.0.0/0 protocol:unlbl
+netlabelctl map add default address:::/0 protocol:unlbl
+netlabelctl map add default address:127.0.0.1 protocol:cipso,16
+netlabelctl map add default address:10.123.123.123 protocol:cipso,4294967295
diff --git a/tests/inet_socket/client.c b/tests/inet_socket/client.c
index f8780d9..b10db38 100644
--- a/tests/inet_socket/client.c
+++ b/tests/inet_socket/client.c
@@ -15,15 +15,22 @@ 
 #include <poll.h>
 #include <stdbool.h>
 #include <selinux/selinux.h>
+#include <selinux/context.h>
 
 void usage(char *progname)
 {
 	fprintf(stderr,
-		"usage:  %s [-e expected_msg] [stream|dgram] addr port\n"
+		"usage:  %s [-e expected_msg] [-s] [-o ip_option] [-t type] [-c type] [stream|dgram] addr port\n"
 		"\nWhere:\n\t"
 		"-e      Optional expected message from server e.g. \"nopeer\".\n\t"
 		"        If not present the client context will be used as a\n\t"
 		"        comparison with the servers reply.\n\t"
+		"-s      If -e is not set the client process context is used\n\t"
+		"        for comparison, however if setsockcreatecon(3) or a\n\t"
+		"        type_transition rule are enabled, use the socket context.\n\t"
+		"-o      Expected IP option string.\n\t"
+		"-t      New type for setsockcreatecon(3) test.\n\t"
+		"-c      Compare type expected on socket.\n\t"
 		"stream  Use TCP protocol or:\n\t"
 		"dgram   use UDP protocol.\n\t"
 		"addr    IPv4 or IPv6 address (e.g. 127.0.0.1 or ::1)\n\t"
@@ -31,18 +38,199 @@  void usage(char *progname)
 	exit(1);
 }
 
+char *get_ip_option(int fd, bool ipv4, socklen_t *opt_len)
+{
+	int result, i;
+	unsigned char ip_options[1024];
+	socklen_t len = sizeof(ip_options);
+	char *ip_optbuf;
+
+	if (ipv4)
+		result = getsockopt(fd, IPPROTO_IP, IP_OPTIONS,
+				    ip_options, &len);
+	else
+		result = getsockopt(fd, IPPROTO_IPV6, IPV6_HOPOPTS,
+				    ip_options, &len);
+
+	if (result < 0) {
+		perror("get ip options error");
+		return NULL;
+	}
+
+	ip_optbuf = calloc(1, len * 2 + 1);
+	if (!ip_optbuf) {
+		perror("get ip options malloc error");
+		return NULL;
+	}
+
+	if (len > 0) {
+		for (i = 0; i < len; i++)
+			sprintf(&ip_optbuf[i * 2], "%02x", ip_options[i]);
+
+		*opt_len = len;
+		return ip_optbuf;
+	}
+
+	return NULL;
+}
+
+void check_ip_option(int fd, bool ipv4, char *text, char *expected)
+{
+	char *ip_options;
+	socklen_t len;
+
+	ip_options = get_ip_option(fd, ipv4, &len);
+
+	if (ip_options) {
+		printf("%s IP Options Family: %s Length: %d\n\tEntry: %s\n",
+		       text, ipv4 ? "IPv4" : "IPv6", len, ip_options);
+		if (expected) {
+			if (strcmp(expected, ip_options)) {
+				fprintf(stderr, "Expected options: %s, got: %s\n",
+					expected, ip_options);
+				exit(20);
+			}
+		}
+		free(ip_options);
+	} else {
+		printf("%s No IP Options set\n", text);
+	}
+}
+
+/* Build new context for socket and set using setsockcreatecon(3) */
+static void set_newsock_con(char *type)
+{
+	int result;
+	char *context, *newcon = NULL;
+	context_t con_t;
+
+	result = getcon(&context);
+	if (result < 0) {
+		fprintf(stderr, "Failed to get process context\n");
+		exit(30);
+	}
+
+	con_t = context_new(context);
+	if (!con_t) {
+		fprintf(stderr, "Unable to create context structure\n");
+		result = -1;
+		goto err2;
+	}
+
+	result = context_type_set(con_t, type);
+	if (result < 0) {
+		fprintf(stderr, "Unable to set new socket type\n");
+		goto err1;
+	}
+
+	newcon = context_str(con_t);
+	if (!newcon) {
+		fprintf(stderr, "Unable to set new socket context string\n");
+		result = -1;
+		goto err1;
+	}
+
+	result = setsockcreatecon_raw(newcon);
+	if (result < 0) {
+		fprintf(stderr, "Failed setsockcreatecon(3) context: %s\n", newcon);
+		goto err;
+	}
+
+	result = getsockcreatecon_raw(&context);
+	if (result < 0) {
+		fprintf(stderr, "Failed getsockcreatecon(3)\n");
+		goto err;
+	}
+	printf("New socket context: %s\n", context);
+
+err:
+	free(newcon);
+err1:
+	free(con_t);
+err2:
+	free(context);
+
+	if (result < 0)
+		exit(31);
+}
+
+static void check_sock_type(int fd, char *expected)
+{
+	char *context;
+	const char *type;
+	context_t con_t;
+	int result;
+
+	result = getcon(&context);
+	if (result < 0) {
+		fprintf(stderr, "Failed to get process context\n");
+		exit(40);
+	}
+	printf("Client process context: %s\n", context);
+	free(context);
+
+	result = fgetfilecon(fd, &context);
+	if (result < 0) {
+		fprintf(stderr, "Failed to get socket context\n");
+		exit(41);
+	}
+	printf("Client socket context: %s\n", context);
+
+	if (expected) {
+		result = -1;
+		con_t = context_new(context);
+		if (!con_t) {
+			fprintf(stderr, "Unable to create context structure\n");
+			goto err;
+		}
+
+		type = context_type_get(con_t);
+		if (!type) {
+			fprintf(stderr, "Unable to get socket type\n");
+			free(con_t);
+			goto err;
+		}
+
+		result = 0;
+		if (strcmp(expected, type)) {
+			fprintf(stderr, "Expected socket type: %s, got: %s\n",
+				expected, type);
+			result = -1;
+		}
+	}
+err:
+	free(context);
+
+	if (result < 0)
+		exit(42);
+}
+
 int main(int argc, char **argv)
 {
 	char byte, label[256], *expected = NULL;
+	char *sock_type = NULL, *chk_type = NULL, *chk_option = NULL;
 	int sock, result, opt;
+	bool ipv4 = false, get_sock_ctx = false;
 	struct addrinfo hints, *serverinfo;
 	struct timeval tm;
 
-	while ((opt = getopt(argc, argv, "e:")) != -1) {
+	while ((opt = getopt(argc, argv, "e:so:t:c:")) != -1) {
 		switch (opt) {
 		case 'e':
 			expected = optarg;
 			break;
+		case 's':
+			get_sock_ctx = true;
+			break;
+		case 'o':
+			chk_option = optarg;
+			break;
+		case 't':
+			sock_type = optarg;
+			break;
+		case 'c':
+			chk_type = optarg;
+			break;
 		default:
 			usage(argv[0]);
 		}
@@ -70,6 +258,13 @@  int main(int argc, char **argv)
 		exit(2);
 	}
 
+	if (serverinfo->ai_family == AF_INET)
+		ipv4 = true;
+
+	/* If -t option - setsockcreatecon(3) */
+	if (sock_type)
+		set_newsock_con(sock_type);
+
 	sock = socket(serverinfo->ai_family, serverinfo->ai_socktype,
 		      serverinfo->ai_protocol);
 	if (sock < 0) {
@@ -77,6 +272,11 @@  int main(int argc, char **argv)
 		exit(3);
 	}
 
+	/* Check context if type_transition rule (-c), also if test run local,
+	 * display both contexts
+	 */
+	check_sock_type(sock, chk_type);
+
 	tm.tv_sec = 5;
 	tm.tv_usec = 0;
 	result = setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tm, sizeof(tm));
@@ -124,12 +324,24 @@  int main(int argc, char **argv)
 	}
 	label[result] = 0;
 
+	if (chk_option)
+		check_ip_option(sock, ipv4, "Client read", chk_option);
+
 	if (!expected) {
-		result = getcon(&expected);
-		if (result < 0) {
-			perror("getcon");
-			close(sock);
-			exit(10);
+		if (get_sock_ctx) {
+			result = fgetfilecon(sock, &expected);
+			if (result < 0) {
+				perror("fgetfilecon");
+				close(sock);
+				exit(10);
+			}
+		} else {
+			result = getcon(&expected);
+			if (result < 0) {
+				perror("getcon");
+				close(sock);
+				exit(10);
+			}
 		}
 	}
 
diff --git a/tests/inet_socket/fb-deny-label-flush b/tests/inet_socket/fb-deny-label-flush
new file mode 100644
index 0000000..b769c63
--- /dev/null
+++ b/tests/inet_socket/fb-deny-label-flush
@@ -0,0 +1,6 @@ 
+#!/bin/sh
+
+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_inet_peer_t:s0
+netlabelctl unlbl del interface:lo address:::1/128 label:system_u:object_r:netlabel_deny_inet_peer_t:s0
diff --git a/tests/inet_socket/fb-deny-label-load b/tests/inet_socket/fb-deny-label-load
new file mode 100644
index 0000000..486022a
--- /dev/null
+++ b/tests/inet_socket/fb-deny-label-load
@@ -0,0 +1,8 @@ 
+#!/bin/sh
+
+# Fallback labeling
+netlabelctl map del default
+netlabelctl map add default address:0.0.0.0/0 protocol:unlbl
+netlabelctl map add default address:::/0 protocol:unlbl
+netlabelctl unlbl add interface:lo address:127.0.0.0/8 label:system_u:object_r:netlabel_inet_peer_t:s0
+netlabelctl unlbl add interface:lo address:::1/128 label:system_u:object_r:netlabel_deny_inet_peer_t:s0
diff --git a/tests/inet_socket/fb-label-flush b/tests/inet_socket/fb-label-flush
new file mode 100644
index 0000000..ca069c0
--- /dev/null
+++ b/tests/inet_socket/fb-label-flush
@@ -0,0 +1,6 @@ 
+#!/bin/sh
+
+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_inet_peer_t:s0
+netlabelctl unlbl del interface:lo address:::1/128 label:system_u:object_r:netlabel_inet_peer_t:s0
diff --git a/tests/inet_socket/fb-label-load b/tests/inet_socket/fb-label-load
new file mode 100644
index 0000000..6523099
--- /dev/null
+++ b/tests/inet_socket/fb-label-load
@@ -0,0 +1,8 @@ 
+#!/bin/sh
+
+# Fallback labeling
+netlabelctl map del default
+netlabelctl map add default address:0.0.0.0/0 protocol:unlbl
+netlabelctl map add default address:::/0 protocol:unlbl
+netlabelctl unlbl add interface:lo address:127.0.0.0/8 label:system_u:object_r:netlabel_inet_peer_t:s0
+netlabelctl unlbl add interface:lo address:::1/128 label:system_u:object_r:netlabel_inet_peer_t:s0
diff --git a/tests/inet_socket/test b/tests/inet_socket/test
index f09b4e3..4a49323 100755
--- a/tests/inet_socket/test
+++ b/tests/inet_socket/test
@@ -5,7 +5,7 @@  BEGIN {
     $basedir = $0;
     $basedir =~ s|(.*)/[^/]*|$1|;
 
-    $test_count = 30;
+    $test_count = 56;
 
     $test_ipsec = 0;
     if ( system("ip xfrm policy help 2>&1 | grep -q ctx") eq 0 ) {
@@ -23,7 +23,7 @@  BEGIN {
 
     $rc = `$basedir/../kvercmp $kvercur $kverminstream`;
     if ( $netlabelctl gt "021" and $rc > 0 ) {
-        $test_count += 3;
+        $test_count += 9;
         $test_calipso_stream = 1;
     }
 
@@ -45,6 +45,11 @@  BEGIN {
         $test_nft = 1;
     }
 
+    # Set up a GRE tunnel over loopback for testing cipso translate.
+    system "ip link add mygre type gretap local 127.0.0.1 remote 127.0.0.1";
+    system "ip addr add 10.123.123.123 dev mygre";
+    system "ip link set mygre up";
+
     plan tests => $test_count;
 }
 
@@ -71,6 +76,65 @@  sub server_end {
     system("rm -f $basedir/flag");
 }
 
+#
+# Test setting new socket contexts using setsockcreatecon(3) and
+# type_transition rules. Note that deny rules for these are only tested
+# once for each socket type (as for example they would never get as far
+# as testing cipso/calipso etc.).
+#
+# Test basics on stream
+$pid = server_start( "-t test_inet_server_t", "-n stream 65535" );
+
+# Set a new context on the socket using setsockcreatecon(3):
+$result = system
+"runcon -t test_inet_client_t -- $basedir/client -e nopeer -t inet_client_setsockcreatecon_t stream 127.0.0.1 65535";
+ok( $result eq 0 );
+
+# Deny socket { create } using setsockcreatecon(3):
+$result = system
+"runcon -t test_inet_deny_setsockcreatecon_t -- $basedir/client -e nopeer -t inet_client_setsockcreatecon_t stream 127.0.0.1 65535 2>&1";
+ok( $result >> 8 eq 3 );
+
+# Set a new context on the socket using type_transition rule, the -c option
+# checks and prints the new socket context:
+$result = system
+"runcon -t test_inet_new_type_client_t -- $basedir/client -e nopeer -c inet_client_type_transition_t stream 127.0.0.1 65535";
+ok( $result eq 0 );
+
+# Deny socket { create } using type_transition rule:
+$result = system
+"runcon -t test_inet_deny_type_transition_t -- $basedir/client -e nopeer stream 127.0.0.1 65535 2>&1";
+ok( $result >> 8 eq 3 );
+
+# Kill the server.
+server_end($pid);
+
+# Test basics on datagram
+$pid = server_start( "-t test_inet_server_t", "-n dgram 65535" );
+
+# Set a new context on the socket using setsockcreatecon(3):
+$result = system
+"runcon -t test_inet_client_t -- $basedir/client -e nopeer -t inet_client_setsockcreatecon_t dgram 127.0.0.1 65535";
+ok( $result eq 0 );
+
+# Deny socket { create } using setsockcreatecon(3):
+$result = system
+"runcon -t test_inet_deny_setsockcreatecon_t -- $basedir/client -e nopeer -t inet_client_setsockcreatecon_t dgram 127.0.0.1 65535 2>&1";
+ok( $result >> 8 eq 3 );
+
+# Set a new context on the socket using type_transition rule:
+$result = system
+"runcon -t test_inet_new_type_client_t -- $basedir/client -e nopeer -c inet_client_type_transition_t dgram 127.0.0.1 65535";
+ok( $result eq 0 );
+
+# Deny socket { create } using type_transition rule:
+$result = system
+"runcon -t test_inet_deny_type_transition_t -- $basedir/client -e nopeer dgram 127.0.0.1 65535 2>&1";
+ok( $result >> 8 eq 3 );
+
+# Kill the server.
+server_end($pid);
+
 # Load NetLabel configuration for full CIPSO/IPv4 labeling over loopback.
 system "/bin/sh $basedir/cipso-fl-load";
 
@@ -87,6 +151,18 @@  $result = system
 "runcon -t test_inet_bad_client_t -- $basedir/client stream 127.0.0.1 65535 2>&1";
 ok( $result >> 8 eq 5 );
 
+# Set a new context on socket using setsockcreatecon(3). Set -s to compare
+# client socket context, not the client process context.
+$result =
+  system
+"runcon -t test_inet_client_t -- $basedir/client -t inet_client_setsockcreatecon_t -s stream 127.0.0.1 65535";
+ok( $result eq 0 );
+
+# Set a new context on socket using type_transition rule.
+$result = system
+"runcon -t test_inet_new_type_client_t -- $basedir/client -s stream 127.0.0.1 65535";
+ok( $result eq 0 );
+
 # Kill the server.
 server_end($pid);
 
@@ -103,12 +179,148 @@  $result = system
 "runcon -t test_inet_bad_client_t -- $basedir/client dgram 127.0.0.1 65535 2>&1";
 ok( $result >> 8 eq 9 );
 
+# Set a new context on socket using setsockcreatecon(3).
+$result =
+  system
+"runcon -t test_inet_client_t -- $basedir/client -t inet_client_setsockcreatecon_t -s dgram 127.0.0.1 65535";
+ok( $result eq 0 );
+
+# Set a new context on socket using type_transition rule.
+$result = system
+"runcon -t test_inet_new_type_client_t -- $basedir/client -s dgram 127.0.0.1 65535";
+ok( $result eq 0 );
+
 # Kill the server.
 server_end($pid);
 
 # Flush NetLabel configuration.
 system "/bin/sh $basedir/cipso-fl-flush";
 
+# Load NetLabel configuration for CIPSO/IPv4 testing label translation.
+system "/bin/sh $basedir/cipso-trans-load";
+
+# Start the stream server with a defined level.
+$pid = server_start( "-t test_inet_server_t -l s0:c0,c2", "stream 65535" );
+
+# This is a translate over-the-wire of two cats:
+# trans doi:16 tags:1 levels:0=0 categories:0=1,2=3
+# The getsockopt(IP_OPTIONS) should be:
+# Type Len DOI          Tag Len Filler Sens Cats               cat:0123456..
+# 86   0b  00 00 00 10  01  05  00     00   5000 - This equates to 0101
+# The [-o option] compares with known string.
+$result = system
+"runcon -t test_inet_client_t -l s0:c0,c2 $basedir/client -e system_u:object_r:netlabel_peer_t:s0:c0,c2 -o 860b00000010010500005000 stream 127.0.0.1 65535";
+ok( $result eq 0 );
+
+# This does not use the translate option and therefore getsockopt(IP_OPTIONS):
+# Type Len DOI          Tag Len Filler Sens Cats               cat:0123456..
+# 86   0b  ff ff ff ff  01  05  00     00   a000 - This equates to 1010
+$result = system
+"runcon -t test_inet_client_t -l s0:c0,c2 $basedir/client -e system_u:object_r:netlabel_peer_t:s0:c0,c2 -o 860bffffffff01050000a000 stream 10.123.123.123 65535";
+ok( $result eq 0 );
+
+# Kill the server.
+server_end($pid);
+
+# Flush NetLabel configuration.
+system "/bin/sh $basedir/cipso-trans-flush";
+
+# Load NetLabel configuration for CIPSO/IPv4 testing domain:<domain> service
+system "/bin/sh $basedir/cipso-domain-load";
+
+# Start the stream server with a defined level.
+$pid = server_start( "-t test_inet_server_t -l s0:c20.c250", "stream 65535" );
+
+$result = system
+"runcon -t test_inet_client_t -l s0:c21.c31 $basedir/client -e system_u:object_r:netlabel_peer_t:s0:c21.c31 stream 127.0.0.1 65535";
+ok( $result eq 0 );
+
+# Set a new context on the socket using setsockcreatecon(3):
+$result = system
+"runcon -t test_inet_client_t -l s0:c21.c31 $basedir/client -e system_u:object_r:netlabel_peer_t:s0:c21.c31 -t inet_client_setsockcreatecon_t stream 127.0.0.1 65535";
+ok( $result eq 0 );
+
+# Set a new context on socket using type_transition rule:
+$result = system
+"runcon -t test_inet_new_type_client_t -l s0:c21.c31 $basedir/client -e system_u:object_r:netlabel_peer_t:s0:c21.c31 stream 127.0.0.1 65535";
+ok( $result eq 0 );
+
+# This fails with ENOENT on connect as no netlabel domain entry for this address:
+$result = system
+"runcon -t test_inet_client_t -l s0:c21.c31 $basedir/client -e system_u:object_r:netlabel_peer_t:s0:c21.c31 stream 10.123.123.123 65535 2>&1";
+ok( $result >> 8 eq 5 );
+
+# Kill the server.
+server_end($pid);
+
+# Flush NetLabel configuration.
+system "/bin/sh $basedir/cipso-domain-flush";
+
+# Test Netlabel Fallback IPv4 & IPv6. Note IPv6 datagram sockets are not yet
+# supported (see https://github.com/SELinuxProject/selinux-kernel/issues/24).
+system "/bin/sh $basedir/fb-label-load";
+$pid = server_start( "-t test_inet_server_t", "stream 65535" );
+
+# Verify that authorized client can communicate with the server.
+$result = system
+"runcon -t test_inet_client_t $basedir/client -e system_u:object_r:netlabel_inet_peer_t:s0 stream ::1 65535";
+ok( $result eq 0 );
+
+# Set a new context on the socket using setsockcreatecon(3):
+$result = system
+"runcon -t test_inet_client_t -- $basedir/client -e system_u:object_r:netlabel_inet_peer_t:s0 -t inet_client_setsockcreatecon_t stream 127.0.0.1 65535";
+ok( $result eq 0 );
+
+# Set a new context on the socket using type_transition rule, the -c option
+# checks and prints the new socket context:
+$result = system
+"runcon -t test_inet_new_type_client_t -- $basedir/client -e system_u:object_r:netlabel_inet_peer_t:s0 -c inet_client_type_transition_t stream 127.0.0.1 65535";
+ok( $result eq 0 );
+
+# Kill the server.
+server_end($pid);
+
+# Test fallback labeling on datagram
+$pid = server_start( "-t test_inet_server_t", "dgram 65535" );
+
+# Verify that authorized client can communicate with the server.
+$result = system
+"runcon -t test_inet_client_t $basedir/client -e system_u:object_r:netlabel_inet_peer_t:s0 dgram 127.0.0.1 65535";
+ok( $result eq 0 );
+
+# Set a new context on the socket using setsockcreatecon(3):
+$result = system
+"runcon -t test_inet_client_t -- $basedir/client -e system_u:object_r:netlabel_inet_peer_t:s0 -t inet_client_setsockcreatecon_t dgram 127.0.0.1 65535";
+ok( $result eq 0 );
+
+# Set a new context on the socket using type_transition rule:
+$result = system
+"runcon -t test_inet_new_type_client_t -- $basedir/client -e system_u:object_r:netlabel_inet_peer_t:s0 -c inet_client_type_transition_t dgram 127.0.0.1 65535";
+ok( $result eq 0 );
+
+# Kill the server.
+server_end($pid);
+
+system "/bin/sh $basedir/fb-label-flush";
+
+system "/bin/sh $basedir/fb-deny-label-load";
+$pid = server_start( "-t test_inet_server_t", "stream 65535" );
+
+# Verify that authorized client can communicate with the server.
+$result = system
+"runcon -t test_inet_client_t $basedir/client -e system_u:object_r:netlabel_inet_peer_t:s0 stream 127.0.0.1 65535";
+ok( $result eq 0 );
+
+# Deny server netlabel_deny_inet_peer_t, client times out.
+$result = system
+"runcon -t test_inet_client_t $basedir/client -e system_u:object_r:netlabel_deny_inet_peer_t:s0 stream ::1 65535 2>&1";
+ok( $result >> 8 eq 5 );
+
+# Kill the server.
+server_end($pid);
+
+system "/bin/sh $basedir/fb-deny-label-flush";
+
 # Load NetLabel configuration for CIPSO/IPv4 using TAG 1 over loopback.
 system "/bin/sh $basedir/cipso-load-t1";
 
@@ -461,10 +673,56 @@  if ($test_calipso_stream) {
 "runcon -t test_inet_client_t -l s0:c8.c12 -- $basedir/client stream ::1 65535 2>&1";
     ok( $result >> 8 eq 5 );
 
+    # Set a new context on the socket using setsockcreatecon(3):
+    $result = system
+"runcon -t test_inet_client_t -l s0:c0.c10 $basedir/client -e system_u:object_r:netlabel_peer_t:s0:c0.c10 -t inet_client_setsockcreatecon_t stream ::1 65535";
+    ok( $result eq 0 );
+
+    # Set a new context on the socket using type_transition rule, the -c option
+    # checks and prints the new socket context:
+    $result = system
+"runcon -t test_inet_new_type_client_t -l s0:c0.c10 $basedir/client -e system_u:object_r:netlabel_peer_t:s0:c0.c10 -c inet_client_type_transition_t stream ::1 65535";
+    ok( $result eq 0 );
+
     # Kill the stream server.
     server_end($pid);
 
     system "/bin/sh $basedir/calipso-flush";
+
+  # Load NetLabel configuration for CALIPSO/IPv6 testing domain:<domain> service
+    system "/bin/sh $basedir/calipso-domain-load";
+
+    # Start the stream server with a defined level.
+    $pid =
+      server_start( "-t test_inet_server_t -l s0:c20.c250", "stream 65535" );
+
+    $result = system
+"runcon -t test_inet_client_t -l s0:c21.c31 $basedir/client -e system_u:object_r:netlabel_peer_t:s0:c21.c31 stream ::1 65535";
+    ok( $result eq 0 );
+
+    # Set a new context on the socket using setsockcreatecon(3):
+    $result = system
+"runcon -t test_inet_client_t -l s0:c21.c31 $basedir/client -e system_u:object_r:netlabel_peer_t:s0:c21.c31 -t inet_client_setsockcreatecon_t stream ::1 65535";
+    ok( $result eq 0 );
+
+    # Set a new context on socket using type_transition rule:
+    $result = system
+"runcon -t test_inet_new_type_client_t -l s0:c21.c31 $basedir/client -e system_u:object_r:netlabel_peer_t:s0:c21.c31 stream ::1 65535";
+    ok( $result eq 0 );
+
+    # This fails with ENOENT on connect as no netlabel domain entry
+    # for this address:
+    $result = system
+"runcon -t test_inet_client_t -l s0:c21.c31 $basedir/client -e system_u:object_r:netlabel_peer_t:s0:c21.c31 stream 2000::1 65535 2>&1";
+    ok( $result >> 8 eq 5 );
+
+    # Kill the server.
+    server_end($pid);
+
+    # Flush NetLabel configuration.
+    system "/bin/sh $basedir/calipso-domain-flush";
 }
 
+system "ip link del mygre";
+
 exit;