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