Skip to content

Commit

Permalink
selftests: netfilter: Test nf_tables audit logging
Browse files Browse the repository at this point in the history
[ Upstream commit e8dbde5 ]

Compare NETFILTER_CFG type audit logs emitted from kernel upon ruleset
modifications against expected output.

Signed-off-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Stable-dep-of: 0d880dc ("netfilter: nf_tables: Deduplicate nft_register_obj audit logs")
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
Phil Sutter authored and gregkh committed Oct 10, 2023
1 parent 00d35e6 commit 82273f1
Show file tree
Hide file tree
Showing 5 changed files with 277 additions and 2 deletions.
1 change: 1 addition & 0 deletions tools/testing/selftests/netfilter/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
nf-queue
connect_close
audit_logread
4 changes: 2 additions & 2 deletions tools/testing/selftests/netfilter/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ TEST_PROGS := nft_trans_stress.sh nft_fib.sh nft_nat.sh bridge_brouter.sh \
nft_concat_range.sh nft_conntrack_helper.sh \
nft_queue.sh nft_meta.sh nf_nat_edemux.sh \
ipip-conntrack-mtu.sh conntrack_tcp_unreplied.sh \
conntrack_vrf.sh nft_synproxy.sh rpath.sh
conntrack_vrf.sh nft_synproxy.sh rpath.sh nft_audit.sh

HOSTPKG_CONFIG := pkg-config

CFLAGS += $(shell $(HOSTPKG_CONFIG) --cflags libmnl 2>/dev/null)
LDLIBS += $(shell $(HOSTPKG_CONFIG) --libs libmnl 2>/dev/null || echo -lmnl)

TEST_GEN_FILES = nf-queue connect_close
TEST_GEN_FILES = nf-queue connect_close audit_logread

include ../lib.mk
165 changes: 165 additions & 0 deletions tools/testing/selftests/netfilter/audit_logread.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
// SPDX-License-Identifier: GPL-2.0

#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <linux/audit.h>
#include <linux/netlink.h>

static int fd;

#define MAX_AUDIT_MESSAGE_LENGTH 8970
struct audit_message {
struct nlmsghdr nlh;
union {
struct audit_status s;
char data[MAX_AUDIT_MESSAGE_LENGTH];
} u;
};

int audit_recv(int fd, struct audit_message *rep)
{
struct sockaddr_nl addr;
socklen_t addrlen = sizeof(addr);
int ret;

do {
ret = recvfrom(fd, rep, sizeof(*rep), 0,
(struct sockaddr *)&addr, &addrlen);
} while (ret < 0 && errno == EINTR);

if (ret < 0 ||
addrlen != sizeof(addr) ||
addr.nl_pid != 0 ||
rep->nlh.nlmsg_type == NLMSG_ERROR) /* short-cut for now */
return -1;

return ret;
}

int audit_send(int fd, uint16_t type, uint32_t key, uint32_t val)
{
static int seq = 0;
struct audit_message msg = {
.nlh = {
.nlmsg_len = NLMSG_SPACE(sizeof(msg.u.s)),
.nlmsg_type = type,
.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
.nlmsg_seq = ++seq,
},
.u.s = {
.mask = key,
.enabled = key == AUDIT_STATUS_ENABLED ? val : 0,
.pid = key == AUDIT_STATUS_PID ? val : 0,
}
};
struct sockaddr_nl addr = {
.nl_family = AF_NETLINK,
};
int ret;

do {
ret = sendto(fd, &msg, msg.nlh.nlmsg_len, 0,
(struct sockaddr *)&addr, sizeof(addr));
} while (ret < 0 && errno == EINTR);

if (ret != (int)msg.nlh.nlmsg_len)
return -1;
return 0;
}

int audit_set(int fd, uint32_t key, uint32_t val)
{
struct audit_message rep = { 0 };
int ret;

ret = audit_send(fd, AUDIT_SET, key, val);
if (ret)
return ret;

ret = audit_recv(fd, &rep);
if (ret < 0)
return ret;
return 0;
}

int readlog(int fd)
{
struct audit_message rep = { 0 };
int ret = audit_recv(fd, &rep);
const char *sep = "";
char *k, *v;

if (ret < 0)
return ret;

if (rep.nlh.nlmsg_type != AUDIT_NETFILTER_CFG)
return 0;

/* skip the initial "audit(...): " part */
strtok(rep.u.data, " ");

while ((k = strtok(NULL, "="))) {
v = strtok(NULL, " ");

/* these vary and/or are uninteresting, ignore */
if (!strcmp(k, "pid") ||
!strcmp(k, "comm") ||
!strcmp(k, "subj"))
continue;

/* strip the varying sequence number */
if (!strcmp(k, "table"))
*strchrnul(v, ':') = '\0';

printf("%s%s=%s", sep, k, v);
sep = " ";
}
if (*sep) {
printf("\n");
fflush(stdout);
}
return 0;
}

void cleanup(int sig)
{
audit_set(fd, AUDIT_STATUS_ENABLED, 0);
close(fd);
if (sig)
exit(0);
}

int main(int argc, char **argv)
{
struct sigaction act = {
.sa_handler = cleanup,
};

fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_AUDIT);
if (fd < 0) {
perror("Can't open netlink socket");
return -1;
}

if (sigaction(SIGTERM, &act, NULL) < 0 ||
sigaction(SIGINT, &act, NULL) < 0) {
perror("Can't set signal handler");
close(fd);
return -1;
}

audit_set(fd, AUDIT_STATUS_ENABLED, 1);
audit_set(fd, AUDIT_STATUS_PID, getpid());

while (1)
readlog(fd);
}
1 change: 1 addition & 0 deletions tools/testing/selftests/netfilter/config
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ CONFIG_NFT_REDIR=m
CONFIG_NFT_MASQ=m
CONFIG_NFT_FLOW_OFFLOAD=m
CONFIG_NF_CT_NETLINK=m
CONFIG_AUDIT=y
108 changes: 108 additions & 0 deletions tools/testing/selftests/netfilter/nft_audit.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# Check that audit logs generated for nft commands are as expected.

SKIP_RC=4
RC=0

nft --version >/dev/null 2>&1 || {
echo "SKIP: missing nft tool"
exit $SKIP_RC
}

logfile=$(mktemp)
echo "logging into $logfile"
./audit_logread >"$logfile" &
logread_pid=$!
trap 'kill $logread_pid; rm -f $logfile' EXIT
exec 3<"$logfile"

do_test() { # (cmd, log)
echo -n "testing for cmd: $1 ... "
cat <&3 >/dev/null
$1 >/dev/null || exit 1
sleep 0.1
res=$(diff -a -u <(echo "$2") - <&3)
[ $? -eq 0 ] && { echo "OK"; return; }
echo "FAIL"
echo "$res"
((RC++))
}

nft flush ruleset

for table in t1 t2; do
do_test "nft add table $table" \
"table=$table family=2 entries=1 op=nft_register_table"

do_test "nft add chain $table c1" \
"table=$table family=2 entries=1 op=nft_register_chain"

do_test "nft add chain $table c2; add chain $table c3" \
"table=$table family=2 entries=2 op=nft_register_chain"

cmd="add rule $table c1 counter"

do_test "nft $cmd" \
"table=$table family=2 entries=1 op=nft_register_rule"

do_test "nft $cmd; $cmd" \
"table=$table family=2 entries=2 op=nft_register_rule"

cmd=""
sep=""
for chain in c2 c3; do
for i in {1..3}; do
cmd+="$sep add rule $table $chain counter"
sep=";"
done
done
do_test "nft $cmd" \
"table=$table family=2 entries=6 op=nft_register_rule"
done

do_test 'nft reset rules t1 c2' \
'table=t1 family=2 entries=3 op=nft_reset_rule'

do_test 'nft reset rules table t1' \
'table=t1 family=2 entries=3 op=nft_reset_rule
table=t1 family=2 entries=3 op=nft_reset_rule
table=t1 family=2 entries=3 op=nft_reset_rule'

do_test 'nft reset rules' \
'table=t1 family=2 entries=3 op=nft_reset_rule
table=t1 family=2 entries=3 op=nft_reset_rule
table=t1 family=2 entries=3 op=nft_reset_rule
table=t2 family=2 entries=3 op=nft_reset_rule
table=t2 family=2 entries=3 op=nft_reset_rule
table=t2 family=2 entries=3 op=nft_reset_rule'

for ((i = 0; i < 500; i++)); do
echo "add rule t2 c3 counter accept comment \"rule $i\""
done | do_test 'nft -f -' \
'table=t2 family=2 entries=500 op=nft_register_rule'

do_test 'nft reset rules t2 c3' \
'table=t2 family=2 entries=189 op=nft_reset_rule
table=t2 family=2 entries=188 op=nft_reset_rule
table=t2 family=2 entries=126 op=nft_reset_rule'

do_test 'nft reset rules t2' \
'table=t2 family=2 entries=3 op=nft_reset_rule
table=t2 family=2 entries=3 op=nft_reset_rule
table=t2 family=2 entries=186 op=nft_reset_rule
table=t2 family=2 entries=188 op=nft_reset_rule
table=t2 family=2 entries=129 op=nft_reset_rule'

do_test 'nft reset rules' \
'table=t1 family=2 entries=3 op=nft_reset_rule
table=t1 family=2 entries=3 op=nft_reset_rule
table=t1 family=2 entries=3 op=nft_reset_rule
table=t2 family=2 entries=3 op=nft_reset_rule
table=t2 family=2 entries=3 op=nft_reset_rule
table=t2 family=2 entries=180 op=nft_reset_rule
table=t2 family=2 entries=188 op=nft_reset_rule
table=t2 family=2 entries=135 op=nft_reset_rule'

exit $RC

0 comments on commit 82273f1

Please sign in to comment.