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#ifndef lint
23static const char rcsid[] _U_ =
24    "@(#) $Header: /tcpdump/master/tcpdump/util.c,v 1.95.2.6 2006/02/08 01:40:09 hannes Exp $ (LBL)";
25#endif
26
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#include <tcpdump-stdinc.h>
32
33#include <sys/stat.h>
34
35#include <errno.h>
36#ifdef HAVE_FCNTL_H
37#include <fcntl.h>
38#endif
39#include <pcap.h>
40#include <stdio.h>
41#include <stdarg.h>
42#include <stdlib.h>
43#include <string.h>
44
45#include "interface.h"
46
47/*
48 * Print out a null-terminated filename (or other ascii string).
49 * If ep is NULL, assume no truncation check is needed.
50 * Return true if truncated.
51 */
52int
53fn_print(register const u_char *s, register const u_char *ep)
54{
55	register int ret;
56	register u_char c;
57
58	ret = 1;			/* assume truncated */
59	while (ep == NULL || s < ep) {
60		c = *s++;
61		if (c == '\0') {
62			ret = 0;
63			break;
64		}
65		if (!isascii(c)) {
66			c = toascii(c);
67			putchar('M');
68			putchar('-');
69		}
70		if (!isprint(c)) {
71			c ^= 0x40;	/* DEL to ?, others to alpha */
72			putchar('^');
73		}
74		putchar(c);
75	}
76	return(ret);
77}
78
79/*
80 * Print out a counted filename (or other ascii string).
81 * If ep is NULL, assume no truncation check is needed.
82 * Return true if truncated.
83 */
84int
85fn_printn(register const u_char *s, register u_int n,
86	  register const u_char *ep)
87{
88	register u_char c;
89
90	while (n > 0 && (ep == NULL || s < ep)) {
91		n--;
92		c = *s++;
93		if (!isascii(c)) {
94			c = toascii(c);
95			putchar('M');
96			putchar('-');
97		}
98		if (!isprint(c)) {
99			c ^= 0x40;	/* DEL to ?, others to alpha */
100			putchar('^');
101		}
102		putchar(c);
103	}
104	return (n == 0) ? 0 : 1;
105}
106
107/*
108 * Print out a null-padded filename (or other ascii string).
109 * If ep is NULL, assume no truncation check is needed.
110 * Return true if truncated.
111 */
112int
113fn_printzp(register const u_char *s, register u_int n,
114	  register const u_char *ep)
115{
116	register int ret;
117	register u_char c;
118
119	ret = 1;			/* assume truncated */
120	while (n > 0 && (ep == NULL || s < ep)) {
121		n--;
122		c = *s++;
123		if (c == '\0') {
124			ret = 0;
125			break;
126		}
127		if (!isascii(c)) {
128			c = toascii(c);
129			putchar('M');
130			putchar('-');
131		}
132		if (!isprint(c)) {
133			c ^= 0x40;	/* DEL to ?, others to alpha */
134			putchar('^');
135		}
136		putchar(c);
137	}
138	return (n == 0) ? 0 : ret;
139}
140
141/*
142 * Print the timestamp
143 */
144void
145ts_print(register const struct timeval *tvp)
146{
147	register int s;
148	struct tm *tm;
149	time_t Time;
150	static unsigned b_sec;
151	static unsigned b_usec;
152
153	switch (tflag) {
154
155	case 0: /* Default */
156		s = (tvp->tv_sec + thiszone) % 86400;
157		(void)printf("%02d:%02d:%02d.%06u ",
158			     s / 3600, (s % 3600) / 60, s % 60,
159			     (unsigned)tvp->tv_usec);
160		break;
161
162	case 1: /* No time stamp */
163		break;
164
165	case 2: /* Unix timeval style */
166		(void)printf("%u.%06u ",
167			     (unsigned)tvp->tv_sec,
168			     (unsigned)tvp->tv_usec);
169		break;
170
171	case 3: /* Microseconds since previous packet */
172		if (b_sec == 0) {
173			printf("000000 ");
174		} else {
175			int d_usec = tvp->tv_usec - b_usec;
176			int d_sec = tvp->tv_sec - b_sec;
177
178			while (d_usec < 0) {
179				d_usec += 1000000;
180				d_sec--;
181			}
182			if (d_sec)
183				printf("%d. ", d_sec);
184			printf("%06d ", d_usec);
185		}
186		b_sec = tvp->tv_sec;
187		b_usec = tvp->tv_usec;
188		break;
189
190	case 4: /* Default + Date*/
191		s = (tvp->tv_sec + thiszone) % 86400;
192		Time = (tvp->tv_sec + thiszone) - s;
193		tm = gmtime (&Time);
194		if (!tm)
195			printf("Date fail  ");
196		else
197			printf("%04d-%02d-%02d ",
198				   tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday);
199		printf("%02d:%02d:%02d.%06u ",
200			   s / 3600, (s % 3600) / 60, s % 60, (unsigned)tvp->tv_usec);
201		break;
202	}
203}
204
205/*
206 * Print a relative number of seconds (e.g. hold time, prune timer)
207 * in the form 5m1s.  This does no truncation, so 32230861 seconds
208 * is represented as 1y1w1d1h1m1s.
209 */
210void
211relts_print(int secs)
212{
213	static const char *lengths[] = {"y", "w", "d", "h", "m", "s"};
214	static const int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
215	const char **l = lengths;
216	const int *s = seconds;
217
218	if (secs == 0) {
219		(void)printf("0s");
220		return;
221	}
222	if (secs < 0) {
223		(void)printf("-");
224		secs = -secs;
225	}
226	while (secs > 0) {
227		if (secs >= *s) {
228			(void)printf("%d%s", secs / *s, *l);
229			secs -= (secs / *s) * *s;
230		}
231		s++;
232		l++;
233	}
234}
235
236/*
237 *  this is a generic routine for printing unknown data;
238 *  we pass on the linefeed plus indentation string to
239 *  get a proper output - returns 0 on error
240 */
241
242int
243print_unknown_data(const u_char *cp,const char *ident,int len)
244{
245	if (len < 0) {
246		printf("%sDissector error: print_unknown_data called with negative length",
247		    ident);
248		return(0);
249	}
250	if (snapend - cp < len)
251		len = snapend - cp;
252	if (len < 0) {
253		printf("%sDissector error: print_unknown_data called with pointer past end of packet",
254		    ident);
255		return(0);
256	}
257        hex_print(ident,cp,len);
258	return(1); /* everything is ok */
259}
260
261/*
262 * Convert a token value to a string; use "fmt" if not found.
263 */
264const char *
265tok2strbuf(register const struct tok *lp, register const char *fmt,
266	   register int v, char *buf, size_t bufsize)
267{
268	if (lp != NULL) {
269		while (lp->s != NULL) {
270			if (lp->v == v)
271				return (lp->s);
272			++lp;
273		}
274	}
275	if (fmt == NULL)
276		fmt = "#%d";
277
278	(void)snprintf(buf, bufsize, fmt, v);
279	return (const char *)buf;
280}
281
282/*
283 * Convert a token value to a string; use "fmt" if not found.
284 */
285const char *
286tok2str(register const struct tok *lp, register const char *fmt,
287	register int v)
288{
289	static char buf[4][128];
290	static int idx = 0;
291	char *ret;
292
293	ret = buf[idx];
294	idx = (idx+1) & 3;
295	return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0]));
296}
297
298/*
299 * Convert a bit token value to a string; use "fmt" if not found.
300 * this is useful for parsing bitfields, the output strings are comma seperated
301 */
302char *
303bittok2str(register const struct tok *lp, register const char *fmt,
304	   register int v)
305{
306        static char buf[256]; /* our stringbuffer */
307        int buflen=0;
308        register int rotbit; /* this is the bit we rotate through all bitpositions */
309        register int tokval;
310
311	while (lp->s != NULL && lp != NULL) {
312            tokval=lp->v;   /* load our first value */
313            rotbit=1;
314            while (rotbit != 0) {
315                /*
316                 * lets AND the rotating bit with our token value
317                 * and see if we have got a match
318                 */
319		if (tokval == (v&rotbit)) {
320                    /* ok we have found something */
321                    buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s, ",lp->s);
322                    break;
323                }
324                rotbit=rotbit<<1; /* no match - lets shift and try again */
325            }
326            lp++;
327	}
328
329        if (buflen != 0) { /* did we find anything */
330            /* yep, set the the trailing zero 2 bytes before to eliminate the last comma & whitespace */
331            buf[buflen-2] = '\0';
332            return (buf);
333        }
334        else {
335            /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
336            if (fmt == NULL)
337		fmt = "#%d";
338            (void)snprintf(buf, sizeof(buf), fmt, v);
339            return (buf);
340        }
341}
342
343/*
344 * Convert a value to a string using an array; the macro
345 * tok2strary() in <interface.h> is the public interface to
346 * this function and ensures that the second argument is
347 * correct for bounds-checking.
348 */
349const char *
350tok2strary_internal(register const char **lp, int n, register const char *fmt,
351	register int v)
352{
353	static char buf[128];
354
355	if (v >= 0 && v < n && lp[v] != NULL)
356		return lp[v];
357	if (fmt == NULL)
358		fmt = "#%d";
359	(void)snprintf(buf, sizeof(buf), fmt, v);
360	return (buf);
361}
362
363/*
364 * Convert a 32-bit netmask to prefixlen if possible
365 * the function returns the prefix-len; if plen == -1
366 * then conversion was not possible;
367 */
368
369int
370mask2plen (u_int32_t mask)
371{
372	u_int32_t bitmasks[33] = {
373		0x00000000,
374		0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
375		0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
376		0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
377		0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
378		0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
379		0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
380		0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
381		0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
382	};
383	int prefix_len = 32;
384
385	/* let's see if we can transform the mask into a prefixlen */
386	while (prefix_len >= 0) {
387		if (bitmasks[prefix_len] == mask)
388			break;
389		prefix_len--;
390	}
391	return (prefix_len);
392}
393
394/* VARARGS */
395void
396error(const char *fmt, ...)
397{
398	va_list ap;
399
400	(void)fprintf(stderr, "%s: ", program_name);
401	va_start(ap, fmt);
402	(void)vfprintf(stderr, fmt, ap);
403	va_end(ap);
404	if (*fmt) {
405		fmt += strlen(fmt);
406		if (fmt[-1] != '\n')
407			(void)fputc('\n', stderr);
408	}
409	exit(1);
410	/* NOTREACHED */
411}
412
413/* VARARGS */
414void
415warning(const char *fmt, ...)
416{
417	va_list ap;
418
419	(void)fprintf(stderr, "%s: WARNING: ", program_name);
420	va_start(ap, fmt);
421	(void)vfprintf(stderr, fmt, ap);
422	va_end(ap);
423	if (*fmt) {
424		fmt += strlen(fmt);
425		if (fmt[-1] != '\n')
426			(void)fputc('\n', stderr);
427	}
428}
429
430/*
431 * Copy arg vector into a new buffer, concatenating arguments with spaces.
432 */
433char *
434copy_argv(register char **argv)
435{
436	register char **p;
437	register u_int len = 0;
438	char *buf;
439	char *src, *dst;
440
441	p = argv;
442	if (*p == 0)
443		return 0;
444
445	while (*p)
446		len += strlen(*p++) + 1;
447
448	buf = (char *)malloc(len);
449	if (buf == NULL)
450		error("copy_argv: malloc");
451
452	p = argv;
453	dst = buf;
454	while ((src = *p++) != NULL) {
455		while ((*dst++ = *src++) != '\0')
456			;
457		dst[-1] = ' ';
458	}
459	dst[-1] = '\0';
460
461	return buf;
462}
463
464/*
465 * On Windows, we need to open the file in binary mode, so that
466 * we get all the bytes specified by the size we get from "fstat()".
467 * On UNIX, that's not necessary.  O_BINARY is defined on Windows;
468 * we define it as 0 if it's not defined, so it does nothing.
469 */
470#ifndef O_BINARY
471#define O_BINARY	0
472#endif
473
474char *
475read_infile(char *fname)
476{
477	register int i, fd, cc;
478	register char *cp;
479	struct stat buf;
480
481	fd = open(fname, O_RDONLY|O_BINARY);
482	if (fd < 0)
483		error("can't open %s: %s", fname, pcap_strerror(errno));
484
485	if (fstat(fd, &buf) < 0)
486		error("can't stat %s: %s", fname, pcap_strerror(errno));
487
488	cp = malloc((u_int)buf.st_size + 1);
489	if (cp == NULL)
490		error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
491			fname, pcap_strerror(errno));
492	cc = read(fd, cp, (u_int)buf.st_size);
493	if (cc < 0)
494		error("read %s: %s", fname, pcap_strerror(errno));
495	if (cc != buf.st_size)
496		error("short read %s (%d != %d)", fname, cc, (int)buf.st_size);
497
498	close(fd);
499	/* replace "# comment" with spaces */
500	for (i = 0; i < cc; i++) {
501		if (cp[i] == '#')
502			while (i < cc && cp[i] != '\n')
503				cp[i++] = ' ';
504	}
505	cp[cc] = '\0';
506	return (cp);
507}
508
509void
510safeputs(const char *s, int maxlen)
511{
512    int idx = 0;
513	while (*s && idx < maxlen) {
514		safeputchar(*s);
515                idx++;
516		s++;
517	}
518}
519
520void
521safeputchar(int c)
522{
523	unsigned char ch;
524
525	ch = (unsigned char)(c & 0xff);
526	if (ch < 0x80 && isprint(ch))
527		printf("%c", ch);
528	else
529		printf("\\%03o", ch);
530}
531