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
26 #pragma ident "%Z%%M% %I% %E% SMI"
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 <varargs.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 char *
get_line(int begin,int end)194 get_line(int begin, int end)
195 {
196 char *line;
197
198 line = get_detail_line(begin, end);
199 (void) strcpy(line, prot_nest_prefix);
200 (void) strcat(line, prot_prefix);
201 return (line + strlen(line));
202 }
203
204 int
get_line_remain(void)205 get_line_remain(void)
206 {
207 return (MAXLINE - strlen(prot_nest_prefix) - strlen(prot_prefix));
208 }
209
210 void
show_line(char * str)211 show_line(char *str)
212 {
213 (void) strcpy(get_line(0, 0), str);
214 }
215
216 char
getxdr_char()217 getxdr_char()
218 {
219 char s;
220
221 if (xdr_char(&xdrm, &s))
222 return (s);
223 longjmp(xdr_err, 1);
224 /* NOTREACHED */
225 }
226
227 char
showxdr_char(char * fmt)228 showxdr_char(char *fmt)
229 {
230 int pos; char val;
231
232 pos = getxdr_pos();
233 val = getxdr_char();
234 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val);
235 return (val);
236 }
237
238 uchar_t
getxdr_u_char()239 getxdr_u_char()
240 {
241 uchar_t s;
242
243 if (xdr_u_char(&xdrm, &s))
244 return (s);
245 longjmp(xdr_err, 1);
246 /* NOTREACHED */
247 }
248
249 uchar_t
showxdr_u_char(char * fmt)250 showxdr_u_char(char *fmt)
251 {
252 int pos;
253 uchar_t val;
254
255 pos = getxdr_pos();
256 val = getxdr_u_char();
257 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val);
258 return (val);
259 }
260
261 short
getxdr_short()262 getxdr_short()
263 {
264 short s;
265
266 if (xdr_short(&xdrm, &s))
267 return (s);
268 longjmp(xdr_err, 1);
269 /* NOTREACHED */
270 }
271
272 short
showxdr_short(char * fmt)273 showxdr_short(char *fmt)
274 {
275 int pos; short val;
276
277 pos = getxdr_pos();
278 val = getxdr_short();
279 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val);
280 return (val);
281 }
282
283 ushort_t
getxdr_u_short()284 getxdr_u_short()
285 {
286 ushort_t s;
287
288 if (xdr_u_short(&xdrm, &s))
289 return (s);
290 longjmp(xdr_err, 1);
291 /* NOTREACHED */
292 }
293
294 ushort_t
showxdr_u_short(char * fmt)295 showxdr_u_short(char *fmt)
296 {
297 int pos;
298 ushort_t val;
299
300 pos = getxdr_pos();
301 val = getxdr_u_short();
302 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val);
303 return (val);
304 }
305
306 long
getxdr_long()307 getxdr_long()
308 {
309 long l;
310
311 if (xdr_long(&xdrm, &l))
312 return (l);
313 longjmp(xdr_err, 1);
314 /* NOTREACHED */
315 }
316
317 long
showxdr_long(char * fmt)318 showxdr_long(char *fmt)
319 {
320 int pos; long val;
321
322 pos = getxdr_pos();
323 val = getxdr_long();
324 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val);
325 return (val);
326 }
327
328 ulong_t
getxdr_u_long()329 getxdr_u_long()
330 {
331 ulong_t l;
332
333 if (xdr_u_long(&xdrm, &l))
334 return (l);
335 longjmp(xdr_err, 1);
336 /* NOTREACHED */
337 }
338
339 ulong_t
showxdr_u_long(char * fmt)340 showxdr_u_long(char *fmt)
341 {
342 int pos;
343 ulong_t val;
344
345 pos = getxdr_pos();
346 val = getxdr_u_long();
347 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val);
348 return (val);
349 }
350
351 longlong_t
getxdr_longlong()352 getxdr_longlong()
353 {
354 longlong_t l;
355
356 if (xdr_longlong_t(&xdrm, &l))
357 return (l);
358 longjmp(xdr_err, 1);
359 /* NOTREACHED */
360 }
361
362 longlong_t
showxdr_longlong(char * fmt)363 showxdr_longlong(char *fmt)
364 {
365 int pos; longlong_t val;
366
367 pos = getxdr_pos();
368 val = getxdr_longlong();
369 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val);
370 return (val);
371 }
372
373 u_longlong_t
getxdr_u_longlong()374 getxdr_u_longlong()
375 {
376 u_longlong_t l;
377
378 if (xdr_u_longlong_t(&xdrm, &l))
379 return (l);
380 longjmp(xdr_err, 1);
381 /* NOTREACHED */
382 }
383
384 u_longlong_t
showxdr_u_longlong(char * fmt)385 showxdr_u_longlong(char *fmt)
386 {
387 int pos; u_longlong_t val;
388
389 pos = getxdr_pos();
390 val = getxdr_u_longlong();
391 (void) sprintf(get_line(pos, getxdr_pos()), fmt, val);
392 return (val);
393 }
394
395 bool_t
getxdr_bool()396 getxdr_bool()
397 {
398 bool_t b;
399
400 if (xdr_bool(&xdrm, &b))
401 return (b);
402 longjmp(xdr_err, 1);
403 /* NOTREACHED */
404 }
405
406 bool_t
showxdr_bool(char * fmt)407 showxdr_bool(char *fmt)
408 {
409 int pos; bool_t val;
410
411 pos = getxdr_pos();
412 val = getxdr_bool();
413 (void) sprintf(get_line(pos, getxdr_pos()), fmt,
414 val ? "True" : "False");
415 return (val);
416 }
417
418 char *
getxdr_opaque(char * p,int len)419 getxdr_opaque(char *p, int len)
420 {
421 if (xdr_opaque(&xdrm, p, len))
422 return (p);
423 longjmp(xdr_err, 1);
424 /* NOTREACHED */
425 }
426
427 char *
getxdr_string(char * p,int len)428 getxdr_string(char *p, /* len+1 bytes or longer */
429 int len)
430 {
431 if (xdr_string(&xdrm, &p, len))
432 return (p);
433 longjmp(xdr_err, 1);
434 /* NOTREACHED */
435 }
436
437 char *
showxdr_string(int len,char * fmt)438 showxdr_string(int len, /* XDR length */
439 char *fmt)
440 {
441 static int buff_len = 0;
442 static char *buff = NULL;
443 int pos;
444
445 /*
446 * XDR strings don't necessarily have a trailing null over the
447 * wire. However, the XDR code will put one in for us. Make sure
448 * we have allocated room for it.
449 */
450 len++;
451
452 if ((len > buff_len) || (buff_len == 0)) {
453 if (buff)
454 free(buff);
455 if ((buff = (char *)malloc(len)) == NULL)
456 pr_err("showxdr_string: no mem");
457 buff_len = len;
458 }
459 pos = getxdr_pos();
460 getxdr_string(buff, len);
461 (void) strcpy(buff+60, "...");
462 (void) sprintf(get_line(pos, getxdr_pos()), fmt, buff);
463 return (buff);
464 }
465
466 char *
getxdr_bytes(uint_t * lenp)467 getxdr_bytes(uint_t *lenp)
468 {
469 static char buff[1024];
470 char *p = buff;
471
472 if (xdr_bytes(&xdrm, &p, lenp, 1024))
473 return (buff);
474 longjmp(xdr_err, 1);
475 /* NOTREACHED */
476 }
477
478 char *
getxdr_context(char * p,int len)479 getxdr_context(char *p, int len)
480 {
481 ushort_t size;
482
483 size = getxdr_u_short();
484 if (((int)size > 0) && ((int)size < len) && getxdr_opaque(p, size))
485 return (p);
486 longjmp(xdr_err, 1);
487 /* NOTREACHED */
488 }
489
490 char *
showxdr_context(char * fmt)491 showxdr_context(char *fmt)
492 {
493 ushort_t size;
494 static char buff[1024];
495 int pos;
496
497 pos = getxdr_pos();
498 size = getxdr_u_short();
499 if (((int)size > 0) && ((int)size < 1024) &&
500 getxdr_opaque(buff, size)) {
501 (void) sprintf(get_line(pos, getxdr_pos()), fmt, buff);
502 return (buff);
503 }
504 longjmp(xdr_err, 1);
505 /* NOTREACHED */
506 }
507
508 enum_t
getxdr_enum()509 getxdr_enum()
510 {
511 enum_t e;
512
513 if (xdr_enum(&xdrm, &e))
514 return (e);
515 longjmp(xdr_err, 1);
516 /* NOTREACHED */
517 }
518
519 void
xdr_skip(int delta)520 xdr_skip(int delta)
521 {
522 uint_t pos;
523 if (delta % 4 != 0 || delta < 0)
524 longjmp(xdr_err, 1);
525 /* Check for overflow */
526 pos = xdr_getpos(&xdrm);
527 if ((pos + delta) < pos)
528 longjmp(xdr_err, 1);
529 /* xdr_setpos() checks for buffer overrun */
530 if (xdr_setpos(&xdrm, pos + delta) == FALSE)
531 longjmp(xdr_err, 1);
532 }
533
534 int
getxdr_pos()535 getxdr_pos()
536 {
537 return (xdr_getpos(&xdrm));
538 }
539
540 void
setxdr_pos(int pos)541 setxdr_pos(int pos)
542 {
543 xdr_setpos(&xdrm, pos);
544 }
545
546 void
show_space()547 show_space()
548 {
549 (void) get_line(0, 0);
550 }
551
552 void
show_trailer()553 show_trailer()
554 {
555 show_space();
556 }
557
558 char *
getxdr_date()559 getxdr_date()
560 {
561 time_t sec;
562 int usec;
563 static char buff[64];
564 char *p;
565 struct tm my_time; /* private buffer to avoid collision */
566 /* between gmtime and strftime */
567 struct tm *tmp;
568
569 sec = getxdr_long();
570 usec = getxdr_long();
571 if (sec == -1)
572 return ("-1 ");
573
574 if (sec < 3600 * 24 * 365) { /* assume not a date */
575 (void) sprintf(buff, "%d.%06d", sec, usec);
576 } else {
577 tmp = gmtime(&sec);
578 (void) memcpy(&my_time, tmp, sizeof (struct tm));
579 strftime(buff, sizeof (buff), "%d-%h-%y %T.", &my_time);
580 p = buff + strlen(buff);
581 (void) sprintf(p, "%06d GMT", usec);
582 }
583 return (buff);
584 }
585
586 char *
showxdr_date(char * fmt)587 showxdr_date(char *fmt)
588 {
589 int pos;
590 char *p;
591
592 pos = getxdr_pos();
593 p = getxdr_date();
594 (void) sprintf(get_line(pos, getxdr_pos()), fmt, p);
595 return (p);
596 }
597
598 char *
getxdr_date_ns(void)599 getxdr_date_ns(void)
600 {
601 time_t sec, nsec;
602
603 sec = getxdr_long();
604 nsec = getxdr_long();
605 if (sec == -1)
606 return ("-1 ");
607 else
608 return (format_time(sec, nsec));
609 }
610
611 /*
612 * Format the given time.
613 */
614 char *
format_time(int64_t sec,uint32_t nsec)615 format_time(int64_t sec, uint32_t nsec)
616 {
617 static char buff[64];
618 char *p;
619 struct tm my_time; /* private buffer to avoid collision */
620 /* between gmtime and strftime */
621 struct tm *tmp;
622
623 if (sec < 3600 * 24 * 365) {
624 /* assume not a date; includes negative times */
625 (void) sprintf(buff, "%lld.%06d", sec, nsec);
626 } else if (sec > INT32_MAX) {
627 /*
628 * XXX No routines are available yet for formatting 64-bit
629 * times.
630 */
631 (void) sprintf(buff, "%lld.%06d", sec, nsec);
632 } else {
633 time_t sec32 = (time_t)sec;
634
635 tmp = gmtime(&sec32);
636 memcpy(&my_time, tmp, sizeof (struct tm));
637 strftime(buff, sizeof (buff), "%d-%h-%y %T.", &my_time);
638 p = buff + strlen(buff);
639 (void) sprintf(p, "%09d GMT", nsec);
640 }
641 return (buff);
642 }
643
644 char *
showxdr_date_ns(char * fmt)645 showxdr_date_ns(char *fmt)
646 {
647 int pos;
648 char *p;
649
650 pos = getxdr_pos();
651 p = getxdr_date_ns();
652 (void) sprintf(get_line(pos, getxdr_pos()), fmt, p);
653 return (p);
654 }
655
656 char *
getxdr_time()657 getxdr_time()
658 {
659 time_t sec;
660 static char buff[64];
661 struct tm my_time; /* private buffer to avoid collision */
662 /* between gmtime and strftime */
663 struct tm *tmp;
664
665 sec = getxdr_long();
666 if (sec == -1)
667 return ("-1 ");
668
669 if (sec < 3600 * 24 * 365) { /* assume not a date */
670 (void) sprintf(buff, "%d", sec);
671 } else {
672 tmp = gmtime(&sec);
673 memcpy(&my_time, tmp, sizeof (struct tm));
674 strftime(buff, sizeof (buff), "%d-%h-%y %T", &my_time);
675 }
676 return (buff);
677 }
678
679 char *
showxdr_time(char * fmt)680 showxdr_time(char *fmt)
681 {
682 int pos;
683 char *p;
684
685 pos = getxdr_pos();
686 p = getxdr_time();
687 (void) sprintf(get_line(pos, getxdr_pos()), fmt, p);
688 return (p);
689 }
690
691 char *
getxdr_hex(int len)692 getxdr_hex(int len)
693 {
694 int i, j;
695 static char hbuff[1024];
696 char rbuff[1024];
697 static char *hexstr = "0123456789ABCDEF";
698 char toobig = 0;
699
700 if (len == 0) {
701 hbuff[0] = '\0';
702 return (hbuff);
703 }
704 if (len > 1024)
705 len = 1024;
706 if (len < 0 || xdr_opaque(&xdrm, rbuff, len) == FALSE) {
707 longjmp(xdr_err, 1);
708 }
709
710 if (len * 2 > sizeof (hbuff)) {
711 toobig++;
712 len = sizeof (hbuff) / 2;
713 }
714
715 j = 0;
716 for (i = 0; i < len; i++) {
717 hbuff[j++] = hexstr[rbuff[i] >> 4 & 0x0f];
718 hbuff[j++] = hexstr[rbuff[i] & 0x0f];
719 }
720
721 if (toobig) {
722 hbuff[len * 2 - strlen("<Too Long>")] = '\0';
723 strcat(hbuff, "<Too Long>");
724 } else
725 hbuff[j] = '\0';
726
727 return (hbuff);
728 }
729
730 char *
showxdr_hex(int len,char * fmt)731 showxdr_hex(int len, char *fmt)
732 {
733 int pos;
734 char *p;
735
736 pos = getxdr_pos();
737 p = getxdr_hex(len);
738 (void) sprintf(get_line(pos, getxdr_pos()), fmt, p);
739 return (p);
740 }
741
742 static void
hexdump(char * data,int datalen)743 hexdump(char *data, int datalen)
744 {
745 char *p;
746 ushort_t *p16 = (ushort_t *)data;
747 char *p8 = data;
748 int i, left, len;
749 int chunk = 16; /* 16 bytes per line */
750
751 printf("\n");
752
753 for (p = data; p < data + datalen; p += chunk) {
754 printf("\t%4d: ", p - data);
755 left = (data + datalen) - p;
756 len = MIN(chunk, left);
757 for (i = 0; i < (len / 2); i++)
758 printf("%04x ", ntohs(*p16++) & 0xffff);
759 if (len % 2) {
760 printf("%02x ", *((unsigned char *)p16));
761 }
762 for (i = 0; i < (chunk - left) / 2; i++)
763 printf(" ");
764
765 printf(" ");
766 for (i = 0; i < len; i++, p8++)
767 printf("%c", isprint(*p8) ? *p8 : '.');
768 printf("\n");
769 }
770
771 printf("\n");
772 }
773