]> The Tcpdump Group git mirrors - tcpdump/blob - util.c
fix bittok2str_internal() w/o separator (GH #391)
[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 const char * sepstr = "";
324
325 while (lp != NULL && lp->s != NULL) {
326 tokval=lp->v; /* load our first value */
327 rotbit=1;
328 while (rotbit != 0) {
329 /*
330 * lets AND the rotating bit with our token value
331 * and see if we have got a match
332 */
333 if (tokval == (v&rotbit)) {
334 /* ok we have found something */
335 buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s%s",
336 sepstr, lp->s);
337 sepstr = sep ? ", " : "";
338 break;
339 }
340 rotbit=rotbit<<1; /* no match - lets shift and try again */
341 }
342 lp++;
343 }
344
345 if (buflen == 0)
346 /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */
347 (void)snprintf(buf, sizeof(buf), fmt == NULL ? "#%d" : fmt, v);
348 return (buf);
349 }
350
351 /*
352 * Convert a bit token value to a string; use "fmt" if not found.
353 * this is useful for parsing bitfields, the output strings are not seperated.
354 */
355 char *
356 bittok2str_nosep(register const struct tok *lp, register const char *fmt,
357 register int v)
358 {
359 return (bittok2str_internal(lp, fmt, v, 0));
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 comma seperated.
365 */
366 char *
367 bittok2str(register const struct tok *lp, register const char *fmt,
368 register int v)
369 {
370 return (bittok2str_internal(lp, fmt, v, 1));
371 }
372
373 /*
374 * Convert a value to a string using an array; the macro
375 * tok2strary() in <interface.h> is the public interface to
376 * this function and ensures that the second argument is
377 * correct for bounds-checking.
378 */
379 const char *
380 tok2strary_internal(register const char **lp, int n, register const char *fmt,
381 register int v)
382 {
383 static char buf[128];
384
385 if (v >= 0 && v < n && lp[v] != NULL)
386 return lp[v];
387 if (fmt == NULL)
388 fmt = "#%d";
389 (void)snprintf(buf, sizeof(buf), fmt, v);
390 return (buf);
391 }
392
393 /*
394 * Convert a 32-bit netmask to prefixlen if possible
395 * the function returns the prefix-len; if plen == -1
396 * then conversion was not possible;
397 */
398
399 int
400 mask2plen(uint32_t mask)
401 {
402 uint32_t bitmasks[33] = {
403 0x00000000,
404 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
405 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
406 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
407 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
408 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
409 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
410 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
411 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
412 };
413 int prefix_len = 32;
414
415 /* let's see if we can transform the mask into a prefixlen */
416 while (prefix_len >= 0) {
417 if (bitmasks[prefix_len] == mask)
418 break;
419 prefix_len--;
420 }
421 return (prefix_len);
422 }
423
424 #ifdef INET6
425 int
426 mask62plen(const u_char *mask)
427 {
428 u_char bitmasks[9] = {
429 0x00,
430 0x80, 0xc0, 0xe0, 0xf0,
431 0xf8, 0xfc, 0xfe, 0xff
432 };
433 int byte;
434 int cidr_len = 0;
435
436 for (byte = 0; byte < 16; byte++) {
437 u_int bits;
438
439 for (bits = 0; bits < (sizeof (bitmasks) / sizeof (bitmasks[0])); bits++) {
440 if (mask[byte] == bitmasks[bits]) {
441 cidr_len += bits;
442 break;
443 }
444 }
445
446 if (mask[byte] != 0xff)
447 break;
448 }
449 return (cidr_len);
450 }
451 #endif /* INET6 */
452
453 /* VARARGS */
454 void
455 error(const char *fmt, ...)
456 {
457 va_list ap;
458
459 (void)fprintf(stderr, "%s: ", program_name);
460 va_start(ap, fmt);
461 (void)vfprintf(stderr, fmt, ap);
462 va_end(ap);
463 if (*fmt) {
464 fmt += strlen(fmt);
465 if (fmt[-1] != '\n')
466 (void)fputc('\n', stderr);
467 }
468 exit(1);
469 /* NOTREACHED */
470 }
471
472 /* VARARGS */
473 void
474 warning(const char *fmt, ...)
475 {
476 va_list ap;
477
478 (void)fprintf(stderr, "%s: WARNING: ", program_name);
479 va_start(ap, fmt);
480 (void)vfprintf(stderr, fmt, ap);
481 va_end(ap);
482 if (*fmt) {
483 fmt += strlen(fmt);
484 if (fmt[-1] != '\n')
485 (void)fputc('\n', stderr);
486 }
487 }
488
489 /*
490 * Copy arg vector into a new buffer, concatenating arguments with spaces.
491 */
492 char *
493 copy_argv(register char **argv)
494 {
495 register char **p;
496 register u_int len = 0;
497 char *buf;
498 char *src, *dst;
499
500 p = argv;
501 if (*p == 0)
502 return 0;
503
504 while (*p)
505 len += strlen(*p++) + 1;
506
507 buf = (char *)malloc(len);
508 if (buf == NULL)
509 error("copy_argv: malloc");
510
511 p = argv;
512 dst = buf;
513 while ((src = *p++) != NULL) {
514 while ((*dst++ = *src++) != '\0')
515 ;
516 dst[-1] = ' ';
517 }
518 dst[-1] = '\0';
519
520 return buf;
521 }
522
523 /*
524 * On Windows, we need to open the file in binary mode, so that
525 * we get all the bytes specified by the size we get from "fstat()".
526 * On UNIX, that's not necessary. O_BINARY is defined on Windows;
527 * we define it as 0 if it's not defined, so it does nothing.
528 */
529 #ifndef O_BINARY
530 #define O_BINARY 0
531 #endif
532
533 char *
534 read_infile(char *fname)
535 {
536 register int i, fd, cc;
537 register char *cp;
538 struct stat buf;
539
540 fd = open(fname, O_RDONLY|O_BINARY);
541 if (fd < 0)
542 error("can't open %s: %s", fname, pcap_strerror(errno));
543
544 if (fstat(fd, &buf) < 0)
545 error("can't stat %s: %s", fname, pcap_strerror(errno));
546
547 cp = malloc((u_int)buf.st_size + 1);
548 if (cp == NULL)
549 error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1,
550 fname, pcap_strerror(errno));
551 cc = read(fd, cp, (u_int)buf.st_size);
552 if (cc < 0)
553 error("read %s: %s", fname, pcap_strerror(errno));
554 if (cc != buf.st_size)
555 error("short read %s (%d != %d)", fname, cc, (int)buf.st_size);
556
557 close(fd);
558 /* replace "# comment" with spaces */
559 for (i = 0; i < cc; i++) {
560 if (cp[i] == '#')
561 while (i < cc && cp[i] != '\n')
562 cp[i++] = ' ';
563 }
564 cp[cc] = '\0';
565 return (cp);
566 }
567
568 void
569 safeputs(netdissect_options *ndo,
570 const u_char *s, const u_int maxlen)
571 {
572 u_int idx = 0;
573
574 while (*s && idx < maxlen) {
575 safeputchar(ndo, *s);
576 idx++;
577 s++;
578 }
579 }
580
581 void
582 safeputchar(netdissect_options *ndo,
583 const u_char c)
584 {
585 ND_PRINT((ndo, (c < 0x80 && ND_ISPRINT(c)) ? "%c" : "\\0x%02x", c));
586 }
587
588 #ifdef LBL_ALIGN
589 /*
590 * Some compilers try to optimize memcpy(), using the alignment constraint
591 * on the argument pointer type. by using this function, we try to avoid the
592 * optimization.
593 */
594 void
595 unaligned_memcpy(void *p, const void *q, size_t l)
596 {
597 memcpy(p, q, l);
598 }
599
600 /* As with memcpy(), so with memcmp(). */
601 int
602 unaligned_memcmp(const void *p, const void *q, size_t l)
603 {
604 return (memcmp(p, q, l));
605 }
606 #endif