2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
3 * The Regents of the University of California. All rights reserved.
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
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.
23 * txtproto_print() derived from original code by Hannes Gredler
24 * (hannes@juniper.net):
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.
38 #define NETDISSECT_REWORKED
43 #include <tcpdump-stdinc.h>
55 #include "interface.h"
56 #include "timeval-operations.h"
59 * timestamp display buffer size, the biggest size of both formats is needed
60 * sizeof("0000000000.000000000") > sizeof("00:00:00.000000000")
62 #define TS_BUF_SIZE sizeof("0000000000.000000000")
65 * Print out a null-terminated filename (or other ascii string).
66 * If ep is NULL, assume no truncation check is needed.
67 * Return true if truncated.
70 fn_print(netdissect_options
*ndo
,
71 register const u_char
*s
, register const u_char
*ep
)
76 ret
= 1; /* assume truncated */
77 while (ep
== NULL
|| s
< ep
) {
85 ND_PRINT((ndo
, "M-"));
88 c
^= 0x40; /* DEL to ?, others to alpha */
91 ND_PRINT((ndo
, "%c", c
));
97 * Print out a counted filename (or other ascii string).
98 * If ep is NULL, assume no truncation check is needed.
99 * Return true if truncated.
102 fn_printn(netdissect_options
*ndo
,
103 register const u_char
*s
, register u_int n
, register const u_char
*ep
)
107 while (n
> 0 && (ep
== NULL
|| s
< ep
)) {
110 if (!ND_ISASCII(c
)) {
112 ND_PRINT((ndo
, "M-"));
114 if (!ND_ISPRINT(c
)) {
115 c
^= 0x40; /* DEL to ?, others to alpha */
116 ND_PRINT((ndo
, "^"));
118 ND_PRINT((ndo
, "%c", c
));
120 return (n
== 0) ? 0 : 1;
124 * Print out a null-padded filename (or other ascii string).
125 * If ep is NULL, assume no truncation check is needed.
126 * Return true if truncated.
129 fn_printzp(netdissect_options
*ndo
,
130 register const u_char
*s
, register u_int n
,
131 register const u_char
*ep
)
136 ret
= 1; /* assume truncated */
137 while (n
> 0 && (ep
== NULL
|| s
< ep
)) {
144 if (!ND_ISASCII(c
)) {
146 ND_PRINT((ndo
, "M-"));
148 if (!ND_ISPRINT(c
)) {
149 c
^= 0x40; /* DEL to ?, others to alpha */
150 ND_PRINT((ndo
, "^"));
152 ND_PRINT((ndo
, "%c", c
));
154 return (n
== 0) ? 0 : ret
;
158 * Format the timestamp
161 ts_format(netdissect_options
*ndo
162 #ifndef HAVE_PCAP_SET_TSTAMP_PRECISION
165 , int sec
, int usec
, char *buf
)
169 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
170 switch (ndo
->ndo_tstamp_precision
) {
172 case PCAP_TSTAMP_PRECISION_MICRO
:
173 format
= "%02d:%02d:%02d.%06u";
176 case PCAP_TSTAMP_PRECISION_NANO
:
177 format
= "%02d:%02d:%02d.%09u";
181 format
= "%02d:%02d:%02d.{unknown}";
185 format
= "%02d:%02d:%02d.%06u";
188 snprintf(buf
, TS_BUF_SIZE
, format
,
189 sec
/ 3600, (sec
% 3600) / 60, sec
% 60, usec
);
195 * Format the timestamp - Unix timeval style
198 ts_unix_format(netdissect_options
*ndo
199 #ifndef HAVE_PCAP_SET_TSTAMP_PRECISION
202 , int sec
, int usec
, char *buf
)
206 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
207 switch (ndo
->ndo_tstamp_precision
) {
209 case PCAP_TSTAMP_PRECISION_MICRO
:
213 case PCAP_TSTAMP_PRECISION_NANO
:
218 format
= "%u.{unknown}";
225 snprintf(buf
, TS_BUF_SIZE
, format
,
226 (unsigned)sec
, (unsigned)usec
);
232 * Print the timestamp
235 ts_print(netdissect_options
*ndo
,
236 register const struct timeval
*tvp
)
241 char buf
[TS_BUF_SIZE
];
242 static struct timeval tv_ref
;
243 struct timeval tv_result
;
247 switch (ndo
->ndo_tflag
) {
249 case 0: /* Default */
250 s
= (tvp
->tv_sec
+ thiszone
) % 86400;
251 ND_PRINT((ndo
, "%s ", ts_format(ndo
, s
, tvp
->tv_usec
, buf
)));
254 case 1: /* No time stamp */
257 case 2: /* Unix timeval style */
258 ND_PRINT((ndo
, "%s ", ts_unix_format(ndo
,
259 tvp
->tv_sec
, tvp
->tv_usec
, buf
)));
262 case 3: /* Microseconds/nanoseconds since previous packet */
263 case 5: /* Microseconds/nanoseconds since first packet */
264 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
265 switch (ndo
->ndo_tstamp_precision
) {
266 case PCAP_TSTAMP_PRECISION_MICRO
:
269 case PCAP_TSTAMP_PRECISION_NANO
:
279 if (!(tcpdump_timevalisset(&tv_ref
)))
280 tv_ref
= *tvp
; /* set timestamp for first packet */
282 negative_offset
= tcpdump_timevalcmp(tvp
, &tv_ref
, <);
284 tcpdump_timevalsub(&tv_ref
, tvp
, &tv_result
, nano_prec
);
286 tcpdump_timevalsub(tvp
, &tv_ref
, &tv_result
, nano_prec
);
288 ND_PRINT((ndo
, (negative_offset
? "-" : " ")));
290 ND_PRINT((ndo
, "%s ", ts_format(ndo
,
291 tv_result
.tv_sec
, tv_result
.tv_usec
, buf
)));
293 if (ndo
->ndo_tflag
== 3)
294 tv_ref
= *tvp
; /* set timestamp for previous packet */
297 case 4: /* Default + Date */
298 s
= (tvp
->tv_sec
+ thiszone
) % 86400;
299 Time
= (tvp
->tv_sec
+ thiszone
) - s
;
302 ND_PRINT((ndo
, "Date fail "));
304 ND_PRINT((ndo
, "%04d-%02d-%02d %s ",
305 tm
->tm_year
+1900, tm
->tm_mon
+1, tm
->tm_mday
,
306 ts_format(ndo
, s
, tvp
->tv_usec
, buf
)));
312 * Print a relative number of seconds (e.g. hold time, prune timer)
313 * in the form 5m1s. This does no truncation, so 32230861 seconds
314 * is represented as 1y1w1d1h1m1s.
317 relts_print(netdissect_options
*ndo
,
320 static const char *lengths
[] = {"y", "w", "d", "h", "m", "s"};
321 static const int seconds
[] = {31536000, 604800, 86400, 3600, 60, 1};
322 const char **l
= lengths
;
323 const int *s
= seconds
;
326 ND_PRINT((ndo
, "0s"));
330 ND_PRINT((ndo
, "-"));
335 ND_PRINT((ndo
, "%d%s", secs
/ *s
, *l
));
336 secs
-= (secs
/ *s
) * *s
;
344 * this is a generic routine for printing unknown data;
345 * we pass on the linefeed plus indentation string to
346 * get a proper output - returns 0 on error
350 print_unknown_data(netdissect_options
*ndo
, const u_char
*cp
,const char *ident
,int len
)
353 ND_PRINT((ndo
,"%sDissector error: print_unknown_data called with negative length",
357 if (ndo
->ndo_snapend
- cp
< len
)
358 len
= ndo
->ndo_snapend
- cp
;
360 ND_PRINT((ndo
,"%sDissector error: print_unknown_data called with pointer past end of packet",
364 hex_print(ndo
, ident
,cp
,len
);
365 return(1); /* everything is ok */
369 * Convert a token value to a string; use "fmt" if not found.
372 tok2strbuf(register const struct tok
*lp
, register const char *fmt
,
373 register u_int v
, char *buf
, size_t bufsize
)
376 while (lp
->s
!= NULL
) {
385 (void)snprintf(buf
, bufsize
, fmt
, v
);
386 return (const char *)buf
;
390 * Convert a token value to a string; use "fmt" if not found.
393 tok2str(register const struct tok
*lp
, register const char *fmt
,
396 static char buf
[4][128];
402 return tok2strbuf(lp
, fmt
, v
, ret
, sizeof(buf
[0]));
406 * Convert a bit token value to a string; use "fmt" if not found.
407 * this is useful for parsing bitfields, the output strings are seperated
408 * if the s field is positive.
411 bittok2str_internal(register const struct tok
*lp
, register const char *fmt
,
412 register u_int v
, const char *sep
)
414 static char buf
[256]; /* our stringbuffer */
416 register u_int rotbit
; /* this is the bit we rotate through all bitpositions */
417 register u_int tokval
;
418 const char * sepstr
= "";
420 while (lp
!= NULL
&& lp
->s
!= NULL
) {
421 tokval
=lp
->v
; /* load our first value */
423 while (rotbit
!= 0) {
425 * lets AND the rotating bit with our token value
426 * and see if we have got a match
428 if (tokval
== (v
&rotbit
)) {
429 /* ok we have found something */
430 buflen
+=snprintf(buf
+buflen
, sizeof(buf
)-buflen
, "%s%s",
435 rotbit
=rotbit
<<1; /* no match - lets shift and try again */
441 /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
442 (void)snprintf(buf
, sizeof(buf
), fmt
== NULL
? "#%08x" : fmt
, v
);
447 * Convert a bit token value to a string; use "fmt" if not found.
448 * this is useful for parsing bitfields, the output strings are not seperated.
451 bittok2str_nosep(register const struct tok
*lp
, register const char *fmt
,
454 return (bittok2str_internal(lp
, fmt
, v
, ""));
458 * Convert a bit token value to a string; use "fmt" if not found.
459 * this is useful for parsing bitfields, the output strings are comma seperated.
462 bittok2str(register const struct tok
*lp
, register const char *fmt
,
465 return (bittok2str_internal(lp
, fmt
, v
, ", "));
469 * Convert a value to a string using an array; the macro
470 * tok2strary() in <interface.h> is the public interface to
471 * this function and ensures that the second argument is
472 * correct for bounds-checking.
475 tok2strary_internal(register const char **lp
, int n
, register const char *fmt
,
478 static char buf
[128];
480 if (v
>= 0 && v
< n
&& lp
[v
] != NULL
)
484 (void)snprintf(buf
, sizeof(buf
), fmt
, v
);
489 * Convert a 32-bit netmask to prefixlen if possible
490 * the function returns the prefix-len; if plen == -1
491 * then conversion was not possible;
495 mask2plen(uint32_t mask
)
497 uint32_t bitmasks
[33] = {
499 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
500 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
501 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
502 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
503 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
504 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
505 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
506 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
510 /* let's see if we can transform the mask into a prefixlen */
511 while (prefix_len
>= 0) {
512 if (bitmasks
[prefix_len
] == mask
)
521 mask62plen(const u_char
*mask
)
523 u_char bitmasks
[9] = {
525 0x80, 0xc0, 0xe0, 0xf0,
526 0xf8, 0xfc, 0xfe, 0xff
531 for (byte
= 0; byte
< 16; byte
++) {
534 for (bits
= 0; bits
< (sizeof (bitmasks
) / sizeof (bitmasks
[0])); bits
++) {
535 if (mask
[byte
] == bitmasks
[bits
]) {
541 if (mask
[byte
] != 0xff)
549 * Routine to print out information for text-based protocols such as FTP,
550 * HTTP, SMTP, RTSP, SIP, ....
552 #define MAX_TOKEN 128
555 * Fetch a token from a packet, starting at the specified index,
556 * and return the length of the token.
558 * Returns 0 on error; yes, this is indistinguishable from an empty
559 * token, but an "empty token" isn't a valid token - it just means
560 * either a space character at the beginning of the line (this
561 * includes a blank line) or no more tokens remaining on the line.
564 fetch_token(netdissect_options
*ndo
, const u_char
*pptr
, u_int idx
, u_int len
,
565 u_char
*tbuf
, size_t tbuflen
)
569 for (; idx
< len
; idx
++) {
570 if (!ND_TTEST(*(pptr
+ idx
))) {
571 /* ran past end of captured data */
574 if (!isascii(*(pptr
+ idx
))) {
575 /* not an ASCII character */
578 if (isspace(*(pptr
+ idx
))) {
582 if (!isprint(*(pptr
+ idx
))) {
583 /* not part of a command token or response code */
586 if (toklen
+ 2 > tbuflen
) {
587 /* no room for this character and terminating '\0' */
590 tbuf
[toklen
] = *(pptr
+ idx
);
600 * Skip past any white space after the token, until we see
601 * an end-of-line (CR or LF).
603 for (; idx
< len
; idx
++) {
604 if (!ND_TTEST(*(pptr
+ idx
))) {
605 /* ran past end of captured data */
608 if (*(pptr
+ idx
) == '\r' || *(pptr
+ idx
) == '\n') {
612 if (!isascii(*(pptr
+ idx
)) || !isprint(*(pptr
+ idx
))) {
613 /* not a printable ASCII character */
616 if (!isspace(*(pptr
+ idx
))) {
617 /* beginning of next token */
625 * Scan a buffer looking for a line ending - LF or CR-LF.
626 * Return the index of the character after the line ending or 0 if
627 * we encounter a non-ASCII or non-printable character or don't find
631 print_txt_line(netdissect_options
*ndo
, const char *protoname
,
632 const char *prefix
, const u_char
*pptr
, u_int idx
, u_int len
)
639 ND_TCHECK(*(pptr
+idx
));
640 if (*(pptr
+idx
) == '\n') {
642 * LF without CR; end of line.
643 * Skip the LF and print the line, with the
644 * exception of the LF.
646 linelen
= idx
- startidx
;
649 } else if (*(pptr
+idx
) == '\r') {
651 if ((idx
+1) >= len
) {
652 /* not in this packet */
655 ND_TCHECK(*(pptr
+idx
+1));
656 if (*(pptr
+idx
+1) == '\n') {
658 * CR-LF; end of line.
659 * Skip the CR-LF and print the line, with
660 * the exception of the CR-LF.
662 linelen
= idx
- startidx
;
668 * CR followed by something else; treat this
669 * as if it were binary data, and don't print
673 } else if (!isascii(*(pptr
+idx
)) ||
674 (!isprint(*(pptr
+idx
)) && *(pptr
+idx
) != '\t')) {
676 * Not a printable ASCII character and not a tab;
677 * treat this as if it were binary data, and
686 * All printable ASCII, but no line ending after that point
687 * in the buffer; treat this as if it were truncated.
690 linelen
= idx
- startidx
;
691 ND_PRINT((ndo
, "%s%.*s[!%s]", prefix
, (int)linelen
, pptr
+ startidx
,
696 ND_PRINT((ndo
, "%s%.*s", prefix
, (int)linelen
, pptr
+ startidx
));
701 txtproto_print(netdissect_options
*ndo
, const u_char
*pptr
, u_int len
,
702 const char *protoname
, const char **cmds
, u_int flags
)
705 u_char token
[MAX_TOKEN
+1];
712 * This protocol has more than just request and
713 * response lines; see whether this looks like a
714 * request or response.
716 idx
= fetch_token(ndo
, pptr
, 0, len
, token
, sizeof(token
));
718 /* Is this a valid request name? */
719 while ((cmd
= *cmds
++) != NULL
) {
720 if (strcasecmp((const char *)token
, cmd
) == 0) {
728 * No - is this a valid response code (3 digits)?
730 * Is this token the response code, or is the next
731 * token the response code?
733 if (flags
& RESP_CODE_SECOND_TOKEN
) {
735 * Next token - get it.
737 idx
= fetch_token(ndo
, pptr
, idx
, len
, token
,
741 if (isdigit(token
[0]) && isdigit(token
[1]) &&
742 isdigit(token
[2]) && token
[3] == '\0') {
750 * This protocol has only request and response lines
751 * (e.g., FTP, where all the data goes over a
752 * different connection); assume the payload is
753 * a request or response.
758 /* Capitalize the protocol name */
759 for (pnp
= protoname
; *pnp
!= '\0'; pnp
++)
760 ND_PRINT((ndo
, "%c", toupper(*pnp
)));
764 * In non-verbose mode, just print the protocol, followed
765 * by the first line as the request or response info.
767 * In verbose mode, print lines as text until we run out
768 * of characters or see something that's not a
769 * printable-ASCII line.
771 if (ndo
->ndo_vflag
) {
773 * We're going to print all the text lines in the
774 * request or response; just print the length
775 * on the first line of the output.
777 ND_PRINT((ndo
, ", length: %u", len
));
779 idx
< len
&& (eol
= print_txt_line(ndo
, protoname
, "\n\t", pptr
, idx
, len
)) != 0;
784 * Just print the first text line.
786 print_txt_line(ndo
, protoname
, ": ", pptr
, 0, len
);
793 error(const char *fmt
, ...)
797 (void)fprintf(stderr
, "%s: ", program_name
);
799 (void)vfprintf(stderr
, fmt
, ap
);
804 (void)fputc('\n', stderr
);
812 warning(const char *fmt
, ...)
816 (void)fprintf(stderr
, "%s: WARNING: ", program_name
);
818 (void)vfprintf(stderr
, fmt
, ap
);
823 (void)fputc('\n', stderr
);
828 * Copy arg vector into a new buffer, concatenating arguments with spaces.
831 copy_argv(register char **argv
)
834 register u_int len
= 0;
843 len
+= strlen(*p
++) + 1;
845 buf
= (char *)malloc(len
);
847 error("copy_argv: malloc");
851 while ((src
= *p
++) != NULL
) {
852 while ((*dst
++ = *src
++) != '\0')
862 * On Windows, we need to open the file in binary mode, so that
863 * we get all the bytes specified by the size we get from "fstat()".
864 * On UNIX, that's not necessary. O_BINARY is defined on Windows;
865 * we define it as 0 if it's not defined, so it does nothing.
872 read_infile(char *fname
)
874 register int i
, fd
, cc
;
878 fd
= open(fname
, O_RDONLY
|O_BINARY
);
880 error("can't open %s: %s", fname
, pcap_strerror(errno
));
882 if (fstat(fd
, &buf
) < 0)
883 error("can't stat %s: %s", fname
, pcap_strerror(errno
));
885 cp
= malloc((u_int
)buf
.st_size
+ 1);
887 error("malloc(%d) for %s: %s", (u_int
)buf
.st_size
+ 1,
888 fname
, pcap_strerror(errno
));
889 cc
= read(fd
, cp
, (u_int
)buf
.st_size
);
891 error("read %s: %s", fname
, pcap_strerror(errno
));
892 if (cc
!= buf
.st_size
)
893 error("short read %s (%d != %d)", fname
, cc
, (int)buf
.st_size
);
896 /* replace "# comment" with spaces */
897 for (i
= 0; i
< cc
; i
++) {
899 while (i
< cc
&& cp
[i
] != '\n')
907 safeputs(netdissect_options
*ndo
,
908 const u_char
*s
, const u_int maxlen
)
912 while (*s
&& idx
< maxlen
) {
913 safeputchar(ndo
, *s
);
920 safeputchar(netdissect_options
*ndo
,
923 ND_PRINT((ndo
, (c
< 0x80 && ND_ISPRINT(c
)) ? "%c" : "\\0x%02x", c
));
928 * Some compilers try to optimize memcpy(), using the alignment constraint
929 * on the argument pointer type. by using this function, we try to avoid the
933 unaligned_memcpy(void *p
, const void *q
, size_t l
)
938 /* As with memcpy(), so with memcmp(). */
940 unaligned_memcmp(const void *p
, const void *q
, size_t l
)
942 return (memcmp(p
, q
, l
));