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