From 26beb2fb195f5639f89b912dada9b5d4c5d2b79f Mon Sep 17 00:00:00 2001 From: Richard Haines Date: Mon, 30 Oct 2017 20:41:16 +0000 Subject: [PATCH] selinux-testsuite: Add SCTP test support The sctp testsuite should test all new sctp SELinux functionality. The README.sctp has details that should be followed before running tests. Signed-off-by: Richard Haines --- README.sctp | 73 +++ policy/Makefile | 2 + policy/test_sctp.cil | 451 ++++++++++++++++++ tests/Makefile | 2 +- tests/sctp/Makefile | 13 + tests/sctp/calipso-flush | 5 + tests/sctp/calipso-load | 7 + tests/sctp/cipso-fl-flush | 5 + tests/sctp/cipso-fl-load | 7 + tests/sctp/cipso-flush | 5 + tests/sctp/cipso-load | 7 + tests/sctp/fb-deny-label-flush | 6 + tests/sctp/fb-deny-label-load | 7 + tests/sctp/fb-label-flush | 6 + tests/sctp/fb-label-load | 8 + tests/sctp/iptables-flush | 4 + tests/sctp/iptables-load | 27 ++ tests/sctp/lksctp-func-tests/README | 26 ++ tests/sctp/lksctp-func-tests/run_calipso_tests | 22 + tests/sctp/lksctp-func-tests/run_cipso_tests | 22 + tests/sctp/lksctp-func-tests/run_func_tests | 19 + tests/sctp/remote-tests/README | 41 ++ tests/sctp/remote-tests/calipso-tests/README | 26 ++ .../remote-tests/calipso-tests/calipso-client1-run | 25 + .../remote-tests/calipso-tests/calipso-client2-run | 11 + .../sctp/remote-tests/calipso-tests/calipso-flush | 7 + .../remote-tests/calipso-tests/calipso-server-run | 24 + tests/sctp/remote-tests/calipso-tests/ipv6.cfg | 13 + tests/sctp/remote-tests/cipso-tests/README | 24 + .../remote-tests/cipso-tests/cipso-client1-run | 24 + .../remote-tests/cipso-tests/cipso-client2-run | 11 + tests/sctp/remote-tests/cipso-tests/cipso-flush | 7 + .../sctp/remote-tests/cipso-tests/cipso-server-run | 23 + tests/sctp/remote-tests/cipso-tests/ipv4.cfg | 13 + tests/sctp/remote-tests/multi-home-tests/README | 37 ++ .../remote-tests/multi-home-tests/mh-client-flush | 15 + .../remote-tests/multi-home-tests/mh-client1-run | 50 ++ .../remote-tests/multi-home-tests/mh-client2-run | 11 + .../remote-tests/multi-home-tests/mh-server-flush | 15 + .../remote-tests/multi-home-tests/mh-server-run | 50 ++ tests/sctp/remote-tests/multi-home-tests/mh.cfg | 15 + tests/sctp/sctp_asconf_params_client.c | 293 ++++++++++++ tests/sctp/sctp_asconf_params_server.c | 231 ++++++++++ tests/sctp/sctp_bind.c | 61 +++ tests/sctp/sctp_bindx.c | 116 +++++ tests/sctp/sctp_client.c | 225 +++++++++ tests/sctp/sctp_common.c | 156 +++++++ tests/sctp/sctp_common.h | 28 ++ tests/sctp/sctp_conformance_test_server.c | 298 ++++++++++++ tests/sctp/sctp_connectx.c | 123 +++++ tests/sctp/sctp_peeloff_server.c | 259 +++++++++++ tests/sctp/sctp_server.c | 332 ++++++++++++++ tests/sctp/sctp_set_params.c | 205 +++++++++ tests/sctp/sctp_set_peer_addr.c | 410 +++++++++++++++++ tests/sctp/sctp_set_pri_addr.c | 135 ++++++ tests/sctp/test | 502 +++++++++++++++++++++ 56 files changed, 4539 insertions(+), 1 deletion(-) create mode 100644 README.sctp create mode 100644 policy/test_sctp.cil create mode 100644 tests/sctp/Makefile create mode 100644 tests/sctp/calipso-flush create mode 100644 tests/sctp/calipso-load create mode 100644 tests/sctp/cipso-fl-flush create mode 100644 tests/sctp/cipso-fl-load create mode 100644 tests/sctp/cipso-flush create mode 100644 tests/sctp/cipso-load create mode 100644 tests/sctp/fb-deny-label-flush create mode 100644 tests/sctp/fb-deny-label-load create mode 100644 tests/sctp/fb-label-flush create mode 100644 tests/sctp/fb-label-load create mode 100644 tests/sctp/iptables-flush create mode 100644 tests/sctp/iptables-load create mode 100644 tests/sctp/lksctp-func-tests/README create mode 100644 tests/sctp/lksctp-func-tests/run_calipso_tests create mode 100644 tests/sctp/lksctp-func-tests/run_cipso_tests create mode 100644 tests/sctp/lksctp-func-tests/run_func_tests create mode 100644 tests/sctp/remote-tests/README create mode 100644 tests/sctp/remote-tests/calipso-tests/README create mode 100644 tests/sctp/remote-tests/calipso-tests/calipso-client1-run create mode 100644 tests/sctp/remote-tests/calipso-tests/calipso-client2-run create mode 100644 tests/sctp/remote-tests/calipso-tests/calipso-flush create mode 100644 tests/sctp/remote-tests/calipso-tests/calipso-server-run create mode 100644 tests/sctp/remote-tests/calipso-tests/ipv6.cfg create mode 100644 tests/sctp/remote-tests/cipso-tests/README create mode 100644 tests/sctp/remote-tests/cipso-tests/cipso-client1-run create mode 100644 tests/sctp/remote-tests/cipso-tests/cipso-client2-run create mode 100644 tests/sctp/remote-tests/cipso-tests/cipso-flush create mode 100644 tests/sctp/remote-tests/cipso-tests/cipso-server-run create mode 100644 tests/sctp/remote-tests/cipso-tests/ipv4.cfg create mode 100644 tests/sctp/remote-tests/multi-home-tests/README create mode 100644 tests/sctp/remote-tests/multi-home-tests/mh-client-flush create mode 100644 tests/sctp/remote-tests/multi-home-tests/mh-client1-run create mode 100644 tests/sctp/remote-tests/multi-home-tests/mh-client2-run create mode 100644 tests/sctp/remote-tests/multi-home-tests/mh-server-flush create mode 100644 tests/sctp/remote-tests/multi-home-tests/mh-server-run create mode 100644 tests/sctp/remote-tests/multi-home-tests/mh.cfg create mode 100644 tests/sctp/sctp_asconf_params_client.c create mode 100644 tests/sctp/sctp_asconf_params_server.c create mode 100644 tests/sctp/sctp_bind.c create mode 100644 tests/sctp/sctp_bindx.c create mode 100644 tests/sctp/sctp_client.c create mode 100644 tests/sctp/sctp_common.c create mode 100644 tests/sctp/sctp_common.h create mode 100644 tests/sctp/sctp_conformance_test_server.c create mode 100644 tests/sctp/sctp_connectx.c create mode 100644 tests/sctp/sctp_peeloff_server.c create mode 100644 tests/sctp/sctp_server.c create mode 100644 tests/sctp/sctp_set_params.c create mode 100644 tests/sctp/sctp_set_peer_addr.c create mode 100644 tests/sctp/sctp_set_pri_addr.c create mode 100755 tests/sctp/test diff --git a/README.sctp b/README.sctp new file mode 100644 index 0000000..348139b --- /dev/null +++ b/README.sctp @@ -0,0 +1,73 @@ + SCTP Testing + ============== + +1) The sctp testsuite has tests that should exercise all new sctp SELinux + functionality. The following is a summary: + + 1) Base configuration + 2) Connectx: SCTP_SOCKOPT_CONNECTX + 3) Bindx: SCTP_SOCKOPT_BINDX_ADD + 4) Address Reconfiguration: SCTP_PRIMARY_ADDR, + SCTP_SET_PEER_PRIMARY_ADDR, SCTP_PARAM_ADD_IP, SCTP_PARAM_SET_PRIMARY + 5) NetLabel Fallback labeling + 6) CIPSO loopback full-labeling + 7) CIPSO/IPv4 + 8) CALIPSO/IPv6 + 9) iptables/ip6tables + +2) Optionally running all the lksctp-tools/src/func_tests with and without + CIPSO/CALIPSO. See selinux-testsuite/tests/sctp/lksctp-func-tests/README + +3) Optionally running remote tests using lksctp-tools/src/apps/sctp_darn and + sctp_test with and without CIPSO/CALIPSO, see: + selinux-testsuite/tests/sctp/remote-tests/README + + +Test Requirements +------------------ + 1) libsepol 2.7 or greater that has support for the policycap + extended_socket_class. The CIL policy is configured for the sctp portcon + statement, therefore libsepol must be updated with the following patch: + http://arctic.selinuxproject.org/~rhaines/selinux-sctp/ + selinux-Add-support-for-the-SCTP-portcon-keyword.patch + + Otherwise the policy will not build. + + 2) The tests in tests/sctp/lksctp-func-tests and tests/sctp/remote-tests + require lksctp-tools. If testing with CIPSO/CALIPSO enabled, then one + func test requires a patch as test_1_to_1_connect "test 5" will fail as + NetLabel returns EPROTONOSUPPORT for illegal addresses. + + lksctp-tools has also been patched to allow sctp_test and sctp_darn to + display the process, peer and socket fd SELinux contexts using the -Z + option. It also patches sctp_test to show any socket ip options set for + testing CIPSO/CALIPSO. This patch is available from: + + http://arctic.selinuxproject.org/~rhaines/selinux-sctp/ + lksctp-tools-Add-SELinux-support-to-sctp_test-and-sc.patch + + The selinux-testsuite/policy/test_sctp.cil policy supports lksctp-tools + being installed in a user's home directory (user_home_t) or roots home + directory (admin_home_t). + + lksctp-tools can be obtained by: + git clone git://github.com/sctp/lksctp-tools.git + + The tools can then be built by adding the patch first (as it modifies + Makefile.am and configure.ac), then: + ./bootstrap + ./configure + make + +3) All SCTP regression tests "./sctp-tests run" run correctly in enforcing + mode. These are obtained from: https://github.com/sctp/sctp-tests + +4) All tests need to be run as root. + +POLICY NOTES: +1) test_sctp.cil has been built and tested on Fedora 27 targeted policy. + NOTE: The current Fedora Reference Policy does not support the sctp_socket + class yet, therefore it is added using CIL policy statements. + +2) It needs a good tidy up. + diff --git a/policy/Makefile b/policy/Makefile index 8ed5e46..462a5c2 100644 --- a/policy/Makefile +++ b/policy/Makefile @@ -111,6 +111,7 @@ load_general: all # General policy load @-/usr/sbin/setsebool allow_domain_fd_use=0 $(SEMODULE) -i test_policy/test_policy.pp + $(SEMODULE) -i test_sctp.cil unload_rhel: # RHEL specific policy unload @@ -119,6 +120,7 @@ unload_rhel: unload_general: # General policy unload @-/usr/sbin/setsebool allow_domain_fd_use=1 + $(SEMODULE) -r test_sctp $(SEMODULE) -r test_policy clean: diff --git a/policy/test_sctp.cil b/policy/test_sctp.cil new file mode 100644 index 0000000..d23814e --- /dev/null +++ b/policy/test_sctp.cil @@ -0,0 +1,451 @@ +; semodule -i test_sctp.cil +; semodule -r test_sctp + +; For SCTP DEV tests: +(allow unconfined_t self (sctp_socket (bind setopt listen read write accept connect getattr getopt shutdown))) +(allow unconfined_t sctp_port_t (sctp_socket (name_bind name_connect))) +(allow unconfined_t node_t (sctp_socket (node_bind))) +(allow unconfined_t port_t (sctp_socket (name_bind name_connect))) + +(allow unconfined_t admin_home_t (file (entrypoint))) + + +(allow test_sctp_client_t self (capability (net_raw))) + +(allow test_sctp_server_t netlabel_peer_t (sctp_socket (recvfrom))) + +; +;;;;;;;;;;;;;;;;;;;;;;;;;; Add SCTP_SOCKET info to policy ;;;;;;;;;;;;;;;;;;;; +; +(classorder (unordered sctp_socket)) +(classcommon sctp_socket socket) +(class sctp_socket (node_bind name_connect association)) + + +(policycap extended_socket_class) +; +;;;;;;;;;;;;;;; Declare an attribute that will hold all peers ;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;; allowed an association on socket_t ;;;;;;;;;;;;;;; +; +(typeattribute sctp_assoc_peers) +(typeattributeset sctp_assoc_peers (netlabel_peer_lo_t netlabel_peer_wlan_t + netlabel_peer_eth_t netlabel_peer_t netlabel_sctp_peer_t unlabeled_t)) + +(allow sctp_assoc_peers sctp_assoc_peers (sctp_socket (association))) +; These are required for NetLabel loopback with full labels: +(allow test_sctp_client_t self (sctp_socket (association))) +(allow test_sctp_client_t unlabeled_t (sctp_socket (association))) + + +;;avc: denied { create } for pid=8868 comm="sctp_server" scontext=unconfined_u:unconfined_r:test_sctp_server_t:s0:c0.c10 tcontext=unconfined_u:unconfined_r:test_sctp_server_t:s0:c0.c10 tclass=netlink_route_socket permissive=0 +(allow test_sctp_server_t self (netlink_route_socket (create bind getattr nlmsg_read))) +; +;;;;;;;;;;;;;;;;;;;; Entries for test_policy services ;;;;;;;;;;;;;;;;;;;;;; +; +;miscfiles_domain_entry_test_files(sctpsocketdomain) +(allow sysadm_t entry_type (file (getattr open read execute))) +(allow sysadm_t capabledomain (process (transition))) +(allow capabledomain sysadm_t (fd (use))) +(allow capabledomain sysadm_t (fifo_file (open getattr read write append ioctl lock))) +(allow capabledomain sysadm_t (process (sigchld))) + +;userdom_sysadm_entry_spec_domtrans_to(sctpsocketdomain) +(allow sctpsocketdomain test_file_t (file (entrypoint))) +(allow sctpsocketdomain test_file_t (file (getattr open read execute lock execute_no_trans map))) + +; +;;;;;;;;; Allow lksctp-tools func tests to run when locally installed ;;;;;;;; +(allow testdomain admin_home_t (file (read execute entrypoint))) +(allow testdomain user_home_t (file (read execute entrypoint))) +(allow testdomain user_devpts_t (chr_file (append))) + +; +;;;;;;;;;;;;;;; Allow lksctp-tools checksctp command to run ;;;;;;;;;;;;;;;;; +; +(allow unconfined_t self (sctp_socket (create))) + +;;;;;;;;;;;;;;;;; This is for testing NetLabel services ;;;;;;;;;;;;;;;;;;;;;; +(type netlabel_sctp_peer_t) + +; +;;;;;;;;;;;;;;;;;;;;;;;;;;; Select SCTP portcon ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; If libsepol has been updated to support the "sctp" portcon keyword then +; enable the TRUE set of statements, else use FALSE statement. +; +; TRUE: + (type sctp_port_t) + (roletype object_r sctp_port_t) + ; Set to (1024 1035) as func_tests start at 1024 with 10 clients (10 + 1). + (portcon sctp (1024 1035) (system_u object_r sctp_port_t ((s0) (s0)))) + ; This allows port 0 otherwise test_1_to_1_connectx will fail as it + ; tests illegal addr. + (portcon sctp 0 (system_u object_r sctp_port_t ((s0) (s0)))) + (allow sctpsocketdomain sctp_port_t (sctp_socket (name_bind name_connect))) + (allow sctpsocketdomain sctp_port_t (sctp_socket (name_bind name_connect))) +; +; FALSE: +; ; need to allow port initial SID: +; (allow sctpsocketdomain port_t (sctp_socket (name_bind name_connect))) +; + +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; SERVER ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +(type test_sctp_server_t) +(typeattributeset domain (test_sctp_server_t)) + +; Call MACRO +(call cil_unconfined_runs_test(test_sctp_server_t)) +(typeattributeset testdomain (test_sctp_server_t)) +(typeattribute sctpsocketdomain) +(typeattributeset sctpsocketdomain (test_sctp_server_t)) +(allow test_sctp_server_t self (sctp_socket (ioctl read getattr write setattr + append bind connect getopt setopt shutdown create listen accept))) + +(typeattributeset node_type (test_sctp_server_t)) +(allow test_sctp_server_t node_type (sctp_socket (node_bind))) +(allow test_sctp_server_t netif_t (netif (ingress egress))) +(allow test_sctp_server_t node_t (node (recvfrom sendto))) + +(allow test_sctp_server_t netlabel_sctp_peer_t (peer (recv))) +(allow netlabel_sctp_peer_t netif_t (netif (ingress egress))) +(allow netlabel_sctp_peer_t node_t (node (recvfrom))) + +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; GOOD CLIENT ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +(type test_sctp_client_t) +(typeattributeset domain (test_sctp_client_t)) + +; Call MACRO +(call cil_unconfined_runs_test(test_sctp_client_t)) + +(typeattributeset testdomain (test_sctp_client_t)) +(typeattributeset sctpsocketdomain (test_sctp_client_t)) +(allow test_sctp_client_t self (sctp_socket (ioctl read getattr write setattr + append bind connect getopt setopt shutdown create listen accept))) + +(allow test_sctp_client_t netif_t (netif (ingress egress))) +(allow test_sctp_client_t node_t (node (recvfrom sendto))) + +;# The server can receive labeled packets from the client. +(allow test_sctp_server_t test_sctp_client_t (peer (recv))) +;# And vice versa. +(allow test_sctp_client_t test_sctp_server_t (peer (recv))) + +(allow test_sctp_client_t netlabel_sctp_peer_t (peer (recv))) +(allow netlabel_sctp_peer_t netif_t (netif (ingress egress))) +(allow netlabel_sctp_peer_t node_t (node (recvfrom))) + +; +;;;;;;;;;;;;;;;; Required when Client/Server are on different ;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;; systems to allow ASCONF chunk checks ;;;;;;;;;;;;;;;;;;; +; +; Client side: +(allow kernel_t test_sctp_client_t (sctp_socket (connect))) + +; +;;;;;;;;;;;;;;;;;;;; Deny peer recv permission Client ;;;;;;;;;;;;;;;;;;;;;;;; +; +(type test_sctp_deny_peer_client_t) +(typeattributeset domain (test_sctp_deny_peer_client_t)) + +; Call MACRO +(call cil_unconfined_runs_test(test_sctp_deny_peer_client_t)) + +(typeattributeset testdomain (test_sctp_deny_peer_client_t)) +(typeattributeset sctpsocketdomain (test_sctp_deny_peer_client_t)) +(allow test_sctp_deny_peer_client_t self (sctp_socket (ioctl read getattr + write setattr append bind connect getopt setopt shutdown create + listen accept))) + +(allow test_sctp_deny_peer_client_t netif_t (netif (ingress egress))) +(allow test_sctp_deny_peer_client_t node_t (node (recvfrom sendto))) + +; +;;;;;;;;;;;;;;;;;;;;;;; Deny association permission ;;;;;;;;;;;;;;;;;;;;;;;;; +; + +; Declare this type for NetLabel etc. to allow the packet through the system, +; however do not allow an association: +(type deny_assoc_sctp_peer_t) + +(allow deny_assoc_sctp_peer_t netif_t (netif (ingress))) +(allow deny_assoc_sctp_peer_t node_t (node (recvfrom))) +(allow test_sctp_server_t deny_assoc_sctp_peer_t (peer (recv))) +(allow kernel_t deny_assoc_sctp_peer_t (peer (recv))) + + +(allow test_sctp_client_t deny_assoc_sctp_peer_t (peer(recv))) +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; CONNECTX ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +(type test_sctp_connectx_t) +(typeattributeset domain (test_sctp_connectx_t)) + +; Call MACRO +(call cil_unconfined_runs_test(test_sctp_connectx_t)) + +(typeattributeset testdomain (test_sctp_connectx_t)) +(typeattributeset sctpsocketdomain (test_sctp_connectx_t)) + +(allow test_sctp_connectx_t self (sctp_socket (ioctl read getattr write + setattr append bind connect getopt setopt shutdown create listen accept))) + +(allow test_sctp_connectx_t netif_t (netif (ingress egress))) +(allow test_sctp_connectx_t node_t (node (recvfrom sendto))) + +(allow test_sctp_server_t test_sctp_connectx_t (peer (recv))) +(allow test_sctp_connectx_t test_sctp_server_t (peer (recv))) + +(typeattributeset node_type (test_sctp_connectx_t)) +(allow test_sctp_connectx_t node_type (sctp_socket (node_bind))) + +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BINDX ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +(type test_sctp_bindx_t) +(typeattributeset domain (test_sctp_bindx_t)) + +; Call MACRO +(call cil_unconfined_runs_test(test_sctp_bindx_t)) + +(typeattributeset testdomain (test_sctp_bindx_t)) +(typeattributeset sctpsocketdomain (test_sctp_bindx_t)) + +(allow test_sctp_bindx_t self (sctp_socket (ioctl read getattr write setattr + append bind connect getopt setopt shutdown create listen accept))) + +(allow test_sctp_bindx_t netif_t (netif (ingress egress))) +(allow test_sctp_bindx_t node_t (node (recvfrom sendto))) + +(allow test_sctp_server_t test_sctp_bindx_t (peer (recv))) +(allow test_sctp_bindx_t test_sctp_server_t (peer (recv))) + +(typeattributeset node_type (test_sctp_bindx_t)) +(allow test_sctp_bindx_t node_type (sctp_socket (node_bind))) + +; +;;;;;;;;;; SET_PRI_ADDR + SET_PEER ADDR for ASCONF process testing ;;;;;;;;;; +; +(type test_sctp_set_peer_addr_t) +(typeattributeset domain (test_sctp_set_peer_addr_t)) + +; Call MACRO +(call cil_unconfined_runs_test(test_sctp_set_peer_addr_t)) + +(typeattributeset testdomain (test_sctp_set_peer_addr_t)) +(typeattributeset sctpsocketdomain (test_sctp_set_peer_addr_t)) + +(allow test_sctp_set_peer_addr_t self (sctp_socket (ioctl read getattr + write setattr append bind connect getopt setopt shutdown create + listen accept))) + +(allow test_sctp_set_peer_addr_t netif_t (netif (ingress egress))) +(allow test_sctp_set_peer_addr_t node_t (node (recvfrom sendto))) + +(allow test_sctp_server_t test_sctp_set_peer_addr_t (peer (recv))) +(allow test_sctp_set_peer_addr_t test_sctp_server_t (peer (recv))) + +(typeattributeset node_type (test_sctp_set_peer_addr_t)) +(allow test_sctp_set_peer_addr_t node_type (sctp_socket (node_bind))) + +; Add this to allow SCTP_PARAM_ADD_IP to client. +;(allow test_sctp_set_peer_addr_t test_sctp_client_t (sctp_socket (connect))) + +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +;;;;;;;;;;;;;;;;;;;; Allow the lksctp test suite to run ;;;;;;;;;;;;;;;;;;;;;; +; +(type test_lksctp_suite_t) +(typeattributeset domain (test_lksctp_suite_t)) +(typeattributeset testdomain (test_lksctp_suite_t)) +(typeattributeset sctpsocketdomain (test_lksctp_suite_t)) + +; Call MACRO +(call cil_unconfined_runs_test(test_lksctp_suite_t)) + +(allow test_lksctp_suite_t self (sctp_socket (ioctl read getattr write setattr + append bind connect getopt setopt shutdown create listen accept))) + +(allow test_lksctp_suite_t netif_t (netif (ingress egress))) +(allow test_lksctp_suite_t node_t (node (recvfrom sendto))) + +; Additional entries to run lksctp test suite using: +; runcon -t test_lksctp_suite_t ./run_func_tests /path/to/lksctp_tools +(allow test_lksctp_suite_t shell_exec_t (file (execute map))) +(allow test_lksctp_suite_t tmp_t (dir (add_name remove_name write read))) +(allow test_lksctp_suite_t tmp_t (file (create open unlink write read))) +(allow test_lksctp_suite_t node_t (sctp_socket (node_bind))) +(allow test_lksctp_suite_t self (tcp_socket (create getopt))) +(allow test_lksctp_suite_t bin_t (file (execute execute_no_trans map))) +(allow test_lksctp_suite_t port_t (sctp_socket (name_connect))) + +; Stuff ???? +(allow test_lksctp_suite_t self (netlink_route_socket (create bind getattr nlmsg_read))) +(allow test_lksctp_suite_t sssd_var_lib_t (dir (search))) +(allow test_lksctp_suite_t net_conf_t (file (getattr open read))) +(allow test_lksctp_suite_t net_conf_t (lnk_file (read))) + +(allow test_lksctp_suite_t deny_assoc_sctp_peer_t (peer (recv))) + +; These depend on where lksctp_tools are located: +(allow test_lksctp_suite_t admin_home_t (file (setattr unlink rename create execute_no_trans getattr ioctl open read write entrypoint map))) +(allow test_lksctp_suite_t user_home_t (file (setattr unlink rename create execute_no_trans getattr ioctl open read write entrypoint map))) +(allow test_lksctp_suite_t admin_home_t (dir (add_name remove_name write read))) +(allow test_lksctp_suite_t user_home_t (dir (add_name remove_name write read))) + + +; +;;;;;;;;;;;;;;;;;;;;;;;; Define peer labels and rules ;;;;;;;;;;;;;;;;;;;;;;;;; +; +(type netlabel_peer_lo_t) +(type netlabel_peer_wlan_t) +(type netlabel_peer_eth_t) +(roletype object_r netlabel_peer_wlan_t) +(roletype object_r netlabel_peer_eth_t) + +(allow test_lksctp_suite_t sctp_assoc_peers (peer (recv))) +(allow sctp_assoc_peers netif_t (netif (ingress egress))) +(allow sctp_assoc_peers node_t (node (recvfrom))) + +(allow test_sctp_server_t sctp_assoc_peers (peer (recv))) + +; +;;;;;;;;;;;;;;;;;;; Define SECMARK packet labels and rules ;;;;;;;;;;;;;;;;;;;; +; +; All packets other than sctp with ports 1024 - 1035 are SECMARK'ed using +; iptables with default_packet_t. There is an 'allow' rule for this because +; SCTP func_tests try illegal addresses, so needed to pass tests, plus all +; other network traffic requires system access. +(type default_packet_t) +(type sctp_packet_lo_t) +(type sctp_packet_wlan_t) +(type sctp_packet_eth_t) +(roletype object_r default_packet_t) +(roletype object_r sctp_packet_lo_t) +(roletype object_r sctp_packet_wlan_t) +(roletype object_r sctp_packet_eth_t) +(typeattribute sctp_packets) +(typeattributeset sctp_packets (default_packet_t sctp_packet_lo_t + sctp_packet_wlan_t sctp_packet_eth_t)) + +(allow test_lksctp_suite_t sctp_packets (packet(send recv relabelto))) +(allow unconfined_t sctp_packets (packet(relabelto))) +(allow kernel_t default_packet_t (packet (send))) +; +;;;;;;;;;;;;;;;;;;;;;;; End lksctp test suite entries ;;;;;;;;;;;;;;;;;;;;;;;; +; + + +; +;;;;;;;;;;;;;;;;;;;;;;;;; SECMARK-specific policy ;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +(type test_sctp_server_packet_t) +(allow unconfined_t test_sctp_server_packet_t (packet (relabelto))) +(allow test_sctp_server_t test_sctp_server_packet_t (packet (send recv))) +(allow test_sctp_client_t test_sctp_server_packet_t (packet (send recv))) + + + +; +;;;;;;;;;;;;;; Common rules for all sctp socket test domains ;;;;;;;;;;;;;;;; +; +; Send/recv unlabeled packets. +(allow sctpsocketdomain unlabeled_t (packet (send recv))) +(allow sctpsocketdomain unlabeled_t (peer (recv))) + +(allow sctpsocketdomain netlabel_peer_t (peer (recv))) +(allow netlabel_peer_t netif_t (netif (ingress egress))) +(allow netlabel_peer_t node_t (node (recvfrom))) + +(allow sctpsocketdomain kernel_t (system (module_request))) + + +;;; Required when using getaddrinfo(3), if_nametoindex(3) type functions ;;;;; +;;;;;;;;;; when resolving IPv6 link local addresses e.g. addr% ;;;;;;;;;;; + +(allow sctpsocketdomain proc_net_t (file (read))) +(allow sctpsocketdomain sysctl_net_t (dir (search))) +(allow sctpsocketdomain self (udp_socket (create))) +(allow sctpsocketdomain self (unix_dgram_socket (create ioctl))) + + +; +;;;;;;;;;;;;;;;;;;;; MLS Rules for sctp_socket ;;;;;;;;;;;;;;;;;;;;;;;;; +; + +;;;;;;;;;;;;;;;;;;;;;;;;; MLS POLICY RULES ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;(mlsconstrain (sctp_socket (relabelto)) +; (dom h1 h2)) +; +;(mlsconstrain (sctp_socket (accept connect)) +; (or (eq l1 l2) +; (and (or (and (eq t1 mlsnetreadtoclr) +; (dom h1 l2)) (eq t1 mlsnetread)) +; (or (or (and (and (eq t1 mlsnetwriteranged) +; (dom l1 l2)) (domby l1 h2)) +; (and (and (eq t1 mlsnetwritetoclr) +; (dom h1 l2)) (domby l1 l2))) +; (eq t1 mlsnetwrite))))) +; +;(mlsconstrain (sctp_socket (read getattr listen accept getopt)) +; (or (or (dom l1 l2) +; (and (eq t1 mlsnetreadtoclr) +; (dom h1 l2))) +; (eq t1 mlsnetread))) +; +;(mlsconstrain (sctp_socket (write setattr relabelfrom connect setopt shutdown)) +; (or (or (or (eq l1 l2) +; (and (and (eq t1 mlsnetwriteranged) +; (dom l1 l2)) (domby l1 h2))) +; (and (and (eq t1 mlsnetwritetoclr) +; (dom h1 l2)) (domby l1 l2))) +; (eq t1 mlsnetwrite))) +; +;(mlsconstrain (sctp_socket (recvfrom)) +; (or (or (eq l1 l2) +; (and (eq t1 mlsnetreadtoclr) +; (dom h1 l2))) +; (eq t1 mlsnetread))) +; +;;;;;;;;;;;;;;;;;;;;;;;;; END MLS POLICY RULES ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; mlsconstrain sctp_socket node_bind (h1 dom h2 or ( t1 != mcs_constrained_type )); +(mlsconstrain (sctp_socket (node_bind)) + (or (dom h1 h2) (neq t1 mcs_constrained_type))) + +;constrain sctp_socket { relabelto create relabelfrom } (u1 == u2 or ( t1 == can_change_object_identity )); +(constrain (sctp_socket (relabelto create relabelfrom)) + (or (eq u1 u2) (eq t1 can_change_object_identity))) + +;(mlsconstrain (sctp_socket (connect)) +; (or (dom l1 l2) +; (and (neq t1 mcs_constrained_type) +; (neq t2 mcs_constrained_type)))) + +;(mlsconstrain (sctp_socket (connect)) +; (or (dom l1 l2) (dom h1 h2))) + +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MACRO ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +(macro cil_unconfined_runs_test ((type ARG1)) + ; Transition from the caller to the test domain. + (allow unconfined_t ARG1 (process (transition))) + (roletype unconfined_r ARG1) + ; Report back from the test domain to the caller. + (allow ARG1 unconfined_t (fd (use))) + (allow ARG1 unconfined_devpts_t (chr_file (read write ioctl getattr))) + (allow ARG1 unconfined_t (fifo_file (read write ioctl getattr))) + (allow ARG1 unconfined_t (process (sigchld))) + + ; allow to use leaked fd from init/init scripts + (allow ARG1 init_t (fd (use))) + (allow ARG1 initrc_t (fd (use))) + (allow ARG1 console_device_t (chr_file (read write ioctl))) +) + diff --git a/tests/Makefile b/tests/Makefile index f2291b2..d02e194 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -11,7 +11,7 @@ SUBDIRS:= domain_trans entrypoint execshare exectrace execute_no_trans \ task_getpgid task_setpgid file ioctl capable_file capable_net \ capable_sys dyntrans dyntrace bounds nnp_nosuid mmap unix_socket \ inet_socket overlay checkreqprot mqueue mac_admin infiniband_pkey \ - infiniband_endport atsecure + infiniband_endport atsecure sctp ifeq ($(shell grep -q cap_userns $(POLDEV)/include/support/all_perms.spt && echo true),true) ifneq ($(shell ./kvercmp $$(uname -r) 4.7),-1) diff --git a/tests/sctp/Makefile b/tests/sctp/Makefile new file mode 100644 index 0000000..0f39f03 --- /dev/null +++ b/tests/sctp/Makefile @@ -0,0 +1,13 @@ +TARGETS = sctp_client sctp_server sctp_bind sctp_bindx sctp_connectx sctp_set_params sctp_set_peer_addr sctp_set_pri_addr sctp_asconf_params_client sctp_asconf_params_server sctp_peeloff_server sctp_conformance_test_server + +DEPS = sctp_common.c sctp_common.h +CFLAGS ?= -Wall + +LDLIBS += -lselinux -lsctp + +all: $(TARGETS) + +clean: + rm -f $(TARGETS) + +$(TARGETS): $(DEPS) diff --git a/tests/sctp/calipso-flush b/tests/sctp/calipso-flush new file mode 100644 index 0000000..5143962 --- /dev/null +++ b/tests/sctp/calipso-flush @@ -0,0 +1,5 @@ +#!/bin/sh +# Reset NetLabel configuration to unlabeled after CALIPSO/IPv6 tests. +netlabelctl map del default +netlabelctl calipso del doi:16 +netlabelctl map add default protocol:unlbl diff --git a/tests/sctp/calipso-load b/tests/sctp/calipso-load new file mode 100644 index 0000000..4bb9c7f --- /dev/null +++ b/tests/sctp/calipso-load @@ -0,0 +1,7 @@ +#!/bin/sh +# Define a doi for testing loopback for CALIPSO/IPv6. +netlabelctl calipso add pass doi:16 +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:::1 protocol:calipso,16 diff --git a/tests/sctp/cipso-fl-flush b/tests/sctp/cipso-fl-flush new file mode 100644 index 0000000..032960d --- /dev/null +++ b/tests/sctp/cipso-fl-flush @@ -0,0 +1,5 @@ +#!/bin/sh + +netlabelctl map del default +netlabelctl cipsov4 del doi:1 +netlabelctl map add default protocol:unlbl diff --git a/tests/sctp/cipso-fl-load b/tests/sctp/cipso-fl-load new file mode 100644 index 0000000..3ef85b4 --- /dev/null +++ b/tests/sctp/cipso-fl-load @@ -0,0 +1,7 @@ +#!/bin/sh + +netlabelctl cipsov4 add local 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 default address:127.0.0.1 protocol:cipsov4,1 diff --git a/tests/sctp/cipso-flush b/tests/sctp/cipso-flush new file mode 100644 index 0000000..6da5b05 --- /dev/null +++ b/tests/sctp/cipso-flush @@ -0,0 +1,5 @@ +#!/bin/sh +# Reset NetLabel configuration to unlabeled for all after CIPSO/IPv4 tests. +netlabelctl map del default +netlabelctl cipsov4 del doi:16 +netlabelctl map add default protocol:unlbl diff --git a/tests/sctp/cipso-load b/tests/sctp/cipso-load new file mode 100644 index 0000000..661afb8 --- /dev/null +++ b/tests/sctp/cipso-load @@ -0,0 +1,7 @@ +#!/bin/sh + +netlabelctl cipsov4 add pass doi:16 tags:5 +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:cipsov4,16 diff --git a/tests/sctp/fb-deny-label-flush b/tests/sctp/fb-deny-label-flush new file mode 100644 index 0000000..059e0b7 --- /dev/null +++ b/tests/sctp/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_sctp_peer_t:s0 +netlabelctl unlbl del interface:lo address:::1/128 label:system_u:object_r:deny_assoc_sctp_peer_t:s0 diff --git a/tests/sctp/fb-deny-label-load b/tests/sctp/fb-deny-label-load new file mode 100644 index 0000000..7c0bd87 --- /dev/null +++ b/tests/sctp/fb-deny-label-load @@ -0,0 +1,7 @@ +#!/bin/sh + +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_sctp_peer_t:s0 +netlabelctl unlbl add interface:lo address:::1/128 label:system_u:object_r:deny_assoc_sctp_peer_t:s0 diff --git a/tests/sctp/fb-label-flush b/tests/sctp/fb-label-flush new file mode 100644 index 0000000..13573a8 --- /dev/null +++ b/tests/sctp/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_sctp_peer_t:s0 +netlabelctl unlbl del interface:lo address:::1/128 label:system_u:object_r:netlabel_sctp_peer_t:s0 diff --git a/tests/sctp/fb-label-load b/tests/sctp/fb-label-load new file mode 100644 index 0000000..a501515 --- /dev/null +++ b/tests/sctp/fb-label-load @@ -0,0 +1,8 @@ +#!/bin/sh + +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_sctp_peer_t:s0 +netlabelctl unlbl add interface:lo address:::1/128 label:system_u:object_r:netlabel_sctp_peer_t:s0 +#netlabelctl -p unlbl list diff --git a/tests/sctp/iptables-flush b/tests/sctp/iptables-flush new file mode 100644 index 0000000..e74271a --- /dev/null +++ b/tests/sctp/iptables-flush @@ -0,0 +1,4 @@ +#!/bin/sh +# Flush the security table after IPv4 and IPv6 tests. +iptables -t security -F +ip6tables -t security -F diff --git a/tests/sctp/iptables-load b/tests/sctp/iptables-load new file mode 100644 index 0000000..9dac576 --- /dev/null +++ b/tests/sctp/iptables-load @@ -0,0 +1,27 @@ +#!/bin/sh +############################ SECMARK IPTABLE ENTRIES ######################## +# +# Flush the security table first: +iptables -t security -F +ip6tables -t security -F + +#-------------- INPUT IP Stream --------------------# +# These rules will replace the above context if sctp ports 1024:1035 are found in the packets: +iptables -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 + +iptables -t security -A INPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --save + +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 + +#-------------- OUTPUT IP Stream --------------------# +# These rules will replace the above context if sctp ports 1024:1035 are found in the packets: +iptables -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 + +iptables -t security -A OUTPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --save + +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 + diff --git a/tests/sctp/lksctp-func-tests/README b/tests/sctp/lksctp-func-tests/README new file mode 100644 index 0000000..fb3fbf9 --- /dev/null +++ b/tests/sctp/lksctp-func-tests/README @@ -0,0 +1,26 @@ +All lksctp-tools/src/func_tests run correctly in enforcing mode. + +The selinux-testsuite policy module must be loaded: +make -C policy load + + +To run lksctp-tools function tests execute the following: +sh ./run_func_tests + +################################## NOTE ####################################### +When running CIPSO/CALIPSO without patching lksctp-tools, test_1_to_1_connect +"test 5" will fail as NetLabel returns EPROTONOSUPPORT for illegal addresses. +The following patch can be applied to lksctp-tools: + http://arctic.selinuxproject.org/~rhaines/selinux-sctp/ + lksctp-tools-Add-SELinux-support-to-sctp_test-and-sc.patch +############################################################################### + +To run CIPSO tests with a large set of categories producing a large +ip_option set: +sh ./run_cipso_tests + + +To run CALIPSO tests with a large set of categories producing a large +ip_option set: +sh ./run_calipso_tests + diff --git a/tests/sctp/lksctp-func-tests/run_calipso_tests b/tests/sctp/lksctp-func-tests/run_calipso_tests new file mode 100644 index 0000000..8308953 --- /dev/null +++ b/tests/sctp/lksctp-func-tests/run_calipso_tests @@ -0,0 +1,22 @@ +#!/bin/sh + +list="test_1_to_1_accept_close test_1_to_1_addrs test_1_to_1_connect test_1_to_1_connectx test_1_to_1_events test_1_to_1_initmsg_connect test_1_to_1_nonblock test_1_to_1_recvfrom test_1_to_1_recvmsg test_1_to_1_rtoinfo test_1_to_1_send test_1_to_1_sendmsg test_1_to_1_sendto test_1_to_1_shutdown test_1_to_1_socket_bind_listen test_1_to_1_sockopt test_1_to_1_threads test_assoc_abort test_assoc_shutdown test_autoclose test_basic test_basic_v6 test_connect test_connectx test_fragments test_fragments_v6 test_getname test_getname_v6 test_inaddr_any test_inaddr_any_v6 test_peeloff test_peeloff_v6 test_recvmsg test_sctp_sendrecvmsg test_sctp_sendrecvmsg_v6 test_sockopt test_sockopt_v6 test_tcp_style test_tcp_style_v6 test_timetolive test_timetolive_v6" + +if [ "$1" = "" ]; then + echo "Require path to lksctp-tools" + exit +fi + +/bin/sh ../calipso-load + +for i in $list + do runcon -t test_lksctp_suite_t -l s0:c223,c224,c225,c226,c227,c228,c229,c230,c231,c232,c233,c234,c235,c236,c237,c238,c239,c240,c241,c242,c243,c244,c245,c246,c247,c248,c249,c250,c251,c252,c253,c254,c255,c256,c257,c258,c259,c260,c261,c262,c263,c264,c265,c266,c267,c268,c269,c270,c271,c272,c273,c274,c275,c276,c277,c278,c279,c280,c281,c282,c283,c284,c285,c286,c287,c288,c289,c290,c291,c292,c293,c294,c295,c296,c297,c298,c299,c300,c301,c302,c303,c304,c305,c306,c307,c308,c309,c310,c311,c312,c313,c314,c315,c316,c317,c318,c319,c320,c321,c322,c323,c324,c325,c326,c327,c328,c329,c330,c331,c332,c333,c334,c335,c336,c337,c338,c339,c340,c341,c342,c343,c344,c345,c346,c347,c348,c349,c350,c351,c352,c353,c354,c355,c356,c357,c358,c359,c360,c361,c362,c363,c364,c365,c366,c367,c368,c369,c370,c371,c372,c373,c374,c375,c376,c377,c378,c379,c380,c381,c382,c383,c384,c385,c386,c387,c388,c389,c390,c391,c392,c393,c394,c395,c396,c397,c398,c399,c400,c401,c402,c403,c404,c405,c406,c407,c408,c409,c410,c411,c412,c413,c414,c415,c416,c417,c418,c419,c420,c421,c422,c423,c424,c425,c426,c427,c428,c429,c430,c431,c432,c433,c434,c435,c436,c437,c438,c439,c440,c441,c442,c443,c444,c445,c446,c447,c448,c449,c450,c451,c452,c453,c454,c455,c456,c457,c458,c459,c460,c461,c462,c463,c464,c465,c466,c467,c468,c469,c470,c471,c472,c473,c474,c475,c476,c477,c478,c479,c480,c481,c482,c483,c484,c485,c486,c487,c488,c489,c490,c491,c492,c493,c494,c495,c496,c497,c498,c499,c500,c501,c502,c503,c504,c505,c506,c507,c508,c509,c510,c511,c512,c513,c514,c515,c516,c517,c518,c519,c520,c521,c522,c523,c524,c525,c526,c527,c528,c529,c530,c531,c532,c533,c534,c535,c536,c537,c538,c539,c540,c541,c542,c543,c544,c545,c546,c547,c548,c549,c550,c551,c552,c553,c554,c555,c556,c557,c558,c559,c560,c561,c562,c563,c564,c565,c566,c567,c568,c569,c570,c571,c572,c573,c574,c575,c576,c577,c578,c579,c580,c581,c582,c583,c584,c585,c586,c587,c588,c589,c590,c591,c592,c593,c594,c595,c596,c597,c598,c599,c600,c601,c602,c603,c604,c605,c606,c607,c608,c609,c610,c611,c612,c613,c614,c615,c616,c617,c618,c619,c620,c621,c622,c623,c624,c625,c626,c627,c628,c629,c630,c631,c632,c633,c634,c635,c636,c637,c638,c639,c640,c641,c642,c643,c644,c645,c646,c647,c648,c649,c650,c651,c652,c653,c654,c655,c656,c657,c658,c659,c660,c661,c662,c663,c664,c665,c666,c667,c668,c669,c670,c671,c672,c673,c674,c675,c676,c677,c678,c679,c680,c681,c682,c683,c684,c685,c686,c687,c688,c689,c690,c691,c692,c693,c694,c695,c696,c697,c698,c699,c700,c701,c702,c703,c704,c705,c706,c707,c708,c709,c710,c711,c712,c713,c714,c715,c716,c717,c718,c719,c720,c721,c722,c723,c724,c725,c726,c727,c728,c729,c730,c731,c732,c733,c734,c735,c736,c737,c738,c739,c740,c741,c742,c743,c744,c745,c746,c747,c748,c749,c750,c751,c752,c753,c754,c755,c756,c757,c758,c759,c760,c761,c762,c763,c764,c765,c766,c767,c768,c769,c770,c771,c772,c773,c774,c775,c776,c777,c778,c779,c780,c781,c782,c783,c784,c785,c786,c787,c788,c789,c790,c791,c792,c793,c794,c795,c796,c797,c798,c799,c800,c801,c802,c803,c804,c805,c806,c807,c808,c809,c810,c811,c812,c813,c814,c815,c816,c817,c818,c819,c820,c821,c822,c823,c824,c825,c826,c827,c828,c829,c830,c831,c832,c833,c834,c835,c836,c837,c838,c839,c840,c841,c842,c843,c844,c845,c846,c847,c848,c849,c850,c851,c852,c853,c854,c855,c856,c857,c858,c859,c860,c861,c862,c863,c864,c865,c866,c867,c868,c869,c870,c871,c872,c873,c874,c875,c876,c877,c878,c879,c880,c881,c882,c883,c884,c885,c886,c887,c888,c889,c890,c891,c892,c893,c894,c895,c896,c897,c898,c899,c900,c901,c902,c903,c904,c905,c906,c907,c908,c909,c910,c911,c912,c913,c914,c915,c916,c917,c918,c919,c920,c921,c922,c923,c924,c925,c926,c927,c928,c929,c930,c931,c932,c933,c934,c935,c936,c937,c938,c939,c940,c941,c942,c943,c944,c945,c946,c947,c948,c949,c950,c951,c952,c953,c954,c955,c956,c957,c958,c959,c960,c961,c962,c963,c964,c965,c966,c967,c968,c969,c970,c971,c972,c973,c974,c975,c976,c977,c978,c979,c980,c981,c982,c983,c984,c985,c986,c987,c988,c989,c990,c991,c992,c993,c994,c995,c996,c997,c998,c999,c1000,c1001,c1002,c1003,c1004,c1005,c1006,c1007,c1008,c1009,c1010,c1011,c1012,c1013,c1014,c1015,c1016,c1017,c1018,c1019,c1020,c1021,c1022,c1023 "$1/lksctp-tools/src/func_tests/$i" + if [ $? != 0 ]; then + echo -e "\nCALIPSO/V6 func_test $i FAILED\n" + /bin/sh ../calipso-flush + exit + fi + done + +/bin/sh ../calipso-flush +echo -e "\nCALIPSO/V6 tests passed.\n" diff --git a/tests/sctp/lksctp-func-tests/run_cipso_tests b/tests/sctp/lksctp-func-tests/run_cipso_tests new file mode 100644 index 0000000..3c6e7cb --- /dev/null +++ b/tests/sctp/lksctp-func-tests/run_cipso_tests @@ -0,0 +1,22 @@ +#!/bin/sh + +list="test_1_to_1_accept_close test_1_to_1_addrs test_1_to_1_connect test_1_to_1_connectx test_1_to_1_events test_1_to_1_initmsg_connect test_1_to_1_nonblock test_1_to_1_recvfrom test_1_to_1_recvmsg test_1_to_1_rtoinfo test_1_to_1_send test_1_to_1_sendmsg test_1_to_1_sendto test_1_to_1_shutdown test_1_to_1_socket_bind_listen test_1_to_1_sockopt test_1_to_1_threads test_assoc_abort test_assoc_shutdown test_autoclose test_basic test_basic_v6 test_connect test_connectx test_fragments test_fragments_v6 test_getname test_getname_v6 test_inaddr_any test_inaddr_any_v6 test_peeloff test_peeloff_v6 test_recvmsg test_sctp_sendrecvmsg test_sctp_sendrecvmsg_v6 test_sockopt test_sockopt_v6 test_tcp_style test_tcp_style_v6 test_timetolive test_timetolive_v6" + +if [ "$1" = "" ]; then + echo "Require path to lksctp-tools" + exit +fi + +/bin/sh ../cipso-load + +for i in $list + do runcon -t test_lksctp_suite_t -l s0:c782,c714,c769,c788,c803,c842,c864 "$1/lksctp-tools/src/func_tests/$i" + if [ $? != 0 ]; then + echo -e "\nCIPSO/V4 func_test $i FAILED\n" + /bin/sh ../cipso-flush + exit + fi + done + +echo -e "\nCIPSO/V4 tests passed.\n" +/bin/sh ../cipso-flush diff --git a/tests/sctp/lksctp-func-tests/run_func_tests b/tests/sctp/lksctp-func-tests/run_func_tests new file mode 100644 index 0000000..74ee838 --- /dev/null +++ b/tests/sctp/lksctp-func-tests/run_func_tests @@ -0,0 +1,19 @@ +#!/bin/sh + +list="test_1_to_1_accept_close test_1_to_1_addrs test_1_to_1_connect test_1_to_1_connectx test_1_to_1_events test_1_to_1_initmsg_connect test_1_to_1_nonblock test_1_to_1_recvfrom test_1_to_1_recvmsg test_1_to_1_rtoinfo test_1_to_1_send test_1_to_1_sendmsg test_1_to_1_sendto test_1_to_1_shutdown test_1_to_1_socket_bind_listen test_1_to_1_sockopt test_1_to_1_threads test_assoc_abort test_assoc_shutdown test_autoclose test_basic test_basic_v6 test_connect test_connectx test_fragments test_fragments_v6 test_getname test_getname_v6 test_inaddr_any test_inaddr_any_v6 test_peeloff test_peeloff_v6 test_recvmsg test_sctp_sendrecvmsg test_sctp_sendrecvmsg_v6 test_sockopt test_sockopt_v6 test_tcp_style test_tcp_style_v6 test_timetolive test_timetolive_v6" + +if [ "$1" = "" ]; then + echo "Require path to lksctp-tools" + exit +fi + +for i in $list + do runcon -t test_lksctp_suite_t "$1/lksctp-tools/src/func_tests/$i" + if [ $? != 0 ]; then + echo -e "\nfunc_test $i FAILED\n" + exit + fi + done + +echo -e "\nAll func_tests passed.\n" + diff --git a/tests/sctp/remote-tests/README b/tests/sctp/remote-tests/README new file mode 100644 index 0000000..36da0f3 --- /dev/null +++ b/tests/sctp/remote-tests/README @@ -0,0 +1,41 @@ +The selinux-testsuite policy module must be loaded: +make -C policy load + +The test setup is shown in the following diagram: + + -------------- Wireless Router ---------------- + / \ + / \ + / \ + 192.168.1.77 (wlp6s0) 192.168.1.64 (wlp12s0) + fe80::7629:afff:fe0f:8e5d fe80::e377:2a87:4614:f8eb + / \ + / \ + ---------- Ethernet ---------- + | | 193.168.1.78 193.168.1.65 | | + | CLIENT |<------------------------------------------------->| SERVER | + | |fe80::76e6:e2ff:fe2b:7789 fe80::9d15:5e:dc66:2a03| | + ---------- (enp7s0) (enp9s0) ---------- + +Note: The IP addresses and i/f names are set in configuration files as +explained in the READMEs listed below. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Testing Overview ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +The CIPSO/CALIPSO tests send 1000 various size messages from clients to server. +They use large sets of categories to ensure SCTP manages its send/receive +buffers correctly as it involves accounting for ip options and fragmentation. + +####################### CIPSO/IPv4 Tests ############################ + +See ./cipso-tests/README + +####################### CALIPSO/IPv6 Test ############################ + +See ./calipso-tests/README + +######################### Multi-Homing Test ####################### + +NetLabel fallback labeling and tests the multi-homing of SCTP. + +See ./multi-home-tests/README diff --git a/tests/sctp/remote-tests/calipso-tests/README b/tests/sctp/remote-tests/calipso-tests/README new file mode 100644 index 0000000..95cfa0e --- /dev/null +++ b/tests/sctp/remote-tests/calipso-tests/README @@ -0,0 +1,26 @@ +The CALIPSO test sends 1000 various size messages from clients to server +using lksctp-tools sctp_test. +They use large sets of categories to ensure SCTP manages its send/receive +buffers correctly as it involves accounting for ip options and fragmentation. + +####################### CALIPSO/IPv6 Test ############################ +ipv6.cfg +This holds the ip addresses for both ends. Need to update to support your +systems. + +sh ./calipso-server-run +Run this on server. Sets up iptables/ip6tables for SCTP, then NetLabel CALIPSO +and finally runs sctp_test as a server. + +sh ./calipso-client1-run +Run client1 first as it sets up iptables/ip6tables for SCTP, then NetLabel +CALIPSO and finally runs sctp_test as a client. + +sh ./calipso-client2-run +Then run this on a different terminal. + +sh ./calipso-flush +Once done testing run this on the client and server systems to reset NetLabel +to defaults. + + diff --git a/tests/sctp/remote-tests/calipso-tests/calipso-client1-run b/tests/sctp/remote-tests/calipso-tests/calipso-client1-run new file mode 100644 index 0000000..d06c9e0 --- /dev/null +++ b/tests/sctp/remote-tests/calipso-tests/calipso-client1-run @@ -0,0 +1,25 @@ +#!/bin/sh + + +if [ "$1" = "" ]; then + echo "Require path to lksctp-tools" + exit +fi + +# Enable SCTP +iptables -I INPUT 1 -p sctp -j ACCEPT +ip6tables -I INPUT 1 -p sctp -j ACCEPT + +source ./ipv6.cfg +# Define CLIENT side for CALIPSO/IPv6 tests. +netlabelctl calipso add pass doi:${DOI} +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:${ServerWAN_IP} protocol:calipso,${DOI} +netlabelctl map add default address:${ServerETH_IP} protocol:calipso,${DOI} +netlabelctl -p calipso list +netlabelctl -p map list + +# Run CLIENT 1: +runcon -t test_lksctp_suite_t -l s0:c0,c12,c24,c36,c28,c610,c712,c414,c516,c318,c820,c622,c924,c726,c128,c330,c832,c534,c936,c138,c740,c42,c44,c246,c648,c950,c152,c354,c856,c158,c960,c662,c634,c686,c368,c570,c782,c714,c769,c788,c803,c842,c864,c986,c788,c290,c392,c594,c896,c698,c1023 /$1/lksctp-tools/src/apps/sctp_test -H ${ClientWAN_IP} -i ${ClientWAN_NM} -P 1024 -h ${ServerWAN_IP} -p 1035 -a 1 -c 6 -x 1000 -o 2 -m 65515 -s -Z diff --git a/tests/sctp/remote-tests/calipso-tests/calipso-client2-run b/tests/sctp/remote-tests/calipso-tests/calipso-client2-run new file mode 100644 index 0000000..7080538 --- /dev/null +++ b/tests/sctp/remote-tests/calipso-tests/calipso-client2-run @@ -0,0 +1,11 @@ +#!/bin/sh + +if [ "$1" = "" ]; then + echo "Require path to lksctp-tools" + exit +fi + +source ./ipv6.cfg + +# Run CLIENT 2: +runcon -t test_lksctp_suite_t -l s0:c0,c12,c24,c36,c28,c610,c712,c414,c516,c318,c820,c622,c924,c726,c128,c330,c832,c534,c936,c138,c740,c42,c44,c246,c648,c950,c152,c354,c856,c158,c960,c662,c634,c686,c368,c570,c782,c714,c769,c788,c803,c842,c864,c986,c788,c290,c392,c594,c896,c698,c1023 /$1/lksctp-tools/src/apps/sctp_test -H ${ClientWAN_IP} -i ${ClientWAN_NM} -P 1025 -h ${ServerWAN_IP} -p 1035 -a 1 -c 6 -x 1000 -o 2 -m 65515 -s -Z diff --git a/tests/sctp/remote-tests/calipso-tests/calipso-flush b/tests/sctp/remote-tests/calipso-tests/calipso-flush new file mode 100644 index 0000000..6b0557d --- /dev/null +++ b/tests/sctp/remote-tests/calipso-tests/calipso-flush @@ -0,0 +1,7 @@ +#!/bin/sh + +source ./ipv6.cfg +# Reset NetLabel configuration to unlabeled after CALIPSO/IPv6 tests. +netlabelctl map del default +netlabelctl calipso del doi:${DOI} +netlabelctl map add default protocol:unlbl diff --git a/tests/sctp/remote-tests/calipso-tests/calipso-server-run b/tests/sctp/remote-tests/calipso-tests/calipso-server-run new file mode 100644 index 0000000..68c1e31 --- /dev/null +++ b/tests/sctp/remote-tests/calipso-tests/calipso-server-run @@ -0,0 +1,24 @@ +#!/bin/sh + +if [ "$1" = "" ]; then + echo "Require path to lksctp-tools" + exit +fi + +# Enable SCTP +iptables -I INPUT 1 -p sctp -j ACCEPT +ip6tables -I INPUT 1 -p sctp -j ACCEPT + +source ./ipv6.cfg +# Define SERVER side for CALIPSO/IPv6 tests. +netlabelctl calipso add pass doi:${DOI} +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:${ClientWAN_IP} protocol:calipso,${DOI} +netlabelctl map add default address:${ClientETH_IP} protocol:calipso,${DOI} +netlabelctl -p calipso list +netlabelctl -p map list + +# Run sctp_test as a server +runcon -t test_lksctp_suite_t -l s0:c0,c12,c24,c36,c28,c610,c712,c414,c516,c318,c820,c622,c924,c726,c128,c330,c832,c534,c936,c138,c740,c42,c44,c246,c648,c950,c152,c354,c856,c158,c960,c662,c634,c686,c368,c570,c782,c714,c769,c788,c803,c842,c864,c986,c788,c290,c392,c594,c896,c698,c1023 /$1/lksctp-tools/src/apps/sctp_test -H ${ServerWAN_IP}%${ServerWAN_NM} -P 1035 -l -Z diff --git a/tests/sctp/remote-tests/calipso-tests/ipv6.cfg b/tests/sctp/remote-tests/calipso-tests/ipv6.cfg new file mode 100644 index 0000000..a2e953b --- /dev/null +++ b/tests/sctp/remote-tests/calipso-tests/ipv6.cfg @@ -0,0 +1,13 @@ +ServerWAN_NM="wlp12s0" +ServerWAN_IP="fe80::e377:2a87:4614:f8eb" + +ServerETH_NM="enp9s0" +ServerETH_IP="fe80::9d15:5e:dc66:2a03" + +ClientWAN_NM="wlp6s0" +ClientWAN_IP="fe80::7629:afff:fe0f:8e5d" + +ClientETH_NM="enp7s0" +ClientETH_IP="fe80::76e6:e2ff:fe2b:7789" + +DOI="16" diff --git a/tests/sctp/remote-tests/cipso-tests/README b/tests/sctp/remote-tests/cipso-tests/README new file mode 100644 index 0000000..ec8281a --- /dev/null +++ b/tests/sctp/remote-tests/cipso-tests/README @@ -0,0 +1,24 @@ +The CIPSO test sends 1000 various size messages from clients to server +using lksctp-tools sctp_test. +They use large sets of categories to ensure SCTP manages its send/receive +buffers correctly as it involves accounting for ip options and fragmentation. + +####################### CIPSO/IPv4 Tests ############################ +ipv4.cfg +This holds the ip addresses for both ends. Need to update to support your +systems. + +sh ./cipso-server-run +Run this on server. Sets up iptables/ip6tables for SCTP, then NetLabel CIPSO +and finally runs sctp_test as a server. + +sh ./cipso-client1-run +Run client1 first as it sets up iptables/ip6tables for SCTP, then NetLabel +CIPSO and finally runs sctp_test as a client. + +sh ./cipso-client2-run +Then run this on a different terminal. + +sh ./cipso-flush +Once done testing run this on the client and server systems to reset NetLabel +to defaults. diff --git a/tests/sctp/remote-tests/cipso-tests/cipso-client1-run b/tests/sctp/remote-tests/cipso-tests/cipso-client1-run new file mode 100644 index 0000000..72af8d1 --- /dev/null +++ b/tests/sctp/remote-tests/cipso-tests/cipso-client1-run @@ -0,0 +1,24 @@ +#!/bin/sh + +if [ "$1" = "" ]; then + echo "Require path to lksctp-tools" + exit +fi + +# Enable SCTP +iptables -I INPUT 1 -p sctp -j ACCEPT +ip6tables -I INPUT 1 -p sctp -j ACCEPT + +source ./ipv4.cfg +# Define CLIENT side for CIPSO/IPv4 tests. +netlabelctl cipsov4 add pass doi:${DOI} tags:5 +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:${ServerWAN_IP} protocol:cipsov4,${DOI} +netlabelctl map add default address:${ServerETH_IP} protocol:cipsov4,${DOI} +netlabelctl -p cipso list +netlabelctl -p map list + +# Run CLIENT 1: +runcon -t test_lksctp_suite_t -l s0:c782,c714,c769,c788,c803,c842,c864 $1/lksctp-tools/src/apps/sctp_test -H ${ClientWAN_IP} -P 1024 -C ${ServerWAN_IP} -p 1035 -a 1 -c 6 -x 1000 -o 2 -m 65515 -s -Z diff --git a/tests/sctp/remote-tests/cipso-tests/cipso-client2-run b/tests/sctp/remote-tests/cipso-tests/cipso-client2-run new file mode 100644 index 0000000..b06a251 --- /dev/null +++ b/tests/sctp/remote-tests/cipso-tests/cipso-client2-run @@ -0,0 +1,11 @@ +#!/bin/sh + +if [ "$1" = "" ]; then + echo "Require path to lksctp-tools" + exit +fi + +source ./ipv4.cfg + +# Run CLIENT 2: +runcon -t test_lksctp_suite_t -l s0:c782,c714,c769,c788,c803,c842,c864 $1/lksctp-tools/src/apps/sctp_test -H ${ClientETH_IP} -P 1025 -C ${ServerETH_IP} -p 1035 -a 1 -c 6 -x 1000 -o 2 -m 65515 -s -Z diff --git a/tests/sctp/remote-tests/cipso-tests/cipso-flush b/tests/sctp/remote-tests/cipso-tests/cipso-flush new file mode 100644 index 0000000..70da996 --- /dev/null +++ b/tests/sctp/remote-tests/cipso-tests/cipso-flush @@ -0,0 +1,7 @@ +#!/bin/sh + +source ./ipv4.cfg +# Reset NetLabel configuration to unlabeled after CIPSO/IPv4 tests. +netlabelctl map del default +netlabelctl cipsov4 del doi:${DOI} +netlabelctl map add default protocol:unlbl diff --git a/tests/sctp/remote-tests/cipso-tests/cipso-server-run b/tests/sctp/remote-tests/cipso-tests/cipso-server-run new file mode 100644 index 0000000..59e770b --- /dev/null +++ b/tests/sctp/remote-tests/cipso-tests/cipso-server-run @@ -0,0 +1,23 @@ +#!/bin/sh + +if [ "$1" = "" ]; then + echo "Require path to lksctp-tools" + exit +fi + +# Enable SCTP +iptables -I INPUT 1 -p sctp -j ACCEPT +ip6tables -I INPUT 1 -p sctp -j ACCEPT + +source ./ipv4.cfg +# Define SERVER side for CIPSO/IPv4 tests. +netlabelctl cipsov4 add pass doi:${DOI} tags:5 +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:${ClientWAN_IP} protocol:cipsov4,${DOI} +netlabelctl map add default address:${ClientETH_IP} protocol:cipsov4,${DOI} +netlabelctl -p cipso list +netlabelctl -p map list + +runcon -t test_lksctp_suite_t -l s0:c782,c714,c769,c788,c803,c842,c864 $1/lksctp-tools/src/apps/sctp_test -H ${ServerWAN_IP} -B ${ServerETH_IP} -P 1035 -l -Z diff --git a/tests/sctp/remote-tests/cipso-tests/ipv4.cfg b/tests/sctp/remote-tests/cipso-tests/ipv4.cfg new file mode 100644 index 0000000..8fc9a71 --- /dev/null +++ b/tests/sctp/remote-tests/cipso-tests/ipv4.cfg @@ -0,0 +1,13 @@ +ServerWAN_NM="wlp12s0" +ServerWAN_IP="192.168.1.64" + +ServerETH_NM="enp9s0" +ServerETH_IP="193.168.1.65" + +ClientWAN_NM="wlp6s0" +ClientWAN_IP="192.168.1.77" + +ClientETH_NM="enp7s0" +ClientETH_IP="193.168.1.78" + +DOI="16" diff --git a/tests/sctp/remote-tests/multi-home-tests/README b/tests/sctp/remote-tests/multi-home-tests/README new file mode 100644 index 0000000..352075e --- /dev/null +++ b/tests/sctp/remote-tests/multi-home-tests/README @@ -0,0 +1,37 @@ +Demonstrates NetLabel fallback labeling and tests the multi-homing of SCTP. + +####################### Multi-Homing Test ############################ +mh.cfg +This holds the ip addresses for both ends. Need to update to support your +systems. + +sh ./mh-server-run +Run this on server. Sets up iptables/ip6tables for SCTP, then NetLabel Fallback +labeling and finally runs sctp_darn as a server. + +sh ./mh-client1-run +Run client1 first as it sets up iptables/ip6tables for SCTP, then NetLabel +Fallback labeling and finally runs sctp_darn as a client. + +To test multi-homing: +1) Send data from client to server. Using tshark the source IP address will be + the Client WAN i/f and the dest IP address will be the Server WAN i/f. + +2) Turn off the Server WAN interface. + +3) Send data from client to server. Using tshark the source IP address will be + the Client WAN i/f and the dest IP address will be the Server ETH i/f. + +Note that the peer context will be "netlabel_peer_wlan_t" even when the +Server side Wifi is turned off. This is because the first association +on the sctp socket sets the peer context to the first connection. + +To set "netlabel_peer_eth_t" run the following on a different terminal: +sh ./mh-client2-run + +sh ./mh-server-flush +Once done testing run this on Server side to reset NetLabel to defaults. + +sh ./mh-client-flush +Once done testing run this on Client side to reset NetLabel to defaults. + diff --git a/tests/sctp/remote-tests/multi-home-tests/mh-client-flush b/tests/sctp/remote-tests/multi-home-tests/mh-client-flush new file mode 100644 index 0000000..d3351c3 --- /dev/null +++ b/tests/sctp/remote-tests/multi-home-tests/mh-client-flush @@ -0,0 +1,15 @@ +#!/bin/sh + +source ./mh.cfg + +# Reset NetLabel +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_peer_lo_t:s0 +netlabelctl unlbl del interface:lo address:::1 label:system_u:object_r:netlabel_peer_lo_t:s0 + +netlabelctl unlbl del interface:${ClientWAN_NM} address:${WANscope} label:system_u:object_r:netlabel_peer_wlan_t:s0 +netlabelctl unlbl del interface:${ClientETH_NM} address:${ETHscope} label:system_u:object_r:netlabel_peer_eth_t:s0 + +# Reset IP Tables +iptables -t security -F diff --git a/tests/sctp/remote-tests/multi-home-tests/mh-client1-run b/tests/sctp/remote-tests/multi-home-tests/mh-client1-run new file mode 100644 index 0000000..35f83db --- /dev/null +++ b/tests/sctp/remote-tests/multi-home-tests/mh-client1-run @@ -0,0 +1,50 @@ +#!/bin/sh + +if [ "$1" = "" ]; then + echo "Require path to lksctp-tools" + exit +fi + +# Flush the security table first: +iptables -t security -F + +# Ensure SCTP will allow access from remote systems: +iptables -I INPUT 1 -p sctp -j ACCEPT +ip6tables -I INPUT 1 -p sctp -j ACCEPT + +source ./mh.cfg + +# Set NetLabel +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_peer_lo_t:s0 +netlabelctl unlbl add interface:lo address:::1 label:system_u:object_r:netlabel_peer_lo_t:s0 +netlabelctl unlbl add interface:${ClientWAN_NM} address:${WANscope} label:system_u:object_r:netlabel_peer_wlan_t:s0 +netlabelctl unlbl add interface:${ClientETH_NM} address:${ETHscope} label:system_u:object_r:netlabel_peer_eth_t:s0 + +# Set iptables +#-------------- INPUT IP Stream --------------------# +# This INPUT rule sets all packets to default_packet_t: +iptables -t security -A INPUT -j SECMARK --selctx system_u:object_r:default_packet_t:s0 + +# These rules will replace the above context if sctp ports 1024:1035 are found in the packets: +iptables -t security -A INPUT -i lo -p sctp -m multiport --port 1024:1035 -j SECMARK --selctx system_u:object_r:sctp_packet_lo_t:s0 +iptables -t security -A INPUT -i ${ClientETH_NM} -p sctp -m multiport --port 1024:1035 -j SECMARK --selctx system_u:object_r:sctp_packet_eth_t:s0 +iptables -t security -A INPUT -i ${ClientWAN_NM} -p sctp -m multiport --port 1024:1035 -j SECMARK --selctx system_u:object_r:sctp_packet_wlan_t:s0 + +iptables -t security -A INPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --save + +#-------------- OUTPUT IP Stream --------------------# +# This OUTPUT rule sets all packets to default_packet_t: +iptables -t security -A OUTPUT -j SECMARK --selctx system_u:object_r:default_packet_t:s0 + +# These rules will replace the above context if sctp ports 1024:1035 are found in the packets: +iptables -t security -A OUTPUT -o lo -p sctp -m multiport --port 1024:1035 -j SECMARK --selctx system_u:object_r:sctp_packet_lo_t:s0 +iptables -t security -A OUTPUT -o ${ClientETH_NM} -p sctp -m multiport --port 1024:1035 -j SECMARK --selctx system_u:object_r:sctp_packet_eth_t:s0 +iptables -t security -A OUTPUT -o ${ClientWAN_NM} -p sctp -m multiport --port 1024:1035 -j SECMARK --selctx system_u:object_r:sctp_packet_wlan_t:s0 + +iptables -t security -A OUTPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --save + +# Run sctp_darn as Client: +runcon -t test_lksctp_suite_t $1/lksctp-tools/src/apps/sctp_darn -H ${ClientWAN_IP} -B ${ClientETH_IP} -P 1024 -c ${ServerWAN_IP} -c ${ServerETH_IP} -p 1035 -s -Z diff --git a/tests/sctp/remote-tests/multi-home-tests/mh-client2-run b/tests/sctp/remote-tests/multi-home-tests/mh-client2-run new file mode 100644 index 0000000..069eb3c --- /dev/null +++ b/tests/sctp/remote-tests/multi-home-tests/mh-client2-run @@ -0,0 +1,11 @@ +#!/bin/sh + +if [ "$1" = "" ]; then + echo "Require path to lksctp-tools" + exit +fi + +source ./mh.cfg + +# Run sctp_darn as Client: +runcon -t test_lksctp_suite_t $1/lksctp-tools/src/apps/sctp_darn -H ${ClientWAN_IP} -B ${ClientETH_IP} -P 1025 -c ${ServerETH_IP} -c ${ServerWAN_IP} -p 1035 -s -Z diff --git a/tests/sctp/remote-tests/multi-home-tests/mh-server-flush b/tests/sctp/remote-tests/multi-home-tests/mh-server-flush new file mode 100644 index 0000000..1aeb41a --- /dev/null +++ b/tests/sctp/remote-tests/multi-home-tests/mh-server-flush @@ -0,0 +1,15 @@ +#!/bin/sh + +source ./mh.cfg + +# Reset NetLabel +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_peer_lo_t:s0 +netlabelctl unlbl del interface:lo address:::1 label:system_u:object_r:netlabel_peer_lo_t:s0 + +netlabelctl unlbl del interface:${ServerWAN_NM} address:${WANscope} label:system_u:object_r:netlabel_peer_wlan_t:s0 +netlabelctl unlbl del interface:${ServerETH_NM} address:${ETHscope} label:system_u:object_r:netlabel_peer_eth_t:s0 + +# Reset IP Tables +iptables -t security -F diff --git a/tests/sctp/remote-tests/multi-home-tests/mh-server-run b/tests/sctp/remote-tests/multi-home-tests/mh-server-run new file mode 100644 index 0000000..769afd3 --- /dev/null +++ b/tests/sctp/remote-tests/multi-home-tests/mh-server-run @@ -0,0 +1,50 @@ +#!/bin/sh + +if [ "$1" = "" ]; then + echo "Require path to lksctp-tools" + exit +fi + +# Flush the security table first: +iptables -t security -F + +# Ensure SCTP will allow access from remote systems: +iptables -I INPUT 1 -p sctp -j ACCEPT +ip6tables -I INPUT 1 -p sctp -j ACCEPT + +source ./mh.cfg + +# Set NetLabel +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_peer_lo_t:s0 +netlabelctl unlbl add interface:lo address:::1 label:system_u:object_r:netlabel_peer_lo_t:s0 +netlabelctl unlbl add interface:${ServerWAN_NM} address:${WANscope} label:system_u:object_r:netlabel_peer_wlan_t:s0 +netlabelctl unlbl add interface:${ServerETH_NM} address:${ETHscope} label:system_u:object_r:netlabel_peer_eth_t:s0 + +# Set iptables +#-------------- INPUT IP Stream --------------------# +# This INPUT rule sets all packets to default_packet_t: +iptables -t security -A INPUT -j SECMARK --selctx system_u:object_r:default_packet_t:s0 + +# These rules will replace the above context if sctp ports 1024:1035 are found in the packets: +iptables -t security -A INPUT -i lo -p sctp -m multiport --port 1024:1035 -j SECMARK --selctx system_u:object_r:sctp_packet_lo_t:s0 +iptables -t security -A INPUT -i ${ServerETH_NM} -p sctp -m multiport --port 1024:1035 -j SECMARK --selctx system_u:object_r:sctp_packet_eth_t:s0 +iptables -t security -A INPUT -i ${ServerWAN_NM} -p sctp -m multiport --port 1024:1035 -j SECMARK --selctx system_u:object_r:sctp_packet_wlan_t:s0 + +iptables -t security -A INPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --save + +#-------------- OUTPUT IP Stream --------------------# +# This OUTPUT rule sets all packets to default_packet_t: +iptables -t security -A OUTPUT -j SECMARK --selctx system_u:object_r:default_packet_t:s0 + +# These rules will replace the above context if sctp ports 1024:1035 are found in the packets: +iptables -t security -A OUTPUT -o lo -p sctp -m multiport --port 1024:1035 -j SECMARK --selctx system_u:object_r:sctp_packet_lo_t:s0 +iptables -t security -A OUTPUT -o ${ServerETH_NM} -p sctp -m multiport --port 1024:1035 -j SECMARK --selctx system_u:object_r:sctp_packet_eth_t:s0 +iptables -t security -A OUTPUT -o ${ServerWAN_NM} -p sctp -m multiport --port 1024:1035 -j SECMARK --selctx system_u:object_r:sctp_packet_wlan_t:s0 + +iptables -t security -A OUTPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --save + +# Run sctp_darn as Server: +runcon -t test_lksctp_suite_t $1/lksctp-tools/src/apps/sctp_darn -H ${ServerWAN_IP} -B ${ServerETH_IP} -P 1035 -l -Z diff --git a/tests/sctp/remote-tests/multi-home-tests/mh.cfg b/tests/sctp/remote-tests/multi-home-tests/mh.cfg new file mode 100644 index 0000000..1f29d05 --- /dev/null +++ b/tests/sctp/remote-tests/multi-home-tests/mh.cfg @@ -0,0 +1,15 @@ +ServerWAN_NM="wlp12s0" +ServerWAN_IP="192.168.1.64" + +ServerETH_NM="enp9s0" +ServerETH_IP="193.168.1.65" + +ClientWAN_NM="wlp6s0" +ClientWAN_IP="192.168.1.77" + +ClientETH_NM="enp7s0" +ClientETH_IP="193.168.1.78" + +WANscope="192.168.1.0/24" +ETHscope="193.168.1.0/24" + diff --git a/tests/sctp/sctp_asconf_params_client.c b/tests/sctp/sctp_asconf_params_client.c new file mode 100644 index 0000000..979defb --- /dev/null +++ b/tests/sctp/sctp_asconf_params_client.c @@ -0,0 +1,293 @@ +/* This test will allow the server side to add/remove bindx addresses and + * inform the client side via ASCONF chunks. It will also allow the server + * side to inform the client that the peer primary address is being updated. + * The code for checking these parameters are in net/sctp/sm_make_chunk.c + * sctp_process_asconf_param(). + * + * To enable the processing of these incoming ASCONF parameters for: + * SCTP_PARAM_SET_PRIMARY, SCTP_PARAM_ADD_IP and SCTP_PARAM_DEL_IP + * the following options must be enabled: + * echo 1 > /proc/sys/net/sctp/addip_enable + * echo 1 > /proc/sys/net/sctp/addip_noauth_enable + * + * If these are not enabled the SCTP_SET_PEER_PRIMARY_ADDR setsockopt + * fails with EPERM "Operation not permitted", however the bindx calls + * will complete but the client side will not be informed. + * + * NOTES: + * 1) SCTP_SET_PEER_PRIMARY_ADDR requires a non-loopback IP address. + * 2) Both addresses used by the client/server MUST be the same type + * (i.e. IPv4 or IPv6). + * 3) The iptables default for Fedora does not allow SCTP remote traffic. + * To allow this set the following: + * iptables -I INPUT 1 -p sctp -j ACCEPT + * ip6tables -I INPUT 1 -p sctp -j ACCEPT + */ + +#include "sctp_common.h" + +void usage(char *progname) +{ + fprintf(stderr, + "usage: %s [-v] [-n] addr port\n" + "\nWhere:\n\t" + "-v Print status information.\n\t" + "-n No bindx_rem will be received from server. This happens\n\t" + " when the client and server are on different systems.\n\t" + "addr IPv4 or IPv6 address (MUST NOT be loopback address).\n\t" + "port port.\n", progname); + + fprintf(stderr, + "Notes:\n\t" + "1) addr and the server side new_pri_addr address MUST be\n\t" + " same type (IPv4 or IPv6).\n\t" + "2) IPv6 link-local addresses require the %% to\n\t" + " obtain scopeid. e.g. fe80::7629:afff:fe0f:8e5d%%wlp6s0\n"); + exit(1); +} + +static int peer_count, peer_count_err; +static void getpaddrs_alarm(int sig) +{ + fprintf(stderr, "Get peer address count timer expired - carry on test\n"); + peer_count += 1; + peer_count_err = true; +} + +static void getprimaddr_alarm(int sig) +{ + fprintf(stderr, "Get primary address timer expired - end test.\n"); + exit(1); +} + +static void get_primaddr(char *addr_buf, int socket) +{ + int result; + struct sctp_prim prim; + struct sockaddr_in *in_addr; + struct sockaddr_in6 *in6_addr; + struct sockaddr *paddr; + socklen_t prim_len; + const char *addr_ptr = NULL; + + memset(&prim, 0, sizeof(struct sctp_prim)); + prim_len = sizeof(struct sctp_prim); + + result = getsockopt(socket, IPPROTO_SCTP, SCTP_PRIMARY_ADDR, + &prim, &prim_len); + if (result < 0) { + perror("getsockopt: SCTP_PRIMARY_ADDR"); + exit(1); + } + + paddr = (struct sockaddr *)&prim.ssp_addr; + if (paddr->sa_family == AF_INET) { + in_addr = (struct sockaddr_in *)&prim.ssp_addr; + addr_ptr = inet_ntop(AF_INET, &in_addr->sin_addr, addr_buf, + INET6_ADDRSTRLEN); + } else if (paddr->sa_family == AF_INET6) { + in6_addr = (struct sockaddr_in6 *)&prim.ssp_addr; + addr_ptr = inet_ntop(AF_INET6, &in6_addr->sin6_addr, addr_buf, + INET6_ADDRSTRLEN); + } + if (!addr_ptr) { + perror("inet_ntop"); + exit(1); + } +} + +int main(int argc, char **argv) +{ + int opt, client_sock, result, len; + struct addrinfo client_hints, *client_res; + struct sockaddr *paddrs; + bool verbose = false, no_bindx_rem = false; + char client_prim_addr1[INET6_ADDRSTRLEN]; + char client_prim_addr2[INET6_ADDRSTRLEN]; + char buffer[128]; + + while ((opt = getopt(argc, argv, "vn")) != -1) { + switch (opt) { + case 'v': + verbose = true; + break; + case 'n': + no_bindx_rem = true; + break; + default: + usage(argv[0]); + } + } + + if ((argc - optind) != 2) + usage(argv[0]); + + /* Set up client side and connect */ + memset(&client_hints, 0, sizeof(struct addrinfo)); + client_hints.ai_socktype = SOCK_STREAM; + client_hints.ai_protocol = IPPROTO_SCTP; + result = getaddrinfo(argv[optind], argv[optind + 1], + &client_hints, &client_res); + if (result < 0) { + fprintf(stderr, "getaddrinfo - client: %s\n", + gai_strerror(result)); + exit(1); + } + + +/* printf("Client scopeID: %d\n", + * ((struct sockaddr_in6 *)client_res->ai_addr)->sin6_scope_id); + */ + + client_sock = socket(client_res->ai_family, client_res->ai_socktype, + client_res->ai_protocol); + if (client_sock < 0) { + perror("socket"); + exit(1); + } + + result = connect(client_sock, client_res->ai_addr, + client_res->ai_addrlen); + if (result < 0) { + if (errno != EINPROGRESS) + perror("connect"); + else + fprintf(stderr, "connect timeout\n"); + + close(client_sock); + exit(1); + } + + /* Get number of peer addresses on CLIENT (should be 1) for a check + * later as sctp_bindx SERVER -> CLIENT is non-blocking. + */ + peer_count = sctp_getpaddrs(client_sock, 0, &paddrs); + sctp_freepaddrs(paddrs); + len = sprintf(buffer, "Client peer address count: %d", peer_count); + if (verbose) + printf("%s\n", buffer); + + + /* Get initial CLIENT primary address (that should be ADDR1). */ + get_primaddr(client_prim_addr1, client_sock); + + /* server waiting for write before sending BINDX_ADD */ + result = write(client_sock, buffer, len); + if (result < 0) { + perror("write"); + close(client_sock); + exit(1); + } + + /* Sleep a while as server pings us the new address */ + sleep(1); + /* then set an alarm and check number of peer addresses for CLIENT. */ + signal(SIGALRM, getpaddrs_alarm); + alarm(2); + peer_count_err = false; + result = 0; + + while (result != peer_count + 1) { + result = sctp_getpaddrs(client_sock, 0, &paddrs); + if (result > 0) + sctp_freepaddrs(paddrs); + + if (peer_count_err) + break; + } + alarm(0); + peer_count = result; + + len = sprintf(buffer, "Client peer address count: %d", result); + if (verbose) + printf("%s\n", buffer); + + /* server waiting for write before send SCTP_SET_PEER_PRIMARY_ADDR */ + result = write(client_sock, buffer, len); + if (result < 0) { + perror("write"); + close(client_sock); + exit(1); + } + + /* Now get the new primary address from the client */ + signal(SIGALRM, getprimaddr_alarm); + alarm(2); + memcpy(client_prim_addr2, client_prim_addr1, INET6_ADDRSTRLEN); + + while (!strcmp(client_prim_addr1, client_prim_addr2)) + get_primaddr(client_prim_addr2, client_sock); + + alarm(0); + len = sprintf(buffer, "Client initial SCTP_PRIMARY_ADDR: %s\nClient current SCTP_PRIMARY_ADDR: %s", + client_prim_addr1, client_prim_addr2); + if (verbose) + printf("%s\n", buffer); + + if (!no_bindx_rem) { + /* Let server send bindx_rem */ + result = write(client_sock, buffer, len); + if (result < 0) { + perror("write"); + close(client_sock); + exit(1); + } + + /* Then delete addr that checks ASCONF - SCTP_PARAM_DEL_IP.*/ + if (!peer_count_err) { + signal(SIGALRM, getprimaddr_alarm); + alarm(2); + result = 0; + while (result != peer_count - 1) { + result = sctp_getpaddrs(client_sock, 0, &paddrs); + if (result > 0) + sctp_freepaddrs(paddrs); + + if (peer_count_err) + break; + } + alarm(0); + sprintf(buffer, "Client peer address count: %d", result); + if (verbose) + printf("%s\n", buffer); + } + } + + /* server waiting for client peer address count */ + result = write(client_sock, buffer, len); + if (result < 0) { + perror("write"); + close(client_sock); + exit(1); + } + + /* Compare the client primary addresses, they should be different. */ + if (!strcmp(client_prim_addr1, client_prim_addr2)) { + len = sprintf(buffer, "Client ADDR1: %s same as ADDR2: %s - SCTP_SET_PEER_PRIMARY_ADDR failed", + client_prim_addr1, client_prim_addr2); + fprintf(stderr, "%s\n", buffer); + + /* server waiting for write to finish */ + result = write(client_sock, buffer, len); + if (result < 0) { + perror("write"); + close(client_sock); + } + exit(1); + } + + len = sprintf(buffer, "Client primary address changed successfully.\n"); + if (verbose) + printf("%s\n", buffer); + + /* server waiting for write to finish */ + result = write(client_sock, buffer, len); + if (result < 0) { + perror("write"); + close(client_sock); + exit(1); + } + + close(client_sock); + exit(0); +} diff --git a/tests/sctp/sctp_asconf_params_server.c b/tests/sctp/sctp_asconf_params_server.c new file mode 100644 index 0000000..3403479 --- /dev/null +++ b/tests/sctp/sctp_asconf_params_server.c @@ -0,0 +1,231 @@ +#include "sctp_common.h" + +void usage(char *progname) +{ + fprintf(stderr, + "usage: %s -v addr new_pri_addr port\n" + "\nWhere:\n\t" + "-v Print status information.\n\t" + "addr IPv4/IPv6 address for initial connection.\n\t" + "new_pri_addr IPv4/IPv6 address that the server will bindx\n\t" + " then set to the new SCTP_PRIMARY_ADDR.\n\t" + "port port.\n", progname); + fprintf(stderr, + "Notes:\n\t" + "1) addr and new_pri_addr MUST NOT be loopback addresses.\n\t" + "2) addr and new_pri_addr MUST be same type (IPv4 or IPv6).\n\t" + "3) IPv6 link-local addresses require the %% to\n\t" + " obtain scopeid. e.g. fe80::7629:afff:fe0f:8e5d%%wlp6s0\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + int opt, srv_sock, new_sock, result, on = 1; + struct addrinfo srv_hints, *srv_res; + struct addrinfo *new_pri_addr_res; + struct sockaddr *sa_ptr; + socklen_t sinlen; + struct sockaddr_storage sin; + struct sctp_setpeerprim setpeerprim; + bool verbose = false, is_ipv6 = false; + char buffer[128]; + + while ((opt = getopt(argc, argv, "v")) != -1) { + switch (opt) { + case 'v': + verbose = true; + break; + default: + usage(argv[0]); + } + } + + if ((argc - optind) != 3) + usage(argv[0]); + + if (strchr(argv[optind], ':') && strchr(argv[optind + 1], ':')) { + is_ipv6 = true; + srv_hints.ai_family = AF_INET6; + } else if (strchr(argv[optind], '.') && strchr(argv[optind + 1], '.')) { + is_ipv6 = false; + srv_hints.ai_family = AF_INET; + } else { + usage(argv[0]); + } + + memset(&srv_hints, 0, sizeof(struct addrinfo)); + srv_hints.ai_flags = AI_PASSIVE; + srv_hints.ai_socktype = SOCK_STREAM; + srv_hints.ai_protocol = IPPROTO_SCTP; + + /* Set up server side */ + result = getaddrinfo(argv[optind], argv[optind + 2], &srv_hints, &srv_res); + if (result < 0) { + fprintf(stderr, "getaddrinfo - server: %s\n", + gai_strerror(result)); + exit(1); + } + if (is_ipv6 && verbose) + printf("Server scopeID: %d\n", + ((struct sockaddr_in6 *)srv_res->ai_addr)->sin6_scope_id); + + srv_sock = socket(srv_res->ai_family, srv_res->ai_socktype, + srv_res->ai_protocol); + if (srv_sock < 0) { + perror("socket - server"); + exit(1); + } + + result = setsockopt(srv_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + if (result < 0) { + perror("setsockopt: SO_REUSEADDR"); + close(srv_sock); + exit(1); + } + + result = bind(srv_sock, srv_res->ai_addr, srv_res->ai_addrlen); + if (result < 0) { + perror("bind"); + close(srv_sock); + exit(1); + } + + listen(srv_sock, 1); + + new_sock = accept(srv_sock, (struct sockaddr *)&sin, &sinlen); + if (new_sock < 0) { + perror("accept"); + result = 1; + goto err2; + } + + /* This waits for a client message before continuing. */ + result = read(new_sock, &buffer, sizeof(buffer)); + if (result < 0) { + perror("read"); + exit(1); + } + buffer[result] = 0; + if (verbose) + printf("%s\n", buffer); + + /* Obtain address info for the BINDX_ADD and new SCTP_PRIMARY_ADDR. */ + result = getaddrinfo(argv[optind + 1], argv[optind + 2], + &srv_hints, &new_pri_addr_res); + if (result < 0) { + fprintf(stderr, "getaddrinfo - new SCTP_PRIMARY_ADDR: %s\n", + gai_strerror(result)); + close(srv_sock); + exit(1); + } + if (is_ipv6 && verbose) + printf("new_pri_addr scopeID: %d\n", + ((struct sockaddr_in6 *)new_pri_addr_res->ai_addr)->sin6_scope_id); + + + /* Now call sctp_bindx to add ADDR2, this will cause an + * ASCONF - SCTP_PARAM_ADD_IP chunk to be sent to the CLIENT. + * This is non-blocking so there maybe a delay before the CLIENT + * receives the asconf chunk. + */ + if (verbose) + printf("Calling sctp_bindx ADD: %s\n", argv[optind + 1]); + + result = sctp_bindx(new_sock, + (struct sockaddr *)new_pri_addr_res->ai_addr, + 1, SCTP_BINDX_ADD_ADDR); + if (result < 0) { + if (errno == EACCES) { + perror("sctp_bindx ADD"); + } else { + perror("sctp_bindx ADD"); + result = 1; + goto err1; + } + } + + /* This waits for a client message before continuing. */ + result = read(new_sock, &buffer, sizeof(buffer)); + if (result < 0) { + perror("read"); + exit(1); + } + buffer[result] = 0; + if (verbose) + printf("%s\n", buffer); + + /* Now that the CLIENT has the new primary address ensure they use + * it by SCTP_SET_PEER_PRIMARY_ADDR. + */ + memset(&setpeerprim, 0, sizeof(struct sctp_setpeerprim)); + sa_ptr = (struct sockaddr *)&setpeerprim.sspp_addr; + if (is_ipv6) + memcpy(sa_ptr, new_pri_addr_res->ai_addr, + sizeof(struct sockaddr_in6)); + else + memcpy(sa_ptr, new_pri_addr_res->ai_addr, + sizeof(struct sockaddr_in)); + + if (verbose) + printf("Calling setsockopt SCTP_SET_PEER_PRIMARY_ADDR: %s\n", + argv[optind + 1]); + + result = setsockopt(new_sock, IPPROTO_SCTP, + SCTP_SET_PEER_PRIMARY_ADDR, + &setpeerprim, sizeof(struct sctp_setpeerprim)); + if (result < 0) { + perror("setsockopt: SCTP_SET_PEER_PRIMARY_ADDR"); + result = 1; + goto err1; + } + /* Sleep a sec to ensure client get info. */ + result = read(new_sock, &buffer, sizeof(buffer)); + if (result < 0) { + perror("read"); + exit(1); + } + buffer[result] = 0; + if (verbose) + printf("%s\n", buffer); + + /* Then delete addr that checks ASCONF - SCTP_PARAM_DEL_IP. */ + if (verbose) + printf("Calling sctp_bindx REM: %s\n", argv[optind]); + + result = sctp_bindx(new_sock, (struct sockaddr *)srv_res->ai_addr, + 1, SCTP_BINDX_REM_ADDR); + if (result < 0) { + perror("sctp_bindx - REM"); + result = 1; + goto err1; + } + + result = read(new_sock, &buffer, sizeof(buffer)); + if (result <= 0) { + if (errno != 0) + perror("read"); + result = 1; + goto err1; + } + buffer[result] = 0; + if (verbose) + printf("%s\n", buffer); + + result = read(new_sock, &buffer, sizeof(buffer)); + if (result < 0) { + perror("read"); + exit(1); + } + buffer[result] = 0; + if (verbose) + printf("%s\n", buffer); + + result = 0; + +err1: + close(new_sock); +err2: + close(srv_sock); + exit(result); +} diff --git a/tests/sctp/sctp_bind.c b/tests/sctp/sctp_bind.c new file mode 100644 index 0000000..bb83a61 --- /dev/null +++ b/tests/sctp/sctp_bind.c @@ -0,0 +1,61 @@ +#include "sctp_common.h" + +void usage(char *progname) +{ + fprintf(stderr, + "usage: %s stream|seq port\n" + "\nWhere:\n\t" + "stream Use SCTP 1-to-1 style or:\n\t" + "seq use SCTP 1-to-Many style.\n\t" + "port Listening port.\n", progname); + exit(1); +} + +int main(int argc, char **argv) +{ + int sock, result, on = 1; + struct addrinfo hints, *res; + + if (argc != 3) + usage(argv[0]); + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_flags = AI_PASSIVE; + hints.ai_protocol = IPPROTO_SCTP; + + if (!strcmp(argv[1], "stream")) + hints.ai_socktype = SOCK_STREAM; + else if (!strcmp(argv[1], "seq")) + hints.ai_socktype = SOCK_SEQPACKET; + else + usage(argv[0]); + + result = getaddrinfo(NULL, argv[2], &hints, &res); + if (result < 0) { + printf("getaddrinfo: %s\n", gai_strerror(result)); + exit(1); + } + + sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (sock < 0) { + perror("socket"); + exit(1); + } + + result = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + if (result < 0) { + perror("setsockopt: SO_REUSEADDR"); + close(sock); + exit(1); + } + + result = bind(sock, res->ai_addr, res->ai_addrlen); + if (result < 0) { + perror("bind"); + close(sock); + exit(1); + } + + close(sock); + exit(0); +} diff --git a/tests/sctp/sctp_bindx.c b/tests/sctp/sctp_bindx.c new file mode 100644 index 0000000..867d283 --- /dev/null +++ b/tests/sctp/sctp_bindx.c @@ -0,0 +1,116 @@ +#include "sctp_common.h" + +void usage(char *progname) +{ + fprintf(stderr, + "usage: %s [-r] [-v] stream|seq port\n" + "\nWhere:\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" + "stream Use SCTP 1-to-1 style or:\n\t" + "seq use SCTP 1-to-Many style.\n\t" + "port port.\n", progname); + exit(1); +} + +int main(int argc, char **argv) +{ + int opt, type, sock, result; + struct sockaddr_in ipv4; + struct sockaddr_in6 ipv6; + unsigned short port; + bool rem = false; + bool verbose = false; + char *context; + + while ((opt = getopt(argc, argv, "rv")) != -1) { + switch (opt) { + case 'v': + verbose = true; + break; + case 'r': + rem = true; + break; + default: + usage(argv[0]); + } + } + + if ((argc - optind) != 2) + usage(argv[0]); + + if (!strcmp(argv[optind], "stream")) + type = SOCK_STREAM; + else if (!strcmp(argv[optind], "seq")) + type = SOCK_SEQPACKET; + else + usage(argv[0]); + + port = atoi(argv[optind + 1]); + if (!port) + usage(argv[0]); + + if (verbose) { + if (getcon(&context) < 0) + context = strdup("unavailable"); + printf("Process context: %s\n", context); + free(context); + } + + sock = socket(PF_INET6, type, IPPROTO_SCTP); + if (sock < 0) { + perror("socket"); + exit(1); + } + + if (verbose) + print_context(sock, "Server"); + + memset(&ipv4, 0, sizeof(struct sockaddr_in)); + ipv4.sin_family = AF_INET; + ipv4.sin_port = htons(port); + ipv4.sin_addr.s_addr = htonl(0x7f000001); + + result = sctp_bindx(sock, (struct sockaddr *)&ipv4, 1, + SCTP_BINDX_ADD_ADDR); + if (result < 0) { + perror("sctp_bindx ADD - ipv4"); + close(sock); + exit(1); + } + + if (verbose) + printf("sctp_bindx ADD - ipv4\n"); + + memset(&ipv6, 0, sizeof(struct sockaddr_in6)); + ipv6.sin6_family = AF_INET6; + ipv6.sin6_port = htons(port); + ipv6.sin6_addr = in6addr_loopback; + + result = sctp_bindx(sock, (struct sockaddr *)&ipv6, 1, + SCTP_BINDX_ADD_ADDR); + if (result < 0) { + perror("sctp_bindx ADD - ipv6"); + close(sock); + exit(1); + } + + 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(1); + } + if (verbose) + printf("sctp_bindx REM - ipv6\n"); + } + + close(sock); + exit(0); +} diff --git a/tests/sctp/sctp_client.c b/tests/sctp/sctp_client.c new file mode 100644 index 0000000..ad7176a --- /dev/null +++ b/tests/sctp/sctp_client.c @@ -0,0 +1,225 @@ +#include "sctp_common.h" + +void usage(char *progname) +{ + fprintf(stderr, + "usage: %s [-e expected_msg] [-v] [-n] [-x] stream|seq 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" + "-n Do NOT call connect(3) or connectx(3).\n\t" + "-v Print context and ip options information.\n\t" + "-x Use sctp_connectx(3) instead of connect(3).\n\t" + "stream Use SCTP 1-to-1 style or:\n\t" + "seq use SCTP 1-to-Many style.\n\t" + "addr IPv4 or IPv6 address (e.g. 127.0.0.1 or ::1).\n\t" + "port Port for accessing server.\n", progname); + exit(1); +} + +int main(int argc, char **argv) +{ + int opt, sock, result; + socklen_t opt_len; + struct addrinfo hints, *serverinfo; + char byte = 0x41, label[1024], *expected = NULL; + bool verbose = false, connectx = false, no_connects = false; + bool ipv4 = false, expect_ipopt = false; + char *context; + struct timeval tm; + + while ((opt = getopt(argc, argv, "e:vxmni")) != -1) { + switch (opt) { + case 'e': + expected = optarg; + break; + case 'i': + expect_ipopt = true; + break; + case 'v': + verbose = true; + break; + case 'n': + no_connects = true; + break; + case 'x': + connectx = true; + break; + default: + usage(argv[0]); + } + } + + if ((argc - optind) != 3) + usage(argv[0]); + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_protocol = IPPROTO_SCTP; + + if (!strcmp(argv[optind], "stream")) + hints.ai_socktype = SOCK_STREAM; + else if (!strcmp(argv[optind], "seq")) + hints.ai_socktype = SOCK_SEQPACKET; + else + usage(argv[0]); + + if (verbose) { + if (getcon(&context) < 0) + context = strdup("unavailable"); + printf("Client process context: %s\n", context); + free(context); + } + + result = getaddrinfo(argv[optind + 1], argv[optind + 2], &hints, + &serverinfo); + if (result < 0) { + fprintf(stderr, "Client getaddrinfo: %s\n", + gai_strerror(result)); + exit(1); + } + + if (serverinfo->ai_family == AF_INET) + ipv4 = true; + + sock = socket(serverinfo->ai_family, serverinfo->ai_socktype, + serverinfo->ai_protocol); + if (sock < 0) { + perror("Client socket"); + exit(1); + } + + /* + * These timeouts are set to test whether the peer { recv } completes + * or not when the permission is denied. These errors will be returned + * during testing: + * EINPROGRESS - Operation now in progress - SOCK_STREAM + * EAGAIN - Resource temporarily unavailable - SOCK_SEQPACKET + */ + tm.tv_sec = 5; + tm.tv_usec = 0; + result = setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tm, sizeof(tm)); + if (result < 0) { + perror("Client setsockopt: SO_SNDTIMEO"); + exit(1); + } + + result = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tm, sizeof(tm)); + if (result < 0) { + perror("Client setsockopt: SO_RCVTIMEO"); + exit(1); + } + + if (!no_connects) { + if (connectx) + result = sctp_connectx(sock, serverinfo->ai_addr, + 1, NULL); + else + result = connect(sock, serverinfo->ai_addr, + serverinfo->ai_addrlen); + if (result < 0) { + if (errno != EINPROGRESS) + perror("Client connect"); + else + fprintf(stderr, "Client connect timeout\n"); + close(sock); + exit(1); + } + if (verbose) { + print_context(sock, "Client connect"); + print_ip_option(sock, ipv4, "Client connect"); + } + } + + + if (hints.ai_socktype == SOCK_STREAM) { + + result = write(sock, &byte, 1); + if (result < 0) { + perror("Client write"); + close(sock); + exit(1); + } + if (verbose) + print_context(sock, "Client STREAM write"); + + result = read(sock, label, sizeof(label)); + if (result < 0) { + perror("Client read"); + close(sock); + exit(1); + } + if (verbose) { + print_context(sock, "Client STREAM read"); + print_ip_option(sock, ipv4, "Client STREAM read"); + } + if (expect_ipopt) + expected = get_ip_option(sock, ipv4, &opt_len); + + } else { /* hints.ai_socktype == SOCK_SEQPACKET */ + + result = sctp_sendmsg(sock, &byte, 1, + serverinfo->ai_addr, + serverinfo->ai_addrlen, + 0, 0, 0, 0, 0); + if (result < 0) { + perror("Client sctp_sendmsg"); + close(sock); + exit(1); + } + + if (verbose) { + print_context(sock, "Client SEQPACKET sctp_sendmsg"); + print_ip_option(sock, ipv4, "Client SEQPACKET sctp_sendmsg"); + } + + result = sctp_recvmsg(sock, label, sizeof(label), + NULL, 0, NULL, NULL); + if (result < 0) { + if (errno != EAGAIN) + perror("Client sctp_recvmsg"); + else + fprintf(stderr, "Client sctp_recvmsg timeout\n"); + + close(sock); + exit(1); + } + if (expect_ipopt) + expected = get_ip_option(sock, ipv4, &opt_len); + } + + label[result] = 0; + + struct pollfd poll_fd; + + poll_fd.fd = sock; + poll_fd.events = POLLRDHUP; + poll_fd.revents = 1; + result = poll(&poll_fd, 1, 500); + if (verbose && result == 1) + printf("Client: Server closed connection\n"); + else if (verbose && result == 0) + printf("Client: poll(2) timed out - OKAY\n"); + else if (result < 0) + perror("Server - poll"); + + close(sock); + + if (!expected && !expect_ipopt) { + result = getcon(&expected); + if (result < 0) { + perror("Client getcon"); + exit(1); + } + } + + if (strcmp(expected, label)) { + fprintf(stderr, "Client expected %s, got %s\n", expected, label); + exit(1); + } else if (verbose) { + printf("Client received %s\n", label); + } + + exit(0); +} diff --git a/tests/sctp/sctp_common.c b/tests/sctp/sctp_common.c new file mode 100644 index 0000000..7a2b130 --- /dev/null +++ b/tests/sctp/sctp_common.c @@ -0,0 +1,156 @@ +#include "sctp_common.h" + +void print_context(int fd, char *text) +{ + char *context; + + if (fgetfilecon(fd, &context) < 0) + context = strdup("unavailable"); + printf("%s fd context: %s\n", text, context); + free(context); + + if (getpeercon(fd, &context) < 0) + context = strdup("unavailable"); + printf("%s peer context: %s\n", text, context); + free(context); +} + +void print_addr_info(struct sockaddr *sin, char *text) +{ + struct sockaddr_in *addr4; + struct sockaddr_in6 *addr6; + char addr_str[INET6_ADDRSTRLEN + 1]; + + switch (sin->sa_family) { + case AF_INET: + addr4 = (struct sockaddr_in *)sin; + inet_ntop(sin->sa_family, + (void *)&addr4->sin_addr, + addr_str, INET6_ADDRSTRLEN + 1); + printf("%s IPv4 addr %s\n", text, addr_str); + break; + case AF_INET6: + addr6 = (struct sockaddr_in6 *)sin; + if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr)) { + inet_ntop(AF_INET, + (void *)&addr6->sin6_addr.s6_addr32[3], + addr_str, INET6_ADDRSTRLEN + 1); + printf("%s IPv6->IPv4 MAPPED addr %s\n", + text, addr_str); + } else { + inet_ntop(sin->sa_family, + (void *)&addr6->sin6_addr, + addr_str, INET6_ADDRSTRLEN + 1); + printf("%s IPv6 addr %s\n", text, + addr_str); + } + break; + } +} + +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 print_ip_option(int fd, bool ipv4, char *text) +{ + 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); + free(ip_options); + } else { + printf("%s No IP Options set\n", text); + } +} + +/* This sets an option to allow large entries when testing buffer + * allocation etc. for SCTP. + * IPv4 the 0xff option is used so can set any rubbish to fill buffer. + * IPv6 the CALIPSO option works and can set rubbish as it does not mind, + * although tshark moans. + */ +int set_ip_option(int fd, bool ipv4) +{ + int result; + unsigned char *ptr; + /* 123456789012345678901234567890123456 */ + char *v4entries = "Hello World..........The end is nigh"; + unsigned char v4options[MAX_IPOPTLEN]; + + char *v6entries = "Hello World..................................." + ".............................................." + ".........The end is nigh"; + unsigned char v6options[120]; + + if (ipv4) { + memset(v4options, 0, sizeof(v4options)); + v4options[0] = IPOPT_NOP; + v4options[1 + IPOPT_OPTVAL] = 0xff; + v4options[1 + IPOPT_OLEN] = sizeof(v4options) - 1; + v4options[1 + IPOPT_OFFSET] = MAX_IPOPTLEN; + + ptr = &v4options[IPOPT_MINOFF]; + memcpy(ptr, v4entries, strlen(v4entries)); + + + result = setsockopt(fd, IPPROTO_IP, IP_OPTIONS, v4options, + sizeof(v4options)); + if (result < 0) { + perror("setsockopt: IP_OPTIONS"); + return -1; + } + } else { + memset(v6options, 0, sizeof(v6options)); + v6options[1] = sizeof(v6options) / 8 - 1; + v6options[2] = 7; + + ptr = &v6options[IPOPT_MINOFF]; + memcpy(ptr, v6entries, strlen(v6entries)); + + result = setsockopt(fd, IPPROTO_IPV6, IPV6_HOPOPTS, v6options, + sizeof(v6options)); + if (result < 0) { + perror("setsockopt: IPV6_HOPOPTS"); + return -1; + } + } + + return 0; +} diff --git a/tests/sctp/sctp_common.h b/tests/sctp/sctp_common.h new file mode 100644 index 0000000..89d8fda --- /dev/null +++ b/tests/sctp/sctp_common.h @@ -0,0 +1,28 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE /* For poll(2) POLLRDHUP - Detect client close(2) */ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void print_context(int fd, char *text); +void print_addr_info(struct sockaddr *sin, char *text); +char *get_ip_option(int fd, bool ipv4, socklen_t *opt_len); +void print_ip_option(int fd, bool ipv4, char *text); +int set_ip_option(int fd, bool ipv4); diff --git a/tests/sctp/sctp_conformance_test_server.c b/tests/sctp/sctp_conformance_test_server.c new file mode 100644 index 0000000..326beb2 --- /dev/null +++ b/tests/sctp/sctp_conformance_test_server.c @@ -0,0 +1,298 @@ +#include "sctp_common.h" + +/* For use by the https://github.com/nplab/sctp-tests sctp-server-tests + * script. Note that 3 of the 27 tests will TIMEOUT as they require specific + * feedback that this app cannot do (tests: sctp-as-o-1-9-2, sctp-d-i-8-5 and + * sctp-rt-i-11-1) + */ + +static void usage(char *progname) +{ + fprintf(stderr, + "usage: %s [-4] [-b ipv4_addr] [-h addr] [-i] [-n] [-v] port\n" + "\nWhere:\n\t" + "-4 Listen on IPv4 addresses only (used for CIPSO tests).\n\t" + "-b Call sctp_bindx(3) with the supplied IPv4 address.\n\t" + "-h IPv4 or IPv6 listen address. If IPv6 link-local address,\n\t" + " then requires the %% to obtain scopeid. e.g.\n\t" + " fe80::7629:afff:fe0f:8e5d%%wlp6s0\n\t" + "-i Send IP Options as msg (default is peer label).\n\t" + "-n No peer label or IP option will be available therefore\n\t" + " send \"nopeer\" message to client.\n\t" + "-v Print context and ip options information.\n\t" + "port Listening port.\n", progname); + exit(1); +} + +static void set_subscr_events(int fd, int value) +{ + int result; + struct sctp_event_subscribe subscr_events; + + memset(&subscr_events, 0, sizeof(subscr_events)); + subscr_events.sctp_association_event = value; + /* subscr_events.sctp_data_io_event = value; */ + + result = setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, + &subscr_events, sizeof(subscr_events)); + if (result < 0) { + perror("Server setsockopt: SCTP_EVENTS"); + close(fd); + exit(1); + } +} + +static void handle_event(void *buf) +{ + union sctp_notification *snp = buf; + struct sctp_assoc_change *sac; + + switch (snp->sn_header.sn_type) { + case SCTP_ASSOC_CHANGE: + sac = &snp->sn_assoc_change; + printf("SCTP_ASSOC_CHANGE ID: %d\n", sac->sac_assoc_id); + break; + case SCTP_PEER_ADDR_CHANGE: + printf("SCTP_PEER_ADDR_CHANGE\n"); + break; + case SCTP_SEND_FAILED: + printf("SCTP_SEND_FAILED\n"); + break; + case SCTP_REMOTE_ERROR: + printf("SCTP_REMOTE_ERROR\n"); + break; + case SCTP_SHUTDOWN_EVENT: + printf("SCTP_SHUTDOWN_EVENT\n"); + break; + case SCTP_PARTIAL_DELIVERY_EVENT: + printf("SCTP_PARTIAL_DELIVERY_EVENT\n"); + break; + case SCTP_ADAPTATION_INDICATION: + printf("SCTP_ADAPTATION_INDICATION\n"); + break; + case SCTP_AUTHENTICATION_INDICATION: + printf("SCTP_AUTHENTICATION_INDICATION\n"); + break; + case SCTP_SENDER_DRY_EVENT: + printf("SCTP_SENDER_DRY_EVENT\n"); + break; + default: + printf("Unknown event: %x\n", snp->sn_header.sn_type); + break; + } + return; +} + +int main(int argc, char **argv) +{ + int opt, sock, result, flags, if_index = 0, on = 1; + socklen_t sinlen, opt_len; + struct sockaddr_storage sin; + struct addrinfo hints, *res; + struct sctp_sndrcvinfo sinfo; + char *peerlabel, msglabel[1024], if_name[30]; + bool nopeer = false, verbose = false, ipv4 = false, snd_opt = false; + char *context, *host_addr = NULL, *bindx_addr = NULL; + struct sockaddr_in ipv4_addr; + unsigned short port; + + while ((opt = getopt(argc, argv, "4b:h:inv")) != -1) { + switch (opt) { + case '4': + ipv4 = true; + break; + case 'b': + bindx_addr = optarg; + break; + case 'h': + host_addr = optarg; + break; + case 'i': + snd_opt = true; + break; + case 'n': + nopeer = true; + break; + case 'v': + verbose = true; + break; + default: + usage(argv[0]); + } + } + + if ((argc - optind) != 1) + usage(argv[0]); + + port = atoi(argv[optind]); + if (!port) + usage(argv[0]); + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_flags = AI_PASSIVE; + hints.ai_protocol = IPPROTO_SCTP; + + if (ipv4) + hints.ai_family = AF_INET; + else + hints.ai_family = AF_INET6; + + hints.ai_socktype = SOCK_SEQPACKET; + + if (verbose) { + if (getcon(&context) < 0) + context = strdup("unavailable"); + printf("Server process context: %s\n", context); + free(context); + } + + if (host_addr) { + char *ptr; + + ptr = strpbrk(host_addr, "%"); + if (ptr) + strcpy(if_name, ptr + 1); + + if_index = if_nametoindex(if_name); + if (!if_index) { + perror("Server if_nametoindex"); + exit(1); + } + + result = getaddrinfo(host_addr, argv[optind], &hints, &res); + + } else { + result = getaddrinfo(NULL, argv[optind], &hints, &res); + } + + if (result < 0) { + fprintf(stderr, "Server getaddrinfo: %s\n", + gai_strerror(result)); + exit(1); + } + + sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (sock < 0) { + perror("Server socket"); + exit(1); + } + + result = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + if (result < 0) { + perror("Server setsockopt: SO_REUSEADDR"); + close(sock); + exit(1); + } + + /* Enables sctp_data_io_events for sctp_recvmsg(3) for assoc_id. */ + result = setsockopt(sock, SOL_SCTP, SCTP_EVENTS, &on, sizeof(on)); + if (result < 0) { + perror("Server setsockopt: SCTP_EVENTS"); + close(sock); + exit(1); + } + + if (bindx_addr) { + memset(&ipv4_addr, 0, sizeof(struct sockaddr_in)); + ipv4_addr.sin_family = AF_INET; + ipv4_addr.sin_port = htons(port); + ipv4_addr.sin_addr.s_addr = inet_addr(bindx_addr); + + result = sctp_bindx(sock, (struct sockaddr *)&ipv4_addr, 1, + SCTP_BINDX_ADD_ADDR); + if (result < 0) { + perror("Server sctp_bindx ADD - ipv4"); + close(sock); + exit(1); + } + } else { + result = bind(sock, res->ai_addr, res->ai_addrlen); + if (result < 0) { + perror("Server bind"); + close(sock); + exit(1); + } + } + + if (verbose) { + print_context(sock, "Server LISTEN"); + print_ip_option(sock, ipv4, "Server LISTEN"); + } + + if (listen(sock, SOMAXCONN)) { + perror("Server listen"); + close(sock); + exit(1); + } + + if (verbose) + print_context(sock, "Server sock"); + + set_subscr_events(sock, 1); + + do { + sinlen = sizeof(sin); + flags = 0; + + result = sctp_recvmsg(sock, msglabel, sizeof(msglabel), + (struct sockaddr *)&sin, &sinlen, + &sinfo, &flags); + if (result < 0) { + perror("Server sctp_recvmsg"); + close(sock); + exit(1); + } + + if (verbose) { + print_addr_info((struct sockaddr *)&sin, + "Server recvmsg"); + print_ip_option(sock, ipv4, + "Server recvmsg"); + printf("sctp_recvmsg response FLAGS: %x\n", flags); + } + + if (flags & MSG_NOTIFICATION) { + handle_event(msglabel); + continue; + } + + if (nopeer) { + peerlabel = strdup("nopeer"); + } else if (snd_opt) { + peerlabel = get_ip_option(sock, ipv4, &opt_len); + + if (!peerlabel) + peerlabel = strdup("no_ip_options"); + } else { + result = getpeercon(sock, &peerlabel); + if (result < 0) { + perror("Server getpeercon"); + close(sock); + exit(1); + } + } + printf("Server %s: %s\n", + snd_opt ? "sock_opt" : "peer label", peerlabel); + + if (sin.ss_family == AF_INET6 && host_addr) + ((struct sockaddr_in6 *)&sin)->sin6_scope_id = if_index; + + result = sctp_sendmsg(sock, peerlabel, + strlen(peerlabel), + (struct sockaddr *)&sin, + sinlen, 0, 0, 0, 0, 0); + if (result < 0) { + perror("Server sctp_sendmsg"); + close(sock); + exit(1); + } + + if (verbose) + printf("Server sent: %s\n", peerlabel); + + free(peerlabel); + } while (1); + + close(sock); + exit(0); +} diff --git a/tests/sctp/sctp_connectx.c b/tests/sctp/sctp_connectx.c new file mode 100644 index 0000000..1e9e3fc --- /dev/null +++ b/tests/sctp/sctp_connectx.c @@ -0,0 +1,123 @@ +#include "sctp_common.h" + +void usage(char *progname) +{ + fprintf(stderr, + "usage: %s [-v] stream|seq addr port\n" + "\nWhere:\n\t" + "-v Print context information.\n\t" + "stream Use SCTP 1-to-1 style or:\n\t" + "seq use SCTP 1-to-Many style.\n\t" + "addr Servers IPv4 or IPv6 address.\n\t" + "port port.\n", progname); + exit(1); +} + +int main(int argc, char **argv) +{ + int opt, type, srv_sock, client_sock, result, on = 1; + struct addrinfo srv_hints, client_hints, *srv_res, *client_res; + bool verbose = false; + char *context; + + while ((opt = getopt(argc, argv, "v")) != -1) { + switch (opt) { + case 'v': + verbose = true; + break; + default: + usage(argv[0]); + } + } + + if ((argc - optind) != 3) + usage(argv[0]); + + if (!strcmp(argv[optind], "stream")) + type = SOCK_STREAM; + else if (!strcmp(argv[optind], "seq")) + type = SOCK_SEQPACKET; + else + usage(argv[0]); + + if (verbose) { + if (getcon(&context) < 0) + context = strdup("unavailable"); + printf("Process context: %s\n", context); + free(context); + } + + memset(&srv_hints, 0, sizeof(struct addrinfo)); + srv_hints.ai_flags = AI_PASSIVE; + srv_hints.ai_family = AF_INET6; + + srv_hints.ai_socktype = type; + srv_hints.ai_protocol = IPPROTO_SCTP; + + /* Set up server side */ + result = getaddrinfo(NULL, argv[optind + 2], &srv_hints, &srv_res); + if (result < 0) { + printf("getaddrinfo - server: %s\n", gai_strerror(result)); + exit(1); + } + + srv_sock = socket(srv_res->ai_family, srv_res->ai_socktype, + srv_res->ai_protocol); + if (srv_sock < 0) { + perror("socket - server"); + exit(1); + } + + if (verbose) + print_context(srv_sock, "Server"); + + result = setsockopt(srv_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + if (result < 0) { + perror("setsockopt: SO_REUSEADDR"); + close(srv_sock); + exit(1); + } + + result = bind(srv_sock, srv_res->ai_addr, srv_res->ai_addrlen); + if (result < 0) { + perror("bind"); + close(srv_sock); + exit(1); + } + + listen(srv_sock, 1); + + /* Set up client side */ + memset(&client_hints, 0, sizeof(struct addrinfo)); + client_hints.ai_socktype = type; + client_hints.ai_protocol = IPPROTO_SCTP; + result = getaddrinfo(argv[optind + 1], argv[optind + 2], + &client_hints, &client_res); + if (result < 0) { + fprintf(stderr, "getaddrinfo - client: %s\n", + gai_strerror(result)); + exit(1); + } + + client_sock = socket(client_res->ai_family, client_res->ai_socktype, + client_res->ai_protocol); + if (client_sock < 0) { + perror("socket - client"); + exit(1); + } + + if (verbose) + print_context(client_sock, "Client"); + + result = sctp_connectx(client_sock, client_res->ai_addr, 1, NULL); + if (result < 0) { + perror("connectx"); + close(srv_sock); + close(client_sock); + exit(1); + } + + close(srv_sock); + close(client_sock); + exit(0); +} diff --git a/tests/sctp/sctp_peeloff_server.c b/tests/sctp/sctp_peeloff_server.c new file mode 100644 index 0000000..ff5fa62 --- /dev/null +++ b/tests/sctp/sctp_peeloff_server.c @@ -0,0 +1,259 @@ +#include "sctp_common.h" + +static void usage(char *progname) +{ + fprintf(stderr, + "usage: %s [-4] [-i] [-n] [-v] port\n" + "\nWhere:\n\t" + "-4 Listen on IPv4 addresses only.\n\t" + "-i Send IP Options as msg (default is peer label).\n\t" + "-n No peer context will be available therefore send\n\t" + " \"nopeer\" message to client, otherwise the peer context\n\t" + " will be retrieved and sent to client.\n\t" + "-v Print context and ip options information.\n\t" + "port Listening port.\n", progname); + exit(1); +} + +static void set_subscr_events(int fd, int value) +{ + int result; + struct sctp_event_subscribe subscr_events; + + memset(&subscr_events, 0, sizeof(subscr_events)); + subscr_events.sctp_association_event = value; + /* subscr_events.sctp_data_io_event = value; */ + + result = setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, + &subscr_events, sizeof(subscr_events)); + if (result < 0) { + perror("Server setsockopt: SCTP_EVENTS"); + close(fd); + exit(1); + } +} + +static sctp_assoc_t handle_event(void *buf) +{ + union sctp_notification *snp = buf; + struct sctp_assoc_change *sac; + + switch (snp->sn_header.sn_type) { + case SCTP_ASSOC_CHANGE: + sac = &snp->sn_assoc_change; + return sac->sac_assoc_id; + case SCTP_PEER_ADDR_CHANGE: + case SCTP_SEND_FAILED: + case SCTP_REMOTE_ERROR: + case SCTP_SHUTDOWN_EVENT: + case SCTP_PARTIAL_DELIVERY_EVENT: + case SCTP_ADAPTATION_INDICATION: + case SCTP_AUTHENTICATION_INDICATION: + case SCTP_SENDER_DRY_EVENT: + printf("Unrequested event: %x\n", snp->sn_header.sn_type); + break; + default: + printf("Unknown event: %x\n", snp->sn_header.sn_type); + break; + } + return -1; +} + +int main(int argc, char **argv) +{ + int opt, sock, result, peeloff_sk = 0, flags, on = 1; + sctp_assoc_t assoc_id; + socklen_t sinlen, opt_len; + struct sockaddr_storage sin; + struct addrinfo hints, *res; + char *peerlabel, *context, msglabel[256]; + bool nopeer = false, verbose = false, ipv4 = false, snd_opt = false; + unsigned short port; + + while ((opt = getopt(argc, argv, "4inv")) != -1) { + switch (opt) { + case '4': + ipv4 = true; + break; + case 'i': + snd_opt = true; + break; + case 'n': + nopeer = true; + break; + case 'v': + verbose = true; + break; + default: + usage(argv[0]); + } + } + + if ((argc - optind) != 1) + usage(argv[0]); + + port = atoi(argv[optind]); + if (!port) + usage(argv[0]); + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_flags = AI_PASSIVE; + hints.ai_protocol = IPPROTO_SCTP; + + if (ipv4) + hints.ai_family = AF_INET; + else + hints.ai_family = AF_INET6; + + /* sctp_peeloff(3) must be from 1 to Many style socket */ + hints.ai_socktype = SOCK_SEQPACKET; + + if (verbose) { + if (getcon(&context) < 0) + context = strdup("unavailable"); + printf("Server process context: %s\n", context); + free(context); + } + + result = getaddrinfo(NULL, argv[optind], &hints, &res); + if (result < 0) { + fprintf(stderr, "Server getaddrinfo: %s\n", + gai_strerror(result)); + exit(1); + } + + sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (sock < 0) { + perror("Server socket"); + exit(1); + } + + result = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + if (result < 0) { + perror("Server setsockopt: SO_REUSEADDR"); + close(sock); + exit(1); + } + + result = bind(sock, res->ai_addr, res->ai_addrlen); + if (result < 0) { + perror("Server bind"); + close(sock); + exit(1); + } + + if (verbose) + print_context(sock, "Server LISTEN sock"); + + if (listen(sock, SOMAXCONN)) { + perror("Server listen"); + close(sock); + exit(1); + } + + do { + set_subscr_events(sock, 1); /* Get assoc_id for sctp_peeloff() */ + sinlen = sizeof(sin); + flags = 0; + + result = sctp_recvmsg(sock, msglabel, sizeof(msglabel), + (struct sockaddr *)&sin, &sinlen, + NULL, &flags); + if (result < 0) { + perror("Server sctp_recvmsg-1"); + close(sock); + exit(1); + } + + if (verbose) + print_addr_info((struct sockaddr *)&sin, + "Server SEQPACKET recvmsg"); + + if (flags & MSG_NOTIFICATION && flags & MSG_EOR) { + assoc_id = handle_event(msglabel); + if (assoc_id <= 0) { + printf("Server Invalid association ID: %d\n", + assoc_id); + close(sock); + exit(1); + } + /* No more notifications */ + set_subscr_events(sock, 0); + + peeloff_sk = sctp_peeloff(sock, assoc_id); + if (peeloff_sk < 0) { + perror("Server sctp_peeloff"); + close(sock); + exit(1); + } + if (verbose) { + printf("Server sctp_peeloff(3) on sk: %d with association ID: %d\n", + peeloff_sk, assoc_id); + print_context(peeloff_sk, "Server PEELOFF"); + } + + /* Now get the client msg on peeloff socket */ + result = sctp_recvmsg(peeloff_sk, msglabel, sizeof(msglabel), + (struct sockaddr *)&sin, &sinlen, + NULL, &flags); + if (result < 0) { + perror("Server sctp_recvmsg-2"); + close(peeloff_sk); + close(sock); + exit(1); + } + + if (verbose) + print_addr_info((struct sockaddr *)&sin, + "Server SEQPACKET peeloff recvmsg"); + } else { + printf("Invalid sctp_recvmsg response FLAGS: %x\n", flags); + close(peeloff_sk); + close(sock); + exit(1); + } + + if (nopeer) { + peerlabel = strdup("nopeer"); + } else if (snd_opt) { + peerlabel = get_ip_option(sock, ipv4, &opt_len); + + if (!peerlabel) + peerlabel = strdup("no_ip_options"); + } else { + result = getpeercon(peeloff_sk, &peerlabel); + if (result < 0) { + perror("Server getpeercon"); + close(sock); + close(peeloff_sk); + exit(1); + } + } + + printf("Server PEELOFF %s: %s\n", + snd_opt ? "sock_opt" : "peer label", peerlabel); + + result = sctp_sendmsg(peeloff_sk, peerlabel, + strlen(peerlabel), + (struct sockaddr *)&sin, + sinlen, 0, 0, 0, 0, 0); + if (result < 0) { + perror("Server sctp_sendmsg"); + close(peeloff_sk); + close(sock); + exit(1); + } + + if (verbose) + printf("Server PEELOFF sent: %s\n", peerlabel); + + free(peerlabel); + + + + close(peeloff_sk); + } while (1); + + close(sock); + exit(0); +} diff --git a/tests/sctp/sctp_server.c b/tests/sctp/sctp_server.c new file mode 100644 index 0000000..2898c93 --- /dev/null +++ b/tests/sctp/sctp_server.c @@ -0,0 +1,332 @@ +#include "sctp_common.h" + +static void usage(char *progname) +{ + fprintf(stderr, + "usage: %s [-4] [-b ipv4_addr] [-h addr] [-i] [-n] [-v] stream|seq port\n" + "\nWhere:\n\t" + "-4 Listen on IPv4 addresses only (used for CIPSO tests).\n\t" + "-b Call sctp_bindx(3) with the supplied IPv4 address.\n\t" + "-h IPv4 or IPv6 listen address. If IPv6 link-local address,\n\t" + " then requires the %% to obtain scopeid. e.g.\n\t" + " fe80::7629:afff:fe0f:8e5d%%wlp6s0\n\t" + "-i Send IP Options as msg (default is peer label).\n\t" + "-n No peer label or IP option will be available therefore\n\t" + " send \"nopeer\" message to client.\n\t" + "-v Print context and ip options information.\n\t" + "stream Use SCTP 1-to-1 style or:\n\t" + "seq use SCTP 1-to-Many style.\n\t" + "port Listening port.\n", progname); + exit(1); +} + +int main(int argc, char **argv) +{ + int opt, sock, newsock, result, flags, if_index = 0, on = 1; + socklen_t sinlen, opt_len; + struct sockaddr_storage sin; + struct addrinfo hints, *res; + struct sctp_sndrcvinfo sinfo; + struct pollfd poll_fd; + char getsockopt_peerlabel[1024]; + char byte, *peerlabel, msglabel[1024], if_name[30]; + bool nopeer = false, verbose = false, ipv4 = false, snd_opt = false; + char *context, *host_addr = NULL, *bindx_addr = NULL; + struct sockaddr_in ipv4_addr; + unsigned short port; + + while ((opt = getopt(argc, argv, "4b:h:inv")) != -1) { + switch (opt) { + case '4': + ipv4 = true; + break; + case 'b': + bindx_addr = optarg; + break; + case 'h': + host_addr = optarg; + break; + case 'i': + snd_opt = true; + break; + case 'n': + nopeer = true; + break; + case 'v': + verbose = true; + break; + default: + usage(argv[0]); + } + } + + if ((argc - optind) != 2) + usage(argv[0]); + + port = atoi(argv[optind + 1]); + if (!port) + usage(argv[0]); + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_flags = AI_PASSIVE; + hints.ai_protocol = IPPROTO_SCTP; + + if (ipv4) + hints.ai_family = AF_INET; + else + hints.ai_family = AF_INET6; + + if (!strcmp(argv[optind], "stream")) + hints.ai_socktype = SOCK_STREAM; + else if (!strcmp(argv[optind], "seq")) + hints.ai_socktype = SOCK_SEQPACKET; + else + usage(argv[0]); + + if (verbose) { + if (getcon(&context) < 0) + context = strdup("unavailable"); + printf("Server process context: %s\n", context); + free(context); + } + + if (host_addr) { + char *ptr; + + ptr = strpbrk(host_addr, "%"); + if (ptr) + strcpy(if_name, ptr + 1); + + if_index = if_nametoindex(if_name); + if (!if_index) { + perror("Server if_nametoindex"); + exit(1); + } + + result = getaddrinfo(host_addr, argv[optind + 1], &hints, &res); + + } else { + result = getaddrinfo(NULL, argv[optind + 1], &hints, &res); + } + + if (result < 0) { + fprintf(stderr, "Server getaddrinfo: %s\n", + gai_strerror(result)); + exit(1); + } + + sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (sock < 0) { + perror("Server socket"); + exit(1); + } + + result = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + if (result < 0) { + perror("Server setsockopt: SO_REUSEADDR"); + close(sock); + exit(1); + } + + /* Enables sctp_data_io_events for sctp_recvmsg(3) for assoc_id. */ + result = setsockopt(sock, SOL_SCTP, SCTP_EVENTS, &on, sizeof(on)); + if (result < 0) { + perror("Server setsockopt: SCTP_EVENTS"); + close(sock); + exit(1); + } + + if (bindx_addr) { + memset(&ipv4_addr, 0, sizeof(struct sockaddr_in)); + ipv4_addr.sin_family = AF_INET; + ipv4_addr.sin_port = htons(port); + ipv4_addr.sin_addr.s_addr = inet_addr(bindx_addr); + + result = sctp_bindx(sock, (struct sockaddr *)&ipv4_addr, 1, + SCTP_BINDX_ADD_ADDR); + if (result < 0) { + perror("Server sctp_bindx ADD - ipv4"); + close(sock); + exit(1); + } + } else { + result = bind(sock, res->ai_addr, res->ai_addrlen); + if (result < 0) { + perror("Server bind"); + close(sock); + exit(1); + } + } + + if (verbose) { + print_context(sock, "Server LISTEN"); + print_ip_option(sock, ipv4, "Server LISTEN"); + } + + if (listen(sock, SOMAXCONN)) { + perror("Server listen"); + close(sock); + exit(1); + } + + if (hints.ai_socktype == SOCK_STREAM) { + if (verbose) + print_context(sock, "Server STREAM"); + + do { + socklen_t labellen = sizeof(getsockopt_peerlabel); + + sinlen = sizeof(sin); + + newsock = accept(sock, (struct sockaddr *)&sin, + &sinlen); + if (newsock < 0) { + perror("Server accept"); + close(sock); + exit(1); + } + + if (verbose) { + print_context(newsock, + "Server STREAM accept on newsock"); + print_addr_info((struct sockaddr *)&sin, + "Server connected to Client"); + print_ip_option(newsock, ipv4, + "Server STREAM accept on newsock"); + } + + if (nopeer) { + peerlabel = strdup("nopeer"); + } else if (snd_opt) { + peerlabel = get_ip_option(newsock, ipv4, &opt_len); + if (!peerlabel) + peerlabel = strdup("no_ip_options"); + } else { + result = getpeercon(newsock, &peerlabel); + if (result < 0) { + perror("Server getpeercon"); + close(sock); + close(newsock); + exit(1); + } + + /* Also test the getsockopt version */ + result = getsockopt(newsock, SOL_SOCKET, + SO_PEERSEC, + getsockopt_peerlabel, + &labellen); + if (result < 0) { + perror("Server getsockopt: SO_PEERSEC"); + close(sock); + close(newsock); + exit(1); + } + if (verbose) + printf("Server STREAM SO_PEERSEC peer label: %s\n", + getsockopt_peerlabel); + } + printf("Server STREAM %s: %s\n", + snd_opt ? "sock_opt" : "peer label", peerlabel); + + result = read(newsock, &byte, 1); + if (result < 0) { + perror("Server read"); + close(sock); + close(newsock); + exit(1); + } + + result = write(newsock, peerlabel, strlen(peerlabel)); + if (result < 0) { + perror("Server write"); + close(sock); + close(newsock); + exit(1); + } + + if (verbose) + printf("Server STREAM sent: %s\n", peerlabel); + + free(peerlabel); + + /* Let the client close the connection first as this + * will stop OOTB chunks if newsock closed early. + */ + poll_fd.fd = newsock; + poll_fd.events = POLLRDHUP; + poll_fd.revents = 1; + result = poll(&poll_fd, 1, 1000); + if (verbose && result == 1) + printf("Server STREAM: Client closed connection\n"); + else if (verbose && result == 0) + printf("Server: poll(2) timed out - OKAY\n"); + else if (result < 0) + perror("Server - poll"); + + close(newsock); + } while (1); + } else { /* hints.ai_socktype == SOCK_SEQPACKET */ + if (verbose) + print_context(sock, "Server SEQPACKET sock"); + + do { + sinlen = sizeof(sin); + + result = sctp_recvmsg(sock, msglabel, sizeof(msglabel), + (struct sockaddr *)&sin, &sinlen, + &sinfo, &flags); + if (result < 0) { + perror("Server sctp_recvmsg"); + close(sock); + exit(1); + } + + if (verbose) { + print_context(sock, "Server SEQPACKET recvmsg"); + print_addr_info((struct sockaddr *)&sin, + "Server SEQPACKET recvmsg"); + print_ip_option(sock, ipv4, + "Server SEQPACKET recvmsg"); + } + + if (nopeer) { + peerlabel = strdup("nopeer"); + } else if (snd_opt) { + peerlabel = get_ip_option(sock, ipv4, &opt_len); + + if (!peerlabel) + peerlabel = strdup("no_ip_options"); + } else { + result = getpeercon(sock, &peerlabel); + if (result < 0) { + perror("Server getpeercon"); + close(sock); + exit(1); + } + } + printf("Server SEQPACKET %s: %s\n", + snd_opt ? "sock_opt" : "peer label", peerlabel); + + if (sin.ss_family == AF_INET6 && host_addr) + ((struct sockaddr_in6 *)&sin)->sin6_scope_id = if_index; + + result = sctp_sendmsg(sock, peerlabel, + strlen(peerlabel), + (struct sockaddr *)&sin, + sinlen, 0, 0, 0, 0, 0); + if (result < 0) { + perror("Server sctp_sendmsg"); + close(sock); + exit(1); + } + + if (verbose) + printf("Server SEQPACKET sent: %s\n", peerlabel); + + free(peerlabel); + } while (1); + } + + close(sock); + exit(0); +} diff --git a/tests/sctp/sctp_set_params.c b/tests/sctp/sctp_set_params.c new file mode 100644 index 0000000..7172788 --- /dev/null +++ b/tests/sctp/sctp_set_params.c @@ -0,0 +1,205 @@ +#include "sctp_common.h" + +void usage(char *progname) +{ + fprintf(stderr, + "usage: %s [-v] [-o aci|pap|pat] stream|seq addr port\n" + "\nWhere:\n\t" + "-v Print information.\n\t" + "-o Test setsockoption(3) using one of the following\n\t" + " options:\n\t\t" + " aci = SCTP_ASSOCINFO\n\t\t" + " pap = SCTP_PEER_ADDR_PARAMS\n\t\t" + " pat = SCTP_PEER_ADDR_THLDS\n\t\t" + "stream SCTP 1-to-1 style or:\n\t" + "seq SCTP 1-to-Many style.\n\t" + "addr Servers IPv4 or IPv6 address.\n\t" + "port port.\n", progname); + exit(1); +} + +/* Test set_param permission for SCTP_ASSOCINFO */ +static void sctp_associnfo(int sk, int option) +{ + int result; + socklen_t len; + struct sctp_assocparams assocparams; + + memset(&assocparams, 0, sizeof(struct sctp_assocparams)); + + len = sizeof(struct sctp_assocparams); + result = getsockopt(sk, IPPROTO_SCTP, option, &assocparams, &len); + if (result < 0) { + perror("getsockopt: SCTP_ASSOCINFO"); + close(sk); + exit(1); + } + + assocparams.sasoc_asocmaxrxt += 5; + assocparams.sasoc_cookie_life += 15; + + result = setsockopt(sk, IPPROTO_SCTP, option, &assocparams, len); + if (result < 0) { + perror("setsockopt: SCTP_ASSOCINFO"); + close(sk); + exit(1); + } +} + + +/* Test set_param permission for SCTP_PEER_ADDR_PARAMS */ +static void sctp_peer_addr_params(int sk, int option) +{ + int result; + struct sctp_paddrparams heartbeat; + + memset(&heartbeat, 0, sizeof(struct sctp_paddrparams)); + heartbeat.spp_flags = SPP_HB_ENABLE; + heartbeat.spp_hbinterval = 100; + heartbeat.spp_pathmaxrxt = 1; + + result = setsockopt(sk, IPPROTO_SCTP, option, + &heartbeat, sizeof(heartbeat)); + if (result < 0) { + perror("setsockopt: SCTP_PEER_ADDR_PARAMS"); + close(sk); + exit(1); + } +} + +int main(int argc, char **argv) +{ + int opt, type, srv_sock, client_sock, result, sockoption = 0; + struct addrinfo srv_hints, client_hints, *srv_res, *client_res; + bool verbose = false; + char *context; + + while ((opt = getopt(argc, argv, "o:v")) != -1) { + switch (opt) { + case 'o': + if (!strcmp(optarg, "aci")) + sockoption = SCTP_ASSOCINFO; + else if (!strcmp(optarg, "pap")) + sockoption = SCTP_PEER_ADDR_PARAMS; + else if (!strcmp(optarg, "pat")) { + printf("SCTP_PEER_ADDR_THLDS not currently supported by userspace\n"); + exit(1); + } else + usage(argv[0]); + break; + case 'v': + verbose = true; + break; + default: + usage(argv[0]); + } + } + + if ((argc - optind) != 3) + usage(argv[0]); + + if (!strcmp(argv[optind], "stream")) + type = SOCK_STREAM; + else if (!strcmp(argv[optind], "seq")) + type = SOCK_SEQPACKET; + else + usage(argv[0]); + + if (verbose) { + if (getcon(&context) < 0) + context = strdup("unavailable"); + + printf("Process context: %s\n", context); + free(context); + } + + memset(&srv_hints, 0, sizeof(struct addrinfo)); + srv_hints.ai_flags = AI_PASSIVE; + srv_hints.ai_family = AF_INET6; + + srv_hints.ai_socktype = type; + srv_hints.ai_protocol = IPPROTO_SCTP; + + /* Set up server side */ + result = getaddrinfo(NULL, argv[optind + 2], &srv_hints, &srv_res); + if (result < 0) { + printf("getaddrinfo - server: %s\n", gai_strerror(result)); + exit(1); + } + + srv_sock = socket(srv_res->ai_family, srv_res->ai_socktype, + srv_res->ai_protocol); + if (srv_sock < 0) { + perror("socket - server"); + exit(1); + } + + if (verbose) + print_context(srv_sock, "Server"); + + if (bind(srv_sock, srv_res->ai_addr, srv_res->ai_addrlen) < 0) { + perror("bind"); + close(srv_sock); + exit(1); + } + + listen(srv_sock, 1); + + /* Set up client side */ + memset(&client_hints, 0, sizeof(struct addrinfo)); + client_hints.ai_socktype = type; + client_hints.ai_protocol = IPPROTO_SCTP; + result = getaddrinfo(argv[optind + 1], argv[optind + 2], + &client_hints, &client_res); + if (result < 0) { + fprintf(stderr, "getaddrinfo - client: %s\n", + gai_strerror(result)); + exit(1); + } + + client_sock = socket(client_res->ai_family, client_res->ai_socktype, + client_res->ai_protocol); + if (client_sock < 0) { + perror("socket - client"); + exit(1); + } + + if (verbose) + print_context(client_sock, "Client"); + + result = sctp_connectx(client_sock, client_res->ai_addr, 1, NULL); + if (result < 0) { + perror("connectx"); + close(client_sock); + exit(1); + } + + if (sockoption) { + switch (sockoption) { + case SCTP_ASSOCINFO: + if (verbose) + printf("Testing: SCTP_ASSOCINFO\n"); + sctp_associnfo(srv_sock, sockoption); + break; + case SCTP_PEER_ADDR_PARAMS: + if (verbose) + printf("Testing: SCTP_PEER_ADDR_PARAMS\n"); + sctp_peer_addr_params(client_sock, sockoption); + break; + } + } else { + + if (verbose) + printf("Testing: SCTP_ASSOCINFO\n"); + sctp_associnfo(srv_sock, SCTP_ASSOCINFO); + + if (verbose) + printf("Testing: SCTP_PEER_ADDR_PARAMS\n"); + sctp_peer_addr_params(client_sock, SCTP_PEER_ADDR_PARAMS); + + } + + close(srv_sock); + close(client_sock); + exit(0); +} diff --git a/tests/sctp/sctp_set_peer_addr.c b/tests/sctp/sctp_set_peer_addr.c new file mode 100644 index 0000000..38576ad --- /dev/null +++ b/tests/sctp/sctp_set_peer_addr.c @@ -0,0 +1,410 @@ +/* + * This test will allow the server side to add/remove bindx addresses and + * inform the client side via ASCONF chunks. It will also allow the server + * side to inform the client that the peer primary address is being updated. + * The code for checking these parameters are in net/sctp/sm_make_chunk.c + * sctp_process_asconf_param(). + * + * To enable the processing of these incoming ASCONF parameters for: + * SCTP_PARAM_SET_PRIMARY, SCTP_PARAM_ADD_IP and SCTP_PARAM_DEL_IP + * the following options must be enabled: + * echo 1 > /proc/sys/net/sctp/addip_enable + * echo 1 > /proc/sys/net/sctp/addip_noauth_enable + * + * If these are not enabled the SCTP_SET_PEER_PRIMARY_ADDR setsockopt + * fails with EPERM "Operation not permitted", however the bindx calls + * will complete but the client side will not be informed. + * + * NOTES: + * 1) SCTP_SET_PEER_PRIMARY_ADDR requires a non-loopback IP address. + * 2) Both addresses MUST be the same type (i.e. IPv4 or IPv6). + */ + +#include "sctp_common.h" + +void usage(char *progname) +{ + fprintf(stderr, + "usage: %s -v addr new_pri_addr port\n" + "\nWhere:\n\t" + "-v Print status information.\n\t" + "addr IPv4/IPv6 address for initial connection.\n\t" + "new_pri_addr IPv4/IPv6 address that the server will bindx\n\t" + " then set to the new SCTP_PRIMARY_ADDR.\n\t" + "port port.\n", progname); + fprintf(stderr, + "Notes:\n\t" + "1) addr and new_pri_addr MUST NOT be loopback addresses.\n\t" + "2) addr and new_pri_addr MUST be same type (IPv4 or IPv6).\n\t" + "3) IPv6 link-local addresses require the %% to\n\t" + " obtain scopeid. e.g. fe80::7629:afff:fe0f:8e5d%%wlp6s0\n"); + exit(1); +} + +static int peer_count, peer_count_err; + +static void getpaddrs_alarm(int sig) +{ + fprintf(stderr, "Get peer address count timer expired - carry on test\n"); + peer_count += 1; + peer_count_err = true; +} + +static void getprimaddr_alarm(int sig) +{ + fprintf(stderr, "Get primary address timer expired - end test.\n"); + exit(1); +} + +static void print_primaddr(char *msg, int socket) +{ + int result; + struct sctp_prim prim; + struct sockaddr_in *in_addr; + struct sockaddr_in6 *in6_addr; + struct sockaddr *paddr; + socklen_t prim_len; + char addr_buf[INET6_ADDRSTRLEN]; + const char *addr_ptr = NULL; + + memset(&prim, 0, sizeof(struct sctp_prim)); + + prim_len = sizeof(struct sctp_prim); + result = getsockopt(socket, IPPROTO_SCTP, SCTP_PRIMARY_ADDR, + &prim, &prim_len); + if (result < 0) { + perror("getsockopt: SCTP_PRIMARY_ADDR"); + exit(1); + } + + paddr = (struct sockaddr *)&prim.ssp_addr; + if (paddr->sa_family == AF_INET) { + in_addr = (struct sockaddr_in *)&prim.ssp_addr; + addr_ptr = inet_ntop(AF_INET, &in_addr->sin_addr, addr_buf, + INET6_ADDRSTRLEN); + } else if (paddr->sa_family == AF_INET6) { + in6_addr = (struct sockaddr_in6 *)&prim.ssp_addr; + addr_ptr = inet_ntop(AF_INET6, &in6_addr->sin6_addr, addr_buf, + INET6_ADDRSTRLEN); + } + + if (!addr_ptr) { + perror("inet_ntop"); + exit(1); + } + + printf("%s SCTP_PRIMARY_ADDR: %s\n", msg, addr_ptr); +} + +static void get_primaddr(char *addr_buf, int socket) +{ + int result; + struct sctp_prim prim; + struct sockaddr_in *in_addr; + struct sockaddr_in6 *in6_addr; + struct sockaddr *paddr; + socklen_t prim_len; + const char *addr_ptr = NULL; + + memset(&prim, 0, sizeof(struct sctp_prim)); + prim_len = sizeof(struct sctp_prim); + result = getsockopt(socket, IPPROTO_SCTP, SCTP_PRIMARY_ADDR, + &prim, &prim_len); + if (result < 0) { + perror("getsockopt: SCTP_PRIMARY_ADDR"); + exit(1); + } + + paddr = (struct sockaddr *)&prim.ssp_addr; + if (paddr->sa_family == AF_INET) { + in_addr = (struct sockaddr_in *)&prim.ssp_addr; + addr_ptr = inet_ntop(AF_INET, &in_addr->sin_addr, addr_buf, + INET6_ADDRSTRLEN); + } else if (paddr->sa_family == AF_INET6) { + in6_addr = (struct sockaddr_in6 *)&prim.ssp_addr; + addr_ptr = inet_ntop(AF_INET6, &in6_addr->sin6_addr, addr_buf, + INET6_ADDRSTRLEN); + } + if (!addr_ptr) { + perror("inet_ntop"); + exit(1); + } +} + +int main(int argc, char **argv) +{ + int opt, srv_sock, client_sock, new_sock, result, on = 1; + struct addrinfo srv_hints, client_hints, *srv_res, *client_res; + struct addrinfo *new_pri_addr_res; + struct sockaddr *sa_ptr, *paddrs; + socklen_t sinlen; + struct sockaddr_storage sin; + struct sctp_setpeerprim setpeerprim; + bool verbose = false, is_ipv6 = false; + char client_prim_addr[INET6_ADDRSTRLEN]; + char client_prim_new_pri_addr[INET6_ADDRSTRLEN]; + + while ((opt = getopt(argc, argv, "v")) != -1) { + switch (opt) { + case 'v': + verbose = true; + break; + default: + usage(argv[0]); + } + } + + if ((argc - optind) != 3) + usage(argv[0]); + + if (strchr(argv[optind], ':') && strchr(argv[optind + 1], ':')) { + is_ipv6 = true; + srv_hints.ai_family = AF_INET6; + } else if (strchr(argv[optind], '.') && strchr(argv[optind + 1], '.')) { + is_ipv6 = false; + srv_hints.ai_family = AF_INET; + } else { + usage(argv[0]); + } + + memset(&srv_hints, 0, sizeof(struct addrinfo)); + srv_hints.ai_flags = AI_PASSIVE; + srv_hints.ai_socktype = SOCK_STREAM; + srv_hints.ai_protocol = IPPROTO_SCTP; + + /* Set up server side */ + result = getaddrinfo(argv[optind], argv[optind + 2], + &srv_hints, &srv_res); + if (result < 0) { + fprintf(stderr, "getaddrinfo - server: %s\n", + gai_strerror(result)); + exit(1); + } + + result = getaddrinfo(argv[optind], argv[optind + 2], + &srv_hints, &srv_res); + if (result < 0) { + fprintf(stderr, "getaddrinfo - server: %s\n", + gai_strerror(result)); + exit(1); + } + if (is_ipv6 && verbose) + printf("Server scopeID: %d\n", + ((struct sockaddr_in6 *)srv_res->ai_addr)->sin6_scope_id); + + srv_sock = socket(srv_res->ai_family, srv_res->ai_socktype, + srv_res->ai_protocol); + if (srv_sock < 0) { + perror("socket - server"); + exit(1); + } + + result = setsockopt(srv_sock, SOL_SOCKET, SO_REUSEADDR, + &on, sizeof(on)); + if (result < 0) { + perror("setsockopt: SO_REUSEADDR"); + close(srv_sock); + exit(1); + } + + result = bind(srv_sock, srv_res->ai_addr, srv_res->ai_addrlen); + if (result < 0) { + perror("bind"); + close(srv_sock); + exit(1); + } + + listen(srv_sock, 1); + + /* Set up client side and connect */ + memset(&client_hints, 0, sizeof(struct addrinfo)); + client_hints.ai_socktype = SOCK_STREAM; + client_hints.ai_protocol = IPPROTO_SCTP; + result = getaddrinfo(argv[optind], argv[optind + 2], + &client_hints, &client_res); + if (result < 0) { + fprintf(stderr, "getaddrinfo - client: %s\n", + gai_strerror(result)); + close(srv_sock); + exit(1); + } + if (is_ipv6 && verbose) + printf("Client scopeID: %d\n", + ((struct sockaddr_in6 *)client_res->ai_addr)->sin6_scope_id); + + client_sock = socket(client_res->ai_family, client_res->ai_socktype, + client_res->ai_protocol); + if (client_sock < 0) { + perror("socket - client"); + close(srv_sock); + exit(1); + } + + result = connect(client_sock, client_res->ai_addr, + client_res->ai_addrlen); + if (result < 0) { + if (errno != EINPROGRESS) + perror("connect"); + else + fprintf(stderr, "connect timeout\n"); + result = 1; + goto err2; + } + + /* Obtain address info for the BINDX_ADD and new SCTP_PRIMARY_ADDR. */ + result = getaddrinfo(argv[optind + 1], argv[optind + 2], + &client_hints, &new_pri_addr_res); + if (result < 0) { + fprintf(stderr, "getaddrinfo - new SCTP_PRIMARY_ADDR: %s\n", + gai_strerror(result)); + close(srv_sock); + exit(1); + } + if (is_ipv6 && verbose) + printf("new_pri_addr scopeID: %d\n", + ((struct sockaddr_in6 *)new_pri_addr_res->ai_addr)->sin6_scope_id); + + /* Get number of peer addresses on CLIENT (should be 1) for a check + * later as sctp_bindx SERVER -> CLIENT is non-blocking. + */ + peer_count = sctp_getpaddrs(client_sock, 0, &paddrs); + sctp_freepaddrs(paddrs); + if (verbose) + printf("Client peer address count: %d\n", peer_count); + + /* Client and server now set so accept new socket on server side. */ + new_sock = accept(srv_sock, (struct sockaddr *)&sin, &sinlen); + if (new_sock < 0) { + perror("accept"); + result = 1; + goto err2; + } + + /* Get initial CLIENT primary address (that should be ADDR1). */ + get_primaddr(client_prim_addr, client_sock); + + /* Now call sctp_bindx to add new_pri_addr, this will cause an + * ASCONF - SCTP_PARAM_ADD_IP chunk to be sent to the CLIENT. + * This is non-blocking so there maybe a delay before the CLIENT + * receives the asconf chunk. + */ + if (verbose) + printf("Calling sctp_bindx ADD: %s\n", argv[optind + 1]); + + result = sctp_bindx(new_sock, + (struct sockaddr *)new_pri_addr_res->ai_addr, + 1, SCTP_BINDX_ADD_ADDR); + if (result < 0) { + if (errno == EACCES) { + perror("sctp_bindx ADD"); + } else { + perror("sctp_bindx ADD"); + result = 1; + goto err1; + } + } + /* so set an alarm and check number of peer addresses for CLIENT. */ + signal(SIGALRM, getpaddrs_alarm); + alarm(2); + peer_count_err = false; + result = 0; + + while (result != peer_count + 1) { + result = sctp_getpaddrs(client_sock, 0, &paddrs); + sctp_freepaddrs(paddrs); + + if (peer_count_err) + break; + } + peer_count = result; + + if (verbose) + printf("Client peer address count: %d\n", result); + + /* Now that the CLIENT has the new primary address ensure they use + * it by SCTP_SET_PEER_PRIMARY_ADDR. + */ + memset(&setpeerprim, 0, sizeof(struct sctp_setpeerprim)); + sa_ptr = (struct sockaddr *)&setpeerprim.sspp_addr; + if (is_ipv6) + memcpy(sa_ptr, new_pri_addr_res->ai_addr, + sizeof(struct sockaddr_in6)); + else + memcpy(sa_ptr, new_pri_addr_res->ai_addr, + sizeof(struct sockaddr_in)); + + if (verbose) + printf("Calling setsockopt SCTP_SET_PEER_PRIMARY_ADDR: %s\n", + argv[optind + 1]); + + result = setsockopt(new_sock, IPPROTO_SCTP, + SCTP_SET_PEER_PRIMARY_ADDR, + &setpeerprim, sizeof(struct sctp_setpeerprim)); + if (result < 0) { + perror("setsockopt: SCTP_SET_PEER_PRIMARY_ADDR"); + result = 1; + goto err1; + } + + /* Now get the new primary address from the client */ + signal(SIGALRM, getprimaddr_alarm); + alarm(2); + memcpy(client_prim_new_pri_addr, client_prim_addr, INET6_ADDRSTRLEN); + + while (!strcmp(client_prim_addr, client_prim_new_pri_addr)) + get_primaddr(client_prim_new_pri_addr, client_sock); + + if (verbose) { + printf("Client initial SCTP_PRIMARY_ADDR: %s\n", + client_prim_addr); + print_primaddr("Server", new_sock); + printf("Client current SCTP_PRIMARY_ADDR: %s\n", + client_prim_new_pri_addr); + } + + /* Then delete addr1 that checks ASCONF - SCTP_PARAM_DEL_IP. */ + if (verbose) + printf("Calling sctp_bindx REM: %s\n", argv[optind]); + + result = sctp_bindx(new_sock, (struct sockaddr *)client_res->ai_addr, + 1, SCTP_BINDX_REM_ADDR); + if (result < 0) { + perror("sctp_bindx - REM"); + result = 1; + goto err1; + } + + if (!peer_count_err) { + alarm(2); + result = 0; + + while (result != peer_count - 1) { + result = sctp_getpaddrs(client_sock, 0, &paddrs); + sctp_freepaddrs(paddrs); + } + + if (verbose) + printf("Client peer address count: %d\n", result); + } + + /* Compare the client primary addresses, they should be different. */ + if (!strcmp(client_prim_addr, client_prim_new_pri_addr)) { + fprintf(stderr, + "Client addr: %s same as new_pri_addr: %s - SCTP_SET_PEER_PRIMARY_ADDR failed\n", + client_prim_addr, client_prim_new_pri_addr); + result = 1; + goto err1; + } + + if (verbose) + printf("Client primary address changed successfully.\n"); + + result = 0; + +err1: + close(new_sock); +err2: + close(srv_sock); + close(client_sock); + exit(result); +} diff --git a/tests/sctp/sctp_set_pri_addr.c b/tests/sctp/sctp_set_pri_addr.c new file mode 100644 index 0000000..5cd6c53 --- /dev/null +++ b/tests/sctp/sctp_set_pri_addr.c @@ -0,0 +1,135 @@ +#include "sctp_common.h" + +void usage(char *progname) +{ + fprintf(stderr, + "usage: %s [-v] addr port\n" + "\nWhere:\n\t" + "-v Print information.\n\t" + "addr Servers IPv4 or IPv6 address.\n\t" + "port port.\n", progname); + exit(1); +} + +static void sctp_primary_addr(int sk, int option) +{ + int result; + socklen_t len; + struct sctp_prim primaddr; + + memset(&primaddr, 0, sizeof(struct sctp_prim)); + + len = sizeof(struct sctp_prim); + result = getsockopt(sk, IPPROTO_SCTP, option, + &primaddr, &len); + if (result < 0) { + perror("getsockopt: SCTP_PRIMARY_ADDR"); + close(sk); + exit(1); + } + + result = setsockopt(sk, IPPROTO_SCTP, option, &primaddr, len); + if (result < 0) { + perror("setsockopt: SCTP_PRIMARY_ADDR"); + close(sk); + exit(1); + } +} + +int main(int argc, char **argv) +{ + int opt, srv_sock, client_sock, result; + struct addrinfo srv_hints, client_hints, *srv_res, *client_res; + bool verbose = false; + char *context; + + while ((opt = getopt(argc, argv, "v")) != -1) { + switch (opt) { + case 'v': + verbose = true; + break; + default: + usage(argv[0]); + } + } + + if ((argc - optind) != 2) + usage(argv[0]); + + if (verbose) { + if (getcon(&context) < 0) + context = strdup("unavailable"); + + printf("Process context: %s\n", context); + free(context); + } + + memset(&srv_hints, 0, sizeof(struct addrinfo)); + srv_hints.ai_flags = AI_PASSIVE; + srv_hints.ai_family = AF_INET6; + + srv_hints.ai_socktype = SOCK_STREAM; + srv_hints.ai_protocol = IPPROTO_SCTP; + + /* Set up server side */ + result = getaddrinfo(NULL, argv[optind + 1], &srv_hints, &srv_res); + if (result < 0) { + printf("getaddrinfo - server: %s\n", gai_strerror(result)); + exit(1); + } + + srv_sock = socket(srv_res->ai_family, srv_res->ai_socktype, + srv_res->ai_protocol); + if (srv_sock < 0) { + perror("socket - server"); + exit(1); + } + + if (verbose) + print_context(srv_sock, "Server"); + + if (bind(srv_sock, srv_res->ai_addr, srv_res->ai_addrlen) < 0) { + perror("bind"); + close(srv_sock); + exit(1); + } + + listen(srv_sock, 1); + + /* Set up client side */ + memset(&client_hints, 0, sizeof(struct addrinfo)); + client_hints.ai_socktype = SOCK_STREAM; + client_hints.ai_protocol = IPPROTO_SCTP; + result = getaddrinfo(argv[optind], argv[optind + 1], &client_hints, + &client_res); + if (result < 0) { + fprintf(stderr, "getaddrinfo - client: %s\n", + gai_strerror(result)); + exit(1); + } + + client_sock = socket(client_res->ai_family, client_res->ai_socktype, + client_res->ai_protocol); + if (client_sock < 0) { + perror("socket - client"); + exit(1); + } + + if (verbose) + print_context(client_sock, "Client"); + + result = sctp_connectx(client_sock, client_res->ai_addr, 1, NULL); + if (result < 0) { + perror("connectx"); + close(client_sock); + exit(1); + } + + if (verbose) + printf("Testing: SCTP_PRIMARY_ADDR\n"); + sctp_primary_addr(client_sock, SCTP_PRIMARY_ADDR); + + close(srv_sock); + close(client_sock); + exit(0); +} diff --git a/tests/sctp/test b/tests/sctp/test new file mode 100755 index 0000000..1d7eff2 --- /dev/null +++ b/tests/sctp/test @@ -0,0 +1,502 @@ +#!/usr/bin/perl +use Test::More; + +BEGIN { + $basedir = $0; + $basedir =~ s|(.*)/[^/]*|$1|; + + # check if sctp enabled + if ( system("checksctp 2> /dev/null") != 0 ) { + plan skip_all => "SCTP not supported"; + } else { + $test_count = 43; + + # asconf parameter tests require two local non-loopback addresses. + $test_asconf = 0; + $ipaddress_list = `hostname -I`; + @ipaddress = split /\s+/, $ipaddress_list; + + if ( $ipaddress[1] ) { + $test_count += 2; + $test_asconf = 1; + } + + # Determine if CALIPSO supported by netlabelctl(8) and kernel. + $test_calipso = 0; + $netlabelctl = `netlabelctl -V`; + $netlabelctl =~ s/\D//g; + $kvercur = `uname -r`; + chomp($kvercur); + $kvermincalipso = "4.8"; + + $rc = `$basedir/../kvercmp $kvercur $kvermincalipso`; + if ( $netlabelctl gt "021" && $rc > 0 ) { + $test_count += 13; + $test_calipso = 1; + } + + plan tests => $test_count; + } +} + +# +# NOTE: direction flow is given as Client->Server (STREAM->SEQ) +# + +# +########################## Test base configuration ########################## +# +print "# Testing base configuration.\n"; + +# Start the stream server. +if ( ( $pid = fork() ) == 0 ) { + exec "runcon -t test_sctp_server_t $basedir/sctp_server -n stream 1035"; +} +sleep 1; # Give it a moment to initialize. + +# Verify that authorized client can communicate with the server STREAM->STREAM with client using connect(2). +$result = system "runcon -t test_sctp_client_t $basedir/sctp_client -e nopeer stream 127.0.0.1 1035"; +ok( $result eq 0 ); + +# Verify that authorized client can communicate with the server STREAM->STREAM with client using sctp_connectx(3). +$result = system "runcon -t test_sctp_client_t $basedir/sctp_client -x -e nopeer stream 127.0.0.1 1035"; +ok( $result eq 0 ); + +# Verify that authorized client can communicate with the server SEQ->STREAM with no client connect(2). +$result = system "runcon -t test_sctp_client_t $basedir/sctp_client -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 -e nopeer seq ::1 1035"; +ok( $result eq 0 ); + +# Verify that the client cannot communicate with server when using port not allowed STREAM->STREAM. +# Note that the sctp_test policy only allows ports 1024 - 1035 +$result = system "runcon -t test_sctp_client_t -- $basedir/sctp_client -e nopeer stream ::1 1036 2>&1"; +ok( $result ); + +# Kill the stream server. +kill TERM, $pid; + +# Verify that the server cannot start when using port not allowed STREAM->STREAM. +# Note that the sctp_test policy only allows ports 1024 - 1035 +$result = system "runcon -t test_sctp_server_t -- $basedir/sctp_bind stream 1036 2>&1"; +ok( $result ); + +# +############################### CONNECTX ##################################### +# +print "# Testing connectx.\n"; + +$result = system "runcon -t test_sctp_connectx_t $basedir/sctp_connectx stream 127.0.0.1 1035"; +ok( $result eq 0 ); + +$result = system "runcon -t test_sctp_connectx_t $basedir/sctp_connectx seq ::1 1035"; +ok( $result eq 0 ); + +# +################################ BINDX ####################################### +# +print "# Testing bindx.\n"; + +$result = system "runcon -t test_sctp_bindx_t $basedir/sctp_bindx -r stream 1035"; +ok( $result eq 0 ); + +$result = system "runcon -t test_sctp_bindx_t $basedir/sctp_bindx -r seq 1035"; +ok( $result eq 0 ); + +# +######################### SET_PRI_ADDR SET_PEER_ADDR ######################## +# + +# These tests require two local non-loopback addresses. +if ( $test_asconf ) { + print "# Testing asconf parameter chunk processing.\n"; + + # To enable processing of incoming ASCONF parameters: + # SCTP_PARAM_SET_PRIMARY, SCTP_PARAM_ADD_IP and SCTP_PARAM_DEL_IP, + # need to set: + system("echo 1 > /proc/sys/net/sctp/addip_enable"); + system("echo 1 > /proc/sys/net/sctp/addip_noauth_enable"); + + # Verify ASCONF params. + $result = system "runcon -t test_sctp_set_peer_addr_t $basedir/sctp_set_peer_addr $ipaddress[0] $ipaddress[1] 1035"; + ok( $result eq 0 ); + + # Start the asconf server. + if ( ( $pid = fork() ) == 0 ) { + exec "runcon -t test_sctp_set_peer_addr_t $basedir/sctp_asconf_params_server $ipaddress[0] $ipaddress[1] 1035"; + } + sleep 1; # Give it a moment to initialize. + + # This should fail connect permission attempting to send SCTP_PARAM_ADD_IP to client. + $result = system "runcon -t test_sctp_client_t -- $basedir/sctp_asconf_params_client $ipaddress[0] 1035 2>&1"; + ok( $result ); + + # The server should automatically exit. + kill TERM, $pid; + + system("echo 0 > /proc/sys/net/sctp/addip_enable"); + system("echo 0 > /proc/sys/net/sctp/addip_noauth_enable"); +} + +# +######################## Test NetLabel Configurations ####################### +# +########################## Fallback peer Labeling ############################ +# + +# Load NetLabel configuration using "netlabel_sctp_peer_t" as the label. +print "# Testing NetLabel fallback peer labeling.\n"; +system "/bin/sh $basedir/fb-label-load"; + +# Start stream server. +if ( ( $pid = fork() ) == 0 ) { + exec "runcon -t test_sctp_server_t $basedir/sctp_server stream 1035"; +} +sleep 1; # Give it a moment to initialize. + +# Verify that authorized client can communicate with the server STREAM->STREAM. +$result = system "runcon -t test_sctp_client_t $basedir/sctp_client -e system_u:object_r:netlabel_sctp_peer_t:s0 stream 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 -e system_u:object_r:netlabel_sctp_peer_t:s0 seq 127.0.0.1 1035"; +ok( $result eq 0 ); + +# Verify that a client without peer { recv } permission cannot communicate with the server STREAM->STREAM. +$result = system "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client -e system_u:object_r:netlabel_sctp_peer_t:s0 stream 127.0.0.1 1035 2>&1"; +ok( $result ); + +# Kill the stream server. +kill TERM, $pid; + +# Start seq server. +if ( ( $pid = fork() ) == 0 ) { + exec "runcon -t test_sctp_server_t $basedir/sctp_server seq 1035"; +} +sleep 1; # Give it a moment to initialize + +# Verify that authorized client can communicate with the server SEQ->SEQ. +$result = system "runcon -t test_sctp_client_t $basedir/sctp_client -e system_u:object_r:netlabel_sctp_peer_t:s0 seq ::1 1035"; +ok( $result eq 0 ); + +# Verify that authorized client can communicate with the server STREAM->SEQ. +$result = system "runcon -t test_sctp_client_t $basedir/sctp_client -e system_u:object_r:netlabel_sctp_peer_t:s0 stream ::1 1035"; +ok( $result eq 0 ); + +# Verify that a client without peer { recv } permission cannot communicate with the server SEQ->SEQ. +$result = system "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client -e system_u:object_r:netlabel_sctp_peer_t:s0 seq ::1 1035 2>&1"; +ok( $result ); + +# Kill the seq server. +kill TERM, $pid; + +system "/bin/sh $basedir/fb-label-flush"; + +# +#################### Test deny association permission ######################## +# +print "# Testing deny association.\n"; +system "/bin/sh $basedir/fb-deny-label-load"; + +if ( ( $pid = fork() ) == 0 ) { + exec "runcon -t test_sctp_server_t $basedir/sctp_server stream 1035"; +} +sleep 1; # Give it a moment to initialize + +# Verify that authorized client can communicate with the server STREAM->STREAM. +# This sets the servers initial peer context to netlabel_sctp_peer_t:s0 +$result = system "runcon -t test_sctp_client_t $basedir/sctp_client -e system_u:object_r:netlabel_sctp_peer_t:s0 stream 127.0.0.1 1035"; +ok( $result eq 0 ); + +# 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 -e system_u:object_r:deny_assoc_sctp_peer_t:s0 stream ::1 1035 2>&1"; +ok( $result ); + +# Kill the seq server. +kill TERM, $pid; + +system "/bin/sh $basedir/fb-deny-label-flush"; + +# +############################## CIPSO/IPv4 #################################### +# +print "# Testing CIPSO/IPv4 using socket ip_option data\n"; +system "/bin/sh $basedir/cipso-load"; + +# Start the stream server for IPv4 only. +if ( ( $pid = fork() ) == 0 ) { + exec "runcon -t test_sctp_server_t -l s0:c782,c714,c769,c788,c803,c842,c864 $basedir/sctp_server -4 -i stream 1035"; +} +sleep 1; # Give it a moment to initialize. + +# Verify that authorized client can communicate with the server STREAM->STREAM with client using sctp_connectx(3). +$result = system "runcon -t test_sctp_client_t -l s0:c782,c714,c769,c788,c803,c842,c864 $basedir/sctp_client -x -i stream 127.0.0.1 1035"; +ok( $result eq 0 ); + +# Verify that authorized client can communicate with the server STREAM->STREAM with client using connect(2). +$result = system "runcon -t test_sctp_client_t -l s0:c782,c714,c769,c788,c803,c842,c864 $basedir/sctp_client -i stream 127.0.0.1 1035"; +ok( $result eq 0 ); + +# Verify that authorized client can communicate with the server using different valid level STREAM->STREAM. +$result = system "runcon -t test_sctp_client_t -l s0:c769,c788,c803,c842,c864 $basedir/sctp_client -i stream 127.0.0.1 1035"; +ok( $result eq 0 ); + +# Verify that authorized client can communicate with the server using different valid level SEQ->STREAM +$result = system "runcon -t test_sctp_client_t -l s0:c769,c788,c803 $basedir/sctp_client -i seq 127.0.0.1 1035"; +ok( $result eq 0 ); + +# Verify that authorized client cannot communicate with the server using invalid level STREAM->STREAM. +$result = system "runcon -t test_sctp_client_t -l s0:c1023 -- $basedir/sctp_client stream 127.0.0.1 1035 2>&1"; +ok( $result ); + +# Kill the stream server. +kill TERM, $pid; + +# Start the seq server. +if ( ( $pid = fork() ) == 0 ) { + exec "runcon -t test_sctp_server_t -l s0:c20.c50 $basedir/sctp_server -i -4 seq 1035"; +} +sleep 1; # Give it a moment to initialize + +# Verify that authorized client can communicate with the server. SEQ->SEQ +$result = system "runcon -t test_sctp_client_t -l s0:c28.c48 $basedir/sctp_client -i seq 127.0.0.1 1035"; +ok( $result eq 0 ); + +# Verify that authorized client can communicate with the server using STREAM->SEQ. +$result = system "runcon -t test_sctp_client_t -l s0:c20.c50 $basedir/sctp_client -i stream 127.0.0.1 1035"; +ok( $result eq 0 ); + +# Verify that authorized client can communicate with the server using SEQ->SEQ with diff valid level. +$result = system "runcon -t test_sctp_client_t -l s0:c20.c30,c31,c35,c40.c45 $basedir/sctp_client -i seq 127.0.0.1 1035"; +ok( $result eq 0 ); + +# Verify that client cannot communicate with the server using SEQ->SEQ with invalid level. +$result = system "runcon -t test_sctp_client_t -l s0:c20.c51 -- $basedir/sctp_client -i seq 127.0.0.1 1035 2>&1"; +ok( $result ); + +# Verify that client cannot communicate with the server using SEQ->SEQ with invalid level. +$result = system "runcon -t test_sctp_client_t -l s0:c19.c50 -- $basedir/sctp_client -i seq 127.0.0.1 1035 2>&1"; +ok( $result ); + +# Kill server. +kill TERM, $pid; + +print "# Testing CIPSO/IPv4 PEELOFF using socket ip_option data\n"; +# Test sctp_peeloff(3) using 1 to Many SOCK_SEQPACKET +if ( ( $pid = fork() ) == 0 ) { + exec "runcon -t test_sctp_server_t -l s0:c0.c10 $basedir/sctp_peeloff_server -4 -i 1035"; +} +sleep 1; # Give it a moment to initialize + +# Verify that authorized client can communicate with the server using SEQ->SEQ->Peeloff with same level. +$result = system "runcon -t test_sctp_client_t -l s0:c0.c10 $basedir/sctp_client -i seq 127.0.0.1 1035"; +ok( $result eq 0 ); + +# Verify that authorized client can communicate with the server using STREAM->SEQ->peeloff with same level. +$result = system "runcon -t test_sctp_client_t -l s0:c0.c10 $basedir/sctp_client -x -i stream 127.0.0.1 1035"; +ok( $result eq 0 ); + +# Verify that client cannot communicate with the server using STREAM->SEQ->peeloff with invalid level. +$result = system "runcon -t test_sctp_client_t -l s0:c0.c11 -- $basedir/sctp_client -x -i stream 127.0.0.1 1035 2>&1"; +ok( $result ); + +# Kill the seq server. +kill TERM, $pid; + +system "/bin/sh $basedir/cipso-flush"; + +# +################## CIPSO/IPv4 Full Labeling over Loopback #################### +# + +print "# Testing CIPSO/IPv4 full labeling over loopback.\n"; +system "/bin/sh $basedir/cipso-fl-load"; + +# Start the stream server for IPv4 only. +if ( ( $pid = fork() ) == 0 ) { + exec "runcon -t test_sctp_server_t $basedir/sctp_server -4 stream 1035"; +} +sleep 1; # Give it a moment to initialize. + +# Verify that authorized client can communicate with the server STREAM->STREAM. +$result = system "runcon -t test_sctp_client_t $basedir/sctp_client stream 127.0.0.1 1035"; +ok( $result eq 0 ); + +# Verify a client without peer { recv } for client/server process cannot communicate with server STREAM->STREAM. +$result = system "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client stream 127.0.0.1 1035 2>&1"; +ok( $result ); + +# Kill the stream server. +kill TERM, $pid; + +# Start the seq server for IPv4 only. +if ( ( $pid = fork() ) == 0 ) { + exec "runcon -t test_sctp_server_t $basedir/sctp_server -4 seq 1035"; +} +sleep 1; # Give it a moment to initialize + +# Verify that authorized client can communicate with the server SEQ->STREAM. +$result = system "runcon -t test_sctp_client_t $basedir/sctp_client seq 127.0.0.1 1035"; +ok( $result eq 0 ); + +# Verify that a client without peer { recv } permission cannot communicate with the server SEQ->SEQ. +$result = system "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client seq 127.0.0.1 1035 2>&1"; +ok( $result ); + +# Kill the seq server. +kill TERM, $pid; + +system "/bin/sh $basedir/cipso-fl-flush"; + +# +############################### CALIPSO/IPv6 ################################# +# + +if ( $test_calipso ) { + print "# Testing CALIPSO/IPv6 using socket ip_option data\n"; + system "/bin/sh $basedir/calipso-load"; + + # Start the stream server. + if ( ( $pid = fork() ) == 0 ) { + exec "runcon -t test_sctp_server_t -l s0:c0,c12,c24,c36,c28,c610,c712,c414,c516,c318,c820,c622,c924,c726,c128,c330,c832,c534,c936,c138,c740,c42,c44,c246,c648,c950,c152,c354,c856,c158,c960,c662,c634,c686,c368,c570,c782,c714,c769,c788,c803,c842,c864,c986,c788,c290,c392,c594,c896,c698,c1023 $basedir/sctp_server -i stream 1035"; + } + sleep 1; # Give it a moment to initialize. + + # Verify that authorized client can communicate with the server STREAM->STREAM with client using sctp_connectx(3). + $result = system "runcon -t test_sctp_client_t -l s0:c0,c12,c24,c36,c28,c610,c712,c414,c516,c318,c820,c622,c924,c726,c128,c330,c832,c534,c936,c138,c740,c42,c44,c246,c648,c950,c152,c354,c856,c158,c960,c662,c634,c686,c368,c570,c782,c714,c769,c788,c803,c842,c864,c986,c788,c290,c392,c594,c896,c698,c1023 $basedir/sctp_client -x -i stream ::1 1035"; + ok( $result eq 0 ); + + # Verify that authorized client can communicate with the server STREAM->STREAM with client using connect(2). + $result = system "runcon -t test_sctp_client_t -l s0:c0,c12,c24,c36,c28,c610,c712,c414,c516,c318,c820,c622,c924,c726,c128,c330,c832,c534,c936,c138,c740,c42,c44,c246,c648,c950,c152,c354,c856,c158,c960,c662,c634,c686,c368,c570,c782,c714,c769,c788,c803,c842,c864,c986,c788,c290,c392,c594,c896,c698,c1023 $basedir/sctp_client -i stream ::1 1035"; + ok( $result eq 0 ); + + # Verify that authorized client can communicate with the server using different valid level STREAM->STREAM. + $result = system "runcon -t test_sctp_client_t -l s0:c924,c726,c128,c330,c832,c534,c936,c138,c740,c42 $basedir/sctp_client -i stream ::1 1035"; + ok( $result eq 0 ); + + # Verify that authorized client can communicate with the server using different valid level SEQ->STREAM + $result = system "runcon -t test_sctp_client_t -l s0:c924,c726,c128,c330,c832,c534,c936,c138,c740,c42 $basedir/sctp_client -i seq ::1 1035"; + ok( $result eq 0 ); + + # Verify that authorized client cannot communicate with the server using invalid level STREAM->STREAM. + $result = system "runcon -t test_sctp_client_t -l s0:c8.c12 -- $basedir/sctp_client -i stream ::1 1035 2>&1"; + ok( $result ); + + # Kill the stream server. + kill TERM, $pid; + + # Start the seq server. + if ( ( $pid = fork() ) == 0 ) { + exec "runcon -t test_sctp_server_t -l s0:c20.c50 $basedir/sctp_server -i seq 1035"; + } + sleep 1; # Give it a moment to initialize + + # Verify that authorized client can communicate with the server. SEQ->SEQ + $result = system "runcon -t test_sctp_client_t -l s0:c28.c48 $basedir/sctp_client -i seq ::1 1035"; + ok( $result eq 0 ); + + # Verify that authorized client can communicate with the server using STREAM->SEQ. + $result = system "runcon -t test_sctp_client_t -l s0:c20.c50 $basedir/sctp_client -i stream ::1 1035"; + ok( $result eq 0 ); + + # Verify that authorized client can communicate with the server using SEQ->SEQ with diff valid level. + $result = system "runcon -t test_sctp_client_t -l s0:c20.c30,c31,c35,c40.c45 $basedir/sctp_client -i seq ::1 1035"; + ok( $result eq 0 ); + + # Verify that client cannot communicate with the server using SEQ->SEQ with invalid level. + $result = system "runcon -t test_sctp_client_t -l s0:c20.c51 $basedir/sctp_client -i seq ::1 1035 2>&1"; + ok( $result ); + + # Verify that client cannot communicate with the server using SEQ->SEQ with invalid level. + $result = system "runcon -t test_sctp_client_t -l s0:c19.c50 -- $basedir/sctp_client -i seq ::1 1035 2>&1"; + ok( $result ); + + # Kill server. + kill TERM, $pid; + + print "# Testing CALIPSO/IPv6 PEELOFF using socket ip_option data\n"; + # Test sctp_peeloff(3) using 1 to Many SOCK_SEQPACKET + if ( ( $pid = fork() ) == 0 ) { + exec "runcon -t test_sctp_server_t -l s0:c0.c10 $basedir/sctp_peeloff_server -i 1035"; + } + sleep 1; # Give it a moment to initialize + + # Verify that authorized client can communicate with the server using SEQ->SEQ->Peeloff with same level. + $result = system "runcon -t test_sctp_client_t -l s0:c0.c10 $basedir/sctp_client -i seq ::1 1035"; + ok( $result eq 0 ); + + # Verify that authorized client can communicate with the server using STREAM->SEQ->peeloff with same level. + $result = system "runcon -t test_sctp_client_t -l s0:c0.c10 $basedir/sctp_client -x -i stream ::1 1035"; + ok( $result eq 0 ); + + # Verify that client cannot communicate with the server using STREAM->SEQ->peeloff with invalid level. + $result = system "runcon -t test_sctp_client_t -l s0:c0.c11 -- $basedir/sctp_client -x -i stream ::1 1035 2>&1"; + ok( $result ); + + # Kill the seq server. + kill TERM, $pid; + + system "/bin/sh $basedir/calipso-flush"; +} + +# +##################### Test iptables configuration ############################ +# +print "# Testing iptables (IPv4/IPv6).\n"; +system "/bin/sh $basedir/iptables-load"; + +# Start the stream server. +if ( ( $pid = fork() ) == 0 ) { + exec "runcon -t test_sctp_server_t $basedir/sctp_server -n stream 1035"; +} +sleep 1; # Give it a moment to initialize. + +# Verify that authorized client can communicate with the server STREAM->STREAM. +$result = system "runcon -t test_sctp_client_t $basedir/sctp_client -e nopeer stream 127.0.0.1 1035"; +ok( $result eq 0 ); + +# Verify that a client without peer { recv } permission cannot communicate with the server STREAM->STREAM. +$result = system "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client -e nopeer stream 127.0.0.1 1035 2>&1"; +ok( $result ); + +# Verify that authorized client can communicate with the server STREAM->STREAM. +$result = system "runcon -t test_sctp_client_t $basedir/sctp_client -e nopeer stream ::1 1035"; +ok( $result eq 0 ); + +# Verify that a client without peer { recv } permission cannot communicate with the server STREAM->STREAM. +$result = system "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client -e nopeer stream ::1 1035 2>&1"; +ok( $result ); + +# Kill the stream server. +kill TERM, $pid; + +# Start the seq server. +if ( ( $pid = fork() ) == 0 ) { + exec "runcon -t test_sctp_server_t $basedir/sctp_server -n seq 1035"; +} +sleep 1; # Give it a moment to initialize. + +# Verify that authorized client can communicate with the server SEQ->SEQ. +$result = system "runcon -t test_sctp_client_t $basedir/sctp_client -e nopeer seq 127.0.0.1 1035"; +ok( $result eq 0 ); + +# Verify that a client without peer { recv } permission cannot communicate with the server SEQ->SEQ. +$result = system "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client -e nopeer seq 127.0.0.1 1035 2>&1"; +ok( $result ); + +# Verify that authorized client can communicate with the server SEQ->SEQ. +$result = system "runcon -t test_sctp_client_t $basedir/sctp_client -e nopeer seq ::1 1035"; +ok( $result eq 0 ); + +# Verify that a client without peer { recv } permission cannot communicate with the server SEQ->SEQ. +$result = system "runcon -t test_sctp_deny_peer_client_t -- $basedir/sctp_client -e nopeer seq ::1 1035 2>&1"; +ok( $result ); + +# Kill the seq server. +kill TERM, $pid; + +system "/bin/sh $basedir/iptables-flush"; + +exit; -- 2.14.3