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.
22 #include <sys/cdefs.h>
24 __RCSID("$NetBSD: util.c,v 1.5 2015/03/31 21:59:35 christos Exp $");
28 * txtproto_print() derived from original code by Hannes Gredler
29 * (hannes@juniper.net):
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that: (1) source code
33 * distributions retain the above copyright notice and this paragraph
34 * in its entirety, and (2) distributions including binary code include
35 * the above copyright notice and this paragraph in its entirety in
36 * the documentation or other materials provided with the distribution.
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
38 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
39 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
40 * FOR A PARTICULAR PURPOSE.
43 #define NETDISSECT_REWORKED
48 #include <tcpdump-stdinc.h>
60 #include "interface.h"
63 * Print out a null-terminated filename (or other ascii string).
64 * If ep is NULL, assume no truncation check is needed.
65 * Return true if truncated.
68 fn_print(netdissect_options
*ndo
,
69 register const u_char
*s
, register const u_char
*ep
)
74 ret
= 1; /* assume truncated */
75 while (ep
== NULL
|| s
< ep
) {
83 ND_PRINT((ndo
, "M-"));
86 c
^= 0x40; /* DEL to ?, others to alpha */
89 ND_PRINT((ndo
, "%c", c
));
95 * Print out a counted filename (or other ascii string).
96 * If ep is NULL, assume no truncation check is needed.
97 * Return true if truncated.
100 fn_printn(netdissect_options
*ndo
,
101 register const u_char
*s
, register u_int n
, register const u_char
*ep
)
105 while (n
> 0 && (ep
== NULL
|| s
< ep
)) {
108 if (!ND_ISASCII(c
)) {
110 ND_PRINT((ndo
, "M-"));
112 if (!ND_ISPRINT(c
)) {
113 c
^= 0x40; /* DEL to ?, others to alpha */
114 ND_PRINT((ndo
, "^"));
116 ND_PRINT((ndo
, "%c", c
));
118 return (n
== 0) ? 0 : 1;
122 * Print out a null-padded filename (or other ascii string).
123 * If ep is NULL, assume no truncation check is needed.
124 * Return true if truncated.
127 fn_printzp(netdissect_options
*ndo
,
128 register const u_char
*s
, register u_int n
,
129 register const u_char
*ep
)
134 ret
= 1; /* assume truncated */
135 while (n
> 0 && (ep
== NULL
|| s
< ep
)) {
142 if (!ND_ISASCII(c
)) {
144 ND_PRINT((ndo
, "M-"));
146 if (!ND_ISPRINT(c
)) {
147 c
^= 0x40; /* DEL to ?, others to alpha */
148 ND_PRINT((ndo
, "^"));
150 ND_PRINT((ndo
, "%c", c
));
152 return (n
== 0) ? 0 : ret
;
156 * Format the timestamp
159 ts_format(netdissect_options
*ndo
160 #ifndef HAVE_PCAP_SET_TSTAMP_PRECISION
165 static char buf
[sizeof("00:00:00.000000000")];
168 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
169 switch (ndo
->ndo_tstamp_precision
) {
171 case PCAP_TSTAMP_PRECISION_MICRO
:
172 format
= "%02d:%02d:%02d.%06u";
175 case PCAP_TSTAMP_PRECISION_NANO
:
176 format
= "%02d:%02d:%02d.%09u";
180 format
= "%02d:%02d:%02d.{unknown precision}";
184 format
= "%02d:%02d:%02d.%06u";
187 snprintf(buf
, sizeof(buf
), format
,
188 sec
/ 3600, (sec
% 3600) / 60, sec
% 60, usec
);
194 * Print the timestamp
197 ts_print(netdissect_options
*ndo
,
198 register const struct timeval
*tvp
)
203 static unsigned b_sec
;
204 static unsigned b_usec
;
208 switch (ndo
->ndo_tflag
) {
210 case 0: /* Default */
211 s
= (tvp
->tv_sec
+ thiszone
) % 86400;
212 ND_PRINT((ndo
, "%s ", ts_format(ndo
, s
, tvp
->tv_usec
)));
215 case 1: /* No time stamp */
218 case 2: /* Unix timeval style */
219 ND_PRINT((ndo
, "%u.%06u ",
220 (unsigned)tvp
->tv_sec
,
221 (unsigned)tvp
->tv_usec
));
224 case 3: /* Microseconds since previous packet */
225 case 5: /* Microseconds since first packet */
227 /* init timestamp for first packet */
228 b_usec
= tvp
->tv_usec
;
232 d_usec
= tvp
->tv_usec
- b_usec
;
233 d_sec
= tvp
->tv_sec
- b_sec
;
240 ND_PRINT((ndo
, "%s ", ts_format(ndo
, d_sec
, d_usec
)));
242 if (ndo
->ndo_tflag
== 3) { /* set timestamp for last packet */
244 b_usec
= tvp
->tv_usec
;
248 case 4: /* Default + Date*/
249 s
= (tvp
->tv_sec
+ thiszone
) % 86400;
250 Time
= (tvp
->tv_sec
+ thiszone
) - s
;
253 ND_PRINT((ndo
, "Date fail "));
255 ND_PRINT((ndo
, "%04d-%02d-%02d %s ",
256 tm
->tm_year
+1900, tm
->tm_mon
+1, tm
->tm_mday
,
257 ts_format(ndo
, s
, tvp
->tv_usec
)));
263 * Print a relative number of seconds (e.g. hold time, prune timer)
264 * in the form 5m1s. This does no truncation, so 32230861 seconds
265 * is represented as 1y1w1d1h1m1s.
268 relts_print(netdissect_options
*ndo
,
271 static const char *lengths
[] = {"y", "w", "d", "h", "m", "s"};
272 static const int seconds
[] = {31536000, 604800, 86400, 3600, 60, 1};
273 const char **l
= lengths
;
274 const int *s
= seconds
;
277 ND_PRINT((ndo
, "0s"));
281 ND_PRINT((ndo
, "-"));
286 ND_PRINT((ndo
, "%d%s", secs
/ *s
, *l
));
287 secs
-= (secs
/ *s
) * *s
;
295 * this is a generic routine for printing unknown data;
296 * we pass on the linefeed plus indentation string to
297 * get a proper output - returns 0 on error
301 print_unknown_data(netdissect_options
*ndo
, const u_char
*cp
,const char *ident
,int len
)
304 ND_PRINT((ndo
,"%sDissector error: print_unknown_data called with negative length",
308 if (ndo
->ndo_snapend
- cp
< len
)
309 len
= ndo
->ndo_snapend
- cp
;
311 ND_PRINT((ndo
,"%sDissector error: print_unknown_data called with pointer past end of packet",
315 hex_print(ndo
, ident
,cp
,len
);
316 return(1); /* everything is ok */
320 * Convert a token value to a string; use "fmt" if not found.
323 tok2strbuf(register const struct tok
*lp
, register const char *fmt
,
324 register u_int v
, char *buf
, size_t bufsize
)
327 while (lp
->s
!= NULL
) {
336 (void)snprintf(buf
, bufsize
, fmt
, v
);
337 return (const char *)buf
;
341 * Convert a token value to a string; use "fmt" if not found.
344 tok2str(register const struct tok
*lp
, register const char *fmt
,
347 static char buf
[4][128];
353 return tok2strbuf(lp
, fmt
, v
, ret
, sizeof(buf
[0]));
357 * Convert a bit token value to a string; use "fmt" if not found.
358 * this is useful for parsing bitfields, the output strings are seperated
359 * if the s field is positive.
362 bittok2str_internal(register const struct tok
*lp
, register const char *fmt
,
363 register int v
, register int sep
)
365 static char buf
[256]; /* our stringbuffer */
367 register int rotbit
; /* this is the bit we rotate through all bitpositions */
369 const char * sepstr
= "";
371 while (lp
!= NULL
&& lp
->s
!= NULL
) {
372 tokval
=lp
->v
; /* load our first value */
374 while (rotbit
!= 0) {
376 * lets AND the rotating bit with our token value
377 * and see if we have got a match
379 if (tokval
== (v
&rotbit
)) {
380 /* ok we have found something */
381 buflen
+=snprintf(buf
+buflen
, sizeof(buf
)-buflen
, "%s%s",
383 sepstr
= sep
? ", " : "";
386 rotbit
=rotbit
<<1; /* no match - lets shift and try again */
392 /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
393 (void)snprintf(buf
, sizeof(buf
), fmt
== NULL
? "#%d" : fmt
, v
);
398 * Convert a bit token value to a string; use "fmt" if not found.
399 * this is useful for parsing bitfields, the output strings are not seperated.
402 bittok2str_nosep(register const struct tok
*lp
, register const char *fmt
,
405 return (bittok2str_internal(lp
, fmt
, v
, 0));
409 * Convert a bit token value to a string; use "fmt" if not found.
410 * this is useful for parsing bitfields, the output strings are comma seperated.
413 bittok2str(register const struct tok
*lp
, register const char *fmt
,
416 return (bittok2str_internal(lp
, fmt
, v
, 1));
420 * Convert a value to a string using an array; the macro
421 * tok2strary() in <interface.h> is the public interface to
422 * this function and ensures that the second argument is
423 * correct for bounds-checking.
426 tok2strary_internal(register const char **lp
, int n
, register const char *fmt
,
429 static char buf
[128];
431 if (v
>= 0 && v
< n
&& lp
[v
] != NULL
)
435 (void)snprintf(buf
, sizeof(buf
), fmt
, v
);
440 * Convert a 32-bit netmask to prefixlen if possible
441 * the function returns the prefix-len; if plen == -1
442 * then conversion was not possible;
446 mask2plen(uint32_t mask
)
448 uint32_t bitmasks
[33] = {
450 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
451 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
452 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
453 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
454 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
455 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
456 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
457 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
461 /* let's see if we can transform the mask into a prefixlen */
462 while (prefix_len
>= 0) {
463 if (bitmasks
[prefix_len
] == mask
)
472 mask62plen(const u_char
*mask
)
474 u_char bitmasks
[9] = {
476 0x80, 0xc0, 0xe0, 0xf0,
477 0xf8, 0xfc, 0xfe, 0xff
482 for (byte
= 0; byte
< 16; byte
++) {
485 for (bits
= 0; bits
< (sizeof (bitmasks
) / sizeof (bitmasks
[0])); bits
++) {
486 if (mask
[byte
] == bitmasks
[bits
]) {
492 if (mask
[byte
] != 0xff)
500 * Routine to print out information for text-based protocols such as FTP,
501 * HTTP, SMTP, RTSP, SIP, ....
503 #define MAX_TOKEN 128
506 * Fetch a token from a packet, starting at the specified index,
507 * and return the length of the token.
509 * Returns 0 on error; yes, this is indistinguishable from an empty
510 * token, but an "empty token" isn't a valid token - it just means
511 * either a space character at the beginning of the line (this
512 * includes a blank line) or no more tokens remaining on the line.
515 fetch_token(netdissect_options
*ndo
, const u_char
*pptr
, u_int idx
, u_int len
,
516 u_char
*tbuf
, size_t tbuflen
)
520 for (; idx
< len
; idx
++) {
521 if (!ND_TTEST(*(pptr
+ idx
))) {
522 /* ran past end of captured data */
525 if (!isascii(*(pptr
+ idx
))) {
526 /* not an ASCII character */
529 if (isspace(*(pptr
+ idx
))) {
533 if (!isprint(*(pptr
+ idx
))) {
534 /* not part of a command token or response code */
537 if (toklen
+ 2 > tbuflen
) {
538 /* no room for this character and terminating '\0' */
541 tbuf
[toklen
] = *(pptr
+ idx
);
551 * Skip past any white space after the token, until we see
552 * an end-of-line (CR or LF).
554 for (; idx
< len
; idx
++) {
555 if (!ND_TTEST(*(pptr
+ idx
))) {
556 /* ran past end of captured data */
559 if (*(pptr
+ idx
) == '\r' || *(pptr
+ idx
) == '\n') {
563 if (!isascii(*(pptr
+ idx
)) || !isprint(*(pptr
+ idx
))) {
564 /* not a printable ASCII character */
567 if (!isspace(*(pptr
+ idx
))) {
568 /* beginning of next token */
576 * Scan a buffer looking for a line ending - LF or CR-LF.
577 * Return the index of the character after the line ending or 0 if
578 * we encounter a non-ASCII or non-printable character or don't find
582 print_txt_line(netdissect_options
*ndo
, const char *protoname
,
583 const char *prefix
, const u_char
*pptr
, u_int idx
, u_int len
)
590 ND_TCHECK(*(pptr
+idx
));
591 if (*(pptr
+idx
) == '\n') {
593 * LF without CR; end of line.
594 * Skip the LF and print the line, with the
595 * exception of the LF.
597 linelen
= idx
- startidx
;
600 } else if (*(pptr
+idx
) == '\r') {
602 if ((idx
+1) >= len
) {
603 /* not in this packet */
606 ND_TCHECK(*(pptr
+idx
+1));
607 if (*(pptr
+idx
+1) == '\n') {
609 * CR-LF; end of line.
610 * Skip the CR-LF and print the line, with
611 * the exception of the CR-LF.
613 linelen
= idx
- startidx
;
619 * CR followed by something else; treat this
620 * as if it were binary data, and don't print
624 } else if (!isascii(*(pptr
+idx
)) ||
625 (!isprint(*(pptr
+idx
)) && *(pptr
+idx
) != '\t')) {
627 * Not a printable ASCII character and not a tab;
628 * treat this as if it were binary data, and
637 * All printable ASCII, but no line ending after that point
638 * in the buffer; treat this as if it were truncated.
641 linelen
= idx
- startidx
;
642 ND_PRINT((ndo
, "%s%.*s[!%s]", prefix
, (int)linelen
, pptr
+ startidx
,
647 ND_PRINT((ndo
, "%s%.*s", prefix
, (int)linelen
, pptr
+ startidx
));
652 txtproto_print(netdissect_options
*ndo
, const u_char
*pptr
, u_int len
,
653 const char *protoname
, const char **cmds
, u_int flags
)
656 u_char token
[MAX_TOKEN
+1];
663 * This protocol has more than just request and
664 * response lines; see whether this looks like a
665 * request or response.
667 idx
= fetch_token(ndo
, pptr
, 0, len
, token
, sizeof(token
));
669 /* Is this a valid request name? */
670 while ((cmd
= *cmds
++) != NULL
) {
671 if (strcasecmp((const char *)token
, cmd
) == 0) {
679 * No - is this a valid response code (3 digits)?
681 * Is this token the response code, or is the next
682 * token the response code?
684 if (flags
& RESP_CODE_SECOND_TOKEN
) {
686 * Next token - get it.
688 idx
= fetch_token(ndo
, pptr
, idx
, len
, token
,
692 if (isdigit(token
[0]) && isdigit(token
[1]) &&
693 isdigit(token
[2]) && token
[3] == '\0') {
701 * This protocol has only request and response lines
702 * (e.g., FTP, where all the data goes over a
703 * different connection); assume the payload is
704 * a request or response.
709 /* Capitalize the protocol name */
710 for (pnp
= protoname
; *pnp
!= '\0'; pnp
++)
711 ND_PRINT((ndo
, "%c", toupper((unsigned char)*pnp
)));
715 * In non-verbose mode, just print the protocol, followed
716 * by the first line as the request or response info.
718 * In verbose mode, print lines as text until we run out
719 * of characters or see something that's not a
720 * printable-ASCII line.
722 if (ndo
->ndo_vflag
) {
724 * We're going to print all the text lines in the
725 * request or response; just print the length
726 * on the first line of the output.
728 ND_PRINT((ndo
, ", length: %u", len
));
730 idx
< len
&& (eol
= print_txt_line(ndo
, protoname
, "\n\t", pptr
, idx
, len
)) != 0;
735 * Just print the first text line.
737 print_txt_line(ndo
, protoname
, ": ", pptr
, 0, len
);
744 error(const char *fmt
, ...)
748 (void)fprintf(stderr
, "%s: ", program_name
);
750 (void)vfprintf(stderr
, fmt
, ap
);
755 (void)fputc('\n', stderr
);
763 warning(const char *fmt
, ...)
767 (void)fprintf(stderr
, "%s: WARNING: ", program_name
);
769 (void)vfprintf(stderr
, fmt
, ap
);
774 (void)fputc('\n', stderr
);
779 * Copy arg vector into a new buffer, concatenating arguments with spaces.
782 copy_argv(register char **argv
)
785 register u_int len
= 0;
794 len
+= strlen(*p
++) + 1;
796 buf
= (char *)malloc(len
);
798 error("copy_argv: malloc");
802 while ((src
= *p
++) != NULL
) {
803 while ((*dst
++ = *src
++) != '\0')
813 * On Windows, we need to open the file in binary mode, so that
814 * we get all the bytes specified by the size we get from "fstat()".
815 * On UNIX, that's not necessary. O_BINARY is defined on Windows;
816 * we define it as 0 if it's not defined, so it does nothing.
823 read_infile(char *fname
)
825 register int i
, fd
, cc
;
829 fd
= open(fname
, O_RDONLY
|O_BINARY
);
831 error("can't open %s: %s", fname
, pcap_strerror(errno
));
833 if (fstat(fd
, &buf
) < 0)
834 error("can't stat %s: %s", fname
, pcap_strerror(errno
));
836 cp
= malloc((u_int
)buf
.st_size
+ 1);
838 error("malloc(%d) for %s: %s", (u_int
)buf
.st_size
+ 1,
839 fname
, pcap_strerror(errno
));
840 cc
= read(fd
, cp
, (u_int
)buf
.st_size
);
842 error("read %s: %s", fname
, pcap_strerror(errno
));
843 if (cc
!= buf
.st_size
)
844 error("short read %s (%d != %d)", fname
, cc
, (int)buf
.st_size
);
847 /* replace "# comment" with spaces */
848 for (i
= 0; i
< cc
; i
++) {
850 while (i
< cc
&& cp
[i
] != '\n')
858 safeputs(netdissect_options
*ndo
,
859 const u_char
*s
, const u_int maxlen
)
863 while (*s
&& idx
< maxlen
) {
864 safeputchar(ndo
, *s
);
871 safeputchar(netdissect_options
*ndo
,
874 ND_PRINT((ndo
, (c
< 0x80 && ND_ISPRINT(c
)) ? "%c" : "\\0x%02x", c
));
879 * Some compilers try to optimize memcpy(), using the alignment constraint
880 * on the argument pointer type. by using this function, we try to avoid the
884 unaligned_memcpy(void *p
, const void *q
, size_t l
)
889 /* As with memcpy(), so with memcmp(). */
891 unaligned_memcmp(const void *p
, const void *q
, size_t l
)
893 return (memcmp(p
, q
, l
));