mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-04 04:04:19 +00:00
selftests: netfilter: add reverse-clash resolution test case
Add test program that is sending UDP packets in both directions and check that packets arrive without source port modification. Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
parent
a4e6a1031e
commit
a57856c0bb
@ -13,6 +13,7 @@ TEST_PROGS += conntrack_ipip_mtu.sh
|
||||
TEST_PROGS += conntrack_tcp_unreplied.sh
|
||||
TEST_PROGS += conntrack_sctp_collision.sh
|
||||
TEST_PROGS += conntrack_vrf.sh
|
||||
TEST_PROGS += conntrack_reverse_clash.sh
|
||||
TEST_PROGS += ipvs.sh
|
||||
TEST_PROGS += nf_conntrack_packetdrill.sh
|
||||
TEST_PROGS += nf_nat_edemux.sh
|
||||
@ -36,6 +37,7 @@ TEST_GEN_PROGS = conntrack_dump_flush
|
||||
|
||||
TEST_GEN_FILES = audit_logread
|
||||
TEST_GEN_FILES += connect_close nf_queue
|
||||
TEST_GEN_FILES += conntrack_reverse_clash
|
||||
TEST_GEN_FILES += sctp_collision
|
||||
|
||||
include ../../lib.mk
|
||||
|
125
tools/testing/selftests/net/netfilter/conntrack_reverse_clash.c
Normal file
125
tools/testing/selftests/net/netfilter/conntrack_reverse_clash.c
Normal file
@ -0,0 +1,125 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Needs something like:
|
||||
*
|
||||
* iptables -t nat -A POSTROUTING -o nomatch -j MASQUERADE
|
||||
*
|
||||
* so NAT engine attaches a NAT null-binding to each connection.
|
||||
*
|
||||
* With unmodified kernels, child or parent will exit with
|
||||
* "Port number changed" error, even though no port translation
|
||||
* was requested.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#define LEN 512
|
||||
#define PORT 56789
|
||||
#define TEST_TIME 5
|
||||
|
||||
static void die(const char *e)
|
||||
{
|
||||
perror(e);
|
||||
exit(111);
|
||||
}
|
||||
|
||||
static void die_port(uint16_t got, uint16_t want)
|
||||
{
|
||||
fprintf(stderr, "Port number changed, wanted %d got %d\n", want, ntohs(got));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int udp_socket(void)
|
||||
{
|
||||
static const struct timeval tv = {
|
||||
.tv_sec = 1,
|
||||
};
|
||||
int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
|
||||
if (fd < 0)
|
||||
die("socket");
|
||||
|
||||
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
|
||||
return fd;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct sockaddr_in sa1 = {
|
||||
.sin_family = AF_INET,
|
||||
};
|
||||
struct sockaddr_in sa2 = {
|
||||
.sin_family = AF_INET,
|
||||
};
|
||||
int s1, s2, status;
|
||||
time_t end, now;
|
||||
socklen_t plen;
|
||||
char buf[LEN];
|
||||
bool child;
|
||||
|
||||
sa1.sin_port = htons(PORT);
|
||||
sa2.sin_port = htons(PORT + 1);
|
||||
|
||||
s1 = udp_socket();
|
||||
s2 = udp_socket();
|
||||
|
||||
inet_pton(AF_INET, "127.0.0.11", &sa1.sin_addr);
|
||||
inet_pton(AF_INET, "127.0.0.12", &sa2.sin_addr);
|
||||
|
||||
if (bind(s1, (struct sockaddr *)&sa1, sizeof(sa1)) < 0)
|
||||
die("bind 1");
|
||||
if (bind(s2, (struct sockaddr *)&sa2, sizeof(sa2)) < 0)
|
||||
die("bind 2");
|
||||
|
||||
child = fork() == 0;
|
||||
|
||||
now = time(NULL);
|
||||
end = now + TEST_TIME;
|
||||
|
||||
while (now < end) {
|
||||
struct sockaddr_in peer;
|
||||
socklen_t plen = sizeof(peer);
|
||||
|
||||
now = time(NULL);
|
||||
|
||||
if (child) {
|
||||
if (sendto(s1, buf, LEN, 0, (struct sockaddr *)&sa2, sizeof(sa2)) != LEN)
|
||||
continue;
|
||||
|
||||
if (recvfrom(s2, buf, LEN, 0, (struct sockaddr *)&peer, &plen) < 0)
|
||||
die("child recvfrom");
|
||||
|
||||
if (peer.sin_port != htons(PORT))
|
||||
die_port(peer.sin_port, PORT);
|
||||
} else {
|
||||
if (sendto(s2, buf, LEN, 0, (struct sockaddr *)&sa1, sizeof(sa1)) != LEN)
|
||||
continue;
|
||||
|
||||
if (recvfrom(s1, buf, LEN, 0, (struct sockaddr *)&peer, &plen) < 0)
|
||||
die("parent recvfrom");
|
||||
|
||||
if (peer.sin_port != htons((PORT + 1)))
|
||||
die_port(peer.sin_port, PORT + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (child)
|
||||
return 0;
|
||||
|
||||
wait(&status);
|
||||
|
||||
if (WIFEXITED(status))
|
||||
return WEXITSTATUS(status);
|
||||
|
||||
return 1;
|
||||
}
|
51
tools/testing/selftests/net/netfilter/conntrack_reverse_clash.sh
Executable file
51
tools/testing/selftests/net/netfilter/conntrack_reverse_clash.sh
Executable file
@ -0,0 +1,51 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
source lib.sh
|
||||
|
||||
cleanup()
|
||||
{
|
||||
cleanup_all_ns
|
||||
}
|
||||
|
||||
checktool "nft --version" "run test without nft"
|
||||
checktool "conntrack --version" "run test without conntrack"
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
setup_ns ns0
|
||||
|
||||
# make loopback connections get nat null bindings assigned
|
||||
ip netns exec "$ns0" nft -f - <<EOF
|
||||
table ip nat {
|
||||
chain POSTROUTING {
|
||||
type nat hook postrouting priority srcnat; policy accept;
|
||||
oifname "nomatch" counter packets 0 bytes 0 masquerade
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
do_flush()
|
||||
{
|
||||
local end
|
||||
local now
|
||||
|
||||
now=$(date +%s)
|
||||
end=$((now + 5))
|
||||
|
||||
while [ $now -lt $end ];do
|
||||
ip netns exec "$ns0" conntrack -F 2>/dev/null
|
||||
now=$(date +%s)
|
||||
done
|
||||
}
|
||||
|
||||
do_flush &
|
||||
|
||||
if ip netns exec "$ns0" ./conntrack_reverse_clash; then
|
||||
echo "PASS: No SNAT performed for null bindings"
|
||||
else
|
||||
echo "ERROR: SNAT performed without any matching snat rule"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
Loading…
Reference in New Issue
Block a user