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