xref: /minix3/external/bsd/tcpdump/dist/util.c (revision b636d99d91c3d54204248f643c14627405d4afd1)
1*b636d99dSDavid van Moolenbroek /*
2*b636d99dSDavid van Moolenbroek  * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
3*b636d99dSDavid van Moolenbroek  *	The Regents of the University of California.  All rights reserved.
4*b636d99dSDavid van Moolenbroek  *
5*b636d99dSDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
6*b636d99dSDavid van Moolenbroek  * modification, are permitted provided that: (1) source code distributions
7*b636d99dSDavid van Moolenbroek  * retain the above copyright notice and this paragraph in its entirety, (2)
8*b636d99dSDavid van Moolenbroek  * distributions including binary code include the above copyright notice and
9*b636d99dSDavid van Moolenbroek  * this paragraph in its entirety in the documentation or other materials
10*b636d99dSDavid van Moolenbroek  * provided with the distribution, and (3) all advertising materials mentioning
11*b636d99dSDavid van Moolenbroek  * features or use of this software display the following acknowledgement:
12*b636d99dSDavid van Moolenbroek  * ``This product includes software developed by the University of California,
13*b636d99dSDavid van Moolenbroek  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14*b636d99dSDavid van Moolenbroek  * the University nor the names of its contributors may be used to endorse
15*b636d99dSDavid van Moolenbroek  * or promote products derived from this software without specific prior
16*b636d99dSDavid van Moolenbroek  * written permission.
17*b636d99dSDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18*b636d99dSDavid van Moolenbroek  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19*b636d99dSDavid van Moolenbroek  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20*b636d99dSDavid van Moolenbroek  */
21*b636d99dSDavid van Moolenbroek 
22*b636d99dSDavid van Moolenbroek #include <sys/cdefs.h>
23*b636d99dSDavid van Moolenbroek #ifndef lint
24*b636d99dSDavid van Moolenbroek __RCSID("$NetBSD: util.c,v 1.5 2015/03/31 21:59:35 christos Exp $");
25*b636d99dSDavid van Moolenbroek #endif
26*b636d99dSDavid van Moolenbroek 
27*b636d99dSDavid van Moolenbroek /*
28*b636d99dSDavid van Moolenbroek  * txtproto_print() derived from original code by Hannes Gredler
29*b636d99dSDavid van Moolenbroek  * (hannes@juniper.net):
30*b636d99dSDavid van Moolenbroek  *
31*b636d99dSDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
32*b636d99dSDavid van Moolenbroek  * modification, are permitted provided that: (1) source code
33*b636d99dSDavid van Moolenbroek  * distributions retain the above copyright notice and this paragraph
34*b636d99dSDavid van Moolenbroek  * in its entirety, and (2) distributions including binary code include
35*b636d99dSDavid van Moolenbroek  * the above copyright notice and this paragraph in its entirety in
36*b636d99dSDavid van Moolenbroek  * the documentation or other materials provided with the distribution.
37*b636d99dSDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
38*b636d99dSDavid van Moolenbroek  * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
39*b636d99dSDavid van Moolenbroek  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
40*b636d99dSDavid van Moolenbroek  * FOR A PARTICULAR PURPOSE.
41*b636d99dSDavid van Moolenbroek  */
42*b636d99dSDavid van Moolenbroek 
43*b636d99dSDavid van Moolenbroek #define NETDISSECT_REWORKED
44*b636d99dSDavid van Moolenbroek #ifdef HAVE_CONFIG_H
45*b636d99dSDavid van Moolenbroek #include "config.h"
46*b636d99dSDavid van Moolenbroek #endif
47*b636d99dSDavid van Moolenbroek 
48*b636d99dSDavid van Moolenbroek #include <tcpdump-stdinc.h>
49*b636d99dSDavid van Moolenbroek 
50*b636d99dSDavid van Moolenbroek #include <sys/stat.h>
51*b636d99dSDavid van Moolenbroek 
52*b636d99dSDavid van Moolenbroek #ifdef HAVE_FCNTL_H
53*b636d99dSDavid van Moolenbroek #include <fcntl.h>
54*b636d99dSDavid van Moolenbroek #endif
55*b636d99dSDavid van Moolenbroek #include <stdio.h>
56*b636d99dSDavid van Moolenbroek #include <stdarg.h>
57*b636d99dSDavid van Moolenbroek #include <stdlib.h>
58*b636d99dSDavid van Moolenbroek #include <string.h>
59*b636d99dSDavid van Moolenbroek 
60*b636d99dSDavid van Moolenbroek #include "interface.h"
61*b636d99dSDavid van Moolenbroek 
62*b636d99dSDavid van Moolenbroek /*
63*b636d99dSDavid van Moolenbroek  * Print out a null-terminated filename (or other ascii string).
64*b636d99dSDavid van Moolenbroek  * If ep is NULL, assume no truncation check is needed.
65*b636d99dSDavid van Moolenbroek  * Return true if truncated.
66*b636d99dSDavid van Moolenbroek  */
67*b636d99dSDavid van Moolenbroek int
fn_print(netdissect_options * ndo,register const u_char * s,register const u_char * ep)68*b636d99dSDavid van Moolenbroek fn_print(netdissect_options *ndo,
69*b636d99dSDavid van Moolenbroek          register const u_char *s, register const u_char *ep)
70*b636d99dSDavid van Moolenbroek {
71*b636d99dSDavid van Moolenbroek 	register int ret;
72*b636d99dSDavid van Moolenbroek 	register u_char c;
73*b636d99dSDavid van Moolenbroek 
74*b636d99dSDavid van Moolenbroek 	ret = 1;			/* assume truncated */
75*b636d99dSDavid van Moolenbroek 	while (ep == NULL || s < ep) {
76*b636d99dSDavid van Moolenbroek 		c = *s++;
77*b636d99dSDavid van Moolenbroek 		if (c == '\0') {
78*b636d99dSDavid van Moolenbroek 			ret = 0;
79*b636d99dSDavid van Moolenbroek 			break;
80*b636d99dSDavid van Moolenbroek 		}
81*b636d99dSDavid van Moolenbroek 		if (!ND_ISASCII(c)) {
82*b636d99dSDavid van Moolenbroek 			c = ND_TOASCII(c);
83*b636d99dSDavid van Moolenbroek 			ND_PRINT((ndo, "M-"));
84*b636d99dSDavid van Moolenbroek 		}
85*b636d99dSDavid van Moolenbroek 		if (!ND_ISPRINT(c)) {
86*b636d99dSDavid van Moolenbroek 			c ^= 0x40;	/* DEL to ?, others to alpha */
87*b636d99dSDavid van Moolenbroek 			ND_PRINT((ndo, "^"));
88*b636d99dSDavid van Moolenbroek 		}
89*b636d99dSDavid van Moolenbroek 		ND_PRINT((ndo, "%c", c));
90*b636d99dSDavid van Moolenbroek 	}
91*b636d99dSDavid van Moolenbroek 	return(ret);
92*b636d99dSDavid van Moolenbroek }
93*b636d99dSDavid van Moolenbroek 
94*b636d99dSDavid van Moolenbroek /*
95*b636d99dSDavid van Moolenbroek  * Print out a counted filename (or other ascii string).
96*b636d99dSDavid van Moolenbroek  * If ep is NULL, assume no truncation check is needed.
97*b636d99dSDavid van Moolenbroek  * Return true if truncated.
98*b636d99dSDavid van Moolenbroek  */
99*b636d99dSDavid van Moolenbroek int
fn_printn(netdissect_options * ndo,register const u_char * s,register u_int n,register const u_char * ep)100*b636d99dSDavid van Moolenbroek fn_printn(netdissect_options *ndo,
101*b636d99dSDavid van Moolenbroek           register const u_char *s, register u_int n, register const u_char *ep)
102*b636d99dSDavid van Moolenbroek {
103*b636d99dSDavid van Moolenbroek 	register u_char c;
104*b636d99dSDavid van Moolenbroek 
105*b636d99dSDavid van Moolenbroek 	while (n > 0 && (ep == NULL || s < ep)) {
106*b636d99dSDavid van Moolenbroek 		n--;
107*b636d99dSDavid van Moolenbroek 		c = *s++;
108*b636d99dSDavid van Moolenbroek 		if (!ND_ISASCII(c)) {
109*b636d99dSDavid van Moolenbroek 			c = ND_TOASCII(c);
110*b636d99dSDavid van Moolenbroek 			ND_PRINT((ndo, "M-"));
111*b636d99dSDavid van Moolenbroek 		}
112*b636d99dSDavid van Moolenbroek 		if (!ND_ISPRINT(c)) {
113*b636d99dSDavid van Moolenbroek 			c ^= 0x40;	/* DEL to ?, others to alpha */
114*b636d99dSDavid van Moolenbroek 			ND_PRINT((ndo, "^"));
115*b636d99dSDavid van Moolenbroek 		}
116*b636d99dSDavid van Moolenbroek 		ND_PRINT((ndo, "%c", c));
117*b636d99dSDavid van Moolenbroek 	}
118*b636d99dSDavid van Moolenbroek 	return (n == 0) ? 0 : 1;
119*b636d99dSDavid van Moolenbroek }
120*b636d99dSDavid van Moolenbroek 
121*b636d99dSDavid van Moolenbroek /*
122*b636d99dSDavid van Moolenbroek  * Print out a null-padded filename (or other ascii string).
123*b636d99dSDavid van Moolenbroek  * If ep is NULL, assume no truncation check is needed.
124*b636d99dSDavid van Moolenbroek  * Return true if truncated.
125*b636d99dSDavid van Moolenbroek  */
126*b636d99dSDavid van Moolenbroek int
fn_printzp(netdissect_options * ndo,register const u_char * s,register u_int n,register const u_char * ep)127*b636d99dSDavid van Moolenbroek fn_printzp(netdissect_options *ndo,
128*b636d99dSDavid van Moolenbroek            register const u_char *s, register u_int n,
129*b636d99dSDavid van Moolenbroek            register const u_char *ep)
130*b636d99dSDavid van Moolenbroek {
131*b636d99dSDavid van Moolenbroek 	register int ret;
132*b636d99dSDavid van Moolenbroek 	register u_char c;
133*b636d99dSDavid van Moolenbroek 
134*b636d99dSDavid van Moolenbroek 	ret = 1;			/* assume truncated */
135*b636d99dSDavid van Moolenbroek 	while (n > 0 && (ep == NULL || s < ep)) {
136*b636d99dSDavid van Moolenbroek 		n--;
137*b636d99dSDavid van Moolenbroek 		c = *s++;
138*b636d99dSDavid van Moolenbroek 		if (c == '\0') {
139*b636d99dSDavid van Moolenbroek 			ret = 0;
140*b636d99dSDavid van Moolenbroek 			break;
141*b636d99dSDavid van Moolenbroek 		}
142*b636d99dSDavid van Moolenbroek 		if (!ND_ISASCII(c)) {
143*b636d99dSDavid van Moolenbroek 			c = ND_TOASCII(c);
144*b636d99dSDavid van Moolenbroek 			ND_PRINT((ndo, "M-"));
145*b636d99dSDavid van Moolenbroek 		}
146*b636d99dSDavid van Moolenbroek 		if (!ND_ISPRINT(c)) {
147*b636d99dSDavid van Moolenbroek 			c ^= 0x40;	/* DEL to ?, others to alpha */
148*b636d99dSDavid van Moolenbroek 			ND_PRINT((ndo, "^"));
149*b636d99dSDavid van Moolenbroek 		}
150*b636d99dSDavid van Moolenbroek 		ND_PRINT((ndo, "%c", c));
151*b636d99dSDavid van Moolenbroek 	}
152*b636d99dSDavid van Moolenbroek 	return (n == 0) ? 0 : ret;
153*b636d99dSDavid van Moolenbroek }
154*b636d99dSDavid van Moolenbroek 
155*b636d99dSDavid van Moolenbroek /*
156*b636d99dSDavid van Moolenbroek  * Format the timestamp
157*b636d99dSDavid van Moolenbroek  */
158*b636d99dSDavid van Moolenbroek static char *
ts_format(netdissect_options * ndo _U_,int sec,int usec)159*b636d99dSDavid van Moolenbroek ts_format(netdissect_options *ndo
160*b636d99dSDavid van Moolenbroek #ifndef HAVE_PCAP_SET_TSTAMP_PRECISION
161*b636d99dSDavid van Moolenbroek _U_
162*b636d99dSDavid van Moolenbroek #endif
163*b636d99dSDavid van Moolenbroek , int sec, int usec)
164*b636d99dSDavid van Moolenbroek {
165*b636d99dSDavid van Moolenbroek 	static char buf[sizeof("00:00:00.000000000")];
166*b636d99dSDavid van Moolenbroek 	const char *format;
167*b636d99dSDavid van Moolenbroek 
168*b636d99dSDavid van Moolenbroek #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
169*b636d99dSDavid van Moolenbroek 	switch (ndo->ndo_tstamp_precision) {
170*b636d99dSDavid van Moolenbroek 
171*b636d99dSDavid van Moolenbroek 	case PCAP_TSTAMP_PRECISION_MICRO:
172*b636d99dSDavid van Moolenbroek 		format = "%02d:%02d:%02d.%06u";
173*b636d99dSDavid van Moolenbroek 		break;
174*b636d99dSDavid van Moolenbroek 
175*b636d99dSDavid van Moolenbroek 	case PCAP_TSTAMP_PRECISION_NANO:
176*b636d99dSDavid van Moolenbroek 		format = "%02d:%02d:%02d.%09u";
177*b636d99dSDavid van Moolenbroek 		break;
178*b636d99dSDavid van Moolenbroek 
179*b636d99dSDavid van Moolenbroek 	default:
180*b636d99dSDavid van Moolenbroek 		format = "%02d:%02d:%02d.{unknown precision}";
181*b636d99dSDavid van Moolenbroek 		break;
182*b636d99dSDavid van Moolenbroek 	}
183*b636d99dSDavid van Moolenbroek #else
184*b636d99dSDavid van Moolenbroek 	format = "%02d:%02d:%02d.%06u";
185*b636d99dSDavid van Moolenbroek #endif
186*b636d99dSDavid van Moolenbroek 
187*b636d99dSDavid van Moolenbroek 	snprintf(buf, sizeof(buf), format,
188*b636d99dSDavid van Moolenbroek                  sec / 3600, (sec % 3600) / 60, sec % 60, usec);
189*b636d99dSDavid van Moolenbroek 
190*b636d99dSDavid van Moolenbroek         return buf;
191*b636d99dSDavid van Moolenbroek }
192*b636d99dSDavid van Moolenbroek 
193*b636d99dSDavid van Moolenbroek /*
194*b636d99dSDavid van Moolenbroek  * Print the timestamp
195*b636d99dSDavid van Moolenbroek  */
196*b636d99dSDavid van Moolenbroek void
ts_print(netdissect_options * ndo,register const struct timeval * tvp)197*b636d99dSDavid van Moolenbroek ts_print(netdissect_options *ndo,
198*b636d99dSDavid van Moolenbroek          register const struct timeval *tvp)
199*b636d99dSDavid van Moolenbroek {
200*b636d99dSDavid van Moolenbroek 	register int s;
201*b636d99dSDavid van Moolenbroek 	struct tm *tm;
202*b636d99dSDavid van Moolenbroek 	time_t Time;
203*b636d99dSDavid van Moolenbroek 	static unsigned b_sec;
204*b636d99dSDavid van Moolenbroek 	static unsigned b_usec;
205*b636d99dSDavid van Moolenbroek 	int d_usec;
206*b636d99dSDavid van Moolenbroek 	int d_sec;
207*b636d99dSDavid van Moolenbroek 
208*b636d99dSDavid van Moolenbroek 	switch (ndo->ndo_tflag) {
209*b636d99dSDavid van Moolenbroek 
210*b636d99dSDavid van Moolenbroek 	case 0: /* Default */
211*b636d99dSDavid van Moolenbroek 		s = (tvp->tv_sec + thiszone) % 86400;
212*b636d99dSDavid van Moolenbroek 		ND_PRINT((ndo, "%s ", ts_format(ndo, s, tvp->tv_usec)));
213*b636d99dSDavid van Moolenbroek 		break;
214*b636d99dSDavid van Moolenbroek 
215*b636d99dSDavid van Moolenbroek 	case 1: /* No time stamp */
216*b636d99dSDavid van Moolenbroek 		break;
217*b636d99dSDavid van Moolenbroek 
218*b636d99dSDavid van Moolenbroek 	case 2: /* Unix timeval style */
219*b636d99dSDavid van Moolenbroek 		ND_PRINT((ndo, "%u.%06u ",
220*b636d99dSDavid van Moolenbroek 			     (unsigned)tvp->tv_sec,
221*b636d99dSDavid van Moolenbroek 			     (unsigned)tvp->tv_usec));
222*b636d99dSDavid van Moolenbroek 		break;
223*b636d99dSDavid van Moolenbroek 
224*b636d99dSDavid van Moolenbroek 	case 3: /* Microseconds since previous packet */
225*b636d99dSDavid van Moolenbroek         case 5: /* Microseconds since first packet */
226*b636d99dSDavid van Moolenbroek 		if (b_sec == 0) {
227*b636d99dSDavid van Moolenbroek                         /* init timestamp for first packet */
228*b636d99dSDavid van Moolenbroek                         b_usec = tvp->tv_usec;
229*b636d99dSDavid van Moolenbroek                         b_sec = tvp->tv_sec;
230*b636d99dSDavid van Moolenbroek                 }
231*b636d99dSDavid van Moolenbroek 
232*b636d99dSDavid van Moolenbroek                 d_usec = tvp->tv_usec - b_usec;
233*b636d99dSDavid van Moolenbroek                 d_sec = tvp->tv_sec - b_sec;
234*b636d99dSDavid van Moolenbroek 
235*b636d99dSDavid van Moolenbroek                 while (d_usec < 0) {
236*b636d99dSDavid van Moolenbroek                     d_usec += 1000000;
237*b636d99dSDavid van Moolenbroek                     d_sec--;
238*b636d99dSDavid van Moolenbroek                 }
239*b636d99dSDavid van Moolenbroek 
240*b636d99dSDavid van Moolenbroek                 ND_PRINT((ndo, "%s ", ts_format(ndo, d_sec, d_usec)));
241*b636d99dSDavid van Moolenbroek 
242*b636d99dSDavid van Moolenbroek                 if (ndo->ndo_tflag == 3) { /* set timestamp for last packet */
243*b636d99dSDavid van Moolenbroek                     b_sec = tvp->tv_sec;
244*b636d99dSDavid van Moolenbroek                     b_usec = tvp->tv_usec;
245*b636d99dSDavid van Moolenbroek                 }
246*b636d99dSDavid van Moolenbroek 		break;
247*b636d99dSDavid van Moolenbroek 
248*b636d99dSDavid van Moolenbroek 	case 4: /* Default + Date*/
249*b636d99dSDavid van Moolenbroek 		s = (tvp->tv_sec + thiszone) % 86400;
250*b636d99dSDavid van Moolenbroek 		Time = (tvp->tv_sec + thiszone) - s;
251*b636d99dSDavid van Moolenbroek 		tm = gmtime (&Time);
252*b636d99dSDavid van Moolenbroek 		if (!tm)
253*b636d99dSDavid van Moolenbroek 			ND_PRINT((ndo, "Date fail  "));
254*b636d99dSDavid van Moolenbroek 		else
255*b636d99dSDavid van Moolenbroek 			ND_PRINT((ndo, "%04d-%02d-%02d %s ",
256*b636d99dSDavid van Moolenbroek                                tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
257*b636d99dSDavid van Moolenbroek                                ts_format(ndo, s, tvp->tv_usec)));
258*b636d99dSDavid van Moolenbroek 		break;
259*b636d99dSDavid van Moolenbroek 	}
260*b636d99dSDavid van Moolenbroek }
261*b636d99dSDavid van Moolenbroek 
262*b636d99dSDavid van Moolenbroek /*
263*b636d99dSDavid van Moolenbroek  * Print a relative number of seconds (e.g. hold time, prune timer)
264*b636d99dSDavid van Moolenbroek  * in the form 5m1s.  This does no truncation, so 32230861 seconds
265*b636d99dSDavid van Moolenbroek  * is represented as 1y1w1d1h1m1s.
266*b636d99dSDavid van Moolenbroek  */
267*b636d99dSDavid van Moolenbroek void
relts_print(netdissect_options * ndo,int secs)268*b636d99dSDavid van Moolenbroek relts_print(netdissect_options *ndo,
269*b636d99dSDavid van Moolenbroek             int secs)
270*b636d99dSDavid van Moolenbroek {
271*b636d99dSDavid van Moolenbroek 	static const char *lengths[] = {"y", "w", "d", "h", "m", "s"};
272*b636d99dSDavid van Moolenbroek 	static const int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
273*b636d99dSDavid van Moolenbroek 	const char **l = lengths;
274*b636d99dSDavid van Moolenbroek 	const int *s = seconds;
275*b636d99dSDavid van Moolenbroek 
276*b636d99dSDavid van Moolenbroek 	if (secs == 0) {
277*b636d99dSDavid van Moolenbroek 		ND_PRINT((ndo, "0s"));
278*b636d99dSDavid van Moolenbroek 		return;
279*b636d99dSDavid van Moolenbroek 	}
280*b636d99dSDavid van Moolenbroek 	if (secs < 0) {
281*b636d99dSDavid van Moolenbroek 		ND_PRINT((ndo, "-"));
282*b636d99dSDavid van Moolenbroek 		secs = -secs;
283*b636d99dSDavid van Moolenbroek 	}
284*b636d99dSDavid van Moolenbroek 	while (secs > 0) {
285*b636d99dSDavid van Moolenbroek 		if (secs >= *s) {
286*b636d99dSDavid van Moolenbroek 			ND_PRINT((ndo, "%d%s", secs / *s, *l));
287*b636d99dSDavid van Moolenbroek 			secs -= (secs / *s) * *s;
288*b636d99dSDavid van Moolenbroek 		}
289*b636d99dSDavid van Moolenbroek 		s++;
290*b636d99dSDavid van Moolenbroek 		l++;
291*b636d99dSDavid van Moolenbroek 	}
292*b636d99dSDavid van Moolenbroek }
293*b636d99dSDavid van Moolenbroek 
294*b636d99dSDavid van Moolenbroek /*
295*b636d99dSDavid van Moolenbroek  *  this is a generic routine for printing unknown data;
296*b636d99dSDavid van Moolenbroek  *  we pass on the linefeed plus indentation string to
297*b636d99dSDavid van Moolenbroek  *  get a proper output - returns 0 on error
298*b636d99dSDavid van Moolenbroek  */
299*b636d99dSDavid van Moolenbroek 
300*b636d99dSDavid van Moolenbroek int
print_unknown_data(netdissect_options * ndo,const u_char * cp,const char * ident,int len)301*b636d99dSDavid van Moolenbroek print_unknown_data(netdissect_options *ndo, const u_char *cp,const char *ident,int len)
302*b636d99dSDavid van Moolenbroek {
303*b636d99dSDavid van Moolenbroek 	if (len < 0) {
304*b636d99dSDavid van Moolenbroek           ND_PRINT((ndo,"%sDissector error: print_unknown_data called with negative length",
305*b636d99dSDavid van Moolenbroek 		    ident));
306*b636d99dSDavid van Moolenbroek 		return(0);
307*b636d99dSDavid van Moolenbroek 	}
308*b636d99dSDavid van Moolenbroek 	if (ndo->ndo_snapend - cp < len)
309*b636d99dSDavid van Moolenbroek 		len = ndo->ndo_snapend - cp;
310*b636d99dSDavid van Moolenbroek 	if (len < 0) {
311*b636d99dSDavid van Moolenbroek           ND_PRINT((ndo,"%sDissector error: print_unknown_data called with pointer past end of packet",
312*b636d99dSDavid van Moolenbroek 		    ident));
313*b636d99dSDavid van Moolenbroek 		return(0);
314*b636d99dSDavid van Moolenbroek 	}
315*b636d99dSDavid van Moolenbroek         hex_print(ndo, ident,cp,len);
316*b636d99dSDavid van Moolenbroek 	return(1); /* everything is ok */
317*b636d99dSDavid van Moolenbroek }
318*b636d99dSDavid van Moolenbroek 
319*b636d99dSDavid van Moolenbroek /*
320*b636d99dSDavid van Moolenbroek  * Convert a token value to a string; use "fmt" if not found.
321*b636d99dSDavid van Moolenbroek  */
322*b636d99dSDavid van Moolenbroek const char *
tok2strbuf(register const struct tok * lp,register const char * fmt,register u_int v,char * buf,size_t bufsize)323*b636d99dSDavid van Moolenbroek tok2strbuf(register const struct tok *lp, register const char *fmt,
324*b636d99dSDavid van Moolenbroek 	   register u_int v, char *buf, size_t bufsize)
325*b636d99dSDavid van Moolenbroek {
326*b636d99dSDavid van Moolenbroek 	if (lp != NULL) {
327*b636d99dSDavid van Moolenbroek 		while (lp->s != NULL) {
328*b636d99dSDavid van Moolenbroek 			if (lp->v == v)
329*b636d99dSDavid van Moolenbroek 				return (lp->s);
330*b636d99dSDavid van Moolenbroek 			++lp;
331*b636d99dSDavid van Moolenbroek 		}
332*b636d99dSDavid van Moolenbroek 	}
333*b636d99dSDavid van Moolenbroek 	if (fmt == NULL)
334*b636d99dSDavid van Moolenbroek 		fmt = "#%d";
335*b636d99dSDavid van Moolenbroek 
336*b636d99dSDavid van Moolenbroek 	(void)snprintf(buf, bufsize, fmt, v);
337*b636d99dSDavid van Moolenbroek 	return (const char *)buf;
338*b636d99dSDavid van Moolenbroek }
339*b636d99dSDavid van Moolenbroek 
340*b636d99dSDavid van Moolenbroek /*
341*b636d99dSDavid van Moolenbroek  * Convert a token value to a string; use "fmt" if not found.
342*b636d99dSDavid van Moolenbroek  */
343*b636d99dSDavid van Moolenbroek const char *
tok2str(register const struct tok * lp,register const char * fmt,register int v)344*b636d99dSDavid van Moolenbroek tok2str(register const struct tok *lp, register const char *fmt,
345*b636d99dSDavid van Moolenbroek 	register int v)
346*b636d99dSDavid van Moolenbroek {
347*b636d99dSDavid van Moolenbroek 	static char buf[4][128];
348*b636d99dSDavid van Moolenbroek 	static int idx = 0;
349*b636d99dSDavid van Moolenbroek 	char *ret;
350*b636d99dSDavid van Moolenbroek 
351*b636d99dSDavid van Moolenbroek 	ret = buf[idx];
352*b636d99dSDavid van Moolenbroek 	idx = (idx+1) & 3;
353*b636d99dSDavid van Moolenbroek 	return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0]));
354*b636d99dSDavid van Moolenbroek }
355*b636d99dSDavid van Moolenbroek 
356*b636d99dSDavid van Moolenbroek /*
357*b636d99dSDavid van Moolenbroek  * Convert a bit token value to a string; use "fmt" if not found.
358*b636d99dSDavid van Moolenbroek  * this is useful for parsing bitfields, the output strings are seperated
359*b636d99dSDavid van Moolenbroek  * if the s field is positive.
360*b636d99dSDavid van Moolenbroek  */
361*b636d99dSDavid van Moolenbroek static char *
bittok2str_internal(register const struct tok * lp,register const char * fmt,register int v,register int sep)362*b636d99dSDavid van Moolenbroek bittok2str_internal(register const struct tok *lp, register const char *fmt,
363*b636d99dSDavid van Moolenbroek 	   register int v, register int sep)
364*b636d99dSDavid van Moolenbroek {
365*b636d99dSDavid van Moolenbroek         static char buf[256]; /* our stringbuffer */
366*b636d99dSDavid van Moolenbroek         int buflen=0;
367*b636d99dSDavid van Moolenbroek         register int rotbit; /* this is the bit we rotate through all bitpositions */
368*b636d99dSDavid van Moolenbroek         register int tokval;
369*b636d99dSDavid van Moolenbroek         const char * sepstr = "";
370*b636d99dSDavid van Moolenbroek 
371*b636d99dSDavid van Moolenbroek 	while (lp != NULL && lp->s != NULL) {
372*b636d99dSDavid van Moolenbroek             tokval=lp->v;   /* load our first value */
373*b636d99dSDavid van Moolenbroek             rotbit=1;
374*b636d99dSDavid van Moolenbroek             while (rotbit != 0) {
375*b636d99dSDavid van Moolenbroek                 /*
376*b636d99dSDavid van Moolenbroek                  * lets AND the rotating bit with our token value
377*b636d99dSDavid van Moolenbroek                  * and see if we have got a match
378*b636d99dSDavid van Moolenbroek                  */
379*b636d99dSDavid van Moolenbroek 		if (tokval == (v&rotbit)) {
380*b636d99dSDavid van Moolenbroek                     /* ok we have found something */
381*b636d99dSDavid van Moolenbroek                     buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s%s",
382*b636d99dSDavid van Moolenbroek                                      sepstr, lp->s);
383*b636d99dSDavid van Moolenbroek                     sepstr = sep ? ", " : "";
384*b636d99dSDavid van Moolenbroek                     break;
385*b636d99dSDavid van Moolenbroek                 }
386*b636d99dSDavid van Moolenbroek                 rotbit=rotbit<<1; /* no match - lets shift and try again */
387*b636d99dSDavid van Moolenbroek             }
388*b636d99dSDavid van Moolenbroek             lp++;
389*b636d99dSDavid van Moolenbroek 	}
390*b636d99dSDavid van Moolenbroek 
391*b636d99dSDavid van Moolenbroek         if (buflen == 0)
392*b636d99dSDavid van Moolenbroek             /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
393*b636d99dSDavid van Moolenbroek             (void)snprintf(buf, sizeof(buf), fmt == NULL ? "#%d" : fmt, v);
394*b636d99dSDavid van Moolenbroek         return (buf);
395*b636d99dSDavid van Moolenbroek }
396*b636d99dSDavid van Moolenbroek 
397*b636d99dSDavid van Moolenbroek /*
398*b636d99dSDavid van Moolenbroek  * Convert a bit token value to a string; use "fmt" if not found.
399*b636d99dSDavid van Moolenbroek  * this is useful for parsing bitfields, the output strings are not seperated.
400*b636d99dSDavid van Moolenbroek  */
401*b636d99dSDavid van Moolenbroek char *
bittok2str_nosep(register const struct tok * lp,register const char * fmt,register int v)402*b636d99dSDavid van Moolenbroek bittok2str_nosep(register const struct tok *lp, register const char *fmt,
403*b636d99dSDavid van Moolenbroek 	   register int v)
404*b636d99dSDavid van Moolenbroek {
405*b636d99dSDavid van Moolenbroek     return (bittok2str_internal(lp, fmt, v, 0));
406*b636d99dSDavid van Moolenbroek }
407*b636d99dSDavid van Moolenbroek 
408*b636d99dSDavid van Moolenbroek /*
409*b636d99dSDavid van Moolenbroek  * Convert a bit token value to a string; use "fmt" if not found.
410*b636d99dSDavid van Moolenbroek  * this is useful for parsing bitfields, the output strings are comma seperated.
411*b636d99dSDavid van Moolenbroek  */
412*b636d99dSDavid van Moolenbroek char *
bittok2str(register const struct tok * lp,register const char * fmt,register int v)413*b636d99dSDavid van Moolenbroek bittok2str(register const struct tok *lp, register const char *fmt,
414*b636d99dSDavid van Moolenbroek 	   register int v)
415*b636d99dSDavid van Moolenbroek {
416*b636d99dSDavid van Moolenbroek     return (bittok2str_internal(lp, fmt, v, 1));
417*b636d99dSDavid van Moolenbroek }
418*b636d99dSDavid van Moolenbroek 
419*b636d99dSDavid van Moolenbroek /*
420*b636d99dSDavid van Moolenbroek  * Convert a value to a string using an array; the macro
421*b636d99dSDavid van Moolenbroek  * tok2strary() in <interface.h> is the public interface to
422*b636d99dSDavid van Moolenbroek  * this function and ensures that the second argument is
423*b636d99dSDavid van Moolenbroek  * correct for bounds-checking.
424*b636d99dSDavid van Moolenbroek  */
425*b636d99dSDavid van Moolenbroek const char *
tok2strary_internal(register const char ** lp,int n,register const char * fmt,register int v)426*b636d99dSDavid van Moolenbroek tok2strary_internal(register const char **lp, int n, register const char *fmt,
427*b636d99dSDavid van Moolenbroek 	register int v)
428*b636d99dSDavid van Moolenbroek {
429*b636d99dSDavid van Moolenbroek 	static char buf[128];
430*b636d99dSDavid van Moolenbroek 
431*b636d99dSDavid van Moolenbroek 	if (v >= 0 && v < n && lp[v] != NULL)
432*b636d99dSDavid van Moolenbroek 		return lp[v];
433*b636d99dSDavid van Moolenbroek 	if (fmt == NULL)
434*b636d99dSDavid van Moolenbroek 		fmt = "#%d";
435*b636d99dSDavid van Moolenbroek 	(void)snprintf(buf, sizeof(buf), fmt, v);
436*b636d99dSDavid van Moolenbroek 	return (buf);
437*b636d99dSDavid van Moolenbroek }
438*b636d99dSDavid van Moolenbroek 
439*b636d99dSDavid van Moolenbroek /*
440*b636d99dSDavid van Moolenbroek  * Convert a 32-bit netmask to prefixlen if possible
441*b636d99dSDavid van Moolenbroek  * the function returns the prefix-len; if plen == -1
442*b636d99dSDavid van Moolenbroek  * then conversion was not possible;
443*b636d99dSDavid van Moolenbroek  */
444*b636d99dSDavid van Moolenbroek 
445*b636d99dSDavid van Moolenbroek int
mask2plen(uint32_t mask)446*b636d99dSDavid van Moolenbroek mask2plen(uint32_t mask)
447*b636d99dSDavid van Moolenbroek {
448*b636d99dSDavid van Moolenbroek 	uint32_t bitmasks[33] = {
449*b636d99dSDavid van Moolenbroek 		0x00000000,
450*b636d99dSDavid van Moolenbroek 		0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
451*b636d99dSDavid van Moolenbroek 		0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
452*b636d99dSDavid van Moolenbroek 		0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
453*b636d99dSDavid van Moolenbroek 		0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
454*b636d99dSDavid van Moolenbroek 		0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
455*b636d99dSDavid van Moolenbroek 		0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
456*b636d99dSDavid van Moolenbroek 		0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
457*b636d99dSDavid van Moolenbroek 		0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
458*b636d99dSDavid van Moolenbroek 	};
459*b636d99dSDavid van Moolenbroek 	int prefix_len = 32;
460*b636d99dSDavid van Moolenbroek 
461*b636d99dSDavid van Moolenbroek 	/* let's see if we can transform the mask into a prefixlen */
462*b636d99dSDavid van Moolenbroek 	while (prefix_len >= 0) {
463*b636d99dSDavid van Moolenbroek 		if (bitmasks[prefix_len] == mask)
464*b636d99dSDavid van Moolenbroek 			break;
465*b636d99dSDavid van Moolenbroek 		prefix_len--;
466*b636d99dSDavid van Moolenbroek 	}
467*b636d99dSDavid van Moolenbroek 	return (prefix_len);
468*b636d99dSDavid van Moolenbroek }
469*b636d99dSDavid van Moolenbroek 
470*b636d99dSDavid van Moolenbroek #ifdef INET6
471*b636d99dSDavid van Moolenbroek int
mask62plen(const u_char * mask)472*b636d99dSDavid van Moolenbroek mask62plen(const u_char *mask)
473*b636d99dSDavid van Moolenbroek {
474*b636d99dSDavid van Moolenbroek 	u_char bitmasks[9] = {
475*b636d99dSDavid van Moolenbroek 		0x00,
476*b636d99dSDavid van Moolenbroek 		0x80, 0xc0, 0xe0, 0xf0,
477*b636d99dSDavid van Moolenbroek 		0xf8, 0xfc, 0xfe, 0xff
478*b636d99dSDavid van Moolenbroek 	};
479*b636d99dSDavid van Moolenbroek 	int byte;
480*b636d99dSDavid van Moolenbroek 	int cidr_len = 0;
481*b636d99dSDavid van Moolenbroek 
482*b636d99dSDavid van Moolenbroek 	for (byte = 0; byte < 16; byte++) {
483*b636d99dSDavid van Moolenbroek 		u_int bits;
484*b636d99dSDavid van Moolenbroek 
485*b636d99dSDavid van Moolenbroek 		for (bits = 0; bits < (sizeof (bitmasks) / sizeof (bitmasks[0])); bits++) {
486*b636d99dSDavid van Moolenbroek 			if (mask[byte] == bitmasks[bits]) {
487*b636d99dSDavid van Moolenbroek 				cidr_len += bits;
488*b636d99dSDavid van Moolenbroek 				break;
489*b636d99dSDavid van Moolenbroek 			}
490*b636d99dSDavid van Moolenbroek 		}
491*b636d99dSDavid van Moolenbroek 
492*b636d99dSDavid van Moolenbroek 		if (mask[byte] != 0xff)
493*b636d99dSDavid van Moolenbroek 			break;
494*b636d99dSDavid van Moolenbroek 	}
495*b636d99dSDavid van Moolenbroek 	return (cidr_len);
496*b636d99dSDavid van Moolenbroek }
497*b636d99dSDavid van Moolenbroek #endif /* INET6 */
498*b636d99dSDavid van Moolenbroek 
499*b636d99dSDavid van Moolenbroek /*
500*b636d99dSDavid van Moolenbroek  * Routine to print out information for text-based protocols such as FTP,
501*b636d99dSDavid van Moolenbroek  * HTTP, SMTP, RTSP, SIP, ....
502*b636d99dSDavid van Moolenbroek  */
503*b636d99dSDavid van Moolenbroek #define MAX_TOKEN	128
504*b636d99dSDavid van Moolenbroek 
505*b636d99dSDavid van Moolenbroek /*
506*b636d99dSDavid van Moolenbroek  * Fetch a token from a packet, starting at the specified index,
507*b636d99dSDavid van Moolenbroek  * and return the length of the token.
508*b636d99dSDavid van Moolenbroek  *
509*b636d99dSDavid van Moolenbroek  * Returns 0 on error; yes, this is indistinguishable from an empty
510*b636d99dSDavid van Moolenbroek  * token, but an "empty token" isn't a valid token - it just means
511*b636d99dSDavid van Moolenbroek  * either a space character at the beginning of the line (this
512*b636d99dSDavid van Moolenbroek  * includes a blank line) or no more tokens remaining on the line.
513*b636d99dSDavid van Moolenbroek  */
514*b636d99dSDavid van Moolenbroek static int
fetch_token(netdissect_options * ndo,const u_char * pptr,u_int idx,u_int len,u_char * tbuf,size_t tbuflen)515*b636d99dSDavid van Moolenbroek fetch_token(netdissect_options *ndo, const u_char *pptr, u_int idx, u_int len,
516*b636d99dSDavid van Moolenbroek     u_char *tbuf, size_t tbuflen)
517*b636d99dSDavid van Moolenbroek {
518*b636d99dSDavid van Moolenbroek 	size_t toklen = 0;
519*b636d99dSDavid van Moolenbroek 
520*b636d99dSDavid van Moolenbroek 	for (; idx < len; idx++) {
521*b636d99dSDavid van Moolenbroek 		if (!ND_TTEST(*(pptr + idx))) {
522*b636d99dSDavid van Moolenbroek 			/* ran past end of captured data */
523*b636d99dSDavid van Moolenbroek 			return (0);
524*b636d99dSDavid van Moolenbroek 		}
525*b636d99dSDavid van Moolenbroek 		if (!isascii(*(pptr + idx))) {
526*b636d99dSDavid van Moolenbroek 			/* not an ASCII character */
527*b636d99dSDavid van Moolenbroek 			return (0);
528*b636d99dSDavid van Moolenbroek 		}
529*b636d99dSDavid van Moolenbroek 		if (isspace(*(pptr + idx))) {
530*b636d99dSDavid van Moolenbroek 			/* end of token */
531*b636d99dSDavid van Moolenbroek 			break;
532*b636d99dSDavid van Moolenbroek 		}
533*b636d99dSDavid van Moolenbroek 		if (!isprint(*(pptr + idx))) {
534*b636d99dSDavid van Moolenbroek 			/* not part of a command token or response code */
535*b636d99dSDavid van Moolenbroek 			return (0);
536*b636d99dSDavid van Moolenbroek 		}
537*b636d99dSDavid van Moolenbroek 		if (toklen + 2 > tbuflen) {
538*b636d99dSDavid van Moolenbroek 			/* no room for this character and terminating '\0' */
539*b636d99dSDavid van Moolenbroek 			return (0);
540*b636d99dSDavid van Moolenbroek 		}
541*b636d99dSDavid van Moolenbroek 		tbuf[toklen] = *(pptr + idx);
542*b636d99dSDavid van Moolenbroek 		toklen++;
543*b636d99dSDavid van Moolenbroek 	}
544*b636d99dSDavid van Moolenbroek 	if (toklen == 0) {
545*b636d99dSDavid van Moolenbroek 		/* no token */
546*b636d99dSDavid van Moolenbroek 		return (0);
547*b636d99dSDavid van Moolenbroek 	}
548*b636d99dSDavid van Moolenbroek 	tbuf[toklen] = '\0';
549*b636d99dSDavid van Moolenbroek 
550*b636d99dSDavid van Moolenbroek 	/*
551*b636d99dSDavid van Moolenbroek 	 * Skip past any white space after the token, until we see
552*b636d99dSDavid van Moolenbroek 	 * an end-of-line (CR or LF).
553*b636d99dSDavid van Moolenbroek 	 */
554*b636d99dSDavid van Moolenbroek 	for (; idx < len; idx++) {
555*b636d99dSDavid van Moolenbroek 		if (!ND_TTEST(*(pptr + idx))) {
556*b636d99dSDavid van Moolenbroek 			/* ran past end of captured data */
557*b636d99dSDavid van Moolenbroek 			break;
558*b636d99dSDavid van Moolenbroek 		}
559*b636d99dSDavid van Moolenbroek 		if (*(pptr + idx) == '\r' || *(pptr + idx) == '\n') {
560*b636d99dSDavid van Moolenbroek 			/* end of line */
561*b636d99dSDavid van Moolenbroek 			break;
562*b636d99dSDavid van Moolenbroek 		}
563*b636d99dSDavid van Moolenbroek 		if (!isascii(*(pptr + idx)) || !isprint(*(pptr + idx))) {
564*b636d99dSDavid van Moolenbroek 			/* not a printable ASCII character */
565*b636d99dSDavid van Moolenbroek 			break;
566*b636d99dSDavid van Moolenbroek 		}
567*b636d99dSDavid van Moolenbroek 		if (!isspace(*(pptr + idx))) {
568*b636d99dSDavid van Moolenbroek 			/* beginning of next token */
569*b636d99dSDavid van Moolenbroek 			break;
570*b636d99dSDavid van Moolenbroek 		}
571*b636d99dSDavid van Moolenbroek 	}
572*b636d99dSDavid van Moolenbroek 	return (idx);
573*b636d99dSDavid van Moolenbroek }
574*b636d99dSDavid van Moolenbroek 
575*b636d99dSDavid van Moolenbroek /*
576*b636d99dSDavid van Moolenbroek  * Scan a buffer looking for a line ending - LF or CR-LF.
577*b636d99dSDavid van Moolenbroek  * Return the index of the character after the line ending or 0 if
578*b636d99dSDavid van Moolenbroek  * we encounter a non-ASCII or non-printable character or don't find
579*b636d99dSDavid van Moolenbroek  * the line ending.
580*b636d99dSDavid van Moolenbroek  */
581*b636d99dSDavid van Moolenbroek static u_int
print_txt_line(netdissect_options * ndo,const char * protoname,const char * prefix,const u_char * pptr,u_int idx,u_int len)582*b636d99dSDavid van Moolenbroek print_txt_line(netdissect_options *ndo, const char *protoname,
583*b636d99dSDavid van Moolenbroek     const char *prefix, const u_char *pptr, u_int idx, u_int len)
584*b636d99dSDavid van Moolenbroek {
585*b636d99dSDavid van Moolenbroek 	u_int startidx;
586*b636d99dSDavid van Moolenbroek 	u_int linelen;
587*b636d99dSDavid van Moolenbroek 
588*b636d99dSDavid van Moolenbroek 	startidx = idx;
589*b636d99dSDavid van Moolenbroek 	while (idx < len) {
590*b636d99dSDavid van Moolenbroek 		ND_TCHECK(*(pptr+idx));
591*b636d99dSDavid van Moolenbroek 		if (*(pptr+idx) == '\n') {
592*b636d99dSDavid van Moolenbroek 			/*
593*b636d99dSDavid van Moolenbroek 			 * LF without CR; end of line.
594*b636d99dSDavid van Moolenbroek 			 * Skip the LF and print the line, with the
595*b636d99dSDavid van Moolenbroek 			 * exception of the LF.
596*b636d99dSDavid van Moolenbroek 			 */
597*b636d99dSDavid van Moolenbroek 			linelen = idx - startidx;
598*b636d99dSDavid van Moolenbroek 			idx++;
599*b636d99dSDavid van Moolenbroek 			goto print;
600*b636d99dSDavid van Moolenbroek 		} else if (*(pptr+idx) == '\r') {
601*b636d99dSDavid van Moolenbroek 			/* CR - any LF? */
602*b636d99dSDavid van Moolenbroek 			if ((idx+1) >= len) {
603*b636d99dSDavid van Moolenbroek 				/* not in this packet */
604*b636d99dSDavid van Moolenbroek 				return (0);
605*b636d99dSDavid van Moolenbroek 			}
606*b636d99dSDavid van Moolenbroek 			ND_TCHECK(*(pptr+idx+1));
607*b636d99dSDavid van Moolenbroek 			if (*(pptr+idx+1) == '\n') {
608*b636d99dSDavid van Moolenbroek 				/*
609*b636d99dSDavid van Moolenbroek 				 * CR-LF; end of line.
610*b636d99dSDavid van Moolenbroek 				 * Skip the CR-LF and print the line, with
611*b636d99dSDavid van Moolenbroek 				 * the exception of the CR-LF.
612*b636d99dSDavid van Moolenbroek 				 */
613*b636d99dSDavid van Moolenbroek 				linelen = idx - startidx;
614*b636d99dSDavid van Moolenbroek 				idx += 2;
615*b636d99dSDavid van Moolenbroek 				goto print;
616*b636d99dSDavid van Moolenbroek 			}
617*b636d99dSDavid van Moolenbroek 
618*b636d99dSDavid van Moolenbroek 			/*
619*b636d99dSDavid van Moolenbroek 			 * CR followed by something else; treat this
620*b636d99dSDavid van Moolenbroek 			 * as if it were binary data, and don't print
621*b636d99dSDavid van Moolenbroek 			 * it.
622*b636d99dSDavid van Moolenbroek 			 */
623*b636d99dSDavid van Moolenbroek 			return (0);
624*b636d99dSDavid van Moolenbroek 		} else if (!isascii(*(pptr+idx)) ||
625*b636d99dSDavid van Moolenbroek 		    (!isprint(*(pptr+idx)) && *(pptr+idx) != '\t')) {
626*b636d99dSDavid van Moolenbroek 			/*
627*b636d99dSDavid van Moolenbroek 			 * Not a printable ASCII character and not a tab;
628*b636d99dSDavid van Moolenbroek 			 * treat this as if it were binary data, and
629*b636d99dSDavid van Moolenbroek 			 * don't print it.
630*b636d99dSDavid van Moolenbroek 			 */
631*b636d99dSDavid van Moolenbroek 			return (0);
632*b636d99dSDavid van Moolenbroek 		}
633*b636d99dSDavid van Moolenbroek 		idx++;
634*b636d99dSDavid van Moolenbroek 	}
635*b636d99dSDavid van Moolenbroek 
636*b636d99dSDavid van Moolenbroek 	/*
637*b636d99dSDavid van Moolenbroek 	 * All printable ASCII, but no line ending after that point
638*b636d99dSDavid van Moolenbroek 	 * in the buffer; treat this as if it were truncated.
639*b636d99dSDavid van Moolenbroek 	 */
640*b636d99dSDavid van Moolenbroek trunc:
641*b636d99dSDavid van Moolenbroek 	linelen = idx - startidx;
642*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "%s%.*s[!%s]", prefix, (int)linelen, pptr + startidx,
643*b636d99dSDavid van Moolenbroek 	    protoname));
644*b636d99dSDavid van Moolenbroek 	return (0);
645*b636d99dSDavid van Moolenbroek 
646*b636d99dSDavid van Moolenbroek print:
647*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, "%s%.*s", prefix, (int)linelen, pptr + startidx));
648*b636d99dSDavid van Moolenbroek 	return (idx);
649*b636d99dSDavid van Moolenbroek }
650*b636d99dSDavid van Moolenbroek 
651*b636d99dSDavid van Moolenbroek void
txtproto_print(netdissect_options * ndo,const u_char * pptr,u_int len,const char * protoname,const char ** cmds,u_int flags)652*b636d99dSDavid van Moolenbroek txtproto_print(netdissect_options *ndo, const u_char *pptr, u_int len,
653*b636d99dSDavid van Moolenbroek     const char *protoname, const char **cmds, u_int flags)
654*b636d99dSDavid van Moolenbroek {
655*b636d99dSDavid van Moolenbroek 	u_int idx, eol;
656*b636d99dSDavid van Moolenbroek 	u_char token[MAX_TOKEN+1];
657*b636d99dSDavid van Moolenbroek 	const char *cmd;
658*b636d99dSDavid van Moolenbroek 	int is_reqresp = 0;
659*b636d99dSDavid van Moolenbroek 	const char *pnp;
660*b636d99dSDavid van Moolenbroek 
661*b636d99dSDavid van Moolenbroek 	if (cmds != NULL) {
662*b636d99dSDavid van Moolenbroek 		/*
663*b636d99dSDavid van Moolenbroek 		 * This protocol has more than just request and
664*b636d99dSDavid van Moolenbroek 		 * response lines; see whether this looks like a
665*b636d99dSDavid van Moolenbroek 		 * request or response.
666*b636d99dSDavid van Moolenbroek 		 */
667*b636d99dSDavid van Moolenbroek 		idx = fetch_token(ndo, pptr, 0, len, token, sizeof(token));
668*b636d99dSDavid van Moolenbroek 		if (idx != 0) {
669*b636d99dSDavid van Moolenbroek 			/* Is this a valid request name? */
670*b636d99dSDavid van Moolenbroek 			while ((cmd = *cmds++) != NULL) {
671*b636d99dSDavid van Moolenbroek 				if (strcasecmp((const char *)token, cmd) == 0) {
672*b636d99dSDavid van Moolenbroek 					/* Yes. */
673*b636d99dSDavid van Moolenbroek 					is_reqresp = 1;
674*b636d99dSDavid van Moolenbroek 					break;
675*b636d99dSDavid van Moolenbroek 				}
676*b636d99dSDavid van Moolenbroek 			}
677*b636d99dSDavid van Moolenbroek 
678*b636d99dSDavid van Moolenbroek 			/*
679*b636d99dSDavid van Moolenbroek 			 * No - is this a valid response code (3 digits)?
680*b636d99dSDavid van Moolenbroek 			 *
681*b636d99dSDavid van Moolenbroek 			 * Is this token the response code, or is the next
682*b636d99dSDavid van Moolenbroek 			 * token the response code?
683*b636d99dSDavid van Moolenbroek 			 */
684*b636d99dSDavid van Moolenbroek 			if (flags & RESP_CODE_SECOND_TOKEN) {
685*b636d99dSDavid van Moolenbroek 				/*
686*b636d99dSDavid van Moolenbroek 				 * Next token - get it.
687*b636d99dSDavid van Moolenbroek 				 */
688*b636d99dSDavid van Moolenbroek 				idx = fetch_token(ndo, pptr, idx, len, token,
689*b636d99dSDavid van Moolenbroek 				    sizeof(token));
690*b636d99dSDavid van Moolenbroek 			}
691*b636d99dSDavid van Moolenbroek 			if (idx != 0) {
692*b636d99dSDavid van Moolenbroek 				if (isdigit(token[0]) && isdigit(token[1]) &&
693*b636d99dSDavid van Moolenbroek 				    isdigit(token[2]) && token[3] == '\0') {
694*b636d99dSDavid van Moolenbroek 					/* Yes. */
695*b636d99dSDavid van Moolenbroek 					is_reqresp = 1;
696*b636d99dSDavid van Moolenbroek 				}
697*b636d99dSDavid van Moolenbroek 			}
698*b636d99dSDavid van Moolenbroek 		}
699*b636d99dSDavid van Moolenbroek 	} else {
700*b636d99dSDavid van Moolenbroek 		/*
701*b636d99dSDavid van Moolenbroek 		 * This protocol has only request and response lines
702*b636d99dSDavid van Moolenbroek 		 * (e.g., FTP, where all the data goes over a
703*b636d99dSDavid van Moolenbroek 		 * different connection); assume the payload is
704*b636d99dSDavid van Moolenbroek 		 * a request or response.
705*b636d99dSDavid van Moolenbroek 		 */
706*b636d99dSDavid van Moolenbroek 		is_reqresp = 1;
707*b636d99dSDavid van Moolenbroek 	}
708*b636d99dSDavid van Moolenbroek 
709*b636d99dSDavid van Moolenbroek 	/* Capitalize the protocol name */
710*b636d99dSDavid van Moolenbroek 	for (pnp = protoname; *pnp != '\0'; pnp++)
711*b636d99dSDavid van Moolenbroek 		ND_PRINT((ndo, "%c", toupper((unsigned char)*pnp)));
712*b636d99dSDavid van Moolenbroek 
713*b636d99dSDavid van Moolenbroek 	if (is_reqresp) {
714*b636d99dSDavid van Moolenbroek 		/*
715*b636d99dSDavid van Moolenbroek 		 * In non-verbose mode, just print the protocol, followed
716*b636d99dSDavid van Moolenbroek 		 * by the first line as the request or response info.
717*b636d99dSDavid van Moolenbroek 		 *
718*b636d99dSDavid van Moolenbroek 		 * In verbose mode, print lines as text until we run out
719*b636d99dSDavid van Moolenbroek 		 * of characters or see something that's not a
720*b636d99dSDavid van Moolenbroek 		 * printable-ASCII line.
721*b636d99dSDavid van Moolenbroek 		 */
722*b636d99dSDavid van Moolenbroek 		if (ndo->ndo_vflag) {
723*b636d99dSDavid van Moolenbroek 			/*
724*b636d99dSDavid van Moolenbroek 			 * We're going to print all the text lines in the
725*b636d99dSDavid van Moolenbroek 			 * request or response; just print the length
726*b636d99dSDavid van Moolenbroek 			 * on the first line of the output.
727*b636d99dSDavid van Moolenbroek 			 */
728*b636d99dSDavid van Moolenbroek 			ND_PRINT((ndo, ", length: %u", len));
729*b636d99dSDavid van Moolenbroek 			for (idx = 0;
730*b636d99dSDavid van Moolenbroek 			    idx < len && (eol = print_txt_line(ndo, protoname, "\n\t", pptr, idx, len)) != 0;
731*b636d99dSDavid van Moolenbroek 			    idx = eol)
732*b636d99dSDavid van Moolenbroek 				;
733*b636d99dSDavid van Moolenbroek 		} else {
734*b636d99dSDavid van Moolenbroek 			/*
735*b636d99dSDavid van Moolenbroek 			 * Just print the first text line.
736*b636d99dSDavid van Moolenbroek 			 */
737*b636d99dSDavid van Moolenbroek 			print_txt_line(ndo, protoname, ": ", pptr, 0, len);
738*b636d99dSDavid van Moolenbroek 		}
739*b636d99dSDavid van Moolenbroek 	}
740*b636d99dSDavid van Moolenbroek }
741*b636d99dSDavid van Moolenbroek 
742*b636d99dSDavid van Moolenbroek /* VARARGS */
743*b636d99dSDavid van Moolenbroek void
error(const char * fmt,...)744*b636d99dSDavid van Moolenbroek error(const char *fmt, ...)
745*b636d99dSDavid van Moolenbroek {
746*b636d99dSDavid van Moolenbroek 	va_list ap;
747*b636d99dSDavid van Moolenbroek 
748*b636d99dSDavid van Moolenbroek 	(void)fprintf(stderr, "%s: ", program_name);
749*b636d99dSDavid van Moolenbroek 	va_start(ap, fmt);
750*b636d99dSDavid van Moolenbroek 	(void)vfprintf(stderr, fmt, ap);
751*b636d99dSDavid van Moolenbroek 	va_end(ap);
752*b636d99dSDavid van Moolenbroek 	if (*fmt) {
753*b636d99dSDavid van Moolenbroek 		fmt += strlen(fmt);
754*b636d99dSDavid van Moolenbroek 		if (fmt[-1] != '\n')
755*b636d99dSDavid van Moolenbroek 			(void)fputc('\n', stderr);
756*b636d99dSDavid van Moolenbroek 	}
757*b636d99dSDavid van Moolenbroek 	exit(1);
758*b636d99dSDavid van Moolenbroek 	/* NOTREACHED */
759*b636d99dSDavid van Moolenbroek }
760*b636d99dSDavid van Moolenbroek 
761*b636d99dSDavid van Moolenbroek /* VARARGS */
762*b636d99dSDavid van Moolenbroek void
warning(const char * fmt,...)763*b636d99dSDavid van Moolenbroek warning(const char *fmt, ...)
764*b636d99dSDavid van Moolenbroek {
765*b636d99dSDavid van Moolenbroek 	va_list ap;
766*b636d99dSDavid van Moolenbroek 
767*b636d99dSDavid van Moolenbroek 	(void)fprintf(stderr, "%s: WARNING: ", program_name);
768*b636d99dSDavid van Moolenbroek 	va_start(ap, fmt);
769*b636d99dSDavid van Moolenbroek 	(void)vfprintf(stderr, fmt, ap);
770*b636d99dSDavid van Moolenbroek 	va_end(ap);
771*b636d99dSDavid van Moolenbroek 	if (*fmt) {
772*b636d99dSDavid van Moolenbroek 		fmt += strlen(fmt);
773*b636d99dSDavid van Moolenbroek 		if (fmt[-1] != '\n')
774*b636d99dSDavid van Moolenbroek 			(void)fputc('\n', stderr);
775*b636d99dSDavid van Moolenbroek 	}
776*b636d99dSDavid van Moolenbroek }
777*b636d99dSDavid van Moolenbroek 
778*b636d99dSDavid van Moolenbroek /*
779*b636d99dSDavid van Moolenbroek  * Copy arg vector into a new buffer, concatenating arguments with spaces.
780*b636d99dSDavid van Moolenbroek  */
781*b636d99dSDavid van Moolenbroek char *
copy_argv(register char ** argv)782*b636d99dSDavid van Moolenbroek copy_argv(register char **argv)
783*b636d99dSDavid van Moolenbroek {
784*b636d99dSDavid van Moolenbroek 	register char **p;
785*b636d99dSDavid van Moolenbroek 	register u_int len = 0;
786*b636d99dSDavid van Moolenbroek 	char *buf;
787*b636d99dSDavid van Moolenbroek 	char *src, *dst;
788*b636d99dSDavid van Moolenbroek 
789*b636d99dSDavid van Moolenbroek 	p = argv;
790*b636d99dSDavid van Moolenbroek 	if (*p == 0)
791*b636d99dSDavid van Moolenbroek 		return 0;
792*b636d99dSDavid van Moolenbroek 
793*b636d99dSDavid van Moolenbroek 	while (*p)
794*b636d99dSDavid van Moolenbroek 		len += strlen(*p++) + 1;
795*b636d99dSDavid van Moolenbroek 
796*b636d99dSDavid van Moolenbroek 	buf = (char *)malloc(len);
797*b636d99dSDavid van Moolenbroek 	if (buf == NULL)
798*b636d99dSDavid van Moolenbroek 		error("copy_argv: malloc");
799*b636d99dSDavid van Moolenbroek 
800*b636d99dSDavid van Moolenbroek 	p = argv;
801*b636d99dSDavid van Moolenbroek 	dst = buf;
802*b636d99dSDavid van Moolenbroek 	while ((src = *p++) != NULL) {
803*b636d99dSDavid van Moolenbroek 		while ((*dst++ = *src++) != '\0')
804*b636d99dSDavid van Moolenbroek 			;
805*b636d99dSDavid van Moolenbroek 		dst[-1] = ' ';
806*b636d99dSDavid van Moolenbroek 	}
807*b636d99dSDavid van Moolenbroek 	dst[-1] = '\0';
808*b636d99dSDavid van Moolenbroek 
809*b636d99dSDavid van Moolenbroek 	return buf;
810*b636d99dSDavid van Moolenbroek }
811*b636d99dSDavid van Moolenbroek 
812*b636d99dSDavid van Moolenbroek /*
813*b636d99dSDavid van Moolenbroek  * On Windows, we need to open the file in binary mode, so that
814*b636d99dSDavid van Moolenbroek  * we get all the bytes specified by the size we get from "fstat()".
815*b636d99dSDavid van Moolenbroek  * On UNIX, that's not necessary.  O_BINARY is defined on Windows;
816*b636d99dSDavid van Moolenbroek  * we define it as 0 if it's not defined, so it does nothing.
817*b636d99dSDavid van Moolenbroek  */
818*b636d99dSDavid van Moolenbroek #ifndef O_BINARY
819*b636d99dSDavid van Moolenbroek #define O_BINARY	0
820*b636d99dSDavid van Moolenbroek #endif
821*b636d99dSDavid van Moolenbroek 
822*b636d99dSDavid van Moolenbroek char *
read_infile(char * fname)823*b636d99dSDavid van Moolenbroek read_infile(char *fname)
824*b636d99dSDavid van Moolenbroek {
825*b636d99dSDavid van Moolenbroek 	register int i, fd, cc;
826*b636d99dSDavid van Moolenbroek 	register char *cp;
827*b636d99dSDavid van Moolenbroek 	struct stat buf;
828*b636d99dSDavid van Moolenbroek 
829*b636d99dSDavid van Moolenbroek 	fd = open(fname, O_RDONLY|O_BINARY);
830*b636d99dSDavid van Moolenbroek 	if (fd < 0)
831*b636d99dSDavid van Moolenbroek 		error("can't open %s: %s", fname, pcap_strerror(errno));
832*b636d99dSDavid van Moolenbroek 
833*b636d99dSDavid van Moolenbroek 	if (fstat(fd, &buf) < 0)
834*b636d99dSDavid van Moolenbroek 		error("can't stat %s: %s", fname, pcap_strerror(errno));
835*b636d99dSDavid van Moolenbroek 
836*b636d99dSDavid van Moolenbroek 	cp = malloc((u_int)buf.st_size + 1);
837*b636d99dSDavid van Moolenbroek 	if (cp == NULL)
838*b636d99dSDavid van Moolenbroek 		error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
839*b636d99dSDavid van Moolenbroek 			fname, pcap_strerror(errno));
840*b636d99dSDavid van Moolenbroek 	cc = read(fd, cp, (u_int)buf.st_size);
841*b636d99dSDavid van Moolenbroek 	if (cc < 0)
842*b636d99dSDavid van Moolenbroek 		error("read %s: %s", fname, pcap_strerror(errno));
843*b636d99dSDavid van Moolenbroek 	if (cc != buf.st_size)
844*b636d99dSDavid van Moolenbroek 		error("short read %s (%d != %d)", fname, cc, (int)buf.st_size);
845*b636d99dSDavid van Moolenbroek 
846*b636d99dSDavid van Moolenbroek 	close(fd);
847*b636d99dSDavid van Moolenbroek 	/* replace "# comment" with spaces */
848*b636d99dSDavid van Moolenbroek 	for (i = 0; i < cc; i++) {
849*b636d99dSDavid van Moolenbroek 		if (cp[i] == '#')
850*b636d99dSDavid van Moolenbroek 			while (i < cc && cp[i] != '\n')
851*b636d99dSDavid van Moolenbroek 				cp[i++] = ' ';
852*b636d99dSDavid van Moolenbroek 	}
853*b636d99dSDavid van Moolenbroek 	cp[cc] = '\0';
854*b636d99dSDavid van Moolenbroek 	return (cp);
855*b636d99dSDavid van Moolenbroek }
856*b636d99dSDavid van Moolenbroek 
857*b636d99dSDavid van Moolenbroek void
safeputs(netdissect_options * ndo,const u_char * s,const u_int maxlen)858*b636d99dSDavid van Moolenbroek safeputs(netdissect_options *ndo,
859*b636d99dSDavid van Moolenbroek          const u_char *s, const u_int maxlen)
860*b636d99dSDavid van Moolenbroek {
861*b636d99dSDavid van Moolenbroek 	u_int idx = 0;
862*b636d99dSDavid van Moolenbroek 
863*b636d99dSDavid van Moolenbroek 	while (*s && idx < maxlen) {
864*b636d99dSDavid van Moolenbroek 		safeputchar(ndo, *s);
865*b636d99dSDavid van Moolenbroek 		idx++;
866*b636d99dSDavid van Moolenbroek 		s++;
867*b636d99dSDavid van Moolenbroek 	}
868*b636d99dSDavid van Moolenbroek }
869*b636d99dSDavid van Moolenbroek 
870*b636d99dSDavid van Moolenbroek void
safeputchar(netdissect_options * ndo,const u_char c)871*b636d99dSDavid van Moolenbroek safeputchar(netdissect_options *ndo,
872*b636d99dSDavid van Moolenbroek             const u_char c)
873*b636d99dSDavid van Moolenbroek {
874*b636d99dSDavid van Moolenbroek 	ND_PRINT((ndo, (c < 0x80 && ND_ISPRINT(c)) ? "%c" : "\\0x%02x", c));
875*b636d99dSDavid van Moolenbroek }
876*b636d99dSDavid van Moolenbroek 
877*b636d99dSDavid van Moolenbroek #ifdef LBL_ALIGN
878*b636d99dSDavid van Moolenbroek /*
879*b636d99dSDavid van Moolenbroek  * Some compilers try to optimize memcpy(), using the alignment constraint
880*b636d99dSDavid van Moolenbroek  * on the argument pointer type.  by using this function, we try to avoid the
881*b636d99dSDavid van Moolenbroek  * optimization.
882*b636d99dSDavid van Moolenbroek  */
883*b636d99dSDavid van Moolenbroek void
unaligned_memcpy(void * p,const void * q,size_t l)884*b636d99dSDavid van Moolenbroek unaligned_memcpy(void *p, const void *q, size_t l)
885*b636d99dSDavid van Moolenbroek {
886*b636d99dSDavid van Moolenbroek 	memcpy(p, q, l);
887*b636d99dSDavid van Moolenbroek }
888*b636d99dSDavid van Moolenbroek 
889*b636d99dSDavid van Moolenbroek /* As with memcpy(), so with memcmp(). */
890*b636d99dSDavid van Moolenbroek int
unaligned_memcmp(const void * p,const void * q,size_t l)891*b636d99dSDavid van Moolenbroek unaligned_memcmp(const void *p, const void *q, size_t l)
892*b636d99dSDavid van Moolenbroek {
893*b636d99dSDavid van Moolenbroek 	return (memcmp(p, q, l));
894*b636d99dSDavid van Moolenbroek }
895*b636d99dSDavid van Moolenbroek #endif
896