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