mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-04 08:24:42 +01:00
Initial checkin of the netdomain test suite. It requires
dejagnu (which, in turn, requires tcl).
This commit is contained in:
parent
f6244becd4
commit
371f984e09
21 changed files with 568 additions and 0 deletions
23
tests/regression/subdomain/netdomain/README
Normal file
23
tests/regression/subdomain/netdomain/README
Normal file
|
@ -0,0 +1,23 @@
|
|||
The multi-run testsuite works as follows:
|
||||
|
||||
In the base netdomain testsuite directory, there are two binaries:
|
||||
test_multi.send and test_multi.receive.
|
||||
|
||||
The testcases are in test_multi/[testcase_name].testcase. These testcases contain
|
||||
key/value pairs separated by a colon:
|
||||
- send_ip: [ip address the sending program should bind to]
|
||||
- send_port: [port number the sending program should bind to]
|
||||
- send_profile: [the netdomain profile string for the sending program. It can be blank]
|
||||
- receive_ip: [ip address the receive program should bind to]
|
||||
- receive_port: [port number the receive program should bind to]
|
||||
- receive_profile: [the netdomain profile string for the receive program. It can be blank]
|
||||
- proto: [udp or tcp]
|
||||
- message: [A message string that the sending program will send to the receiving program]
|
||||
|
||||
In test_multi/output there are the expected output files:
|
||||
- [testcase_name].send.out
|
||||
- [testcase_name].receive.out
|
||||
|
||||
When the test suite runs, it will execute the sending and receiving programs in parallel with
|
||||
the appropriate testcase settings applied to them. Once the programs have finished executing,
|
||||
the output is diff'd against the expected output to determine whether or not the test passes.
|
0
tests/regression/subdomain/netdomain/config/default.exp
Normal file
0
tests/regression/subdomain/netdomain/config/default.exp
Normal file
1
tests/regression/subdomain/netdomain/config/unix.exp
Normal file
1
tests/regression/subdomain/netdomain/config/unix.exp
Normal file
|
@ -0,0 +1 @@
|
|||
load_lib "netdomain_init.exp"
|
2
tests/regression/subdomain/netdomain/config/unknown.exp
Normal file
2
tests/regression/subdomain/netdomain/config/unknown.exp
Normal file
|
@ -0,0 +1,2 @@
|
|||
perror "No setup for current configuration."
|
||||
exit 1
|
161
tests/regression/subdomain/netdomain/lib/netdomain_init.exp
Normal file
161
tests/regression/subdomain/netdomain/lib/netdomain_init.exp
Normal file
|
@ -0,0 +1,161 @@
|
|||
# Adapted from the limal testsuite
|
||||
|
||||
proc multi-run { send_program } {
|
||||
set user_id [exec sh -c "/usr/bin/whoami"]
|
||||
if {$user_id != "root"} {
|
||||
puts "In order to actually load profiles, you need to run this test as root."
|
||||
return 0
|
||||
}
|
||||
set errorOccurred 0
|
||||
set path [split $send_program "/"]
|
||||
set filename [lindex $path [expr [llength $path]-1]]
|
||||
set cwd [pwd]
|
||||
|
||||
# extract basename and check extension
|
||||
|
||||
set fname [split $filename "."]
|
||||
|
||||
if {[llength $fname] < 2} {
|
||||
fail "Bad filename syntax '$send_program'"
|
||||
return -1
|
||||
}
|
||||
|
||||
if {[lindex $fname [expr [llength $fname]-1]] != "send"} {
|
||||
fail "Not .send extension '$send_program'"
|
||||
return -1
|
||||
}
|
||||
|
||||
# Set the name the multi run test
|
||||
set base_name [lindex $fname 0]
|
||||
puts "Running $base_name..."
|
||||
|
||||
set testcases [glob $base_name/*.testcase ]
|
||||
|
||||
foreach testcase $testcases {
|
||||
set testPath [split $testcase "/"]
|
||||
set testFilename [lindex $testPath [expr [llength $testPath]-1]]
|
||||
set testFname [split $testFilename "."]
|
||||
set testBase_name [lindex $testFname 0]
|
||||
|
||||
puts " ... $testBase_name"
|
||||
|
||||
# Generate the executable output directory
|
||||
exec rm -rf $cwd/$base_name/.out
|
||||
exec mkdir -p $cwd/$base_name/.out
|
||||
set send_output_file $cwd/$base_name/.out/$testBase_name.sent
|
||||
set receive_output_file $cwd/$base_name/.out/$testBase_name.received
|
||||
|
||||
# Set the testcase expected output files
|
||||
set send_expected_out $cwd/$base_name/output/$testBase_name.send.out
|
||||
set receive_expected_out $cwd/$base_name/output/$testBase_name.receive.out
|
||||
|
||||
# A little ways down I use sed to turn a generic profile into a testcase
|
||||
# specific one. Since it uses sed, and we look for three variables in the
|
||||
# generic testcase, we need a couple of staging files.
|
||||
set profile $cwd/$base_name/$testBase_name.profile
|
||||
set generic_profile $cwd/$base_name/$base_name.generic-profile
|
||||
set pathname_profile $cwd/$base_name/.out/$testBase_name.profile.pathnames
|
||||
set netdomain_profile $cwd/$base_name/.out/$testBase_name.profile.netdomain
|
||||
set generated_profile $cwd/$base_name/.out/$testBase_name.profile
|
||||
|
||||
# The name of the server program
|
||||
set receive_program "./$base_name.receive"
|
||||
# This is used to check whether or not the receive daemon is still running
|
||||
set receive_in_process ./$base_name/$testBase_name.rec.in.process
|
||||
|
||||
# Read in the test case
|
||||
set testcaseFileId [open $testcase r]
|
||||
set contents [read $testcaseFileId]
|
||||
close $testcaseFileId
|
||||
set line_list [split $contents "\n"]
|
||||
|
||||
foreach line $line_list {
|
||||
set listlist [split $line ":"]
|
||||
set listvalue [string trimleft [lindex $listlist 1]]
|
||||
set testcase_array([lindex $listlist 0]) $listvalue
|
||||
}
|
||||
|
||||
# Set up the sed commands to generate the profile
|
||||
set sed_cmd "/bin/sed \"s|\\\$\\\$PWD|[pwd]|\" < $generic_profile > $pathname_profile"
|
||||
set send_netdomain_sed_cmd "/bin/sed \"s|\\\$\\\$SENDNETDOMAIN|$testcase_array(send_profile)|\" < $pathname_profile > $netdomain_profile"
|
||||
set receive_netdomain_sed_cmd "/bin/sed \"s|\\\$\\\$RECEIVENETDOMAIN|$testcase_array(receive_profile)|\" < $netdomain_profile > $generated_profile"
|
||||
|
||||
# Run sed
|
||||
exec sh -c $sed_cmd
|
||||
exec sh -c $send_netdomain_sed_cmd
|
||||
exec sh -c $receive_netdomain_sed_cmd
|
||||
|
||||
# Load the profile
|
||||
set apparmor_cmd "/sbin/apparmor_parser --replace < $generated_profile > /dev/null"
|
||||
exec sh -c $apparmor_cmd
|
||||
|
||||
# fork off the server process
|
||||
if {[fork] == 0} {
|
||||
# Make a note of our running process
|
||||
set fileId [open $receive_in_process w]
|
||||
puts -nonewline $fileId "[pid]"
|
||||
close $fileId
|
||||
set rec_cmd "$receive_program $testcase_array(receive_ip) $testcase_array(receive_port) $testcase_array(proto) >$receive_output_file 2>$receive_output_file"
|
||||
set rec_status [catch { exec sh -c $rec_cmd } rec_result]
|
||||
file delete $receive_in_process
|
||||
if { $rec_status != 0 } {
|
||||
exit 1
|
||||
}
|
||||
exit 0
|
||||
}
|
||||
# Give the server a little time to get settled
|
||||
sleep 2
|
||||
|
||||
set send_command "$send_program $testcase_array(send_ip) $testcase_array(send_port) $testcase_array(receive_ip) $testcase_array(receive_port) $testcase_array(proto) \"$testcase_array(message)\" >$send_output_file 2>$send_output_file"
|
||||
set result ""
|
||||
set oops [catch { set result [exec sh -c $send_command] } caught]
|
||||
if {$oops != 0} {
|
||||
fail "Test case failed for $testBase_name: $caught"
|
||||
set errorOccurred 0
|
||||
continue
|
||||
}
|
||||
|
||||
if {$result != ""} {
|
||||
warning "Run of $testBase_name results in '$result'"
|
||||
set errorOccurred 0
|
||||
continue
|
||||
}
|
||||
|
||||
# Wait for the process that we forked earlier to be done
|
||||
while { [file exists $receive_in_process ] != 0 } { }
|
||||
|
||||
# Now compare the expect output with the actual output from the two programs
|
||||
if { [ file exists $send_output_file ] == 0 } {
|
||||
perror "Missing file $send_output_file" 0
|
||||
} else {
|
||||
if { [ diff $send_output_file $send_expected_out ] != 1 } {
|
||||
puts "Send program output doesn't match expected data:"
|
||||
puts [ exec sh -c "diff -u $send_output_file $send_expected_out || true" ]
|
||||
fail $testBase_name
|
||||
set errorOccurred 0
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if { [ file exists $receive_output_file ] == 0 } {
|
||||
perror "Missing file $receive_output_file" 0
|
||||
} else {
|
||||
if { [ diff $receive_output_file $receive_expected_out ] != 1 } {
|
||||
puts "Receive program output doesn't match expected data:"
|
||||
puts [ exec sh -c "diff -u $receive_output_file $receive_expected_out || true" ]
|
||||
fail $testBase_name
|
||||
set errorOccurred 0
|
||||
continue
|
||||
}
|
||||
}
|
||||
# If we got this far, then everything is fine
|
||||
pass $testBase_name
|
||||
}
|
||||
|
||||
if { $errorOccurred == 0 } {
|
||||
return 0
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
if { [catch { set filenames [glob $srcdir/*.send] } ] } {
|
||||
puts "No .send files found"
|
||||
} else {
|
||||
# foreach file, call multi-run (from testsuite/lib)
|
||||
|
||||
foreach file $filenames { multi-run $file }
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
MESSAGE: tcp_accept pass
|
|
@ -0,0 +1 @@
|
|||
Sending "tcp_accept pass"
|
|
@ -0,0 +1 @@
|
|||
MESSAGE: Test pass
|
|
@ -0,0 +1 @@
|
|||
Sending "Test pass"
|
|
@ -0,0 +1 @@
|
|||
MESSAGE: udp_recv pass
|
|
@ -0,0 +1 @@
|
|||
Sending "udp_recv pass"
|
|
@ -0,0 +1 @@
|
|||
MESSAGE: udp_send pass
|
|
@ -0,0 +1 @@
|
|||
Sending "udp_send pass"
|
|
@ -0,0 +1,8 @@
|
|||
send_ip: 127.0.0.1
|
||||
send_port: 8989
|
||||
send_profile:
|
||||
receive_ip: 127.0.0.1
|
||||
receive_port: 8990
|
||||
receive_profile:
|
||||
message: tcp_accept pass
|
||||
proto: tcp
|
|
@ -0,0 +1,8 @@
|
|||
send_ip: 127.0.0.1
|
||||
send_port: 9001
|
||||
send_profile:
|
||||
receive_ip: 127.0.0.1
|
||||
receive_port: 9002
|
||||
receive_profile:
|
||||
message: Test pass
|
||||
proto: tcp
|
|
@ -0,0 +1,17 @@
|
|||
# Generic profile for test_multi.send and test_multi.receive
|
||||
#include <tunables/global>
|
||||
|
||||
$$PWD/test_multi.send {
|
||||
#include <abstractions/base>
|
||||
$$SENDNETDOMAIN
|
||||
$$PWD/test_multi/*.send r,
|
||||
$$PWD/test_multi.send mr,
|
||||
}
|
||||
|
||||
$$PWD/test_multi.receive {
|
||||
#include <abstractions/base>
|
||||
$$RECEIVENETDOMAIN
|
||||
$$PWD/test_multi/*.receive r,
|
||||
$$PWD/test_multi.receive mr,
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
send_ip: 127.0.0.1
|
||||
send_port: 9100
|
||||
send_profile:
|
||||
receive_ip: 127.0.0.1
|
||||
receive_port: 9101
|
||||
receive_profile:
|
||||
message: udp_recv pass
|
||||
proto: udp
|
|
@ -0,0 +1,8 @@
|
|||
send_ip: 127.0.0.1
|
||||
send_port: 9200
|
||||
send_profile:
|
||||
receive_ip: 127.0.0.1
|
||||
receive_port: 9201
|
||||
receive_profile:
|
||||
message: udp_send pass
|
||||
proto: udp
|
191
tests/regression/subdomain/netdomain/test_multi_receive.c
Normal file
191
tests/regression/subdomain/netdomain/test_multi_receive.c
Normal file
|
@ -0,0 +1,191 @@
|
|||
/* Multiple iteration sending test. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
|
||||
int receive_udp(char *bind_ip, char *bind_port);
|
||||
int receive_tcp(char *bind_ip, char *bind_port);
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (argc < 4)
|
||||
{
|
||||
printf("Usage: %s bind_ip bind_port proto\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (strcmp(argv[3], "udp") == 0)
|
||||
{
|
||||
ret = receive_udp(argv[1], argv[2]);
|
||||
}
|
||||
else if (strcmp(argv[3], "tcp") == 0)
|
||||
{
|
||||
ret = receive_tcp(argv[1], argv[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Unknown protocol.\n");
|
||||
}
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
printf("Receive message failed.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int receive_udp(char *bind_ip, char *bind_port)
|
||||
{
|
||||
|
||||
int sock;
|
||||
char *buf;
|
||||
struct sockaddr_in remote, local;
|
||||
int ret = -1;
|
||||
int select_return;
|
||||
|
||||
fd_set read_set, err_set;
|
||||
struct timeval timeout;
|
||||
|
||||
buf = (char *) malloc(255);
|
||||
memset(buf, '\0', 255);
|
||||
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
|
||||
{
|
||||
perror("Socket error: ");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
local.sin_family = AF_INET;
|
||||
local.sin_port = htons(atoi(bind_port));
|
||||
inet_aton(bind_ip, &local.sin_addr);
|
||||
|
||||
if (bind(sock, (struct sockaddr *) &local, sizeof(local)) < 0)
|
||||
{
|
||||
perror("Bind error: ");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
FD_ZERO(&read_set);
|
||||
FD_SET(sock, &read_set);
|
||||
FD_ZERO(&err_set);
|
||||
FD_SET(sock, &err_set);
|
||||
timeout.tv_sec = 10;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
select_return = select(sock + 1, &read_set, NULL, &err_set, &timeout);
|
||||
if (select_return < 0)
|
||||
{
|
||||
perror("Select error: ");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ((select_return > 0) && (FD_ISSET(sock, &read_set)) && (!FD_ISSET(sock, &err_set)))
|
||||
{
|
||||
|
||||
if (recvfrom(sock, buf, 255, 0, (struct sockaddr *)0, (int *)0) >= 1)
|
||||
{
|
||||
printf("MESSAGE: %s\n", buf);
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("recvfrom failed\n");
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
free(buf);
|
||||
return(ret);
|
||||
|
||||
}
|
||||
|
||||
int receive_tcp(char *bind_ip, char *bind_port)
|
||||
{
|
||||
int sock, cli_sock;
|
||||
char *buf;
|
||||
struct sockaddr_in remote, local;
|
||||
int ret = -1;
|
||||
int select_return;
|
||||
|
||||
fd_set read_set, err_set;
|
||||
struct timeval timeout;
|
||||
|
||||
buf = (char *) malloc(255);
|
||||
memset(buf, '\0', 255);
|
||||
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
|
||||
{
|
||||
perror("Socket error:");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
local.sin_family = AF_INET;
|
||||
local.sin_port = htons(atoi(bind_port));
|
||||
inet_aton(bind_ip, &local.sin_addr);
|
||||
|
||||
if (bind(sock, (struct sockaddr *) &local, sizeof(local)) < 0)
|
||||
{
|
||||
perror("Could not bind.");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (listen(sock, 5) == -1)
|
||||
{
|
||||
perror("Could not listen: ");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
FD_ZERO(&read_set);
|
||||
FD_SET(sock, &read_set);
|
||||
FD_ZERO(&err_set);
|
||||
FD_SET(sock, &err_set);
|
||||
timeout.tv_sec = 10;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
select_return = select(sock + 1, &read_set, NULL, &err_set, &timeout);
|
||||
if (select_return < 0)
|
||||
{
|
||||
perror("Select failed: ");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if ((select_return > 0) && (FD_ISSET(sock, &read_set)) && (!FD_ISSET(sock, &err_set)))
|
||||
{
|
||||
if ((cli_sock = accept(sock, NULL, NULL)) < 0)
|
||||
{
|
||||
perror("Accept failed: ");
|
||||
ret = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (recv(cli_sock, buf, 255, 0) >= 1)
|
||||
{
|
||||
printf("MESSAGE: %s\n", buf);
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
perror("recv failure: ");
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
perror("There were select failures: ");
|
||||
ret = -1;
|
||||
}
|
||||
free(buf);
|
||||
return(ret);
|
||||
}
|
125
tests/regression/subdomain/netdomain/test_multi_send.c
Normal file
125
tests/regression/subdomain/netdomain/test_multi_send.c
Normal file
|
@ -0,0 +1,125 @@
|
|||
/* Multiple iteration sending test. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
int send_udp(char *bind_ip, char *bind_port, char *remote_ip, char *remote_port, char *message);
|
||||
int send_tcp(char *bind_ip, char *bind_port, char *remote_ip, char *remote_port, char *message);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int send_ret;
|
||||
|
||||
if (argc < 7)
|
||||
{
|
||||
printf("Usage: %s bind_ip bind_port remote_ip remote_port proto message\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
send_ret = -1;
|
||||
if (strcmp(argv[5], "udp") == 0)
|
||||
{
|
||||
send_ret = send_udp(argv[1], argv[2], argv[3], argv[4], argv[6]);
|
||||
}
|
||||
else if (strcmp(argv[5], "tcp") == 0)
|
||||
{
|
||||
send_ret = send_tcp(argv[1], argv[2], argv[3], argv[4], argv[6]);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Unknown protocol.\n");
|
||||
}
|
||||
|
||||
if (send_ret == -1)
|
||||
{
|
||||
printf("Send message failed.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int send_udp(char *bind_ip, char *bind_port, char *remote_ip, char *remote_port, char *message)
|
||||
{
|
||||
int sock;
|
||||
struct sockaddr_in remote, local;
|
||||
|
||||
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
|
||||
{
|
||||
perror("Could not open socket: ");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
remote.sin_family = AF_INET;
|
||||
remote.sin_port = htons(atoi(remote_port));
|
||||
inet_aton(remote_ip, &remote.sin_addr);
|
||||
|
||||
local.sin_family = AF_INET;
|
||||
local.sin_port = htons(atoi(bind_port));
|
||||
inet_aton(bind_ip, &local.sin_addr);
|
||||
|
||||
if (bind(sock, (struct sockaddr *) &local, sizeof(local)) < 0)
|
||||
{
|
||||
perror("Could not bind: ");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
printf("Sending \"%s\"\n", message);
|
||||
if (sendto(sock, message, strlen(message), 0, (struct sockaddr *) &remote, sizeof(remote)) <= 0)
|
||||
{
|
||||
perror("Send failed: ");
|
||||
return(-1);
|
||||
}
|
||||
close(sock);
|
||||
return(0);
|
||||
|
||||
}
|
||||
|
||||
int send_tcp(char *bind_ip, char *bind_port, char *remote_ip, char *remote_port, char *message)
|
||||
{
|
||||
int sock;
|
||||
struct sockaddr_in remote, local;
|
||||
|
||||
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
|
||||
{
|
||||
perror("Could not open socket: ");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
remote.sin_family = AF_INET;
|
||||
remote.sin_port = htons(atoi(remote_port));
|
||||
inet_aton(remote_ip, &remote.sin_addr);
|
||||
|
||||
local.sin_family = AF_INET;
|
||||
local.sin_port = htons(atoi(bind_port));
|
||||
inet_aton(bind_ip, &local.sin_addr);
|
||||
|
||||
if (bind(sock, (struct sockaddr *) &local, sizeof(local)) < 0)
|
||||
{
|
||||
perror("Could not bind: ");
|
||||
return(-1);
|
||||
}
|
||||
if (connect(sock, (struct sockaddr *) &remote, sizeof(remote)) < 0)
|
||||
{
|
||||
perror("Could not connect: ");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
printf("Sending \"%s\"\n", message);
|
||||
if (send(sock, message, strlen(message), 0) <= 0)
|
||||
{
|
||||
perror("Send failed: ");
|
||||
return(-1);
|
||||
}
|
||||
close(sock);
|
||||
return(0);
|
||||
|
||||
|
||||
}
|
||||
|
Loading…
Add table
Reference in a new issue