]> The Tcpdump Group git mirrors - tcpdump/blob - util.c
Merge remote-tracking branch 'bpf/master'
[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 #include <errno.h>
32 #ifdef HAVE_FCNTL_H
33 #include <fcntl.h>
34 #endif
35 #include <stdio.h>
36 #include <stdarg.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 #include "interface.h"
41
42 /*
43 * Print out a null-terminated filename (or other ascii string).
44 * If ep is NULL, assume no truncation check is needed.
45 * Return true if truncated.
46 */
47 int
48 fn_print(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 putchar('M');
63 putchar('-');
64 }
65 if (!ND_ISPRINT(c)) {
66 c ^= 0x40; /* DEL to ?, others to alpha */
67 putchar('^');
68 }
69 putchar(c);
70 }
71 return(ret);
72 }
73
74 /*
75 * Print out a counted filename (or other ascii string).
76 * If ep is NULL, assume no truncation check is needed.
77 * Return true if truncated.
78 */
79 int
80 fn_printn(register const u_char *s, register u_int n,
81 register const u_char *ep)
82 {
83 register u_char c;
84
85 while (n > 0 && (ep == NULL || s < ep)) {
86 n--;
87 c = *s++;
88 if (!ND_ISASCII(c)) {
89 c = ND_TOASCII(c);
90 putchar('M');
91 putchar('-');
92 }
93 if (!ND_ISPRINT(c)) {
94 c ^= 0x40; /* DEL to ?, others to alpha */
95 putchar('^');
96 }
97 putchar(c);
98 }
99 return (n == 0) ? 0 : 1;
100 }
101
102 /*
103 * Print out a null-padded filename (or other ascii string).
104 * If ep is NULL, assume no truncation check is needed.
105 * Return true if truncated.
106 */
107 int
108 fn_printzp(register const u_char *s, register u_int n,
109 register const u_char *ep)
110 {
111 register int ret;
112 register u_char c;
113
114 ret = 1; /* assume truncated */
115 while (n > 0 && (ep == NULL || s < ep)) {
116 n--;
117 c = *s++;
118 if (c == '\0') {
119 ret = 0;
120 break;
121 }
122 if (!ND_ISASCII(c)) {
123 c = ND_TOASCII(c);
124 putchar('M');
125 putchar('-');
126 }
127 if (!ND_ISPRINT(c)) {
128 c ^= 0x40; /* DEL to ?, others to alpha */
129 putchar('^');
130 }
131 putchar(c);
132 }
133 return (n == 0) ? 0 : ret;
134 }
135
136 /*
137 * Format the timestamp
138 */
139 static char *
140 ts_format(register int sec, register int usec)
141 {
142 static char buf[sizeof("00:00:00.000000")];
143 (void)snprintf(buf, sizeof(buf), "%02d:%02d:%02d.%06u",
144 sec / 3600, (sec % 3600) / 60, sec % 60, usec);
145
146 return buf;
147 }
148
149 /*
150 * Print the timestamp
151 */
152 void
153 ts_print(netdissect_options *ndo,
154 register const struct timeval *tvp)
155 {
156 register int s;
157 struct tm *tm;
158 time_t Time;
159 static unsigned b_sec;
160 static unsigned b_usec;
161 int d_usec;
162 int d_sec;
163
164 switch (ndo->ndo_tflag) {
165
166 case 0: /* Default */
167 s = (tvp->tv_sec + thiszone) % 86400;
168 ND_PRINT((ndo, "%s ", ts_format(s, tvp->tv_usec)));
169 break;
170
171 case 1: /* No time stamp */
172 break;
173
174 case 2: /* Unix timeval style */
175 ND_PRINT((ndo, "%u.%06u ",
176 (unsigned)tvp->tv_sec,
177 (unsigned)tvp->tv_usec));
178 break;
179
180 case 3: /* Microseconds since previous packet */
181 case 5: /* Microseconds since first packet */
182 if (b_sec == 0) {
183 /* init timestamp for first packet */
184 b_usec = tvp->tv_usec;
185 b_sec = tvp->tv_sec;
186 }
187
188 d_usec = tvp->tv_usec - b_usec;
189 d_sec = tvp->tv_sec - b_sec;
190
191 while (d_usec < 0) {
192 d_usec += 1000000;
193 d_sec--;
194 }
195
196 ND_PRINT((ndo, "%s ", ts_format(d_sec, d_usec)));
197
198 if (ndo->ndo_tflag == 3) { /* set timestamp for last packet */
199 b_sec = tvp->tv_sec;
200 b_usec = tvp->tv_usec;
201 }
202 break;
203
204 case 4: /* Default + Date*/
205 s = (tvp->tv_sec + thiszone) % 86400;
206 Time = (tvp->tv_sec + thiszone) - s;
207 tm = gmtime (&Time);
208 if (!tm)
209 ND_PRINT((ndo, "Date fail "));
210 else
211 ND_PRINT((ndo, "%04d-%02d-%02d %s ",
212 tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
213 ts_format(s, tvp->tv_usec)));
214 break;
215 }
216 }
217
218 /*
219 * Print a relative number of seconds (e.g. hold time, prune timer)
220 * in the form 5m1s. This does no truncation, so 32230861 seconds
221 * is represented as 1y1w1d1h1m1s.
222 */
223 void
224 relts_print(netdissect_options *ndo,
225 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 ND_PRINT((ndo, "0s"));
234 return;
235 }
236 if (secs < 0) {
237 ND_PRINT((ndo, "-"));
238 secs = -secs;
239 }
240 while (secs > 0) {
241 if (secs >= *s) {
242 ND_PRINT((ndo, "%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 (ndo->ndo_snapend - cp < len)
265 len = ndo->ndo_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 u_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 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(netdissect_options *ndo,
583 const u_char *s, const u_int maxlen)
584 {
585 u_int idx = 0;
586
587 while (*s && idx < maxlen) {
588 safeputchar(ndo, *s);
589 idx++;
590 s++;
591 }
592 }
593
594 void
595 safeputchar(netdissect_options *ndo,
596 const u_char c)
597 {
598 ND_PRINT((ndo, (c < 0x80 && ND_ISPRINT(c)) ? "%c" : "\\0x%02x", c));
599 }
600
601 #ifdef LBL_ALIGN
602 /*
603 * Some compilers try to optimize memcpy(), using the alignment constraint
604 * on the argument pointer type. by using this function, we try to avoid the
605 * optimization.
606 */
607 void
608 unaligned_memcpy(void *p, const void *q, size_t l)
609 {
610 memcpy(p, q, l);
611 }
612
613 /* As with memcpy(), so with memcmp(). */
614 int
615 unaligned_memcmp(const void *p, const void *q, size_t l)
616 {
617 return (memcmp(p, q, l));
618 }
619 #endif