tcptop_snv revision 1.1.1.1
1#!/usr/bin/ksh 2# 3# tcptop_snv - display top TCP network packets by process. 4# Written using DTrace (Solaris Nevada) 5# 6# This analyses TCP network packets and prints the responsible PID and UID, 7# plus standard details such as IP address and port. This captures traffic 8# of newly created TCP connections that were established while this program 9# was running. It can help identify which processes is causing TCP traffic. 10# 11# WARNING: This script may only work on Solaris Nevada and OpenSolaris 12# of the late 2007 vintage, since it uses the fbt provider to trace the raw 13# operation of a specific version of the kernel. In the future, a 'stable' 14# network provider should exist which will allow this to be written for that 15# and subsequent versions of the kernel. In the meantime, check for other 16# versions of this script in the /Net directory, and read the 17# Notes/ALLfbt_notes.txt for more background on fbt. 18# 19# $Id: tcptop_snv,v 1.1.1.1 2015/09/30 22:01:09 christos Exp $ 20# 21# USAGE: tcptop [-Ch] [-j|-Z] [interval [count]] 22# 23# -C # don't clear the screen 24# -j # print project IDs 25# -Z # print zone IDs 26# 27# FIELDS: 28# UID user ID 29# PID process ID 30# CMD command 31# LADDR local IP address 32# RADDR remote IP address 33# LPORT local port number 34# RPORT remote port number 35# SIZE packet size, bytes 36# load 1 min load average 37# TCPin TCP inbound payload data 38# TCPout TCP outbound payload data 39# ZONE zone ID 40# PROJ project ID 41# 42# SEE ALSO: tcpsnoop 43# 44# COPYRIGHT: Copyright (c) 2005, 2006 Brendan Gregg. 45# 46# CDDL HEADER START 47# 48# The contents of this file are subject to the terms of the 49# Common Development and Distribution License, Version 1.0 only 50# (the "License"). You may not use this file except in compliance 51# with the License. 52# 53# You can obtain a copy of the license at Docs/cddl1.txt 54# or http://www.opensolaris.org/os/licensing. 55# See the License for the specific language governing permissions 56# and limitations under the License. 57# 58# CDDL HEADER END 59# 60# Author: Brendan Gregg [Sydney, Australia] 61# 62# ToDo: IPv6 63# 64# 05-Jul-2005 Brendan Gregg Created this. 65# 03-Dec-2005 " " Fixed tcp_accept_finish bug, now 100% correct 66# execname. Thanks Kias Belgaied for expertise. 67# 20-Apr-2006 " " Fixed SS_TCP_FAST_ACCEPT bug in build 31+. 68# 20-Apr-2006 " " Last update. 69# 30-Sep-2007 " " Bumped this for recent OpenSolaris/Nevada. 70# 71 72############################## 73# --- Process Arguments --- 74# 75 76### default variables 77opt_def=1; opt_clear=1; opt_zone=0; opt_proj=0; interval=5; count=-1 78 79### process options 80while getopts ChjZ name 81do 82 case $name in 83 C) opt_clear=0 ;; 84 j) opt_proj=1; opt_def=0 ;; 85 Z) opt_zone=1; opt_def=0 ;; 86 h|?) cat <<-END >&2 87 USAGE: tcptop [-h] [-j|-Z] [interval [count]] 88 tcptop # default output 89 -C # don't clear the screen 90 -j # print project ID 91 -Z # print zonename 92 eg, 93 tcptop # default is 5 sec interval 94 tcptop 2 # 2 second interval 95 tcptop -C 1 10 # 10 x 1 sec samples, no clear 96 END 97 exit 1 98 esac 99done 100shift $(( $OPTIND - 1 )) 101 102### option logic 103if [[ "$1" > 0 ]]; then 104 interval=$1; shift 105fi 106if [[ "$1" > 0 ]]; then 107 count=$1; shift 108fi 109if (( opt_proj && opt_zone )); then 110 opt_proj=0 111fi 112if (( opt_clear )); then 113 clearstr=`clear` 114else 115 clearstr=. 116fi 117 118################################# 119# --- Main Program, DTrace --- 120# 121/usr/sbin/dtrace -Cs <( print -r ' 122 /* 123 * Command line arguments 124 */ 125 inline int OPT_def = '$opt_def'; 126 inline int OPT_zone = '$opt_zone'; 127 inline int OPT_proj = '$opt_proj'; 128 inline int OPT_clear = '$opt_clear'; 129 inline int INTERVAL = '$interval'; 130 inline int COUNTER = '$count'; 131 inline string CLEAR = "'$clearstr'"; 132 133#pragma D option quiet 134#pragma D option switchrate=10hz 135 136#include <sys/file.h> 137#include <inet/common.h> 138#include <sys/byteorder.h> 139#include <sys/socket.h> 140#include <sys/socketvar.h> 141 142/* 143 * Print header 144 */ 145dtrace:::BEGIN 146{ 147 /* starting values */ 148 counts = COUNTER; 149 secs = INTERVAL; 150 TCP_out = 0; 151 TCP_in = 0; 152 153 printf("Tracing... Please wait.\n"); 154} 155 156/* 157 * TCP Process inbound connections 158 * 159 * 0x00200000 has been hardcoded. It was SS_TCP_FAST_ACCEPT, but was 160 * renamed to SS_DIRECT around build 31. 161 */ 162fbt:sockfs:sotpi_accept:entry 163/(arg1 & FREAD) && (arg1 & FWRITE) && (args[0]->so_state & 0x00200000)/ 164{ 165 self->sop = args[0]; 166} 167 168fbt:sockfs:sotpi_create:return 169/self->sop/ 170{ 171 self->nsop = (struct sonode *)arg1; 172} 173 174fbt:sockfs:sotpi_accept:return 175/self->nsop/ 176{ 177 this->tcpp = (tcp_t *)self->nsop->so_priv; 178 self->connp = (conn_t *)this->tcpp->tcp_connp; 179 tname[(int)self->connp] = execname; 180 tpid[(int)self->connp] = pid; 181 tuid[(int)self->connp] = uid; 182} 183 184fbt:sockfs:sotpi_accept:return 185{ 186 self->nsop = 0; 187 self->sop = 0; 188} 189 190/* 191 * TCP Process outbound connections 192 */ 193fbt:ip:tcp_connect:entry 194{ 195 this->tcpp = (tcp_t *)arg0; 196 self->connp = (conn_t *)this->tcpp->tcp_connp; 197 tname[(int)self->connp] = execname; 198 tpid[(int)self->connp] = pid; 199 tuid[(int)self->connp] = uid; 200 OPT_proj ? tproj[(int)self->connp] = curpsinfo->pr_projid : 1; 201} 202 203/* 204 * TCP Data translations 205 */ 206fbt:sockfs:sotpi_accept:return, 207fbt:ip:tcp_connect:return 208/self->connp/ 209{ 210 /* fetch ports */ 211#if defined(_BIG_ENDIAN) 212 self->lport = self->connp->u_port.tcpu_ports.tcpu_lport; 213 self->fport = self->connp->u_port.tcpu_ports.tcpu_fport; 214#else 215 self->lport = BSWAP_16(self->connp->u_port.tcpu_ports.tcpu_lport); 216 self->fport = BSWAP_16(self->connp->u_port.tcpu_ports.tcpu_fport); 217#endif 218 219 /* fetch IPv4 addresses */ 220 this->fad12 = 221 (int)self->connp->connua_v6addr.connua_faddr._S6_un._S6_u8[12]; 222 this->fad13 = 223 (int)self->connp->connua_v6addr.connua_faddr._S6_un._S6_u8[13]; 224 this->fad14 = 225 (int)self->connp->connua_v6addr.connua_faddr._S6_un._S6_u8[14]; 226 this->fad15 = 227 (int)self->connp->connua_v6addr.connua_faddr._S6_un._S6_u8[15]; 228 this->lad12 = 229 (int)self->connp->connua_v6addr.connua_laddr._S6_un._S6_u8[12]; 230 this->lad13 = 231 (int)self->connp->connua_v6addr.connua_laddr._S6_un._S6_u8[13]; 232 this->lad14 = 233 (int)self->connp->connua_v6addr.connua_laddr._S6_un._S6_u8[14]; 234 this->lad15 = 235 (int)self->connp->connua_v6addr.connua_laddr._S6_un._S6_u8[15]; 236 237 /* convert type for use with lltostr() */ 238 this->fad12 = this->fad12 < 0 ? 256 + this->fad12 : this->fad12; 239 this->fad13 = this->fad13 < 0 ? 256 + this->fad13 : this->fad13; 240 this->fad14 = this->fad14 < 0 ? 256 + this->fad14 : this->fad14; 241 this->fad15 = this->fad15 < 0 ? 256 + this->fad15 : this->fad15; 242 this->lad12 = this->lad12 < 0 ? 256 + this->lad12 : this->lad12; 243 this->lad13 = this->lad13 < 0 ? 256 + this->lad13 : this->lad13; 244 this->lad14 = this->lad14 < 0 ? 256 + this->lad14 : this->lad14; 245 this->lad15 = this->lad15 < 0 ? 256 + this->lad15 : this->lad15; 246 247 /* stringify addresses */ 248 self->faddr = strjoin(lltostr(this->fad12), "."); 249 self->faddr = strjoin(self->faddr, strjoin(lltostr(this->fad13), ".")); 250 self->faddr = strjoin(self->faddr, strjoin(lltostr(this->fad14), ".")); 251 self->faddr = strjoin(self->faddr, lltostr(this->fad15 + 0)); 252 self->laddr = strjoin(lltostr(this->lad12), "."); 253 self->laddr = strjoin(self->laddr, strjoin(lltostr(this->lad13), ".")); 254 self->laddr = strjoin(self->laddr, strjoin(lltostr(this->lad14), ".")); 255 self->laddr = strjoin(self->laddr, lltostr(this->lad15 + 0)); 256 257 /* fix direction and save values */ 258 tladdr[(int)self->connp] = self->laddr; 259 tfaddr[(int)self->connp] = self->faddr; 260 tlport[(int)self->connp] = self->lport; 261 tfport[(int)self->connp] = self->fport; 262 263 /* all systems go */ 264 tok[(int)self->connp] = 1; 265} 266 267/* 268 * TCP Clear connp 269 */ 270fbt:ip:tcp_get_conn:return 271{ 272 /* Q_TO_CONN */ 273 this->connp = (conn_t *)arg1; 274 tok[(int)this->connp] = 0; 275 tpid[(int)this->connp] = 0; 276 tuid[(int)this->connp] = 0; 277 tname[(int)this->connp] = 0; 278 tproj[(int)this->connp] = 0; 279} 280 281/* 282 * TCP Process "port closed" 283 */ 284fbt:ip:tcp_xmit_early_reset:entry 285{ 286 this->queuep = args[7]->tcps_g_q; 287 this->connp = (conn_t *)this->queuep->q_ptr; 288 this->tcpp = (tcp_t *)this->connp->conn_tcp; 289 self->zoneid = this->connp->conn_zoneid; 290 291 /* split addresses */ 292 this->ipha = (ipha_t *)args[1]->b_rptr; 293 this->fad15 = (this->ipha->ipha_src & 0xff000000) >> 24; 294 this->fad14 = (this->ipha->ipha_src & 0x00ff0000) >> 16; 295 this->fad13 = (this->ipha->ipha_src & 0x0000ff00) >> 8; 296 this->fad12 = (this->ipha->ipha_src & 0x000000ff); 297 this->lad15 = (this->ipha->ipha_dst & 0xff000000) >> 24; 298 this->lad14 = (this->ipha->ipha_dst & 0x00ff0000) >> 16; 299 this->lad13 = (this->ipha->ipha_dst & 0x0000ff00) >> 8; 300 this->lad12 = (this->ipha->ipha_dst & 0x000000ff); 301 302 /* stringify addresses */ 303 self->faddr = strjoin(lltostr(this->fad12), "."); 304 self->faddr = strjoin(self->faddr, strjoin(lltostr(this->fad13), ".")); 305 self->faddr = strjoin(self->faddr, strjoin(lltostr(this->fad14), ".")); 306 self->faddr = strjoin(self->faddr, lltostr(this->fad15 + 0)); 307 self->laddr = strjoin(lltostr(this->lad12), "."); 308 self->laddr = strjoin(self->laddr, strjoin(lltostr(this->lad13), ".")); 309 self->laddr = strjoin(self->laddr, strjoin(lltostr(this->lad14), ".")); 310 self->laddr = strjoin(self->laddr, lltostr(this->lad15 + 0)); 311 312 self->reset = 1; 313} 314 315/* 316 * TCP Fetch "port closed" ports 317 */ 318fbt:ip:tcp_xchg:entry 319/self->reset/ 320{ 321#if defined(_BIG_ENDIAN) 322 self->lport = (uint16_t)arg0; 323 self->fport = (uint16_t)arg1; 324#else 325 self->lport = BSWAP_16((uint16_t)arg0); 326 self->fport = BSWAP_16((uint16_t)arg1); 327#endif 328 self->lport = BE16_TO_U16(arg0); 329 self->fport = BE16_TO_U16(arg1); 330} 331 332/* 333 * TCP Print "port closed" 334 */ 335fbt:ip:tcp_xmit_early_reset:return 336{ 337 self->name = "<closed>"; 338 self->pid = 0; 339 self->uid = 0; 340 self->proj = 0; 341 self->size = 54 * 2; /* should check trailers */ 342 OPT_def ? @out[self->uid, self->pid, self->laddr, self->lport, 343 self->faddr, self->fport, self->name] = sum(self->size) : 1; 344 OPT_zone ? @out[self->zoneid, self->pid, self->laddr, self->lport, 345 self->faddr, self->fport, self->name] = sum(self->size) : 1; 346 OPT_proj ? @out[self->proj, self->pid, self->laddr, self->lport, 347 self->faddr, self->fport, self->name] = sum(self->size) : 1; 348 self->reset = 0; 349 self->size = 0; 350 self->name = 0; 351} 352 353/* 354 * TCP Process Write 355 */ 356fbt:ip:tcp_send_data:entry 357{ 358 self->conn_p = (conn_t *)args[0]->tcp_connp; 359} 360 361fbt:ip:tcp_send_data:entry 362/tok[(int)self->conn_p]/ 363{ 364 self->size = msgdsize(args[2]) + 14; /* should check trailers */ 365 self->uid = tuid[(int)self->conn_p]; 366 self->laddr = tladdr[(int)self->conn_p]; 367 self->faddr = tfaddr[(int)self->conn_p]; 368 self->lport = tlport[(int)self->conn_p]; 369 self->fport = tfport[(int)self->conn_p]; 370 OPT_proj ? self->proj = tproj[(int)self->conn_p] : 1; 371 self->zoneid = self->conn_p->conn_zoneid; 372 self->ok = 2; 373 374 /* follow inetd -> in.* transitions */ 375 self->name = pid && (tname[(int)self->conn_p] == "inetd") ? 376 execname : tname[(int)self->conn_p]; 377 self->pid = pid && (tname[(int)self->conn_p] == "inetd") ? 378 pid : tpid[(int)self->conn_p]; 379 tname[(int)self->conn_p] = self->name; 380 tpid[(int)self->conn_p] = self->pid; 381} 382 383/* 384 * TCP Process Read 385 */ 386fbt:ip:tcp_rput_data:entry 387{ 388 self->conn_p = (conn_t *)arg0; 389 self->size = msgdsize(args[1]) + 14; /* should check trailers */ 390} 391 392fbt:ip:tcp_rput_data:entry 393/tok[(int)self->conn_p]/ 394{ 395 self->uid = tuid[(int)self->conn_p]; 396 self->laddr = tladdr[(int)self->conn_p]; 397 self->faddr = tfaddr[(int)self->conn_p]; 398 self->lport = tlport[(int)self->conn_p]; 399 self->fport = tfport[(int)self->conn_p]; 400 OPT_proj ? self->proj = tproj[(int)self->conn_p] : 1; 401 self->zoneid = self->conn_p->conn_zoneid; 402 self->ok = 2; 403 404 /* follow inetd -> in.* transitions */ 405 self->name = pid && (tname[(int)self->conn_p] == "inetd") ? 406 execname : tname[(int)self->conn_p]; 407 self->pid = pid && (tname[(int)self->conn_p] == "inetd") ? 408 pid : tpid[(int)self->conn_p]; 409 tname[(int)self->conn_p] = self->name; 410 tpid[(int)self->conn_p] = self->pid; 411} 412 413/* 414 * TCP Complete printing outbound handshake 415 */ 416fbt:ip:tcp_connect:return 417/self->connp/ 418{ 419 self->name = tname[(int)self->connp]; 420 self->pid = tpid[(int)self->connp]; 421 self->uid = tuid[(int)self->connp]; 422 self->zoneid = self->connp->conn_zoneid; 423 OPT_proj ? self->proj = tproj[(int)self->connp] : 1; 424 self->size = 54; /* should check trailers */ 425 426 /* this packet occured before connp was fully established */ 427 OPT_def ? @out[self->uid, self->pid, self->laddr, self->lport, 428 self->faddr, self->fport, self->name] = sum(self->size) : 1; 429 OPT_zone ? @out[self->zoneid, self->pid, self->laddr, self->lport, 430 self->faddr, self->fport, self->name] = sum(self->size) : 1; 431 OPT_proj ? @out[self->proj, self->pid, self->laddr, self->lport, 432 self->faddr, self->fport, self->name] = sum(self->size) : 1; 433} 434 435/* 436 * TCP Complete printing inbound handshake 437 */ 438fbt:sockfs:sotpi_accept:return 439/self->connp/ 440{ 441 self->name = tname[(int)self->connp]; 442 self->pid = tpid[(int)self->connp]; 443 self->uid = tuid[(int)self->connp]; 444 self->zoneid = self->connp->conn_zoneid; 445 OPT_proj ? self->proj = tproj[(int)self->connp] : 1; 446 self->size = 54 * 3; /* should check trailers */ 447 448 /* these packets occured before connp was fully established */ 449 OPT_def ? @out[self->uid, self->pid, self->laddr, self->lport, 450 self->faddr, self->fport, self->name] = sum(self->size) : 1; 451 OPT_zone ? @out[self->zoneid, self->pid, self->laddr, self->lport, 452 self->faddr, self->fport, self->name] = sum(self->size) : 1; 453 OPT_proj ? @out[self->proj, self->pid, self->laddr, self->lport, 454 self->faddr, self->fport, self->name] = sum(self->size) : 1; 455} 456 457/* 458 * TCP Save data 459 */ 460fbt:ip:tcp_send_data:entry, 461fbt:ip:tcp_rput_data:entry 462/self->ok == 2/ 463{ 464 /* save r+w data*/ 465 OPT_def ? @out[self->uid, self->pid, self->laddr, self->lport, 466 self->faddr, self->fport, self->name] = sum(self->size) : 1; 467 OPT_zone ? @out[self->zoneid, self->pid, self->laddr, self->lport, 468 self->faddr, self->fport, self->name] = sum(self->size) : 1; 469 OPT_proj ? @out[self->proj, self->pid, self->laddr, self->lport, 470 self->faddr, self->fport, self->name] = sum(self->size) : 1; 471} 472 473/* 474 * TCP Clear connect variables 475 */ 476fbt:sockfs:sotpi_accept:return, 477fbt:ip:tcp_connect:return 478/self->connp/ 479{ 480 self->faddr = 0; 481 self->laddr = 0; 482 self->fport = 0; 483 self->lport = 0; 484 self->connp = 0; 485 self->name = 0; 486 self->pid = 0; 487 self->uid = 0; 488} 489 490/* 491 * TCP Clear r/w variables 492 */ 493fbt:ip:tcp_send_data:entry, 494fbt:ip:tcp_rput_data:entry 495{ 496 self->ok = 0; 497 self->uid = 0; 498 self->pid = 0; 499 self->size = 0; 500 self->name = 0; 501 self->lport = 0; 502 self->fport = 0; 503 self->laddr = 0; 504 self->faddr = 0; 505 self->conn_p = 0; 506 self->zoneid = 0; 507 self->proj = 0; 508} 509 510/* 511 * TCP Systemwide Stats 512 */ 513mib:::tcpOutDataBytes { TCP_out += args[0]; } 514mib:::tcpRetransBytes { TCP_out += args[0]; } 515mib:::tcpInDataInorderBytes { TCP_in += args[0]; } 516mib:::tcpInDataDupBytes { TCP_in += args[0]; } 517mib:::tcpInDataUnorderBytes { TCP_in += args[0]; } 518 519/* 520 * Timer 521 */ 522profile:::tick-1sec 523{ 524 secs--; 525} 526 527/* 528 * Print Report 529 */ 530profile:::tick-1sec 531/secs == 0/ 532{ 533 /* fetch 1 min load average */ 534 this->load1a = `hp_avenrun[0] / 65536; 535 this->load1b = ((`hp_avenrun[0] % 65536) * 100) / 65536; 536 537 /* convert TCP counters to Kbytes */ 538 TCP_out /= 1024; 539 TCP_in /= 1024; 540 541 /* print status */ 542 OPT_clear ? printf("%s", CLEAR) : 1; 543 printf("%Y, load: %d.%02d, TCPin: %6d KB, TCPout: %6d KB\n\n", 544 walltimestamp, this->load1a, this->load1b, TCP_in, TCP_out); 545 546 /* print headers */ 547 OPT_def ? printf(" UID ") : 1; 548 OPT_proj ? printf("PROJ ") : 1; 549 OPT_zone ? printf("ZONE ") : 1; 550 printf("%6s %-15s %5s %-15s %5s %9s %s\n", 551 "PID", "LADDR", "LPORT", "RADDR", "RPORT", "SIZE", "NAME"); 552 553 /* print data */ 554 printa("%4d %6d %-15s %5d %-15s %5d %@9d %s\n", @out); 555 printf("\n"); 556 557 /* clear data */ 558 trunc(@out); 559 TCP_in = 0; 560 TCP_out = 0; 561 secs = INTERVAL; 562 counts--; 563} 564 565/* 566 * End of program 567 */ 568profile:::tick-1sec 569/counts == 0/ 570{ 571 exit(0); 572} 573 574/* 575 * Cleanup for Ctrl-C 576 */ 577dtrace:::END 578{ 579 trunc(@out); 580} 581') 582