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@gredler.at):
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.
42 #include <netdissect-stdinc.h>
55 #include "netdissect.h"
56 #include "ascii_strcasecmp.h"
57 #include "timeval-operations.h"
59 int32_t thiszone; /* seconds offset from gmt to local time */
60 /* invalid string to print '(invalid)' for malformed or corrupted packets */
61 const char istr[] = " (invalid)";
64 * timestamp display buffer size, the biggest size of both formats is needed
65 * sizeof("0000000000.000000000") > sizeof("00:00:00.000000000")
67 #define TS_BUF_SIZE sizeof("0000000000.000000000")
69 #define TOKBUFSIZE 128
72 * Print out a character, filtering out the non-printable ones
75 fn_print_char(netdissect_options *ndo, u_char c)
79 ND_PRINT((ndo, "M-"));
82 c ^= 0x40; /* DEL to ?, others to alpha */
85 ND_PRINT((ndo, "%c", c));
89 * Print out a null-terminated filename (or other ascii string).
90 * If ep is NULL, assume no truncation check is needed.
91 * Return true if truncated.
92 * Stop at ep (if given) or before the null char, whichever is first.
95 fn_print(netdissect_options *ndo,
96 register const u_char *s, register const u_char *ep)
101 ret = 1; /* assume truncated */
102 while (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));
122 * Print out a null-terminated filename (or other ascii string) from
123 * a fixed-length field in the packet buffer, or from what remains of
126 * n is the length of the fixed-length field, or the number of bytes
127 * remaining in the packet based on its on-the-network length.
129 * If ep is non-null, it should point just past the last captured byte
130 * of the packet, e.g. ndo->ndo_snapend. If ep is NULL, we assume no
131 * truncation check, other than the checks of the field length/remaining
132 * packet data length, is needed.
134 * Return the number of bytes of string processed, including the
135 * terminating null, if not truncated; as the terminating null is
136 * included in the count, and as there must be a terminating null,
137 * this will always be non-zero. Return 0 if truncated.
140 fn_printztn(netdissect_options *ndo,
141 register const u_char *s, register u_int n, register const u_char *ep)
143 register u_int bytes;
148 if (n == 0 || (ep != NULL && s >= ep)) {
150 * Truncated. This includes "no null before we
151 * got to the end of the fixed-length buffer or
152 * the end of the packet".
154 * XXX - BOOTP says "null-terminated", which
155 * means the maximum length of the string, in
156 * bytes, is 1 less than the size of the buffer,
157 * as there must always be a terminating null.
170 if (!ND_ISASCII(c)) {
172 ND_PRINT((ndo, "M-"));
174 if (!ND_ISPRINT(c)) {
175 c ^= 0x40; /* DEL to ?, others to alpha */
176 ND_PRINT((ndo, "^"));
178 ND_PRINT((ndo, "%c", c));
184 * Print out a counted filename (or other ascii string).
185 * If ep is NULL, assume no truncation check is needed.
186 * Return true if truncated.
187 * Stop at ep (if given) or after n bytes, whichever is first.
190 fn_printn(netdissect_options *ndo,
191 register const u_char *s, register u_int n, register const u_char *ep)
195 while (n > 0 && (ep == NULL || s < ep)) {
198 if (!ND_ISASCII(c)) {
200 ND_PRINT((ndo, "M-"));
202 if (!ND_ISPRINT(c)) {
203 c ^= 0x40; /* DEL to ?, others to alpha */
204 ND_PRINT((ndo, "^"));
206 ND_PRINT((ndo, "%c", c));
208 return (n == 0) ? 0 : 1;
212 * Print out a null-padded filename (or other ascii string).
213 * If ep is NULL, assume no truncation check is needed.
214 * Return true if truncated.
215 * Stop at ep (if given) or after n bytes or before the null char,
216 * whichever is first.
219 fn_printzp(netdissect_options *ndo,
220 register const u_char *s, register u_int n,
221 register const u_char *ep)
226 ret = 1; /* assume truncated */
227 while (n > 0 && (ep == NULL || s < ep)) {
234 if (!ND_ISASCII(c)) {
236 ND_PRINT((ndo, "M-"));
238 if (!ND_ISPRINT(c)) {
239 c ^= 0x40; /* DEL to ?, others to alpha */
240 ND_PRINT((ndo, "^"));
242 ND_PRINT((ndo, "%c", c));
244 return (n == 0) ? 0 : ret;
248 * Format the timestamp
251 ts_format(netdissect_options *ndo
252 #ifndef HAVE_PCAP_SET_TSTAMP_PRECISION
255 , int sec, int usec, char *buf)
259 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
260 switch (ndo->ndo_tstamp_precision) {
262 case PCAP_TSTAMP_PRECISION_MICRO:
263 format = "%02d:%02d:%02d.%06u";
266 case PCAP_TSTAMP_PRECISION_NANO:
267 format = "%02d:%02d:%02d.%09u";
271 format = "%02d:%02d:%02d.{unknown}";
275 format = "%02d:%02d:%02d.%06u";
278 snprintf(buf, TS_BUF_SIZE, format,
279 sec / 3600, (sec % 3600) / 60, sec % 60, usec);
285 * Format the timestamp - Unix timeval style
288 ts_unix_format(netdissect_options *ndo
289 #ifndef HAVE_PCAP_SET_TSTAMP_PRECISION
292 , int sec, int usec, char *buf)
296 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
297 switch (ndo->ndo_tstamp_precision) {
299 case PCAP_TSTAMP_PRECISION_MICRO:
303 case PCAP_TSTAMP_PRECISION_NANO:
308 format = "%u.{unknown}";
315 snprintf(buf, TS_BUF_SIZE, format,
316 (unsigned)sec, (unsigned)usec);
322 * Print the timestamp
325 ts_print(netdissect_options *ndo,
326 register const struct timeval *tvp)
331 char buf[TS_BUF_SIZE];
332 static struct timeval tv_ref;
333 struct timeval tv_result;
337 switch (ndo->ndo_tflag) {
339 case 0: /* Default */
340 s = (tvp->tv_sec + thiszone) % 86400;
341 ND_PRINT((ndo, "%s ", ts_format(ndo, s, tvp->tv_usec, buf)));
344 case 1: /* No time stamp */
347 case 2: /* Unix timeval style */
348 ND_PRINT((ndo, "%s ", ts_unix_format(ndo,
349 tvp->tv_sec, tvp->tv_usec, buf)));
352 case 3: /* Microseconds/nanoseconds since previous packet */
353 case 5: /* Microseconds/nanoseconds since first packet */
354 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
355 switch (ndo->ndo_tstamp_precision) {
356 case PCAP_TSTAMP_PRECISION_MICRO:
359 case PCAP_TSTAMP_PRECISION_NANO:
369 if (!(netdissect_timevalisset(&tv_ref)))
370 tv_ref = *tvp; /* set timestamp for first packet */
372 negative_offset = netdissect_timevalcmp(tvp, &tv_ref, <);
374 netdissect_timevalsub(&tv_ref, tvp, &tv_result, nano_prec);
376 netdissect_timevalsub(tvp, &tv_ref, &tv_result, nano_prec);
378 ND_PRINT((ndo, (negative_offset ? "-" : " ")));
380 ND_PRINT((ndo, "%s ", ts_format(ndo,
381 tv_result.tv_sec, tv_result.tv_usec, buf)));
383 if (ndo->ndo_tflag == 3)
384 tv_ref = *tvp; /* set timestamp for previous packet */
387 case 4: /* Default + Date */
388 s = (tvp->tv_sec + thiszone) % 86400;
389 Time = (tvp->tv_sec + thiszone) - s;
392 ND_PRINT((ndo, "Date fail "));
394 ND_PRINT((ndo, "%04d-%02d-%02d %s ",
395 tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
396 ts_format(ndo, s, tvp->tv_usec, buf)));
402 * Print an unsigned relative number of seconds (e.g. hold time, prune timer)
403 * in the form 5m1s. This does no truncation, so 32230861 seconds
404 * is represented as 1y1w1d1h1m1s.
407 unsigned_relts_print(netdissect_options *ndo,
410 static const char *lengths[] = {"y", "w", "d", "h", "m", "s"};
411 static const u_int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
412 const char **l = lengths;
413 const u_int *s = seconds;
416 ND_PRINT((ndo, "0s"));
421 ND_PRINT((ndo, "%d%s", secs / *s, *l));
422 secs -= (secs / *s) * *s;
430 * Print a signed relative number of seconds (e.g. hold time, prune timer)
431 * in the form 5m1s. This does no truncation, so 32230861 seconds
432 * is represented as 1y1w1d1h1m1s.
435 signed_relts_print(netdissect_options *ndo,
439 ND_PRINT((ndo, "-"));
440 if (secs == INT32_MIN) {
442 * -2^31; you can't fit its absolute value into
443 * a 32-bit signed integer.
445 * Just directly pass said absolute value to
446 * unsigned_relts_print() directly.
448 * (XXX - does ISO C guarantee that -(-2^n),
449 * when calculated and cast to an n-bit unsigned
450 * integer type, will have the value 2^n?)
452 unsigned_relts_print(ndo, 2147483648U);
455 * We now know -secs will fit into an int32_t;
456 * negate it and pass that to unsigned_relts_print().
458 unsigned_relts_print(ndo, -secs);
462 unsigned_relts_print(ndo, secs);
466 * this is a generic routine for printing unknown data;
467 * we pass on the linefeed plus indentation string to
468 * get a proper output - returns 0 on error
472 print_unknown_data(netdissect_options *ndo, const u_char *cp,const char *ident,int len)
475 ND_PRINT((ndo,"%sDissector error: print_unknown_data called with negative length",
479 if (ndo->ndo_snapend - cp < len)
480 len = ndo->ndo_snapend - cp;
482 ND_PRINT((ndo,"%sDissector error: print_unknown_data called with pointer past end of packet",
486 hex_print(ndo, ident,cp,len);
487 return(1); /* everything is ok */
491 * Convert a token value to a string; use "fmt" if not found.
494 tok2strbuf(register const struct tok *lp, register const char *fmt,
495 register u_int v, char *buf, size_t bufsize)
498 while (lp->s != NULL) {
507 (void)snprintf(buf, bufsize, fmt, v);
508 return (const char *)buf;
512 * Convert a token value to a string; use "fmt" if not found.
515 tok2str(register const struct tok *lp, register const char *fmt,
518 static char buf[4][TOKBUFSIZE];
524 return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0]));
528 * Convert a bit token value to a string; use "fmt" if not found.
529 * this is useful for parsing bitfields, the output strings are seperated
530 * if the s field is positive.
533 bittok2str_internal(register const struct tok *lp, register const char *fmt,
534 register u_int v, const char *sep)
536 static char buf[1024+1]; /* our string buffer */
538 size_t space_left = sizeof(buf), string_size;
539 register u_int rotbit; /* this is the bit we rotate through all bitpositions */
540 register u_int tokval;
541 const char * sepstr = "";
543 while (lp != NULL && lp->s != NULL) {
544 tokval=lp->v; /* load our first value */
546 while (rotbit != 0) {
548 * lets AND the rotating bit with our token value
549 * and see if we have got a match
551 if (tokval == (v&rotbit)) {
552 /* ok we have found something */
554 return (buf); /* only enough room left for NUL, if that */
555 string_size = strlcpy(bufp, sepstr, space_left);
556 if (string_size >= space_left)
557 return (buf); /* we ran out of room */
559 space_left -= string_size;
561 return (buf); /* only enough room left for NUL, if that */
562 string_size = strlcpy(bufp, lp->s, space_left);
563 if (string_size >= space_left)
564 return (buf); /* we ran out of room */
566 space_left -= string_size;
570 rotbit=rotbit<<1; /* no match - lets shift and try again */
576 /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
577 (void)snprintf(buf, sizeof(buf), fmt == NULL ? "#%08x" : fmt, v);
582 * Convert a bit token value to a string; use "fmt" if not found.
583 * this is useful for parsing bitfields, the output strings are not seperated.
586 bittok2str_nosep(register const struct tok *lp, register const char *fmt,
589 return (bittok2str_internal(lp, fmt, v, ""));
593 * Convert a bit token value to a string; use "fmt" if not found.
594 * this is useful for parsing bitfields, the output strings are comma seperated.
597 bittok2str(register const struct tok *lp, register const char *fmt,
600 return (bittok2str_internal(lp, fmt, v, ", "));
604 * Convert a value to a string using an array; the macro
605 * tok2strary() in <netdissect.h> is the public interface to
606 * this function and ensures that the second argument is
607 * correct for bounds-checking.
610 tok2strary_internal(register const char **lp, int n, register const char *fmt,
613 static char buf[TOKBUFSIZE];
615 if (v >= 0 && v < n && lp[v] != NULL)
619 (void)snprintf(buf, sizeof(buf), fmt, v);
624 * Convert a 32-bit netmask to prefixlen if possible
625 * the function returns the prefix-len; if plen == -1
626 * then conversion was not possible;
630 mask2plen(uint32_t mask)
632 uint32_t bitmasks[33] = {
634 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
635 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
636 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
637 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
638 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
639 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
640 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
641 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
645 /* let's see if we can transform the mask into a prefixlen */
646 while (prefix_len >= 0) {
647 if (bitmasks[prefix_len] == mask)
655 mask62plen(const u_char *mask)
657 u_char bitmasks[9] = {
659 0x80, 0xc0, 0xe0, 0xf0,
660 0xf8, 0xfc, 0xfe, 0xff
665 for (byte = 0; byte < 16; byte++) {
668 for (bits = 0; bits < (sizeof (bitmasks) / sizeof (bitmasks[0])); bits++) {
669 if (mask[byte] == bitmasks[bits]) {
675 if (mask[byte] != 0xff)
682 * Routine to print out information for text-based protocols such as FTP,
683 * HTTP, SMTP, RTSP, SIP, ....
685 #define MAX_TOKEN 128
688 * Fetch a token from a packet, starting at the specified index,
689 * and return the length of the token.
691 * Returns 0 on error; yes, this is indistinguishable from an empty
692 * token, but an "empty token" isn't a valid token - it just means
693 * either a space character at the beginning of the line (this
694 * includes a blank line) or no more tokens remaining on the line.
697 fetch_token(netdissect_options *ndo, const u_char *pptr, u_int idx, u_int len,
698 u_char *tbuf, size_t tbuflen)
702 for (; idx < len; idx++) {
703 if (!ND_TTEST(*(pptr + idx))) {
704 /* ran past end of captured data */
707 if (!isascii(*(pptr + idx))) {
708 /* not an ASCII character */
711 if (isspace(*(pptr + idx))) {
715 if (!isprint(*(pptr + idx))) {
716 /* not part of a command token or response code */
719 if (toklen + 2 > tbuflen) {
720 /* no room for this character and terminating '\0' */
723 tbuf[toklen] = *(pptr + idx);
733 * Skip past any white space after the token, until we see
734 * an end-of-line (CR or LF).
736 for (; idx < len; idx++) {
737 if (!ND_TTEST(*(pptr + idx))) {
738 /* ran past end of captured data */
741 if (*(pptr + idx) == '\r' || *(pptr + idx) == '\n') {
745 if (!isascii(*(pptr + idx)) || !isprint(*(pptr + idx))) {
746 /* not a printable ASCII character */
749 if (!isspace(*(pptr + idx))) {
750 /* beginning of next token */
758 * Scan a buffer looking for a line ending - LF or CR-LF.
759 * Return the index of the character after the line ending or 0 if
760 * we encounter a non-ASCII or non-printable character or don't find
764 print_txt_line(netdissect_options *ndo, const char *protoname,
765 const char *prefix, const u_char *pptr, u_int idx, u_int len)
772 ND_TCHECK(*(pptr+idx));
773 if (*(pptr+idx) == '\n') {
775 * LF without CR; end of line.
776 * Skip the LF and print the line, with the
777 * exception of the LF.
779 linelen = idx - startidx;
782 } else if (*(pptr+idx) == '\r') {
784 if ((idx+1) >= len) {
785 /* not in this packet */
788 ND_TCHECK(*(pptr+idx+1));
789 if (*(pptr+idx+1) == '\n') {
791 * CR-LF; end of line.
792 * Skip the CR-LF and print the line, with
793 * the exception of the CR-LF.
795 linelen = idx - startidx;
801 * CR followed by something else; treat this
802 * as if it were binary data, and don't print
806 } else if (!isascii(*(pptr+idx)) ||
807 (!isprint(*(pptr+idx)) && *(pptr+idx) != '\t')) {
809 * Not a printable ASCII character and not a tab;
810 * treat this as if it were binary data, and
819 * All printable ASCII, but no line ending after that point
820 * in the buffer; treat this as if it were truncated.
823 linelen = idx - startidx;
824 ND_PRINT((ndo, "%s%.*s[!%s]", prefix, (int)linelen, pptr + startidx,
829 ND_PRINT((ndo, "%s%.*s", prefix, (int)linelen, pptr + startidx));
834 txtproto_print(netdissect_options *ndo, const u_char *pptr, u_int len,
835 const char *protoname, const char **cmds, u_int flags)
838 u_char token[MAX_TOKEN+1];
845 * This protocol has more than just request and
846 * response lines; see whether this looks like a
847 * request or response.
849 idx = fetch_token(ndo, pptr, 0, len, token, sizeof(token));
851 /* Is this a valid request name? */
852 while ((cmd = *cmds++) != NULL) {
853 if (ascii_strcasecmp((const char *)token, cmd) == 0) {
861 * No - is this a valid response code (3 digits)?
863 * Is this token the response code, or is the next
864 * token the response code?
866 if (flags & RESP_CODE_SECOND_TOKEN) {
868 * Next token - get it.
870 idx = fetch_token(ndo, pptr, idx, len, token,
874 if (isdigit(token[0]) && isdigit(token[1]) &&
875 isdigit(token[2]) && token[3] == '\0') {
883 * This protocol has only request and response lines
884 * (e.g., FTP, where all the data goes over a
885 * different connection); assume the payload is
886 * a request or response.
891 /* Capitalize the protocol name */
892 for (pnp = protoname; *pnp != '\0'; pnp++)
893 ND_PRINT((ndo, "%c", toupper((u_char)*pnp)));
897 * In non-verbose mode, just print the protocol, followed
898 * by the first line as the request or response info.
900 * In verbose mode, print lines as text until we run out
901 * of characters or see something that's not a
902 * printable-ASCII line.
904 if (ndo->ndo_vflag) {
906 * We're going to print all the text lines in the
907 * request or response; just print the length
908 * on the first line of the output.
910 ND_PRINT((ndo, ", length: %u", len));
912 idx < len && (eol = print_txt_line(ndo, protoname, "\n\t", pptr, idx, len)) != 0;
917 * Just print the first text line.
919 print_txt_line(ndo, protoname, ": ", pptr, 0, len);
925 safeputs(netdissect_options *ndo,
926 const u_char *s, const u_int maxlen)
930 while (idx < maxlen && *s) {
931 safeputchar(ndo, *s);
938 safeputchar(netdissect_options *ndo,
941 ND_PRINT((ndo, (c < 0x80 && ND_ISPRINT(c)) ? "%c" : "\\0x%02x", c));
946 * Some compilers try to optimize memcpy(), using the alignment constraint
947 * on the argument pointer type. by using this function, we try to avoid the
951 unaligned_memcpy(void *p, const void *q, size_t l)
956 /* As with memcpy(), so with memcmp(). */
958 unaligned_memcmp(const void *p, const void *q, size_t l)
960 return (memcmp(p, q, l));