util.c revision 146773
117680Spst/*
239297Sfenner * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
317680Spst *	The Regents of the University of California.  All rights reserved.
417680Spst *
517680Spst * Redistribution and use in source and binary forms, with or without
617680Spst * modification, are permitted provided that: (1) source code distributions
717680Spst * retain the above copyright notice and this paragraph in its entirety, (2)
817680Spst * distributions including binary code include the above copyright notice and
917680Spst * this paragraph in its entirety in the documentation or other materials
1017680Spst * provided with the distribution, and (3) all advertising materials mentioning
1117680Spst * features or use of this software display the following acknowledgement:
1217680Spst * ``This product includes software developed by the University of California,
1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1417680Spst * the University nor the names of its contributors may be used to endorse
1517680Spst * or promote products derived from this software without specific prior
1617680Spst * written permission.
1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2017680Spst */
2117680Spst
2217680Spst#ifndef lint
23127668Sbmsstatic const char rcsid[] _U_ =
24146773Ssam    "@(#) $Header: /tcpdump/master/tcpdump/util.c,v 1.95 2005/03/21 11:35:55 hannes Exp $ (LBL)";
2517680Spst#endif
2617680Spst
2756893Sfenner#ifdef HAVE_CONFIG_H
2856893Sfenner#include "config.h"
2956893Sfenner#endif
3056893Sfenner
31127668Sbms#include <tcpdump-stdinc.h>
32127668Sbms
3317680Spst#include <sys/stat.h>
3417680Spst
3517680Spst#include <errno.h>
3617680Spst#ifdef HAVE_FCNTL_H
3717680Spst#include <fcntl.h>
3817680Spst#endif
3917680Spst#include <pcap.h>
4017680Spst#include <stdio.h>
4117680Spst#include <stdarg.h>
4217680Spst#include <stdlib.h>
4317680Spst#include <string.h>
4417680Spst
4517680Spst#include "interface.h"
4617680Spst
4717680Spst/*
4817680Spst * Print out a filename (or other ascii string).
4917680Spst * If ep is NULL, assume no truncation check is needed.
5017680Spst * Return true if truncated.
5117680Spst */
5217680Spstint
5317680Spstfn_print(register const u_char *s, register const u_char *ep)
5417680Spst{
5517680Spst	register int ret;
5617680Spst	register u_char c;
5717680Spst
5817680Spst	ret = 1;			/* assume truncated */
5917680Spst	while (ep == NULL || s < ep) {
6017680Spst		c = *s++;
6117680Spst		if (c == '\0') {
6217680Spst			ret = 0;
6317680Spst			break;
6417680Spst		}
6517680Spst		if (!isascii(c)) {
6617680Spst			c = toascii(c);
6717680Spst			putchar('M');
6817680Spst			putchar('-');
6917680Spst		}
7017680Spst		if (!isprint(c)) {
7117680Spst			c ^= 0x40;	/* DEL to ?, others to alpha */
7217680Spst			putchar('^');
7317680Spst		}
7417680Spst		putchar(c);
7517680Spst	}
7617680Spst	return(ret);
7717680Spst}
7817680Spst
7917680Spst/*
8017680Spst * Print out a counted filename (or other ascii string).
8117680Spst * If ep is NULL, assume no truncation check is needed.
8217680Spst * Return true if truncated.
8317680Spst */
8417680Spstint
8517680Spstfn_printn(register const u_char *s, register u_int n,
8617680Spst	  register const u_char *ep)
8717680Spst{
8817680Spst	register u_char c;
8917680Spst
90127668Sbms	while (n > 0 && (ep == NULL || s < ep)) {
91127668Sbms		n--;
9217680Spst		c = *s++;
9317680Spst		if (!isascii(c)) {
9417680Spst			c = toascii(c);
9517680Spst			putchar('M');
9617680Spst			putchar('-');
9717680Spst		}
9817680Spst		if (!isprint(c)) {
9917680Spst			c ^= 0x40;	/* DEL to ?, others to alpha */
10017680Spst			putchar('^');
10117680Spst		}
10217680Spst		putchar(c);
10317680Spst	}
104127668Sbms	return (n == 0) ? 0 : 1;
10517680Spst}
10617680Spst
10717680Spst/*
10817680Spst * Print the timestamp
10917680Spst */
11017680Spstvoid
11117680Spstts_print(register const struct timeval *tvp)
11217680Spst{
11317680Spst	register int s;
11475115Sfenner	struct tm *tm;
11575115Sfenner	time_t Time;
11675115Sfenner	static unsigned b_sec;
11775115Sfenner	static unsigned b_usec;
11817680Spst
119146773Ssam	switch (tflag) {
120146773Ssam
121146773Ssam	case 0: /* Default */
12217680Spst		s = (tvp->tv_sec + thiszone) % 86400;
12317680Spst		(void)printf("%02d:%02d:%02d.%06u ",
12475115Sfenner			     s / 3600, (s % 3600) / 60, s % 60,
12575115Sfenner			     (unsigned)tvp->tv_usec);
12675115Sfenner		break;
127146773Ssam
128146773Ssam	case 1: /* No time stamp */
129146773Ssam		break;
130146773Ssam
131146773Ssam	case 2: /* Unix timeval style */
13275115Sfenner		(void)printf("%u.%06u ",
13375115Sfenner			     (unsigned)tvp->tv_sec,
13475115Sfenner			     (unsigned)tvp->tv_usec);
13575115Sfenner		break;
136146773Ssam
137146773Ssam	case 3: /* Microseconds since previous packet */
13875115Sfenner		if (b_sec == 0) {
13975115Sfenner			printf("000000 ");
14075115Sfenner		} else {
14175115Sfenner			int d_usec = tvp->tv_usec - b_usec;
14275115Sfenner			int d_sec = tvp->tv_sec - b_sec;
143127668Sbms
14475115Sfenner			while (d_usec < 0) {
14575115Sfenner				d_usec += 1000000;
14675115Sfenner				d_sec--;
14756893Sfenner			}
14875115Sfenner			if (d_sec)
14975115Sfenner				printf("%d. ", d_sec);
15075115Sfenner			printf("%06d ", d_usec);
15156893Sfenner		}
15275115Sfenner		b_sec = tvp->tv_sec;
15375115Sfenner		b_usec = tvp->tv_usec;
15475115Sfenner		break;
155146773Ssam
156146773Ssam	case 4: /* Default + Date*/
15775115Sfenner		s = (tvp->tv_sec + thiszone) % 86400;
15875115Sfenner		Time = (tvp->tv_sec + thiszone) - s;
159127668Sbms		tm = gmtime (&Time);
160127668Sbms		if (!tm)
161127668Sbms			printf("Date fail  ");
162127668Sbms		else
163127668Sbms			printf("%04d-%02d-%02d ",
164127668Sbms				   tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday);
165127668Sbms		printf("%02d:%02d:%02d.%06u ",
166127668Sbms			   s / 3600, (s % 3600) / 60, s % 60, (unsigned)tvp->tv_usec);
16775115Sfenner		break;
16817680Spst	}
16917680Spst}
17017680Spst
17117680Spst/*
17256893Sfenner * Print a relative number of seconds (e.g. hold time, prune timer)
17356893Sfenner * in the form 5m1s.  This does no truncation, so 32230861 seconds
17456893Sfenner * is represented as 1y1w1d1h1m1s.
17556893Sfenner */
17656893Sfennervoid
17756893Sfennerrelts_print(int secs)
17856893Sfenner{
17998524Sfenner	static const char *lengths[] = {"y", "w", "d", "h", "m", "s"};
18098524Sfenner	static const int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
18198524Sfenner	const char **l = lengths;
18298524Sfenner	const int *s = seconds;
18356893Sfenner
18498524Sfenner	if (secs == 0) {
18575115Sfenner		(void)printf("0s");
18675115Sfenner		return;
18756893Sfenner	}
18898524Sfenner	if (secs < 0) {
18998524Sfenner		(void)printf("-");
19098524Sfenner		secs = -secs;
19198524Sfenner	}
19275115Sfenner	while (secs > 0) {
19375115Sfenner		if (secs >= *s) {
19475115Sfenner			(void)printf("%d%s", secs / *s, *l);
19575115Sfenner			secs -= (secs / *s) * *s;
19675115Sfenner		}
19775115Sfenner		s++;
19875115Sfenner		l++;
19975115Sfenner	}
20056893Sfenner}
20156893Sfenner
20256893Sfenner/*
203127668Sbms *  this is a generic routine for printing unknown data;
204127668Sbms *  we pass on the linefeed plus indentation string to
205127668Sbms *  get a proper output - returns 0 on error
206127668Sbms */
207127668Sbms
208127668Sbmsint
209127668Sbmsprint_unknown_data(const u_char *cp,const char *ident,int len)
210127668Sbms{
211127668Sbms        hex_print(ident,cp,len);
212127668Sbms	return(1); /* everything is ok */
213127668Sbms}
214127668Sbms
215127668Sbms/*
21617680Spst * Convert a token value to a string; use "fmt" if not found.
21717680Spst */
21817680Spstconst char *
219146773Ssamtok2strbuf(register const struct tok *lp, register const char *fmt,
220146773Ssam	   register int v, char *buf, size_t bufsize)
22117680Spst{
222146773Ssam	while (lp->s != NULL && lp != NULL) {
22317680Spst		if (lp->v == v)
22417680Spst			return (lp->s);
22517680Spst		++lp;
22617680Spst	}
22717680Spst	if (fmt == NULL)
22817680Spst		fmt = "#%d";
229146773Ssam
230146773Ssam	(void)snprintf(buf, bufsize, fmt, v);
231146773Ssam	return (const char *)buf;
23217680Spst}
23317680Spst
23498524Sfenner/*
235146773Ssam * Convert a token value to a string; use "fmt" if not found.
236146773Ssam */
237146773Ssamconst char *
238146773Ssamtok2str(register const struct tok *lp, register const char *fmt,
239146773Ssam	register int v)
240146773Ssam{
241146773Ssam	static char buf[4][128];
242146773Ssam	static int idx = 0;
243146773Ssam	char *ret;
244146773Ssam
245146773Ssam	ret = buf[idx];
246146773Ssam	idx = (idx+1) & 3;
247146773Ssam	return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0]));
248146773Ssam}
249146773Ssam
250146773Ssam/*
251127668Sbms * Convert a bit token value to a string; use "fmt" if not found.
252127668Sbms * this is useful for parsing bitfields, the output strings are comma seperated
253127668Sbms */
254127668Sbmschar *
255127668Sbmsbittok2str(register const struct tok *lp, register const char *fmt,
256146773Ssam	   register int v)
257127668Sbms{
258127668Sbms        static char buf[256]; /* our stringbuffer */
259127668Sbms        int buflen=0;
260127668Sbms        register int rotbit; /* this is the bit we rotate through all bitpositions */
261127668Sbms        register int tokval;
262127668Sbms
263146773Ssam	while (lp->s != NULL && lp != NULL) {
264127668Sbms            tokval=lp->v;   /* load our first value */
265127668Sbms            rotbit=1;
266127668Sbms            while (rotbit != 0) {
267127668Sbms                /*
268127668Sbms                 * lets AND the rotating bit with our token value
269127668Sbms                 * and see if we have got a match
270127668Sbms                 */
271127668Sbms		if (tokval == (v&rotbit)) {
272127668Sbms                    /* ok we have found something */
273127668Sbms                    buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s, ",lp->s);
274127668Sbms                    break;
275127668Sbms                }
276127668Sbms                rotbit=rotbit<<1; /* no match - lets shift and try again */
277127668Sbms            }
278127668Sbms            lp++;
279127668Sbms	}
280127668Sbms
281127668Sbms        if (buflen != 0) { /* did we find anything */
282127668Sbms            /* yep, set the the trailing zero 2 bytes before to eliminate the last comma & whitespace */
283127668Sbms            buf[buflen-2] = '\0';
284127668Sbms            return (buf);
285127668Sbms        }
286127668Sbms        else {
287127668Sbms            /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
288127668Sbms            if (fmt == NULL)
289127668Sbms		fmt = "#%d";
290127668Sbms            (void)snprintf(buf, sizeof(buf), fmt, v);
291127668Sbms            return (buf);
292127668Sbms        }
293127668Sbms}
294127668Sbms
295127668Sbms/*
29698524Sfenner * Convert a value to a string using an array; the macro
29798524Sfenner * tok2strary() in <interface.h> is the public interface to
29898524Sfenner * this function and ensures that the second argument is
29998524Sfenner * correct for bounds-checking.
30098524Sfenner */
30198524Sfennerconst char *
30298524Sfennertok2strary_internal(register const char **lp, int n, register const char *fmt,
30398524Sfenner	register int v)
30498524Sfenner{
30598524Sfenner	static char buf[128];
30617680Spst
30798524Sfenner	if (v >= 0 && v < n && lp[v] != NULL)
30898524Sfenner		return lp[v];
30998524Sfenner	if (fmt == NULL)
31098524Sfenner		fmt = "#%d";
31198524Sfenner	(void)snprintf(buf, sizeof(buf), fmt, v);
31298524Sfenner	return (buf);
31398524Sfenner}
31498524Sfenner
315127668Sbms/*
316127668Sbms * Convert a 32-bit netmask to prefixlen if possible
317127668Sbms * the function returns the prefix-len; if plen == -1
318127668Sbms * then conversion was not possible;
319127668Sbms */
320127668Sbms
321127668Sbmsint
322127668Sbmsmask2plen (u_int32_t mask)
323127668Sbms{
324127668Sbms	u_int32_t bitmasks[33] = {
325127668Sbms		0x00000000,
326127668Sbms		0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
327127668Sbms		0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
328127668Sbms		0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
329127668Sbms		0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
330127668Sbms		0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
331127668Sbms		0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
332127668Sbms		0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
333127668Sbms		0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
334127668Sbms	};
335127668Sbms	int prefix_len = 32;
336127668Sbms
337127668Sbms	/* let's see if we can transform the mask into a prefixlen */
338127668Sbms	while (prefix_len >= 0) {
339127668Sbms		if (bitmasks[prefix_len] == mask)
340127668Sbms			break;
341127668Sbms		prefix_len--;
342127668Sbms	}
343127668Sbms	return (prefix_len);
344127668Sbms}
345127668Sbms
34617680Spst/* VARARGS */
34775115Sfennervoid
34817680Spsterror(const char *fmt, ...)
34917680Spst{
35017680Spst	va_list ap;
35117680Spst
35217680Spst	(void)fprintf(stderr, "%s: ", program_name);
35317680Spst	va_start(ap, fmt);
35417680Spst	(void)vfprintf(stderr, fmt, ap);
35517680Spst	va_end(ap);
35617680Spst	if (*fmt) {
35717680Spst		fmt += strlen(fmt);
35817680Spst		if (fmt[-1] != '\n')
35917680Spst			(void)fputc('\n', stderr);
36017680Spst	}
36117680Spst	exit(1);
36217680Spst	/* NOTREACHED */
36317680Spst}
36417680Spst
36517680Spst/* VARARGS */
36617680Spstvoid
36717680Spstwarning(const char *fmt, ...)
36817680Spst{
36917680Spst	va_list ap;
37017680Spst
37117680Spst	(void)fprintf(stderr, "%s: WARNING: ", program_name);
37217680Spst	va_start(ap, fmt);
37317680Spst	(void)vfprintf(stderr, fmt, ap);
37417680Spst	va_end(ap);
37517680Spst	if (*fmt) {
37617680Spst		fmt += strlen(fmt);
37717680Spst		if (fmt[-1] != '\n')
37817680Spst			(void)fputc('\n', stderr);
37917680Spst	}
38017680Spst}
38117680Spst
38217680Spst/*
38317680Spst * Copy arg vector into a new buffer, concatenating arguments with spaces.
38417680Spst */
38517680Spstchar *
38617680Spstcopy_argv(register char **argv)
38717680Spst{
38817680Spst	register char **p;
38917680Spst	register u_int len = 0;
39017680Spst	char *buf;
39117680Spst	char *src, *dst;
39217680Spst
39317680Spst	p = argv;
39417680Spst	if (*p == 0)
39517680Spst		return 0;
39617680Spst
39717680Spst	while (*p)
39817680Spst		len += strlen(*p++) + 1;
39917680Spst
40017680Spst	buf = (char *)malloc(len);
40117680Spst	if (buf == NULL)
40217680Spst		error("copy_argv: malloc");
40317680Spst
40417680Spst	p = argv;
40517680Spst	dst = buf;
40617680Spst	while ((src = *p++) != NULL) {
40717680Spst		while ((*dst++ = *src++) != '\0')
40817680Spst			;
40917680Spst		dst[-1] = ' ';
41017680Spst	}
41117680Spst	dst[-1] = '\0';
41217680Spst
41317680Spst	return buf;
41417680Spst}
41517680Spst
416127668Sbms/*
417127668Sbms * On Windows, we need to open the file in binary mode, so that
418127668Sbms * we get all the bytes specified by the size we get from "fstat()".
419127668Sbms * On UNIX, that's not necessary.  O_BINARY is defined on Windows;
420127668Sbms * we define it as 0 if it's not defined, so it does nothing.
421127668Sbms */
422127668Sbms#ifndef O_BINARY
423127668Sbms#define O_BINARY	0
424127668Sbms#endif
425127668Sbms
42617680Spstchar *
42717680Spstread_infile(char *fname)
42817680Spst{
429127668Sbms	register int i, fd, cc;
43017680Spst	register char *cp;
43117680Spst	struct stat buf;
43217680Spst
433127668Sbms	fd = open(fname, O_RDONLY|O_BINARY);
43417680Spst	if (fd < 0)
43517680Spst		error("can't open %s: %s", fname, pcap_strerror(errno));
43617680Spst
43717680Spst	if (fstat(fd, &buf) < 0)
43817680Spst		error("can't stat %s: %s", fname, pcap_strerror(errno));
43917680Spst
44017680Spst	cp = malloc((u_int)buf.st_size + 1);
44198524Sfenner	if (cp == NULL)
44298524Sfenner		error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
44398524Sfenner			fname, pcap_strerror(errno));
44498524Sfenner	cc = read(fd, cp, (u_int)buf.st_size);
44517680Spst	if (cc < 0)
44617680Spst		error("read %s: %s", fname, pcap_strerror(errno));
44717680Spst	if (cc != buf.st_size)
44817680Spst		error("short read %s (%d != %d)", fname, cc, (int)buf.st_size);
44917680Spst
450127668Sbms	close(fd);
451127668Sbms	/* replace "# comment" with spaces */
452127668Sbms	for (i = 0; i < cc; i++) {
453127668Sbms		if (cp[i] == '#')
454127668Sbms			while (i < cc && cp[i] != '\n')
455127668Sbms				cp[i++] = ' ';
456127668Sbms	}
457127668Sbms	cp[cc] = '\0';
45817680Spst	return (cp);
45917680Spst}
46075115Sfenner
46175115Sfennervoid
46275115Sfennersafeputs(const char *s)
46375115Sfenner{
46475115Sfenner	while (*s) {
46575115Sfenner		safeputchar(*s);
46675115Sfenner		s++;
46775115Sfenner	}
46875115Sfenner}
46975115Sfenner
47075115Sfennervoid
47175115Sfennersafeputchar(int c)
47275115Sfenner{
47375115Sfenner	unsigned char ch;
47475115Sfenner
47575115Sfenner	ch = (unsigned char)(c & 0xff);
476111726Sfenner	if (ch < 0x80 && isprint(ch))
477111726Sfenner		printf("%c", ch);
47875115Sfenner	else
479111726Sfenner		printf("\\%03o", ch);
48075115Sfenner}
481