mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-09-02 15:25:27 +00:00
tests: add fine grained network regression tests
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -266,6 +266,8 @@ tests/regression/apparmor/mmap
|
|||||||
tests/regression/apparmor/mount
|
tests/regression/apparmor/mount
|
||||||
tests/regression/apparmor/move_mount
|
tests/regression/apparmor/move_mount
|
||||||
tests/regression/apparmor/named_pipe
|
tests/regression/apparmor/named_pipe
|
||||||
|
tests/regression/apparmor/net_finegrained_rcv
|
||||||
|
tests/regression/apparmor/net_finegrained_snd
|
||||||
tests/regression/apparmor/net_raw
|
tests/regression/apparmor/net_raw
|
||||||
tests/regression/apparmor/open
|
tests/regression/apparmor/open
|
||||||
tests/regression/apparmor/openat
|
tests/regression/apparmor/openat
|
||||||
|
@@ -111,6 +111,8 @@ SRC=access.c \
|
|||||||
mount.c \
|
mount.c \
|
||||||
move_mount.c \
|
move_mount.c \
|
||||||
named_pipe.c \
|
named_pipe.c \
|
||||||
|
net_finegrained_rcv.c \
|
||||||
|
net_finegrained_snd.c \
|
||||||
net_raw.c \
|
net_raw.c \
|
||||||
open.c \
|
open.c \
|
||||||
openat.c \
|
openat.c \
|
||||||
|
@@ -164,8 +164,14 @@ sub gen_netdomain($@) {
|
|||||||
|
|
||||||
sub gen_network($@) {
|
sub gen_network($@) {
|
||||||
my ($rule, $qualifier) = @_;
|
my ($rule, $qualifier) = @_;
|
||||||
|
if ($rule =~ /^network:/) {
|
||||||
my @rules = split (/:/, $rule);
|
my @rules = split (/:/, $rule);
|
||||||
push (@{$output_rules{$hat}}, " ${qualifier}@rules,\n");
|
push (@{$output_rules{$hat}}, " ${qualifier}@rules,\n");
|
||||||
|
} else {
|
||||||
|
# if using fine grained mediation, separator needs to be ; because of ipv6
|
||||||
|
my @rules = split (/;/, $rule);
|
||||||
|
push (@{$output_rules{$hat}}, " ${qualifier}@rules,\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub gen_unix($@) {
|
sub gen_unix($@) {
|
||||||
@@ -495,7 +501,7 @@ sub gen_from_args() {
|
|||||||
if ($rule =~ /^(tcp|udp)/) {
|
if ($rule =~ /^(tcp|udp)/) {
|
||||||
# netdomain rules
|
# netdomain rules
|
||||||
gen_netdomain($rule, $qualifier);
|
gen_netdomain($rule, $qualifier);
|
||||||
} elsif ($rule =~ /^network:/) {
|
} elsif ($rule =~ /^network(:|;)/) {
|
||||||
gen_network($rule, $qualifier);
|
gen_network($rule, $qualifier);
|
||||||
} elsif ($rule =~ /^unix:/) {
|
} elsif ($rule =~ /^unix:/) {
|
||||||
gen_unix($rule, $qualifier);
|
gen_unix($rule, $qualifier);
|
||||||
|
60
tests/regression/apparmor/net_finegrained.h
Normal file
60
tests/regression/apparmor/net_finegrained.h
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
struct ip_address {
|
||||||
|
union {
|
||||||
|
uint8_t address_v6[16];
|
||||||
|
uint32_t address_v4;
|
||||||
|
} address;
|
||||||
|
uint16_t family;
|
||||||
|
uint16_t port;
|
||||||
|
uint8_t subnet_mask;
|
||||||
|
};
|
||||||
|
|
||||||
|
int parse_ipv4_address(const char *ip, const char *port, struct ip_address *result)
|
||||||
|
{
|
||||||
|
struct in_addr addr;
|
||||||
|
if (inet_pton(AF_INET, ip, &addr) == 1) {
|
||||||
|
result->family = AF_INET;
|
||||||
|
result->address.address_v4 = addr.s_addr;
|
||||||
|
result->port = htons(atoi(port));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_ipv6_address(const char *ip, const char *port, struct ip_address *result)
|
||||||
|
{
|
||||||
|
struct in6_addr addr;
|
||||||
|
if (inet_pton(AF_INET6, ip, &addr) == 1) {
|
||||||
|
result->family = AF_INET6;
|
||||||
|
memcpy(result->address.address_v6, addr.s6_addr, 16);
|
||||||
|
result->port = htons(atoi(port));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_ip(const char *ip, const char *port, struct ip_address *result)
|
||||||
|
{
|
||||||
|
return parse_ipv6_address(ip, port, result) ||
|
||||||
|
parse_ipv4_address(ip, port, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_in convert_to_sockaddr_in(struct ip_address result)
|
||||||
|
{
|
||||||
|
struct sockaddr_in sockaddr;
|
||||||
|
sockaddr.sin_family = result.family;
|
||||||
|
sockaddr.sin_port = result.port;
|
||||||
|
sockaddr.sin_addr.s_addr = result.address.address_v4;
|
||||||
|
return sockaddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_in6 convert_to_sockaddr_in6(struct ip_address result)
|
||||||
|
{
|
||||||
|
struct sockaddr_in6 sockaddr;
|
||||||
|
sockaddr.sin6_family = result.family;
|
||||||
|
sockaddr.sin6_port = result.port;
|
||||||
|
memcpy(sockaddr.sin6_addr.s6_addr, result.address.address_v6, 16);
|
||||||
|
return sockaddr;
|
||||||
|
}
|
131
tests/regression/apparmor/net_finegrained.sh
Normal file
131
tests/regression/apparmor/net_finegrained.sh
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
#Copyright (C) 2022 Canonical, Ltd.
|
||||||
|
#
|
||||||
|
#This program is free software; you can redistribute it and/or
|
||||||
|
#modify it under the terms of the GNU General Public License as
|
||||||
|
#published by the Free Software Foundation, version 2 of the
|
||||||
|
#License.
|
||||||
|
|
||||||
|
#=NAME posix_mq
|
||||||
|
#=DESCRIPTION
|
||||||
|
# This test verifies if mediation of posix message queues is working
|
||||||
|
#=END
|
||||||
|
|
||||||
|
pwd=`dirname $0`
|
||||||
|
pwd=`cd $pwd ; /bin/pwd`
|
||||||
|
|
||||||
|
bin=$pwd
|
||||||
|
|
||||||
|
. $bin/prologue.inc
|
||||||
|
|
||||||
|
#requires_kernel_features network_v8/finegrained
|
||||||
|
requires_parser_support "network ip=::1,"
|
||||||
|
|
||||||
|
settest net_finegrained_rcv
|
||||||
|
|
||||||
|
sender="$bin/net_finegrained_snd"
|
||||||
|
receiver="$bin/net_finegrained_rcv"
|
||||||
|
|
||||||
|
# local ipv6 address generated according to https://www.rfc-editor.org/rfc/rfc4193.html
|
||||||
|
#ipv6_subnet=fd74:1820:b03a:b361::/64
|
||||||
|
bind_ipv6=fd74:1820:b03a:b361::cf32
|
||||||
|
remote_ipv6=fd74:1820:b03a:b361::a0f9
|
||||||
|
|
||||||
|
bind_ipv4=127.0.97.3
|
||||||
|
remote_ipv4=127.187.243.54
|
||||||
|
|
||||||
|
ip -6 addr add $bind_ipv6 dev lo || true
|
||||||
|
ip -6 addr add $remote_ipv6 dev lo || true
|
||||||
|
|
||||||
|
cleanup()
|
||||||
|
{
|
||||||
|
ip -6 addr del $bind_ipv6 dev lo || true
|
||||||
|
ip -6 addr del $remote_ipv6 dev lo || true
|
||||||
|
}
|
||||||
|
|
||||||
|
do_onexit="cleanup"
|
||||||
|
|
||||||
|
do_test()
|
||||||
|
{
|
||||||
|
local desc="FINEGRAINED NETWORK ($1)"
|
||||||
|
shift
|
||||||
|
runchecktest "$desc" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
do_tests()
|
||||||
|
{
|
||||||
|
prefix="$1"
|
||||||
|
expect_rcv=$2
|
||||||
|
expect_snd=$3
|
||||||
|
bind_ip=$4
|
||||||
|
bind_port=$5
|
||||||
|
remote_ip=$6
|
||||||
|
remote_port=$7
|
||||||
|
protocol=$8
|
||||||
|
generate_profile=$9
|
||||||
|
|
||||||
|
settest net_finegrained_rcv
|
||||||
|
$generate_profile
|
||||||
|
do_test "$prefix - root" $expect_rcv --bind_ip $bind_ip --bind_port $bind_port --remote_ip $remote_ip --remote_port $remote_port --protocol $protocol --timeout 5 --sender $sender
|
||||||
|
|
||||||
|
|
||||||
|
settest -u "foo" net_finegrained_rcv
|
||||||
|
$generate_profile
|
||||||
|
do_test "$prefix - user" $expect_rcv --bind_ip $bind_ip --bind_port $bind_port --remote_ip $remote_ip --remote_port $remote_port --protocol $protocol --timeout 5 --sender $sender
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bind_port=3456
|
||||||
|
while lsof -i:$bind_port >/dev/null; do
|
||||||
|
let bind_port=$bind_port+1
|
||||||
|
done
|
||||||
|
|
||||||
|
let remote_port=$bind_port+1
|
||||||
|
while lsof -i:$remote_port >/dev/null; do
|
||||||
|
let remote_port=$remote_port+1
|
||||||
|
done
|
||||||
|
|
||||||
|
generate_profile=""
|
||||||
|
do_tests "ipv4 udp unconfined" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port udp "$generate_profile"
|
||||||
|
do_tests "ipv4 tcp unconfined" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port tcp "$generate_profile"
|
||||||
|
|
||||||
|
generate_profile="genprofile network $sender:px -- image=$sender network"
|
||||||
|
do_tests "ipv4 udp no conds" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port udp "$generate_profile"
|
||||||
|
|
||||||
|
generate_profile="genprofile network $sender:px -- image=$sender network"
|
||||||
|
do_tests "ipv4 tcp no conds" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port tcp "$generate_profile"
|
||||||
|
|
||||||
|
generate_profile="genprofile network;ip=$bind_ipv4;port=$bind_port;peer=(ip=$remote_ipv4,port=$remote_port) $sender:px -- image=$sender network;ip=$remote_ipv4;port=$remote_port;peer=(ip=$bind_ipv4,port=$bind_port)"
|
||||||
|
do_tests "ipv4 udp generic perms" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port udp "$generate_profile"
|
||||||
|
|
||||||
|
generate_profile="genprofile network;ip=$bind_ipv4;port=$bind_port;peer=(ip=$remote_ipv4,port=$remote_port) $sender:px -- image=$sender network;ip=$remote_ipv4;port=$remote_port;peer=(ip=$bind_ipv4,port=$bind_port)"
|
||||||
|
do_tests "ipv4 tcp generic perms" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port tcp "$generate_profile"
|
||||||
|
|
||||||
|
generate_profile="genprofile network;(connect,receive,send);ip=$bind_ipv4;port=$bind_port;peer=(ip=$remote_ipv4,port=$remote_port) $sender:px -- image=$sender network;ip=$remote_ipv4;port=$remote_port;peer=(ip=$bind_ipv4,port=$bind_port)"
|
||||||
|
do_tests "ipv4 udp specific perms" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port udp "$generate_profile"
|
||||||
|
|
||||||
|
generate_profile="genprofile network;(connect,receive,send);ip=$bind_ipv4;port=$bind_port;peer=(ip=$remote_ipv4,port=$remote_port) $sender:px -- image=$sender network;ip=$remote_ipv4;port=$remote_port;peer=(ip=$bind_ipv4,port=$bind_port)"
|
||||||
|
do_tests "ipv4 tcp specific perms" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port tcp "$generate_profile"
|
||||||
|
|
||||||
|
removeprofile
|
||||||
|
# ipv6 tests
|
||||||
|
|
||||||
|
generate_profile=""
|
||||||
|
do_tests "ipv6 udp unconfined" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remote_port udp "$generate_profile"
|
||||||
|
do_tests "ipv6 tcp unconfined" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remote_port tcp "$generate_profile"
|
||||||
|
|
||||||
|
generate_profile="genprofile network $sender:px -- image=$sender network"
|
||||||
|
do_tests "ipv6 udp no conds" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remote_port udp "$generate_profile"
|
||||||
|
|
||||||
|
generate_profile="genprofile network $sender:px -- image=$sender network"
|
||||||
|
do_tests "ipv6 tcp no conds" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remote_port tcp "$generate_profile"
|
||||||
|
|
||||||
|
generate_profile="genprofile network;ip=$bind_ipv6;port=$bind_port;peer=(ip=$remote_ipv6,port=$remote_port) $sender:px -- image=$sender network;ip=$remote_ipv6;port=$remote_port;peer=(ip=$bind_ipv6,port=$bind_port)"
|
||||||
|
do_tests "ipv6 udp generic perms" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remote_port udp "$generate_profile"
|
||||||
|
|
||||||
|
generate_profile="genprofile network;ip=$bind_ipv6;port=$bind_port;peer=(ip=$remote_ipv6,port=$remote_port) $sender:px -- image=$sender network;ip=$remote_ipv6;port=$remote_port;peer=(ip=$bind_ipv6,port=$bind_port)"
|
||||||
|
do_tests "ipv6 tcp generic perms" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remote_port tcp "$generate_profile"
|
||||||
|
|
||||||
|
|
378
tests/regression/apparmor/net_finegrained_rcv.c
Normal file
378
tests/regression/apparmor/net_finegrained_rcv.c
Normal file
@@ -0,0 +1,378 @@
|
|||||||
|
#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>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include "net_finegrained.h"
|
||||||
|
|
||||||
|
struct connection_info {
|
||||||
|
char *bind_ip;
|
||||||
|
char *bind_port;
|
||||||
|
char *remote_ip;
|
||||||
|
char *remote_port;
|
||||||
|
char *protocol;
|
||||||
|
int timeout;
|
||||||
|
} net_info;
|
||||||
|
|
||||||
|
|
||||||
|
int receive_udp()
|
||||||
|
{
|
||||||
|
|
||||||
|
int sock;
|
||||||
|
char *buf;
|
||||||
|
struct sockaddr_in local;
|
||||||
|
struct sockaddr_in6 local6;
|
||||||
|
int ret = -1;
|
||||||
|
int select_return;
|
||||||
|
|
||||||
|
fd_set read_set, err_set;
|
||||||
|
struct timeval timeout;
|
||||||
|
|
||||||
|
buf = (char *) malloc(255);
|
||||||
|
memset(buf, '\0', 255);
|
||||||
|
|
||||||
|
struct ip_address bind_addr;
|
||||||
|
if (!parse_ip(net_info.bind_ip, net_info.bind_port, &bind_addr)) {
|
||||||
|
fprintf(stderr, "FAIL - could not parse bind ip address\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((sock = socket(bind_addr.family, SOCK_DGRAM, 0)) < 0) {
|
||||||
|
perror("FAIL - Socket error: ");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int enable = 1;
|
||||||
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &enable, sizeof(int)) < 0)
|
||||||
|
perror("FAIL - setsockopt(SO_REUSEADDR) failed");
|
||||||
|
|
||||||
|
if (bind_addr.family == AF_INET) {
|
||||||
|
local = convert_to_sockaddr_in(bind_addr);
|
||||||
|
if (bind(sock, (struct sockaddr *) &local, sizeof(local)) < 0)
|
||||||
|
{
|
||||||
|
perror("FAIL - Bind error: ");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
local6 = convert_to_sockaddr_in6(bind_addr);
|
||||||
|
if (bind(sock, (struct sockaddr *) &local6, sizeof(local6)) < 0)
|
||||||
|
{
|
||||||
|
printf("errno %d\n", errno);
|
||||||
|
perror("FAIL - 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 = net_info.timeout;
|
||||||
|
timeout.tv_usec = 0;
|
||||||
|
|
||||||
|
select_return = select(sock + 1, &read_set, NULL, &err_set, &timeout);
|
||||||
|
if (select_return < 0)
|
||||||
|
{
|
||||||
|
perror("FAIL - 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, (unsigned int *)0) >= 1)
|
||||||
|
{
|
||||||
|
//printf("MESSAGE: %s\n", buf);
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("FAIL - recvfrom failed\n");
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(buf);
|
||||||
|
return(ret);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int receive_tcp()
|
||||||
|
{
|
||||||
|
int sock, cli_sock;
|
||||||
|
char *buf;
|
||||||
|
struct sockaddr_in local;
|
||||||
|
struct sockaddr_in6 local6;
|
||||||
|
int ret = -1;
|
||||||
|
int select_return;
|
||||||
|
|
||||||
|
fd_set read_set, err_set;
|
||||||
|
struct timeval timeout;
|
||||||
|
|
||||||
|
buf = (char *) malloc(255);
|
||||||
|
memset(buf, '\0', 255);
|
||||||
|
|
||||||
|
struct ip_address bind_addr;
|
||||||
|
if (!parse_ip(net_info.bind_ip, net_info.bind_port, &bind_addr)) {
|
||||||
|
fprintf(stderr, "FAIL - could not parse bind ip address\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((sock = socket(bind_addr.family, SOCK_STREAM, 0)) < 0)
|
||||||
|
{
|
||||||
|
perror("FAIL - Socket error:");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int enable = 1;
|
||||||
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &enable, sizeof(int)) < 0)
|
||||||
|
perror("FAIL - setsockopt(SO_REUSEADDR) failed");
|
||||||
|
|
||||||
|
if (bind_addr.family == AF_INET) {
|
||||||
|
local = convert_to_sockaddr_in(bind_addr);
|
||||||
|
if (bind(sock, (struct sockaddr *) &local, sizeof(local)) < 0)
|
||||||
|
{
|
||||||
|
perror("FAIL - Bind error: ");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
local6 = convert_to_sockaddr_in6(bind_addr);
|
||||||
|
if (bind(sock, (struct sockaddr *) &local6, sizeof(local6)) < 0)
|
||||||
|
{
|
||||||
|
perror("FAIL - Bind error: ");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(sock, 5) == -1)
|
||||||
|
{
|
||||||
|
perror("FAIL - 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 = net_info.timeout;
|
||||||
|
timeout.tv_usec = 0;
|
||||||
|
|
||||||
|
select_return = select(sock + 1, &read_set, NULL, &err_set, &timeout);
|
||||||
|
if (select_return < 0)
|
||||||
|
{
|
||||||
|
perror("FAIL - 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("FAIL - Accept failed: ");
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (recv(cli_sock, buf, 255, 0) >= 1)
|
||||||
|
{
|
||||||
|
//printf("MESSAGE: %s\n", buf);
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
perror("FAIL - recv failure: ");
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
perror("FAIL - There were select failures: ");
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
free(buf);
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int receive_icmp()
|
||||||
|
{
|
||||||
|
|
||||||
|
int sock;
|
||||||
|
char *buf;
|
||||||
|
struct sockaddr_in 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, IPPROTO_ICMP)) < 0)
|
||||||
|
{
|
||||||
|
perror("FAIL - Socket error: ");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int enable = 1;
|
||||||
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &enable, sizeof(int)) < 0)
|
||||||
|
perror("FAIL - setsockopt(SO_REUSEADDR) failed");
|
||||||
|
|
||||||
|
local.sin_family = AF_INET;
|
||||||
|
local.sin_port = htons(atoi(net_info.bind_port));
|
||||||
|
inet_aton(net_info.bind_ip, &local.sin_addr);
|
||||||
|
|
||||||
|
if (bind(sock, (struct sockaddr *) &local, sizeof(local)) < 0)
|
||||||
|
{
|
||||||
|
perror("FAIL - 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 = net_info.timeout;
|
||||||
|
timeout.tv_usec = 0;
|
||||||
|
|
||||||
|
select_return = select(sock + 1, &read_set, NULL, &err_set, &timeout);
|
||||||
|
if (select_return < 0)
|
||||||
|
{
|
||||||
|
perror("FAIL - 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, (unsigned int *)0) >= 1)
|
||||||
|
{
|
||||||
|
//printf("MESSAGE: %s\n", buf);
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("FAIL - recvfrom failed\n");
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(buf);
|
||||||
|
return(ret);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usage(char *prog_name, char *msg)
|
||||||
|
{
|
||||||
|
if (msg != NULL)
|
||||||
|
fprintf(stderr, "%s\n", msg);
|
||||||
|
|
||||||
|
fprintf(stderr, "Usage: %s [options]\n", prog_name);
|
||||||
|
fprintf(stderr, "Options are:\n");
|
||||||
|
fprintf(stderr, "--bind_ip local ip address\n");
|
||||||
|
fprintf(stderr, "--bind_port local port\n");
|
||||||
|
fprintf(stderr, "--remote_ip remote ip address\n");
|
||||||
|
fprintf(stderr, "--remote_port remote port\n");
|
||||||
|
fprintf(stderr, "--protocol protocol: udp or tcp\n");
|
||||||
|
fprintf(stderr, "--sender path of the sender\n");
|
||||||
|
fprintf(stderr, "--timeout timeout in seconds\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int opt = 0;
|
||||||
|
int pid, ret = -1;
|
||||||
|
char *sender;
|
||||||
|
|
||||||
|
static struct option long_options[] = {
|
||||||
|
{"bind_ip", required_argument, 0, 'i' },
|
||||||
|
{"bind_port", required_argument, 0, 'o' },
|
||||||
|
{"remote_ip", required_argument, 0, 'r' },
|
||||||
|
{"remote_port", required_argument, 0, 'e' },
|
||||||
|
{"protocol", required_argument, 0, 'p' },
|
||||||
|
{"timeout", required_argument, 0, 't' },
|
||||||
|
{"sender", required_argument, 0, 's' },
|
||||||
|
{0, 0, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
while ((opt = getopt_long(argc, argv,"i:o:r:e:p:t:s:", long_options, 0)) != -1) {
|
||||||
|
switch (opt) {
|
||||||
|
case 'i':
|
||||||
|
net_info.bind_ip = optarg;
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
net_info.bind_port = optarg;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
net_info.remote_ip = optarg;
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
net_info.remote_port = optarg;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
net_info.protocol = optarg;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
net_info.timeout = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
sender = optarg;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage(argv[0], "Unrecognized option\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* exec the sender */
|
||||||
|
pid = fork();
|
||||||
|
if (pid == -1) {
|
||||||
|
perror("FAIL - could not fork");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
} else if (!pid) {
|
||||||
|
if (sender == NULL) {
|
||||||
|
usage(argv[0], "sender not specified");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
/* execution of the main thread continues
|
||||||
|
* in case the sender will be manually executed
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
/* invert remote x local ips to sender */
|
||||||
|
execl(sender, sender, net_info.remote_ip, net_info.remote_port,
|
||||||
|
net_info.bind_ip, net_info.bind_port,
|
||||||
|
net_info.protocol, NULL);
|
||||||
|
printf("FAIL %d - execlp %s --bind_ip %s --bind_port %s "
|
||||||
|
"--remote_ip %s --remote_port %s --protocol %s - %m\n",
|
||||||
|
getuid(), sender, net_info.bind_ip, net_info.bind_port,
|
||||||
|
net_info.remote_ip, net_info.remote_port, net_info.protocol);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(net_info.protocol, "udp") == 0)
|
||||||
|
ret = receive_udp(net_info);
|
||||||
|
else if (strcmp(net_info.protocol, "tcp") == 0)
|
||||||
|
ret = receive_tcp(net_info);
|
||||||
|
else if (strcmp(net_info.protocol, "icmp") == 0)
|
||||||
|
ret = receive_icmp(net_info);
|
||||||
|
else
|
||||||
|
printf("FAIL - Unknown protocol.\n");
|
||||||
|
|
||||||
|
if (ret == -1)
|
||||||
|
{
|
||||||
|
printf("FAIL - Receive message failed.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("PASS\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
263
tests/regression/apparmor/net_finegrained_snd.c
Normal file
263
tests/regression/apparmor/net_finegrained_snd.c
Normal file
@@ -0,0 +1,263 @@
|
|||||||
|
/* 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 <arpa/inet.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/ip_icmp.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "net_finegrained.h"
|
||||||
|
|
||||||
|
struct connection_info {
|
||||||
|
char *bind_ip;
|
||||||
|
char *bind_port;
|
||||||
|
char *remote_ip;
|
||||||
|
char *remote_port;
|
||||||
|
char *protocol;
|
||||||
|
} net_info;
|
||||||
|
|
||||||
|
int send_udp(char *message)
|
||||||
|
{
|
||||||
|
int sock;
|
||||||
|
struct sockaddr_in remote, local;
|
||||||
|
struct sockaddr_in6 remote6, local6;
|
||||||
|
|
||||||
|
struct ip_address bind_addr;
|
||||||
|
if (!parse_ip(net_info.bind_ip, net_info.bind_port, &bind_addr)) {
|
||||||
|
fprintf(stderr, "FAIL SND - could not parse bind ip address\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ip_address remote_addr;
|
||||||
|
if (!parse_ip(net_info.remote_ip, net_info.remote_port, &remote_addr)) {
|
||||||
|
fprintf(stderr, "FAIL SND - could not parse remote ip address\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((sock = socket(bind_addr.family, SOCK_DGRAM, 0)) < 0)
|
||||||
|
{
|
||||||
|
perror("FAIL SND - Could not open socket: ");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int enable = 1;
|
||||||
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &enable, sizeof(int)) < 0)
|
||||||
|
perror("FAIL SND - setsockopt(SO_REUSEADDR) failed");
|
||||||
|
|
||||||
|
|
||||||
|
if (bind_addr.family == AF_INET) {
|
||||||
|
local = convert_to_sockaddr_in(bind_addr);
|
||||||
|
if (bind(sock, (struct sockaddr *) &local, sizeof(local)) < 0)
|
||||||
|
{
|
||||||
|
perror("FAIL SND - Bind error: ");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
local6 = convert_to_sockaddr_in6(bind_addr);
|
||||||
|
if (bind(sock, (struct sockaddr *) &local6, sizeof(local6)) < 0)
|
||||||
|
{
|
||||||
|
perror("FAIL SND - Bind error: ");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remote_addr.family == AF_INET) {
|
||||||
|
remote = convert_to_sockaddr_in(remote_addr);
|
||||||
|
//printf("Sending \"%s\"\n", message);
|
||||||
|
if (sendto(sock, message, strlen(message), 0, (struct sockaddr *) &remote, sizeof(remote)) <= 0)
|
||||||
|
{
|
||||||
|
perror("FAIL SND - Send failed: ");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
remote6 = convert_to_sockaddr_in6(remote_addr);
|
||||||
|
//printf("Sending \"%s\"\n", message);
|
||||||
|
if (sendto(sock, message, strlen(message), 0, (struct sockaddr *) &remote6, sizeof(remote6)) <= 0)
|
||||||
|
{
|
||||||
|
perror("FAIL SND - Send failed: ");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
close(sock);
|
||||||
|
return(0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int send_tcp(char *message)
|
||||||
|
{
|
||||||
|
int sock;
|
||||||
|
struct sockaddr_in remote, local;
|
||||||
|
struct sockaddr_in6 remote6, local6;
|
||||||
|
|
||||||
|
struct ip_address bind_addr;
|
||||||
|
if (!parse_ip(net_info.bind_ip, net_info.bind_port, &bind_addr)) {
|
||||||
|
fprintf(stderr, "FAIL SND - could not parse bind ip address\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ip_address remote_addr;
|
||||||
|
if (!parse_ip(net_info.remote_ip, net_info.remote_port, &remote_addr)) {
|
||||||
|
fprintf(stderr, "FAIL SND - could not parse remote ip address\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((sock = socket(bind_addr.family, SOCK_STREAM, 0)) < 0)
|
||||||
|
{
|
||||||
|
perror("FAIL SND - Could not open socket: ");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int enable = 1;
|
||||||
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &enable, sizeof(int)) < 0)
|
||||||
|
perror("FAIL SND - setsockopt(SO_REUSEADDR) failed");
|
||||||
|
|
||||||
|
if (bind_addr.family == AF_INET) {
|
||||||
|
local = convert_to_sockaddr_in(bind_addr);
|
||||||
|
if (bind(sock, (struct sockaddr *) &local, sizeof(local)) < 0)
|
||||||
|
{
|
||||||
|
perror("FAIL SND - Bind error: ");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
local6 = convert_to_sockaddr_in6(bind_addr);
|
||||||
|
if (bind(sock, (struct sockaddr *) &local6, sizeof(local6)) < 0)
|
||||||
|
{
|
||||||
|
perror("FAIL SND - Bind error: ");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remote_addr.family == AF_INET) {
|
||||||
|
remote = convert_to_sockaddr_in(remote_addr);
|
||||||
|
//printf("Sending \"%s\"\n", message);
|
||||||
|
if (connect(sock, (struct sockaddr *) &remote, sizeof(remote)) < 0)
|
||||||
|
{
|
||||||
|
perror("FAIL SND - Could not connect: ");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
remote6 = convert_to_sockaddr_in6(remote_addr);
|
||||||
|
//printf("Sending \"%s\"\n", message);
|
||||||
|
if (connect(sock, (struct sockaddr *) &remote6, sizeof(remote6)) < 0)
|
||||||
|
{
|
||||||
|
perror("FAIL SND - Could not connect: ");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//printf("Sending \"%s\"\n", message);
|
||||||
|
if (send(sock, message, strlen(message), 0) <= 0)
|
||||||
|
{
|
||||||
|
perror("FAIL SND - Send failed: ");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
close(sock);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int send_icmp(char *message)
|
||||||
|
{
|
||||||
|
int sock;
|
||||||
|
struct sockaddr_in remote, local;
|
||||||
|
struct icmphdr icmp_hdr;
|
||||||
|
char packetdata[sizeof(icmp_hdr) + 4];
|
||||||
|
|
||||||
|
|
||||||
|
if ((sock = socket(AF_INET | AF_INET6, SOCK_DGRAM, IPPROTO_ICMP)) < 0)
|
||||||
|
{
|
||||||
|
perror("FAIL SND - Could not open socket: ");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int enable = 1;
|
||||||
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &enable, sizeof(int)) < 0)
|
||||||
|
perror("FAIL SND - setsockopt(SO_REUSEADDR) failed");
|
||||||
|
|
||||||
|
remote.sin_family = AF_INET;
|
||||||
|
remote.sin_port = htons(atoi(net_info.remote_port));
|
||||||
|
inet_aton(net_info.remote_ip, &remote.sin_addr);
|
||||||
|
|
||||||
|
local.sin_family = AF_INET;
|
||||||
|
local.sin_port = htons(atoi(net_info.bind_port));
|
||||||
|
inet_aton(net_info.bind_ip, &local.sin_addr);
|
||||||
|
|
||||||
|
// Initialize the ICMP header
|
||||||
|
memset(&icmp_hdr, 0, sizeof(icmp_hdr));
|
||||||
|
icmp_hdr.type = ICMP_ECHO;
|
||||||
|
icmp_hdr.un.echo.id = 1234;
|
||||||
|
icmp_hdr.un.echo.sequence = 1;
|
||||||
|
|
||||||
|
// Initialize the packet data (header and payload)
|
||||||
|
memcpy(packetdata, &icmp_hdr, sizeof(icmp_hdr));
|
||||||
|
memcpy(packetdata + sizeof(icmp_hdr), message, strlen(message));
|
||||||
|
|
||||||
|
if (bind(sock, (struct sockaddr *) &local, sizeof(local)) < 0)
|
||||||
|
{
|
||||||
|
perror("FAIL SND - Could not bind: ");
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//printf("Sending \"%s\"\n", message);
|
||||||
|
|
||||||
|
// Send the packet
|
||||||
|
if(sendto(sock, packetdata, sizeof(packetdata), 0, (struct sockaddr*) &remote, sizeof(remote)) < 0)
|
||||||
|
{
|
||||||
|
perror("FAIL SND - Send failed: ");
|
||||||
|
close(sock);
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//printf("Sent \"%s\"\n", message);
|
||||||
|
|
||||||
|
/* if (send(sock, packetdata, strlen(packetdata), 0) <= 0) */
|
||||||
|
/* { */
|
||||||
|
/* perror("FAIL SND - Send failed: "); */
|
||||||
|
/* close(sock); */
|
||||||
|
/* return(-1); */
|
||||||
|
/* } */
|
||||||
|
close(sock);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int send_ret;
|
||||||
|
|
||||||
|
if (argc < 6)
|
||||||
|
{
|
||||||
|
printf("Usage: %s bind_ip bind_port remote_ip remote_port proto\n", argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
net_info.bind_ip = argv[1];
|
||||||
|
net_info.bind_port = argv[2];
|
||||||
|
net_info.remote_ip = argv[3];
|
||||||
|
net_info.remote_port = argv[4];
|
||||||
|
net_info.protocol = argv[5];
|
||||||
|
|
||||||
|
send_ret = -1;
|
||||||
|
if (strcmp(net_info.protocol, "udp") == 0)
|
||||||
|
send_ret = send_udp("test");
|
||||||
|
else if (strcmp(net_info.protocol, "tcp") == 0)
|
||||||
|
send_ret = send_tcp("test");
|
||||||
|
else if (strcmp(net_info.protocol, "icmp") == 0)
|
||||||
|
send_ret = send_icmp("test");
|
||||||
|
else
|
||||||
|
printf("FAIL SND - Unknown protocol.\n");
|
||||||
|
|
||||||
|
if (send_ret == -1)
|
||||||
|
{
|
||||||
|
printf("FAIL SND - Send message failed.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
Reference in New Issue
Block a user