1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 *
25 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
26 */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <ctype.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <string.h>
34 #include <sys/types.h>
35 #include <time.h>
36 #include <sys/time.h>
37 #include <sys/bufmod.h>
38 #include <setjmp.h>
39 #include <stdarg.h>
40 #include <sys/socket.h>
41 #include <net/if.h>
42 #include <netinet/in_systm.h>
43 #include <netinet/in.h>
44 #include <netinet/ip.h>
45 #include <netinet/if_ether.h>
46 #include <rpc/types.h>
47 #include <rpc/xdr.h>
48 #include <inttypes.h>
49
50 #include "snoop.h"
51
52 char *dlc_header;
53 char *src_name, *dst_name;
54 int pi_frame;
55 int pi_time_hour;
56 int pi_time_min;
57 int pi_time_sec;
58 int pi_time_usec;
59
60 #ifndef MIN
61 #define MIN(a, b) ((a) < (b) ? (a) : (b))
62 #endif
63
64 static void hexdump(char *, int);
65
66 /*
67 * This routine invokes the packet interpreters
68 * on a packet. There's some messing around
69 * setting up a few packet-externals before
70 * starting with the ethernet interpreter.
71 * Yes, we assume here that all packets will
72 * be ethernet packets.
73 */
74 void
process_pkt(struct sb_hdr * hdrp,char * pktp,int num,int flags)75 process_pkt(struct sb_hdr *hdrp, char *pktp, int num, int flags)
76 {
77 int drops, pktlen;
78 struct timeval *tvp;
79 struct tm *tm;
80 extern int x_offset;
81 extern int x_length;
82 int offset, length;
83 static struct timeval ptv;
84
85 if (hdrp == NULL)
86 return;
87
88 tvp = &hdrp->sbh_timestamp;
89 if (ptv.tv_sec == 0)
90 ptv = *tvp;
91 drops = hdrp->sbh_drops;
92 pktlen = hdrp->sbh_msglen;
93 if (pktlen <= 0)
94 return;
95
96 /* set up externals */
97 dlc_header = pktp;
98 pi_frame = num;
99 tm = localtime(&tvp->tv_sec);
100 pi_time_hour = tm->tm_hour;
101 pi_time_min = tm->tm_min;
102 pi_time_sec = tm->tm_sec;
103 pi_time_usec = tvp->tv_usec;
104
105 src_name = "?";
106 dst_name = "*";
107
108 click(hdrp->sbh_origlen);
109
110 (*interface->interpreter)(flags, dlc_header, hdrp->sbh_msglen,
111 hdrp->sbh_origlen);
112
113 show_pktinfo(flags, num, src_name, dst_name, &ptv, tvp, drops,
114 hdrp->sbh_origlen);
115
116 if (x_offset >= 0) {
117 offset = MIN(x_offset, hdrp->sbh_msglen);
118 offset -= (offset % 2); /* round down */
119 length = MIN(hdrp->sbh_msglen - offset, x_length);
120
121 hexdump(dlc_header + offset, length);
122 }
123
124 ptv = *tvp;
125 }
126
127
128 /*
129 * *************************************************************
130 * The following routines constitute a library
131 * used by the packet interpreters to facilitate
132 * the display of packet data. This library
133 * of routines helps provide a consistent
134 * "look and feel".
135 */
136
137
138 /*
139 * Display the value of a flag bit in
140 * a byte together with some text that
141 * corresponds to its value - whether
142 * true or false.
143 */
144 char *
getflag(int val,int mask,char * s_true,char * s_false)145 getflag(int val, int mask, char *s_true, char *s_false)
146 {
147 static char buff[80];
148 char *p;
149 int set;
150
151 (void) strcpy(buff, ".... .... = ");
152 if (s_false == NULL)
153 s_false = s_true;
154
155 for (p = &buff[8]; p >= buff; p--) {
156 if (*p == ' ')
157 p--;
158 if (mask & 0x1) {
159 set = val & mask & 0x1;
160 *p = set ? '1':'0';
161 (void) strcat(buff, set ? s_true: s_false);
162 break;
163 }
164 mask >>= 1;
165 val >>= 1;
166 }
167 return (buff);
168 }
169
170 XDR xdrm;
171 jmp_buf xdr_err;
172 int xdr_totlen;
173 char *prot_prefix;
174 char *prot_nest_prefix = "";
175 char *prot_title;
176
177 void
show_header(char * pref,char * str,int len)178 show_header(char *pref, char *str, int len)
179 {
180 prot_prefix = pref;
181 prot_title = str;
182 (void) sprintf(get_detail_line(0, len), "%s%s----- %s -----",
183 prot_nest_prefix, pref, str);
184 }
185
186 void
xdr_init(char * addr,int len)187 xdr_init(char *addr, int len)
188 {
189 xdr_totlen = len;
190 xdrmem_create(&xdrm, addr, len, XDR_DECODE);
191 }
192
193 /* Note: begin+end are ignored in get_detail_line */
194 char *
get_line(int begin,int end)195 get_line(int begin, int end)
196 {
197 char *line;
198
199 line = get_detail_line(begin, end);
200 (void) strcpy(line, prot_nest_prefix);
201 (void) strcat(line, prot_prefix);
202 return (line + strlen(line));
203 }
204
205 int
get_line_remain(void)206 get_line_remain(void)
207 {
208 return (MAXLINE - strlen(prot_nest_prefix) - strlen(prot_prefix));
209 }
210
211 void
show_line(char * str)212 show_line(char *str)
213 {
214 (void) strlcpy(get_line(0, 0), str, get_line_remain());
215 }
216
217 void
show_printf(char * fmt,...)218 show_printf(char *fmt, ...)
219 {
220 va_list ap;
221
222 va_start(ap, fmt);
223 (void) vsnprintf(get_line(0, 0), get_line_remain(), fmt, ap);
224 va_end(ap);
225 }
226
227 char
getxdr_char()228 getxdr_char()
229 {
230 char s;
231
232 if (xdr_char(&xdrm, &s))
233 return (s);
234 longjmp(xdr_err, 1);
235 /* NOTREACHED */
236 }
237
238 char
showxdr_char(char * fmt)239 showxdr_char(char *fmt)
240 {
241 int pos; char val;
242
243 pos = getxdr_pos();
244 val = getxdr_char();
245 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val);
246 return (val);
247 }
248
249 uchar_t
getxdr_u_char()250 getxdr_u_char()
251 {
252 uchar_t s;
253
254 if (xdr_u_char(&xdrm, &s))
255 return (s);
256 longjmp(xdr_err, 1);
257 /* NOTREACHED */
258 }
259
260 uchar_t
showxdr_u_char(char * fmt)261 showxdr_u_char(char *fmt)
262 {
263 int pos;
264 uchar_t val;
265
266 pos = getxdr_pos();
267 val = getxdr_u_char();
268 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val);
269 return (val);
270 }
271
272 short
getxdr_short()273 getxdr_short()
274 {
275 short s;
276
277 if (xdr_short(&xdrm, &s))
278 return (s);
279 longjmp(xdr_err, 1);
280 /* NOTREACHED */
281 }
282
283 short
showxdr_short(char * fmt)284 showxdr_short(char *fmt)
285 {
286 int pos; short val;
287
288 pos = getxdr_pos();
289 val = getxdr_short();
290 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val);
291 return (val);
292 }
293
294 ushort_t
getxdr_u_short()295 getxdr_u_short()
296 {
297 ushort_t s;
298
299 if (xdr_u_short(&xdrm, &s))
300 return (s);
301 longjmp(xdr_err, 1);
302 /* NOTREACHED */
303 }
304
305 ushort_t
showxdr_u_short(char * fmt)306 showxdr_u_short(char *fmt)
307 {
308 int pos;
309 ushort_t val;
310
311 pos = getxdr_pos();
312 val = getxdr_u_short();
313 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val);
314 return (val);
315 }
316
317 long
getxdr_long()318 getxdr_long()
319 {
320 long l;
321
322 if (xdr_long(&xdrm, &l))
323 return (l);
324 longjmp(xdr_err, 1);
325 /* NOTREACHED */
326 }
327
328 long
showxdr_long(char * fmt)329 showxdr_long(char *fmt)
330 {
331 int pos; long val;
332
333 pos = getxdr_pos();
334 val = getxdr_long();
335 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val);
336 return (val);
337 }
338
339 ulong_t
getxdr_u_long()340 getxdr_u_long()
341 {
342 ulong_t l;
343
344 if (xdr_u_long(&xdrm, &l))
345 return (l);
346 longjmp(xdr_err, 1);
347 /* NOTREACHED */
348 }
349
350 ulong_t
showxdr_u_long(char * fmt)351 showxdr_u_long(char *fmt)
352 {
353 int pos;
354 ulong_t val;
355
356 pos = getxdr_pos();
357 val = getxdr_u_long();
358 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val);
359 return (val);
360 }
361
362 longlong_t
getxdr_longlong()363 getxdr_longlong()
364 {
365 longlong_t l;
366
367 if (xdr_longlong_t(&xdrm, &l))
368 return (l);
369 longjmp(xdr_err, 1);
370 /* NOTREACHED */
371 }
372
373 longlong_t
showxdr_longlong(char * fmt)374 showxdr_longlong(char *fmt)
375 {
376 int pos; longlong_t val;
377
378 pos = getxdr_pos();
379 val = getxdr_longlong();
380 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val);
381 return (val);
382 }
383
384 u_longlong_t
getxdr_u_longlong()385 getxdr_u_longlong()
386 {
387 u_longlong_t l;
388
389 if (xdr_u_longlong_t(&xdrm, &l))
390 return (l);
391 longjmp(xdr_err, 1);
392 /* NOTREACHED */
393 }
394
395 u_longlong_t
showxdr_u_longlong(char * fmt)396 showxdr_u_longlong(char *fmt)
397 {
398 int pos; u_longlong_t val;
399
400 pos = getxdr_pos();
401 val = getxdr_u_longlong();
402 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val);
403 return (val);
404 }
405
406 bool_t
getxdr_bool()407 getxdr_bool()
408 {
409 bool_t b;
410
411 if (xdr_bool(&xdrm, &b))
412 return (b);
413 longjmp(xdr_err, 1);
414 /* NOTREACHED */
415 }
416
417 bool_t
showxdr_bool(char * fmt)418 showxdr_bool(char *fmt)
419 {
420 int pos; bool_t val;
421
422 pos = getxdr_pos();
423 val = getxdr_bool();
424 (void) sprintf(get_line(pos, getxdr_pos()), fmt,
425 val ? "True" : "False");
426 return (val);
427 }
428
429 char *
getxdr_opaque(char * p,int len)430 getxdr_opaque(char *p, int len)
431 {
432 if (xdr_opaque(&xdrm, p, len))
433 return (p);
434 longjmp(xdr_err, 1);
435 /* NOTREACHED */
436 }
437
438 char *
getxdr_string(char * p,int len)439 getxdr_string(char *p, /* len+1 bytes or longer */
440 int len)
441 {
442 if (xdr_string(&xdrm, &p, len))
443 return (p);
444 longjmp(xdr_err, 1);
445 /* NOTREACHED */
446 }
447
448 char *
showxdr_string(int len,char * fmt)449 showxdr_string(int len, /* XDR length */
450 char *fmt)
451 {
452 static int buff_len = 0;
453 static char *buff = NULL;
454 int pos;
455
456 /*
457 * XDR strings don't necessarily have a trailing null over the
458 * wire. However, the XDR code will put one in for us. Make sure
459 * we have allocated room for it.
460 */
461 len++;
462
463 if ((len > buff_len) || (buff_len == 0)) {
464 if (buff)
465 free(buff);
466 if ((buff = (char *)malloc(len)) == NULL)
467 pr_err("showxdr_string: no mem");
468 buff_len = len;
469 }
470 pos = getxdr_pos();
471 getxdr_string(buff, len);
472 (void) strcpy(buff+60, "...");
473 (void) sprintf(get_line(pos, getxdr_pos()), fmt, buff);
474 return (buff);
475 }
476
477 char *
getxdr_bytes(uint_t * lenp)478 getxdr_bytes(uint_t *lenp)
479 {
480 static char buff[1024];
481 char *p = buff;
482
483 if (xdr_bytes(&xdrm, &p, lenp, 1024))
484 return (buff);
485 longjmp(xdr_err, 1);
486 /* NOTREACHED */
487 }
488
489 char *
getxdr_context(char * p,int len)490 getxdr_context(char *p, int len)
491 {
492 ushort_t size;
493
494 size = getxdr_u_short();
495 if (((int)size > 0) && ((int)size < len) && getxdr_opaque(p, size))
496 return (p);
497 longjmp(xdr_err, 1);
498 /* NOTREACHED */
499 }
500
501 char *
showxdr_context(char * fmt)502 showxdr_context(char *fmt)
503 {
504 ushort_t size;
505 static char buff[1024];
506 int pos;
507
508 pos = getxdr_pos();
509 size = getxdr_u_short();
510 if (((int)size > 0) && ((int)size < 1024) &&
511 getxdr_opaque(buff, size)) {
512 (void) sprintf(get_line(pos, getxdr_pos()), fmt, buff);
513 return (buff);
514 }
515 longjmp(xdr_err, 1);
516 /* NOTREACHED */
517 }
518
519 enum_t
getxdr_enum()520 getxdr_enum()
521 {
522 enum_t e;
523
524 if (xdr_enum(&xdrm, &e))
525 return (e);
526 longjmp(xdr_err, 1);
527 /* NOTREACHED */
528 }
529
530 void
xdr_skip(int delta)531 xdr_skip(int delta)
532 {
533 uint_t pos;
534 if (delta % 4 != 0 || delta < 0)
535 longjmp(xdr_err, 1);
536 /* Check for overflow */
537 pos = xdr_getpos(&xdrm);
538 if ((pos + delta) < pos)
539 longjmp(xdr_err, 1);
540 /* xdr_setpos() checks for buffer overrun */
541 if (xdr_setpos(&xdrm, pos + delta) == FALSE)
542 longjmp(xdr_err, 1);
543 }
544
545 int
getxdr_pos()546 getxdr_pos()
547 {
548 return (xdr_getpos(&xdrm));
549 }
550
551 void
setxdr_pos(int pos)552 setxdr_pos(int pos)
553 {
554 xdr_setpos(&xdrm, pos);
555 }
556
557 void
show_space()558 show_space()
559 {
560 (void) get_line(0, 0);
561 }
562
563 void
show_trailer()564 show_trailer()
565 {
566 show_space();
567 }
568
569 char *
getxdr_date()570 getxdr_date()
571 {
572 time_t sec;
573 int usec;
574 static char buff[64];
575 char *p;
576 struct tm my_time; /* private buffer to avoid collision */
577 /* between gmtime and strftime */
578 struct tm *tmp;
579
580 sec = getxdr_long();
581 usec = getxdr_long();
582 if (sec == -1)
583 return ("-1 ");
584
585 if (sec < 3600 * 24 * 365) { /* assume not a date */
586 (void) sprintf(buff, "%d.%06d", sec, usec);
587 } else {
588 tmp = gmtime(&sec);
589 (void) memcpy(&my_time, tmp, sizeof (struct tm));
590 strftime(buff, sizeof (buff), "%d-%h-%y %T.", &my_time);
591 p = buff + strlen(buff);
592 (void) sprintf(p, "%06d GMT", usec);
593 }
594 return (buff);
595 }
596
597 char *
showxdr_date(char * fmt)598 showxdr_date(char *fmt)
599 {
600 int pos;
601 char *p;
602
603 pos = getxdr_pos();
604 p = getxdr_date();
605 (void) sprintf(get_line(pos, getxdr_pos()), fmt, p);
606 return (p);
607 }
608
609 char *
getxdr_date_ns(void)610 getxdr_date_ns(void)
611 {
612 time_t sec, nsec;
613
614 sec = getxdr_long();
615 nsec = getxdr_long();
616 if (sec == -1)
617 return ("-1 ");
618 else
619 return (format_time(sec, nsec));
620 }
621
622 /*
623 * Format the given time.
624 */
625 char *
format_time(int64_t sec,uint32_t nsec)626 format_time(int64_t sec, uint32_t nsec)
627 {
628 static char buff[64];
629 char *p;
630 struct tm my_time; /* private buffer to avoid collision */
631 /* between gmtime and strftime */
632 struct tm *tmp;
633
634 if (sec < 3600 * 24 * 365) {
635 /* assume not a date; includes negative times */
636 (void) sprintf(buff, "%lld.%06d", sec, nsec);
637 } else if (sec > INT32_MAX) {
638 /*
639 * XXX No routines are available yet for formatting 64-bit
640 * times.
641 */
642 (void) sprintf(buff, "%lld.%06d", sec, nsec);
643 } else {
644 time_t sec32 = (time_t)sec;
645
646 tmp = gmtime(&sec32);
647 memcpy(&my_time, tmp, sizeof (struct tm));
648 strftime(buff, sizeof (buff), "%d-%h-%y %T.", &my_time);
649 p = buff + strlen(buff);
650 (void) sprintf(p, "%09d GMT", nsec);
651 }
652 return (buff);
653 }
654
655 char *
showxdr_date_ns(char * fmt)656 showxdr_date_ns(char *fmt)
657 {
658 int pos;
659 char *p;
660
661 pos = getxdr_pos();
662 p = getxdr_date_ns();
663 (void) sprintf(get_line(pos, getxdr_pos()), fmt, p);
664 return (p);
665 }
666
667 char *
getxdr_time()668 getxdr_time()
669 {
670 time_t sec;
671 static char buff[64];
672 struct tm my_time; /* private buffer to avoid collision */
673 /* between gmtime and strftime */
674 struct tm *tmp;
675
676 sec = getxdr_long();
677 if (sec == -1)
678 return ("-1 ");
679
680 if (sec < 3600 * 24 * 365) { /* assume not a date */
681 (void) sprintf(buff, "%d", sec);
682 } else {
683 tmp = gmtime(&sec);
684 memcpy(&my_time, tmp, sizeof (struct tm));
685 strftime(buff, sizeof (buff), "%d-%h-%y %T", &my_time);
686 }
687 return (buff);
688 }
689
690 char *
showxdr_time(char * fmt)691 showxdr_time(char *fmt)
692 {
693 int pos;
694 char *p;
695
696 pos = getxdr_pos();
697 p = getxdr_time();
698 (void) sprintf(get_line(pos, getxdr_pos()), fmt, p);
699 return (p);
700 }
701
702 char *
getxdr_hex(int len)703 getxdr_hex(int len)
704 {
705 int i, j;
706 static char hbuff[1024];
707 char rbuff[1024];
708 static char *hexstr = "0123456789ABCDEF";
709 char toobig = 0;
710
711 if (len == 0) {
712 hbuff[0] = '\0';
713 return (hbuff);
714 }
715 if (len > 1024)
716 len = 1024;
717 if (len < 0 || xdr_opaque(&xdrm, rbuff, len) == FALSE) {
718 longjmp(xdr_err, 1);
719 }
720
721 if (len * 2 > sizeof (hbuff)) {
722 toobig++;
723 len = sizeof (hbuff) / 2;
724 }
725
726 j = 0;
727 for (i = 0; i < len; i++) {
728 hbuff[j++] = hexstr[rbuff[i] >> 4 & 0x0f];
729 hbuff[j++] = hexstr[rbuff[i] & 0x0f];
730 }
731
732 if (toobig) {
733 hbuff[len * 2 - strlen("<Too Long>")] = '\0';
734 strcat(hbuff, "<Too Long>");
735 } else
736 hbuff[j] = '\0';
737
738 return (hbuff);
739 }
740
741 char *
showxdr_hex(int len,char * fmt)742 showxdr_hex(int len, char *fmt)
743 {
744 int pos;
745 char *p;
746
747 pos = getxdr_pos();
748 p = getxdr_hex(len);
749 (void) sprintf(get_line(pos, getxdr_pos()), fmt, p);
750 return (p);
751 }
752
753 static void
hexdump(char * data,int datalen)754 hexdump(char *data, int datalen)
755 {
756 char *p;
757 ushort_t *p16 = (ushort_t *)data;
758 char *p8 = data;
759 int i, left, len;
760 int chunk = 16; /* 16 bytes per line */
761
762 printf("\n");
763
764 for (p = data; p < data + datalen; p += chunk) {
765 printf("\t%4d: ", p - data);
766 left = (data + datalen) - p;
767 len = MIN(chunk, left);
768 for (i = 0; i < (len / 2); i++)
769 printf("%04x ", ntohs(*p16++) & 0xffff);
770 if (len % 2) {
771 printf("%02x ", *((unsigned char *)p16));
772 }
773 for (i = 0; i < (chunk - left) / 2; i++)
774 printf(" ");
775
776 printf(" ");
777 for (i = 0; i < len; i++, p8++)
778 printf("%c", isprint(*p8) ? *p8 : '.');
779 printf("\n");
780 }
781
782 printf("\n");
783 }
784
785 char *
show_string(const char * str,int dlen,int maxlen)786 show_string(const char *str, int dlen, int maxlen)
787 /*
788 * Prints len bytes from str enclosed in quotes.
789 * If len is negative, length is taken from strlen(str).
790 * No more than maxlen bytes will be printed. Longer
791 * strings are flagged with ".." after the closing quote.
792 * Non-printing characters are converted to C-style escape
793 * codes or octal digits.
794 */
795 {
796 #define TBSIZE 256
797 static char tbuff[TBSIZE];
798 const char *p;
799 char *pp;
800 int printable = 0;
801 int c, len;
802
803 len = dlen > maxlen ? maxlen : dlen;
804 dlen = len;
805
806 for (p = str, pp = tbuff; len; p++, len--) {
807 switch (c = *p & 0xFF) {
808 case '\n': (void) strcpy(pp, "\\n"); pp += 2; break;
809 case '\b': (void) strcpy(pp, "\\b"); pp += 2; break;
810 case '\t': (void) strcpy(pp, "\\t"); pp += 2; break;
811 case '\r': (void) strcpy(pp, "\\r"); pp += 2; break;
812 case '\f': (void) strcpy(pp, "\\f"); pp += 2; break;
813 default:
814 if (isascii(c) && isprint(c)) {
815 *pp++ = c;
816 printable++;
817 } else {
818 (void) snprintf(pp, TBSIZE - (pp - tbuff),
819 isdigit(*(p + 1)) ?
820 "\\%03o" : "\\%o", c);
821 pp += strlen(pp);
822 }
823 break;
824 }
825 *pp = '\0';
826 /*
827 * Check for overflow of temporary buffer. Allow for
828 * the next character to be a \nnn followed by a trailing
829 * null. If not, then just bail with what we have.
830 */
831 if (pp + 5 >= &tbuff[TBSIZE]) {
832 break;
833 }
834 }
835 return (printable > dlen / 2 ? tbuff : "");
836 }
837