tcpsnoop.d revision 235368
1#!/usr/sbin/dtrace -Cs 2/* 3 * tcpsnoop.d - snoop TCP network packets by process. 4 * Written using DTrace (Solaris 10 3/05) 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 10 3/05, since it uses the 12 * fbt provider to trace the raw operation of a specific version of the kernel. 13 * In the future, a 'stable' network provider should exist which will allow 14 * this to be written for that and subsequent versions of the kernel. In the 15 * meantime, check for other versions of this script in the /Net directory, 16 * and read the Notes/ALLfbt_notes.txt for more background on fbt. 17 * 18 * $Id: tcpsnoop.d 69 2007-10-04 13:40:00Z brendan $ 19 * 20 * USAGE: tcpsnoop.d 21 * 22 * FIELDS: 23 * UID user ID 24 * PID process ID 25 * CMD command 26 * LADDR local IP address 27 * RADDR remote IP address 28 * LPORT local port number 29 * RPORT remote port number 30 * DR direction 31 * SIZE packet size, bytes 32 * 33 * SEE ALSO: snoop -rS 34 * 35 * COPYRIGHT: Copyright (c) 2005, 2006 Brendan Gregg. 36 * 37 * CDDL HEADER START 38 * 39 * The contents of this file are subject to the terms of the 40 * Common Development and Distribution License, Version 1.0 only 41 * (the "License"). You may not use this file except in compliance 42 * with the License. 43 * 44 * You can obtain a copy of the license at Docs/cddl1.txt 45 * or http://www.opensolaris.org/os/licensing. 46 * See the License for the specific language governing permissions 47 * and limitations under the License. 48 * 49 * CDDL HEADER END 50 * 51 * Author: Brendan Gregg [Sydney, Australia] 52 * 53 * TODO: IPv6 54 * 55 * 09-Jul-2004 Brendan Gregg Created this. 56 * 12-Mar-2005 " " Changed probes, size info now printed. 57 * 02-Jul-2005 " " Many more probes. Renamed "tcpsnoop.d". 58 * 03-Dec-2005 " " Fixed tcp_accept_finish bug, now 100% correct 59 * execname. Thanks Kias Belgaied for expertise. 60 * 20-Apr-2006 " " Fixed SS_TCP_FAST_ACCEPT bug in build 31+. 61 * 20-Apr-2006 " " Last update. 62 */ 63 64#pragma D option quiet 65#pragma D option switchrate=10hz 66 67#include <sys/file.h> 68#include <inet/common.h> 69#include <sys/byteorder.h> 70 71/* 72 * Print header 73 */ 74dtrace:::BEGIN 75{ 76 /* print main headers */ 77 printf("%5s %6s %-15s %5s %2s %-15s %5s %5s %s\n", 78 "UID", "PID", "LADDR", "LPORT", "DR", "RADDR", "RPORT", 79 "SIZE", "CMD"); 80} 81 82/* 83 * TCP Process inbound connections 84 * 85 * 0x00200000 has been hardcoded. It was SS_TCP_FAST_ACCEPT, but was 86 * renamed to SS_DIRECT around build 31. 87 */ 88fbt:sockfs:sotpi_accept:entry 89/(arg1 & FREAD) && (arg1 & FWRITE) && (args[0]->so_state & 0x00200000)/ 90{ 91 self->sop = args[0]; 92} 93 94fbt:sockfs:sotpi_create:return 95/self->sop/ 96{ 97 self->nsop = (struct sonode *)arg1; 98} 99 100fbt:sockfs:sotpi_accept:return 101/self->nsop/ 102{ 103 this->tcpp = (tcp_t *)self->nsop->so_priv; 104 self->connp = (conn_t *)this->tcpp->tcp_connp; 105 tname[(int)self->connp] = execname; 106 tpid[(int)self->connp] = pid; 107 tuid[(int)self->connp] = uid; 108} 109 110fbt:sockfs:sotpi_accept:return 111{ 112 self->nsop = 0; 113 self->sop = 0; 114} 115 116/* 117 * TCP Process outbound connections 118 */ 119fbt:ip:tcp_connect:entry 120{ 121 this->tcpp = (tcp_t *)arg0; 122 self->connp = (conn_t *)this->tcpp->tcp_connp; 123 tname[(int)self->connp] = execname; 124 tpid[(int)self->connp] = pid; 125 tuid[(int)self->connp] = uid; 126} 127 128/* 129 * TCP Data translations 130 */ 131fbt:sockfs:sotpi_accept:return, 132fbt:ip:tcp_connect:return 133/self->connp/ 134{ 135 /* fetch ports */ 136#if defined(_BIG_ENDIAN) 137 self->lport = self->connp->u_port.tcpu_ports.tcpu_lport; 138 self->fport = self->connp->u_port.tcpu_ports.tcpu_fport; 139#else 140 self->lport = BSWAP_16(self->connp->u_port.tcpu_ports.tcpu_lport); 141 self->fport = BSWAP_16(self->connp->u_port.tcpu_ports.tcpu_fport); 142#endif 143 144 /* fetch IPv4 addresses */ 145 this->fad12 = 146 (int)self->connp->connua_v6addr.connua_faddr._S6_un._S6_u8[12]; 147 this->fad13 = 148 (int)self->connp->connua_v6addr.connua_faddr._S6_un._S6_u8[13]; 149 this->fad14 = 150 (int)self->connp->connua_v6addr.connua_faddr._S6_un._S6_u8[14]; 151 this->fad15 = 152 (int)self->connp->connua_v6addr.connua_faddr._S6_un._S6_u8[15]; 153 this->lad12 = 154 (int)self->connp->connua_v6addr.connua_laddr._S6_un._S6_u8[12]; 155 this->lad13 = 156 (int)self->connp->connua_v6addr.connua_laddr._S6_un._S6_u8[13]; 157 this->lad14 = 158 (int)self->connp->connua_v6addr.connua_laddr._S6_un._S6_u8[14]; 159 this->lad15 = 160 (int)self->connp->connua_v6addr.connua_laddr._S6_un._S6_u8[15]; 161 162 /* convert type for use with lltostr() */ 163 this->fad12 = this->fad12 < 0 ? 256 + this->fad12 : this->fad12; 164 this->fad13 = this->fad13 < 0 ? 256 + this->fad13 : this->fad13; 165 this->fad14 = this->fad14 < 0 ? 256 + this->fad14 : this->fad14; 166 this->fad15 = this->fad15 < 0 ? 256 + this->fad15 : this->fad15; 167 this->lad12 = this->lad12 < 0 ? 256 + this->lad12 : this->lad12; 168 this->lad13 = this->lad13 < 0 ? 256 + this->lad13 : this->lad13; 169 this->lad14 = this->lad14 < 0 ? 256 + this->lad14 : this->lad14; 170 this->lad15 = this->lad15 < 0 ? 256 + this->lad15 : this->lad15; 171 172 /* stringify addresses */ 173 self->faddr = strjoin(lltostr(this->fad12), "."); 174 self->faddr = strjoin(self->faddr, strjoin(lltostr(this->fad13), ".")); 175 self->faddr = strjoin(self->faddr, strjoin(lltostr(this->fad14), ".")); 176 self->faddr = strjoin(self->faddr, lltostr(this->fad15 + 0)); 177 self->laddr = strjoin(lltostr(this->lad12), "."); 178 self->laddr = strjoin(self->laddr, strjoin(lltostr(this->lad13), ".")); 179 self->laddr = strjoin(self->laddr, strjoin(lltostr(this->lad14), ".")); 180 self->laddr = strjoin(self->laddr, lltostr(this->lad15 + 0)); 181 182 /* fix direction and save values */ 183 tladdr[(int)self->connp] = self->laddr; 184 tfaddr[(int)self->connp] = self->faddr; 185 tlport[(int)self->connp] = self->lport; 186 tfport[(int)self->connp] = self->fport; 187 188 /* all systems go */ 189 tok[(int)self->connp] = 1; 190} 191 192/* 193 * TCP Clear connp 194 */ 195fbt:ip:tcp_get_conn:return 196{ 197 /* Q_TO_CONN */ 198 this->connp = (conn_t *)arg1; 199 tok[(int)this->connp] = 0; 200 tpid[(int)this->connp] = 0; 201 tuid[(int)this->connp] = 0; 202 tname[(int)this->connp] = 0; 203} 204 205/* 206 * TCP Process "port closed" 207 */ 208fbt:ip:tcp_xmit_early_reset:entry 209{ 210 this->queuep = (queue_t *)`tcp_g_q; /* ` */ 211 this->connp = (conn_t *)this->queuep->q_ptr; 212 this->tcpp = (tcp_t *)this->connp->conn_tcp; 213 214 /* split addresses */ 215 this->ipha = (ipha_t *)args[1]->b_rptr; 216 this->fad15 = (this->ipha->ipha_src & 0xff000000) >> 24; 217 this->fad14 = (this->ipha->ipha_src & 0x00ff0000) >> 16; 218 this->fad13 = (this->ipha->ipha_src & 0x0000ff00) >> 8; 219 this->fad12 = (this->ipha->ipha_src & 0x000000ff); 220 this->lad15 = (this->ipha->ipha_dst & 0xff000000) >> 24; 221 this->lad14 = (this->ipha->ipha_dst & 0x00ff0000) >> 16; 222 this->lad13 = (this->ipha->ipha_dst & 0x0000ff00) >> 8; 223 this->lad12 = (this->ipha->ipha_dst & 0x000000ff); 224 225 /* stringify addresses */ 226 self->faddr = strjoin(lltostr(this->fad12), "."); 227 self->faddr = strjoin(self->faddr, strjoin(lltostr(this->fad13), ".")); 228 self->faddr = strjoin(self->faddr, strjoin(lltostr(this->fad14), ".")); 229 self->faddr = strjoin(self->faddr, lltostr(this->fad15 + 0)); 230 self->laddr = strjoin(lltostr(this->lad12), "."); 231 self->laddr = strjoin(self->laddr, strjoin(lltostr(this->lad13), ".")); 232 self->laddr = strjoin(self->laddr, strjoin(lltostr(this->lad14), ".")); 233 self->laddr = strjoin(self->laddr, lltostr(this->lad15 + 0)); 234 235 self->reset = 1; 236} 237 238/* 239 * TCP Fetch "port closed" ports 240 */ 241fbt:ip:tcp_xchg:entry 242/self->reset/ 243{ 244#if defined(_BIG_ENDIAN) 245 self->lport = (uint16_t)arg0; 246 self->fport = (uint16_t)arg1; 247#else 248 self->lport = BSWAP_16((uint16_t)arg0); 249 self->fport = BSWAP_16((uint16_t)arg1); 250#endif 251 self->lport = BE16_TO_U16(arg0); 252 self->fport = BE16_TO_U16(arg1); 253} 254 255/* 256 * TCP Print "port closed" 257 */ 258fbt:ip:tcp_xmit_early_reset:return 259{ 260 self->name = "<closed>"; 261 self->pid = 0; 262 self->uid = 0; 263 self->size = 54; /* should check trailers */ 264 self->dir = "<-"; 265 printf("%5d %6d %-15s %5d %2s %-15s %5d %5d %s\n", 266 self->uid, self->pid, self->laddr, self->lport, self->dir, 267 self->faddr, self->fport, self->size, self->name); 268 self->dir = "->"; 269 printf("%5d %6d %-15s %5d %2s %-15s %5d %5d %s\n", 270 self->uid, self->pid, self->laddr, self->lport, self->dir, 271 self->faddr, self->fport, self->size, self->name); 272 self->reset = 0; 273 self->size = 0; 274 self->name = 0; 275} 276 277/* 278 * TCP Process Write 279 */ 280fbt:ip:tcp_send_data:entry 281{ 282 self->conn_p = (conn_t *)args[0]->tcp_connp; 283} 284 285fbt:ip:tcp_send_data:entry 286/tok[(int)self->conn_p]/ 287{ 288 self->dir = "->"; 289 self->size = msgdsize(args[2]) + 14; /* should check trailers */ 290 self->uid = tuid[(int)self->conn_p]; 291 self->laddr = tladdr[(int)self->conn_p]; 292 self->faddr = tfaddr[(int)self->conn_p]; 293 self->lport = tlport[(int)self->conn_p]; 294 self->fport = tfport[(int)self->conn_p]; 295 self->ok = 2; 296 297 /* follow inetd -> in.* transitions */ 298 self->name = pid && (tname[(int)self->conn_p] == "inetd") ? 299 execname : tname[(int)self->conn_p]; 300 self->pid = pid && (tname[(int)self->conn_p] == "inetd") ? 301 pid : tpid[(int)self->conn_p]; 302 tname[(int)self->conn_p] = self->name; 303 tpid[(int)self->conn_p] = self->pid; 304} 305 306/* 307 * TCP Process Read 308 */ 309fbt:ip:tcp_rput_data:entry 310{ 311 self->conn_p = (conn_t *)arg0; 312 self->size = msgdsize(args[1]) + 14; /* should check trailers */ 313} 314 315fbt:ip:tcp_rput_data:entry 316/tok[(int)self->conn_p]/ 317{ 318 self->dir = "<-"; 319 self->uid = tuid[(int)self->conn_p]; 320 self->laddr = tladdr[(int)self->conn_p]; 321 self->faddr = tfaddr[(int)self->conn_p]; 322 self->lport = tlport[(int)self->conn_p]; 323 self->fport = tfport[(int)self->conn_p]; 324 self->ok = 2; 325 326 /* follow inetd -> in.* transitions */ 327 self->name = pid && (tname[(int)self->conn_p] == "inetd") ? 328 execname : tname[(int)self->conn_p]; 329 self->pid = pid && (tname[(int)self->conn_p] == "inetd") ? 330 pid : tpid[(int)self->conn_p]; 331 tname[(int)self->conn_p] = self->name; 332 tpid[(int)self->conn_p] = self->pid; 333} 334 335/* 336 * TCP Complete printing outbound handshake 337 */ 338fbt:ip:tcp_connect:return 339/self->connp/ 340{ 341 self->name = tname[(int)self->connp]; 342 self->pid = tpid[(int)self->connp]; 343 self->uid = tuid[(int)self->connp]; 344 self->size = 54; /* should check trailers */ 345 self->dir = "->"; 346 /* this packet occured before connp was fully established */ 347 printf("%5d %6d %-15s %5d %2s %-15s %5d %5d %s\n", 348 self->uid, self->pid, self->laddr, self->lport, self->dir, 349 self->faddr, self->fport, self->size, self->name); 350} 351 352/* 353 * TCP Complete printing inbound handshake 354 */ 355fbt:sockfs:sotpi_accept:return 356/self->connp/ 357{ 358 self->name = tname[(int)self->connp]; 359 self->pid = tpid[(int)self->connp]; 360 self->uid = tuid[(int)self->connp]; 361 self->size = 54; /* should check trailers */ 362 /* these packets occured before connp was fully established */ 363 self->dir = "<-"; 364 printf("%5d %6d %-15s %5d %2s %-15s %5d %5d %s\n", 365 self->uid, self->pid, self->laddr, self->lport, self->dir, 366 self->faddr, self->fport, self->size, self->name); 367 self->dir = "->"; 368 printf("%5d %6d %-15s %5d %2s %-15s %5d %5d %s\n", 369 self->uid, self->pid, self->laddr, self->lport, self->dir, 370 self->faddr, self->fport, self->size, self->name); 371 self->dir = "<-"; 372 printf("%5d %6d %-15s %5d %2s %-15s %5d %5d %s\n", 373 self->uid, self->pid, self->laddr, self->lport, self->dir, 374 self->faddr, self->fport, self->size, self->name); 375} 376 377/* 378 * Print output 379 */ 380fbt:ip:tcp_send_data:entry, 381fbt:ip:tcp_rput_data:entry 382/self->ok == 2/ 383{ 384 /* print output line */ 385 printf("%5d %6d %-15s %5d %2s %-15s %5d %5d %s\n", 386 self->uid, self->pid, self->laddr, self->lport, self->dir, 387 self->faddr, self->fport, self->size, self->name); 388} 389 390/* 391 * TCP Clear connect variables 392 */ 393fbt:sockfs:sotpi_accept:return, 394fbt:ip:tcp_connect:return 395/self->connp/ 396{ 397 self->faddr = 0; 398 self->laddr = 0; 399 self->fport = 0; 400 self->lport = 0; 401 self->connp = 0; 402 self->name = 0; 403 self->pid = 0; 404 self->uid = 0; 405} 406 407/* 408 * TCP Clear r/w variables 409 */ 410fbt:ip:tcp_send_data:entry, 411fbt:ip:tcp_rput_data:entry 412{ 413 self->ok = 0; 414 self->dir = 0; 415 self->uid = 0; 416 self->pid = 0; 417 self->size = 0; 418 self->name = 0; 419 self->lport = 0; 420 self->fport = 0; 421 self->laddr = 0; 422 self->faddr = 0; 423 self->conn_p = 0; 424} 425