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