]> The Tcpdump Group git mirrors - tcpdump/blob - util.c
Introduce --time-stamp-precision
[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 = ndo->ndo_tstamp_precision == PCAP_TSTAMP_PRECISION_NANO ?
142 "%02d:%02d:%02d.%09u" : "%02d:%02d:%02d.%06u";
143
144 snprintf(buf, sizeof(buf), format,
145 sec / 3600, (sec % 3600) / 60, sec % 60, usec);
146
147 return buf;
148 }
149
150 /*
151 * Print the timestamp
152 */
153 void
154 ts_print(netdissect_options *ndo,
155 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 (ndo->ndo_tflag) {
166
167 case 0: /* Default */
168 s = (tvp->tv_sec + thiszone) % 86400;
169 ND_PRINT((ndo, "%s ", ts_format(ndo, s, tvp->tv_usec)));
170 break;
171
172 case 1: /* No time stamp */
173 break;
174
175 case 2: /* Unix timeval style */
176 ND_PRINT((ndo, "%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 ND_PRINT((ndo, "%s ", ts_format(ndo, d_sec, d_usec)));
198
199 if (ndo->ndo_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 ND_PRINT((ndo, "Date fail "));
211 else
212 ND_PRINT((ndo, "%04d-%02d-%02d %s ",
213 tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
214 ts_format(ndo, 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(netdissect_options *ndo,
226 int secs)
227 {
228 static const char *lengths[] = {"y", "w", "d", "h", "m", "s"};
229 static const int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
230 const char **l = lengths;
231 const int *s = seconds;
232
233 if (secs == 0) {
234 ND_PRINT((ndo, "0s"));
235 return;
236 }
237 if (secs < 0) {
238 ND_PRINT((ndo, "-"));
239 secs = -secs;
240 }
241 while (secs > 0) {
242 if (secs >= *s) {
243 ND_PRINT((ndo, "%d%s", secs / *s, *l));
244 secs -= (secs / *s) * *s;
245 }
246 s++;
247 l++;
248 }
249 }
250
251 /*
252 * this is a generic routine for printing unknown data;
253 * we pass on the linefeed plus indentation string to
254 * get a proper output - returns 0 on error
255 */
256
257 int
258 print_unknown_data(netdissect_options *ndo, const u_char *cp,const char *ident,int len)
259 {
260 if (len < 0) {
261 ND_PRINT((ndo,"%sDissector error: print_unknown_data called with negative length",
262 ident));
263 return(0);
264 }
265 if (ndo->ndo_snapend - cp < len)
266 len = ndo->ndo_snapend - cp;
267 if (len < 0) {
268 ND_PRINT((ndo,"%sDissector error: print_unknown_data called with pointer past end of packet",
269 ident));
270 return(0);
271 }
272 hex_print(ndo, ident,cp,len);
273 return(1); /* everything is ok */
274 }
275
276 /*
277 * Convert a token value to a string; use "fmt" if not found.
278 */
279 const char *
280 tok2strbuf(register const struct tok *lp, register const char *fmt,
281 register u_int v, char *buf, size_t bufsize)
282 {
283 if (lp != NULL) {
284 while (lp->s != NULL) {
285 if (lp->v == v)
286 return (lp->s);
287 ++lp;
288 }
289 }
290 if (fmt == NULL)
291 fmt = "#%d";
292
293 (void)snprintf(buf, bufsize, fmt, v);
294 return (const char *)buf;
295 }
296
297 /*
298 * Convert a token value to a string; use "fmt" if not found.
299 */
300 const char *
301 tok2str(register const struct tok *lp, register const char *fmt,
302 register int v)
303 {
304 static char buf[4][128];
305 static int idx = 0;
306 char *ret;
307
308 ret = buf[idx];
309 idx = (idx+1) & 3;
310 return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0]));
311 }
312
313 /*
314 * Convert a bit token value to a string; use "fmt" if not found.
315 * this is useful for parsing bitfields, the output strings are seperated
316 * if the s field is positive.
317 */
318 static char *
319 bittok2str_internal(register const struct tok *lp, register const char *fmt,
320 register int v, register int sep)
321 {
322 static char buf[256]; /* our stringbuffer */
323 int buflen=0;
324 register int rotbit; /* this is the bit we rotate through all bitpositions */
325 register int tokval;
326
327 while (lp != NULL && lp->s != NULL) {
328 tokval=lp->v; /* load our first value */
329 rotbit=1;
330 while (rotbit != 0) {
331 /*
332 * lets AND the rotating bit with our token value
333 * and see if we have got a match
334 */
335 if (tokval == (v&rotbit)) {
336 /* ok we have found something */
337 buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s%s",
338 lp->s, sep ? ", " : "");
339 break;
340 }
341 rotbit=rotbit<<1; /* no match - lets shift and try again */
342 }
343 lp++;
344 }
345
346 /* user didn't want string seperation - no need to cut off trailing seperators */
347 if (!sep) {
348 return (buf);
349 }
350
351 if (buflen != 0) { /* did we find anything */
352 /* yep, set the trailing zero 2 bytes before to eliminate the last comma & whitespace */
353 buf[buflen-2] = '\0';
354 return (buf);
355 }
356 else {
357 /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
358 if (fmt == NULL)
359 fmt = "#%d";
360 (void)snprintf(buf, sizeof(buf), fmt, v);
361 return (buf);
362 }
363 }
364
365 /*
366 * Convert a bit token value to a string; use "fmt" if not found.
367 * this is useful for parsing bitfields, the output strings are not seperated.
368 */
369 char *
370 bittok2str_nosep(register const struct tok *lp, register const char *fmt,
371 register int v)
372 {
373 return (bittok2str_internal(lp, fmt, v, 0));
374 }
375
376 /*
377 * Convert a bit token value to a string; use "fmt" if not found.
378 * this is useful for parsing bitfields, the output strings are comma seperated.
379 */
380 char *
381 bittok2str(register const struct tok *lp, register const char *fmt,
382 register int v)
383 {
384 return (bittok2str_internal(lp, fmt, v, 1));
385 }
386
387 /*
388 * Convert a value to a string using an array; the macro
389 * tok2strary() in <interface.h> is the public interface to
390 * this function and ensures that the second argument is
391 * correct for bounds-checking.
392 */
393 const char *
394 tok2strary_internal(register const char **lp, int n, register const char *fmt,
395 register int v)
396 {
397 static char buf[128];
398
399 if (v >= 0 && v < n && lp[v] != NULL)
400 return lp[v];
401 if (fmt == NULL)
402 fmt = "#%d";
403 (void)snprintf(buf, sizeof(buf), fmt, v);
404 return (buf);
405 }
406
407 /*
408 * Convert a 32-bit netmask to prefixlen if possible
409 * the function returns the prefix-len; if plen == -1
410 * then conversion was not possible;
411 */
412
413 int
414 mask2plen(uint32_t mask)
415 {
416 uint32_t bitmasks[33] = {
417 0x00000000,
418 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
419 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
420 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
421 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
422 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
423 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
424 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
425 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
426 };
427 int prefix_len = 32;
428
429 /* let's see if we can transform the mask into a prefixlen */
430 while (prefix_len >= 0) {
431 if (bitmasks[prefix_len] == mask)
432 break;
433 prefix_len--;
434 }
435 return (prefix_len);
436 }
437
438 #ifdef INET6
439 int
440 mask62plen(const u_char *mask)
441 {
442 u_char bitmasks[9] = {
443 0x00,
444 0x80, 0xc0, 0xe0, 0xf0,
445 0xf8, 0xfc, 0xfe, 0xff
446 };
447 int byte;
448 int cidr_len = 0;
449
450 for (byte = 0; byte < 16; byte++) {
451 u_int bits;
452
453 for (bits = 0; bits < (sizeof (bitmasks) / sizeof (bitmasks[0])); bits++) {
454 if (mask[byte] == bitmasks[bits]) {
455 cidr_len += bits;
456 break;
457 }
458 }
459
460 if (mask[byte] != 0xff)
461 break;
462 }
463 return (cidr_len);
464 }
465 #endif /* INET6 */
466
467 /* VARARGS */
468 void
469 error(const char *fmt, ...)
470 {
471 va_list ap;
472
473 (void)fprintf(stderr, "%s: ", program_name);
474 va_start(ap, fmt);
475 (void)vfprintf(stderr, fmt, ap);
476 va_end(ap);
477 if (*fmt) {
478 fmt += strlen(fmt);
479 if (fmt[-1] != '\n')
480 (void)fputc('\n', stderr);
481 }
482 exit(1);
483 /* NOTREACHED */
484 }
485
486 /* VARARGS */
487 void
488 warning(const char *fmt, ...)
489 {
490 va_list ap;
491
492 (void)fprintf(stderr, "%s: WARNING: ", program_name);
493 va_start(ap, fmt);
494 (void)vfprintf(stderr, fmt, ap);
495 va_end(ap);
496 if (*fmt) {
497 fmt += strlen(fmt);
498 if (fmt[-1] != '\n')
499 (void)fputc('\n', stderr);
500 }
501 }
502
503 /*
504 * Copy arg vector into a new buffer, concatenating arguments with spaces.
505 */
506 char *
507 copy_argv(register char **argv)
508 {
509 register char **p;
510 register u_int len = 0;
511 char *buf;
512 char *src, *dst;
513
514 p = argv;
515 if (*p == 0)
516 return 0;
517
518 while (*p)
519 len += strlen(*p++) + 1;
520
521 buf = (char *)malloc(len);
522 if (buf == NULL)
523 error("copy_argv: malloc");
524
525 p = argv;
526 dst = buf;
527 while ((src = *p++) != NULL) {
528 while ((*dst++ = *src++) != '\0')
529 ;
530 dst[-1] = ' ';
531 }
532 dst[-1] = '\0';
533
534 return buf;
535 }
536
537 /*
538 * On Windows, we need to open the file in binary mode, so that
539 * we get all the bytes specified by the size we get from "fstat()".
540 * On UNIX, that's not necessary. O_BINARY is defined on Windows;
541 * we define it as 0 if it's not defined, so it does nothing.
542 */
543 #ifndef O_BINARY
544 #define O_BINARY 0
545 #endif
546
547 char *
548 read_infile(char *fname)
549 {
550 register int i, fd, cc;
551 register char *cp;
552 struct stat buf;
553
554 fd = open(fname, O_RDONLY|O_BINARY);
555 if (fd < 0)
556 error("can't open %s: %s", fname, pcap_strerror(errno));
557
558 if (fstat(fd, &buf) < 0)
559 error("can't stat %s: %s", fname, pcap_strerror(errno));
560
561 cp = malloc((u_int)buf.st_size + 1);
562 if (cp == NULL)
563 error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
564 fname, pcap_strerror(errno));
565 cc = read(fd, cp, (u_int)buf.st_size);
566 if (cc < 0)
567 error("read %s: %s", fname, pcap_strerror(errno));
568 if (cc != buf.st_size)
569 error("short read %s (%d != %d)", fname, cc, (int)buf.st_size);
570
571 close(fd);
572 /* replace "# comment" with spaces */
573 for (i = 0; i < cc; i++) {
574 if (cp[i] == '#')
575 while (i < cc && cp[i] != '\n')
576 cp[i++] = ' ';
577 }
578 cp[cc] = '\0';
579 return (cp);
580 }
581
582 void
583 safeputs(netdissect_options *ndo,
584 const u_char *s, const u_int maxlen)
585 {
586 u_int idx = 0;
587
588 while (*s && idx < maxlen) {
589 safeputchar(ndo, *s);
590 idx++;
591 s++;
592 }
593 }
594
595 void
596 safeputchar(netdissect_options *ndo,
597 const u_char c)
598 {
599 ND_PRINT((ndo, (c < 0x80 && ND_ISPRINT(c)) ? "%c" : "\\0x%02x", c));
600 }
601
602 #ifdef LBL_ALIGN
603 /*
604 * Some compilers try to optimize memcpy(), using the alignment constraint
605 * on the argument pointer type. by using this function, we try to avoid the
606 * optimization.
607 */
608 void
609 unaligned_memcpy(void *p, const void *q, size_t l)
610 {
611 memcpy(p, q, l);
612 }
613
614 /* As with memcpy(), so with memcmp(). */
615 int
616 unaligned_memcmp(const void *p, const void *q, size_t l)
617 {
618 return (memcmp(p, q, l));
619 }
620 #endif