Home | History | Annotate | Line # | Download | only in dist
      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 (at) 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 #include <sys/cdefs.h>
     39 #ifndef lint
     40 __RCSID("$NetBSD: util-print.c,v 1.9 2026/03/19 00:05:13 christos Exp $");
     41 #endif
     42 
     43 #include <config.h>
     44 
     45 #include "netdissect-stdinc.h"
     46 
     47 #include <sys/stat.h>
     48 
     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 counted 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,
    178  * whichever is first.
    179  * The suffix comes from: j:longJmp, n:after N bytes.
    180  */
    181 void
    182 nd_printjn(netdissect_options *ndo, const u_char *s, u_int n)
    183 {
    184 	while (n > 0) {
    185 		fn_print_char(ndo, GET_U_1(s));
    186 		n--;
    187 		s++;
    188 	}
    189 }
    190 
    191 /*
    192  * Print a null-padded filename (or other ASCII string), part of
    193  * the packet buffer, filtering out non-printable characters.
    194  * Stop if truncated (via GET_U_1/longjmp) or after n bytes or before
    195  * the null char, whichever occurs first.
    196  * The suffix comes from: j:longJmp, n:after N bytes, p:null-Padded.
    197  */
    198 void
    199 nd_printjnp(netdissect_options *ndo, const u_char *s, u_int n)
    200 {
    201 	u_char c;
    202 
    203 	while (n > 0) {
    204 		c = GET_U_1(s);
    205 		if (c == '\0')
    206 			break;
    207 		fn_print_char(ndo, c);
    208 		n--;
    209 		s++;
    210 	}
    211 }
    212 
    213 /*
    214  * Print the timestamp .FRAC part (Microseconds/nanoseconds)
    215  */
    216 static void
    217 ts_frac_print(netdissect_options *ndo, const struct timeval *tv)
    218 {
    219 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
    220 	switch (ndo->ndo_tstamp_precision) {
    221 
    222 	case PCAP_TSTAMP_PRECISION_MICRO:
    223 		ND_PRINT(".%06u", (unsigned)tv->tv_usec);
    224 		if ((unsigned)tv->tv_usec > ND_MICRO_PER_SEC - 1)
    225 			ND_PRINT(" " ND_INVALID_MICRO_SEC_STR);
    226 		break;
    227 
    228 	case PCAP_TSTAMP_PRECISION_NANO:
    229 		ND_PRINT(".%09u", (unsigned)tv->tv_usec);
    230 		if ((unsigned)tv->tv_usec > ND_NANO_PER_SEC - 1)
    231 			ND_PRINT(" " ND_INVALID_NANO_SEC_STR);
    232 		break;
    233 
    234 	default:
    235 		ND_PRINT(".{unknown}");
    236 		break;
    237 	}
    238 #else
    239 	ND_PRINT(".%06u", (unsigned)tv->tv_usec);
    240 	if ((unsigned)tv->tv_usec > ND_MICRO_PER_SEC - 1)
    241 		ND_PRINT(" " ND_INVALID_MICRO_SEC_STR);
    242 #endif
    243 }
    244 
    245 /*
    246  * Print the timestamp as [YY:MM:DD] HH:MM:SS.FRAC.
    247  *   if time_flag == LOCAL_TIME print local time else UTC/GMT time
    248  *   if date_flag == WITH_DATE print YY:MM:DD before HH:MM:SS.FRAC
    249  */
    250 static void
    251 ts_date_hmsfrac_print(netdissect_options *ndo, const struct timeval *tv,
    252 		      enum date_flag date_flag, enum time_flag time_flag)
    253 {
    254 	struct tm *tm;
    255 	char timebuf[32];
    256 	const char *timestr;
    257 #ifdef _WIN32
    258 	time_t sec;
    259 #endif
    260 
    261 	if (tv->tv_sec < 0) {
    262 		ND_PRINT("[timestamp overflow]");
    263 		return;
    264 	}
    265 
    266 #ifdef _WIN32
    267 	/* on Windows tv->tv_sec is a long not a 64-bit time_t. */
    268 	sec = tv->tv_sec;
    269 #endif
    270 
    271 	if (time_flag == LOCAL_TIME)
    272 #ifdef _WIN32
    273 		tm = localtime(&sec);
    274 #else
    275 		tm = localtime(&tv->tv_sec);
    276 #endif
    277 	else
    278 #ifdef _WIN32
    279 		tm = gmtime(&sec);
    280 #else
    281 		tm = gmtime(&tv->tv_sec);
    282 #endif
    283 
    284 	if (date_flag == WITH_DATE) {
    285 		timestr = nd_format_time(timebuf, sizeof(timebuf),
    286 		    "%Y-%m-%d %H:%M:%S", tm);
    287 	} else {
    288 		timestr = nd_format_time(timebuf, sizeof(timebuf),
    289 		    "%H:%M:%S", tm);
    290 	}
    291 	ND_PRINT("%s", timestr);
    292 
    293 	ts_frac_print(ndo, tv);
    294 }
    295 
    296 /*
    297  * Print the timestamp - Unix timeval style, as SECS.FRAC.
    298  */
    299 static void
    300 ts_unix_print(netdissect_options *ndo, const struct timeval *tv)
    301 {
    302 	if (tv->tv_sec < 0) {
    303 		ND_PRINT("[timestamp overflow]");
    304 		return;
    305 	}
    306 
    307 	ND_PRINT("%" PRId64, (int64_t)tv->tv_sec);
    308 	ts_frac_print(ndo, tv);
    309 }
    310 
    311 /*
    312  * Print the timestamp
    313  */
    314 void
    315 ts_print(netdissect_options *ndo,
    316          const struct timeval *tvp)
    317 {
    318 	static struct timeval tv_ref;
    319 	struct timeval tv_result;
    320 	int negative_offset;
    321 	int nano_prec;
    322 
    323 	switch (ndo->ndo_tflag) {
    324 
    325 	case 0: /* Default */
    326 		ts_date_hmsfrac_print(ndo, tvp, WITHOUT_DATE, LOCAL_TIME);
    327 		ND_PRINT(" ");
    328 		break;
    329 
    330 	case 1: /* No time stamp */
    331 		break;
    332 
    333 	case 2: /* Unix timeval style */
    334 		ts_unix_print(ndo, tvp);
    335 		ND_PRINT(" ");
    336 		break;
    337 
    338 	case 3: /* Microseconds/nanoseconds since previous packet */
    339         case 5: /* Microseconds/nanoseconds since first packet */
    340 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
    341 		switch (ndo->ndo_tstamp_precision) {
    342 		case PCAP_TSTAMP_PRECISION_MICRO:
    343 			nano_prec = 0;
    344 			break;
    345 		case PCAP_TSTAMP_PRECISION_NANO:
    346 			nano_prec = 1;
    347 			break;
    348 		default:
    349 			nano_prec = 0;
    350 			break;
    351 		}
    352 #else
    353 		nano_prec = 0;
    354 #endif
    355 		if (!(netdissect_timevalisset(&tv_ref)))
    356 			tv_ref = *tvp; /* set timestamp for first packet */
    357 
    358 		negative_offset = netdissect_timevalcmp(tvp, &tv_ref, <);
    359 		if (negative_offset)
    360 			netdissect_timevalsub(&tv_ref, tvp, &tv_result, nano_prec);
    361 		else
    362 			netdissect_timevalsub(tvp, &tv_ref, &tv_result, nano_prec);
    363 
    364 		ND_PRINT((negative_offset ? "-" : " "));
    365 		ts_date_hmsfrac_print(ndo, &tv_result, WITHOUT_DATE, UTC_TIME);
    366 		ND_PRINT(" ");
    367 
    368                 if (ndo->ndo_tflag == 3)
    369 			tv_ref = *tvp; /* set timestamp for previous packet */
    370 		break;
    371 
    372 	case 4: /* Date + Default */
    373 		ts_date_hmsfrac_print(ndo, tvp, WITH_DATE, LOCAL_TIME);
    374 		ND_PRINT(" ");
    375 		break;
    376 	}
    377 }
    378 
    379 /*
    380  * Print an unsigned relative number of seconds (e.g. hold time, prune timer)
    381  * in the form 5m1s.  This does no truncation, so 32230861 seconds
    382  * is represented as 1y1w1d1h1m1s.
    383  */
    384 void
    385 unsigned_relts_print(netdissect_options *ndo,
    386                      uint32_t secs)
    387 {
    388 	static const char *lengths[] = {"y", "w", "d", "h", "m", "s"};
    389 	static const u_int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
    390 	const char **l = lengths;
    391 	const u_int *s = seconds;
    392 
    393 	if (secs == 0) {
    394 		ND_PRINT("0s");
    395 		return;
    396 	}
    397 	while (secs > 0) {
    398 		if (secs >= *s) {
    399 			ND_PRINT("%u%s", secs / *s, *l);
    400 			secs -= (secs / *s) * *s;
    401 		}
    402 		s++;
    403 		l++;
    404 	}
    405 }
    406 
    407 /*
    408  * Print a signed relative number of seconds (e.g. hold time, prune timer)
    409  * in the form 5m1s.  This does no truncation, so 32230861 seconds
    410  * is represented as 1y1w1d1h1m1s.
    411  */
    412 void
    413 signed_relts_print(netdissect_options *ndo,
    414                    int32_t secs)
    415 {
    416 	if (secs < 0) {
    417 		ND_PRINT("-");
    418 		if (secs == INT32_MIN) {
    419 			/*
    420 			 * -2^31; you can't fit its absolute value into
    421 			 * a 32-bit signed integer.
    422 			 *
    423 			 * Just directly pass said absolute value to
    424 			 * unsigned_relts_print() directly.
    425 			 *
    426 			 * (XXX - does ISO C guarantee that -(-2^n),
    427 			 * when calculated and cast to an n-bit unsigned
    428 			 * integer type, will have the value 2^n?)
    429 			 */
    430 			unsigned_relts_print(ndo, 2147483648U);
    431 		} else {
    432 			/*
    433 			 * We now know -secs will fit into an int32_t;
    434 			 * negate it and pass that to unsigned_relts_print().
    435 			 */
    436 			unsigned_relts_print(ndo, -secs);
    437 		}
    438 		return;
    439 	}
    440 	unsigned_relts_print(ndo, secs);
    441 }
    442 
    443 /*
    444  * Format a struct tm with strftime().
    445  * If the pointer to the struct tm is null, that means that the
    446  * routine to convert a time_t to a struct tm failed; the localtime()
    447  * and gmtime() in the Microsoft Visual Studio C library will fail,
    448  * returning null, if the value is before the UNIX Epoch.
    449  */
    450 const char *
    451 nd_format_time(char *buf, size_t bufsize, const char *format,
    452          const struct tm *timeptr)
    453 {
    454 	if (timeptr != NULL) {
    455 		if (strftime(buf, bufsize, format, timeptr) != 0)
    456 			return (buf);
    457 		else
    458 			return ("[nd_format_time() buffer is too small]");
    459 	} else
    460 		return ("[localtime() or gmtime() couldn't convert the date and time]");
    461 }
    462 
    463 /* Print the truncated string */
    464 void nd_print_trunc(netdissect_options *ndo)
    465 {
    466 	ND_PRINT(" [|%s]", ndo->ndo_protocol);
    467 }
    468 
    469 /* Print the protocol name */
    470 void nd_print_protocol(netdissect_options *ndo)
    471 {
    472 	ND_PRINT("%s", ndo->ndo_protocol);
    473 }
    474 
    475 /* Print the protocol name in caps (uppercases) */
    476 void nd_print_protocol_caps(netdissect_options *ndo)
    477 {
    478 	const char *p;
    479         for (p = ndo->ndo_protocol; *p != '\0'; p++)
    480                 ND_PRINT("%c", ND_ASCII_TOUPPER(*p));
    481 }
    482 
    483 /* Print the invalid string */
    484 void nd_print_invalid(netdissect_options *ndo)
    485 {
    486 	ND_PRINT(" (invalid)");
    487 }
    488 
    489 /*
    490  *  this is a generic routine for printing unknown data;
    491  *  we pass on the linefeed plus indentation string to
    492  *  get a proper output - returns 0 on error
    493  */
    494 
    495 int
    496 print_unknown_data(netdissect_options *ndo, const u_char *cp,
    497                    const char *indent, u_int len)
    498 {
    499 	if (!ND_TTEST_LEN(cp, 0)) {
    500 		ND_PRINT("%sDissector error: %s() called with pointer past end of packet",
    501 		    indent, __func__);
    502 		return(0);
    503 	}
    504 	hex_print(ndo, indent, cp, ND_MIN(len, ND_BYTES_AVAILABLE_AFTER(cp)));
    505 	return(1); /* everything is ok */
    506 }
    507 
    508 /*
    509  * Convert a token value to a string; use "fmt" if not found.
    510  */
    511 static const char *
    512 tok2strbuf(const struct tok *lp, const char *fmt,
    513 	   const u_int v, char *buf, const size_t bufsize)
    514 {
    515 	if (lp != NULL) {
    516 		while (lp->s != NULL) {
    517 			if (lp->v == v)
    518 				return (lp->s);
    519 			++lp;
    520 		}
    521 	}
    522 	if (fmt == NULL)
    523 		fmt = "#%d";
    524 
    525 	(void)snprintf(buf, bufsize, fmt, v);
    526 	return (const char *)buf;
    527 }
    528 
    529 /*
    530  * Convert a token value to a string; use "fmt" if not found.
    531  * Uses tok2strbuf() on one of four local static buffers of size TOKBUFSIZE
    532  * in round-robin fashion.
    533  */
    534 const char *
    535 tok2str(const struct tok *lp, const char *fmt, const u_int v)
    536 {
    537 	static char buf[4][TOKBUFSIZE];
    538 	static int idx = 0;
    539 	char *ret;
    540 
    541 	ret = buf[idx];
    542 	idx = (idx+1) & 3;
    543 	return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0]));
    544 }
    545 
    546 /*
    547  * Convert a bit token value to a string; use "fmt" if not found.
    548  * this is useful for parsing bitfields, the output strings are separated
    549  * if the s field is positive.
    550  *
    551  * A token matches iff it has one or more bits set and every bit that is set
    552  * in the token is set in v. Consequently, a 0 token never matches.
    553  */
    554 static char *
    555 bittok2str_internal(const struct tok *lp, const char *fmt,
    556 		    const u_int v, const char *sep)
    557 {
    558         static char buf[1024+1]; /* our string buffer */
    559         char *bufp = buf;
    560         size_t space_left = sizeof(buf), string_size;
    561         const char * sepstr = "";
    562 
    563         while (lp != NULL && lp->s != NULL) {
    564             if (lp->v && (v & lp->v) == lp->v) {
    565                 /* ok we have found something */
    566                 if (space_left <= 1)
    567                     return (buf); /* only enough room left for NUL, if that */
    568                 string_size = strlcpy(bufp, sepstr, space_left);
    569                 if (string_size >= space_left)
    570                     return (buf);    /* we ran out of room */
    571                 bufp += string_size;
    572                 space_left -= string_size;
    573                 if (space_left <= 1)
    574                     return (buf); /* only enough room left for NUL, if that */
    575                 string_size = strlcpy(bufp, lp->s, space_left);
    576                 if (string_size >= space_left)
    577                     return (buf);    /* we ran out of room */
    578                 bufp += string_size;
    579                 space_left -= string_size;
    580                 sepstr = sep;
    581             }
    582             lp++;
    583         }
    584 
    585         if (bufp == buf)
    586             /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
    587             (void)snprintf(buf, sizeof(buf), fmt == NULL ? "#%08x" : fmt, v);
    588         return (buf);
    589 }
    590 
    591 /*
    592  * Convert a bit token value to a string; use "fmt" if not found.
    593  * this is useful for parsing bitfields, the output strings are not separated.
    594  */
    595 char *
    596 bittok2str_nosep(const struct tok *lp, const char *fmt, const u_int v)
    597 {
    598     return (bittok2str_internal(lp, fmt, v, ""));
    599 }
    600 
    601 /*
    602  * Convert a bit token value to a string; use "fmt" if not found.
    603  * this is useful for parsing bitfields, the output strings are comma separated.
    604  */
    605 char *
    606 bittok2str(const struct tok *lp, const char *fmt, const u_int v)
    607 {
    608     return (bittok2str_internal(lp, fmt, v, ", "));
    609 }
    610 
    611 /*
    612  * Convert a value to a string using an array; the macro
    613  * tok2strary() in <netdissect.h> is the public interface to
    614  * this function and ensures that the second argument is
    615  * correct for bounds-checking.
    616  */
    617 const char *
    618 tok2strary_internal(const char **lp, int n, const char *fmt, const int v)
    619 {
    620 	static char buf[TOKBUFSIZE];
    621 
    622 	if (v >= 0 && v < n && lp[v] != NULL)
    623 		return lp[v];
    624 	if (fmt == NULL)
    625 		fmt = "#%d";
    626 	(void)snprintf(buf, sizeof(buf), fmt, v);
    627 	return (buf);
    628 }
    629 
    630 const struct tok *
    631 uint2tokary_internal(const struct uint_tokary dict[], const size_t size,
    632                      const u_int val)
    633 {
    634 	size_t i;
    635 	/* Try a direct lookup before the full scan. */
    636 	if (val < size && dict[val].uintval == val)
    637 		return dict[val].tokary; /* OK if NULL */
    638 	for (i = 0; i < size; i++)
    639 		if (dict[i].uintval == val)
    640 			return dict[i].tokary; /* OK if NULL */
    641 	return NULL;
    642 }
    643 
    644 /*
    645  * Convert a 32-bit netmask to prefixlen if possible
    646  * the function returns the prefix-len; if plen == -1
    647  * then conversion was not possible;
    648  */
    649 
    650 int
    651 mask2plen(const uint32_t mask)
    652 {
    653 	const uint32_t bitmasks[33] = {
    654 		0x00000000,
    655 		0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
    656 		0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
    657 		0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
    658 		0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
    659 		0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
    660 		0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
    661 		0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
    662 		0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
    663 	};
    664 	int prefix_len = 32;
    665 
    666 	/* let's see if we can transform the mask into a prefixlen */
    667 	while (prefix_len >= 0) {
    668 		if (bitmasks[prefix_len] == mask)
    669 			break;
    670 		prefix_len--;
    671 	}
    672 	return (prefix_len);
    673 }
    674 
    675 int
    676 mask62plen(const u_char *mask)
    677 {
    678 	u_char bitmasks[9] = {
    679 		0x00,
    680 		0x80, 0xc0, 0xe0, 0xf0,
    681 		0xf8, 0xfc, 0xfe, 0xff
    682 	};
    683 	int byte;
    684 	int cidr_len = 0;
    685 
    686 	for (byte = 0; byte < 16; byte++) {
    687 		u_int bits;
    688 
    689 		for (bits = 0; bits < (sizeof (bitmasks) / sizeof (bitmasks[0])); bits++) {
    690 			if (mask[byte] == bitmasks[bits]) {
    691 				cidr_len += bits;
    692 				break;
    693 			}
    694 		}
    695 
    696 		if (mask[byte] != 0xff)
    697 			break;
    698 	}
    699 	return (cidr_len);
    700 }
    701 
    702 /*
    703  * Routine to print out information for text-based protocols such as FTP,
    704  * HTTP, SMTP, RTSP, SIP, ....
    705  */
    706 #define MAX_TOKEN	128
    707 
    708 /*
    709  * Fetch a token from a packet, starting at the specified index,
    710  * and return the length of the token.
    711  *
    712  * Returns 0 on error; yes, this is indistinguishable from an empty
    713  * token, but an "empty token" isn't a valid token - it just means
    714  * either a space character at the beginning of the line (this
    715  * includes a blank line) or no more tokens remaining on the line.
    716  */
    717 static u_int
    718 fetch_token(netdissect_options *ndo, const u_char *pptr, u_int idx, u_int len,
    719 	    u_char *tbuf, size_t tbuflen)
    720 {
    721 	size_t toklen = 0;
    722 	u_char c;
    723 
    724 	for (; idx < len; idx++) {
    725 		if (!ND_TTEST_1(pptr + idx)) {
    726 			/* ran past end of captured data */
    727 			return (0);
    728 		}
    729 		c = GET_U_1(pptr + idx);
    730 		if (!ND_ISASCII(c)) {
    731 			/* not an ASCII character */
    732 			return (0);
    733 		}
    734 		if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
    735 			/* end of token */
    736 			break;
    737 		}
    738 		if (!ND_ASCII_ISPRINT(c)) {
    739 			/* not part of a command token or response code */
    740 			return (0);
    741 		}
    742 		if (toklen + 2 > tbuflen) {
    743 			/* no room for this character and terminating '\0' */
    744 			return (0);
    745 		}
    746 		tbuf[toklen] = c;
    747 		toklen++;
    748 	}
    749 	if (toklen == 0) {
    750 		/* no token */
    751 		return (0);
    752 	}
    753 	tbuf[toklen] = '\0';
    754 
    755 	/*
    756 	 * Skip past any white space after the token, until we see
    757 	 * an end-of-line (CR or LF).
    758 	 */
    759 	for (; idx < len; idx++) {
    760 		if (!ND_TTEST_1(pptr + idx)) {
    761 			/* ran past end of captured data */
    762 			break;
    763 		}
    764 		c = GET_U_1(pptr + idx);
    765 		if (c == '\r' || c == '\n') {
    766 			/* end of line */
    767 			break;
    768 		}
    769 		if (!ND_ASCII_ISPRINT(c)) {
    770 			/* not a printable ASCII character */
    771 			break;
    772 		}
    773 		if (c != ' ' && c != '\t' && c != '\r' && c != '\n') {
    774 			/* beginning of next token */
    775 			break;
    776 		}
    777 	}
    778 	return (idx);
    779 }
    780 
    781 /*
    782  * Scan a buffer looking for a line ending - LF or CR-LF.
    783  * Return the index of the character after the line ending or 0 if
    784  * we encounter a non-ASCII or non-printable character or don't find
    785  * the line ending.
    786  */
    787 static u_int
    788 print_txt_line(netdissect_options *ndo, const char *prefix,
    789 	       const u_char *pptr, u_int idx, u_int len)
    790 {
    791 	u_int startidx;
    792 	u_int linelen;
    793 	u_char c;
    794 
    795 	startidx = idx;
    796 	while (idx < len) {
    797 		c = GET_U_1(pptr + idx);
    798 		if (c == '\n') {
    799 			/*
    800 			 * LF without CR; end of line.
    801 			 * Skip the LF and print the line, with the
    802 			 * exception of the LF.
    803 			 */
    804 			linelen = idx - startidx;
    805 			idx++;
    806 			goto print;
    807 		} else if (c == '\r') {
    808 			/* CR - any LF? */
    809 			if ((idx+1) >= len) {
    810 				/* not in this packet */
    811 				return (0);
    812 			}
    813 			if (GET_U_1(pptr + idx + 1) == '\n') {
    814 				/*
    815 				 * CR-LF; end of line.
    816 				 * Skip the CR-LF and print the line, with
    817 				 * the exception of the CR-LF.
    818 				 */
    819 				linelen = idx - startidx;
    820 				idx += 2;
    821 				goto print;
    822 			}
    823 
    824 			/*
    825 			 * CR followed by something else; treat this
    826 			 * as if it were binary data, and don't print
    827 			 * it.
    828 			 */
    829 			return (0);
    830 		} else if (!ND_ASCII_ISPRINT(c) && c != '\t') {
    831 			/*
    832 			 * Not a printable ASCII character and not a tab;
    833 			 * treat this as if it were binary data, and
    834 			 * don't print it.
    835 			 */
    836 			return (0);
    837 		}
    838 		idx++;
    839 	}
    840 
    841 	/*
    842 	 * All printable ASCII, but no line ending after that point
    843 	 * in the buffer.
    844 	 */
    845 	linelen = idx - startidx;
    846 	ND_PRINT("%s%.*s", prefix, (int)linelen, pptr + startidx);
    847 	return (0);
    848 
    849 print:
    850 	ND_PRINT("%s%.*s", prefix, (int)linelen, pptr + startidx);
    851 	return (idx);
    852 }
    853 
    854 /* Assign needed before calling txtproto_print(): ndo->ndo_protocol = "proto" */
    855 void
    856 txtproto_print(netdissect_options *ndo, const u_char *pptr, u_int len,
    857 	       const char **cmds, u_int flags)
    858 {
    859 	u_int idx, eol;
    860 	u_char token[MAX_TOKEN+1];
    861 	const char *cmd;
    862 	int print_this = 0;
    863 
    864 	if (cmds != NULL) {
    865 		/*
    866 		 * This protocol has more than just request and
    867 		 * response lines; see whether this looks like a
    868 		 * request or response and, if so, print it and,
    869 		 * in verbose mode, print everything after it.
    870 		 *
    871 		 * This is for HTTP-like protocols, where we
    872 		 * want to print requests and responses, but
    873 		 * don't want to print continuations of request
    874 		 * or response bodies in packets that don't
    875 		 * contain the request or response line.
    876 		 */
    877 		idx = fetch_token(ndo, pptr, 0, len, token, sizeof(token));
    878 		if (idx != 0) {
    879 			/* Is this a valid request name? */
    880 			while ((cmd = *cmds++) != NULL) {
    881 				if (ascii_strcasecmp((const char *)token, cmd) == 0) {
    882 					/* Yes. */
    883 					print_this = 1;
    884 					break;
    885 				}
    886 			}
    887 
    888 			/*
    889 			 * No - is this a valid response code (3 digits)?
    890 			 *
    891 			 * Is this token the response code, or is the next
    892 			 * token the response code?
    893 			 */
    894 			if (flags & RESP_CODE_SECOND_TOKEN) {
    895 				/*
    896 				 * Next token - get it.
    897 				 */
    898 				idx = fetch_token(ndo, pptr, idx, len, token,
    899 				    sizeof(token));
    900 			}
    901 			if (idx != 0) {
    902 				if (ND_ASCII_ISDIGIT(token[0]) && ND_ASCII_ISDIGIT(token[1]) &&
    903 				    ND_ASCII_ISDIGIT(token[2]) && token[3] == '\0') {
    904 					/* Yes. */
    905 					print_this = 1;
    906 				}
    907 			}
    908 		}
    909 	} else {
    910 		/*
    911 		 * Either:
    912 		 *
    913 		 * 1) This protocol has only request and response lines
    914 		 *    (e.g., FTP, where all the data goes over a different
    915 		 *    connection); assume the payload is a request or
    916 		 *    response.
    917 		 *
    918 		 * or
    919 		 *
    920 		 * 2) This protocol is just text, so that we should
    921 		 *    always, at minimum, print the first line and,
    922 		 *    in verbose mode, print all lines.
    923 		 */
    924 		print_this = 1;
    925 	}
    926 
    927 	nd_print_protocol_caps(ndo);
    928 
    929 	if (print_this) {
    930 		/*
    931 		 * In non-verbose mode, just print the protocol, followed
    932 		 * by the first line.
    933 		 *
    934 		 * In verbose mode, print lines as text until we run out
    935 		 * of characters or see something that's not a
    936 		 * printable-ASCII line.
    937 		 */
    938 		if (ndo->ndo_vflag) {
    939 			/*
    940 			 * We're going to print all the text lines in the
    941 			 * request or response; just print the length
    942 			 * on the first line of the output.
    943 			 */
    944 			ND_PRINT(", length: %u", len);
    945 			for (idx = 0;
    946 			    idx < len && (eol = print_txt_line(ndo, "\n\t", pptr, idx, len)) != 0;
    947 			    idx = eol)
    948 				;
    949 		} else {
    950 			/*
    951 			 * Just print the first text line.
    952 			 */
    953 			print_txt_line(ndo, ": ", pptr, 0, len);
    954 		}
    955 	}
    956 }
    957 
    958 #if (defined(__i386__) || defined(_M_IX86) || defined(__X86__) || defined(__x86_64__) || defined(_M_X64)) || \
    959     (defined(__arm__) || defined(_M_ARM) || defined(__aarch64__)) || \
    960     (defined(__m68k__) && (!defined(__mc68000__) && !defined(__mc68010__))) || \
    961     (defined(__ppc__) || defined(__ppc64__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PPC64)) || \
    962     (defined(__s390__) || defined(__s390x__) || defined(__zarch__)) || \
    963     defined(__vax__)
    964 /*
    965  * The processor natively handles unaligned loads, so just use memcpy()
    966  * and memcmp(), to enable those optimizations.
    967  *
    968  * XXX - are those all the x86 tests we need?
    969  * XXX - do we need to worry about ARMv1 through ARMv5, which didn't
    970  * support unaligned loads, and, if so, do we need to worry about all
    971  * of them, or just some of them, e.g. ARMv5?
    972  * XXX - are those the only 68k tests we need not to generated
    973  * unaligned accesses if the target is the 68000 or 68010?
    974  * XXX - are there any tests we don't need, because some definitions are for
    975  * compilers that also predefine the GCC symbols?
    976  * XXX - do we need to test for both 32-bit and 64-bit versions of those
    977  * architectures in all cases?
    978  */
    979 #else
    980 /*
    981  * The processor doesn't natively handle unaligned loads,
    982  * and the compiler might "helpfully" optimize memcpy()
    983  * and memcmp(), when handed pointers that would normally
    984  * be properly aligned, into sequences that assume proper
    985  * alignment.
    986  *
    987  * Do copies and compares of possibly-unaligned data by
    988  * calling routines that wrap memcpy() and memcmp(), to
    989  * prevent that optimization.
    990  */
    991 void
    992 unaligned_memcpy(void *p, const void *q, size_t l)
    993 {
    994 	memcpy(p, q, l);
    995 }
    996 
    997 /* As with memcpy(), so with memcmp(). */
    998 int
    999 unaligned_memcmp(const void *p, const void *q, size_t l)
   1000 {
   1001 	return (memcmp(p, q, l));
   1002 }
   1003 #endif
   1004 
   1005