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