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:07 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 77 opt_def=1; opt_clear=1; opt_zone=0; opt_proj=0; interval=5; count=-1 78 79 ### process options 80 while getopts ChjZ name 81 do 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 99 done 100 shift $(( $OPTIND - 1 )) 101 102 ### option logic 103 if [[ "$1" > 0 ]]; then 104 interval=$1; shift 105 fi 106 if [[ "$1" > 0 ]]; then 107 count=$1; shift 108 fi 109 if (( opt_proj && opt_zone )); then 110 opt_proj=0 111 fi 112 if (( opt_clear )); then 113 clearstr=`clear` 114 else 115 clearstr=. 116 fi 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 */ 145 dtrace:::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 */ 162 fbt:sockfs:sotpi_accept:entry 163 /(arg1 & FREAD) && (arg1 & FWRITE) && (args[0]->so_state & 0x00200000)/ 164 { 165 self->sop = args[0]; 166 } 167 168 fbt:sockfs:sotpi_create:return 169 /self->sop/ 170 { 171 self->nsop = (struct sonode *)arg1; 172 } 173 174 fbt: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 184 fbt:sockfs:sotpi_accept:return 185 { 186 self->nsop = 0; 187 self->sop = 0; 188 } 189 190 /* 191 * TCP Process outbound connections 192 */ 193 fbt: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 */ 206 fbt:sockfs:sotpi_accept:return, 207 fbt: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 */ 270 fbt: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 */ 284 fbt: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 */ 318 fbt: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 */ 335 fbt: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 */ 356 fbt:ip:tcp_send_data:entry 357 { 358 self->conn_p = (conn_t *)args[0]->tcp_connp; 359 } 360 361 fbt: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 */ 386 fbt: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 392 fbt: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 */ 416 fbt: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 */ 438 fbt: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 */ 460 fbt:ip:tcp_send_data:entry, 461 fbt: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 */ 476 fbt:sockfs:sotpi_accept:return, 477 fbt: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 */ 493 fbt:ip:tcp_send_data:entry, 494 fbt: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 */ 513 mib:::tcpOutDataBytes { TCP_out += args[0]; } 514 mib:::tcpRetransBytes { TCP_out += args[0]; } 515 mib:::tcpInDataInorderBytes { TCP_in += args[0]; } 516 mib:::tcpInDataDupBytes { TCP_in += args[0]; } 517 mib:::tcpInDataUnorderBytes { TCP_in += args[0]; } 518 519 /* 520 * Timer 521 */ 522 profile:::tick-1sec 523 { 524 secs--; 525 } 526 527 /* 528 * Print Report 529 */ 530 profile:::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 */ 568 profile:::tick-1sec 569 /counts == 0/ 570 { 571 exit(0); 572 } 573 574 /* 575 * Cleanup for Ctrl-C 576 */ 577 dtrace:::END 578 { 579 trunc(@out); 580 } 581 ') 582