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

6-freebsd-12
Last change on this file was 46b3858, checked in by Sebastian Huber <sebastian.huber@…>, on 02/10/20 at 14:34:55

Update to FreeBSD stable/12 2020-02-10

Git mirror commit 0d1c391321b34b3025cf0e72f2231d836ff76da8.

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