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