xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_display.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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
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 *
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
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
187 xdr_init(char *addr, int len)
188 {
189 	xdr_totlen = len;
190 	xdrmem_create(&xdrm, addr, len, XDR_DECODE);
191 }
192 
193 char *
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
205 get_line_remain(void)
206 {
207 	return (MAXLINE - strlen(prot_nest_prefix) - strlen(prot_prefix));
208 }
209 
210 void
211 show_line(char *str)
212 {
213 	(void) strcpy(get_line(0, 0), str);
214 }
215 
216 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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 *
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 *
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 *
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 *
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 *
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
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
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
535 getxdr_pos()
536 {
537 	return (xdr_getpos(&xdrm));
538 }
539 
540 void
541 setxdr_pos(int pos)
542 {
543 	xdr_setpos(&xdrm, pos);
544 }
545 
546 void
547 show_space()
548 {
549 	(void) get_line(0, 0);
550 }
551 
552 void
553 show_trailer()
554 {
555 	show_space();
556 }
557 
558 char *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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
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