File Index
Files and directories
Sign in
FILE

udpclash.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/net/netfilter/udpclash.c C
  1// SPDX-License-Identifier: GPL-2.0
  2
  3/* Usage: ./udpclash <IP> <PORT>
  4 *
  5 * Emit THREAD_COUNT UDP packets sharing the same saddr:daddr pair.
  6 *
  7 * This mimics DNS resolver libraries that emit A and AAAA requests
  8 * in parallel.
  9 *
 10 * This exercises conntrack clash resolution logic added and later
 11 * refined in
 12 *
 13 *  71d8c47fc653 ("netfilter: conntrack: introduce clash resolution on insertion race")
 14 *  ed07d9a021df ("netfilter: nf_conntrack: resolve clash for matching conntracks")
 15 *  6a757c07e51f ("netfilter: conntrack: allow insertion of clashing entries")
 16 */
 17#include <stdio.h>
 18#include <string.h>
 19#include <stdlib.h>
 20#include <unistd.h>
 21#include <arpa/inet.h>
 22#include <sys/socket.h>
 23#include <pthread.h>
 24
 25#define THREAD_COUNT 128
 26
 27struct thread_args {
 28	const struct sockaddr_in *si_remote;
 29	int sockfd;
 30};
 31
 32static volatile int wait = 1;
 33
 34static void *thread_main(void *varg)
 35{
 36	const struct sockaddr_in *si_remote;
 37	const struct thread_args *args = varg;
 38	static const char msg[] = "foo";
 39
 40	si_remote = args->si_remote;
 41
 42	while (wait == 1)
 43		;
 44
 45	if (sendto(args->sockfd, msg, strlen(msg), MSG_NOSIGNAL,
 46		   (struct sockaddr *)si_remote, sizeof(*si_remote)) < 0)
 47		exit(111);
 48
 49	return varg;
 50}
 51
 52static int run_test(int fd, const struct sockaddr_in *si_remote)
 53{
 54	struct thread_args thread_args = {
 55		.si_remote = si_remote,
 56		.sockfd = fd,
 57	};
 58	pthread_t *tid = calloc(THREAD_COUNT, sizeof(pthread_t));
 59	unsigned int repl_count = 0, timeout = 0;
 60	int i;
 61
 62	if (!tid) {
 63		perror("calloc");
 64		return 1;
 65	}
 66
 67	for (i = 0; i < THREAD_COUNT; i++) {
 68		int err = pthread_create(&tid[i], NULL, &thread_main, &thread_args);
 69
 70		if (err != 0) {
 71			perror("pthread_create");
 72			exit(1);
 73		}
 74	}
 75
 76	wait = 0;
 77
 78	for (i = 0; i < THREAD_COUNT; i++)
 79		pthread_join(tid[i], NULL);
 80
 81	while (repl_count < THREAD_COUNT) {
 82		struct sockaddr_in si_repl;
 83		socklen_t si_repl_len = sizeof(si_repl);
 84		char repl[512];
 85		ssize_t ret;
 86
 87		ret = recvfrom(fd, repl, sizeof(repl), MSG_NOSIGNAL,
 88			       (struct sockaddr *) &si_repl, &si_repl_len);
 89		if (ret < 0) {
 90			if (timeout++ > 5000) {
 91				fputs("timed out while waiting for reply from thread\n", stderr);
 92				break;
 93			}
 94
 95			/* give reply time to pass though the stack */
 96			usleep(1000);
 97			continue;
 98		}
 99
100		if (si_repl_len != sizeof(*si_remote)) {
101			fprintf(stderr, "warning: reply has unexpected repl_len %d vs %d\n",
102				(int)si_repl_len, (int)sizeof(si_repl));
103		} else if (si_remote->sin_addr.s_addr != si_repl.sin_addr.s_addr ||
104			si_remote->sin_port != si_repl.sin_port) {
105			char a[64], b[64];
106
107			inet_ntop(AF_INET, &si_remote->sin_addr, a, sizeof(a));
108			inet_ntop(AF_INET, &si_repl.sin_addr, b, sizeof(b));
109
110			fprintf(stderr, "reply from wrong source: want %s:%d got %s:%d\n",
111				a, ntohs(si_remote->sin_port), b, ntohs(si_repl.sin_port));
112		}
113
114		repl_count++;
115	}
116
117	printf("got %d of %d replies\n", repl_count, THREAD_COUNT);
118
119	free(tid);
120
121	return repl_count == THREAD_COUNT ? 0 : 1;
122}
123
124int main(int argc, char *argv[])
125{
126	struct sockaddr_in si_local = {
127		.sin_family = AF_INET,
128	};
129	struct sockaddr_in si_remote = {
130		.sin_family = AF_INET,
131	};
132	int fd, ret;
133
134	if (argc < 3) {
135		fputs("Usage: send_udp <daddr> <dport>\n", stderr);
136		return 1;
137	}
138
139	si_remote.sin_port = htons(atoi(argv[2]));
140	si_remote.sin_addr.s_addr = inet_addr(argv[1]);
141
142	fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_UDP);
143	if (fd < 0) {
144		perror("socket");
145		return 1;
146	}
147
148	if (bind(fd, (struct sockaddr *)&si_local, sizeof(si_local)) < 0) {
149		perror("bind");
150		return 1;
151	}
152
153	ret = run_test(fd, &si_remote);
154
155	close(fd);
156
157	return ret;
158}
~/ Read-only file preview.