]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/tcpdump/util-print.c
riscv: report additional known SBI implementations
[FreeBSD/FreeBSD.git] / contrib / tcpdump / util-print.c
1 /*
2  * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that: (1) source code distributions
7  * retain the above copyright notice and this paragraph in its entirety, (2)
8  * distributions including binary code include the above copyright notice and
9  * this paragraph in its entirety in the documentation or other materials
10  * provided with the distribution, and (3) all advertising materials mentioning
11  * features or use of this software display the following acknowledgement:
12  * ``This product includes software developed by the University of California,
13  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14  * the University nor the names of its contributors may be used to endorse
15  * or promote products derived from this software without specific prior
16  * written permission.
17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20  */
21
22 /*
23  * txtproto_print() derived from original code by Hannes Gredler
24  * (hannes@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 <ctype.h>
50 #include <stdio.h>
51 #include <stdarg.h>
52 #include <stdlib.h>
53 #include <string.h>
54
55 #include "netdissect.h"
56 #include "ascii_strcasecmp.h"
57 #include "timeval-operations.h"
58
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)";
62
63 /*
64  * timestamp display buffer size, the biggest size of both formats is needed
65  * sizeof("0000000000.000000000") > sizeof("00:00:00.000000000")
66  */
67 #define TS_BUF_SIZE sizeof("0000000000.000000000")
68
69 #define TOKBUFSIZE 128
70
71 /*
72  * Print out a character, filtering out the non-printable ones
73  */
74 void
75 fn_print_char(netdissect_options *ndo, u_char c)
76 {
77         if (!ND_ISASCII(c)) {
78                 c = ND_TOASCII(c);
79                 ND_PRINT((ndo, "M-"));
80         }
81         if (!ND_ISPRINT(c)) {
82                 c ^= 0x40;      /* DEL to ?, others to alpha */
83                 ND_PRINT((ndo, "^"));
84         }
85         ND_PRINT((ndo, "%c", c));
86 }
87
88 /*
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.
93  */
94 int
95 fn_print(netdissect_options *ndo,
96          register const u_char *s, register const u_char *ep)
97 {
98         register int ret;
99         register u_char c;
100
101         ret = 1;                        /* assume truncated */
102         while (ep == NULL || s < ep) {
103                 c = *s++;
104                 if (c == '\0') {
105                         ret = 0;
106                         break;
107                 }
108                 if (!ND_ISASCII(c)) {
109                         c = ND_TOASCII(c);
110                         ND_PRINT((ndo, "M-"));
111                 }
112                 if (!ND_ISPRINT(c)) {
113                         c ^= 0x40;      /* DEL to ?, others to alpha */
114                         ND_PRINT((ndo, "^"));
115                 }
116                 ND_PRINT((ndo, "%c", c));
117         }
118         return(ret);
119 }
120
121 /*
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
124  * the packet.
125  *
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.
128  *
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.
133  *
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.
138  */
139 u_int
140 fn_printztn(netdissect_options *ndo,
141          register const u_char *s, register u_int n, register const u_char *ep)
142 {
143         register u_int bytes;
144         register u_char c;
145
146         bytes = 0;
147         for (;;) {
148                 if (n == 0 || (ep != NULL && s >= ep)) {
149                         /*
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".
153                          *
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.
158                          */
159                         bytes = 0;
160                         break;
161                 }
162
163                 c = *s++;
164                 bytes++;
165                 n--;
166                 if (c == '\0') {
167                         /* End of string */
168                         break;
169                 }
170                 if (!ND_ISASCII(c)) {
171                         c = ND_TOASCII(c);
172                         ND_PRINT((ndo, "M-"));
173                 }
174                 if (!ND_ISPRINT(c)) {
175                         c ^= 0x40;      /* DEL to ?, others to alpha */
176                         ND_PRINT((ndo, "^"));
177                 }
178                 ND_PRINT((ndo, "%c", c));
179         }
180         return(bytes);
181 }
182
183 /*
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.
188  */
189 int
190 fn_printn(netdissect_options *ndo,
191           register const u_char *s, register u_int n, register const u_char *ep)
192 {
193         register u_char c;
194
195         while (n > 0 && (ep == NULL || s < ep)) {
196                 n--;
197                 c = *s++;
198                 if (!ND_ISASCII(c)) {
199                         c = ND_TOASCII(c);
200                         ND_PRINT((ndo, "M-"));
201                 }
202                 if (!ND_ISPRINT(c)) {
203                         c ^= 0x40;      /* DEL to ?, others to alpha */
204                         ND_PRINT((ndo, "^"));
205                 }
206                 ND_PRINT((ndo, "%c", c));
207         }
208         return (n == 0) ? 0 : 1;
209 }
210
211 /*
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.
217  */
218 int
219 fn_printzp(netdissect_options *ndo,
220            register const u_char *s, register u_int n,
221            register const u_char *ep)
222 {
223         register int ret;
224         register u_char c;
225
226         ret = 1;                        /* assume truncated */
227         while (n > 0 && (ep == NULL || s < ep)) {
228                 n--;
229                 c = *s++;
230                 if (c == '\0') {
231                         ret = 0;
232                         break;
233                 }
234                 if (!ND_ISASCII(c)) {
235                         c = ND_TOASCII(c);
236                         ND_PRINT((ndo, "M-"));
237                 }
238                 if (!ND_ISPRINT(c)) {
239                         c ^= 0x40;      /* DEL to ?, others to alpha */
240                         ND_PRINT((ndo, "^"));
241                 }
242                 ND_PRINT((ndo, "%c", c));
243         }
244         return (n == 0) ? 0 : ret;
245 }
246
247 /*
248  * Format the timestamp
249  */
250 static char *
251 ts_format(netdissect_options *ndo
252 #ifndef HAVE_PCAP_SET_TSTAMP_PRECISION
253 _U_
254 #endif
255 , int sec, int usec, char *buf)
256 {
257         const char *format;
258
259 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
260         switch (ndo->ndo_tstamp_precision) {
261
262         case PCAP_TSTAMP_PRECISION_MICRO:
263                 format = "%02d:%02d:%02d.%06u";
264                 break;
265
266         case PCAP_TSTAMP_PRECISION_NANO:
267                 format = "%02d:%02d:%02d.%09u";
268                 break;
269
270         default:
271                 format = "%02d:%02d:%02d.{unknown}";
272                 break;
273         }
274 #else
275         format = "%02d:%02d:%02d.%06u";
276 #endif
277
278         snprintf(buf, TS_BUF_SIZE, format,
279                  sec / 3600, (sec % 3600) / 60, sec % 60, usec);
280
281         return buf;
282 }
283
284 /*
285  * Format the timestamp - Unix timeval style
286  */
287 static char *
288 ts_unix_format(netdissect_options *ndo
289 #ifndef HAVE_PCAP_SET_TSTAMP_PRECISION
290 _U_
291 #endif
292 , int sec, int usec, char *buf)
293 {
294         const char *format;
295
296 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
297         switch (ndo->ndo_tstamp_precision) {
298
299         case PCAP_TSTAMP_PRECISION_MICRO:
300                 format = "%u.%06u";
301                 break;
302
303         case PCAP_TSTAMP_PRECISION_NANO:
304                 format = "%u.%09u";
305                 break;
306
307         default:
308                 format = "%u.{unknown}";
309                 break;
310         }
311 #else
312         format = "%u.%06u";
313 #endif
314
315         snprintf(buf, TS_BUF_SIZE, format,
316                  (unsigned)sec, (unsigned)usec);
317
318         return buf;
319 }
320
321 /*
322  * Print the timestamp
323  */
324 void
325 ts_print(netdissect_options *ndo,
326          register const struct timeval *tvp)
327 {
328         register int s;
329         struct tm *tm;
330         time_t Time;
331         char buf[TS_BUF_SIZE];
332         static struct timeval tv_ref;
333         struct timeval tv_result;
334         int negative_offset;
335         int nano_prec;
336
337         switch (ndo->ndo_tflag) {
338
339         case 0: /* Default */
340                 s = (tvp->tv_sec + thiszone) % 86400;
341                 ND_PRINT((ndo, "%s ", ts_format(ndo, s, tvp->tv_usec, buf)));
342                 break;
343
344         case 1: /* No time stamp */
345                 break;
346
347         case 2: /* Unix timeval style */
348                 ND_PRINT((ndo, "%s ", ts_unix_format(ndo,
349                           tvp->tv_sec, tvp->tv_usec, buf)));
350                 break;
351
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:
357                         nano_prec = 0;
358                         break;
359                 case PCAP_TSTAMP_PRECISION_NANO:
360                         nano_prec = 1;
361                         break;
362                 default:
363                         nano_prec = 0;
364                         break;
365                 }
366 #else
367                 nano_prec = 0;
368 #endif
369                 if (!(netdissect_timevalisset(&tv_ref)))
370                         tv_ref = *tvp; /* set timestamp for first packet */
371
372                 negative_offset = netdissect_timevalcmp(tvp, &tv_ref, <);
373                 if (negative_offset)
374                         netdissect_timevalsub(&tv_ref, tvp, &tv_result, nano_prec);
375                 else
376                         netdissect_timevalsub(tvp, &tv_ref, &tv_result, nano_prec);
377
378                 ND_PRINT((ndo, (negative_offset ? "-" : " ")));
379
380                 ND_PRINT((ndo, "%s ", ts_format(ndo,
381                           tv_result.tv_sec, tv_result.tv_usec, buf)));
382
383                 if (ndo->ndo_tflag == 3)
384                         tv_ref = *tvp; /* set timestamp for previous packet */
385                 break;
386
387         case 4: /* Default + Date */
388                 s = (tvp->tv_sec + thiszone) % 86400;
389                 Time = (tvp->tv_sec + thiszone) - s;
390                 tm = gmtime (&Time);
391                 if (!tm)
392                         ND_PRINT((ndo, "Date fail  "));
393                 else
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)));
397                 break;
398         }
399 }
400
401 /*
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.
405  */
406 void
407 unsigned_relts_print(netdissect_options *ndo,
408                      uint32_t secs)
409 {
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;
414
415         if (secs == 0) {
416                 ND_PRINT((ndo, "0s"));
417                 return;
418         }
419         while (secs > 0) {
420                 if (secs >= *s) {
421                         ND_PRINT((ndo, "%d%s", secs / *s, *l));
422                         secs -= (secs / *s) * *s;
423                 }
424                 s++;
425                 l++;
426         }
427 }
428
429 /*
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.
433  */
434 void
435 signed_relts_print(netdissect_options *ndo,
436                    int32_t secs)
437 {
438         if (secs < 0) {
439                 ND_PRINT((ndo, "-"));
440                 if (secs == INT32_MIN) {
441                         /*
442                          * -2^31; you can't fit its absolute value into
443                          * a 32-bit signed integer.
444                          *
445                          * Just directly pass said absolute value to
446                          * unsigned_relts_print() directly.
447                          *
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?)
451                          */
452                         unsigned_relts_print(ndo, 2147483648U);
453                 } else {
454                         /*
455                          * We now know -secs will fit into an int32_t;
456                          * negate it and pass that to unsigned_relts_print().
457                          */
458                         unsigned_relts_print(ndo, -secs);
459                 }
460                 return;
461         }
462         unsigned_relts_print(ndo, secs);
463 }
464
465 /*
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
469  */
470
471 int
472 print_unknown_data(netdissect_options *ndo, const u_char *cp,const char *ident,int len)
473 {
474         if (len < 0) {
475           ND_PRINT((ndo,"%sDissector error: print_unknown_data called with negative length",
476                     ident));
477                 return(0);
478         }
479         if (ndo->ndo_snapend - cp < len)
480                 len = ndo->ndo_snapend - cp;
481         if (len < 0) {
482           ND_PRINT((ndo,"%sDissector error: print_unknown_data called with pointer past end of packet",
483                     ident));
484                 return(0);
485         }
486         hex_print(ndo, ident,cp,len);
487         return(1); /* everything is ok */
488 }
489
490 /*
491  * Convert a token value to a string; use "fmt" if not found.
492  */
493 const char *
494 tok2strbuf(register const struct tok *lp, register const char *fmt,
495            register u_int v, char *buf, size_t bufsize)
496 {
497         if (lp != NULL) {
498                 while (lp->s != NULL) {
499                         if (lp->v == v)
500                                 return (lp->s);
501                         ++lp;
502                 }
503         }
504         if (fmt == NULL)
505                 fmt = "#%d";
506
507         (void)snprintf(buf, bufsize, fmt, v);
508         return (const char *)buf;
509 }
510
511 /*
512  * Convert a token value to a string; use "fmt" if not found.
513  */
514 const char *
515 tok2str(register const struct tok *lp, register const char *fmt,
516         register u_int v)
517 {
518         static char buf[4][TOKBUFSIZE];
519         static int idx = 0;
520         char *ret;
521
522         ret = buf[idx];
523         idx = (idx+1) & 3;
524         return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0]));
525 }
526
527 /*
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.
531  */
532 static char *
533 bittok2str_internal(register const struct tok *lp, register const char *fmt,
534            register u_int v, const char *sep)
535 {
536         static char buf[1024+1]; /* our string buffer */
537         char *bufp = buf;
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 = "";
542
543         while (lp != NULL && lp->s != NULL) {
544             tokval=lp->v;   /* load our first value */
545             rotbit=1;
546             while (rotbit != 0) {
547                 /*
548                  * lets AND the rotating bit with our token value
549                  * and see if we have got a match
550                  */
551                 if (tokval == (v&rotbit)) {
552                     /* ok we have found something */
553                     if (space_left <= 1)
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 */
558                     bufp += string_size;
559                     space_left -= string_size;
560                     if (space_left <= 1)
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 */
565                     bufp += string_size;
566                     space_left -= string_size;
567                     sepstr = sep;
568                     break;
569                 }
570                 rotbit=rotbit<<1; /* no match - lets shift and try again */
571             }
572             lp++;
573         }
574
575         if (bufp == buf)
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);
578         return (buf);
579 }
580
581 /*
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.
584  */
585 char *
586 bittok2str_nosep(register const struct tok *lp, register const char *fmt,
587            register u_int v)
588 {
589     return (bittok2str_internal(lp, fmt, v, ""));
590 }
591
592 /*
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.
595  */
596 char *
597 bittok2str(register const struct tok *lp, register const char *fmt,
598            register u_int v)
599 {
600     return (bittok2str_internal(lp, fmt, v, ", "));
601 }
602
603 /*
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.
608  */
609 const char *
610 tok2strary_internal(register const char **lp, int n, register const char *fmt,
611         register int v)
612 {
613         static char buf[TOKBUFSIZE];
614
615         if (v >= 0 && v < n && lp[v] != NULL)
616                 return lp[v];
617         if (fmt == NULL)
618                 fmt = "#%d";
619         (void)snprintf(buf, sizeof(buf), fmt, v);
620         return (buf);
621 }
622
623 /*
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;
627  */
628
629 int
630 mask2plen(uint32_t mask)
631 {
632         uint32_t bitmasks[33] = {
633                 0x00000000,
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
642         };
643         int prefix_len = 32;
644
645         /* let's see if we can transform the mask into a prefixlen */
646         while (prefix_len >= 0) {
647                 if (bitmasks[prefix_len] == mask)
648                         break;
649                 prefix_len--;
650         }
651         return (prefix_len);
652 }
653
654 int
655 mask62plen(const u_char *mask)
656 {
657         u_char bitmasks[9] = {
658                 0x00,
659                 0x80, 0xc0, 0xe0, 0xf0,
660                 0xf8, 0xfc, 0xfe, 0xff
661         };
662         int byte;
663         int cidr_len = 0;
664
665         for (byte = 0; byte < 16; byte++) {
666                 u_int bits;
667
668                 for (bits = 0; bits < (sizeof (bitmasks) / sizeof (bitmasks[0])); bits++) {
669                         if (mask[byte] == bitmasks[bits]) {
670                                 cidr_len += bits;
671                                 break;
672                         }
673                 }
674
675                 if (mask[byte] != 0xff)
676                         break;
677         }
678         return (cidr_len);
679 }
680
681 /*
682  * Routine to print out information for text-based protocols such as FTP,
683  * HTTP, SMTP, RTSP, SIP, ....
684  */
685 #define MAX_TOKEN       128
686
687 /*
688  * Fetch a token from a packet, starting at the specified index,
689  * and return the length of the token.
690  *
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.
695  */
696 static int
697 fetch_token(netdissect_options *ndo, const u_char *pptr, u_int idx, u_int len,
698     u_char *tbuf, size_t tbuflen)
699 {
700         size_t toklen = 0;
701
702         for (; idx < len; idx++) {
703                 if (!ND_TTEST(*(pptr + idx))) {
704                         /* ran past end of captured data */
705                         return (0);
706                 }
707                 if (!isascii(*(pptr + idx))) {
708                         /* not an ASCII character */
709                         return (0);
710                 }
711                 if (isspace(*(pptr + idx))) {
712                         /* end of token */
713                         break;
714                 }
715                 if (!isprint(*(pptr + idx))) {
716                         /* not part of a command token or response code */
717                         return (0);
718                 }
719                 if (toklen + 2 > tbuflen) {
720                         /* no room for this character and terminating '\0' */
721                         return (0);
722                 }
723                 tbuf[toklen] = *(pptr + idx);
724                 toklen++;
725         }
726         if (toklen == 0) {
727                 /* no token */
728                 return (0);
729         }
730         tbuf[toklen] = '\0';
731
732         /*
733          * Skip past any white space after the token, until we see
734          * an end-of-line (CR or LF).
735          */
736         for (; idx < len; idx++) {
737                 if (!ND_TTEST(*(pptr + idx))) {
738                         /* ran past end of captured data */
739                         break;
740                 }
741                 if (*(pptr + idx) == '\r' || *(pptr + idx) == '\n') {
742                         /* end of line */
743                         break;
744                 }
745                 if (!isascii(*(pptr + idx)) || !isprint(*(pptr + idx))) {
746                         /* not a printable ASCII character */
747                         break;
748                 }
749                 if (!isspace(*(pptr + idx))) {
750                         /* beginning of next token */
751                         break;
752                 }
753         }
754         return (idx);
755 }
756
757 /*
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
761  * the line ending.
762  */
763 static u_int
764 print_txt_line(netdissect_options *ndo, const char *protoname,
765     const char *prefix, const u_char *pptr, u_int idx, u_int len)
766 {
767         u_int startidx;
768         u_int linelen;
769
770         startidx = idx;
771         while (idx < len) {
772                 ND_TCHECK(*(pptr+idx));
773                 if (*(pptr+idx) == '\n') {
774                         /*
775                          * LF without CR; end of line.
776                          * Skip the LF and print the line, with the
777                          * exception of the LF.
778                          */
779                         linelen = idx - startidx;
780                         idx++;
781                         goto print;
782                 } else if (*(pptr+idx) == '\r') {
783                         /* CR - any LF? */
784                         if ((idx+1) >= len) {
785                                 /* not in this packet */
786                                 return (0);
787                         }
788                         ND_TCHECK(*(pptr+idx+1));
789                         if (*(pptr+idx+1) == '\n') {
790                                 /*
791                                  * CR-LF; end of line.
792                                  * Skip the CR-LF and print the line, with
793                                  * the exception of the CR-LF.
794                                  */
795                                 linelen = idx - startidx;
796                                 idx += 2;
797                                 goto print;
798                         }
799
800                         /*
801                          * CR followed by something else; treat this
802                          * as if it were binary data, and don't print
803                          * it.
804                          */
805                         return (0);
806                 } else if (!isascii(*(pptr+idx)) ||
807                     (!isprint(*(pptr+idx)) && *(pptr+idx) != '\t')) {
808                         /*
809                          * Not a printable ASCII character and not a tab;
810                          * treat this as if it were binary data, and
811                          * don't print it.
812                          */
813                         return (0);
814                 }
815                 idx++;
816         }
817
818         /*
819          * All printable ASCII, but no line ending after that point
820          * in the buffer; treat this as if it were truncated.
821          */
822 trunc:
823         linelen = idx - startidx;
824         ND_PRINT((ndo, "%s%.*s[!%s]", prefix, (int)linelen, pptr + startidx,
825             protoname));
826         return (0);
827
828 print:
829         ND_PRINT((ndo, "%s%.*s", prefix, (int)linelen, pptr + startidx));
830         return (idx);
831 }
832
833 void
834 txtproto_print(netdissect_options *ndo, const u_char *pptr, u_int len,
835     const char *protoname, const char **cmds, u_int flags)
836 {
837         u_int idx, eol;
838         u_char token[MAX_TOKEN+1];
839         const char *cmd;
840         int is_reqresp = 0;
841         const char *pnp;
842
843         if (cmds != NULL) {
844                 /*
845                  * This protocol has more than just request and
846                  * response lines; see whether this looks like a
847                  * request or response.
848                  */
849                 idx = fetch_token(ndo, pptr, 0, len, token, sizeof(token));
850                 if (idx != 0) {
851                         /* Is this a valid request name? */
852                         while ((cmd = *cmds++) != NULL) {
853                                 if (ascii_strcasecmp((const char *)token, cmd) == 0) {
854                                         /* Yes. */
855                                         is_reqresp = 1;
856                                         break;
857                                 }
858                         }
859
860                         /*
861                          * No - is this a valid response code (3 digits)?
862                          *
863                          * Is this token the response code, or is the next
864                          * token the response code?
865                          */
866                         if (flags & RESP_CODE_SECOND_TOKEN) {
867                                 /*
868                                  * Next token - get it.
869                                  */
870                                 idx = fetch_token(ndo, pptr, idx, len, token,
871                                     sizeof(token));
872                         }
873                         if (idx != 0) {
874                                 if (isdigit(token[0]) && isdigit(token[1]) &&
875                                     isdigit(token[2]) && token[3] == '\0') {
876                                         /* Yes. */
877                                         is_reqresp = 1;
878                                 }
879                         }
880                 }
881         } else {
882                 /*
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.
887                  */
888                 is_reqresp = 1;
889         }
890
891         /* Capitalize the protocol name */
892         for (pnp = protoname; *pnp != '\0'; pnp++)
893                 ND_PRINT((ndo, "%c", toupper((u_char)*pnp)));
894
895         if (is_reqresp) {
896                 /*
897                  * In non-verbose mode, just print the protocol, followed
898                  * by the first line as the request or response info.
899                  *
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.
903                  */
904                 if (ndo->ndo_vflag) {
905                         /*
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.
909                          */
910                         ND_PRINT((ndo, ", length: %u", len));
911                         for (idx = 0;
912                             idx < len && (eol = print_txt_line(ndo, protoname, "\n\t", pptr, idx, len)) != 0;
913                             idx = eol)
914                                 ;
915                 } else {
916                         /*
917                          * Just print the first text line.
918                          */
919                         print_txt_line(ndo, protoname, ": ", pptr, 0, len);
920                 }
921         }
922 }
923
924 void
925 safeputs(netdissect_options *ndo,
926          const u_char *s, const u_int maxlen)
927 {
928         u_int idx = 0;
929
930         while (idx < maxlen && *s) {
931                 safeputchar(ndo, *s);
932                 idx++;
933                 s++;
934         }
935 }
936
937 void
938 safeputchar(netdissect_options *ndo,
939             const u_char c)
940 {
941         ND_PRINT((ndo, (c < 0x80 && ND_ISPRINT(c)) ? "%c" : "\\0x%02x", c));
942 }
943
944 #ifdef LBL_ALIGN
945 /*
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
948  * optimization.
949  */
950 void
951 unaligned_memcpy(void *p, const void *q, size_t l)
952 {
953         memcpy(p, q, l);
954 }
955
956 /* As with memcpy(), so with memcmp(). */
957 int
958 unaligned_memcmp(const void *p, const void *q, size_t l)
959 {
960         return (memcmp(p, q, l));
961 }
962 #endif
963