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