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