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