source: rtems-libbsd/freebsd/contrib/tcpdump/util-print.c @ 32a41a1

5
Last change on this file since 32a41a1 was 24631e2, checked in by Sebastian Huber <sebastian.huber@…>, on 03/11/19 at 08:33:28

tcpdump: Move static variables to special section

This fixes some issues if tcpdump is invoked a second time.

  • Property mode set to 100644
File size: 23.6 KB
Line 
1#include <machine/rtems-bsd-user-space.h>
2
3#ifdef __rtems__
4#include <machine/rtems-bsd-program.h>
5#include "rtems-bsd-tcpdump-namespace.h"
6#endif /* __rtems__ */
7/*
8 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
9 *      The Regents of the University of California.  All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that: (1) source code distributions
13 * retain the above copyright notice and this paragraph in its entirety, (2)
14 * distributions including binary code include the above copyright notice and
15 * this paragraph in its entirety in the documentation or other materials
16 * provided with the distribution, and (3) all advertising materials mentioning
17 * features or use of this software display the following acknowledgement:
18 * ``This product includes software developed by the University of California,
19 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
20 * the University nor the names of its contributors may be used to endorse
21 * or promote products derived from this software without specific prior
22 * written permission.
23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
24 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
26 */
27
28/*
29 * txtproto_print() derived from original code by Hannes Gredler
30 * (hannes@gredler.at):
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that: (1) source code
34 * distributions retain the above copyright notice and this paragraph
35 * in its entirety, and (2) distributions including binary code include
36 * the above copyright notice and this paragraph in its entirety in
37 * the documentation or other materials provided with the distribution.
38 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
39 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
40 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
41 * FOR A PARTICULAR PURPOSE.
42 */
43
44#ifdef HAVE_CONFIG_H
45#include "config.h"
46#endif
47
48#include <netdissect-stdinc.h>
49
50#include <sys/stat.h>
51
52#ifdef HAVE_FCNTL_H
53#include <fcntl.h>
54#endif
55#include <ctype.h>
56#include <stdio.h>
57#include <stdarg.h>
58#include <stdlib.h>
59#include <string.h>
60
61#include "netdissect.h"
62#include "ascii_strcasecmp.h"
63#include "timeval-operations.h"
64
65int32_t thiszone;               /* seconds offset from gmt to local time */
66/* invalid string to print '(invalid)' for malformed or corrupted packets */
67const char istr[] = " (invalid)";
68
69/*
70 * timestamp display buffer size, the biggest size of both formats is needed
71 * sizeof("0000000000.000000000") > sizeof("00:00:00.000000000")
72 */
73#define TS_BUF_SIZE sizeof("0000000000.000000000")
74
75#define TOKBUFSIZE 128
76
77/*
78 * Print out a character, filtering out the non-printable ones
79 */
80void
81fn_print_char(netdissect_options *ndo, u_char c)
82{
83        if (!ND_ISASCII(c)) {
84                c = ND_TOASCII(c);
85                ND_PRINT((ndo, "M-"));
86        }
87        if (!ND_ISPRINT(c)) {
88                c ^= 0x40;      /* DEL to ?, others to alpha */
89                ND_PRINT((ndo, "^"));
90        }
91        ND_PRINT((ndo, "%c", c));
92}
93
94/*
95 * Print out a null-terminated filename (or other ascii string).
96 * If ep is NULL, assume no truncation check is needed.
97 * Return true if truncated.
98 * Stop at ep (if given) or before the null char, whichever is first.
99 */
100int
101fn_print(netdissect_options *ndo,
102         register const u_char *s, register const u_char *ep)
103{
104        register int ret;
105        register u_char c;
106
107        ret = 1;                        /* assume truncated */
108        while (ep == NULL || s < ep) {
109                c = *s++;
110                if (c == '\0') {
111                        ret = 0;
112                        break;
113                }
114                if (!ND_ISASCII(c)) {
115                        c = ND_TOASCII(c);
116                        ND_PRINT((ndo, "M-"));
117                }
118                if (!ND_ISPRINT(c)) {
119                        c ^= 0x40;      /* DEL to ?, others to alpha */
120                        ND_PRINT((ndo, "^"));
121                }
122                ND_PRINT((ndo, "%c", c));
123        }
124        return(ret);
125}
126
127/*
128 * Print out a null-terminated filename (or other ascii string) from
129 * a fixed-length buffer.
130 * If ep is NULL, assume no truncation check is needed.
131 * Return the number of bytes of string processed, including the
132 * terminating null, if not truncated.  Return 0 if truncated.
133 */
134u_int
135fn_printztn(netdissect_options *ndo,
136         register const u_char *s, register u_int n, register const u_char *ep)
137{
138        register u_int bytes;
139        register u_char c;
140
141        bytes = 0;
142        for (;;) {
143                if (n == 0 || (ep != NULL && s >= ep)) {
144                        /*
145                         * Truncated.  This includes "no null before we
146                         * got to the end of the fixed-length buffer".
147                         *
148                         * XXX - BOOTP says "null-terminated", which
149                         * means the maximum length of the string, in
150                         * bytes, is 1 less than the size of the buffer,
151                         * as there must always be a terminating null.
152                         */
153                        bytes = 0;
154                        break;
155                }
156
157                c = *s++;
158                bytes++;
159                n--;
160                if (c == '\0') {
161                        /* End of string */
162                        break;
163                }
164                if (!ND_ISASCII(c)) {
165                        c = ND_TOASCII(c);
166                        ND_PRINT((ndo, "M-"));
167                }
168                if (!ND_ISPRINT(c)) {
169                        c ^= 0x40;      /* DEL to ?, others to alpha */
170                        ND_PRINT((ndo, "^"));
171                }
172                ND_PRINT((ndo, "%c", c));
173        }
174        return(bytes);
175}
176
177/*
178 * Print out a counted filename (or other ascii string).
179 * If ep is NULL, assume no truncation check is needed.
180 * Return true if truncated.
181 * Stop at ep (if given) or after n bytes, whichever is first.
182 */
183int
184fn_printn(netdissect_options *ndo,
185          register const u_char *s, register u_int n, register const u_char *ep)
186{
187        register u_char c;
188
189        while (n > 0 && (ep == NULL || s < ep)) {
190                n--;
191                c = *s++;
192                if (!ND_ISASCII(c)) {
193                        c = ND_TOASCII(c);
194                        ND_PRINT((ndo, "M-"));
195                }
196                if (!ND_ISPRINT(c)) {
197                        c ^= 0x40;      /* DEL to ?, others to alpha */
198                        ND_PRINT((ndo, "^"));
199                }
200                ND_PRINT((ndo, "%c", c));
201        }
202        return (n == 0) ? 0 : 1;
203}
204
205/*
206 * Print out a null-padded filename (or other ascii string).
207 * If ep is NULL, assume no truncation check is needed.
208 * Return true if truncated.
209 * Stop at ep (if given) or after n bytes or before the null char,
210 * whichever is first.
211 */
212int
213fn_printzp(netdissect_options *ndo,
214           register const u_char *s, register u_int n,
215           register const u_char *ep)
216{
217        register int ret;
218        register u_char c;
219
220        ret = 1;                        /* assume truncated */
221        while (n > 0 && (ep == NULL || s < ep)) {
222                n--;
223                c = *s++;
224                if (c == '\0') {
225                        ret = 0;
226                        break;
227                }
228                if (!ND_ISASCII(c)) {
229                        c = ND_TOASCII(c);
230                        ND_PRINT((ndo, "M-"));
231                }
232                if (!ND_ISPRINT(c)) {
233                        c ^= 0x40;      /* DEL to ?, others to alpha */
234                        ND_PRINT((ndo, "^"));
235                }
236                ND_PRINT((ndo, "%c", c));
237        }
238        return (n == 0) ? 0 : ret;
239}
240
241/*
242 * Format the timestamp
243 */
244static char *
245ts_format(netdissect_options *ndo
246#ifndef HAVE_PCAP_SET_TSTAMP_PRECISION
247_U_
248#endif
249, int sec, int usec, char *buf)
250{
251        const char *format;
252
253#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
254        switch (ndo->ndo_tstamp_precision) {
255
256        case PCAP_TSTAMP_PRECISION_MICRO:
257                format = "%02d:%02d:%02d.%06u";
258                break;
259
260        case PCAP_TSTAMP_PRECISION_NANO:
261                format = "%02d:%02d:%02d.%09u";
262                break;
263
264        default:
265                format = "%02d:%02d:%02d.{unknown}";
266                break;
267        }
268#else
269        format = "%02d:%02d:%02d.%06u";
270#endif
271
272        snprintf(buf, TS_BUF_SIZE, format,
273                 sec / 3600, (sec % 3600) / 60, sec % 60, usec);
274
275        return buf;
276}
277
278/*
279 * Format the timestamp - Unix timeval style
280 */
281static char *
282ts_unix_format(netdissect_options *ndo
283#ifndef HAVE_PCAP_SET_TSTAMP_PRECISION
284_U_
285#endif
286, int sec, int usec, char *buf)
287{
288        const char *format;
289
290#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
291        switch (ndo->ndo_tstamp_precision) {
292
293        case PCAP_TSTAMP_PRECISION_MICRO:
294                format = "%u.%06u";
295                break;
296
297        case PCAP_TSTAMP_PRECISION_NANO:
298                format = "%u.%09u";
299                break;
300
301        default:
302                format = "%u.{unknown}";
303                break;
304        }
305#else
306        format = "%u.%06u";
307#endif
308
309        snprintf(buf, TS_BUF_SIZE, format,
310                 (unsigned)sec, (unsigned)usec);
311
312        return buf;
313}
314
315/*
316 * Print the timestamp
317 */
318void
319ts_print(netdissect_options *ndo,
320         register const struct timeval *tvp)
321{
322        register int s;
323        struct tm *tm;
324        time_t Time;
325        char buf[TS_BUF_SIZE];
326#ifdef __rtems__
327        __section(".rtemsrwset.bsd_prog_tcpdump.content")
328#endif /* __rtems__ */
329        static struct timeval tv_ref;
330        struct timeval tv_result;
331        int negative_offset;
332        int nano_prec;
333
334        switch (ndo->ndo_tflag) {
335
336        case 0: /* Default */
337                s = (tvp->tv_sec + thiszone) % 86400;
338                ND_PRINT((ndo, "%s ", ts_format(ndo, s, tvp->tv_usec, buf)));
339                break;
340
341        case 1: /* No time stamp */
342                break;
343
344        case 2: /* Unix timeval style */
345                ND_PRINT((ndo, "%s ", ts_unix_format(ndo,
346                          tvp->tv_sec, tvp->tv_usec, buf)));
347                break;
348
349        case 3: /* Microseconds/nanoseconds since previous packet */
350        case 5: /* Microseconds/nanoseconds since first packet */
351#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
352                switch (ndo->ndo_tstamp_precision) {
353                case PCAP_TSTAMP_PRECISION_MICRO:
354                        nano_prec = 0;
355                        break;
356                case PCAP_TSTAMP_PRECISION_NANO:
357                        nano_prec = 1;
358                        break;
359                default:
360                        nano_prec = 0;
361                        break;
362                }
363#else
364                nano_prec = 0;
365#endif
366                if (!(netdissect_timevalisset(&tv_ref)))
367                        tv_ref = *tvp; /* set timestamp for first packet */
368
369                negative_offset = netdissect_timevalcmp(tvp, &tv_ref, <);
370                if (negative_offset)
371                        netdissect_timevalsub(&tv_ref, tvp, &tv_result, nano_prec);
372                else
373                        netdissect_timevalsub(tvp, &tv_ref, &tv_result, nano_prec);
374
375                ND_PRINT((ndo, (negative_offset ? "-" : " ")));
376
377                ND_PRINT((ndo, "%s ", ts_format(ndo,
378                          tv_result.tv_sec, tv_result.tv_usec, buf)));
379
380                if (ndo->ndo_tflag == 3)
381                        tv_ref = *tvp; /* set timestamp for previous packet */
382                break;
383
384        case 4: /* Default + Date */
385                s = (tvp->tv_sec + thiszone) % 86400;
386                Time = (tvp->tv_sec + thiszone) - s;
387                tm = gmtime (&Time);
388                if (!tm)
389                        ND_PRINT((ndo, "Date fail  "));
390                else
391                        ND_PRINT((ndo, "%04d-%02d-%02d %s ",
392                               tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
393                               ts_format(ndo, s, tvp->tv_usec, buf)));
394                break;
395        }
396}
397
398/*
399 * Print an unsigned relative number of seconds (e.g. hold time, prune timer)
400 * in the form 5m1s.  This does no truncation, so 32230861 seconds
401 * is represented as 1y1w1d1h1m1s.
402 */
403void
404unsigned_relts_print(netdissect_options *ndo,
405                     uint32_t secs)
406{
407        static const char * const lengths[] = {"y", "w", "d", "h", "m", "s"};
408        static const u_int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
409        const char * const *l = lengths;
410        const u_int *s = seconds;
411
412        if (secs == 0) {
413                ND_PRINT((ndo, "0s"));
414                return;
415        }
416        while (secs > 0) {
417                if (secs >= *s) {
418                        ND_PRINT((ndo, "%d%s", secs / *s, *l));
419                        secs -= (secs / *s) * *s;
420                }
421                s++;
422                l++;
423        }
424}
425
426/*
427 * Print a signed relative number of seconds (e.g. hold time, prune timer)
428 * in the form 5m1s.  This does no truncation, so 32230861 seconds
429 * is represented as 1y1w1d1h1m1s.
430 */
431void
432signed_relts_print(netdissect_options *ndo,
433                   int32_t secs)
434{
435        if (secs < 0) {
436                ND_PRINT((ndo, "-"));
437                if (secs == INT32_MIN) {
438                        /*
439                         * -2^31; you can't fit its absolute value into
440                         * a 32-bit signed integer.
441                         *
442                         * Just directly pass said absolute value to
443                         * unsigned_relts_print() directly.
444                         *
445                         * (XXX - does ISO C guarantee that -(-2^n),
446                         * when calculated and cast to an n-bit unsigned
447                         * integer type, will have the value 2^n?)
448                         */
449                        unsigned_relts_print(ndo, 2147483648U);
450                } else {
451                        /*
452                         * We now know -secs will fit into an int32_t;
453                         * negate it and pass that to unsigned_relts_print().
454                         */
455                        unsigned_relts_print(ndo, -secs);
456                }
457                return;
458        }
459        unsigned_relts_print(ndo, secs);
460}
461
462/*
463 *  this is a generic routine for printing unknown data;
464 *  we pass on the linefeed plus indentation string to
465 *  get a proper output - returns 0 on error
466 */
467
468int
469print_unknown_data(netdissect_options *ndo, const u_char *cp,const char *ident,int len)
470{
471        if (len < 0) {
472          ND_PRINT((ndo,"%sDissector error: print_unknown_data called with negative length",
473                    ident));
474                return(0);
475        }
476        if (ndo->ndo_snapend - cp < len)
477                len = ndo->ndo_snapend - cp;
478        if (len < 0) {
479          ND_PRINT((ndo,"%sDissector error: print_unknown_data called with pointer past end of packet",
480                    ident));
481                return(0);
482        }
483        hex_print(ndo, ident,cp,len);
484        return(1); /* everything is ok */
485}
486
487/*
488 * Convert a token value to a string; use "fmt" if not found.
489 */
490const char *
491tok2strbuf(register const struct tok *lp, register const char *fmt,
492           register u_int v, char *buf, size_t bufsize)
493{
494        if (lp != NULL) {
495                while (lp->s != NULL) {
496                        if (lp->v == v)
497                                return (lp->s);
498                        ++lp;
499                }
500        }
501        if (fmt == NULL)
502                fmt = "#%d";
503
504        (void)snprintf(buf, bufsize, fmt, v);
505        return (const char *)buf;
506}
507
508/*
509 * Convert a token value to a string; use "fmt" if not found.
510 */
511const char *
512tok2str(register const struct tok *lp, register const char *fmt,
513        register u_int v)
514{
515        static char buf[4][TOKBUFSIZE];
516#ifdef __rtems__
517        __section(".rtemsrwset.bsd_prog_tcpdump.content")
518#endif /* __rtems__ */
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 */
532static char *
533bittok2str_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 */
585char *
586bittok2str_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 */
596char *
597bittok2str(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 */
609const char *
610tok2strary_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
629int
630mask2plen(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
654int
655mask62plen(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 */
696static int
697fetch_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 */
763static u_int
764print_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         */
822trunc:
823        linelen = idx - startidx;
824        ND_PRINT((ndo, "%s%.*s[!%s]", prefix, (int)linelen, pptr + startidx,
825            protoname));
826        return (0);
827
828print:
829        ND_PRINT((ndo, "%s%.*s", prefix, (int)linelen, pptr + startidx));
830        return (idx);
831}
832
833void
834txtproto_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
924void
925safeputs(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
937void
938safeputchar(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 */
950void
951unaligned_memcpy(void *p, const void *q, size_t l)
952{
953        memcpy(p, q, l);
954}
955
956/* As with memcpy(), so with memcmp(). */
957int
958unaligned_memcmp(const void *p, const void *q, size_t l)
959{
960        return (memcmp(p, q, l));
961}
962#endif
963
964#ifdef __rtems__
965#include "rtems-bsd-tcpdump-util-print-data.h"
966#endif /* __rtems__ */
Note: See TracBrowser for help on using the repository browser.