]> The Tcpdump Group git mirrors - tcpdump/blob - util.c
Don't dump core if a null "struct tok" array pointer is passed to
[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.95.2.1 2005-04-25 16:15:07 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 hex_print(ident,cp,len);
212 return(1); /* everything is ok */
213 }
214
215 /*
216 * Convert a token value to a string; use "fmt" if not found.
217 */
218 const char *
219 tok2strbuf(register const struct tok *lp, register const char *fmt,
220 register int v, char *buf, size_t bufsize)
221 {
222 if (lp != NULL) {
223 while (lp->s != NULL) {
224 if (lp->v == v)
225 return (lp->s);
226 ++lp;
227 }
228 }
229 if (fmt == NULL)
230 fmt = "#%d";
231
232 (void)snprintf(buf, bufsize, fmt, v);
233 return (const char *)buf;
234 }
235
236 /*
237 * Convert a token value to a string; use "fmt" if not found.
238 */
239 const char *
240 tok2str(register const struct tok *lp, register const char *fmt,
241 register int v)
242 {
243 static char buf[4][128];
244 static int idx = 0;
245 char *ret;
246
247 ret = buf[idx];
248 idx = (idx+1) & 3;
249 return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0]));
250 }
251
252 /*
253 * Convert a bit token value to a string; use "fmt" if not found.
254 * this is useful for parsing bitfields, the output strings are comma seperated
255 */
256 char *
257 bittok2str(register const struct tok *lp, register const char *fmt,
258 register int v)
259 {
260 static char buf[256]; /* our stringbuffer */
261 int buflen=0;
262 register int rotbit; /* this is the bit we rotate through all bitpositions */
263 register int tokval;
264
265 while (lp->s != NULL && lp != NULL) {
266 tokval=lp->v; /* load our first value */
267 rotbit=1;
268 while (rotbit != 0) {
269 /*
270 * lets AND the rotating bit with our token value
271 * and see if we have got a match
272 */
273 if (tokval == (v&rotbit)) {
274 /* ok we have found something */
275 buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s, ",lp->s);
276 break;
277 }
278 rotbit=rotbit<<1; /* no match - lets shift and try again */
279 }
280 lp++;
281 }
282
283 if (buflen != 0) { /* did we find anything */
284 /* yep, set the the trailing zero 2 bytes before to eliminate the last comma & whitespace */
285 buf[buflen-2] = '\0';
286 return (buf);
287 }
288 else {
289 /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
290 if (fmt == NULL)
291 fmt = "#%d";
292 (void)snprintf(buf, sizeof(buf), fmt, v);
293 return (buf);
294 }
295 }
296
297 /*
298 * Convert a value to a string using an array; the macro
299 * tok2strary() in <interface.h> is the public interface to
300 * this function and ensures that the second argument is
301 * correct for bounds-checking.
302 */
303 const char *
304 tok2strary_internal(register const char **lp, int n, register const char *fmt,
305 register int v)
306 {
307 static char buf[128];
308
309 if (v >= 0 && v < n && lp[v] != NULL)
310 return lp[v];
311 if (fmt == NULL)
312 fmt = "#%d";
313 (void)snprintf(buf, sizeof(buf), fmt, v);
314 return (buf);
315 }
316
317 /*
318 * Convert a 32-bit netmask to prefixlen if possible
319 * the function returns the prefix-len; if plen == -1
320 * then conversion was not possible;
321 */
322
323 int
324 mask2plen (u_int32_t mask)
325 {
326 u_int32_t bitmasks[33] = {
327 0x00000000,
328 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
329 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
330 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
331 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
332 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
333 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
334 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
335 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
336 };
337 int prefix_len = 32;
338
339 /* let's see if we can transform the mask into a prefixlen */
340 while (prefix_len >= 0) {
341 if (bitmasks[prefix_len] == mask)
342 break;
343 prefix_len--;
344 }
345 return (prefix_len);
346 }
347
348 /* VARARGS */
349 void
350 error(const char *fmt, ...)
351 {
352 va_list ap;
353
354 (void)fprintf(stderr, "%s: ", program_name);
355 va_start(ap, fmt);
356 (void)vfprintf(stderr, fmt, ap);
357 va_end(ap);
358 if (*fmt) {
359 fmt += strlen(fmt);
360 if (fmt[-1] != '\n')
361 (void)fputc('\n', stderr);
362 }
363 exit(1);
364 /* NOTREACHED */
365 }
366
367 /* VARARGS */
368 void
369 warning(const char *fmt, ...)
370 {
371 va_list ap;
372
373 (void)fprintf(stderr, "%s: WARNING: ", program_name);
374 va_start(ap, fmt);
375 (void)vfprintf(stderr, fmt, ap);
376 va_end(ap);
377 if (*fmt) {
378 fmt += strlen(fmt);
379 if (fmt[-1] != '\n')
380 (void)fputc('\n', stderr);
381 }
382 }
383
384 /*
385 * Copy arg vector into a new buffer, concatenating arguments with spaces.
386 */
387 char *
388 copy_argv(register char **argv)
389 {
390 register char **p;
391 register u_int len = 0;
392 char *buf;
393 char *src, *dst;
394
395 p = argv;
396 if (*p == 0)
397 return 0;
398
399 while (*p)
400 len += strlen(*p++) + 1;
401
402 buf = (char *)malloc(len);
403 if (buf == NULL)
404 error("copy_argv: malloc");
405
406 p = argv;
407 dst = buf;
408 while ((src = *p++) != NULL) {
409 while ((*dst++ = *src++) != '\0')
410 ;
411 dst[-1] = ' ';
412 }
413 dst[-1] = '\0';
414
415 return buf;
416 }
417
418 /*
419 * On Windows, we need to open the file in binary mode, so that
420 * we get all the bytes specified by the size we get from "fstat()".
421 * On UNIX, that's not necessary. O_BINARY is defined on Windows;
422 * we define it as 0 if it's not defined, so it does nothing.
423 */
424 #ifndef O_BINARY
425 #define O_BINARY 0
426 #endif
427
428 char *
429 read_infile(char *fname)
430 {
431 register int i, fd, cc;
432 register char *cp;
433 struct stat buf;
434
435 fd = open(fname, O_RDONLY|O_BINARY);
436 if (fd < 0)
437 error("can't open %s: %s", fname, pcap_strerror(errno));
438
439 if (fstat(fd, &buf) < 0)
440 error("can't stat %s: %s", fname, pcap_strerror(errno));
441
442 cp = malloc((u_int)buf.st_size + 1);
443 if (cp == NULL)
444 error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
445 fname, pcap_strerror(errno));
446 cc = read(fd, cp, (u_int)buf.st_size);
447 if (cc < 0)
448 error("read %s: %s", fname, pcap_strerror(errno));
449 if (cc != buf.st_size)
450 error("short read %s (%d != %d)", fname, cc, (int)buf.st_size);
451
452 close(fd);
453 /* replace "# comment" with spaces */
454 for (i = 0; i < cc; i++) {
455 if (cp[i] == '#')
456 while (i < cc && cp[i] != '\n')
457 cp[i++] = ' ';
458 }
459 cp[cc] = '\0';
460 return (cp);
461 }
462
463 void
464 safeputs(const char *s)
465 {
466 while (*s) {
467 safeputchar(*s);
468 s++;
469 }
470 }
471
472 void
473 safeputchar(int c)
474 {
475 unsigned char ch;
476
477 ch = (unsigned char)(c & 0xff);
478 if (ch < 0x80 && isprint(ch))
479 printf("%c", ch);
480 else
481 printf("\\%03o", ch);
482 }