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