]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/tcpdump/util-print.c
strings: do not continue if getc or getcharacter returns EOF
[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 buffer.
124  * If ep is NULL, assume no truncation check is needed.
125  * Return the number of bytes of string processed, including the
126  * terminating null, if not truncated.  Return 0 if truncated.
127  */
128 u_int
129 fn_printztn(netdissect_options *ndo,
130          register const u_char *s, register u_int n, register const u_char *ep)
131 {
132         register u_int bytes;
133         register u_char c;
134
135         bytes = 0;
136         for (;;) {
137                 if (n == 0 || (ep != NULL && s >= ep)) {
138                         /*
139                          * Truncated.  This includes "no null before we
140                          * got to the end of the fixed-length buffer".
141                          *
142                          * XXX - BOOTP says "null-terminated", which
143                          * means the maximum length of the string, in
144                          * bytes, is 1 less than the size of the buffer,
145                          * as there must always be a terminating null.
146                          */
147                         bytes = 0;
148                         break;
149                 }
150
151                 c = *s++;
152                 bytes++;
153                 n--;
154                 if (c == '\0') {
155                         /* End of string */
156                         break;
157                 }
158                 if (!ND_ISASCII(c)) {
159                         c = ND_TOASCII(c);
160                         ND_PRINT((ndo, "M-"));
161                 }
162                 if (!ND_ISPRINT(c)) {
163                         c ^= 0x40;      /* DEL to ?, others to alpha */
164                         ND_PRINT((ndo, "^"));
165                 }
166                 ND_PRINT((ndo, "%c", c));
167         }
168         return(bytes);
169 }
170
171 /*
172  * Print out a counted filename (or other ascii string).
173  * If ep is NULL, assume no truncation check is needed.
174  * Return true if truncated.
175  * Stop at ep (if given) or after n bytes, whichever is first.
176  */
177 int
178 fn_printn(netdissect_options *ndo,
179           register const u_char *s, register u_int n, register const u_char *ep)
180 {
181         register u_char c;
182
183         while (n > 0 && (ep == NULL || s < ep)) {
184                 n--;
185                 c = *s++;
186                 if (!ND_ISASCII(c)) {
187                         c = ND_TOASCII(c);
188                         ND_PRINT((ndo, "M-"));
189                 }
190                 if (!ND_ISPRINT(c)) {
191                         c ^= 0x40;      /* DEL to ?, others to alpha */
192                         ND_PRINT((ndo, "^"));
193                 }
194                 ND_PRINT((ndo, "%c", c));
195         }
196         return (n == 0) ? 0 : 1;
197 }
198
199 /*
200  * Print out a null-padded filename (or other ascii string).
201  * If ep is NULL, assume no truncation check is needed.
202  * Return true if truncated.
203  * Stop at ep (if given) or after n bytes or before the null char,
204  * whichever is first.
205  */
206 int
207 fn_printzp(netdissect_options *ndo,
208            register const u_char *s, register u_int n,
209            register const u_char *ep)
210 {
211         register int ret;
212         register u_char c;
213
214         ret = 1;                        /* assume truncated */
215         while (n > 0 && (ep == NULL || s < ep)) {
216                 n--;
217                 c = *s++;
218                 if (c == '\0') {
219                         ret = 0;
220                         break;
221                 }
222                 if (!ND_ISASCII(c)) {
223                         c = ND_TOASCII(c);
224                         ND_PRINT((ndo, "M-"));
225                 }
226                 if (!ND_ISPRINT(c)) {
227                         c ^= 0x40;      /* DEL to ?, others to alpha */
228                         ND_PRINT((ndo, "^"));
229                 }
230                 ND_PRINT((ndo, "%c", c));
231         }
232         return (n == 0) ? 0 : ret;
233 }
234
235 /*
236  * Format the timestamp
237  */
238 static char *
239 ts_format(netdissect_options *ndo
240 #ifndef HAVE_PCAP_SET_TSTAMP_PRECISION
241 _U_
242 #endif
243 , int sec, int usec, char *buf)
244 {
245         const char *format;
246
247 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
248         switch (ndo->ndo_tstamp_precision) {
249
250         case PCAP_TSTAMP_PRECISION_MICRO:
251                 format = "%02d:%02d:%02d.%06u";
252                 break;
253
254         case PCAP_TSTAMP_PRECISION_NANO:
255                 format = "%02d:%02d:%02d.%09u";
256                 break;
257
258         default:
259                 format = "%02d:%02d:%02d.{unknown}";
260                 break;
261         }
262 #else
263         format = "%02d:%02d:%02d.%06u";
264 #endif
265
266         snprintf(buf, TS_BUF_SIZE, format,
267                  sec / 3600, (sec % 3600) / 60, sec % 60, usec);
268
269         return buf;
270 }
271
272 /*
273  * Format the timestamp - Unix timeval style
274  */
275 static char *
276 ts_unix_format(netdissect_options *ndo
277 #ifndef HAVE_PCAP_SET_TSTAMP_PRECISION
278 _U_
279 #endif
280 , int sec, int usec, char *buf)
281 {
282         const char *format;
283
284 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
285         switch (ndo->ndo_tstamp_precision) {
286
287         case PCAP_TSTAMP_PRECISION_MICRO:
288                 format = "%u.%06u";
289                 break;
290
291         case PCAP_TSTAMP_PRECISION_NANO:
292                 format = "%u.%09u";
293                 break;
294
295         default:
296                 format = "%u.{unknown}";
297                 break;
298         }
299 #else
300         format = "%u.%06u";
301 #endif
302
303         snprintf(buf, TS_BUF_SIZE, format,
304                  (unsigned)sec, (unsigned)usec);
305
306         return buf;
307 }
308
309 /*
310  * Print the timestamp
311  */
312 void
313 ts_print(netdissect_options *ndo,
314          register const struct timeval *tvp)
315 {
316         register int s;
317         struct tm *tm;
318         time_t Time;
319         char buf[TS_BUF_SIZE];
320         static struct timeval tv_ref;
321         struct timeval tv_result;
322         int negative_offset;
323         int nano_prec;
324
325         switch (ndo->ndo_tflag) {
326
327         case 0: /* Default */
328                 s = (tvp->tv_sec + thiszone) % 86400;
329                 ND_PRINT((ndo, "%s ", ts_format(ndo, s, tvp->tv_usec, buf)));
330                 break;
331
332         case 1: /* No time stamp */
333                 break;
334
335         case 2: /* Unix timeval style */
336                 ND_PRINT((ndo, "%s ", ts_unix_format(ndo,
337                           tvp->tv_sec, tvp->tv_usec, buf)));
338                 break;
339
340         case 3: /* Microseconds/nanoseconds since previous packet */
341         case 5: /* Microseconds/nanoseconds since first packet */
342 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
343                 switch (ndo->ndo_tstamp_precision) {
344                 case PCAP_TSTAMP_PRECISION_MICRO:
345                         nano_prec = 0;
346                         break;
347                 case PCAP_TSTAMP_PRECISION_NANO:
348                         nano_prec = 1;
349                         break;
350                 default:
351                         nano_prec = 0;
352                         break;
353                 }
354 #else
355                 nano_prec = 0;
356 #endif
357                 if (!(netdissect_timevalisset(&tv_ref)))
358                         tv_ref = *tvp; /* set timestamp for first packet */
359
360                 negative_offset = netdissect_timevalcmp(tvp, &tv_ref, <);
361                 if (negative_offset)
362                         netdissect_timevalsub(&tv_ref, tvp, &tv_result, nano_prec);
363                 else
364                         netdissect_timevalsub(tvp, &tv_ref, &tv_result, nano_prec);
365
366                 ND_PRINT((ndo, (negative_offset ? "-" : " ")));
367
368                 ND_PRINT((ndo, "%s ", ts_format(ndo,
369                           tv_result.tv_sec, tv_result.tv_usec, buf)));
370
371                 if (ndo->ndo_tflag == 3)
372                         tv_ref = *tvp; /* set timestamp for previous packet */
373                 break;
374
375         case 4: /* Default + Date */
376                 s = (tvp->tv_sec + thiszone) % 86400;
377                 Time = (tvp->tv_sec + thiszone) - s;
378                 tm = gmtime (&Time);
379                 if (!tm)
380                         ND_PRINT((ndo, "Date fail  "));
381                 else
382                         ND_PRINT((ndo, "%04d-%02d-%02d %s ",
383                                tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
384                                ts_format(ndo, s, tvp->tv_usec, buf)));
385                 break;
386         }
387 }
388
389 /*
390  * Print an unsigned relative number of seconds (e.g. hold time, prune timer)
391  * in the form 5m1s.  This does no truncation, so 32230861 seconds
392  * is represented as 1y1w1d1h1m1s.
393  */
394 void
395 unsigned_relts_print(netdissect_options *ndo,
396                      uint32_t secs)
397 {
398         static const char *lengths[] = {"y", "w", "d", "h", "m", "s"};
399         static const u_int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
400         const char **l = lengths;
401         const u_int *s = seconds;
402
403         if (secs == 0) {
404                 ND_PRINT((ndo, "0s"));
405                 return;
406         }
407         while (secs > 0) {
408                 if (secs >= *s) {
409                         ND_PRINT((ndo, "%d%s", secs / *s, *l));
410                         secs -= (secs / *s) * *s;
411                 }
412                 s++;
413                 l++;
414         }
415 }
416
417 /*
418  * Print a signed relative number of seconds (e.g. hold time, prune timer)
419  * in the form 5m1s.  This does no truncation, so 32230861 seconds
420  * is represented as 1y1w1d1h1m1s.
421  */
422 void
423 signed_relts_print(netdissect_options *ndo,
424                    int32_t secs)
425 {
426         if (secs < 0) {
427                 ND_PRINT((ndo, "-"));
428                 if (secs == INT32_MIN) {
429                         /*
430                          * -2^31; you can't fit its absolute value into
431                          * a 32-bit signed integer.
432                          *
433                          * Just directly pass said absolute value to
434                          * unsigned_relts_print() directly.
435                          *
436                          * (XXX - does ISO C guarantee that -(-2^n),
437                          * when calculated and cast to an n-bit unsigned
438                          * integer type, will have the value 2^n?)
439                          */
440                         unsigned_relts_print(ndo, 2147483648U);
441                 } else {
442                         /*
443                          * We now know -secs will fit into an int32_t;
444                          * negate it and pass that to unsigned_relts_print().
445                          */
446                         unsigned_relts_print(ndo, -secs);
447                 }
448                 return;
449         }
450         unsigned_relts_print(ndo, secs);
451 }
452
453 /*
454  *  this is a generic routine for printing unknown data;
455  *  we pass on the linefeed plus indentation string to
456  *  get a proper output - returns 0 on error
457  */
458
459 int
460 print_unknown_data(netdissect_options *ndo, const u_char *cp,const char *ident,int len)
461 {
462         if (len < 0) {
463           ND_PRINT((ndo,"%sDissector error: print_unknown_data called with negative length",
464                     ident));
465                 return(0);
466         }
467         if (ndo->ndo_snapend - cp < len)
468                 len = ndo->ndo_snapend - cp;
469         if (len < 0) {
470           ND_PRINT((ndo,"%sDissector error: print_unknown_data called with pointer past end of packet",
471                     ident));
472                 return(0);
473         }
474         hex_print(ndo, ident,cp,len);
475         return(1); /* everything is ok */
476 }
477
478 /*
479  * Convert a token value to a string; use "fmt" if not found.
480  */
481 const char *
482 tok2strbuf(register const struct tok *lp, register const char *fmt,
483            register u_int v, char *buf, size_t bufsize)
484 {
485         if (lp != NULL) {
486                 while (lp->s != NULL) {
487                         if (lp->v == v)
488                                 return (lp->s);
489                         ++lp;
490                 }
491         }
492         if (fmt == NULL)
493                 fmt = "#%d";
494
495         (void)snprintf(buf, bufsize, fmt, v);
496         return (const char *)buf;
497 }
498
499 /*
500  * Convert a token value to a string; use "fmt" if not found.
501  */
502 const char *
503 tok2str(register const struct tok *lp, register const char *fmt,
504         register u_int v)
505 {
506         static char buf[4][TOKBUFSIZE];
507         static int idx = 0;
508         char *ret;
509
510         ret = buf[idx];
511         idx = (idx+1) & 3;
512         return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0]));
513 }
514
515 /*
516  * Convert a bit token value to a string; use "fmt" if not found.
517  * this is useful for parsing bitfields, the output strings are seperated
518  * if the s field is positive.
519  */
520 static char *
521 bittok2str_internal(register const struct tok *lp, register const char *fmt,
522            register u_int v, const char *sep)
523 {
524         static char buf[1024+1]; /* our string buffer */
525         char *bufp = buf;
526         size_t space_left = sizeof(buf), string_size;
527         register u_int rotbit; /* this is the bit we rotate through all bitpositions */
528         register u_int tokval;
529         const char * sepstr = "";
530
531         while (lp != NULL && lp->s != NULL) {
532             tokval=lp->v;   /* load our first value */
533             rotbit=1;
534             while (rotbit != 0) {
535                 /*
536                  * lets AND the rotating bit with our token value
537                  * and see if we have got a match
538                  */
539                 if (tokval == (v&rotbit)) {
540                     /* ok we have found something */
541                     if (space_left <= 1)
542                         return (buf); /* only enough room left for NUL, if that */
543                     string_size = strlcpy(bufp, sepstr, space_left);
544                     if (string_size >= space_left)
545                         return (buf);    /* we ran out of room */
546                     bufp += string_size;
547                     space_left -= string_size;
548                     if (space_left <= 1)
549                         return (buf); /* only enough room left for NUL, if that */
550                     string_size = strlcpy(bufp, lp->s, space_left);
551                     if (string_size >= space_left)
552                         return (buf);    /* we ran out of room */
553                     bufp += string_size;
554                     space_left -= string_size;
555                     sepstr = sep;
556                     break;
557                 }
558                 rotbit=rotbit<<1; /* no match - lets shift and try again */
559             }
560             lp++;
561         }
562
563         if (bufp == buf)
564             /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
565             (void)snprintf(buf, sizeof(buf), fmt == NULL ? "#%08x" : fmt, v);
566         return (buf);
567 }
568
569 /*
570  * Convert a bit token value to a string; use "fmt" if not found.
571  * this is useful for parsing bitfields, the output strings are not seperated.
572  */
573 char *
574 bittok2str_nosep(register const struct tok *lp, register const char *fmt,
575            register u_int v)
576 {
577     return (bittok2str_internal(lp, fmt, v, ""));
578 }
579
580 /*
581  * Convert a bit token value to a string; use "fmt" if not found.
582  * this is useful for parsing bitfields, the output strings are comma seperated.
583  */
584 char *
585 bittok2str(register const struct tok *lp, register const char *fmt,
586            register u_int v)
587 {
588     return (bittok2str_internal(lp, fmt, v, ", "));
589 }
590
591 /*
592  * Convert a value to a string using an array; the macro
593  * tok2strary() in <netdissect.h> is the public interface to
594  * this function and ensures that the second argument is
595  * correct for bounds-checking.
596  */
597 const char *
598 tok2strary_internal(register const char **lp, int n, register const char *fmt,
599         register int v)
600 {
601         static char buf[TOKBUFSIZE];
602
603         if (v >= 0 && v < n && lp[v] != NULL)
604                 return lp[v];
605         if (fmt == NULL)
606                 fmt = "#%d";
607         (void)snprintf(buf, sizeof(buf), fmt, v);
608         return (buf);
609 }
610
611 /*
612  * Convert a 32-bit netmask to prefixlen if possible
613  * the function returns the prefix-len; if plen == -1
614  * then conversion was not possible;
615  */
616
617 int
618 mask2plen(uint32_t mask)
619 {
620         uint32_t bitmasks[33] = {
621                 0x00000000,
622                 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
623                 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
624                 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
625                 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
626                 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
627                 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
628                 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
629                 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
630         };
631         int prefix_len = 32;
632
633         /* let's see if we can transform the mask into a prefixlen */
634         while (prefix_len >= 0) {
635                 if (bitmasks[prefix_len] == mask)
636                         break;
637                 prefix_len--;
638         }
639         return (prefix_len);
640 }
641
642 int
643 mask62plen(const u_char *mask)
644 {
645         u_char bitmasks[9] = {
646                 0x00,
647                 0x80, 0xc0, 0xe0, 0xf0,
648                 0xf8, 0xfc, 0xfe, 0xff
649         };
650         int byte;
651         int cidr_len = 0;
652
653         for (byte = 0; byte < 16; byte++) {
654                 u_int bits;
655
656                 for (bits = 0; bits < (sizeof (bitmasks) / sizeof (bitmasks[0])); bits++) {
657                         if (mask[byte] == bitmasks[bits]) {
658                                 cidr_len += bits;
659                                 break;
660                         }
661                 }
662
663                 if (mask[byte] != 0xff)
664                         break;
665         }
666         return (cidr_len);
667 }
668
669 /*
670  * Routine to print out information for text-based protocols such as FTP,
671  * HTTP, SMTP, RTSP, SIP, ....
672  */
673 #define MAX_TOKEN       128
674
675 /*
676  * Fetch a token from a packet, starting at the specified index,
677  * and return the length of the token.
678  *
679  * Returns 0 on error; yes, this is indistinguishable from an empty
680  * token, but an "empty token" isn't a valid token - it just means
681  * either a space character at the beginning of the line (this
682  * includes a blank line) or no more tokens remaining on the line.
683  */
684 static int
685 fetch_token(netdissect_options *ndo, const u_char *pptr, u_int idx, u_int len,
686     u_char *tbuf, size_t tbuflen)
687 {
688         size_t toklen = 0;
689
690         for (; idx < len; idx++) {
691                 if (!ND_TTEST(*(pptr + idx))) {
692                         /* ran past end of captured data */
693                         return (0);
694                 }
695                 if (!isascii(*(pptr + idx))) {
696                         /* not an ASCII character */
697                         return (0);
698                 }
699                 if (isspace(*(pptr + idx))) {
700                         /* end of token */
701                         break;
702                 }
703                 if (!isprint(*(pptr + idx))) {
704                         /* not part of a command token or response code */
705                         return (0);
706                 }
707                 if (toklen + 2 > tbuflen) {
708                         /* no room for this character and terminating '\0' */
709                         return (0);
710                 }
711                 tbuf[toklen] = *(pptr + idx);
712                 toklen++;
713         }
714         if (toklen == 0) {
715                 /* no token */
716                 return (0);
717         }
718         tbuf[toklen] = '\0';
719
720         /*
721          * Skip past any white space after the token, until we see
722          * an end-of-line (CR or LF).
723          */
724         for (; idx < len; idx++) {
725                 if (!ND_TTEST(*(pptr + idx))) {
726                         /* ran past end of captured data */
727                         break;
728                 }
729                 if (*(pptr + idx) == '\r' || *(pptr + idx) == '\n') {
730                         /* end of line */
731                         break;
732                 }
733                 if (!isascii(*(pptr + idx)) || !isprint(*(pptr + idx))) {
734                         /* not a printable ASCII character */
735                         break;
736                 }
737                 if (!isspace(*(pptr + idx))) {
738                         /* beginning of next token */
739                         break;
740                 }
741         }
742         return (idx);
743 }
744
745 /*
746  * Scan a buffer looking for a line ending - LF or CR-LF.
747  * Return the index of the character after the line ending or 0 if
748  * we encounter a non-ASCII or non-printable character or don't find
749  * the line ending.
750  */
751 static u_int
752 print_txt_line(netdissect_options *ndo, const char *protoname,
753     const char *prefix, const u_char *pptr, u_int idx, u_int len)
754 {
755         u_int startidx;
756         u_int linelen;
757
758         startidx = idx;
759         while (idx < len) {
760                 ND_TCHECK(*(pptr+idx));
761                 if (*(pptr+idx) == '\n') {
762                         /*
763                          * LF without CR; end of line.
764                          * Skip the LF and print the line, with the
765                          * exception of the LF.
766                          */
767                         linelen = idx - startidx;
768                         idx++;
769                         goto print;
770                 } else if (*(pptr+idx) == '\r') {
771                         /* CR - any LF? */
772                         if ((idx+1) >= len) {
773                                 /* not in this packet */
774                                 return (0);
775                         }
776                         ND_TCHECK(*(pptr+idx+1));
777                         if (*(pptr+idx+1) == '\n') {
778                                 /*
779                                  * CR-LF; end of line.
780                                  * Skip the CR-LF and print the line, with
781                                  * the exception of the CR-LF.
782                                  */
783                                 linelen = idx - startidx;
784                                 idx += 2;
785                                 goto print;
786                         }
787
788                         /*
789                          * CR followed by something else; treat this
790                          * as if it were binary data, and don't print
791                          * it.
792                          */
793                         return (0);
794                 } else if (!isascii(*(pptr+idx)) ||
795                     (!isprint(*(pptr+idx)) && *(pptr+idx) != '\t')) {
796                         /*
797                          * Not a printable ASCII character and not a tab;
798                          * treat this as if it were binary data, and
799                          * don't print it.
800                          */
801                         return (0);
802                 }
803                 idx++;
804         }
805
806         /*
807          * All printable ASCII, but no line ending after that point
808          * in the buffer; treat this as if it were truncated.
809          */
810 trunc:
811         linelen = idx - startidx;
812         ND_PRINT((ndo, "%s%.*s[!%s]", prefix, (int)linelen, pptr + startidx,
813             protoname));
814         return (0);
815
816 print:
817         ND_PRINT((ndo, "%s%.*s", prefix, (int)linelen, pptr + startidx));
818         return (idx);
819 }
820
821 void
822 txtproto_print(netdissect_options *ndo, const u_char *pptr, u_int len,
823     const char *protoname, const char **cmds, u_int flags)
824 {
825         u_int idx, eol;
826         u_char token[MAX_TOKEN+1];
827         const char *cmd;
828         int is_reqresp = 0;
829         const char *pnp;
830
831         if (cmds != NULL) {
832                 /*
833                  * This protocol has more than just request and
834                  * response lines; see whether this looks like a
835                  * request or response.
836                  */
837                 idx = fetch_token(ndo, pptr, 0, len, token, sizeof(token));
838                 if (idx != 0) {
839                         /* Is this a valid request name? */
840                         while ((cmd = *cmds++) != NULL) {
841                                 if (ascii_strcasecmp((const char *)token, cmd) == 0) {
842                                         /* Yes. */
843                                         is_reqresp = 1;
844                                         break;
845                                 }
846                         }
847
848                         /*
849                          * No - is this a valid response code (3 digits)?
850                          *
851                          * Is this token the response code, or is the next
852                          * token the response code?
853                          */
854                         if (flags & RESP_CODE_SECOND_TOKEN) {
855                                 /*
856                                  * Next token - get it.
857                                  */
858                                 idx = fetch_token(ndo, pptr, idx, len, token,
859                                     sizeof(token));
860                         }
861                         if (idx != 0) {
862                                 if (isdigit(token[0]) && isdigit(token[1]) &&
863                                     isdigit(token[2]) && token[3] == '\0') {
864                                         /* Yes. */
865                                         is_reqresp = 1;
866                                 }
867                         }
868                 }
869         } else {
870                 /*
871                  * This protocol has only request and response lines
872                  * (e.g., FTP, where all the data goes over a
873                  * different connection); assume the payload is
874                  * a request or response.
875                  */
876                 is_reqresp = 1;
877         }
878
879         /* Capitalize the protocol name */
880         for (pnp = protoname; *pnp != '\0'; pnp++)
881                 ND_PRINT((ndo, "%c", toupper((u_char)*pnp)));
882
883         if (is_reqresp) {
884                 /*
885                  * In non-verbose mode, just print the protocol, followed
886                  * by the first line as the request or response info.
887                  *
888                  * In verbose mode, print lines as text until we run out
889                  * of characters or see something that's not a
890                  * printable-ASCII line.
891                  */
892                 if (ndo->ndo_vflag) {
893                         /*
894                          * We're going to print all the text lines in the
895                          * request or response; just print the length
896                          * on the first line of the output.
897                          */
898                         ND_PRINT((ndo, ", length: %u", len));
899                         for (idx = 0;
900                             idx < len && (eol = print_txt_line(ndo, protoname, "\n\t", pptr, idx, len)) != 0;
901                             idx = eol)
902                                 ;
903                 } else {
904                         /*
905                          * Just print the first text line.
906                          */
907                         print_txt_line(ndo, protoname, ": ", pptr, 0, len);
908                 }
909         }
910 }
911
912 void
913 safeputs(netdissect_options *ndo,
914          const u_char *s, const u_int maxlen)
915 {
916         u_int idx = 0;
917
918         while (idx < maxlen && *s) {
919                 safeputchar(ndo, *s);
920                 idx++;
921                 s++;
922         }
923 }
924
925 void
926 safeputchar(netdissect_options *ndo,
927             const u_char c)
928 {
929         ND_PRINT((ndo, (c < 0x80 && ND_ISPRINT(c)) ? "%c" : "\\0x%02x", c));
930 }
931
932 #ifdef LBL_ALIGN
933 /*
934  * Some compilers try to optimize memcpy(), using the alignment constraint
935  * on the argument pointer type.  by using this function, we try to avoid the
936  * optimization.
937  */
938 void
939 unaligned_memcpy(void *p, const void *q, size_t l)
940 {
941         memcpy(p, q, l);
942 }
943
944 /* As with memcpy(), so with memcmp(). */
945 int
946 unaligned_memcmp(const void *p, const void *q, size_t l)
947 {
948         return (memcmp(p, q, l));
949 }
950 #endif
951