xref: /dragonfly/contrib/tcpdump/util-print.c (revision 59c07fbdf8168fa08c76c515186d561b5a92690c)
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@gredler.at):
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 "netdissect-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 "netdissect-ctype.h"
55 
56 #include "netdissect.h"
57 #include "extract.h"
58 #include "ascii_strcasecmp.h"
59 #include "timeval-operations.h"
60 
61 #define TOKBUFSIZE 128
62 
63 enum date_flag { WITHOUT_DATE = 0, WITH_DATE = 1 };
64 enum time_flag { UTC_TIME = 0, LOCAL_TIME = 1 };
65 
66 /*
67  * Print out a character, filtering out the non-printable ones
68  */
69 void
fn_print_char(netdissect_options * ndo,u_char c)70 fn_print_char(netdissect_options *ndo, u_char c)
71 {
72           if (!ND_ISASCII(c)) {
73                     c = ND_TOASCII(c);
74                     ND_PRINT("M-");
75           }
76           if (!ND_ASCII_ISPRINT(c)) {
77                     c ^= 0x40;          /* DEL to ?, others to alpha */
78                     ND_PRINT("^");
79           }
80           ND_PRINT("%c", c);
81 }
82 
83 /*
84  * Print a null-terminated string, filtering out non-printable characters.
85  * DON'T USE IT with a pointer on the packet buffer because there is no
86  * truncation check. For this use, see the nd_printX() functions below.
87  */
88 void
fn_print_str(netdissect_options * ndo,const u_char * s)89 fn_print_str(netdissect_options *ndo, const u_char *s)
90 {
91           while (*s != '\0') {
92                     fn_print_char(ndo, *s);
93                     s++;
94        }
95 }
96 
97 /*
98  * Print out a null-terminated filename (or other ASCII string) from
99  * a fixed-length field in the packet buffer, or from what remains of
100  * the packet.
101  *
102  * n is the length of the fixed-length field, or the number of bytes
103  * remaining in the packet based on its on-the-network length.
104  *
105  * If ep is non-null, it should point just past the last captured byte
106  * of the packet, e.g. ndo->ndo_snapend.  If ep is NULL, we assume no
107  * truncation check, other than the checks of the field length/remaining
108  * packet data length, is needed.
109  *
110  * Return the number of bytes of string processed, including the
111  * terminating null, if not truncated; as the terminating null is
112  * included in the count, and as there must be a terminating null,
113  * this will always be non-zero.  Return 0 if truncated.
114  */
115 u_int
nd_printztn(netdissect_options * ndo,const u_char * s,u_int n,const u_char * ep)116 nd_printztn(netdissect_options *ndo,
117          const u_char *s, u_int n, const u_char *ep)
118 {
119           u_int bytes;
120           u_char c;
121 
122           bytes = 0;
123           for (;;) {
124                     if (n == 0 || (ep != NULL && s >= ep)) {
125                               /*
126                                * Truncated.  This includes "no null before we
127                                * got to the end of the fixed-length buffer or
128                                * the end of the packet".
129                                *
130                                * XXX - BOOTP says "null-terminated", which
131                                * means the maximum length of the string, in
132                                * bytes, is 1 less than the size of the buffer,
133                                * as there must always be a terminating null.
134                                */
135                               bytes = 0;
136                               break;
137                     }
138 
139                     c = GET_U_1(s);
140                     s++;
141                     bytes++;
142                     n--;
143                     if (c == '\0') {
144                               /* End of string */
145                               break;
146                     }
147                     fn_print_char(ndo, c);
148           }
149           return(bytes);
150 }
151 
152 /*
153  * Print out a counted filename (or other ASCII string), part of
154  * the packet buffer.
155  * If ep is NULL, assume no truncation check is needed.
156  * Return true if truncated.
157  * Stop at ep (if given) or after n bytes, whichever is first.
158  */
159 int
nd_printn(netdissect_options * ndo,const u_char * s,u_int n,const u_char * ep)160 nd_printn(netdissect_options *ndo,
161           const u_char *s, u_int n, const u_char *ep)
162 {
163           u_char c;
164 
165           while (n > 0 && (ep == NULL || s < ep)) {
166                     n--;
167                     c = GET_U_1(s);
168                     s++;
169                     fn_print_char(ndo, c);
170           }
171           return (n == 0) ? 0 : 1;
172 }
173 
174 /*
175  * Print a null-padded filename (or other ASCII string), part of
176  * the packet buffer, filtering out non-printable characters.
177  * Stop if truncated (via GET_U_1/longjmp) or after n bytes or before
178  * the null char, whichever occurs first.
179  * The suffix comes from: j:longJmp, n:after N bytes, p:null-Padded.
180  */
181 void
nd_printjnp(netdissect_options * ndo,const u_char * s,u_int n)182 nd_printjnp(netdissect_options *ndo, const u_char *s, u_int n)
183 {
184           u_char c;
185 
186           while (n > 0) {
187                     c = GET_U_1(s);
188                     if (c == '\0')
189                               break;
190                     fn_print_char(ndo, c);
191                     n--;
192                     s++;
193           }
194 }
195 
196 /*
197  * Print the timestamp .FRAC part (Microseconds/nanoseconds)
198  */
199 static void
ts_frac_print(netdissect_options * ndo,long usec)200 ts_frac_print(netdissect_options *ndo, long usec)
201 {
202 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
203           switch (ndo->ndo_tstamp_precision) {
204 
205           case PCAP_TSTAMP_PRECISION_MICRO:
206                     ND_PRINT(".%06u", (unsigned)usec);
207                     break;
208 
209           case PCAP_TSTAMP_PRECISION_NANO:
210                     ND_PRINT(".%09u", (unsigned)usec);
211                     break;
212 
213           default:
214                     ND_PRINT(".{unknown}");
215                     break;
216           }
217 #else
218           ND_PRINT(".%06u", (unsigned)usec);
219 #endif
220 }
221 
222 /*
223  * Print the timestamp as [YY:MM:DD] HH:MM:SS.FRAC.
224  *   if time_flag == LOCAL_TIME print local time else UTC/GMT time
225  *   if date_flag == WITH_DATE print YY:MM:DD before HH:MM:SS.FRAC
226  */
227 static void
ts_date_hmsfrac_print(netdissect_options * ndo,long sec,long usec,enum date_flag date_flag,enum time_flag time_flag)228 ts_date_hmsfrac_print(netdissect_options *ndo, long sec, long usec,
229                           enum date_flag date_flag, enum time_flag time_flag)
230 {
231           time_t Time = sec;
232           struct tm *tm;
233           char timestr[32];
234 
235           if ((unsigned)sec & 0x80000000) {
236                     ND_PRINT("[Error converting time]");
237                     return;
238           }
239 
240           if (time_flag == LOCAL_TIME)
241                     tm = localtime(&Time);
242           else
243                     tm = gmtime(&Time);
244 
245           if (!tm) {
246                     ND_PRINT("[Error converting time]");
247                     return;
248           }
249           if (date_flag == WITH_DATE)
250                     strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", tm);
251           else
252                     strftime(timestr, sizeof(timestr), "%H:%M:%S", tm);
253           ND_PRINT("%s", timestr);
254 
255           ts_frac_print(ndo, usec);
256 }
257 
258 /*
259  * Print the timestamp - Unix timeval style, as SECS.FRAC.
260  */
261 static void
ts_unix_print(netdissect_options * ndo,long sec,long usec)262 ts_unix_print(netdissect_options *ndo, long sec, long usec)
263 {
264           if ((unsigned)sec & 0x80000000) {
265                     ND_PRINT("[Error converting time]");
266                     return;
267           }
268 
269           ND_PRINT("%u", (unsigned)sec);
270           ts_frac_print(ndo, usec);
271 }
272 
273 /*
274  * Print the timestamp
275  */
276 void
ts_print(netdissect_options * ndo,const struct timeval * tvp)277 ts_print(netdissect_options *ndo,
278          const struct timeval *tvp)
279 {
280           static struct timeval tv_ref;
281           struct timeval tv_result;
282           int negative_offset;
283           int nano_prec;
284 
285           switch (ndo->ndo_tflag) {
286 
287           case 0: /* Default */
288                     ts_date_hmsfrac_print(ndo, tvp->tv_sec, tvp->tv_usec,
289                                               WITHOUT_DATE, LOCAL_TIME);
290                     ND_PRINT(" ");
291                     break;
292 
293           case 1: /* No time stamp */
294                     break;
295 
296           case 2: /* Unix timeval style */
297                     ts_unix_print(ndo, tvp->tv_sec, tvp->tv_usec);
298                     ND_PRINT(" ");
299                     break;
300 
301           case 3: /* Microseconds/nanoseconds since previous packet */
302         case 5: /* Microseconds/nanoseconds since first packet */
303 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
304                     switch (ndo->ndo_tstamp_precision) {
305                     case PCAP_TSTAMP_PRECISION_MICRO:
306                               nano_prec = 0;
307                               break;
308                     case PCAP_TSTAMP_PRECISION_NANO:
309                               nano_prec = 1;
310                               break;
311                     default:
312                               nano_prec = 0;
313                               break;
314                     }
315 #else
316                     nano_prec = 0;
317 #endif
318                     if (!(netdissect_timevalisset(&tv_ref)))
319                               tv_ref = *tvp; /* set timestamp for first packet */
320 
321                     negative_offset = netdissect_timevalcmp(tvp, &tv_ref, <);
322                     if (negative_offset)
323                               netdissect_timevalsub(&tv_ref, tvp, &tv_result, nano_prec);
324                     else
325                               netdissect_timevalsub(tvp, &tv_ref, &tv_result, nano_prec);
326 
327                     ND_PRINT((negative_offset ? "-" : " "));
328                     ts_date_hmsfrac_print(ndo, tv_result.tv_sec, tv_result.tv_usec,
329                                               WITHOUT_DATE, UTC_TIME);
330                     ND_PRINT(" ");
331 
332                 if (ndo->ndo_tflag == 3)
333                               tv_ref = *tvp; /* set timestamp for previous packet */
334                     break;
335 
336           case 4: /* Date + Default */
337                     ts_date_hmsfrac_print(ndo, tvp->tv_sec, tvp->tv_usec,
338                                               WITH_DATE, LOCAL_TIME);
339                     ND_PRINT(" ");
340                     break;
341           }
342 }
343 
344 /*
345  * Print an unsigned relative number of seconds (e.g. hold time, prune timer)
346  * in the form 5m1s.  This does no truncation, so 32230861 seconds
347  * is represented as 1y1w1d1h1m1s.
348  */
349 void
unsigned_relts_print(netdissect_options * ndo,uint32_t secs)350 unsigned_relts_print(netdissect_options *ndo,
351                      uint32_t secs)
352 {
353           static const char *lengths[] = {"y", "w", "d", "h", "m", "s"};
354           static const u_int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
355           const char **l = lengths;
356           const u_int *s = seconds;
357 
358           if (secs == 0) {
359                     ND_PRINT("0s");
360                     return;
361           }
362           while (secs > 0) {
363                     if (secs >= *s) {
364                               ND_PRINT("%u%s", secs / *s, *l);
365                               secs -= (secs / *s) * *s;
366                     }
367                     s++;
368                     l++;
369           }
370 }
371 
372 /*
373  * Print a signed relative number of seconds (e.g. hold time, prune timer)
374  * in the form 5m1s.  This does no truncation, so 32230861 seconds
375  * is represented as 1y1w1d1h1m1s.
376  */
377 void
signed_relts_print(netdissect_options * ndo,int32_t secs)378 signed_relts_print(netdissect_options *ndo,
379                    int32_t secs)
380 {
381           if (secs < 0) {
382                     ND_PRINT("-");
383                     if (secs == INT32_MIN) {
384                               /*
385                                * -2^31; you can't fit its absolute value into
386                                * a 32-bit signed integer.
387                                *
388                                * Just directly pass said absolute value to
389                                * unsigned_relts_print() directly.
390                                *
391                                * (XXX - does ISO C guarantee that -(-2^n),
392                                * when calculated and cast to an n-bit unsigned
393                                * integer type, will have the value 2^n?)
394                                */
395                               unsigned_relts_print(ndo, 2147483648U);
396                     } else {
397                               /*
398                                * We now know -secs will fit into an int32_t;
399                                * negate it and pass that to unsigned_relts_print().
400                                */
401                               unsigned_relts_print(ndo, -secs);
402                     }
403                     return;
404           }
405           unsigned_relts_print(ndo, secs);
406 }
407 
408 /* Print the truncated string */
nd_print_trunc(netdissect_options * ndo)409 void nd_print_trunc(netdissect_options *ndo)
410 {
411           ND_PRINT(" [|%s]", ndo->ndo_protocol);
412 }
413 
414 /* Print the protocol name */
nd_print_protocol(netdissect_options * ndo)415 void nd_print_protocol(netdissect_options *ndo)
416 {
417           ND_PRINT("%s", ndo->ndo_protocol);
418 }
419 
420 /* Print the protocol name in caps (uppercases) */
nd_print_protocol_caps(netdissect_options * ndo)421 void nd_print_protocol_caps(netdissect_options *ndo)
422 {
423           const char *p;
424         for (p = ndo->ndo_protocol; *p != '\0'; p++)
425                 ND_PRINT("%c", ND_ASCII_TOUPPER(*p));
426 }
427 
428 /* Print the invalid string */
nd_print_invalid(netdissect_options * ndo)429 void nd_print_invalid(netdissect_options *ndo)
430 {
431           ND_PRINT(" (invalid)");
432 }
433 
434 /*
435  *  this is a generic routine for printing unknown data;
436  *  we pass on the linefeed plus indentation string to
437  *  get a proper output - returns 0 on error
438  */
439 
440 int
print_unknown_data(netdissect_options * ndo,const u_char * cp,const char * ident,u_int len)441 print_unknown_data(netdissect_options *ndo, const u_char *cp,
442                    const char *ident, u_int len)
443 {
444           u_int len_to_print;
445 
446           len_to_print = len;
447           if (!ND_TTEST_LEN(cp, 0)) {
448                     ND_PRINT("%sDissector error: print_unknown_data called with pointer past end of packet",
449                         ident);
450                     return(0);
451           }
452           if (ND_BYTES_AVAILABLE_AFTER(cp) < len_to_print)
453                     len_to_print = ND_BYTES_AVAILABLE_AFTER(cp);
454           hex_print(ndo, ident, cp, len_to_print);
455           return(1); /* everything is ok */
456 }
457 
458 /*
459  * Convert a token value to a string; use "fmt" if not found.
460  */
461 const char *
tok2strbuf(const struct tok * lp,const char * fmt,u_int v,char * buf,size_t bufsize)462 tok2strbuf(const struct tok *lp, const char *fmt,
463              u_int v, char *buf, size_t bufsize)
464 {
465           if (lp != NULL) {
466                     while (lp->s != NULL) {
467                               if (lp->v == v)
468                                         return (lp->s);
469                               ++lp;
470                     }
471           }
472           if (fmt == NULL)
473                     fmt = "#%d";
474 
475           (void)snprintf(buf, bufsize, fmt, v);
476           return (const char *)buf;
477 }
478 
479 /*
480  * Convert a token value to a string; use "fmt" if not found.
481  * Uses tok2strbuf() on one of four local static buffers of size TOKBUFSIZE
482  * in round-robin fashion.
483  */
484 const char *
tok2str(const struct tok * lp,const char * fmt,u_int v)485 tok2str(const struct tok *lp, const char *fmt,
486           u_int v)
487 {
488           static char buf[4][TOKBUFSIZE];
489           static int idx = 0;
490           char *ret;
491 
492           ret = buf[idx];
493           idx = (idx+1) & 3;
494           return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0]));
495 }
496 
497 /*
498  * Convert a bit token value to a string; use "fmt" if not found.
499  * this is useful for parsing bitfields, the output strings are separated
500  * if the s field is positive.
501  *
502  * A token matches iff it has one or more bits set and every bit that is set
503  * in the token is set in v. Consequently, a 0 token never matches.
504  */
505 static char *
bittok2str_internal(const struct tok * lp,const char * fmt,u_int v,const char * sep)506 bittok2str_internal(const struct tok *lp, const char *fmt,
507              u_int v, const char *sep)
508 {
509         static char buf[1024+1]; /* our string buffer */
510         char *bufp = buf;
511         size_t space_left = sizeof(buf), string_size;
512         const char * sepstr = "";
513 
514         while (lp != NULL && lp->s != NULL) {
515             if (lp->v && (v & lp->v) == lp->v) {
516                 /* ok we have found something */
517                 if (space_left <= 1)
518                     return (buf); /* only enough room left for NUL, if that */
519                 string_size = strlcpy(bufp, sepstr, space_left);
520                 if (string_size >= space_left)
521                     return (buf);    /* we ran out of room */
522                 bufp += string_size;
523                 space_left -= string_size;
524                 if (space_left <= 1)
525                     return (buf); /* only enough room left for NUL, if that */
526                 string_size = strlcpy(bufp, lp->s, space_left);
527                 if (string_size >= space_left)
528                     return (buf);    /* we ran out of room */
529                 bufp += string_size;
530                 space_left -= string_size;
531                 sepstr = sep;
532             }
533             lp++;
534         }
535 
536         if (bufp == buf)
537             /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
538             (void)snprintf(buf, sizeof(buf), fmt == NULL ? "#%08x" : fmt, v);
539         return (buf);
540 }
541 
542 /*
543  * Convert a bit token value to a string; use "fmt" if not found.
544  * this is useful for parsing bitfields, the output strings are not separated.
545  */
546 char *
bittok2str_nosep(const struct tok * lp,const char * fmt,u_int v)547 bittok2str_nosep(const struct tok *lp, const char *fmt,
548              u_int v)
549 {
550     return (bittok2str_internal(lp, fmt, v, ""));
551 }
552 
553 /*
554  * Convert a bit token value to a string; use "fmt" if not found.
555  * this is useful for parsing bitfields, the output strings are comma separated.
556  */
557 char *
bittok2str(const struct tok * lp,const char * fmt,u_int v)558 bittok2str(const struct tok *lp, const char *fmt,
559              u_int v)
560 {
561     return (bittok2str_internal(lp, fmt, v, ", "));
562 }
563 
564 /*
565  * Convert a value to a string using an array; the macro
566  * tok2strary() in <netdissect.h> is the public interface to
567  * this function and ensures that the second argument is
568  * correct for bounds-checking.
569  */
570 const char *
tok2strary_internal(const char ** lp,int n,const char * fmt,int v)571 tok2strary_internal(const char **lp, int n, const char *fmt,
572           int v)
573 {
574           static char buf[TOKBUFSIZE];
575 
576           if (v >= 0 && v < n && lp[v] != NULL)
577                     return lp[v];
578           if (fmt == NULL)
579                     fmt = "#%d";
580           (void)snprintf(buf, sizeof(buf), fmt, v);
581           return (buf);
582 }
583 
584 const struct tok *
uint2tokary_internal(const struct uint_tokary dict[],const size_t size,const u_int val)585 uint2tokary_internal(const struct uint_tokary dict[], const size_t size,
586                      const u_int val)
587 {
588           size_t i;
589           /* Try a direct lookup before the full scan. */
590           if (val < size && dict[val].uintval == val)
591                     return dict[val].tokary; /* OK if NULL */
592           for (i = 0; i < size; i++)
593                     if (dict[i].uintval == val)
594                               return dict[i].tokary; /* OK if NULL */
595           return NULL;
596 }
597 
598 /*
599  * Convert a 32-bit netmask to prefixlen if possible
600  * the function returns the prefix-len; if plen == -1
601  * then conversion was not possible;
602  */
603 
604 int
mask2plen(uint32_t mask)605 mask2plen(uint32_t mask)
606 {
607           uint32_t bitmasks[33] = {
608                     0x00000000,
609                     0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
610                     0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
611                     0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
612                     0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
613                     0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
614                     0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
615                     0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
616                     0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
617           };
618           int prefix_len = 32;
619 
620           /* let's see if we can transform the mask into a prefixlen */
621           while (prefix_len >= 0) {
622                     if (bitmasks[prefix_len] == mask)
623                               break;
624                     prefix_len--;
625           }
626           return (prefix_len);
627 }
628 
629 int
mask62plen(const u_char * mask)630 mask62plen(const u_char *mask)
631 {
632           u_char bitmasks[9] = {
633                     0x00,
634                     0x80, 0xc0, 0xe0, 0xf0,
635                     0xf8, 0xfc, 0xfe, 0xff
636           };
637           int byte;
638           int cidr_len = 0;
639 
640           for (byte = 0; byte < 16; byte++) {
641                     u_int bits;
642 
643                     for (bits = 0; bits < (sizeof (bitmasks) / sizeof (bitmasks[0])); bits++) {
644                               if (mask[byte] == bitmasks[bits]) {
645                                         cidr_len += bits;
646                                         break;
647                               }
648                     }
649 
650                     if (mask[byte] != 0xff)
651                               break;
652           }
653           return (cidr_len);
654 }
655 
656 /*
657  * Routine to print out information for text-based protocols such as FTP,
658  * HTTP, SMTP, RTSP, SIP, ....
659  */
660 #define MAX_TOKEN   128
661 
662 /*
663  * Fetch a token from a packet, starting at the specified index,
664  * and return the length of the token.
665  *
666  * Returns 0 on error; yes, this is indistinguishable from an empty
667  * token, but an "empty token" isn't a valid token - it just means
668  * either a space character at the beginning of the line (this
669  * includes a blank line) or no more tokens remaining on the line.
670  */
671 static int
fetch_token(netdissect_options * ndo,const u_char * pptr,u_int idx,u_int len,u_char * tbuf,size_t tbuflen)672 fetch_token(netdissect_options *ndo, const u_char *pptr, u_int idx, u_int len,
673     u_char *tbuf, size_t tbuflen)
674 {
675           size_t toklen = 0;
676           u_char c;
677 
678           for (; idx < len; idx++) {
679                     if (!ND_TTEST_1(pptr + idx)) {
680                               /* ran past end of captured data */
681                               return (0);
682                     }
683                     c = GET_U_1(pptr + idx);
684                     if (!ND_ISASCII(c)) {
685                               /* not an ASCII character */
686                               return (0);
687                     }
688                     if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
689                               /* end of token */
690                               break;
691                     }
692                     if (!ND_ASCII_ISPRINT(c)) {
693                               /* not part of a command token or response code */
694                               return (0);
695                     }
696                     if (toklen + 2 > tbuflen) {
697                               /* no room for this character and terminating '\0' */
698                               return (0);
699                     }
700                     tbuf[toklen] = c;
701                     toklen++;
702           }
703           if (toklen == 0) {
704                     /* no token */
705                     return (0);
706           }
707           tbuf[toklen] = '\0';
708 
709           /*
710            * Skip past any white space after the token, until we see
711            * an end-of-line (CR or LF).
712            */
713           for (; idx < len; idx++) {
714                     if (!ND_TTEST_1(pptr + idx)) {
715                               /* ran past end of captured data */
716                               break;
717                     }
718                     c = GET_U_1(pptr + idx);
719                     if (c == '\r' || c == '\n') {
720                               /* end of line */
721                               break;
722                     }
723                     if (!ND_ASCII_ISPRINT(c)) {
724                               /* not a printable ASCII character */
725                               break;
726                     }
727                     if (c != ' ' && c != '\t' && c != '\r' && c != '\n') {
728                               /* beginning of next token */
729                               break;
730                     }
731           }
732           return (idx);
733 }
734 
735 /*
736  * Scan a buffer looking for a line ending - LF or CR-LF.
737  * Return the index of the character after the line ending or 0 if
738  * we encounter a non-ASCII or non-printable character or don't find
739  * the line ending.
740  */
741 static u_int
print_txt_line(netdissect_options * ndo,const char * prefix,const u_char * pptr,u_int idx,u_int len)742 print_txt_line(netdissect_options *ndo, const char *prefix,
743                  const u_char *pptr, u_int idx, u_int len)
744 {
745           u_int startidx;
746           u_int linelen;
747           u_char c;
748 
749           startidx = idx;
750           while (idx < len) {
751                     c = GET_U_1(pptr + idx);
752                     if (c == '\n') {
753                               /*
754                                * LF without CR; end of line.
755                                * Skip the LF and print the line, with the
756                                * exception of the LF.
757                                */
758                               linelen = idx - startidx;
759                               idx++;
760                               goto print;
761                     } else if (c == '\r') {
762                               /* CR - any LF? */
763                               if ((idx+1) >= len) {
764                                         /* not in this packet */
765                                         return (0);
766                               }
767                               if (GET_U_1(pptr + idx + 1) == '\n') {
768                                         /*
769                                          * CR-LF; end of line.
770                                          * Skip the CR-LF and print the line, with
771                                          * the exception of the CR-LF.
772                                          */
773                                         linelen = idx - startidx;
774                                         idx += 2;
775                                         goto print;
776                               }
777 
778                               /*
779                                * CR followed by something else; treat this
780                                * as if it were binary data, and don't print
781                                * it.
782                                */
783                               return (0);
784                     } else if (!ND_ASCII_ISPRINT(c) && c != '\t') {
785                               /*
786                                * Not a printable ASCII character and not a tab;
787                                * treat this as if it were binary data, and
788                                * don't print it.
789                                */
790                               return (0);
791                     }
792                     idx++;
793           }
794 
795           /*
796            * All printable ASCII, but no line ending after that point
797            * in the buffer; treat this as if it were truncated.
798            */
799           linelen = idx - startidx;
800           ND_PRINT("%s%.*s", prefix, (int)linelen, pptr + startidx);
801           nd_print_trunc(ndo);
802           return (0);
803 
804 print:
805           ND_PRINT("%s%.*s", prefix, (int)linelen, pptr + startidx);
806           return (idx);
807 }
808 
809 /* Assign needed before calling txtproto_print(): ndo->ndo_protocol = "proto" */
810 void
txtproto_print(netdissect_options * ndo,const u_char * pptr,u_int len,const char ** cmds,u_int flags)811 txtproto_print(netdissect_options *ndo, const u_char *pptr, u_int len,
812                  const char **cmds, u_int flags)
813 {
814           u_int idx, eol;
815           u_char token[MAX_TOKEN+1];
816           const char *cmd;
817           int print_this = 0;
818 
819           if (cmds != NULL) {
820                     /*
821                      * This protocol has more than just request and
822                      * response lines; see whether this looks like a
823                      * request or response and, if so, print it and,
824                      * in verbose mode, print everything after it.
825                      *
826                      * This is for HTTP-like protocols, where we
827                      * want to print requests and responses, but
828                      * don't want to print continuations of request
829                      * or response bodies in packets that don't
830                      * contain the request or response line.
831                      */
832                     idx = fetch_token(ndo, pptr, 0, len, token, sizeof(token));
833                     if (idx != 0) {
834                               /* Is this a valid request name? */
835                               while ((cmd = *cmds++) != NULL) {
836                                         if (ascii_strcasecmp((const char *)token, cmd) == 0) {
837                                                   /* Yes. */
838                                                   print_this = 1;
839                                                   break;
840                                         }
841                               }
842 
843                               /*
844                                * No - is this a valid response code (3 digits)?
845                                *
846                                * Is this token the response code, or is the next
847                                * token the response code?
848                                */
849                               if (flags & RESP_CODE_SECOND_TOKEN) {
850                                         /*
851                                          * Next token - get it.
852                                          */
853                                         idx = fetch_token(ndo, pptr, idx, len, token,
854                                             sizeof(token));
855                               }
856                               if (idx != 0) {
857                                         if (ND_ASCII_ISDIGIT(token[0]) && ND_ASCII_ISDIGIT(token[1]) &&
858                                             ND_ASCII_ISDIGIT(token[2]) && token[3] == '\0') {
859                                                   /* Yes. */
860                                                   print_this = 1;
861                                         }
862                               }
863                     }
864           } else {
865                     /*
866                      * Either:
867                      *
868                      * 1) This protocol has only request and response lines
869                      *    (e.g., FTP, where all the data goes over a different
870                      *    connection); assume the payload is a request or
871                      *    response.
872                      *
873                      * or
874                      *
875                      * 2) This protocol is just text, so that we should
876                      *    always, at minimum, print the first line and,
877                      *    in verbose mode, print all lines.
878                      */
879                     print_this = 1;
880           }
881 
882           nd_print_protocol_caps(ndo);
883 
884           if (print_this) {
885                     /*
886                      * In non-verbose mode, just print the protocol, followed
887                      * by the first line.
888                      *
889                      * In verbose mode, print lines as text until we run out
890                      * of characters or see something that's not a
891                      * printable-ASCII line.
892                      */
893                     if (ndo->ndo_vflag) {
894                               /*
895                                * We're going to print all the text lines in the
896                                * request or response; just print the length
897                                * on the first line of the output.
898                                */
899                               ND_PRINT(", length: %u", len);
900                               for (idx = 0;
901                                   idx < len && (eol = print_txt_line(ndo, "\n\t", pptr, idx, len)) != 0;
902                                   idx = eol)
903                                         ;
904                     } else {
905                               /*
906                                * Just print the first text line.
907                                */
908                               print_txt_line(ndo, ": ", pptr, 0, len);
909                     }
910           }
911 }
912 
913 #if (defined(__i386__) || defined(_M_IX86) || defined(__X86__) || defined(__x86_64__) || defined(_M_X64)) || \
914     (defined(__arm__) || defined(_M_ARM) || defined(__aarch64__)) || \
915     (defined(__m68k__) && (!defined(__mc68000__) && !defined(__mc68010__))) || \
916     (defined(__ppc__) || defined(__ppc64__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PPC64)) || \
917     (defined(__s390__) || defined(__s390x__) || defined(__zarch__)) || \
918     defined(__vax__)
919 /*
920  * The procesor natively handles unaligned loads, so just use memcpy()
921  * and memcmp(), to enable those optimizations.
922  *
923  * XXX - are those all the x86 tests we need?
924  * XXX - do we need to worry about ARMv1 through ARMv5, which didn't
925  * support unaligned loads, and, if so, do we need to worry about all
926  * of them, or just some of them, e.g. ARMv5?
927  * XXX - are those the only 68k tests we need not to generated
928  * unaligned accesses if the target is the 68000 or 68010?
929  * XXX - are there any tests we don't need, because some definitions are for
930  * compilers that also predefine the GCC symbols?
931  * XXX - do we need to test for both 32-bit and 64-bit versions of those
932  * architectures in all cases?
933  */
934 #else
935 /*
936  * The processor doesn't natively handle unaligned loads,
937  * and the compiler might "helpfully" optimize memcpy()
938  * and memcmp(), when handed pointers that would normally
939  * be properly aligned, into sequences that assume proper
940  * alignment.
941  *
942  * Do copies and compares of possibly-unaligned data by
943  * calling routines that wrap memcpy() and memcmp(), to
944  * prevent that optimization.
945  */
946 void
unaligned_memcpy(void * p,const void * q,size_t l)947 unaligned_memcpy(void *p, const void *q, size_t l)
948 {
949           memcpy(p, q, l);
950 }
951 
952 /* As with memcpy(), so with memcmp(). */
953 int
unaligned_memcmp(const void * p,const void * q,size_t l)954 unaligned_memcmp(const void *p, const void *q, size_t l)
955 {
956           return (memcmp(p, q, l));
957 }
958 #endif
959 
960