xref: /illumos-gate/usr/src/cmd/dtrace/test/tst/common/ip/tst.localtcpstate.ksh (revision 4f06f471d7f0863b816d15ea031e9fe062f9743f)
1#!/usr/bin/ksh
2#
3# CDDL HEADER START
4#
5# The contents of this file are subject to the terms of the
6# Common Development and Distribution License (the "License").
7# You may not use this file except in compliance with the License.
8#
9# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10# or http://www.opensolaris.org/os/licensing.
11# See the License for the specific language governing permissions
12# and limitations under the License.
13#
14# When distributing Covered Code, include this CDDL HEADER in each
15# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16# If applicable, add the following below this CDDL HEADER, with the
17# fields enclosed by brackets "[]" replaced with your own identifying
18# information: Portions Copyright [yyyy] [name of copyright owner]
19#
20# CDDL HEADER END
21#
22
23#
24# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
25# Copyright 2025 Oxide computer Company
26#
27
28#
29# Test tcp:::state-change and tcp:::{send,receive} by connecting to
30# the local ssh service and sending a test message. This should result
31# in a "Protocol mismatch" response and a close of the connection.
32# A number of state transition events along with tcp fusion send and
33# receive events for the message should result.
34#
35# This may fail due to:
36#
37# 1. A change to the ip stack breaking expected probe behavior,
38#    which is the reason we are testing.
39# 2. The lo0 interface missing or not up.
40# 3. The local ssh service is not online.
41# 4. An unlikely race causes the unlocked global send/receive
42#    variables to be corrupted.
43#
44# This test performs a TCP connection to the ssh service (port 22) and
45# checks that at least the following packet counts were traced:
46#
47# 3 x ip:::send (2 during the TCP handshake, then a FIN)
48# 4 x tcp:::send (2 during the TCP handshake, 1 message then a FIN)
49# 2 x ip:::receive (1 during the TCP handshake, then the FIN ACK)
50# 3 x tcp:::receive (1 during the TCP handshake, 1 message then the FIN ACK)
51#
52# The actual ip count tested is 5 each way, since we are tracing both
53# source and destination events.  The actual tcp count tested is 7
54# each way, since the TCP fusion send/receive events will not reach IP.
55#
56# For this test to work, we are assuming that the TCP handshake and
57# TCP close will enter the IP code path and not use tcp fusion.
58#
59
60if (( $# != 1 )); then
61	print -u2 "expected one argument: <dtrace-path>"
62	exit 2
63fi
64
65dtrace=$1
66local=127.0.0.1
67tcpport=12345
68
69nc -l $local $tcpport >/dev/null &
70child=$!
71
72$dtrace -c "./msnc.exe $local $tcpport" -qs /dev/stdin <<EODTRACE
73BEGIN
74{
75	ipsend = tcpsend = ipreceive = tcpreceive = 0;
76	connreq = connest = connaccept = 0;
77}
78
79ip:::send
80/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
81    args[4]->ipv4_protocol == IPPROTO_TCP/
82{
83	ipsend++;
84}
85
86tcp:::send
87/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
88 (args[4]->tcp_sport == $tcpport || args[4]->tcp_dport == $tcpport)/
89{
90	tcpsend++;
91}
92
93ip:::receive
94/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
95    args[4]->ipv4_protocol == IPPROTO_TCP/
96{
97	ipreceive++;
98}
99
100tcp:::receive
101/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
102 (args[4]->tcp_sport == $tcpport || args[4]->tcp_dport == $tcpport)/
103{
104	tcpreceive++;
105}
106
107tcp:::state-change
108{
109	state_event[args[3]->tcps_state]++;
110}
111
112tcp:::connect-request
113/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
114 args[4]->tcp_dport == $tcpport/
115{
116	connreq++;
117}
118
119tcp:::connect-established
120/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
121 args[4]->tcp_sport == $tcpport/
122{
123	connest++;
124}
125
126tcp:::accept-established
127/args[2]->ip_saddr == "$local" && args[2]->ip_daddr == "$local" &&
128 args[4]->tcp_dport == $tcpport/
129{
130	connaccept++;
131}
132
133END
134{
135	printf("Minimum TCP events seen\n\n");
136	printf("ip:::send - %s\n", ipsend >= 5 ? "yes" : "no");
137	printf("ip:::receive - %s\n", ipreceive >= 5 ? "yes" : "no");
138	printf("tcp:::send - %s\n", tcpsend >= 7 ? "yes" : "no");
139	printf("tcp:::receive - %s\n", tcpreceive >= 7 ? "yes" : "no");
140	printf("tcp:::state-change to syn-sent - %s\n",
141	    state_event[TCP_STATE_SYN_SENT] >=1 ? "yes" : "no");
142	printf("tcp:::state-change to syn-received - %s\n",
143	    state_event[TCP_STATE_SYN_RECEIVED] >=1 ? "yes" : "no");
144	printf("tcp:::state-change to established - %s\n",
145	    state_event[TCP_STATE_ESTABLISHED] >= 2 ? "yes" : "no");
146	printf("tcp:::state-change to fin-wait-1 - %s\n",
147	    state_event[TCP_STATE_FIN_WAIT_1] >= 1 ? "yes" : "no");
148	printf("tcp:::state-change to close-wait - %s\n",
149	    state_event[TCP_STATE_CLOSE_WAIT] >= 1 ? "yes" : "no");
150	printf("tcp:::state-change to fin-wait-2 - %s\n",
151	    state_event[TCP_STATE_FIN_WAIT_2] >= 1 ? "yes" : "no");
152	printf("tcp:::state-change to last-ack - %s\n",
153	    state_event[TCP_STATE_LAST_ACK] >= 1 ? "yes" : "no");
154	printf("tcp:::state-change to time-wait - %s\n",
155	    state_event[TCP_STATE_TIME_WAIT] >= 1 ? "yes" : "no");
156	printf("tcp:::connect-request - %s\n",
157	    connreq >=1 ? "yes" : "no");
158	printf("tcp:::connect-established - %s\n",
159	    connest >=1 ? "yes" : "no");
160	printf("tcp:::accept-established - %s\n",
161	    connaccept >=1 ? "yes" : "no");
162}
163EODTRACE
164
165status=$?
166
167exit $status
168