util.c revision 147899
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_ =
24147899Ssam    "@(#) $Header: /tcpdump/master/tcpdump/util.c,v 1.95.2.5 2005/06/16 01:19:57 guy 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/*
48147899Ssam * Print out a null-terminated 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/*
108147899Ssam * Print out a null-padded filename (or other ascii string).
109147899Ssam * If ep is NULL, assume no truncation check is needed.
110147899Ssam * Return true if truncated.
111147899Ssam */
112147899Ssamint
113147899Ssamfn_printzp(register const u_char *s, register u_int n,
114147899Ssam	  register const u_char *ep)
115147899Ssam{
116147899Ssam	register int ret;
117147899Ssam	register u_char c;
118147899Ssam
119147899Ssam	ret = 1;			/* assume truncated */
120147899Ssam	while (n > 0 && (ep == NULL || s < ep)) {
121147899Ssam		n--;
122147899Ssam		c = *s++;
123147899Ssam		if (c == '\0') {
124147899Ssam			ret = 0;
125147899Ssam			break;
126147899Ssam		}
127147899Ssam		if (!isascii(c)) {
128147899Ssam			c = toascii(c);
129147899Ssam			putchar('M');
130147899Ssam			putchar('-');
131147899Ssam		}
132147899Ssam		if (!isprint(c)) {
133147899Ssam			c ^= 0x40;	/* DEL to ?, others to alpha */
134147899Ssam			putchar('^');
135147899Ssam		}
136147899Ssam		putchar(c);
137147899Ssam	}
138147899Ssam	return (n == 0) ? 0 : ret;
139147899Ssam}
140147899Ssam
141147899Ssam/*
14217680Spst * Print the timestamp
14317680Spst */
14417680Spstvoid
14517680Spstts_print(register const struct timeval *tvp)
14617680Spst{
14717680Spst	register int s;
14875115Sfenner	struct tm *tm;
14975115Sfenner	time_t Time;
15075115Sfenner	static unsigned b_sec;
15175115Sfenner	static unsigned b_usec;
15217680Spst
153146773Ssam	switch (tflag) {
154146773Ssam
155146773Ssam	case 0: /* Default */
15617680Spst		s = (tvp->tv_sec + thiszone) % 86400;
15717680Spst		(void)printf("%02d:%02d:%02d.%06u ",
15875115Sfenner			     s / 3600, (s % 3600) / 60, s % 60,
15975115Sfenner			     (unsigned)tvp->tv_usec);
16075115Sfenner		break;
161146773Ssam
162146773Ssam	case 1: /* No time stamp */
163146773Ssam		break;
164146773Ssam
165146773Ssam	case 2: /* Unix timeval style */
16675115Sfenner		(void)printf("%u.%06u ",
16775115Sfenner			     (unsigned)tvp->tv_sec,
16875115Sfenner			     (unsigned)tvp->tv_usec);
16975115Sfenner		break;
170146773Ssam
171146773Ssam	case 3: /* Microseconds since previous packet */
17275115Sfenner		if (b_sec == 0) {
17375115Sfenner			printf("000000 ");
17475115Sfenner		} else {
17575115Sfenner			int d_usec = tvp->tv_usec - b_usec;
17675115Sfenner			int d_sec = tvp->tv_sec - b_sec;
177127668Sbms
17875115Sfenner			while (d_usec < 0) {
17975115Sfenner				d_usec += 1000000;
18075115Sfenner				d_sec--;
18156893Sfenner			}
18275115Sfenner			if (d_sec)
18375115Sfenner				printf("%d. ", d_sec);
18475115Sfenner			printf("%06d ", d_usec);
18556893Sfenner		}
18675115Sfenner		b_sec = tvp->tv_sec;
18775115Sfenner		b_usec = tvp->tv_usec;
18875115Sfenner		break;
189146773Ssam
190146773Ssam	case 4: /* Default + Date*/
19175115Sfenner		s = (tvp->tv_sec + thiszone) % 86400;
19275115Sfenner		Time = (tvp->tv_sec + thiszone) - s;
193127668Sbms		tm = gmtime (&Time);
194127668Sbms		if (!tm)
195127668Sbms			printf("Date fail  ");
196127668Sbms		else
197127668Sbms			printf("%04d-%02d-%02d ",
198127668Sbms				   tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday);
199127668Sbms		printf("%02d:%02d:%02d.%06u ",
200127668Sbms			   s / 3600, (s % 3600) / 60, s % 60, (unsigned)tvp->tv_usec);
20175115Sfenner		break;
20217680Spst	}
20317680Spst}
20417680Spst
20517680Spst/*
20656893Sfenner * Print a relative number of seconds (e.g. hold time, prune timer)
20756893Sfenner * in the form 5m1s.  This does no truncation, so 32230861 seconds
20856893Sfenner * is represented as 1y1w1d1h1m1s.
20956893Sfenner */
21056893Sfennervoid
21156893Sfennerrelts_print(int secs)
21256893Sfenner{
21398524Sfenner	static const char *lengths[] = {"y", "w", "d", "h", "m", "s"};
21498524Sfenner	static const int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
21598524Sfenner	const char **l = lengths;
21698524Sfenner	const int *s = seconds;
21756893Sfenner
21898524Sfenner	if (secs == 0) {
21975115Sfenner		(void)printf("0s");
22075115Sfenner		return;
22156893Sfenner	}
22298524Sfenner	if (secs < 0) {
22398524Sfenner		(void)printf("-");
22498524Sfenner		secs = -secs;
22598524Sfenner	}
22675115Sfenner	while (secs > 0) {
22775115Sfenner		if (secs >= *s) {
22875115Sfenner			(void)printf("%d%s", secs / *s, *l);
22975115Sfenner			secs -= (secs / *s) * *s;
23075115Sfenner		}
23175115Sfenner		s++;
23275115Sfenner		l++;
23375115Sfenner	}
23456893Sfenner}
23556893Sfenner
23656893Sfenner/*
237127668Sbms *  this is a generic routine for printing unknown data;
238127668Sbms *  we pass on the linefeed plus indentation string to
239127668Sbms *  get a proper output - returns 0 on error
240127668Sbms */
241127668Sbms
242127668Sbmsint
243127668Sbmsprint_unknown_data(const u_char *cp,const char *ident,int len)
244127668Sbms{
245147899Ssam	if (len < 0) {
246147899Ssam		printf("%sDissector error: print_unknown_data called with negative length",
247147899Ssam		    ident);
248147899Ssam		return(0);
249147899Ssam	}
250147899Ssam	if (snapend - cp < len)
251147899Ssam		len = snapend - cp;
252147899Ssam	if (len < 0) {
253147899Ssam		printf("%sDissector error: print_unknown_data called with pointer past end of packet",
254147899Ssam		    ident);
255147899Ssam		return(0);
256147899Ssam	}
257127668Sbms        hex_print(ident,cp,len);
258127668Sbms	return(1); /* everything is ok */
259127668Sbms}
260127668Sbms
261127668Sbms/*
26217680Spst * Convert a token value to a string; use "fmt" if not found.
26317680Spst */
26417680Spstconst char *
265146773Ssamtok2strbuf(register const struct tok *lp, register const char *fmt,
266146773Ssam	   register int v, char *buf, size_t bufsize)
26717680Spst{
268147899Ssam	if (lp != NULL) {
269147899Ssam		while (lp->s != NULL) {
270147899Ssam			if (lp->v == v)
271147899Ssam				return (lp->s);
272147899Ssam			++lp;
273147899Ssam		}
27417680Spst	}
27517680Spst	if (fmt == NULL)
27617680Spst		fmt = "#%d";
277146773Ssam
278146773Ssam	(void)snprintf(buf, bufsize, fmt, v);
279146773Ssam	return (const char *)buf;
28017680Spst}
28117680Spst
28298524Sfenner/*
283146773Ssam * Convert a token value to a string; use "fmt" if not found.
284146773Ssam */
285146773Ssamconst char *
286146773Ssamtok2str(register const struct tok *lp, register const char *fmt,
287146773Ssam	register int v)
288146773Ssam{
289146773Ssam	static char buf[4][128];
290146773Ssam	static int idx = 0;
291146773Ssam	char *ret;
292146773Ssam
293146773Ssam	ret = buf[idx];
294146773Ssam	idx = (idx+1) & 3;
295146773Ssam	return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0]));
296146773Ssam}
297146773Ssam
298146773Ssam/*
299127668Sbms * Convert a bit token value to a string; use "fmt" if not found.
300127668Sbms * this is useful for parsing bitfields, the output strings are comma seperated
301127668Sbms */
302127668Sbmschar *
303127668Sbmsbittok2str(register const struct tok *lp, register const char *fmt,
304146773Ssam	   register int v)
305127668Sbms{
306127668Sbms        static char buf[256]; /* our stringbuffer */
307127668Sbms        int buflen=0;
308127668Sbms        register int rotbit; /* this is the bit we rotate through all bitpositions */
309127668Sbms        register int tokval;
310127668Sbms
311146773Ssam	while (lp->s != NULL && lp != NULL) {
312127668Sbms            tokval=lp->v;   /* load our first value */
313127668Sbms            rotbit=1;
314127668Sbms            while (rotbit != 0) {
315127668Sbms                /*
316127668Sbms                 * lets AND the rotating bit with our token value
317127668Sbms                 * and see if we have got a match
318127668Sbms                 */
319127668Sbms		if (tokval == (v&rotbit)) {
320127668Sbms                    /* ok we have found something */
321127668Sbms                    buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s, ",lp->s);
322127668Sbms                    break;
323127668Sbms                }
324127668Sbms                rotbit=rotbit<<1; /* no match - lets shift and try again */
325127668Sbms            }
326127668Sbms            lp++;
327127668Sbms	}
328127668Sbms
329127668Sbms        if (buflen != 0) { /* did we find anything */
330127668Sbms            /* yep, set the the trailing zero 2 bytes before to eliminate the last comma & whitespace */
331127668Sbms            buf[buflen-2] = '\0';
332127668Sbms            return (buf);
333127668Sbms        }
334127668Sbms        else {
335127668Sbms            /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
336127668Sbms            if (fmt == NULL)
337127668Sbms		fmt = "#%d";
338127668Sbms            (void)snprintf(buf, sizeof(buf), fmt, v);
339127668Sbms            return (buf);
340127668Sbms        }
341127668Sbms}
342127668Sbms
343127668Sbms/*
34498524Sfenner * Convert a value to a string using an array; the macro
34598524Sfenner * tok2strary() in <interface.h> is the public interface to
34698524Sfenner * this function and ensures that the second argument is
34798524Sfenner * correct for bounds-checking.
34898524Sfenner */
34998524Sfennerconst char *
35098524Sfennertok2strary_internal(register const char **lp, int n, register const char *fmt,
35198524Sfenner	register int v)
35298524Sfenner{
35398524Sfenner	static char buf[128];
35417680Spst
35598524Sfenner	if (v >= 0 && v < n && lp[v] != NULL)
35698524Sfenner		return lp[v];
35798524Sfenner	if (fmt == NULL)
35898524Sfenner		fmt = "#%d";
35998524Sfenner	(void)snprintf(buf, sizeof(buf), fmt, v);
36098524Sfenner	return (buf);
36198524Sfenner}
36298524Sfenner
363127668Sbms/*
364127668Sbms * Convert a 32-bit netmask to prefixlen if possible
365127668Sbms * the function returns the prefix-len; if plen == -1
366127668Sbms * then conversion was not possible;
367127668Sbms */
368127668Sbms
369127668Sbmsint
370127668Sbmsmask2plen (u_int32_t mask)
371127668Sbms{
372127668Sbms	u_int32_t bitmasks[33] = {
373127668Sbms		0x00000000,
374127668Sbms		0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
375127668Sbms		0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
376127668Sbms		0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
377127668Sbms		0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
378127668Sbms		0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
379127668Sbms		0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
380127668Sbms		0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
381127668Sbms		0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
382127668Sbms	};
383127668Sbms	int prefix_len = 32;
384127668Sbms
385127668Sbms	/* let's see if we can transform the mask into a prefixlen */
386127668Sbms	while (prefix_len >= 0) {
387127668Sbms		if (bitmasks[prefix_len] == mask)
388127668Sbms			break;
389127668Sbms		prefix_len--;
390127668Sbms	}
391127668Sbms	return (prefix_len);
392127668Sbms}
393127668Sbms
39417680Spst/* VARARGS */
39575115Sfennervoid
39617680Spsterror(const char *fmt, ...)
39717680Spst{
39817680Spst	va_list ap;
39917680Spst
40017680Spst	(void)fprintf(stderr, "%s: ", program_name);
40117680Spst	va_start(ap, fmt);
40217680Spst	(void)vfprintf(stderr, fmt, ap);
40317680Spst	va_end(ap);
40417680Spst	if (*fmt) {
40517680Spst		fmt += strlen(fmt);
40617680Spst		if (fmt[-1] != '\n')
40717680Spst			(void)fputc('\n', stderr);
40817680Spst	}
40917680Spst	exit(1);
41017680Spst	/* NOTREACHED */
41117680Spst}
41217680Spst
41317680Spst/* VARARGS */
41417680Spstvoid
41517680Spstwarning(const char *fmt, ...)
41617680Spst{
41717680Spst	va_list ap;
41817680Spst
41917680Spst	(void)fprintf(stderr, "%s: WARNING: ", program_name);
42017680Spst	va_start(ap, fmt);
42117680Spst	(void)vfprintf(stderr, fmt, ap);
42217680Spst	va_end(ap);
42317680Spst	if (*fmt) {
42417680Spst		fmt += strlen(fmt);
42517680Spst		if (fmt[-1] != '\n')
42617680Spst			(void)fputc('\n', stderr);
42717680Spst	}
42817680Spst}
42917680Spst
43017680Spst/*
43117680Spst * Copy arg vector into a new buffer, concatenating arguments with spaces.
43217680Spst */
43317680Spstchar *
43417680Spstcopy_argv(register char **argv)
43517680Spst{
43617680Spst	register char **p;
43717680Spst	register u_int len = 0;
43817680Spst	char *buf;
43917680Spst	char *src, *dst;
44017680Spst
44117680Spst	p = argv;
44217680Spst	if (*p == 0)
44317680Spst		return 0;
44417680Spst
44517680Spst	while (*p)
44617680Spst		len += strlen(*p++) + 1;
44717680Spst
44817680Spst	buf = (char *)malloc(len);
44917680Spst	if (buf == NULL)
45017680Spst		error("copy_argv: malloc");
45117680Spst
45217680Spst	p = argv;
45317680Spst	dst = buf;
45417680Spst	while ((src = *p++) != NULL) {
45517680Spst		while ((*dst++ = *src++) != '\0')
45617680Spst			;
45717680Spst		dst[-1] = ' ';
45817680Spst	}
45917680Spst	dst[-1] = '\0';
46017680Spst
46117680Spst	return buf;
46217680Spst}
46317680Spst
464127668Sbms/*
465127668Sbms * On Windows, we need to open the file in binary mode, so that
466127668Sbms * we get all the bytes specified by the size we get from "fstat()".
467127668Sbms * On UNIX, that's not necessary.  O_BINARY is defined on Windows;
468127668Sbms * we define it as 0 if it's not defined, so it does nothing.
469127668Sbms */
470127668Sbms#ifndef O_BINARY
471127668Sbms#define O_BINARY	0
472127668Sbms#endif
473127668Sbms
47417680Spstchar *
47517680Spstread_infile(char *fname)
47617680Spst{
477127668Sbms	register int i, fd, cc;
47817680Spst	register char *cp;
47917680Spst	struct stat buf;
48017680Spst
481127668Sbms	fd = open(fname, O_RDONLY|O_BINARY);
48217680Spst	if (fd < 0)
48317680Spst		error("can't open %s: %s", fname, pcap_strerror(errno));
48417680Spst
48517680Spst	if (fstat(fd, &buf) < 0)
48617680Spst		error("can't stat %s: %s", fname, pcap_strerror(errno));
48717680Spst
48817680Spst	cp = malloc((u_int)buf.st_size + 1);
48998524Sfenner	if (cp == NULL)
49098524Sfenner		error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
49198524Sfenner			fname, pcap_strerror(errno));
49298524Sfenner	cc = read(fd, cp, (u_int)buf.st_size);
49317680Spst	if (cc < 0)
49417680Spst		error("read %s: %s", fname, pcap_strerror(errno));
49517680Spst	if (cc != buf.st_size)
49617680Spst		error("short read %s (%d != %d)", fname, cc, (int)buf.st_size);
49717680Spst
498127668Sbms	close(fd);
499127668Sbms	/* replace "# comment" with spaces */
500127668Sbms	for (i = 0; i < cc; i++) {
501127668Sbms		if (cp[i] == '#')
502127668Sbms			while (i < cc && cp[i] != '\n')
503127668Sbms				cp[i++] = ' ';
504127668Sbms	}
505127668Sbms	cp[cc] = '\0';
50617680Spst	return (cp);
50717680Spst}
50875115Sfenner
50975115Sfennervoid
51075115Sfennersafeputs(const char *s)
51175115Sfenner{
51275115Sfenner	while (*s) {
51375115Sfenner		safeputchar(*s);
51475115Sfenner		s++;
51575115Sfenner	}
51675115Sfenner}
51775115Sfenner
51875115Sfennervoid
51975115Sfennersafeputchar(int c)
52075115Sfenner{
52175115Sfenner	unsigned char ch;
52275115Sfenner
52375115Sfenner	ch = (unsigned char)(c & 0xff);
524111726Sfenner	if (ch < 0x80 && isprint(ch))
525111726Sfenner		printf("%c", ch);
52675115Sfenner	else
527111726Sfenner		printf("\\%03o", ch);
52875115Sfenner}
529