xref: /freebsd/tools/regression/netinet/ipdivert/ipdivert.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
17fcc404bSRobert Watson /*-
27fcc404bSRobert Watson  * Copyright (c) 2010-2011 Juniper Networks, Inc.
37fcc404bSRobert Watson  * All rights reserved.
47fcc404bSRobert Watson  *
57fcc404bSRobert Watson  * This software was developed by Robert N. M. Watson under contract
67fcc404bSRobert Watson  * to Juniper Networks, Inc.
77fcc404bSRobert Watson  *
87fcc404bSRobert Watson  * Redistribution and use in source and binary forms, with or without
97fcc404bSRobert Watson  * modification, are permitted provided that the following conditions
107fcc404bSRobert Watson  * are met:
117fcc404bSRobert Watson  * 1. Redistributions of source code must retain the above copyright
127fcc404bSRobert Watson  *    notice, this list of conditions and the following disclaimer.
137fcc404bSRobert Watson  * 2. Redistributions in binary form must reproduce the above copyright
147fcc404bSRobert Watson  *    notice, this list of conditions and the following disclaimer in the
157fcc404bSRobert Watson  *    documentation and/or other materials provided with the distribution.
167fcc404bSRobert Watson  *
177fcc404bSRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
187fcc404bSRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
197fcc404bSRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
207fcc404bSRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
217fcc404bSRobert Watson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
227fcc404bSRobert Watson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
237fcc404bSRobert Watson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
247fcc404bSRobert Watson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
257fcc404bSRobert Watson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
267fcc404bSRobert Watson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
277fcc404bSRobert Watson  * SUCH DAMAGE.
287fcc404bSRobert Watson  */
297fcc404bSRobert Watson 
307fcc404bSRobert Watson /*
317fcc404bSRobert Watson  * This is a test tool for IP divert sockets.  For the time being, it just
327fcc404bSRobert Watson  * exercise creation and binding of sockets, rather than their divert
337fcc404bSRobert Watson  * behaviour.  It would be highly desirable to broaden this test tool to
347fcc404bSRobert Watson  * include packet injection and diversion.
357fcc404bSRobert Watson  */
367fcc404bSRobert Watson 
377fcc404bSRobert Watson #include <sys/types.h>
387fcc404bSRobert Watson #include <sys/socket.h>
397fcc404bSRobert Watson 
407fcc404bSRobert Watson #include <netinet/in.h>
417fcc404bSRobert Watson 
427fcc404bSRobert Watson #include <err.h>
437fcc404bSRobert Watson #include <errno.h>
447fcc404bSRobert Watson #include <stdio.h>
457fcc404bSRobert Watson #include <stdlib.h>
467fcc404bSRobert Watson #include <string.h>
477fcc404bSRobert Watson #include <unistd.h>
487fcc404bSRobert Watson 
497fcc404bSRobert Watson static void
ok(const char * test)507fcc404bSRobert Watson ok(const char *test)
517fcc404bSRobert Watson {
527fcc404bSRobert Watson 
537fcc404bSRobert Watson 	fprintf(stderr, "%s: OK\n", test);
547fcc404bSRobert Watson }
557fcc404bSRobert Watson 
567fcc404bSRobert Watson static void
fail(const char * test,const char * note)577fcc404bSRobert Watson fail(const char *test, const char *note)
587fcc404bSRobert Watson {
597fcc404bSRobert Watson 
607fcc404bSRobert Watson 	fprintf(stderr, "%s - %s: FAIL (%s)\n", test, note, strerror(errno));
617fcc404bSRobert Watson 	exit(1);
627fcc404bSRobert Watson }
637fcc404bSRobert Watson 
647fcc404bSRobert Watson static void
failx(const char * test,const char * note)657fcc404bSRobert Watson failx(const char *test, const char *note)
667fcc404bSRobert Watson {
677fcc404bSRobert Watson 
687fcc404bSRobert Watson 	fprintf(stderr, "%s - %s: FAIL\n", test, note);
697fcc404bSRobert Watson 	exit(1);
707fcc404bSRobert Watson }
717fcc404bSRobert Watson 
727fcc404bSRobert Watson static int
ipdivert_create(const char * test)737fcc404bSRobert Watson ipdivert_create(const char *test)
747fcc404bSRobert Watson {
757fcc404bSRobert Watson 	int s;
767fcc404bSRobert Watson 
77*4627bc1eSGleb Smirnoff 	s = socket(PF_DIVERT, SOCK_RAW, 0);
787fcc404bSRobert Watson 	if (s < 0)
797fcc404bSRobert Watson 		fail(test, "socket");
807fcc404bSRobert Watson 	return (s);
817fcc404bSRobert Watson }
827fcc404bSRobert Watson 
837fcc404bSRobert Watson static void
ipdivert_close(const char * test,int s)847fcc404bSRobert Watson ipdivert_close(const char *test, int s)
857fcc404bSRobert Watson {
867fcc404bSRobert Watson 
877fcc404bSRobert Watson 	if (close(s) < 0)
887fcc404bSRobert Watson 		fail(test, "close");
897fcc404bSRobert Watson }
907fcc404bSRobert Watson 
917fcc404bSRobert Watson static void
ipdivert_bind(const char * test,int s,u_short port,int expect)927fcc404bSRobert Watson ipdivert_bind(const char *test, int s, u_short port, int expect)
937fcc404bSRobert Watson {
947fcc404bSRobert Watson 	struct sockaddr_in sin;
957fcc404bSRobert Watson 	int err;
967fcc404bSRobert Watson 
977fcc404bSRobert Watson 	bzero(&sin, sizeof(sin));
987fcc404bSRobert Watson 	sin.sin_family = AF_INET;
997fcc404bSRobert Watson 	sin.sin_addr.s_addr = htonl(INADDR_ANY);
1007fcc404bSRobert Watson 	sin.sin_port = htons(port);
1017fcc404bSRobert Watson 
1027fcc404bSRobert Watson 	err = bind(s, (struct sockaddr *)&sin, sizeof(sin));
1037fcc404bSRobert Watson 	if (err < 0) {
1047fcc404bSRobert Watson 		if (expect == 0)
1057fcc404bSRobert Watson 			fail(test, "bind");
1067fcc404bSRobert Watson 		if (errno != expect)
1077fcc404bSRobert Watson 			fail(test, "bind");
1087fcc404bSRobert Watson 	} else {
1097fcc404bSRobert Watson 		if (expect != 0)
1107fcc404bSRobert Watson 			failx(test, "bind");
1117fcc404bSRobert Watson 	}
1127fcc404bSRobert Watson }
1137fcc404bSRobert Watson 
1147fcc404bSRobert Watson int
main(int argc,char * argv[])1157fcc404bSRobert Watson main(int argc, char *argv[])
1167fcc404bSRobert Watson {
1177fcc404bSRobert Watson 	const char *test;
1187fcc404bSRobert Watson 	int s1, s2;
1197fcc404bSRobert Watson 
1207fcc404bSRobert Watson 	/*
1217fcc404bSRobert Watson 	 * First test: create and close an IP divert socket.
1227fcc404bSRobert Watson 	 */
1237fcc404bSRobert Watson 	test = "create_close";
1247fcc404bSRobert Watson 	s1 = ipdivert_create(test);
1257fcc404bSRobert Watson 	ipdivert_close(test, s1);
1267fcc404bSRobert Watson 	ok(test);
1277fcc404bSRobert Watson 
1287fcc404bSRobert Watson 	/*
1297fcc404bSRobert Watson 	 * Second test: create, bind, and close an IP divert socket.
1307fcc404bSRobert Watson 	 */
1317fcc404bSRobert Watson 	test = "create_bind_close";
1327fcc404bSRobert Watson 	s1 = ipdivert_create(test);
1337fcc404bSRobert Watson 	ipdivert_bind(test, s1, 1000, 0);
1347fcc404bSRobert Watson 	ipdivert_close(test, s1);
1357fcc404bSRobert Watson 	ok(test);
1367fcc404bSRobert Watson 
1377fcc404bSRobert Watson 	/*
1387fcc404bSRobert Watson 	 * Third test: create two sockets, bind to different ports, and close.
1397fcc404bSRobert Watson 	 * This should succeed due to non-conflict on the port numbers.
1407fcc404bSRobert Watson 	 */
1417fcc404bSRobert Watson 	test = "create2_bind2_close2";
1427fcc404bSRobert Watson 	s1 = ipdivert_create(test);
1437fcc404bSRobert Watson 	s2 = ipdivert_create(test);
1447fcc404bSRobert Watson 	ipdivert_bind(test, s1, 1000, 0);
1457fcc404bSRobert Watson 	ipdivert_bind(test, s2, 1001, 0);
1467fcc404bSRobert Watson 	ipdivert_close(test, s1);
1477fcc404bSRobert Watson 	ipdivert_close(test, s2);
1487fcc404bSRobert Watson 	ok(test);
1497fcc404bSRobert Watson 
1507fcc404bSRobert Watson 	/*
1517fcc404bSRobert Watson 	 * Fourth test: create two sockets, bind to the *same* port, and
1527fcc404bSRobert Watson 	 * close.  This should fail due to conflicting port numbers.
1537fcc404bSRobert Watson 	 */
1547fcc404bSRobert Watson 	test = "create2_bind2_conflict_close2";
1557fcc404bSRobert Watson 	s1 = ipdivert_create(test);
1567fcc404bSRobert Watson 	s2 = ipdivert_create(test);
1577fcc404bSRobert Watson 	ipdivert_bind(test, s1, 1000, 0);
1587fcc404bSRobert Watson 	ipdivert_bind(test, s2, 1000, EADDRINUSE);
1597fcc404bSRobert Watson 	ipdivert_close(test, s1);
1607fcc404bSRobert Watson 	ipdivert_close(test, s2);
1617fcc404bSRobert Watson 	ok(test);
1627fcc404bSRobert Watson 
1637fcc404bSRobert Watson 	return (0);
1647fcc404bSRobert Watson }
165