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