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

5
Last change on this file since d315955 was 12c2cfb, checked in by Sebastian Huber <sebastian.huber@…>, on 03/11/19 at 08:16:02

tcpdump: Constify

  • Property mode set to 100644
File size: 23.5 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        static struct timeval tv_ref;
327        struct timeval tv_result;
328        int negative_offset;
329        int nano_prec;
330
331        switch (ndo->ndo_tflag) {
332
333        case 0: /* Default */
334                s = (tvp->tv_sec + thiszone) % 86400;
335                ND_PRINT((ndo, "%s ", ts_format(ndo, s, tvp->tv_usec, buf)));
336                break;
337
338        case 1: /* No time stamp */
339                break;
340
341        case 2: /* Unix timeval style */
342                ND_PRINT((ndo, "%s ", ts_unix_format(ndo,
343                          tvp->tv_sec, tvp->tv_usec, buf)));
344                break;
345
346        case 3: /* Microseconds/nanoseconds since previous packet */
347        case 5: /* Microseconds/nanoseconds since first packet */
348#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
349                switch (ndo->ndo_tstamp_precision) {
350                case PCAP_TSTAMP_PRECISION_MICRO:
351                        nano_prec = 0;
352                        break;
353                case PCAP_TSTAMP_PRECISION_NANO:
354                        nano_prec = 1;
355                        break;
356                default:
357                        nano_prec = 0;
358                        break;
359                }
360#else
361                nano_prec = 0;
362#endif
363                if (!(netdissect_timevalisset(&tv_ref)))
364                        tv_ref = *tvp; /* set timestamp for first packet */
365
366                negative_offset = netdissect_timevalcmp(tvp, &tv_ref, <);
367                if (negative_offset)
368                        netdissect_timevalsub(&tv_ref, tvp, &tv_result, nano_prec);
369                else
370                        netdissect_timevalsub(tvp, &tv_ref, &tv_result, nano_prec);
371
372                ND_PRINT((ndo, (negative_offset ? "-" : " ")));
373
374                ND_PRINT((ndo, "%s ", ts_format(ndo,
375                          tv_result.tv_sec, tv_result.tv_usec, buf)));
376
377                if (ndo->ndo_tflag == 3)
378                        tv_ref = *tvp; /* set timestamp for previous packet */
379                break;
380
381        case 4: /* Default + Date */
382                s = (tvp->tv_sec + thiszone) % 86400;
383                Time = (tvp->tv_sec + thiszone) - s;
384                tm = gmtime (&Time);
385                if (!tm)
386                        ND_PRINT((ndo, "Date fail  "));
387                else
388                        ND_PRINT((ndo, "%04d-%02d-%02d %s ",
389                               tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
390                               ts_format(ndo, s, tvp->tv_usec, buf)));
391                break;
392        }
393}
394
395/*
396 * Print an unsigned relative number of seconds (e.g. hold time, prune timer)
397 * in the form 5m1s.  This does no truncation, so 32230861 seconds
398 * is represented as 1y1w1d1h1m1s.
399 */
400void
401unsigned_relts_print(netdissect_options *ndo,
402                     uint32_t secs)
403{
404        static const char * const lengths[] = {"y", "w", "d", "h", "m", "s"};
405        static const u_int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
406        const char * const *l = lengths;
407        const u_int *s = seconds;
408
409        if (secs == 0) {
410                ND_PRINT((ndo, "0s"));
411                return;
412        }
413        while (secs > 0) {
414                if (secs >= *s) {
415                        ND_PRINT((ndo, "%d%s", secs / *s, *l));
416                        secs -= (secs / *s) * *s;
417                }
418                s++;
419                l++;
420        }
421}
422
423/*
424 * Print a signed relative number of seconds (e.g. hold time, prune timer)
425 * in the form 5m1s.  This does no truncation, so 32230861 seconds
426 * is represented as 1y1w1d1h1m1s.
427 */
428void
429signed_relts_print(netdissect_options *ndo,
430                   int32_t secs)
431{
432        if (secs < 0) {
433                ND_PRINT((ndo, "-"));
434                if (secs == INT32_MIN) {
435                        /*
436                         * -2^31; you can't fit its absolute value into
437                         * a 32-bit signed integer.
438                         *
439                         * Just directly pass said absolute value to
440                         * unsigned_relts_print() directly.
441                         *
442                         * (XXX - does ISO C guarantee that -(-2^n),
443                         * when calculated and cast to an n-bit unsigned
444                         * integer type, will have the value 2^n?)
445                         */
446                        unsigned_relts_print(ndo, 2147483648U);
447                } else {
448                        /*
449                         * We now know -secs will fit into an int32_t;
450                         * negate it and pass that to unsigned_relts_print().
451                         */
452                        unsigned_relts_print(ndo, -secs);
453                }
454                return;
455        }
456        unsigned_relts_print(ndo, secs);
457}
458
459/*
460 *  this is a generic routine for printing unknown data;
461 *  we pass on the linefeed plus indentation string to
462 *  get a proper output - returns 0 on error
463 */
464
465int
466print_unknown_data(netdissect_options *ndo, const u_char *cp,const char *ident,int len)
467{
468        if (len < 0) {
469          ND_PRINT((ndo,"%sDissector error: print_unknown_data called with negative length",
470                    ident));
471                return(0);
472        }
473        if (ndo->ndo_snapend - cp < len)
474                len = ndo->ndo_snapend - cp;
475        if (len < 0) {
476          ND_PRINT((ndo,"%sDissector error: print_unknown_data called with pointer past end of packet",
477                    ident));
478                return(0);
479        }
480        hex_print(ndo, ident,cp,len);
481        return(1); /* everything is ok */
482}
483
484/*
485 * Convert a token value to a string; use "fmt" if not found.
486 */
487const char *
488tok2strbuf(register const struct tok *lp, register const char *fmt,
489           register u_int v, char *buf, size_t bufsize)
490{
491        if (lp != NULL) {
492                while (lp->s != NULL) {
493                        if (lp->v == v)
494                                return (lp->s);
495                        ++lp;
496                }
497        }
498        if (fmt == NULL)
499                fmt = "#%d";
500
501        (void)snprintf(buf, bufsize, fmt, v);
502        return (const char *)buf;
503}
504
505/*
506 * Convert a token value to a string; use "fmt" if not found.
507 */
508const char *
509tok2str(register const struct tok *lp, register const char *fmt,
510        register u_int v)
511{
512        static char buf[4][TOKBUFSIZE];
513        static int idx = 0;
514        char *ret;
515
516        ret = buf[idx];
517        idx = (idx+1) & 3;
518        return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0]));
519}
520
521/*
522 * Convert a bit token value to a string; use "fmt" if not found.
523 * this is useful for parsing bitfields, the output strings are seperated
524 * if the s field is positive.
525 */
526static char *
527bittok2str_internal(register const struct tok *lp, register const char *fmt,
528           register u_int v, const char *sep)
529{
530        static char buf[1024+1]; /* our string buffer */
531        char *bufp = buf;
532        size_t space_left = sizeof(buf), string_size;
533        register u_int rotbit; /* this is the bit we rotate through all bitpositions */
534        register u_int tokval;
535        const char * sepstr = "";
536
537        while (lp != NULL && lp->s != NULL) {
538            tokval=lp->v;   /* load our first value */
539            rotbit=1;
540            while (rotbit != 0) {
541                /*
542                 * lets AND the rotating bit with our token value
543                 * and see if we have got a match
544                 */
545                if (tokval == (v&rotbit)) {
546                    /* ok we have found something */
547                    if (space_left <= 1)
548                        return (buf); /* only enough room left for NUL, if that */
549                    string_size = strlcpy(bufp, sepstr, space_left);
550                    if (string_size >= space_left)
551                        return (buf);    /* we ran out of room */
552                    bufp += string_size;
553                    space_left -= string_size;
554                    if (space_left <= 1)
555                        return (buf); /* only enough room left for NUL, if that */
556                    string_size = strlcpy(bufp, lp->s, space_left);
557                    if (string_size >= space_left)
558                        return (buf);    /* we ran out of room */
559                    bufp += string_size;
560                    space_left -= string_size;
561                    sepstr = sep;
562                    break;
563                }
564                rotbit=rotbit<<1; /* no match - lets shift and try again */
565            }
566            lp++;
567        }
568
569        if (bufp == buf)
570            /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
571            (void)snprintf(buf, sizeof(buf), fmt == NULL ? "#%08x" : fmt, v);
572        return (buf);
573}
574
575/*
576 * Convert a bit token value to a string; use "fmt" if not found.
577 * this is useful for parsing bitfields, the output strings are not seperated.
578 */
579char *
580bittok2str_nosep(register const struct tok *lp, register const char *fmt,
581           register u_int v)
582{
583    return (bittok2str_internal(lp, fmt, v, ""));
584}
585
586/*
587 * Convert a bit token value to a string; use "fmt" if not found.
588 * this is useful for parsing bitfields, the output strings are comma seperated.
589 */
590char *
591bittok2str(register const struct tok *lp, register const char *fmt,
592           register u_int v)
593{
594    return (bittok2str_internal(lp, fmt, v, ", "));
595}
596
597/*
598 * Convert a value to a string using an array; the macro
599 * tok2strary() in <netdissect.h> is the public interface to
600 * this function and ensures that the second argument is
601 * correct for bounds-checking.
602 */
603const char *
604tok2strary_internal(register const char **lp, int n, register const char *fmt,
605        register int v)
606{
607        static char buf[TOKBUFSIZE];
608
609        if (v >= 0 && v < n && lp[v] != NULL)
610                return lp[v];
611        if (fmt == NULL)
612                fmt = "#%d";
613        (void)snprintf(buf, sizeof(buf), fmt, v);
614        return (buf);
615}
616
617/*
618 * Convert a 32-bit netmask to prefixlen if possible
619 * the function returns the prefix-len; if plen == -1
620 * then conversion was not possible;
621 */
622
623int
624mask2plen(uint32_t mask)
625{
626        uint32_t bitmasks[33] = {
627                0x00000000,
628                0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
629                0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
630                0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
631                0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
632                0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
633                0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
634                0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
635                0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
636        };
637        int prefix_len = 32;
638
639        /* let's see if we can transform the mask into a prefixlen */
640        while (prefix_len >= 0) {
641                if (bitmasks[prefix_len] == mask)
642                        break;
643                prefix_len--;
644        }
645        return (prefix_len);
646}
647
648int
649mask62plen(const u_char *mask)
650{
651        u_char bitmasks[9] = {
652                0x00,
653                0x80, 0xc0, 0xe0, 0xf0,
654                0xf8, 0xfc, 0xfe, 0xff
655        };
656        int byte;
657        int cidr_len = 0;
658
659        for (byte = 0; byte < 16; byte++) {
660                u_int bits;
661
662                for (bits = 0; bits < (sizeof (bitmasks) / sizeof (bitmasks[0])); bits++) {
663                        if (mask[byte] == bitmasks[bits]) {
664                                cidr_len += bits;
665                                break;
666                        }
667                }
668
669                if (mask[byte] != 0xff)
670                        break;
671        }
672        return (cidr_len);
673}
674
675/*
676 * Routine to print out information for text-based protocols such as FTP,
677 * HTTP, SMTP, RTSP, SIP, ....
678 */
679#define MAX_TOKEN       128
680
681/*
682 * Fetch a token from a packet, starting at the specified index,
683 * and return the length of the token.
684 *
685 * Returns 0 on error; yes, this is indistinguishable from an empty
686 * token, but an "empty token" isn't a valid token - it just means
687 * either a space character at the beginning of the line (this
688 * includes a blank line) or no more tokens remaining on the line.
689 */
690static int
691fetch_token(netdissect_options *ndo, const u_char *pptr, u_int idx, u_int len,
692    u_char *tbuf, size_t tbuflen)
693{
694        size_t toklen = 0;
695
696        for (; idx < len; idx++) {
697                if (!ND_TTEST(*(pptr + idx))) {
698                        /* ran past end of captured data */
699                        return (0);
700                }
701                if (!isascii(*(pptr + idx))) {
702                        /* not an ASCII character */
703                        return (0);
704                }
705                if (isspace(*(pptr + idx))) {
706                        /* end of token */
707                        break;
708                }
709                if (!isprint(*(pptr + idx))) {
710                        /* not part of a command token or response code */
711                        return (0);
712                }
713                if (toklen + 2 > tbuflen) {
714                        /* no room for this character and terminating '\0' */
715                        return (0);
716                }
717                tbuf[toklen] = *(pptr + idx);
718                toklen++;
719        }
720        if (toklen == 0) {
721                /* no token */
722                return (0);
723        }
724        tbuf[toklen] = '\0';
725
726        /*
727         * Skip past any white space after the token, until we see
728         * an end-of-line (CR or LF).
729         */
730        for (; idx < len; idx++) {
731                if (!ND_TTEST(*(pptr + idx))) {
732                        /* ran past end of captured data */
733                        break;
734                }
735                if (*(pptr + idx) == '\r' || *(pptr + idx) == '\n') {
736                        /* end of line */
737                        break;
738                }
739                if (!isascii(*(pptr + idx)) || !isprint(*(pptr + idx))) {
740                        /* not a printable ASCII character */
741                        break;
742                }
743                if (!isspace(*(pptr + idx))) {
744                        /* beginning of next token */
745                        break;
746                }
747        }
748        return (idx);
749}
750
751/*
752 * Scan a buffer looking for a line ending - LF or CR-LF.
753 * Return the index of the character after the line ending or 0 if
754 * we encounter a non-ASCII or non-printable character or don't find
755 * the line ending.
756 */
757static u_int
758print_txt_line(netdissect_options *ndo, const char *protoname,
759    const char *prefix, const u_char *pptr, u_int idx, u_int len)
760{
761        u_int startidx;
762        u_int linelen;
763
764        startidx = idx;
765        while (idx < len) {
766                ND_TCHECK(*(pptr+idx));
767                if (*(pptr+idx) == '\n') {
768                        /*
769                         * LF without CR; end of line.
770                         * Skip the LF and print the line, with the
771                         * exception of the LF.
772                         */
773                        linelen = idx - startidx;
774                        idx++;
775                        goto print;
776                } else if (*(pptr+idx) == '\r') {
777                        /* CR - any LF? */
778                        if ((idx+1) >= len) {
779                                /* not in this packet */
780                                return (0);
781                        }
782                        ND_TCHECK(*(pptr+idx+1));
783                        if (*(pptr+idx+1) == '\n') {
784                                /*
785                                 * CR-LF; end of line.
786                                 * Skip the CR-LF and print the line, with
787                                 * the exception of the CR-LF.
788                                 */
789                                linelen = idx - startidx;
790                                idx += 2;
791                                goto print;
792                        }
793
794                        /*
795                         * CR followed by something else; treat this
796                         * as if it were binary data, and don't print
797                         * it.
798                         */
799                        return (0);
800                } else if (!isascii(*(pptr+idx)) ||
801                    (!isprint(*(pptr+idx)) && *(pptr+idx) != '\t')) {
802                        /*
803                         * Not a printable ASCII character and not a tab;
804                         * treat this as if it were binary data, and
805                         * don't print it.
806                         */
807                        return (0);
808                }
809                idx++;
810        }
811
812        /*
813         * All printable ASCII, but no line ending after that point
814         * in the buffer; treat this as if it were truncated.
815         */
816trunc:
817        linelen = idx - startidx;
818        ND_PRINT((ndo, "%s%.*s[!%s]", prefix, (int)linelen, pptr + startidx,
819            protoname));
820        return (0);
821
822print:
823        ND_PRINT((ndo, "%s%.*s", prefix, (int)linelen, pptr + startidx));
824        return (idx);
825}
826
827void
828txtproto_print(netdissect_options *ndo, const u_char *pptr, u_int len,
829    const char *protoname, const char **cmds, u_int flags)
830{
831        u_int idx, eol;
832        u_char token[MAX_TOKEN+1];
833        const char *cmd;
834        int is_reqresp = 0;
835        const char *pnp;
836
837        if (cmds != NULL) {
838                /*
839                 * This protocol has more than just request and
840                 * response lines; see whether this looks like a
841                 * request or response.
842                 */
843                idx = fetch_token(ndo, pptr, 0, len, token, sizeof(token));
844                if (idx != 0) {
845                        /* Is this a valid request name? */
846                        while ((cmd = *cmds++) != NULL) {
847                                if (ascii_strcasecmp((const char *)token, cmd) == 0) {
848                                        /* Yes. */
849                                        is_reqresp = 1;
850                                        break;
851                                }
852                        }
853
854                        /*
855                         * No - is this a valid response code (3 digits)?
856                         *
857                         * Is this token the response code, or is the next
858                         * token the response code?
859                         */
860                        if (flags & RESP_CODE_SECOND_TOKEN) {
861                                /*
862                                 * Next token - get it.
863                                 */
864                                idx = fetch_token(ndo, pptr, idx, len, token,
865                                    sizeof(token));
866                        }
867                        if (idx != 0) {
868                                if (isdigit(token[0]) && isdigit(token[1]) &&
869                                    isdigit(token[2]) && token[3] == '\0') {
870                                        /* Yes. */
871                                        is_reqresp = 1;
872                                }
873                        }
874                }
875        } else {
876                /*
877                 * This protocol has only request and response lines
878                 * (e.g., FTP, where all the data goes over a
879                 * different connection); assume the payload is
880                 * a request or response.
881                 */
882                is_reqresp = 1;
883        }
884
885        /* Capitalize the protocol name */
886        for (pnp = protoname; *pnp != '\0'; pnp++)
887                ND_PRINT((ndo, "%c", toupper((u_char)*pnp)));
888
889        if (is_reqresp) {
890                /*
891                 * In non-verbose mode, just print the protocol, followed
892                 * by the first line as the request or response info.
893                 *
894                 * In verbose mode, print lines as text until we run out
895                 * of characters or see something that's not a
896                 * printable-ASCII line.
897                 */
898                if (ndo->ndo_vflag) {
899                        /*
900                         * We're going to print all the text lines in the
901                         * request or response; just print the length
902                         * on the first line of the output.
903                         */
904                        ND_PRINT((ndo, ", length: %u", len));
905                        for (idx = 0;
906                            idx < len && (eol = print_txt_line(ndo, protoname, "\n\t", pptr, idx, len)) != 0;
907                            idx = eol)
908                                ;
909                } else {
910                        /*
911                         * Just print the first text line.
912                         */
913                        print_txt_line(ndo, protoname, ": ", pptr, 0, len);
914                }
915        }
916}
917
918void
919safeputs(netdissect_options *ndo,
920         const u_char *s, const u_int maxlen)
921{
922        u_int idx = 0;
923
924        while (idx < maxlen && *s) {
925                safeputchar(ndo, *s);
926                idx++;
927                s++;
928        }
929}
930
931void
932safeputchar(netdissect_options *ndo,
933            const u_char c)
934{
935        ND_PRINT((ndo, (c < 0x80 && ND_ISPRINT(c)) ? "%c" : "\\0x%02x", c));
936}
937
938#ifdef LBL_ALIGN
939/*
940 * Some compilers try to optimize memcpy(), using the alignment constraint
941 * on the argument pointer type.  by using this function, we try to avoid the
942 * optimization.
943 */
944void
945unaligned_memcpy(void *p, const void *q, size_t l)
946{
947        memcpy(p, q, l);
948}
949
950/* As with memcpy(), so with memcmp(). */
951int
952unaligned_memcmp(const void *p, const void *q, size_t l)
953{
954        return (memcmp(p, q, l));
955}
956#endif
957
958#ifdef __rtems__
959#include "rtems-bsd-tcpdump-util-print-data.h"
960#endif /* __rtems__ */
Note: See TracBrowser for help on using the repository browser.