xref: /freebsd-src/tests/sys/netpfil/common/divapp.c (revision b3e7d4b67ce653bcdd9ec671cfdcdfed58a0ea50)
19b86b272SIgor Ostapenko /*-
29b86b272SIgor Ostapenko  * SPDX-License-Identifier: BSD-2-Clause
39b86b272SIgor Ostapenko  *
49b86b272SIgor Ostapenko  * Copyright (c) 2023 Igor Ostapenko <pm@igoro.pro>
59b86b272SIgor Ostapenko  *
69b86b272SIgor Ostapenko  * Redistribution and use in source and binary forms, with or without
79b86b272SIgor Ostapenko  * modification, are permitted provided that the following conditions
89b86b272SIgor Ostapenko  * are met:
99b86b272SIgor Ostapenko  * 1. Redistributions of source code must retain the above copyright
109b86b272SIgor Ostapenko  *    notice, this list of conditions and the following disclaimer.
119b86b272SIgor Ostapenko  * 2. Redistributions in binary form must reproduce the above copyright
129b86b272SIgor Ostapenko  *    notice, this list of conditions and the following disclaimer in the
139b86b272SIgor Ostapenko  *    documentation and/or other materials provided with the distribution.
149b86b272SIgor Ostapenko  *
159b86b272SIgor Ostapenko  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
169b86b272SIgor Ostapenko  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
179b86b272SIgor Ostapenko  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
189b86b272SIgor Ostapenko  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
199b86b272SIgor Ostapenko  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
209b86b272SIgor Ostapenko  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
219b86b272SIgor Ostapenko  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
229b86b272SIgor Ostapenko  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
239b86b272SIgor Ostapenko  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
249b86b272SIgor Ostapenko  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
259b86b272SIgor Ostapenko  * SUCH DAMAGE.
269b86b272SIgor Ostapenko  */
279b86b272SIgor Ostapenko 
289b86b272SIgor Ostapenko /* Used by divert(4) related tests */
299b86b272SIgor Ostapenko 
309b86b272SIgor Ostapenko #include <errno.h>
319b86b272SIgor Ostapenko #include <stdlib.h>
329b86b272SIgor Ostapenko #include <stdbool.h>
339b86b272SIgor Ostapenko #include <err.h>
349b86b272SIgor Ostapenko #include <sysexits.h>
359b86b272SIgor Ostapenko #include <string.h>
369b86b272SIgor Ostapenko 
379b86b272SIgor Ostapenko #include <sys/types.h>
389b86b272SIgor Ostapenko #include <sys/socket.h>
399b86b272SIgor Ostapenko #include <netinet/in.h>
409b86b272SIgor Ostapenko #include <netinet/ip.h>
419b86b272SIgor Ostapenko 
429b86b272SIgor Ostapenko 
439b86b272SIgor Ostapenko struct context {
449b86b272SIgor Ostapenko 	unsigned short divert_port;
459b86b272SIgor Ostapenko 	bool divert_back;
469b86b272SIgor Ostapenko 
479b86b272SIgor Ostapenko 	int fd;
489b86b272SIgor Ostapenko 	struct sockaddr_in sin;
499b86b272SIgor Ostapenko 	socklen_t sin_len;
509b86b272SIgor Ostapenko 	char pkt[IP_MAXPACKET];
519b86b272SIgor Ostapenko 	ssize_t pkt_n;
529b86b272SIgor Ostapenko };
539b86b272SIgor Ostapenko 
549b86b272SIgor Ostapenko static void
559b86b272SIgor Ostapenko init(struct context *c)
569b86b272SIgor Ostapenko {
579b86b272SIgor Ostapenko 	c->fd = socket(PF_DIVERT, SOCK_RAW, 0);
589b86b272SIgor Ostapenko 	if (c->fd == -1)
599b86b272SIgor Ostapenko 		errx(EX_OSERR, "init: Cannot create divert socket.");
609b86b272SIgor Ostapenko 
619b86b272SIgor Ostapenko 	memset(&c->sin, 0, sizeof(c->sin));
629b86b272SIgor Ostapenko 	c->sin.sin_family = AF_INET;
639b86b272SIgor Ostapenko 	c->sin.sin_port = htons(c->divert_port);
649b86b272SIgor Ostapenko 	c->sin.sin_addr.s_addr = INADDR_ANY;
659b86b272SIgor Ostapenko 	c->sin_len = sizeof(struct sockaddr_in);
669b86b272SIgor Ostapenko 
679b86b272SIgor Ostapenko 	if (bind(c->fd, (struct sockaddr *) &c->sin, c->sin_len) != 0)
689b86b272SIgor Ostapenko 		errx(EX_OSERR, "init: Cannot bind divert socket.");
699b86b272SIgor Ostapenko }
709b86b272SIgor Ostapenko 
719b86b272SIgor Ostapenko static ssize_t
729b86b272SIgor Ostapenko recv_pkt(struct context *c)
739b86b272SIgor Ostapenko {
749b86b272SIgor Ostapenko 	fd_set readfds;
759b86b272SIgor Ostapenko 	struct timeval timeout;
769b86b272SIgor Ostapenko 	int s;
779b86b272SIgor Ostapenko 
789b86b272SIgor Ostapenko 	FD_ZERO(&readfds);
799b86b272SIgor Ostapenko 	FD_SET(c->fd, &readfds);
809b86b272SIgor Ostapenko 	timeout.tv_sec = 3;
819b86b272SIgor Ostapenko 	timeout.tv_usec = 0;
829b86b272SIgor Ostapenko 
839b86b272SIgor Ostapenko 	s = select(c->fd + 1, &readfds, 0, 0, &timeout);
849b86b272SIgor Ostapenko 	if (s == -1)
859b86b272SIgor Ostapenko 		errx(EX_IOERR, "recv_pkt: select() errors.");
86*b3e7d4b6SIgor Ostapenko 	if (s != 1) /* timeout */
87*b3e7d4b6SIgor Ostapenko 		return (-1);
889b86b272SIgor Ostapenko 
899b86b272SIgor Ostapenko 	c->pkt_n = recvfrom(c->fd, c->pkt, sizeof(c->pkt), 0,
909b86b272SIgor Ostapenko 	    (struct sockaddr *) &c->sin, &c->sin_len);
919b86b272SIgor Ostapenko 	if (c->pkt_n == -1)
929b86b272SIgor Ostapenko 		errx(EX_IOERR, "recv_pkt: recvfrom() errors.");
939b86b272SIgor Ostapenko 
949b86b272SIgor Ostapenko 	return (c->pkt_n);
959b86b272SIgor Ostapenko }
969b86b272SIgor Ostapenko 
979b86b272SIgor Ostapenko static void
989b86b272SIgor Ostapenko send_pkt(struct context *c)
999b86b272SIgor Ostapenko {
1009b86b272SIgor Ostapenko 	ssize_t n;
1019b86b272SIgor Ostapenko 
1029b86b272SIgor Ostapenko 	n = sendto(c->fd, c->pkt, c->pkt_n, 0,
1039b86b272SIgor Ostapenko 	    (struct sockaddr *) &c->sin, c->sin_len);
104*b3e7d4b6SIgor Ostapenko 	if (n == -1)
105*b3e7d4b6SIgor Ostapenko 		err(EX_IOERR, "send_pkt: sendto() errors");
1069b86b272SIgor Ostapenko 	if (n != c->pkt_n)
1079b86b272SIgor Ostapenko 		errx(EX_IOERR, "send_pkt: sendto() sent %zd of %zd bytes.",
1089b86b272SIgor Ostapenko 		    n, c->pkt_n);
1099b86b272SIgor Ostapenko }
1109b86b272SIgor Ostapenko 
1119b86b272SIgor Ostapenko int
1129b86b272SIgor Ostapenko main(int argc, char *argv[])
1139b86b272SIgor Ostapenko {
1149b86b272SIgor Ostapenko 	struct context c;
1159b86b272SIgor Ostapenko 	int npkt;
1169b86b272SIgor Ostapenko 
1179b86b272SIgor Ostapenko 	if (argc < 2)
1189b86b272SIgor Ostapenko 		errx(EX_USAGE,
1199b86b272SIgor Ostapenko 		    "Usage: %s <divert-port> [divert-back]", argv[0]);
1209b86b272SIgor Ostapenko 
1219b86b272SIgor Ostapenko 	memset(&c, 0, sizeof(struct context));
1229b86b272SIgor Ostapenko 
1239b86b272SIgor Ostapenko 	c.divert_port = (unsigned short) strtol(argv[1], NULL, 10);
1249b86b272SIgor Ostapenko 	if (c.divert_port == 0)
1259b86b272SIgor Ostapenko 		errx(EX_USAGE, "divert port is not defined.");
1269b86b272SIgor Ostapenko 
1279b86b272SIgor Ostapenko 	if (argc >= 3 && strcmp(argv[2], "divert-back") == 0)
1289b86b272SIgor Ostapenko 		c.divert_back = true;
1299b86b272SIgor Ostapenko 
1309b86b272SIgor Ostapenko 
1319b86b272SIgor Ostapenko 	init(&c);
1329b86b272SIgor Ostapenko 
1339b86b272SIgor Ostapenko 	npkt = 0;
1349b86b272SIgor Ostapenko 	while (recv_pkt(&c) > 0) {
1359b86b272SIgor Ostapenko 		if (c.divert_back)
1369b86b272SIgor Ostapenko 			send_pkt(&c);
1379b86b272SIgor Ostapenko 		npkt++;
1389b86b272SIgor Ostapenko 		if (npkt >= 10)
1399b86b272SIgor Ostapenko 			break;
1409b86b272SIgor Ostapenko 	}
1419b86b272SIgor Ostapenko 
1429b86b272SIgor Ostapenko 	if (npkt != 1)
1439b86b272SIgor Ostapenko 		errx(EXIT_FAILURE, "%d: npkt=%d.", c.divert_port, npkt);
1449b86b272SIgor Ostapenko 
145*b3e7d4b6SIgor Ostapenko 	return (EXIT_SUCCESS);
1469b86b272SIgor Ostapenko }
147