xref: /illumos-gate/usr/src/test/os-tests/tests/tcpsig/tcpsig.c (revision 54819d46b24e4252ba4cdbe22d8c419c16f0d396)
11edba515SAndy Fiddaman /*
21edba515SAndy Fiddaman  * This file and its contents are supplied under the terms of the
31edba515SAndy Fiddaman  * Common Development and Distribution License ("CDDL"), version 1.0.
41edba515SAndy Fiddaman  * You may only use this file in accordance with the terms of version
51edba515SAndy Fiddaman  * 1.0 of the CDDL.
61edba515SAndy Fiddaman  *
71edba515SAndy Fiddaman  * A full copy of the text of the CDDL should have accompanied this
81edba515SAndy Fiddaman  * source.  A copy of the CDDL is also available via the Internet at
91edba515SAndy Fiddaman  * http://www.illumos.org/license/CDDL.
101edba515SAndy Fiddaman  */
111edba515SAndy Fiddaman 
121edba515SAndy Fiddaman /*
131edba515SAndy Fiddaman  * Copyright 2024 Oxide Computer Company
141edba515SAndy Fiddaman  */
151edba515SAndy Fiddaman 
161edba515SAndy Fiddaman /*
171edba515SAndy Fiddaman  * Basic set of tests for TCP_MD5SIG. The main design of this is to spin up
181edba515SAndy Fiddaman  * connections on localhost that walk through different options and confirm
191edba515SAndy Fiddaman  * that traffic either flows or is dropped according to the configuration.
201edba515SAndy Fiddaman  */
211edba515SAndy Fiddaman 
221edba515SAndy Fiddaman #include <err.h>
231edba515SAndy Fiddaman #include <port.h>
241edba515SAndy Fiddaman #include <stdlib.h>
251edba515SAndy Fiddaman #include <sys/types.h>
261edba515SAndy Fiddaman #include <sys/socket.h>
271edba515SAndy Fiddaman #include <netinet/in.h>
281edba515SAndy Fiddaman #include <netinet/tcp.h>
291edba515SAndy Fiddaman #include <arpa/inet.h>
301edba515SAndy Fiddaman #include <sys/sysmacros.h>
311edba515SAndy Fiddaman #include <stdbool.h>
321edba515SAndy Fiddaman #include <unistd.h>
331edba515SAndy Fiddaman #include <string.h>
341edba515SAndy Fiddaman #include <errno.h>
351edba515SAndy Fiddaman #include <sys/debug.h>
361edba515SAndy Fiddaman 
371edba515SAndy Fiddaman static hrtime_t sock_to = MSEC2NSEC(100); /* ms in ns */
381edba515SAndy Fiddaman static const uint32_t msgdata = 0x7777;
391edba515SAndy Fiddaman 
401edba515SAndy Fiddaman /*
411edba515SAndy Fiddaman  * Port setup - see tcpsig_init
421edba515SAndy Fiddaman  */
431edba515SAndy Fiddaman 
441edba515SAndy Fiddaman /* No SAs are configured */
451edba515SAndy Fiddaman #define	PORT_NOSA	24134
461edba515SAndy Fiddaman /* SAs exist in both directions, and the authentication keys match */
471edba515SAndy Fiddaman #define	PORT_BIDIR	24135
481edba515SAndy Fiddaman /* SAs exist in both directions, but the authentication keys don't match */
491edba515SAndy Fiddaman #define	PORT_MISMATCH	24136
501edba515SAndy Fiddaman /* A single SA exists in the outbound direction, none for inbound */
511edba515SAndy Fiddaman #define	PORT_OBSA	24137
521edba515SAndy Fiddaman /* A single SA exists in the inbound direction, none for outbound */
531edba515SAndy Fiddaman #define	PORT_IBSA	24138
541edba515SAndy Fiddaman 
551edba515SAndy Fiddaman typedef enum {
561edba515SAndy Fiddaman 	TCPSIG_SENDRECV,
571edba515SAndy Fiddaman 	TCPSIG_NOCONNECT,
581edba515SAndy Fiddaman 	TCPSIG_CONNREFUSED,
591edba515SAndy Fiddaman 	TCPSIG_NODATA
601edba515SAndy Fiddaman } tcpsig_pass_t;
611edba515SAndy Fiddaman 
621edba515SAndy Fiddaman typedef struct {
631edba515SAndy Fiddaman 	const char		*tt_desc;
641edba515SAndy Fiddaman 	const int		tt_domain;
651edba515SAndy Fiddaman 	const uint16_t		tt_port;
661edba515SAndy Fiddaman 	const bool		tt_enable_src;
671edba515SAndy Fiddaman 	const bool		tt_enable_dst;
681edba515SAndy Fiddaman 	const tcpsig_pass_t	tt_pass;
691edba515SAndy Fiddaman } tcpsig_test_t;
701edba515SAndy Fiddaman 
711edba515SAndy Fiddaman static const tcpsig_test_t tcpsig_tests[] = {
721edba515SAndy Fiddaman 	/* Tests using the port that (hopefully) has no SAs configured */
731edba515SAndy Fiddaman 	{
741edba515SAndy Fiddaman 		.tt_desc = "IPv4 NOSA with MD5 enabled on both sides",
751edba515SAndy Fiddaman 		.tt_domain = PF_INET,
761edba515SAndy Fiddaman 		.tt_port = PORT_NOSA,
771edba515SAndy Fiddaman 		.tt_enable_src = true,
781edba515SAndy Fiddaman 		.tt_enable_dst = true,
791edba515SAndy Fiddaman 		.tt_pass = TCPSIG_CONNREFUSED
801edba515SAndy Fiddaman 	}, {
811edba515SAndy Fiddaman 		.tt_desc = "IPv4 NOSA with MD5 disabled on both sides",
821edba515SAndy Fiddaman 		.tt_domain = PF_INET,
831edba515SAndy Fiddaman 		.tt_port = PORT_NOSA,
841edba515SAndy Fiddaman 		.tt_enable_src = false,
851edba515SAndy Fiddaman 		.tt_enable_dst = false,
861edba515SAndy Fiddaman 		.tt_pass = TCPSIG_SENDRECV
871edba515SAndy Fiddaman 	}, {
881edba515SAndy Fiddaman 		.tt_desc = "IPv4 NOSA with MD5 enabled on src only",
891edba515SAndy Fiddaman 		.tt_domain = PF_INET,
901edba515SAndy Fiddaman 		.tt_port = PORT_NOSA,
911edba515SAndy Fiddaman 		.tt_enable_src = true,
921edba515SAndy Fiddaman 		.tt_enable_dst = false,
931edba515SAndy Fiddaman 		.tt_pass = TCPSIG_CONNREFUSED
941edba515SAndy Fiddaman 	}, {
951edba515SAndy Fiddaman 		.tt_desc = "IPv4 NOSA with MD5 enabled on dst only",
961edba515SAndy Fiddaman 		.tt_domain = PF_INET,
971edba515SAndy Fiddaman 		.tt_port = PORT_NOSA,
981edba515SAndy Fiddaman 		.tt_enable_src = false,
991edba515SAndy Fiddaman 		.tt_enable_dst = true,
100*54819d46SAndy Fiddaman 		.tt_pass = TCPSIG_SENDRECV
1011edba515SAndy Fiddaman 	},
1021edba515SAndy Fiddaman 	{
1031edba515SAndy Fiddaman 		.tt_desc = "IPv6 NOSA with MD5 enabled on both sides",
1041edba515SAndy Fiddaman 		.tt_domain = PF_INET6,
1051edba515SAndy Fiddaman 		.tt_port = PORT_NOSA,
1061edba515SAndy Fiddaman 		.tt_enable_src = true,
1071edba515SAndy Fiddaman 		.tt_enable_dst = true,
1081edba515SAndy Fiddaman 		.tt_pass = TCPSIG_CONNREFUSED
1091edba515SAndy Fiddaman 	}, {
1101edba515SAndy Fiddaman 		.tt_desc = "IPv6 NOSA with MD5 disabled on both sides",
1111edba515SAndy Fiddaman 		.tt_domain = PF_INET6,
1121edba515SAndy Fiddaman 		.tt_port = PORT_NOSA,
1131edba515SAndy Fiddaman 		.tt_enable_src = false,
1141edba515SAndy Fiddaman 		.tt_enable_dst = false,
1151edba515SAndy Fiddaman 		.tt_pass = TCPSIG_SENDRECV
1161edba515SAndy Fiddaman 	}, {
1171edba515SAndy Fiddaman 		.tt_desc = "IPv6 NOSA with MD5 enabled on src only",
1181edba515SAndy Fiddaman 		.tt_domain = PF_INET6,
1191edba515SAndy Fiddaman 		.tt_port = PORT_NOSA,
1201edba515SAndy Fiddaman 		.tt_enable_src = true,
1211edba515SAndy Fiddaman 		.tt_enable_dst = false,
1221edba515SAndy Fiddaman 		.tt_pass = TCPSIG_CONNREFUSED
1231edba515SAndy Fiddaman 	}, {
1241edba515SAndy Fiddaman 		.tt_desc = "IPv6 NOSA with MD5 enabled on dst only",
1251edba515SAndy Fiddaman 		.tt_domain = PF_INET6,
1261edba515SAndy Fiddaman 		.tt_port = PORT_NOSA,
1271edba515SAndy Fiddaman 		.tt_enable_src = false,
1281edba515SAndy Fiddaman 		.tt_enable_dst = true,
129*54819d46SAndy Fiddaman 		.tt_pass = TCPSIG_SENDRECV
1301edba515SAndy Fiddaman 	},
1311edba515SAndy Fiddaman 	/* Tests using the port that has bi-directional SAs configured */
1321edba515SAndy Fiddaman 	{
1331edba515SAndy Fiddaman 		.tt_desc = "IPv4 BIDIR with MD5 enabled on both sides",
1341edba515SAndy Fiddaman 		.tt_domain = PF_INET,
1351edba515SAndy Fiddaman 		.tt_port = PORT_BIDIR,
1361edba515SAndy Fiddaman 		.tt_enable_src = true,
1371edba515SAndy Fiddaman 		.tt_enable_dst = true,
1381edba515SAndy Fiddaman 		.tt_pass = TCPSIG_SENDRECV
1391edba515SAndy Fiddaman 	}, {
1401edba515SAndy Fiddaman 		.tt_desc = "IPv4 BIDIR with MD5 disabled on both sides",
1411edba515SAndy Fiddaman 		.tt_domain = PF_INET,
1421edba515SAndy Fiddaman 		.tt_port = PORT_BIDIR,
1431edba515SAndy Fiddaman 		.tt_enable_src = false,
1441edba515SAndy Fiddaman 		.tt_enable_dst = false,
1451edba515SAndy Fiddaman 		.tt_pass = TCPSIG_SENDRECV
1461edba515SAndy Fiddaman 	}, {
1471edba515SAndy Fiddaman 		.tt_desc = "IPv4 BIDIR with MD5 enabled on src only",
1481edba515SAndy Fiddaman 		.tt_domain = PF_INET,
1491edba515SAndy Fiddaman 		.tt_port = PORT_BIDIR,
1501edba515SAndy Fiddaman 		.tt_enable_src = true,
1511edba515SAndy Fiddaman 		.tt_enable_dst = false,
1521edba515SAndy Fiddaman 		.tt_pass = TCPSIG_NOCONNECT
1531edba515SAndy Fiddaman 	}, {
1541edba515SAndy Fiddaman 		.tt_desc = "IPv4 BIDIR with MD5 enabled on dst only",
1551edba515SAndy Fiddaman 		.tt_domain = PF_INET,
1561edba515SAndy Fiddaman 		.tt_port = PORT_BIDIR,
1571edba515SAndy Fiddaman 		.tt_enable_src = false,
1581edba515SAndy Fiddaman 		.tt_enable_dst = true,
1591edba515SAndy Fiddaman 		.tt_pass = TCPSIG_NOCONNECT
1601edba515SAndy Fiddaman 	}, {
1611edba515SAndy Fiddaman 		.tt_desc = "IPv6 BIDIR with MD5 enabled on both sides",
1621edba515SAndy Fiddaman 		.tt_domain = PF_INET6,
1631edba515SAndy Fiddaman 		.tt_port = PORT_BIDIR,
1641edba515SAndy Fiddaman 		.tt_enable_src = true,
1651edba515SAndy Fiddaman 		.tt_enable_dst = true,
1661edba515SAndy Fiddaman 		.tt_pass = TCPSIG_SENDRECV
1671edba515SAndy Fiddaman 	}, {
1681edba515SAndy Fiddaman 		.tt_desc = "IPv6 BIDIR with MD5 disabled on both sides",
1691edba515SAndy Fiddaman 		.tt_domain = PF_INET6,
1701edba515SAndy Fiddaman 		.tt_port = PORT_BIDIR,
1711edba515SAndy Fiddaman 		.tt_enable_src = false,
1721edba515SAndy Fiddaman 		.tt_enable_dst = false,
1731edba515SAndy Fiddaman 		.tt_pass = TCPSIG_SENDRECV
1741edba515SAndy Fiddaman 	}, {
1751edba515SAndy Fiddaman 		.tt_desc = "IPv6 BIDIR with MD5 enabled on src only",
1761edba515SAndy Fiddaman 		.tt_domain = PF_INET6,
1771edba515SAndy Fiddaman 		.tt_port = PORT_BIDIR,
1781edba515SAndy Fiddaman 		.tt_enable_src = true,
1791edba515SAndy Fiddaman 		.tt_enable_dst = false,
1801edba515SAndy Fiddaman 		.tt_pass = TCPSIG_NOCONNECT
1811edba515SAndy Fiddaman 	}, {
1821edba515SAndy Fiddaman 		.tt_desc = "IPv6 BIDIR with MD5 enabled on dst only",
1831edba515SAndy Fiddaman 		.tt_domain = PF_INET6,
1841edba515SAndy Fiddaman 		.tt_port = PORT_BIDIR,
1851edba515SAndy Fiddaman 		.tt_enable_src = false,
1861edba515SAndy Fiddaman 		.tt_enable_dst = true,
1871edba515SAndy Fiddaman 		.tt_pass = TCPSIG_NOCONNECT
1881edba515SAndy Fiddaman 	},
1891edba515SAndy Fiddaman 	/* Tests using the port with mismatching SA keys */
1901edba515SAndy Fiddaman 	{
1911edba515SAndy Fiddaman 		/*
1921edba515SAndy Fiddaman 		 * Both sides of the connection have access to the two
1931edba515SAndy Fiddaman 		 * SAs and will use the correct key depending on the direction
1941edba515SAndy Fiddaman 		 * of the traffic. We therefore expect this to succeed.
1951edba515SAndy Fiddaman 		 * `tcpdump -M` can be used to verify that a different key is
1961edba515SAndy Fiddaman 		 * being used in each direction.
1971edba515SAndy Fiddaman 		 */
1981edba515SAndy Fiddaman 		.tt_desc = "IPv4 MISMATCH with MD5 enabled on both sides",
1991edba515SAndy Fiddaman 		.tt_domain = PF_INET,
2001edba515SAndy Fiddaman 		.tt_port = PORT_MISMATCH,
2011edba515SAndy Fiddaman 		.tt_enable_src = true,
2021edba515SAndy Fiddaman 		.tt_enable_dst = true,
2031edba515SAndy Fiddaman 		.tt_pass = TCPSIG_SENDRECV
2041edba515SAndy Fiddaman 	}, {
2051edba515SAndy Fiddaman 		.tt_desc = "IPv4 MISMATCH with MD5 disabled on both sides",
2061edba515SAndy Fiddaman 		.tt_domain = PF_INET,
2071edba515SAndy Fiddaman 		.tt_port = PORT_MISMATCH,
2081edba515SAndy Fiddaman 		.tt_enable_src = false,
2091edba515SAndy Fiddaman 		.tt_enable_dst = false,
2101edba515SAndy Fiddaman 		.tt_pass = TCPSIG_SENDRECV
2111edba515SAndy Fiddaman 	}, {
2121edba515SAndy Fiddaman 		.tt_desc = "IPv4 MISMATCH with MD5 enabled on src only",
2131edba515SAndy Fiddaman 		.tt_domain = PF_INET,
2141edba515SAndy Fiddaman 		.tt_port = PORT_MISMATCH,
2151edba515SAndy Fiddaman 		.tt_enable_src = true,
2161edba515SAndy Fiddaman 		.tt_enable_dst = false,
2171edba515SAndy Fiddaman 		.tt_pass = TCPSIG_NOCONNECT
2181edba515SAndy Fiddaman 	}, {
2191edba515SAndy Fiddaman 		.tt_desc = "IPv4 MISMATCH with MD5 enabled on dst only",
2201edba515SAndy Fiddaman 		.tt_domain = PF_INET,
2211edba515SAndy Fiddaman 		.tt_port = PORT_MISMATCH,
2221edba515SAndy Fiddaman 		.tt_enable_src = false,
2231edba515SAndy Fiddaman 		.tt_enable_dst = true,
2241edba515SAndy Fiddaman 		.tt_pass = TCPSIG_NOCONNECT
2251edba515SAndy Fiddaman 	}, {
2261edba515SAndy Fiddaman 		.tt_desc = "IPv6 MISMATCH with MD5 enabled on both sides",
2271edba515SAndy Fiddaman 		.tt_domain = PF_INET6,
2281edba515SAndy Fiddaman 		.tt_port = PORT_MISMATCH,
2291edba515SAndy Fiddaman 		.tt_enable_src = true,
2301edba515SAndy Fiddaman 		.tt_enable_dst = true,
2311edba515SAndy Fiddaman 		.tt_pass = TCPSIG_SENDRECV
2321edba515SAndy Fiddaman 	}, {
2331edba515SAndy Fiddaman 		.tt_desc = "IPv6 MISMATCH with MD5 disabled on both sides",
2341edba515SAndy Fiddaman 		.tt_domain = PF_INET6,
2351edba515SAndy Fiddaman 		.tt_port = PORT_MISMATCH,
2361edba515SAndy Fiddaman 		.tt_enable_src = false,
2371edba515SAndy Fiddaman 		.tt_enable_dst = false,
2381edba515SAndy Fiddaman 		.tt_pass = TCPSIG_SENDRECV
2391edba515SAndy Fiddaman 	}, {
2401edba515SAndy Fiddaman 		.tt_desc = "IPv6 MISMATCH with MD5 enabled on src only",
2411edba515SAndy Fiddaman 		.tt_domain = PF_INET6,
2421edba515SAndy Fiddaman 		.tt_port = PORT_MISMATCH,
2431edba515SAndy Fiddaman 		.tt_enable_src = true,
2441edba515SAndy Fiddaman 		.tt_enable_dst = false,
2451edba515SAndy Fiddaman 		.tt_pass = TCPSIG_NOCONNECT
2461edba515SAndy Fiddaman 	}, {
2471edba515SAndy Fiddaman 		.tt_desc = "IPv6 MISMATCH with MD5 enabled on dst only",
2481edba515SAndy Fiddaman 		.tt_domain = PF_INET6,
2491edba515SAndy Fiddaman 		.tt_port = PORT_MISMATCH,
2501edba515SAndy Fiddaman 		.tt_enable_src = false,
2511edba515SAndy Fiddaman 		.tt_enable_dst = true,
2521edba515SAndy Fiddaman 		.tt_pass = TCPSIG_NOCONNECT
2531edba515SAndy Fiddaman 	},
2541edba515SAndy Fiddaman 	/* Tests using the port with only an outbound SA */
2551edba515SAndy Fiddaman 	{
2561edba515SAndy Fiddaman 		.tt_desc = "IPv4 OBSA with MD5 enabled on both sides",
2571edba515SAndy Fiddaman 		.tt_domain = PF_INET,
2581edba515SAndy Fiddaman 		.tt_port = PORT_OBSA,
2591edba515SAndy Fiddaman 		.tt_enable_src = true,
2601edba515SAndy Fiddaman 		.tt_enable_dst = true,
2611edba515SAndy Fiddaman 		.tt_pass = TCPSIG_NOCONNECT
2621edba515SAndy Fiddaman 	}, {
2631edba515SAndy Fiddaman 		.tt_desc = "IPv4 OBSA with MD5 disabled on both sides",
2641edba515SAndy Fiddaman 		.tt_domain = PF_INET,
2651edba515SAndy Fiddaman 		.tt_port = PORT_OBSA,
2661edba515SAndy Fiddaman 		.tt_enable_src = false,
2671edba515SAndy Fiddaman 		.tt_enable_dst = false,
2681edba515SAndy Fiddaman 		.tt_pass = TCPSIG_SENDRECV
2691edba515SAndy Fiddaman 	}, {
2701edba515SAndy Fiddaman 		.tt_desc = "IPv4 OBSA with MD5 enabled on src only",
2711edba515SAndy Fiddaman 		.tt_domain = PF_INET,
2721edba515SAndy Fiddaman 		.tt_port = PORT_OBSA,
2731edba515SAndy Fiddaman 		.tt_enable_src = true,
2741edba515SAndy Fiddaman 		.tt_enable_dst = false,
2751edba515SAndy Fiddaman 		.tt_pass = TCPSIG_NOCONNECT
2761edba515SAndy Fiddaman 	}, {
2771edba515SAndy Fiddaman 		.tt_desc = "IPv4 OBSA with MD5 enabled on dst only",
2781edba515SAndy Fiddaman 		.tt_domain = PF_INET,
2791edba515SAndy Fiddaman 		.tt_port = PORT_OBSA,
2801edba515SAndy Fiddaman 		.tt_enable_src = false,
2811edba515SAndy Fiddaman 		.tt_enable_dst = true,
2821edba515SAndy Fiddaman 		.tt_pass = TCPSIG_NOCONNECT
2831edba515SAndy Fiddaman 	}, {
2841edba515SAndy Fiddaman 		.tt_desc = "IPv6 OBSA with MD5 enabled on both sides",
2851edba515SAndy Fiddaman 		.tt_domain = PF_INET6,
2861edba515SAndy Fiddaman 		.tt_port = PORT_OBSA,
2871edba515SAndy Fiddaman 		.tt_enable_src = true,
2881edba515SAndy Fiddaman 		.tt_enable_dst = true,
2891edba515SAndy Fiddaman 		.tt_pass = TCPSIG_NOCONNECT
2901edba515SAndy Fiddaman 	}, {
2911edba515SAndy Fiddaman 		.tt_desc = "IPv6 OBSA with MD5 disabled on both sides",
2921edba515SAndy Fiddaman 		.tt_domain = PF_INET6,
2931edba515SAndy Fiddaman 		.tt_port = PORT_OBSA,
2941edba515SAndy Fiddaman 		.tt_enable_src = false,
2951edba515SAndy Fiddaman 		.tt_enable_dst = false,
2961edba515SAndy Fiddaman 		.tt_pass = TCPSIG_SENDRECV
2971edba515SAndy Fiddaman 	}, {
2981edba515SAndy Fiddaman 		.tt_desc = "IPv6 OBSA with MD5 enabled on src only",
2991edba515SAndy Fiddaman 		.tt_domain = PF_INET6,
3001edba515SAndy Fiddaman 		.tt_port = PORT_OBSA,
3011edba515SAndy Fiddaman 		.tt_enable_src = true,
3021edba515SAndy Fiddaman 		.tt_enable_dst = false,
3031edba515SAndy Fiddaman 		.tt_pass = TCPSIG_NOCONNECT
3041edba515SAndy Fiddaman 	}, {
3051edba515SAndy Fiddaman 		.tt_desc = "IPv6 OBSA with MD5 enabled on dst only",
3061edba515SAndy Fiddaman 		.tt_domain = PF_INET6,
3071edba515SAndy Fiddaman 		.tt_port = PORT_OBSA,
3081edba515SAndy Fiddaman 		.tt_enable_src = false,
3091edba515SAndy Fiddaman 		.tt_enable_dst = true,
3101edba515SAndy Fiddaman 		.tt_pass = TCPSIG_NOCONNECT
3111edba515SAndy Fiddaman 	},
3121edba515SAndy Fiddaman 	/* Tests using the port with only an inbound SA */
3131edba515SAndy Fiddaman 	{
3141edba515SAndy Fiddaman 		.tt_desc = "IPv4 IBSA with MD5 enabled on both sides",
3151edba515SAndy Fiddaman 		.tt_domain = PF_INET,
3161edba515SAndy Fiddaman 		.tt_port = PORT_IBSA,
3171edba515SAndy Fiddaman 		.tt_enable_src = true,
3181edba515SAndy Fiddaman 		.tt_enable_dst = true,
3191edba515SAndy Fiddaman 		.tt_pass = TCPSIG_CONNREFUSED
3201edba515SAndy Fiddaman 	}, {
3211edba515SAndy Fiddaman 		.tt_desc = "IPv4 IBSA with MD5 disabled on both sides",
3221edba515SAndy Fiddaman 		.tt_domain = PF_INET,
3231edba515SAndy Fiddaman 		.tt_port = PORT_IBSA,
3241edba515SAndy Fiddaman 		.tt_enable_src = false,
3251edba515SAndy Fiddaman 		.tt_enable_dst = false,
3261edba515SAndy Fiddaman 		.tt_pass = TCPSIG_SENDRECV
3271edba515SAndy Fiddaman 	}, {
3281edba515SAndy Fiddaman 		.tt_desc = "IPv4 IBSA with MD5 enabled on src only",
3291edba515SAndy Fiddaman 		.tt_domain = PF_INET,
3301edba515SAndy Fiddaman 		.tt_port = PORT_IBSA,
3311edba515SAndy Fiddaman 		.tt_enable_src = true,
3321edba515SAndy Fiddaman 		.tt_enable_dst = false,
3331edba515SAndy Fiddaman 		.tt_pass = TCPSIG_CONNREFUSED
3341edba515SAndy Fiddaman 	}, {
3351edba515SAndy Fiddaman 		.tt_desc = "IPv4 IBSA with MD5 enabled on dst only",
3361edba515SAndy Fiddaman 		.tt_domain = PF_INET,
3371edba515SAndy Fiddaman 		.tt_port = PORT_IBSA,
3381edba515SAndy Fiddaman 		.tt_enable_src = false,
3391edba515SAndy Fiddaman 		.tt_enable_dst = true,
340*54819d46SAndy Fiddaman 		.tt_pass = TCPSIG_SENDRECV
3411edba515SAndy Fiddaman 	}, {
3421edba515SAndy Fiddaman 		.tt_desc = "IPv6 IBSA with MD5 enabled on both sides",
3431edba515SAndy Fiddaman 		.tt_domain = PF_INET6,
3441edba515SAndy Fiddaman 		.tt_port = PORT_IBSA,
3451edba515SAndy Fiddaman 		.tt_enable_src = true,
3461edba515SAndy Fiddaman 		.tt_enable_dst = true,
3471edba515SAndy Fiddaman 		.tt_pass = TCPSIG_CONNREFUSED
3481edba515SAndy Fiddaman 	}, {
3491edba515SAndy Fiddaman 		.tt_desc = "IPv6 IBSA with MD5 disabled on both sides",
3501edba515SAndy Fiddaman 		.tt_domain = PF_INET6,
3511edba515SAndy Fiddaman 		.tt_port = PORT_IBSA,
3521edba515SAndy Fiddaman 		.tt_enable_src = false,
3531edba515SAndy Fiddaman 		.tt_enable_dst = false,
3541edba515SAndy Fiddaman 		.tt_pass = TCPSIG_SENDRECV
3551edba515SAndy Fiddaman 	}, {
3561edba515SAndy Fiddaman 		.tt_desc = "IPv6 IBSA with MD5 enabled on src only",
3571edba515SAndy Fiddaman 		.tt_domain = PF_INET6,
3581edba515SAndy Fiddaman 		.tt_port = PORT_IBSA,
3591edba515SAndy Fiddaman 		.tt_enable_src = true,
3601edba515SAndy Fiddaman 		.tt_enable_dst = false,
3611edba515SAndy Fiddaman 		.tt_pass = TCPSIG_CONNREFUSED
3621edba515SAndy Fiddaman 	}, {
3631edba515SAndy Fiddaman 		.tt_desc = "IPv6 IBSA with MD5 enabled on dst only",
3641edba515SAndy Fiddaman 		.tt_domain = PF_INET6,
3651edba515SAndy Fiddaman 		.tt_port = PORT_IBSA,
3661edba515SAndy Fiddaman 		.tt_enable_src = false,
3671edba515SAndy Fiddaman 		.tt_enable_dst = true,
368*54819d46SAndy Fiddaman 		.tt_pass = TCPSIG_SENDRECV
3691edba515SAndy Fiddaman 	}
3701edba515SAndy Fiddaman };
3711edba515SAndy Fiddaman 
3721edba515SAndy Fiddaman static bool
tcpsig_bind_dest(const tcpsig_test_t * test,int sock,struct sockaddr_storage * dst)3731edba515SAndy Fiddaman tcpsig_bind_dest(const tcpsig_test_t *test, int sock,
3741edba515SAndy Fiddaman     struct sockaddr_storage *dst)
3751edba515SAndy Fiddaman {
3761edba515SAndy Fiddaman 	socklen_t len;
3771edba515SAndy Fiddaman 	struct sockaddr_storage addr;
3781edba515SAndy Fiddaman 
3791edba515SAndy Fiddaman 	(void) memset(&addr, 0, sizeof (struct sockaddr_storage));
3801edba515SAndy Fiddaman 
3811edba515SAndy Fiddaman 	if (test->tt_domain == PF_INET) {
3821edba515SAndy Fiddaman 		struct sockaddr_in *in = (struct sockaddr_in *)&addr;
3831edba515SAndy Fiddaman 		in->sin_family = AF_INET;
3841edba515SAndy Fiddaman 		in->sin_port = htons(test->tt_port);
3851edba515SAndy Fiddaman 		if (inet_pton(AF_INET, "127.0.0.1", &in->sin_addr) != 1) {
3861edba515SAndy Fiddaman 			warnx("TEST FAILED: %s: failed to convert 127.0.0.1 "
3871edba515SAndy Fiddaman 			    "to an IPv4 address", test->tt_desc);
3881edba515SAndy Fiddaman 			return (false);
3891edba515SAndy Fiddaman 		}
3901edba515SAndy Fiddaman 		len = sizeof (struct sockaddr_in);
3911edba515SAndy Fiddaman 	} else {
3921edba515SAndy Fiddaman 		struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&addr;
3931edba515SAndy Fiddaman 		in6->sin6_family = AF_INET6;
3941edba515SAndy Fiddaman 		in6->sin6_port = htons(test->tt_port);
3951edba515SAndy Fiddaman 		if (inet_pton(AF_INET6, "::1", &in6->sin6_addr) != 1) {
3961edba515SAndy Fiddaman 			warnx("TEST FAILED: %s: failed to convert ::1 "
3971edba515SAndy Fiddaman 			    "to an IPv6 address", test->tt_desc);
3981edba515SAndy Fiddaman 			return (false);
3991edba515SAndy Fiddaman 		}
4001edba515SAndy Fiddaman 		len = sizeof (struct sockaddr_in6);
4011edba515SAndy Fiddaman 	}
4021edba515SAndy Fiddaman 
4031edba515SAndy Fiddaman 	if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
4041edba515SAndy Fiddaman 		warn("TEST FAILED: %s: failed to bind listen socket",
4051edba515SAndy Fiddaman 		    test->tt_desc);
4061edba515SAndy Fiddaman 		return (false);
4071edba515SAndy Fiddaman 	}
4081edba515SAndy Fiddaman 
4091edba515SAndy Fiddaman 	len = sizeof (struct sockaddr_storage);
4101edba515SAndy Fiddaman 	if (getsockname(sock, (struct sockaddr *)dst, &len) != 0) {
4111edba515SAndy Fiddaman 		warn("TEST FAILED: %s: failed to retrieve socket address ",
4121edba515SAndy Fiddaman 		    test->tt_desc);
4131edba515SAndy Fiddaman 		return (false);
4141edba515SAndy Fiddaman 	}
4151edba515SAndy Fiddaman 
4161edba515SAndy Fiddaman 	return (true);
4171edba515SAndy Fiddaman }
4181edba515SAndy Fiddaman 
4191edba515SAndy Fiddaman /*
4201edba515SAndy Fiddaman  * Our job is to attempt to connect to the other end with our current settings.
4211edba515SAndy Fiddaman  * This may not work, so we use our port to get things ready just in case.
4221edba515SAndy Fiddaman  */
4231edba515SAndy Fiddaman static bool
tcpsig_connect(const tcpsig_test_t * test,int port,int src,int dst,int * cfd,const struct sockaddr * addr)4241edba515SAndy Fiddaman tcpsig_connect(const tcpsig_test_t *test, int port, int src, int dst, int *cfd,
4251edba515SAndy Fiddaman     const struct sockaddr *addr)
4261edba515SAndy Fiddaman {
4271edba515SAndy Fiddaman 	struct timespec to = { .tv_nsec = sock_to };
4281edba515SAndy Fiddaman 	int namelen = test->tt_domain == PF_INET ? sizeof (struct sockaddr_in) :
4291edba515SAndy Fiddaman 	    sizeof (struct sockaddr_in6);
430*54819d46SAndy Fiddaman 	int conn, opt;
431*54819d46SAndy Fiddaman 	unsigned int optlen;
4321edba515SAndy Fiddaman 	port_event_t pe;
4331edba515SAndy Fiddaman 
4341edba515SAndy Fiddaman 	if (listen(dst, 5) != 0) {
4351edba515SAndy Fiddaman 		warn("TEST FAILED: %s: failed to listen", test->tt_desc);
4361edba515SAndy Fiddaman 		return (false);
4371edba515SAndy Fiddaman 	}
4381edba515SAndy Fiddaman 
4391edba515SAndy Fiddaman 	if (connect(src, addr, namelen) != 0 && errno != EINPROGRESS) {
4401edba515SAndy Fiddaman 		if (errno == ECONNREFUSED &&
4411edba515SAndy Fiddaman 		    test->tt_pass == TCPSIG_CONNREFUSED) {
4421edba515SAndy Fiddaman 			(void) printf("TEST PASSED: %s: connection refused\n",
4431edba515SAndy Fiddaman 			    test->tt_desc);
4441edba515SAndy Fiddaman 			return (true);
4451edba515SAndy Fiddaman 		}
4461edba515SAndy Fiddaman 		warn("TEST FAILED: %s: failed to connect", test->tt_desc);
4471edba515SAndy Fiddaman 		return (false);
4481edba515SAndy Fiddaman 	}
4491edba515SAndy Fiddaman 
4501edba515SAndy Fiddaman 	if (port_associate(port, PORT_SOURCE_FD, src, POLLOUT, NULL) != 0) {
4511edba515SAndy Fiddaman 		err(EXIT_FAILURE, "INTERNAL TEST FAILURE: %s: could not port "
4521edba515SAndy Fiddaman 		    "associate to watch connect", test->tt_desc);
4531edba515SAndy Fiddaman 	}
4541edba515SAndy Fiddaman 
4551edba515SAndy Fiddaman 	if (port_get(port, &pe, &to) != 0) {
4561edba515SAndy Fiddaman 		if (test->tt_pass == TCPSIG_NOCONNECT) {
4571edba515SAndy Fiddaman 			(void) printf(
4581edba515SAndy Fiddaman 			    "TEST PASSED: %s: correctly failed to connect\n",
4591edba515SAndy Fiddaman 			    test->tt_desc);
4601edba515SAndy Fiddaman 			return (true);
4611edba515SAndy Fiddaman 		} else {
4621edba515SAndy Fiddaman 			warn("TEST FAILED: %s: timed out waiting to connect",
4631edba515SAndy Fiddaman 			    test->tt_desc);
4641edba515SAndy Fiddaman 			return (false);
4651edba515SAndy Fiddaman 		}
4661edba515SAndy Fiddaman 	}
4671edba515SAndy Fiddaman 
4681edba515SAndy Fiddaman 	if ((pe.portev_events & POLLOUT) == 0) {
4691edba515SAndy Fiddaman 		warnx("TEST FAILED: %s: connect port event doesn't contain "
4701edba515SAndy Fiddaman 		    "POLLOUT, found 0x%x", test->tt_desc, pe.portev_events);
4711edba515SAndy Fiddaman 		return (false);
4721edba515SAndy Fiddaman 	}
4731edba515SAndy Fiddaman 
4741edba515SAndy Fiddaman 	/*
4751edba515SAndy Fiddaman 	 * Now make sure the listen socket is ready.
4761edba515SAndy Fiddaman 	 */
4771edba515SAndy Fiddaman 	if (port_associate(port, PORT_SOURCE_FD, dst, POLLIN, NULL) != 0) {
4781edba515SAndy Fiddaman 		err(EXIT_FAILURE, "INTERNAL TEST FAILURE: %s: could not port "
4791edba515SAndy Fiddaman 		    "associate to watch accept", test->tt_desc);
4801edba515SAndy Fiddaman 	}
4811edba515SAndy Fiddaman 
4821edba515SAndy Fiddaman 	if (port_get(port, &pe, &to) != 0) {
4831edba515SAndy Fiddaman 		warn("TEST FAILED: %s: timed out waiting to accept",
4841edba515SAndy Fiddaman 		    test->tt_desc);
4851edba515SAndy Fiddaman 		return (false);
4861edba515SAndy Fiddaman 	}
4871edba515SAndy Fiddaman 
4881edba515SAndy Fiddaman 	if ((pe.portev_events & POLLIN) == 0) {
4891edba515SAndy Fiddaman 		warnx("TEST FAILED: %s: accept port event doesn't contain "
4901edba515SAndy Fiddaman 		    "POLLIN, found 0x%x", test->tt_desc, pe.portev_events);
4911edba515SAndy Fiddaman 		return (false);
4921edba515SAndy Fiddaman 	}
4931edba515SAndy Fiddaman 
4941edba515SAndy Fiddaman 	conn = accept4(dst, NULL, NULL, SOCK_NONBLOCK);
4951edba515SAndy Fiddaman 	if (conn < 0) {
4961edba515SAndy Fiddaman 		warn("TEST FAILED: %s: failed to get client connection",
4971edba515SAndy Fiddaman 		    test->tt_desc);
4981edba515SAndy Fiddaman 		return (false);
4991edba515SAndy Fiddaman 	}
5001edba515SAndy Fiddaman 
501*54819d46SAndy Fiddaman 	optlen = sizeof (opt);
502*54819d46SAndy Fiddaman 	if (getsockopt(conn, IPPROTO_TCP, TCP_MD5SIG, &opt, &optlen) != 0) {
503*54819d46SAndy Fiddaman 		warn("TEST FAILED: %s: failed to retrieve accepted socket "
504*54819d46SAndy Fiddaman 		    "TCP_MD5SIG option", test->tt_desc);
505*54819d46SAndy Fiddaman 		return (false);
506*54819d46SAndy Fiddaman 	}
507*54819d46SAndy Fiddaman 
508*54819d46SAndy Fiddaman 	if (optlen != sizeof (opt)) {
509*54819d46SAndy Fiddaman 		warn("TEST FAILED: %s: TCP_MD5SIG option has wrong length %d "
510*54819d46SAndy Fiddaman 		    "(expected %ld).", test->tt_desc, optlen, sizeof (opt));
511*54819d46SAndy Fiddaman 		return (false);
512*54819d46SAndy Fiddaman 	}
513*54819d46SAndy Fiddaman 
514*54819d46SAndy Fiddaman 	/*
515*54819d46SAndy Fiddaman 	 * For tests where the TCP MD5 option is not enabled on the source, but
516*54819d46SAndy Fiddaman 	 * is on the destination, and where we expect the connection to
517*54819d46SAndy Fiddaman 	 * succeed, we also expect that the socket option has been disabled on
518*54819d46SAndy Fiddaman 	 * accept(). Check.
519*54819d46SAndy Fiddaman 	 */
520*54819d46SAndy Fiddaman 	if (test->tt_enable_dst && !test->tt_enable_src &&
521*54819d46SAndy Fiddaman 	    test->tt_pass == TCPSIG_SENDRECV && opt != 0) {
522*54819d46SAndy Fiddaman 		warnx("TEST FAILED: %s: TCP_MD5SIG is set and should not be",
523*54819d46SAndy Fiddaman 		    test->tt_desc);
524*54819d46SAndy Fiddaman 		return (false);
525*54819d46SAndy Fiddaman 	} else if (test->tt_enable_src && opt == 0) {
526*54819d46SAndy Fiddaman 		warnx("TEST FAILED: %s: TCP_MD5SIG is not set and should be",
527*54819d46SAndy Fiddaman 		    test->tt_desc);
528*54819d46SAndy Fiddaman 		return (false);
529*54819d46SAndy Fiddaman 	}
530*54819d46SAndy Fiddaman 
5311edba515SAndy Fiddaman 	if (test->tt_pass != TCPSIG_SENDRECV &&
5321edba515SAndy Fiddaman 	    test->tt_pass != TCPSIG_NODATA) {
5331edba515SAndy Fiddaman 		warnx("TEST FAILED: %s: expected connect to fail, but passed",
5341edba515SAndy Fiddaman 		    test->tt_desc);
5351edba515SAndy Fiddaman 		return (false);
5361edba515SAndy Fiddaman 	}
5371edba515SAndy Fiddaman 
5381edba515SAndy Fiddaman 	*cfd = conn;
5391edba515SAndy Fiddaman 	return (true);
5401edba515SAndy Fiddaman }
5411edba515SAndy Fiddaman 
5421edba515SAndy Fiddaman /*
5431edba515SAndy Fiddaman  * Attempt to send data with the tcpsigs set up appropriately. This might fail,
5441edba515SAndy Fiddaman  * hence our port_associate dance and unfortunately regrettable timeout.
5451edba515SAndy Fiddaman  */
5461edba515SAndy Fiddaman static bool
tcpsig_sendrecv(const tcpsig_test_t * test,int port,int src,int dst)5471edba515SAndy Fiddaman tcpsig_sendrecv(const tcpsig_test_t *test, int port, int src, int dst)
5481edba515SAndy Fiddaman {
5491edba515SAndy Fiddaman 	struct timespec to = { .tv_nsec = sock_to };
5501edba515SAndy Fiddaman 	port_event_t pe;
5511edba515SAndy Fiddaman 	uint32_t data;
5521edba515SAndy Fiddaman 	ssize_t sret;
5531edba515SAndy Fiddaman 
5541edba515SAndy Fiddaman 	if (send(src, &msgdata, sizeof (msgdata), MSG_NOSIGNAL) !=
5551edba515SAndy Fiddaman 	    sizeof (msgdata)) {
5561edba515SAndy Fiddaman 		warn("TEST FAILED: %s: failed to write message to socket",
5571edba515SAndy Fiddaman 		    test->tt_desc);
5581edba515SAndy Fiddaman 	}
5591edba515SAndy Fiddaman 
5601edba515SAndy Fiddaman 	if (port_associate(port, PORT_SOURCE_FD, dst, POLLIN, NULL) != 0) {
5611edba515SAndy Fiddaman 		err(EXIT_FAILURE, "INTERNAL TEST FAILURE: %s: could not port "
5621edba515SAndy Fiddaman 		    "associate to watch recv", test->tt_desc);
5631edba515SAndy Fiddaman 	}
5641edba515SAndy Fiddaman 
5651edba515SAndy Fiddaman 	if (port_get(port, &pe, &to) != 0) {
5661edba515SAndy Fiddaman 		if (test->tt_pass == TCPSIG_NODATA) {
5671edba515SAndy Fiddaman 			(void) printf("TEST PASSED: %s: timed out waiting "
5681edba515SAndy Fiddaman 			    "for data\n", test->tt_desc);
5691edba515SAndy Fiddaman 			return (true);
5701edba515SAndy Fiddaman 		} else {
5711edba515SAndy Fiddaman 			warn("TEST FAILED: %s: timed out waiting to recv",
5721edba515SAndy Fiddaman 			    test->tt_desc);
5731edba515SAndy Fiddaman 			return (false);
5741edba515SAndy Fiddaman 		}
5751edba515SAndy Fiddaman 	}
5761edba515SAndy Fiddaman 
5771edba515SAndy Fiddaman 	if ((pe.portev_events & POLLIN) == 0) {
5781edba515SAndy Fiddaman 		warnx("TEST FAILED: %s: receive port event doesn't contain "
5791edba515SAndy Fiddaman 		    "POLLIN, found 0x%x", test->tt_desc, pe.portev_events);
5801edba515SAndy Fiddaman 		return (false);
5811edba515SAndy Fiddaman 	}
5821edba515SAndy Fiddaman 
5831edba515SAndy Fiddaman 	sret = recv(dst, &data, sizeof (data), MSG_DONTWAIT);
5841edba515SAndy Fiddaman 	if (sret != (ssize_t)sizeof (data)) {
5851edba515SAndy Fiddaman 		warnx("TEST FAILED: %s: failed to receive data: %zx",
5861edba515SAndy Fiddaman 		    test->tt_desc, sret);
5871edba515SAndy Fiddaman 		return (false);
5881edba515SAndy Fiddaman 	}
5891edba515SAndy Fiddaman 
5901edba515SAndy Fiddaman 	if (test->tt_pass != TCPSIG_SENDRECV) {
5911edba515SAndy Fiddaman 		warnx("TEST FAILED: %s: found data, despite expecting not to",
5921edba515SAndy Fiddaman 		    test->tt_desc);
5931edba515SAndy Fiddaman 		return (false);
5941edba515SAndy Fiddaman 	}
5951edba515SAndy Fiddaman 
5961edba515SAndy Fiddaman 	if (data != msgdata) {
5971edba515SAndy Fiddaman 		warnx("TEST FAILED: %s: data mismatch: expected 0x%x, found "
5981edba515SAndy Fiddaman 		    "0x%x", test->tt_desc, msgdata, data);
5991edba515SAndy Fiddaman 		return (false);
6001edba515SAndy Fiddaman 	}
6011edba515SAndy Fiddaman 
6021edba515SAndy Fiddaman 	(void) printf("TEST PASSED: %s: successfully received data\n",
6031edba515SAndy Fiddaman 	    test->tt_desc);
6041edba515SAndy Fiddaman 	return (true);
6051edba515SAndy Fiddaman }
6061edba515SAndy Fiddaman 
6071edba515SAndy Fiddaman static bool
tcpsig_test_one(const tcpsig_test_t * test)6081edba515SAndy Fiddaman tcpsig_test_one(const tcpsig_test_t *test)
6091edba515SAndy Fiddaman {
6101edba515SAndy Fiddaman 	int src = -1, dst = -1, cfd = -1, port = -1, tdst;
6111edba515SAndy Fiddaman 	int x;
6121edba515SAndy Fiddaman 	bool ret = true;
6131edba515SAndy Fiddaman 	struct sockaddr_storage dst_addr;
6141edba515SAndy Fiddaman 
6151edba515SAndy Fiddaman 	if ((port = port_create()) < 0)
6161edba515SAndy Fiddaman 		err(EXIT_FAILURE, "TEST FAILED: failed to create event port");
6171edba515SAndy Fiddaman 
6181edba515SAndy Fiddaman 	src = socket(test->tt_domain, SOCK_STREAM | SOCK_NONBLOCK, 0);
6191edba515SAndy Fiddaman 	if (src < 0) {
6201edba515SAndy Fiddaman 		warn("TEST FAILED: %s: failed to create source socket",
6211edba515SAndy Fiddaman 		    test->tt_desc);
6221edba515SAndy Fiddaman 		ret = false;
6231edba515SAndy Fiddaman 		goto cleanup;
6241edba515SAndy Fiddaman 	}
6251edba515SAndy Fiddaman 
6261edba515SAndy Fiddaman 	x = test->tt_enable_src ? 1 : 0;
6271edba515SAndy Fiddaman 	if (setsockopt(src, IPPROTO_TCP, TCP_MD5SIG, &x, sizeof (x)) != 0) {
6281edba515SAndy Fiddaman 		warn("TEST FAILED: %s: failed to configure src MD5SIG option",
6291edba515SAndy Fiddaman 		    test->tt_desc);
6301edba515SAndy Fiddaman 		ret = false;
6311edba515SAndy Fiddaman 		goto cleanup;
6321edba515SAndy Fiddaman 	}
6331edba515SAndy Fiddaman 
6341edba515SAndy Fiddaman 	dst = socket(test->tt_domain, SOCK_STREAM | SOCK_NONBLOCK, 0);
6351edba515SAndy Fiddaman 	if (dst < 0) {
6361edba515SAndy Fiddaman 		warn("TEST FAILED: %s: failed to create destination socket",
6371edba515SAndy Fiddaman 		    test->tt_desc);
6381edba515SAndy Fiddaman 		ret = false;
6391edba515SAndy Fiddaman 		goto cleanup;
6401edba515SAndy Fiddaman 	}
6411edba515SAndy Fiddaman 
6421edba515SAndy Fiddaman 	x = test->tt_enable_dst ? 1 : 0;
6431edba515SAndy Fiddaman 	if (setsockopt(dst, IPPROTO_TCP, TCP_MD5SIG, &x, sizeof (x)) != 0) {
6441edba515SAndy Fiddaman 		warn("TEST FAILED: %s: failed to configure dst MD5SIG option",
6451edba515SAndy Fiddaman 		    test->tt_desc);
6461edba515SAndy Fiddaman 		ret = false;
6471edba515SAndy Fiddaman 		goto cleanup;
6481edba515SAndy Fiddaman 	}
6491edba515SAndy Fiddaman 
6501edba515SAndy Fiddaman 	if (!tcpsig_bind_dest(test, dst, &dst_addr)) {
6511edba515SAndy Fiddaman 		ret = false;
6521edba515SAndy Fiddaman 		goto cleanup;
6531edba515SAndy Fiddaman 	}
6541edba515SAndy Fiddaman 
6551edba515SAndy Fiddaman 	if (!tcpsig_connect(test, port, src, dst, &cfd,
6561edba515SAndy Fiddaman 	    (struct sockaddr *)&dst_addr)) {
6571edba515SAndy Fiddaman 		ret = false;
6581edba515SAndy Fiddaman 		goto cleanup;
6591edba515SAndy Fiddaman 	}
6601edba515SAndy Fiddaman 
6611edba515SAndy Fiddaman 	if (test->tt_pass != TCPSIG_SENDRECV && test->tt_pass != TCPSIG_NODATA)
6621edba515SAndy Fiddaman 		goto cleanup;
6631edba515SAndy Fiddaman 
6641edba515SAndy Fiddaman 	tdst = cfd;
6651edba515SAndy Fiddaman 
6661edba515SAndy Fiddaman 	if (!tcpsig_sendrecv(test, port, src, tdst)) {
6671edba515SAndy Fiddaman 		ret = false;
6681edba515SAndy Fiddaman 		goto cleanup;
6691edba515SAndy Fiddaman 	}
6701edba515SAndy Fiddaman 
6711edba515SAndy Fiddaman cleanup:
6721edba515SAndy Fiddaman 	if (port > -1)
6731edba515SAndy Fiddaman 		(void) close(port);
6741edba515SAndy Fiddaman 	if (src > -1) {
6751edba515SAndy Fiddaman 		(void) shutdown(src, SHUT_RDWR);
6761edba515SAndy Fiddaman 		(void) close(src);
6771edba515SAndy Fiddaman 	}
6781edba515SAndy Fiddaman 	if (dst > -1)
6791edba515SAndy Fiddaman 		(void) close(dst);
6801edba515SAndy Fiddaman 	if (cfd > -1)
6811edba515SAndy Fiddaman 		(void) close(cfd);
6821edba515SAndy Fiddaman 	return (ret);
6831edba515SAndy Fiddaman }
6841edba515SAndy Fiddaman 
6851edba515SAndy Fiddaman int
main(int argc,char ** argv)6861edba515SAndy Fiddaman main(int argc, char **argv)
6871edba515SAndy Fiddaman {
6881edba515SAndy Fiddaman 	size_t max = ARRAY_SIZE(tcpsig_tests) - 1;
6891edba515SAndy Fiddaman 	int ret = EXIT_SUCCESS;
6901edba515SAndy Fiddaman 
6911edba515SAndy Fiddaman 	if (argc == 2) {
6921edba515SAndy Fiddaman 		const char *errstr;
6931edba515SAndy Fiddaman 		size_t idx;
6941edba515SAndy Fiddaman 
6951edba515SAndy Fiddaman 		idx = (size_t)strtonumx(argv[1], 0, max, &errstr, 0);
6961edba515SAndy Fiddaman 		if (errstr != NULL) {
6971edba515SAndy Fiddaman 			(void) fprintf(stderr, "Syntax: %s [test number]\n",
6981edba515SAndy Fiddaman 			    getprogname());
6991edba515SAndy Fiddaman 			(void) fprintf(stderr,
7001edba515SAndy Fiddaman 			    "Test number is in the range [0-%u]\n", max);
7011edba515SAndy Fiddaman 			(void) fprintf(stderr, "\nAvailable tests:\n");
7021edba515SAndy Fiddaman 			for (size_t i = 0; i <= max; i++) {
7031edba515SAndy Fiddaman 				(void) fprintf(stderr, "    %5d - %s\n", i,
7041edba515SAndy Fiddaman 				    tcpsig_tests[i].tt_desc);
7051edba515SAndy Fiddaman 			}
7061edba515SAndy Fiddaman 			return (EXIT_FAILURE);
7071edba515SAndy Fiddaman 		}
7081edba515SAndy Fiddaman 
7091edba515SAndy Fiddaman 		if (!tcpsig_test_one(&tcpsig_tests[idx]))
7101edba515SAndy Fiddaman 			ret = EXIT_FAILURE;
7111edba515SAndy Fiddaman 	} else {
7121edba515SAndy Fiddaman 		for (size_t i = 0; i <= max; i++) {
7131edba515SAndy Fiddaman 			if (!tcpsig_test_one(&tcpsig_tests[i]))
7141edba515SAndy Fiddaman 				ret = EXIT_FAILURE;
7151edba515SAndy Fiddaman 		}
7161edba515SAndy Fiddaman 		if (ret == EXIT_SUCCESS)
7171edba515SAndy Fiddaman 			(void) printf("All tests passed successfully\n");
7181edba515SAndy Fiddaman 	}
7191edba515SAndy Fiddaman 
7201edba515SAndy Fiddaman 	return (ret);
7211edba515SAndy Fiddaman }
722