]> The Tcpdump Group git mirrors - tcpdump/blob - util-print.c
Merge branch 'master' of git+ssh://bpf.tcpdump.org/tcpdump/master/git/tcpdump
[tcpdump] / util-print.c
1 /*
2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 */
21
22 /*
23 * txtproto_print() derived from original code by Hannes Gredler
24 * (hannes@juniper.net):
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that: (1) source code
28 * distributions retain the above copyright notice and this paragraph
29 * in its entirety, and (2) distributions including binary code include
30 * the above copyright notice and this paragraph in its entirety in
31 * the documentation or other materials provided with the distribution.
32 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
33 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
34 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
35 * FOR A PARTICULAR PURPOSE.
36 */
37
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41
42 #include <tcpdump-stdinc.h>
43
44 #include <sys/stat.h>
45
46 #ifdef HAVE_FCNTL_H
47 #include <fcntl.h>
48 #endif
49 #include <stdio.h>
50 #include <stdarg.h>
51 #include <stdlib.h>
52 #include <string.h>
53
54 #include "interface.h"
55
56 int32_t thiszone; /* seconds offset from gmt to local time */
57
58 /*
59 * Print out a null-terminated filename (or other ascii string).
60 * If ep is NULL, assume no truncation check is needed.
61 * Return true if truncated.
62 */
63 int
64 fn_print(netdissect_options *ndo,
65 register const u_char *s, register const u_char *ep)
66 {
67 register int ret;
68 register u_char c;
69
70 ret = 1; /* assume truncated */
71 while (ep == NULL || s < ep) {
72 c = *s++;
73 if (c == '\0') {
74 ret = 0;
75 break;
76 }
77 if (!ND_ISASCII(c)) {
78 c = ND_TOASCII(c);
79 ND_PRINT((ndo, "M-"));
80 }
81 if (!ND_ISPRINT(c)) {
82 c ^= 0x40; /* DEL to ?, others to alpha */
83 ND_PRINT((ndo, "^"));
84 }
85 ND_PRINT((ndo, "%c", c));
86 }
87 return(ret);
88 }
89
90 /*
91 * Print out a counted filename (or other ascii string).
92 * If ep is NULL, assume no truncation check is needed.
93 * Return true if truncated.
94 */
95 int
96 fn_printn(netdissect_options *ndo,
97 register const u_char *s, register u_int n, register const u_char *ep)
98 {
99 register u_char c;
100
101 while (n > 0 && (ep == NULL || s < ep)) {
102 n--;
103 c = *s++;
104 if (!ND_ISASCII(c)) {
105 c = ND_TOASCII(c);
106 ND_PRINT((ndo, "M-"));
107 }
108 if (!ND_ISPRINT(c)) {
109 c ^= 0x40; /* DEL to ?, others to alpha */
110 ND_PRINT((ndo, "^"));
111 }
112 ND_PRINT((ndo, "%c", c));
113 }
114 return (n == 0) ? 0 : 1;
115 }
116
117 /*
118 * Print out a null-padded filename (or other ascii string).
119 * If ep is NULL, assume no truncation check is needed.
120 * Return true if truncated.
121 */
122 int
123 fn_printzp(netdissect_options *ndo,
124 register const u_char *s, register u_int n,
125 register const u_char *ep)
126 {
127 register int ret;
128 register u_char c;
129
130 ret = 1; /* assume truncated */
131 while (n > 0 && (ep == NULL || s < ep)) {
132 n--;
133 c = *s++;
134 if (c == '\0') {
135 ret = 0;
136 break;
137 }
138 if (!ND_ISASCII(c)) {
139 c = ND_TOASCII(c);
140 ND_PRINT((ndo, "M-"));
141 }
142 if (!ND_ISPRINT(c)) {
143 c ^= 0x40; /* DEL to ?, others to alpha */
144 ND_PRINT((ndo, "^"));
145 }
146 ND_PRINT((ndo, "%c", c));
147 }
148 return (n == 0) ? 0 : ret;
149 }
150
151 /*
152 * Format the timestamp
153 */
154 static char *
155 ts_format(netdissect_options *ndo
156 #ifndef HAVE_PCAP_SET_TSTAMP_PRECISION
157 _U_
158 #endif
159 , int sec, int usec)
160 {
161 static char buf[sizeof("00:00:00.000000000")];
162 const char *format;
163
164 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
165 switch (ndo->ndo_tstamp_precision) {
166
167 case PCAP_TSTAMP_PRECISION_MICRO:
168 format = "%02d:%02d:%02d.%06u";
169 break;
170
171 case PCAP_TSTAMP_PRECISION_NANO:
172 format = "%02d:%02d:%02d.%09u";
173 break;
174
175 default:
176 format = "%02d:%02d:%02d.{unknown precision}";
177 break;
178 }
179 #else
180 format = "%02d:%02d:%02d.%06u";
181 #endif
182
183 snprintf(buf, sizeof(buf), format,
184 sec / 3600, (sec % 3600) / 60, sec % 60, usec);
185
186 return buf;
187 }
188
189 /*
190 * Print the timestamp
191 */
192 void
193 ts_print(netdissect_options *ndo,
194 register const struct timeval *tvp)
195 {
196 register int s;
197 struct tm *tm;
198 time_t Time;
199 static unsigned b_sec;
200 static unsigned b_usec;
201 int d_usec;
202 int d_sec;
203
204 switch (ndo->ndo_tflag) {
205
206 case 0: /* Default */
207 s = (tvp->tv_sec + thiszone) % 86400;
208 ND_PRINT((ndo, "%s ", ts_format(ndo, s, tvp->tv_usec)));
209 break;
210
211 case 1: /* No time stamp */
212 break;
213
214 case 2: /* Unix timeval style */
215 ND_PRINT((ndo, "%u.%06u ",
216 (unsigned)tvp->tv_sec,
217 (unsigned)tvp->tv_usec));
218 break;
219
220 case 3: /* Microseconds since previous packet */
221 case 5: /* Microseconds since first packet */
222 if (b_sec == 0) {
223 /* init timestamp for first packet */
224 b_usec = tvp->tv_usec;
225 b_sec = tvp->tv_sec;
226 }
227
228 d_usec = tvp->tv_usec - b_usec;
229 d_sec = tvp->tv_sec - b_sec;
230
231 while (d_usec < 0) {
232 d_usec += 1000000;
233 d_sec--;
234 }
235
236 ND_PRINT((ndo, "%s ", ts_format(ndo, d_sec, d_usec)));
237
238 if (ndo->ndo_tflag == 3) { /* set timestamp for last packet */
239 b_sec = tvp->tv_sec;
240 b_usec = tvp->tv_usec;
241 }
242 break;
243
244 case 4: /* Default + Date*/
245 s = (tvp->tv_sec + thiszone) % 86400;
246 Time = (tvp->tv_sec + thiszone) - s;
247 tm = gmtime (&Time);
248 if (!tm)
249 ND_PRINT((ndo, "Date fail "));
250 else
251 ND_PRINT((ndo, "%04d-%02d-%02d %s ",
252 tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
253 ts_format(ndo, s, tvp->tv_usec)));
254 break;
255 }
256 }
257
258 /*
259 * Print a relative number of seconds (e.g. hold time, prune timer)
260 * in the form 5m1s. This does no truncation, so 32230861 seconds
261 * is represented as 1y1w1d1h1m1s.
262 */
263 void
264 relts_print(netdissect_options *ndo,
265 int secs)
266 {
267 static const char *lengths[] = {"y", "w", "d", "h", "m", "s"};
268 static const int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
269 const char **l = lengths;
270 const int *s = seconds;
271
272 if (secs == 0) {
273 ND_PRINT((ndo, "0s"));
274 return;
275 }
276 if (secs < 0) {
277 ND_PRINT((ndo, "-"));
278 secs = -secs;
279 }
280 while (secs > 0) {
281 if (secs >= *s) {
282 ND_PRINT((ndo, "%d%s", secs / *s, *l));
283 secs -= (secs / *s) * *s;
284 }
285 s++;
286 l++;
287 }
288 }
289
290 /*
291 * this is a generic routine for printing unknown data;
292 * we pass on the linefeed plus indentation string to
293 * get a proper output - returns 0 on error
294 */
295
296 int
297 print_unknown_data(netdissect_options *ndo, const u_char *cp,const char *ident,int len)
298 {
299 if (len < 0) {
300 ND_PRINT((ndo,"%sDissector error: print_unknown_data called with negative length",
301 ident));
302 return(0);
303 }
304 if (ndo->ndo_snapend - cp < len)
305 len = ndo->ndo_snapend - cp;
306 if (len < 0) {
307 ND_PRINT((ndo,"%sDissector error: print_unknown_data called with pointer past end of packet",
308 ident));
309 return(0);
310 }
311 hex_print(ndo, ident,cp,len);
312 return(1); /* everything is ok */
313 }
314
315 /*
316 * Convert a token value to a string; use "fmt" if not found.
317 */
318 const char *
319 tok2strbuf(register const struct tok *lp, register const char *fmt,
320 register u_int v, char *buf, size_t bufsize)
321 {
322 if (lp != NULL) {
323 while (lp->s != NULL) {
324 if (lp->v == v)
325 return (lp->s);
326 ++lp;
327 }
328 }
329 if (fmt == NULL)
330 fmt = "#%d";
331
332 (void)snprintf(buf, bufsize, fmt, v);
333 return (const char *)buf;
334 }
335
336 /*
337 * Convert a token value to a string; use "fmt" if not found.
338 */
339 const char *
340 tok2str(register const struct tok *lp, register const char *fmt,
341 register u_int v)
342 {
343 static char buf[4][128];
344 static int idx = 0;
345 char *ret;
346
347 ret = buf[idx];
348 idx = (idx+1) & 3;
349 return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0]));
350 }
351
352 /*
353 * Convert a bit token value to a string; use "fmt" if not found.
354 * this is useful for parsing bitfields, the output strings are seperated
355 * if the s field is positive.
356 */
357 static char *
358 bittok2str_internal(register const struct tok *lp, register const char *fmt,
359 register u_int v, const char *sep)
360 {
361 static char buf[256]; /* our stringbuffer */
362 int buflen=0;
363 register u_int rotbit; /* this is the bit we rotate through all bitpositions */
364 register u_int tokval;
365 const char * sepstr = "";
366
367 while (lp != NULL && lp->s != NULL) {
368 tokval=lp->v; /* load our first value */
369 rotbit=1;
370 while (rotbit != 0) {
371 /*
372 * lets AND the rotating bit with our token value
373 * and see if we have got a match
374 */
375 if (tokval == (v&rotbit)) {
376 /* ok we have found something */
377 buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s%s",
378 sepstr, lp->s);
379 sepstr = sep;
380 break;
381 }
382 rotbit=rotbit<<1; /* no match - lets shift and try again */
383 }
384 lp++;
385 }
386
387 if (buflen == 0)
388 /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
389 (void)snprintf(buf, sizeof(buf), fmt == NULL ? "#%08x" : fmt, v);
390 return (buf);
391 }
392
393 /*
394 * Convert a bit token value to a string; use "fmt" if not found.
395 * this is useful for parsing bitfields, the output strings are not seperated.
396 */
397 char *
398 bittok2str_nosep(register const struct tok *lp, register const char *fmt,
399 register u_int v)
400 {
401 return (bittok2str_internal(lp, fmt, v, ""));
402 }
403
404 /*
405 * Convert a bit token value to a string; use "fmt" if not found.
406 * this is useful for parsing bitfields, the output strings are comma seperated.
407 */
408 char *
409 bittok2str(register const struct tok *lp, register const char *fmt,
410 register u_int v)
411 {
412 return (bittok2str_internal(lp, fmt, v, ", "));
413 }
414
415 /*
416 * Convert a value to a string using an array; the macro
417 * tok2strary() in <interface.h> is the public interface to
418 * this function and ensures that the second argument is
419 * correct for bounds-checking.
420 */
421 const char *
422 tok2strary_internal(register const char **lp, int n, register const char *fmt,
423 register int v)
424 {
425 static char buf[128];
426
427 if (v >= 0 && v < n && lp[v] != NULL)
428 return lp[v];
429 if (fmt == NULL)
430 fmt = "#%d";
431 (void)snprintf(buf, sizeof(buf), fmt, v);
432 return (buf);
433 }
434
435 /*
436 * Convert a 32-bit netmask to prefixlen if possible
437 * the function returns the prefix-len; if plen == -1
438 * then conversion was not possible;
439 */
440
441 int
442 mask2plen(uint32_t mask)
443 {
444 uint32_t bitmasks[33] = {
445 0x00000000,
446 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
447 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
448 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
449 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
450 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
451 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
452 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
453 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
454 };
455 int prefix_len = 32;
456
457 /* let's see if we can transform the mask into a prefixlen */
458 while (prefix_len >= 0) {
459 if (bitmasks[prefix_len] == mask)
460 break;
461 prefix_len--;
462 }
463 return (prefix_len);
464 }
465
466 #ifdef INET6
467 int
468 mask62plen(const u_char *mask)
469 {
470 u_char bitmasks[9] = {
471 0x00,
472 0x80, 0xc0, 0xe0, 0xf0,
473 0xf8, 0xfc, 0xfe, 0xff
474 };
475 int byte;
476 int cidr_len = 0;
477
478 for (byte = 0; byte < 16; byte++) {
479 u_int bits;
480
481 for (bits = 0; bits < (sizeof (bitmasks) / sizeof (bitmasks[0])); bits++) {
482 if (mask[byte] == bitmasks[bits]) {
483 cidr_len += bits;
484 break;
485 }
486 }
487
488 if (mask[byte] != 0xff)
489 break;
490 }
491 return (cidr_len);
492 }
493 #endif /* INET6 */
494
495 /*
496 * Routine to print out information for text-based protocols such as FTP,
497 * HTTP, SMTP, RTSP, SIP, ....
498 */
499 #define MAX_TOKEN 128
500
501 /*
502 * Fetch a token from a packet, starting at the specified index,
503 * and return the length of the token.
504 *
505 * Returns 0 on error; yes, this is indistinguishable from an empty
506 * token, but an "empty token" isn't a valid token - it just means
507 * either a space character at the beginning of the line (this
508 * includes a blank line) or no more tokens remaining on the line.
509 */
510 static int
511 fetch_token(netdissect_options *ndo, const u_char *pptr, u_int idx, u_int len,
512 u_char *tbuf, size_t tbuflen)
513 {
514 size_t toklen = 0;
515
516 for (; idx < len; idx++) {
517 if (!ND_TTEST(*(pptr + idx))) {
518 /* ran past end of captured data */
519 return (0);
520 }
521 if (!isascii(*(pptr + idx))) {
522 /* not an ASCII character */
523 return (0);
524 }
525 if (isspace(*(pptr + idx))) {
526 /* end of token */
527 break;
528 }
529 if (!isprint(*(pptr + idx))) {
530 /* not part of a command token or response code */
531 return (0);
532 }
533 if (toklen + 2 > tbuflen) {
534 /* no room for this character and terminating '\0' */
535 return (0);
536 }
537 tbuf[toklen] = *(pptr + idx);
538 toklen++;
539 }
540 if (toklen == 0) {
541 /* no token */
542 return (0);
543 }
544 tbuf[toklen] = '\0';
545
546 /*
547 * Skip past any white space after the token, until we see
548 * an end-of-line (CR or LF).
549 */
550 for (; idx < len; idx++) {
551 if (!ND_TTEST(*(pptr + idx))) {
552 /* ran past end of captured data */
553 break;
554 }
555 if (*(pptr + idx) == '\r' || *(pptr + idx) == '\n') {
556 /* end of line */
557 break;
558 }
559 if (!isascii(*(pptr + idx)) || !isprint(*(pptr + idx))) {
560 /* not a printable ASCII character */
561 break;
562 }
563 if (!isspace(*(pptr + idx))) {
564 /* beginning of next token */
565 break;
566 }
567 }
568 return (idx);
569 }
570
571 /*
572 * Scan a buffer looking for a line ending - LF or CR-LF.
573 * Return the index of the character after the line ending or 0 if
574 * we encounter a non-ASCII or non-printable character or don't find
575 * the line ending.
576 */
577 static u_int
578 print_txt_line(netdissect_options *ndo, const char *protoname,
579 const char *prefix, const u_char *pptr, u_int idx, u_int len)
580 {
581 u_int startidx;
582 u_int linelen;
583
584 startidx = idx;
585 while (idx < len) {
586 ND_TCHECK(*(pptr+idx));
587 if (*(pptr+idx) == '\n') {
588 /*
589 * LF without CR; end of line.
590 * Skip the LF and print the line, with the
591 * exception of the LF.
592 */
593 linelen = idx - startidx;
594 idx++;
595 goto print;
596 } else if (*(pptr+idx) == '\r') {
597 /* CR - any LF? */
598 if ((idx+1) >= len) {
599 /* not in this packet */
600 return (0);
601 }
602 ND_TCHECK(*(pptr+idx+1));
603 if (*(pptr+idx+1) == '\n') {
604 /*
605 * CR-LF; end of line.
606 * Skip the CR-LF and print the line, with
607 * the exception of the CR-LF.
608 */
609 linelen = idx - startidx;
610 idx += 2;
611 goto print;
612 }
613
614 /*
615 * CR followed by something else; treat this
616 * as if it were binary data, and don't print
617 * it.
618 */
619 return (0);
620 } else if (!isascii(*(pptr+idx)) ||
621 (!isprint(*(pptr+idx)) && *(pptr+idx) != '\t')) {
622 /*
623 * Not a printable ASCII character and not a tab;
624 * treat this as if it were binary data, and
625 * don't print it.
626 */
627 return (0);
628 }
629 idx++;
630 }
631
632 /*
633 * All printable ASCII, but no line ending after that point
634 * in the buffer; treat this as if it were truncated.
635 */
636 trunc:
637 linelen = idx - startidx;
638 ND_PRINT((ndo, "%s%.*s[!%s]", prefix, (int)linelen, pptr + startidx,
639 protoname));
640 return (0);
641
642 print:
643 ND_PRINT((ndo, "%s%.*s", prefix, (int)linelen, pptr + startidx));
644 return (idx);
645 }
646
647 void
648 txtproto_print(netdissect_options *ndo, const u_char *pptr, u_int len,
649 const char *protoname, const char **cmds, u_int flags)
650 {
651 u_int idx, eol;
652 u_char token[MAX_TOKEN+1];
653 const char *cmd;
654 int is_reqresp = 0;
655 const char *pnp;
656
657 if (cmds != NULL) {
658 /*
659 * This protocol has more than just request and
660 * response lines; see whether this looks like a
661 * request or response.
662 */
663 idx = fetch_token(ndo, pptr, 0, len, token, sizeof(token));
664 if (idx != 0) {
665 /* Is this a valid request name? */
666 while ((cmd = *cmds++) != NULL) {
667 if (strcasecmp((const char *)token, cmd) == 0) {
668 /* Yes. */
669 is_reqresp = 1;
670 break;
671 }
672 }
673
674 /*
675 * No - is this a valid response code (3 digits)?
676 *
677 * Is this token the response code, or is the next
678 * token the response code?
679 */
680 if (flags & RESP_CODE_SECOND_TOKEN) {
681 /*
682 * Next token - get it.
683 */
684 idx = fetch_token(ndo, pptr, idx, len, token,
685 sizeof(token));
686 }
687 if (idx != 0) {
688 if (isdigit(token[0]) && isdigit(token[1]) &&
689 isdigit(token[2]) && token[3] == '\0') {
690 /* Yes. */
691 is_reqresp = 1;
692 }
693 }
694 }
695 } else {
696 /*
697 * This protocol has only request and response lines
698 * (e.g., FTP, where all the data goes over a
699 * different connection); assume the payload is
700 * a request or response.
701 */
702 is_reqresp = 1;
703 }
704
705 /* Capitalize the protocol name */
706 for (pnp = protoname; *pnp != '\0'; pnp++)
707 ND_PRINT((ndo, "%c", toupper(*pnp)));
708
709 if (is_reqresp) {
710 /*
711 * In non-verbose mode, just print the protocol, followed
712 * by the first line as the request or response info.
713 *
714 * In verbose mode, print lines as text until we run out
715 * of characters or see something that's not a
716 * printable-ASCII line.
717 */
718 if (ndo->ndo_vflag) {
719 /*
720 * We're going to print all the text lines in the
721 * request or response; just print the length
722 * on the first line of the output.
723 */
724 ND_PRINT((ndo, ", length: %u", len));
725 for (idx = 0;
726 idx < len && (eol = print_txt_line(ndo, protoname, "\n\t", pptr, idx, len)) != 0;
727 idx = eol)
728 ;
729 } else {
730 /*
731 * Just print the first text line.
732 */
733 print_txt_line(ndo, protoname, ": ", pptr, 0, len);
734 }
735 }
736 }
737
738 void
739 safeputs(netdissect_options *ndo,
740 const u_char *s, const u_int maxlen)
741 {
742 u_int idx = 0;
743
744 while (*s && idx < maxlen) {
745 safeputchar(ndo, *s);
746 idx++;
747 s++;
748 }
749 }
750
751 void
752 safeputchar(netdissect_options *ndo,
753 const u_char c)
754 {
755 ND_PRINT((ndo, (c < 0x80 && ND_ISPRINT(c)) ? "%c" : "\\0x%02x", c));
756 }
757
758 #ifdef LBL_ALIGN
759 /*
760 * Some compilers try to optimize memcpy(), using the alignment constraint
761 * on the argument pointer type. by using this function, we try to avoid the
762 * optimization.
763 */
764 void
765 unaligned_memcpy(void *p, const void *q, size_t l)
766 {
767 memcpy(p, q, l);
768 }
769
770 /* As with memcpy(), so with memcmp(). */
771 int
772 unaligned_memcmp(const void *p, const void *q, size_t l)
773 {
774 return (memcmp(p, q, l));
775 }
776 #endif
777