]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/tcpdump/util.c
Update libucl to git version 8d3b186
[FreeBSD/FreeBSD.git] / contrib / 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