]> The Tcpdump Group git mirrors - tcpdump/blob - util.c
remove tcpdump's own CVS keywords
[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 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <tcpdump-stdinc.h>
27
28 #include <sys/stat.h>
29
30 #include <errno.h>
31 #ifdef HAVE_FCNTL_H
32 #include <fcntl.h>
33 #endif
34 #include <pcap.h>
35 #include <stdio.h>
36 #include <stdarg.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 #include "interface.h"
41
42 char * ts_format(register int, register int);
43
44 /*
45 * Print out a null-terminated filename (or other ascii string).
46 * If ep is NULL, assume no truncation check is needed.
47 * Return true if truncated.
48 */
49 int
50 fn_print(register const u_char *s, register const u_char *ep)
51 {
52 register int ret;
53 register u_char c;
54
55 ret = 1; /* assume truncated */
56 while (ep == NULL || s < ep) {
57 c = *s++;
58 if (c == '\0') {
59 ret = 0;
60 break;
61 }
62 if (!isascii(c)) {
63 c = toascii(c);
64 putchar('M');
65 putchar('-');
66 }
67 if (!isprint(c)) {
68 c ^= 0x40; /* DEL to ?, others to alpha */
69 putchar('^');
70 }
71 putchar(c);
72 }
73 return(ret);
74 }
75
76 /*
77 * Print out a counted filename (or other ascii string).
78 * If ep is NULL, assume no truncation check is needed.
79 * Return true if truncated.
80 */
81 int
82 fn_printn(register const u_char *s, register u_int n,
83 register const u_char *ep)
84 {
85 register u_char c;
86
87 while (n > 0 && (ep == NULL || s < ep)) {
88 n--;
89 c = *s++;
90 if (!isascii(c)) {
91 c = toascii(c);
92 putchar('M');
93 putchar('-');
94 }
95 if (!isprint(c)) {
96 c ^= 0x40; /* DEL to ?, others to alpha */
97 putchar('^');
98 }
99 putchar(c);
100 }
101 return (n == 0) ? 0 : 1;
102 }
103
104 /*
105 * Print out a null-padded filename (or other ascii string).
106 * If ep is NULL, assume no truncation check is needed.
107 * Return true if truncated.
108 */
109 int
110 fn_printzp(register const u_char *s, register u_int n,
111 register const u_char *ep)
112 {
113 register int ret;
114 register u_char c;
115
116 ret = 1; /* assume truncated */
117 while (n > 0 && (ep == NULL || s < ep)) {
118 n--;
119 c = *s++;
120 if (c == '\0') {
121 ret = 0;
122 break;
123 }
124 if (!isascii(c)) {
125 c = toascii(c);
126 putchar('M');
127 putchar('-');
128 }
129 if (!isprint(c)) {
130 c ^= 0x40; /* DEL to ?, others to alpha */
131 putchar('^');
132 }
133 putchar(c);
134 }
135 return (n == 0) ? 0 : ret;
136 }
137
138 /*
139 * Format the timestamp
140 */
141 char *
142 ts_format(register int sec, register int usec)
143 {
144 static char buf[sizeof("00:00:00.000000")];
145 (void)snprintf(buf, sizeof(buf), "%02d:%02d:%02d.%06u",
146 sec / 3600, (sec % 3600) / 60, sec % 60, usec);
147
148 return buf;
149 }
150
151 /*
152 * Print the timestamp
153 */
154 void
155 ts_print(register const struct timeval *tvp)
156 {
157 register int s;
158 struct tm *tm;
159 time_t Time;
160 static unsigned b_sec;
161 static unsigned b_usec;
162 int d_usec;
163 int d_sec;
164
165 switch (tflag) {
166
167 case 0: /* Default */
168 s = (tvp->tv_sec + thiszone) % 86400;
169 (void)printf("%s ", ts_format(s, tvp->tv_usec));
170 break;
171
172 case 1: /* No time stamp */
173 break;
174
175 case 2: /* Unix timeval style */
176 (void)printf("%u.%06u ",
177 (unsigned)tvp->tv_sec,
178 (unsigned)tvp->tv_usec);
179 break;
180
181 case 3: /* Microseconds since previous packet */
182 case 5: /* Microseconds since first packet */
183 if (b_sec == 0) {
184 /* init timestamp for first packet */
185 b_usec = tvp->tv_usec;
186 b_sec = tvp->tv_sec;
187 }
188
189 d_usec = tvp->tv_usec - b_usec;
190 d_sec = tvp->tv_sec - b_sec;
191
192 while (d_usec < 0) {
193 d_usec += 1000000;
194 d_sec--;
195 }
196
197 (void)printf("%s ", ts_format(d_sec, d_usec));
198
199 if (tflag == 3) { /* set timestamp for last packet */
200 b_sec = tvp->tv_sec;
201 b_usec = tvp->tv_usec;
202 }
203 break;
204
205 case 4: /* Default + Date*/
206 s = (tvp->tv_sec + thiszone) % 86400;
207 Time = (tvp->tv_sec + thiszone) - s;
208 tm = gmtime (&Time);
209 if (!tm)
210 printf("Date fail ");
211 else
212 printf("%04d-%02d-%02d %s ",
213 tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
214 ts_format(s, tvp->tv_usec));
215 break;
216 }
217 }
218
219 /*
220 * Print a relative number of seconds (e.g. hold time, prune timer)
221 * in the form 5m1s. This does no truncation, so 32230861 seconds
222 * is represented as 1y1w1d1h1m1s.
223 */
224 void
225 relts_print(int secs)
226 {
227 static const char *lengths[] = {"y", "w", "d", "h", "m", "s"};
228 static const int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
229 const char **l = lengths;
230 const int *s = seconds;
231
232 if (secs == 0) {
233 (void)printf("0s");
234 return;
235 }
236 if (secs < 0) {
237 (void)printf("-");
238 secs = -secs;
239 }
240 while (secs > 0) {
241 if (secs >= *s) {
242 (void)printf("%d%s", secs / *s, *l);
243 secs -= (secs / *s) * *s;
244 }
245 s++;
246 l++;
247 }
248 }
249
250 /*
251 * this is a generic routine for printing unknown data;
252 * we pass on the linefeed plus indentation string to
253 * get a proper output - returns 0 on error
254 */
255
256 int
257 print_unknown_data(netdissect_options *ndo, const u_char *cp,const char *ident,int len)
258 {
259 if (len < 0) {
260 ND_PRINT((ndo,"%sDissector error: print_unknown_data called with negative length",
261 ident));
262 return(0);
263 }
264 if (snapend - cp < len)
265 len = snapend - cp;
266 if (len < 0) {
267 ND_PRINT((ndo,"%sDissector error: print_unknown_data called with pointer past end of packet",
268 ident));
269 return(0);
270 }
271 hex_print(ndo, ident,cp,len);
272 return(1); /* everything is ok */
273 }
274
275 /*
276 * Convert a token value to a string; use "fmt" if not found.
277 */
278 const char *
279 tok2strbuf(register const struct tok *lp, register const char *fmt,
280 register int v, char *buf, size_t bufsize)
281 {
282 if (lp != NULL) {
283 while (lp->s != NULL) {
284 if (lp->v == v)
285 return (lp->s);
286 ++lp;
287 }
288 }
289 if (fmt == NULL)
290 fmt = "#%d";
291
292 (void)snprintf(buf, bufsize, fmt, v);
293 return (const char *)buf;
294 }
295
296 /*
297 * Convert a token value to a string; use "fmt" if not found.
298 */
299 const char *
300 tok2str(register const struct tok *lp, register const char *fmt,
301 register int v)
302 {
303 static char buf[4][128];
304 static int idx = 0;
305 char *ret;
306
307 ret = buf[idx];
308 idx = (idx+1) & 3;
309 return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0]));
310 }
311
312 /*
313 * Convert a bit token value to a string; use "fmt" if not found.
314 * this is useful for parsing bitfields, the output strings are seperated
315 * if the s field is positive.
316 */
317 static char *
318 bittok2str_internal(register const struct tok *lp, register const char *fmt,
319 register int v, register int sep)
320 {
321 static char buf[256]; /* our stringbuffer */
322 int buflen=0;
323 register int rotbit; /* this is the bit we rotate through all bitpositions */
324 register int tokval;
325
326 while (lp != NULL && lp->s != NULL) {
327 tokval=lp->v; /* load our first value */
328 rotbit=1;
329 while (rotbit != 0) {
330 /*
331 * lets AND the rotating bit with our token value
332 * and see if we have got a match
333 */
334 if (tokval == (v&rotbit)) {
335 /* ok we have found something */
336 buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s%s",
337 lp->s, sep ? ", " : "");
338 break;
339 }
340 rotbit=rotbit<<1; /* no match - lets shift and try again */
341 }
342 lp++;
343 }
344
345 /* user didn't want string seperation - no need to cut off trailing seperators */
346 if (!sep) {
347 return (buf);
348 }
349
350 if (buflen != 0) { /* did we find anything */
351 /* yep, set the the trailing zero 2 bytes before to eliminate the last comma & whitespace */
352 buf[buflen-2] = '\0';
353 return (buf);
354 }
355 else {
356 /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
357 if (fmt == NULL)
358 fmt = "#%d";
359 (void)snprintf(buf, sizeof(buf), fmt, v);
360 return (buf);
361 }
362 }
363
364 /*
365 * Convert a bit token value to a string; use "fmt" if not found.
366 * this is useful for parsing bitfields, the output strings are not seperated.
367 */
368 char *
369 bittok2str_nosep(register const struct tok *lp, register const char *fmt,
370 register int v)
371 {
372 return (bittok2str_internal(lp, fmt, v, 0));
373 }
374
375 /*
376 * Convert a bit token value to a string; use "fmt" if not found.
377 * this is useful for parsing bitfields, the output strings are comma seperated.
378 */
379 char *
380 bittok2str(register const struct tok *lp, register const char *fmt,
381 register int v)
382 {
383 return (bittok2str_internal(lp, fmt, v, 1));
384 }
385
386 /*
387 * Convert a value to a string using an array; the macro
388 * tok2strary() in <interface.h> is the public interface to
389 * this function and ensures that the second argument is
390 * correct for bounds-checking.
391 */
392 const char *
393 tok2strary_internal(register const char **lp, int n, register const char *fmt,
394 register int v)
395 {
396 static char buf[128];
397
398 if (v >= 0 && v < n && lp[v] != NULL)
399 return lp[v];
400 if (fmt == NULL)
401 fmt = "#%d";
402 (void)snprintf(buf, sizeof(buf), fmt, v);
403 return (buf);
404 }
405
406 /*
407 * Convert a 32-bit netmask to prefixlen if possible
408 * the function returns the prefix-len; if plen == -1
409 * then conversion was not possible;
410 */
411
412 int
413 mask2plen(u_int32_t mask)
414 {
415 u_int32_t bitmasks[33] = {
416 0x00000000,
417 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
418 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
419 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
420 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
421 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
422 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
423 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
424 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
425 };
426 int prefix_len = 32;
427
428 /* let's see if we can transform the mask into a prefixlen */
429 while (prefix_len >= 0) {
430 if (bitmasks[prefix_len] == mask)
431 break;
432 prefix_len--;
433 }
434 return (prefix_len);
435 }
436
437 #ifdef INET6
438 int
439 mask62plen(const u_char *mask)
440 {
441 u_char bitmasks[9] = {
442 0x00,
443 0x80, 0xc0, 0xe0, 0xf0,
444 0xf8, 0xfc, 0xfe, 0xff
445 };
446 int byte;
447 int cidr_len = 0;
448
449 for (byte = 0; byte < 16; byte++) {
450 u_int bits;
451
452 for (bits = 0; bits < (sizeof (bitmasks) / sizeof (bitmasks[0])); bits++) {
453 if (mask[byte] == bitmasks[bits]) {
454 cidr_len += bits;
455 break;
456 }
457 }
458
459 if (mask[byte] != 0xff)
460 break;
461 }
462 return (cidr_len);
463 }
464 #endif /* INET6 */
465
466 /* VARARGS */
467 void
468 error(const char *fmt, ...)
469 {
470 va_list ap;
471
472 (void)fprintf(stderr, "%s: ", program_name);
473 va_start(ap, fmt);
474 (void)vfprintf(stderr, fmt, ap);
475 va_end(ap);
476 if (*fmt) {
477 fmt += strlen(fmt);
478 if (fmt[-1] != '\n')
479 (void)fputc('\n', stderr);
480 }
481 exit(1);
482 /* NOTREACHED */
483 }
484
485 /* VARARGS */
486 void
487 warning(const char *fmt, ...)
488 {
489 va_list ap;
490
491 (void)fprintf(stderr, "%s: WARNING: ", program_name);
492 va_start(ap, fmt);
493 (void)vfprintf(stderr, fmt, ap);
494 va_end(ap);
495 if (*fmt) {
496 fmt += strlen(fmt);
497 if (fmt[-1] != '\n')
498 (void)fputc('\n', stderr);
499 }
500 }
501
502 /*
503 * Copy arg vector into a new buffer, concatenating arguments with spaces.
504 */
505 char *
506 copy_argv(register char **argv)
507 {
508 register char **p;
509 register u_int len = 0;
510 char *buf;
511 char *src, *dst;
512
513 p = argv;
514 if (*p == 0)
515 return 0;
516
517 while (*p)
518 len += strlen(*p++) + 1;
519
520 buf = (char *)malloc(len);
521 if (buf == NULL)
522 error("copy_argv: malloc");
523
524 p = argv;
525 dst = buf;
526 while ((src = *p++) != NULL) {
527 while ((*dst++ = *src++) != '\0')
528 ;
529 dst[-1] = ' ';
530 }
531 dst[-1] = '\0';
532
533 return buf;
534 }
535
536 /*
537 * On Windows, we need to open the file in binary mode, so that
538 * we get all the bytes specified by the size we get from "fstat()".
539 * On UNIX, that's not necessary. O_BINARY is defined on Windows;
540 * we define it as 0 if it's not defined, so it does nothing.
541 */
542 #ifndef O_BINARY
543 #define O_BINARY 0
544 #endif
545
546 char *
547 read_infile(char *fname)
548 {
549 register int i, fd, cc;
550 register char *cp;
551 struct stat buf;
552
553 fd = open(fname, O_RDONLY|O_BINARY);
554 if (fd < 0)
555 error("can't open %s: %s", fname, pcap_strerror(errno));
556
557 if (fstat(fd, &buf) < 0)
558 error("can't stat %s: %s", fname, pcap_strerror(errno));
559
560 cp = malloc((u_int)buf.st_size + 1);
561 if (cp == NULL)
562 error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
563 fname, pcap_strerror(errno));
564 cc = read(fd, cp, (u_int)buf.st_size);
565 if (cc < 0)
566 error("read %s: %s", fname, pcap_strerror(errno));
567 if (cc != buf.st_size)
568 error("short read %s (%d != %d)", fname, cc, (int)buf.st_size);
569
570 close(fd);
571 /* replace "# comment" with spaces */
572 for (i = 0; i < cc; i++) {
573 if (cp[i] == '#')
574 while (i < cc && cp[i] != '\n')
575 cp[i++] = ' ';
576 }
577 cp[cc] = '\0';
578 return (cp);
579 }
580
581 void
582 safeputs(const char *s, int maxlen)
583 {
584 int idx = 0;
585
586 while (*s && idx < maxlen) {
587 safeputchar(*s);
588 idx++;
589 s++;
590 }
591 }
592
593 void
594 safeputchar(int c)
595 {
596 unsigned char ch;
597
598 ch = (unsigned char)(c & 0xff);
599 if (ch < 0x80 && isprint(ch))
600 printf("%c", ch);
601 else
602 printf("\\0x%02x", ch);
603 }