Loading tools/testing/selftests/netfilter/.gitignore +1 −0 Original line number Diff line number Diff line # SPDX-License-Identifier: GPL-2.0-only nf-queue connect_close audit_logread tools/testing/selftests/netfilter/Makefile +2 −2 Original line number Diff line number Diff line Loading @@ -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 tools/testing/selftests/netfilter/audit_logread.c 0 → 100644 +165 −0 Original line number Diff line number Diff line // 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); } tools/testing/selftests/netfilter/config +1 −0 Original line number Diff line number Diff line Loading @@ -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 tools/testing/selftests/netfilter/nft_audit.sh 0 → 100755 +108 −0 Original line number Diff line number Diff line #!/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 Loading
tools/testing/selftests/netfilter/.gitignore +1 −0 Original line number Diff line number Diff line # SPDX-License-Identifier: GPL-2.0-only nf-queue connect_close audit_logread
tools/testing/selftests/netfilter/Makefile +2 −2 Original line number Diff line number Diff line Loading @@ -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
tools/testing/selftests/netfilter/audit_logread.c 0 → 100644 +165 −0 Original line number Diff line number Diff line // 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); }
tools/testing/selftests/netfilter/config +1 −0 Original line number Diff line number Diff line Loading @@ -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
tools/testing/selftests/netfilter/nft_audit.sh 0 → 100755 +108 −0 Original line number Diff line number Diff line #!/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