"Fossies" - the Fresh Open Source Software Archive

Member "tcpdump-4.99.1/./util-print.c" (7 Jun 2021, 24958 Bytes) of package /linux/misc/tcpdump-4.99.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "util-print.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.99.0_vs_4.99.1.

    1 /*
    2  * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
    3  *  The Regents of the University of California.  All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that: (1) source code distributions
    7  * retain the above copyright notice and this paragraph in its entirety, (2)
    8  * distributions including binary code include the above copyright notice and
    9  * this paragraph in its entirety in the documentation or other materials
   10  * provided with the distribution, and (3) all advertising materials mentioning
   11  * features or use of this software display the following acknowledgement:
   12  * ``This product includes software developed by the University of California,
   13  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
   14  * the University nor the names of its contributors may be used to endorse
   15  * or promote products derived from this software without specific prior
   16  * written permission.
   17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
   18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
   19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
   20  */
   21 
   22 /*
   23  * txtproto_print() derived from original code by Hannes Gredler
   24  * (hannes@gredler.at):
   25  *
   26  * Redistribution and use in source and binary forms, with or without
   27  * modification, are permitted provided that: (1) source code
   28  * distributions retain the above copyright notice and this paragraph
   29  * in its entirety, and (2) distributions including binary code include
   30  * the above copyright notice and this paragraph in its entirety in
   31  * the documentation or other materials provided with the distribution.
   32  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
   33  * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
   34  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   35  * FOR A PARTICULAR PURPOSE.
   36  */
   37 
   38 #ifdef HAVE_CONFIG_H
   39 #include <config.h>
   40 #endif
   41 
   42 #include "netdissect-stdinc.h"
   43 
   44 #include <sys/stat.h>
   45 
   46 #ifdef HAVE_FCNTL_H
   47 #include <fcntl.h>
   48 #endif
   49 #include <stdio.h>
   50 #include <stdarg.h>
   51 #include <stdlib.h>
   52 #include <string.h>
   53 
   54 #include "netdissect-ctype.h"
   55 
   56 #include "netdissect.h"
   57 #include "extract.h"
   58 #include "ascii_strcasecmp.h"
   59 #include "timeval-operations.h"
   60 
   61 #define TOKBUFSIZE 128
   62 
   63 enum date_flag { WITHOUT_DATE = 0, WITH_DATE = 1 };
   64 enum time_flag { UTC_TIME = 0, LOCAL_TIME = 1 };
   65 
   66 /*
   67  * Print out a character, filtering out the non-printable ones
   68  */
   69 void
   70 fn_print_char(netdissect_options *ndo, u_char c)
   71 {
   72     if (!ND_ISASCII(c)) {
   73         c = ND_TOASCII(c);
   74         ND_PRINT("M-");
   75     }
   76     if (!ND_ASCII_ISPRINT(c)) {
   77         c ^= 0x40;  /* DEL to ?, others to alpha */
   78         ND_PRINT("^");
   79     }
   80     ND_PRINT("%c", c);
   81 }
   82 
   83 /*
   84  * Print a null-terminated string, filtering out non-printable characters.
   85  * DON'T USE IT with a pointer on the packet buffer because there is no
   86  * truncation check. For this use, see the nd_printX() functions below.
   87  */
   88 void
   89 fn_print_str(netdissect_options *ndo, const u_char *s)
   90 {
   91     while (*s != '\0') {
   92         fn_print_char(ndo, *s);
   93         s++;
   94        }
   95 }
   96 
   97 /*
   98  * Print out a null-terminated filename (or other ASCII string) from
   99  * a fixed-length field in the packet buffer, or from what remains of
  100  * the packet.
  101  *
  102  * n is the length of the fixed-length field, or the number of bytes
  103  * remaining in the packet based on its on-the-network length.
  104  *
  105  * If ep is non-null, it should point just past the last captured byte
  106  * of the packet, e.g. ndo->ndo_snapend.  If ep is NULL, we assume no
  107  * truncation check, other than the checks of the field length/remaining
  108  * packet data length, is needed.
  109  *
  110  * Return the number of bytes of string processed, including the
  111  * terminating null, if not truncated; as the terminating null is
  112  * included in the count, and as there must be a terminating null,
  113  * this will always be non-zero.  Return 0 if truncated.
  114  */
  115 u_int
  116 nd_printztn(netdissect_options *ndo,
  117          const u_char *s, u_int n, const u_char *ep)
  118 {
  119     u_int bytes;
  120     u_char c;
  121 
  122     bytes = 0;
  123     for (;;) {
  124         if (n == 0 || (ep != NULL && s >= ep)) {
  125             /*
  126              * Truncated.  This includes "no null before we
  127              * got to the end of the fixed-length buffer or
  128              * the end of the packet".
  129              *
  130              * XXX - BOOTP says "null-terminated", which
  131              * means the maximum length of the string, in
  132              * bytes, is 1 less than the size of the buffer,
  133              * as there must always be a terminating null.
  134              */
  135             bytes = 0;
  136             break;
  137         }
  138 
  139         c = GET_U_1(s);
  140         s++;
  141         bytes++;
  142         n--;
  143         if (c == '\0') {
  144             /* End of string */
  145             break;
  146         }
  147         fn_print_char(ndo, c);
  148     }
  149     return(bytes);
  150 }
  151 
  152 /*
  153  * Print out a counted filename (or other ASCII string), part of
  154  * the packet buffer.
  155  * If ep is NULL, assume no truncation check is needed.
  156  * Return true if truncated.
  157  * Stop at ep (if given) or after n bytes, whichever is first.
  158  */
  159 int
  160 nd_printn(netdissect_options *ndo,
  161           const u_char *s, u_int n, const u_char *ep)
  162 {
  163     u_char c;
  164 
  165     while (n > 0 && (ep == NULL || s < ep)) {
  166         n--;
  167         c = GET_U_1(s);
  168         s++;
  169         fn_print_char(ndo, c);
  170     }
  171     return (n == 0) ? 0 : 1;
  172 }
  173 
  174 /*
  175  * Print a null-padded filename (or other ASCII string), part of
  176  * the packet buffer, filtering out non-printable characters.
  177  * Stop if truncated (via GET_U_1/longjmp) or after n bytes or before
  178  * the null char, whichever occurs first.
  179  * The suffix comes from: j:longJmp, n:after N bytes, p:null-Padded.
  180  */
  181 void
  182 nd_printjnp(netdissect_options *ndo, const u_char *s, u_int n)
  183 {
  184     u_char c;
  185 
  186     while (n > 0) {
  187         c = GET_U_1(s);
  188         if (c == '\0')
  189             break;
  190         fn_print_char(ndo, c);
  191         n--;
  192         s++;
  193     }
  194 }
  195 
  196 /*
  197  * Print the timestamp .FRAC part (Microseconds/nanoseconds)
  198  */
  199 static void
  200 ts_frac_print(netdissect_options *ndo, long usec)
  201 {
  202 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
  203     switch (ndo->ndo_tstamp_precision) {
  204 
  205     case PCAP_TSTAMP_PRECISION_MICRO:
  206         ND_PRINT(".%06u", (unsigned)usec);
  207         break;
  208 
  209     case PCAP_TSTAMP_PRECISION_NANO:
  210         ND_PRINT(".%09u", (unsigned)usec);
  211         break;
  212 
  213     default:
  214         ND_PRINT(".{unknown}");
  215         break;
  216     }
  217 #else
  218     ND_PRINT(".%06u", (unsigned)usec);
  219 #endif
  220 }
  221 
  222 /*
  223  * Print the timestamp as [YY:MM:DD] HH:MM:SS.FRAC.
  224  *   if time_flag == LOCAL_TIME print local time else UTC/GMT time
  225  *   if date_flag == WITH_DATE print YY:MM:DD before HH:MM:SS.FRAC
  226  */
  227 static void
  228 ts_date_hmsfrac_print(netdissect_options *ndo, long sec, long usec,
  229               enum date_flag date_flag, enum time_flag time_flag)
  230 {
  231     time_t Time = sec;
  232     struct tm *tm;
  233     char timestr[32];
  234 
  235     if ((unsigned)sec & 0x80000000) {
  236         ND_PRINT("[Error converting time]");
  237         return;
  238     }
  239 
  240     if (time_flag == LOCAL_TIME)
  241         tm = localtime(&Time);
  242     else
  243         tm = gmtime(&Time);
  244 
  245     if (!tm) {
  246         ND_PRINT("[Error converting time]");
  247         return;
  248     }
  249     if (date_flag == WITH_DATE)
  250         strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", tm);
  251     else
  252         strftime(timestr, sizeof(timestr), "%H:%M:%S", tm);
  253     ND_PRINT("%s", timestr);
  254 
  255     ts_frac_print(ndo, usec);
  256 }
  257 
  258 /*
  259  * Print the timestamp - Unix timeval style, as SECS.FRAC.
  260  */
  261 static void
  262 ts_unix_print(netdissect_options *ndo, long sec, long usec)
  263 {
  264     if ((unsigned)sec & 0x80000000) {
  265         ND_PRINT("[Error converting time]");
  266         return;
  267     }
  268 
  269     ND_PRINT("%u", (unsigned)sec);
  270     ts_frac_print(ndo, usec);
  271 }
  272 
  273 /*
  274  * Print the timestamp
  275  */
  276 void
  277 ts_print(netdissect_options *ndo,
  278          const struct timeval *tvp)
  279 {
  280     static struct timeval tv_ref;
  281     struct timeval tv_result;
  282     int negative_offset;
  283     int nano_prec;
  284 
  285     switch (ndo->ndo_tflag) {
  286 
  287     case 0: /* Default */
  288         ts_date_hmsfrac_print(ndo, tvp->tv_sec, tvp->tv_usec,
  289                       WITHOUT_DATE, LOCAL_TIME);
  290         ND_PRINT(" ");
  291         break;
  292 
  293     case 1: /* No time stamp */
  294         break;
  295 
  296     case 2: /* Unix timeval style */
  297         ts_unix_print(ndo, tvp->tv_sec, tvp->tv_usec);
  298         ND_PRINT(" ");
  299         break;
  300 
  301     case 3: /* Microseconds/nanoseconds since previous packet */
  302         case 5: /* Microseconds/nanoseconds since first packet */
  303 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
  304         switch (ndo->ndo_tstamp_precision) {
  305         case PCAP_TSTAMP_PRECISION_MICRO:
  306             nano_prec = 0;
  307             break;
  308         case PCAP_TSTAMP_PRECISION_NANO:
  309             nano_prec = 1;
  310             break;
  311         default:
  312             nano_prec = 0;
  313             break;
  314         }
  315 #else
  316         nano_prec = 0;
  317 #endif
  318         if (!(netdissect_timevalisset(&tv_ref)))
  319             tv_ref = *tvp; /* set timestamp for first packet */
  320 
  321         negative_offset = netdissect_timevalcmp(tvp, &tv_ref, <);
  322         if (negative_offset)
  323             netdissect_timevalsub(&tv_ref, tvp, &tv_result, nano_prec);
  324         else
  325             netdissect_timevalsub(tvp, &tv_ref, &tv_result, nano_prec);
  326 
  327         ND_PRINT((negative_offset ? "-" : " "));
  328         ts_date_hmsfrac_print(ndo, tv_result.tv_sec, tv_result.tv_usec,
  329                       WITHOUT_DATE, UTC_TIME);
  330         ND_PRINT(" ");
  331 
  332                 if (ndo->ndo_tflag == 3)
  333             tv_ref = *tvp; /* set timestamp for previous packet */
  334         break;
  335 
  336     case 4: /* Date + Default */
  337         ts_date_hmsfrac_print(ndo, tvp->tv_sec, tvp->tv_usec,
  338                       WITH_DATE, LOCAL_TIME);
  339         ND_PRINT(" ");
  340         break;
  341     }
  342 }
  343 
  344 /*
  345  * Print an unsigned relative number of seconds (e.g. hold time, prune timer)
  346  * in the form 5m1s.  This does no truncation, so 32230861 seconds
  347  * is represented as 1y1w1d1h1m1s.
  348  */
  349 void
  350 unsigned_relts_print(netdissect_options *ndo,
  351                      uint32_t secs)
  352 {
  353     static const char *lengths[] = {"y", "w", "d", "h", "m", "s"};
  354     static const u_int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
  355     const char **l = lengths;
  356     const u_int *s = seconds;
  357 
  358     if (secs == 0) {
  359         ND_PRINT("0s");
  360         return;
  361     }
  362     while (secs > 0) {
  363         if (secs >= *s) {
  364             ND_PRINT("%u%s", secs / *s, *l);
  365             secs -= (secs / *s) * *s;
  366         }
  367         s++;
  368         l++;
  369     }
  370 }
  371 
  372 /*
  373  * Print a signed relative number of seconds (e.g. hold time, prune timer)
  374  * in the form 5m1s.  This does no truncation, so 32230861 seconds
  375  * is represented as 1y1w1d1h1m1s.
  376  */
  377 void
  378 signed_relts_print(netdissect_options *ndo,
  379                    int32_t secs)
  380 {
  381     if (secs < 0) {
  382         ND_PRINT("-");
  383         if (secs == INT32_MIN) {
  384             /*
  385              * -2^31; you can't fit its absolute value into
  386              * a 32-bit signed integer.
  387              *
  388              * Just directly pass said absolute value to
  389              * unsigned_relts_print() directly.
  390              *
  391              * (XXX - does ISO C guarantee that -(-2^n),
  392              * when calculated and cast to an n-bit unsigned
  393              * integer type, will have the value 2^n?)
  394              */
  395             unsigned_relts_print(ndo, 2147483648U);
  396         } else {
  397             /*
  398              * We now know -secs will fit into an int32_t;
  399              * negate it and pass that to unsigned_relts_print().
  400              */
  401             unsigned_relts_print(ndo, -secs);
  402         }
  403         return;
  404     }
  405     unsigned_relts_print(ndo, secs);
  406 }
  407 
  408 /* Print the truncated string */
  409 void nd_print_trunc(netdissect_options *ndo)
  410 {
  411     ND_PRINT(" [|%s]", ndo->ndo_protocol);
  412 }
  413 
  414 /* Print the protocol name */
  415 void nd_print_protocol(netdissect_options *ndo)
  416 {
  417     ND_PRINT("%s", ndo->ndo_protocol);
  418 }
  419 
  420 /* Print the protocol name in caps (uppercases) */
  421 void nd_print_protocol_caps(netdissect_options *ndo)
  422 {
  423     const char *p;
  424         for (p = ndo->ndo_protocol; *p != '\0'; p++)
  425                 ND_PRINT("%c", ND_ASCII_TOUPPER(*p));
  426 }
  427 
  428 /* Print the invalid string */
  429 void nd_print_invalid(netdissect_options *ndo)
  430 {
  431     ND_PRINT(" (invalid)");
  432 }
  433 
  434 /*
  435  *  this is a generic routine for printing unknown data;
  436  *  we pass on the linefeed plus indentation string to
  437  *  get a proper output - returns 0 on error
  438  */
  439 
  440 int
  441 print_unknown_data(netdissect_options *ndo, const u_char *cp,
  442                    const char *ident, u_int len)
  443 {
  444     u_int len_to_print;
  445 
  446     len_to_print = len;
  447     if (!ND_TTEST_LEN(cp, 0)) {
  448         ND_PRINT("%sDissector error: print_unknown_data called with pointer past end of packet",
  449             ident);
  450         return(0);
  451     }
  452     if (ND_BYTES_AVAILABLE_AFTER(cp) < len_to_print)
  453         len_to_print = ND_BYTES_AVAILABLE_AFTER(cp);
  454     hex_print(ndo, ident, cp, len_to_print);
  455     return(1); /* everything is ok */
  456 }
  457 
  458 /*
  459  * Convert a token value to a string; use "fmt" if not found.
  460  */
  461 const char *
  462 tok2strbuf(const struct tok *lp, const char *fmt,
  463        u_int v, char *buf, size_t bufsize)
  464 {
  465     if (lp != NULL) {
  466         while (lp->s != NULL) {
  467             if (lp->v == v)
  468                 return (lp->s);
  469             ++lp;
  470         }
  471     }
  472     if (fmt == NULL)
  473         fmt = "#%d";
  474 
  475     (void)snprintf(buf, bufsize, fmt, v);
  476     return (const char *)buf;
  477 }
  478 
  479 /*
  480  * Convert a token value to a string; use "fmt" if not found.
  481  * Uses tok2strbuf() on one of four local static buffers of size TOKBUFSIZE
  482  * in round-robin fashion.
  483  */
  484 const char *
  485 tok2str(const struct tok *lp, const char *fmt,
  486     u_int v)
  487 {
  488     static char buf[4][TOKBUFSIZE];
  489     static int idx = 0;
  490     char *ret;
  491 
  492     ret = buf[idx];
  493     idx = (idx+1) & 3;
  494     return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0]));
  495 }
  496 
  497 /*
  498  * Convert a bit token value to a string; use "fmt" if not found.
  499  * this is useful for parsing bitfields, the output strings are separated
  500  * if the s field is positive.
  501  *
  502  * A token matches iff it has one or more bits set and every bit that is set
  503  * in the token is set in v. Consequently, a 0 token never matches.
  504  */
  505 static char *
  506 bittok2str_internal(const struct tok *lp, const char *fmt,
  507        u_int v, const char *sep)
  508 {
  509         static char buf[1024+1]; /* our string buffer */
  510         char *bufp = buf;
  511         size_t space_left = sizeof(buf), string_size;
  512         const char * sepstr = "";
  513 
  514         while (lp != NULL && lp->s != NULL) {
  515             if (lp->v && (v & lp->v) == lp->v) {
  516                 /* ok we have found something */
  517                 if (space_left <= 1)
  518                     return (buf); /* only enough room left for NUL, if that */
  519                 string_size = strlcpy(bufp, sepstr, space_left);
  520                 if (string_size >= space_left)
  521                     return (buf);    /* we ran out of room */
  522                 bufp += string_size;
  523                 space_left -= string_size;
  524                 if (space_left <= 1)
  525                     return (buf); /* only enough room left for NUL, if that */
  526                 string_size = strlcpy(bufp, lp->s, space_left);
  527                 if (string_size >= space_left)
  528                     return (buf);    /* we ran out of room */
  529                 bufp += string_size;
  530                 space_left -= string_size;
  531                 sepstr = sep;
  532             }
  533             lp++;
  534         }
  535 
  536         if (bufp == buf)
  537             /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
  538             (void)snprintf(buf, sizeof(buf), fmt == NULL ? "#%08x" : fmt, v);
  539         return (buf);
  540 }
  541 
  542 /*
  543  * Convert a bit token value to a string; use "fmt" if not found.
  544  * this is useful for parsing bitfields, the output strings are not separated.
  545  */
  546 char *
  547 bittok2str_nosep(const struct tok *lp, const char *fmt,
  548        u_int v)
  549 {
  550     return (bittok2str_internal(lp, fmt, v, ""));
  551 }
  552 
  553 /*
  554  * Convert a bit token value to a string; use "fmt" if not found.
  555  * this is useful for parsing bitfields, the output strings are comma separated.
  556  */
  557 char *
  558 bittok2str(const struct tok *lp, const char *fmt,
  559        u_int v)
  560 {
  561     return (bittok2str_internal(lp, fmt, v, ", "));
  562 }
  563 
  564 /*
  565  * Convert a value to a string using an array; the macro
  566  * tok2strary() in <netdissect.h> is the public interface to
  567  * this function and ensures that the second argument is
  568  * correct for bounds-checking.
  569  */
  570 const char *
  571 tok2strary_internal(const char **lp, int n, const char *fmt,
  572     int v)
  573 {
  574     static char buf[TOKBUFSIZE];
  575 
  576     if (v >= 0 && v < n && lp[v] != NULL)
  577         return lp[v];
  578     if (fmt == NULL)
  579         fmt = "#%d";
  580     (void)snprintf(buf, sizeof(buf), fmt, v);
  581     return (buf);
  582 }
  583 
  584 const struct tok *
  585 uint2tokary_internal(const struct uint_tokary dict[], const size_t size,
  586                      const u_int val)
  587 {
  588     size_t i;
  589     /* Try a direct lookup before the full scan. */
  590     if (val < size && dict[val].uintval == val)
  591         return dict[val].tokary; /* OK if NULL */
  592     for (i = 0; i < size; i++)
  593         if (dict[i].uintval == val)
  594             return dict[i].tokary; /* OK if NULL */
  595     return NULL;
  596 }
  597 
  598 /*
  599  * Convert a 32-bit netmask to prefixlen if possible
  600  * the function returns the prefix-len; if plen == -1
  601  * then conversion was not possible;
  602  */
  603 
  604 int
  605 mask2plen(uint32_t mask)
  606 {
  607     uint32_t bitmasks[33] = {
  608         0x00000000,
  609         0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
  610         0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
  611         0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
  612         0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
  613         0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
  614         0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
  615         0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
  616         0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
  617     };
  618     int prefix_len = 32;
  619 
  620     /* let's see if we can transform the mask into a prefixlen */
  621     while (prefix_len >= 0) {
  622         if (bitmasks[prefix_len] == mask)
  623             break;
  624         prefix_len--;
  625     }
  626     return (prefix_len);
  627 }
  628 
  629 int
  630 mask62plen(const u_char *mask)
  631 {
  632     u_char bitmasks[9] = {
  633         0x00,
  634         0x80, 0xc0, 0xe0, 0xf0,
  635         0xf8, 0xfc, 0xfe, 0xff
  636     };
  637     int byte;
  638     int cidr_len = 0;
  639 
  640     for (byte = 0; byte < 16; byte++) {
  641         u_int bits;
  642 
  643         for (bits = 0; bits < (sizeof (bitmasks) / sizeof (bitmasks[0])); bits++) {
  644             if (mask[byte] == bitmasks[bits]) {
  645                 cidr_len += bits;
  646                 break;
  647             }
  648         }
  649 
  650         if (mask[byte] != 0xff)
  651             break;
  652     }
  653     return (cidr_len);
  654 }
  655 
  656 /*
  657  * Routine to print out information for text-based protocols such as FTP,
  658  * HTTP, SMTP, RTSP, SIP, ....
  659  */
  660 #define MAX_TOKEN   128
  661 
  662 /*
  663  * Fetch a token from a packet, starting at the specified index,
  664  * and return the length of the token.
  665  *
  666  * Returns 0 on error; yes, this is indistinguishable from an empty
  667  * token, but an "empty token" isn't a valid token - it just means
  668  * either a space character at the beginning of the line (this
  669  * includes a blank line) or no more tokens remaining on the line.
  670  */
  671 static int
  672 fetch_token(netdissect_options *ndo, const u_char *pptr, u_int idx, u_int len,
  673     u_char *tbuf, size_t tbuflen)
  674 {
  675     size_t toklen = 0;
  676     u_char c;
  677 
  678     for (; idx < len; idx++) {
  679         if (!ND_TTEST_1(pptr + idx)) {
  680             /* ran past end of captured data */
  681             return (0);
  682         }
  683         c = GET_U_1(pptr + idx);
  684         if (!ND_ISASCII(c)) {
  685             /* not an ASCII character */
  686             return (0);
  687         }
  688         if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
  689             /* end of token */
  690             break;
  691         }
  692         if (!ND_ASCII_ISPRINT(c)) {
  693             /* not part of a command token or response code */
  694             return (0);
  695         }
  696         if (toklen + 2 > tbuflen) {
  697             /* no room for this character and terminating '\0' */
  698             return (0);
  699         }
  700         tbuf[toklen] = c;
  701         toklen++;
  702     }
  703     if (toklen == 0) {
  704         /* no token */
  705         return (0);
  706     }
  707     tbuf[toklen] = '\0';
  708 
  709     /*
  710      * Skip past any white space after the token, until we see
  711      * an end-of-line (CR or LF).
  712      */
  713     for (; idx < len; idx++) {
  714         if (!ND_TTEST_1(pptr + idx)) {
  715             /* ran past end of captured data */
  716             break;
  717         }
  718         c = GET_U_1(pptr + idx);
  719         if (c == '\r' || c == '\n') {
  720             /* end of line */
  721             break;
  722         }
  723         if (!ND_ASCII_ISPRINT(c)) {
  724             /* not a printable ASCII character */
  725             break;
  726         }
  727         if (c != ' ' && c != '\t' && c != '\r' && c != '\n') {
  728             /* beginning of next token */
  729             break;
  730         }
  731     }
  732     return (idx);
  733 }
  734 
  735 /*
  736  * Scan a buffer looking for a line ending - LF or CR-LF.
  737  * Return the index of the character after the line ending or 0 if
  738  * we encounter a non-ASCII or non-printable character or don't find
  739  * the line ending.
  740  */
  741 static u_int
  742 print_txt_line(netdissect_options *ndo, const char *prefix,
  743            const u_char *pptr, u_int idx, u_int len)
  744 {
  745     u_int startidx;
  746     u_int linelen;
  747     u_char c;
  748 
  749     startidx = idx;
  750     while (idx < len) {
  751         c = GET_U_1(pptr + idx);
  752         if (c == '\n') {
  753             /*
  754              * LF without CR; end of line.
  755              * Skip the LF and print the line, with the
  756              * exception of the LF.
  757              */
  758             linelen = idx - startidx;
  759             idx++;
  760             goto print;
  761         } else if (c == '\r') {
  762             /* CR - any LF? */
  763             if ((idx+1) >= len) {
  764                 /* not in this packet */
  765                 return (0);
  766             }
  767             if (GET_U_1(pptr + idx + 1) == '\n') {
  768                 /*
  769                  * CR-LF; end of line.
  770                  * Skip the CR-LF and print the line, with
  771                  * the exception of the CR-LF.
  772                  */
  773                 linelen = idx - startidx;
  774                 idx += 2;
  775                 goto print;
  776             }
  777 
  778             /*
  779              * CR followed by something else; treat this
  780              * as if it were binary data, and don't print
  781              * it.
  782              */
  783             return (0);
  784         } else if (!ND_ASCII_ISPRINT(c) && c != '\t') {
  785             /*
  786              * Not a printable ASCII character and not a tab;
  787              * treat this as if it were binary data, and
  788              * don't print it.
  789              */
  790             return (0);
  791         }
  792         idx++;
  793     }
  794 
  795     /*
  796      * All printable ASCII, but no line ending after that point
  797      * in the buffer; treat this as if it were truncated.
  798      */
  799     linelen = idx - startidx;
  800     ND_PRINT("%s%.*s", prefix, (int)linelen, pptr + startidx);
  801     nd_print_trunc(ndo);
  802     return (0);
  803 
  804 print:
  805     ND_PRINT("%s%.*s", prefix, (int)linelen, pptr + startidx);
  806     return (idx);
  807 }
  808 
  809 /* Assign needed before calling txtproto_print(): ndo->ndo_protocol = "proto" */
  810 void
  811 txtproto_print(netdissect_options *ndo, const u_char *pptr, u_int len,
  812            const char **cmds, u_int flags)
  813 {
  814     u_int idx, eol;
  815     u_char token[MAX_TOKEN+1];
  816     const char *cmd;
  817     int print_this = 0;
  818 
  819     if (cmds != NULL) {
  820         /*
  821          * This protocol has more than just request and
  822          * response lines; see whether this looks like a
  823          * request or response and, if so, print it and,
  824          * in verbose mode, print everything after it.
  825          *
  826          * This is for HTTP-like protocols, where we
  827          * want to print requests and responses, but
  828          * don't want to print continuations of request
  829          * or response bodies in packets that don't
  830          * contain the request or response line.
  831          */
  832         idx = fetch_token(ndo, pptr, 0, len, token, sizeof(token));
  833         if (idx != 0) {
  834             /* Is this a valid request name? */
  835             while ((cmd = *cmds++) != NULL) {
  836                 if (ascii_strcasecmp((const char *)token, cmd) == 0) {
  837                     /* Yes. */
  838                     print_this = 1;
  839                     break;
  840                 }
  841             }
  842 
  843             /*
  844              * No - is this a valid response code (3 digits)?
  845              *
  846              * Is this token the response code, or is the next
  847              * token the response code?
  848              */
  849             if (flags & RESP_CODE_SECOND_TOKEN) {
  850                 /*
  851                  * Next token - get it.
  852                  */
  853                 idx = fetch_token(ndo, pptr, idx, len, token,
  854                     sizeof(token));
  855             }
  856             if (idx != 0) {
  857                 if (ND_ASCII_ISDIGIT(token[0]) && ND_ASCII_ISDIGIT(token[1]) &&
  858                     ND_ASCII_ISDIGIT(token[2]) && token[3] == '\0') {
  859                     /* Yes. */
  860                     print_this = 1;
  861                 }
  862             }
  863         }
  864     } else {
  865         /*
  866          * Either:
  867          *
  868          * 1) This protocol has only request and response lines
  869          *    (e.g., FTP, where all the data goes over a different
  870          *    connection); assume the payload is a request or
  871          *    response.
  872          *
  873          * or
  874          *
  875          * 2) This protocol is just text, so that we should
  876          *    always, at minimum, print the first line and,
  877          *    in verbose mode, print all lines.
  878          */
  879         print_this = 1;
  880     }
  881 
  882     nd_print_protocol_caps(ndo);
  883 
  884     if (print_this) {
  885         /*
  886          * In non-verbose mode, just print the protocol, followed
  887          * by the first line.
  888          *
  889          * In verbose mode, print lines as text until we run out
  890          * of characters or see something that's not a
  891          * printable-ASCII line.
  892          */
  893         if (ndo->ndo_vflag) {
  894             /*
  895              * We're going to print all the text lines in the
  896              * request or response; just print the length
  897              * on the first line of the output.
  898              */
  899             ND_PRINT(", length: %u", len);
  900             for (idx = 0;
  901                 idx < len && (eol = print_txt_line(ndo, "\n\t", pptr, idx, len)) != 0;
  902                 idx = eol)
  903                 ;
  904         } else {
  905             /*
  906              * Just print the first text line.
  907              */
  908             print_txt_line(ndo, ": ", pptr, 0, len);
  909         }
  910     }
  911 }
  912 
  913 #if (defined(__i386__) || defined(_M_IX86) || defined(__X86__) || defined(__x86_64__) || defined(_M_X64)) || \
  914     (defined(__arm__) || defined(_M_ARM) || defined(__aarch64__)) || \
  915     (defined(__m68k__) && (!defined(__mc68000__) && !defined(__mc68010__))) || \
  916     (defined(__ppc__) || defined(__ppc64__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PPC64)) || \
  917     (defined(__s390__) || defined(__s390x__) || defined(__zarch__)) || \
  918     defined(__vax__)
  919 /*
  920  * The procesor natively handles unaligned loads, so just use memcpy()
  921  * and memcmp(), to enable those optimizations.
  922  *
  923  * XXX - are those all the x86 tests we need?
  924  * XXX - do we need to worry about ARMv1 through ARMv5, which didn't
  925  * support unaligned loads, and, if so, do we need to worry about all
  926  * of them, or just some of them, e.g. ARMv5?
  927  * XXX - are those the only 68k tests we need not to generated
  928  * unaligned accesses if the target is the 68000 or 68010?
  929  * XXX - are there any tests we don't need, because some definitions are for
  930  * compilers that also predefine the GCC symbols?
  931  * XXX - do we need to test for both 32-bit and 64-bit versions of those
  932  * architectures in all cases?
  933  */
  934 #else
  935 /*
  936  * The processor doesn't natively handle unaligned loads,
  937  * and the compiler might "helpfully" optimize memcpy()
  938  * and memcmp(), when handed pointers that would normally
  939  * be properly aligned, into sequences that assume proper
  940  * alignment.
  941  *
  942  * Do copies and compares of possibly-unaligned data by
  943  * calling routines that wrap memcpy() and memcmp(), to
  944  * prevent that optimization.
  945  */
  946 void
  947 unaligned_memcpy(void *p, const void *q, size_t l)
  948 {
  949     memcpy(p, q, l);
  950 }
  951 
  952 /* As with memcpy(), so with memcmp(). */
  953 int
  954 unaligned_memcmp(const void *p, const void *q, size_t l)
  955 {
  956     return (memcmp(p, q, l));
  957 }
  958 #endif
  959