util.c revision 147899
117680Spst/* 239297Sfenner * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997 317680Spst * The Regents of the University of California. All rights reserved. 417680Spst * 517680Spst * Redistribution and use in source and binary forms, with or without 617680Spst * modification, are permitted provided that: (1) source code distributions 717680Spst * retain the above copyright notice and this paragraph in its entirety, (2) 817680Spst * distributions including binary code include the above copyright notice and 917680Spst * this paragraph in its entirety in the documentation or other materials 1017680Spst * provided with the distribution, and (3) all advertising materials mentioning 1117680Spst * features or use of this software display the following acknowledgement: 1217680Spst * ``This product includes software developed by the University of California, 1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 1417680Spst * the University nor the names of its contributors may be used to endorse 1517680Spst * or promote products derived from this software without specific prior 1617680Spst * written permission. 1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2017680Spst */ 2117680Spst 2217680Spst#ifndef lint 23127668Sbmsstatic const char rcsid[] _U_ = 24147899Ssam "@(#) $Header: /tcpdump/master/tcpdump/util.c,v 1.95.2.5 2005/06/16 01:19:57 guy Exp $ (LBL)"; 2517680Spst#endif 2617680Spst 2756893Sfenner#ifdef HAVE_CONFIG_H 2856893Sfenner#include "config.h" 2956893Sfenner#endif 3056893Sfenner 31127668Sbms#include <tcpdump-stdinc.h> 32127668Sbms 3317680Spst#include <sys/stat.h> 3417680Spst 3517680Spst#include <errno.h> 3617680Spst#ifdef HAVE_FCNTL_H 3717680Spst#include <fcntl.h> 3817680Spst#endif 3917680Spst#include <pcap.h> 4017680Spst#include <stdio.h> 4117680Spst#include <stdarg.h> 4217680Spst#include <stdlib.h> 4317680Spst#include <string.h> 4417680Spst 4517680Spst#include "interface.h" 4617680Spst 4717680Spst/* 48147899Ssam * Print out a null-terminated filename (or other ascii string). 4917680Spst * If ep is NULL, assume no truncation check is needed. 5017680Spst * Return true if truncated. 5117680Spst */ 5217680Spstint 5317680Spstfn_print(register const u_char *s, register const u_char *ep) 5417680Spst{ 5517680Spst register int ret; 5617680Spst register u_char c; 5717680Spst 5817680Spst ret = 1; /* assume truncated */ 5917680Spst while (ep == NULL || s < ep) { 6017680Spst c = *s++; 6117680Spst if (c == '\0') { 6217680Spst ret = 0; 6317680Spst break; 6417680Spst } 6517680Spst if (!isascii(c)) { 6617680Spst c = toascii(c); 6717680Spst putchar('M'); 6817680Spst putchar('-'); 6917680Spst } 7017680Spst if (!isprint(c)) { 7117680Spst c ^= 0x40; /* DEL to ?, others to alpha */ 7217680Spst putchar('^'); 7317680Spst } 7417680Spst putchar(c); 7517680Spst } 7617680Spst return(ret); 7717680Spst} 7817680Spst 7917680Spst/* 8017680Spst * Print out a counted filename (or other ascii string). 8117680Spst * If ep is NULL, assume no truncation check is needed. 8217680Spst * Return true if truncated. 8317680Spst */ 8417680Spstint 8517680Spstfn_printn(register const u_char *s, register u_int n, 8617680Spst register const u_char *ep) 8717680Spst{ 8817680Spst register u_char c; 8917680Spst 90127668Sbms while (n > 0 && (ep == NULL || s < ep)) { 91127668Sbms n--; 9217680Spst c = *s++; 9317680Spst if (!isascii(c)) { 9417680Spst c = toascii(c); 9517680Spst putchar('M'); 9617680Spst putchar('-'); 9717680Spst } 9817680Spst if (!isprint(c)) { 9917680Spst c ^= 0x40; /* DEL to ?, others to alpha */ 10017680Spst putchar('^'); 10117680Spst } 10217680Spst putchar(c); 10317680Spst } 104127668Sbms return (n == 0) ? 0 : 1; 10517680Spst} 10617680Spst 10717680Spst/* 108147899Ssam * Print out a null-padded filename (or other ascii string). 109147899Ssam * If ep is NULL, assume no truncation check is needed. 110147899Ssam * Return true if truncated. 111147899Ssam */ 112147899Ssamint 113147899Ssamfn_printzp(register const u_char *s, register u_int n, 114147899Ssam register const u_char *ep) 115147899Ssam{ 116147899Ssam register int ret; 117147899Ssam register u_char c; 118147899Ssam 119147899Ssam ret = 1; /* assume truncated */ 120147899Ssam while (n > 0 && (ep == NULL || s < ep)) { 121147899Ssam n--; 122147899Ssam c = *s++; 123147899Ssam if (c == '\0') { 124147899Ssam ret = 0; 125147899Ssam break; 126147899Ssam } 127147899Ssam if (!isascii(c)) { 128147899Ssam c = toascii(c); 129147899Ssam putchar('M'); 130147899Ssam putchar('-'); 131147899Ssam } 132147899Ssam if (!isprint(c)) { 133147899Ssam c ^= 0x40; /* DEL to ?, others to alpha */ 134147899Ssam putchar('^'); 135147899Ssam } 136147899Ssam putchar(c); 137147899Ssam } 138147899Ssam return (n == 0) ? 0 : ret; 139147899Ssam} 140147899Ssam 141147899Ssam/* 14217680Spst * Print the timestamp 14317680Spst */ 14417680Spstvoid 14517680Spstts_print(register const struct timeval *tvp) 14617680Spst{ 14717680Spst register int s; 14875115Sfenner struct tm *tm; 14975115Sfenner time_t Time; 15075115Sfenner static unsigned b_sec; 15175115Sfenner static unsigned b_usec; 15217680Spst 153146773Ssam switch (tflag) { 154146773Ssam 155146773Ssam case 0: /* Default */ 15617680Spst s = (tvp->tv_sec + thiszone) % 86400; 15717680Spst (void)printf("%02d:%02d:%02d.%06u ", 15875115Sfenner s / 3600, (s % 3600) / 60, s % 60, 15975115Sfenner (unsigned)tvp->tv_usec); 16075115Sfenner break; 161146773Ssam 162146773Ssam case 1: /* No time stamp */ 163146773Ssam break; 164146773Ssam 165146773Ssam case 2: /* Unix timeval style */ 16675115Sfenner (void)printf("%u.%06u ", 16775115Sfenner (unsigned)tvp->tv_sec, 16875115Sfenner (unsigned)tvp->tv_usec); 16975115Sfenner break; 170146773Ssam 171146773Ssam case 3: /* Microseconds since previous packet */ 17275115Sfenner if (b_sec == 0) { 17375115Sfenner printf("000000 "); 17475115Sfenner } else { 17575115Sfenner int d_usec = tvp->tv_usec - b_usec; 17675115Sfenner int d_sec = tvp->tv_sec - b_sec; 177127668Sbms 17875115Sfenner while (d_usec < 0) { 17975115Sfenner d_usec += 1000000; 18075115Sfenner d_sec--; 18156893Sfenner } 18275115Sfenner if (d_sec) 18375115Sfenner printf("%d. ", d_sec); 18475115Sfenner printf("%06d ", d_usec); 18556893Sfenner } 18675115Sfenner b_sec = tvp->tv_sec; 18775115Sfenner b_usec = tvp->tv_usec; 18875115Sfenner break; 189146773Ssam 190146773Ssam case 4: /* Default + Date*/ 19175115Sfenner s = (tvp->tv_sec + thiszone) % 86400; 19275115Sfenner Time = (tvp->tv_sec + thiszone) - s; 193127668Sbms tm = gmtime (&Time); 194127668Sbms if (!tm) 195127668Sbms printf("Date fail "); 196127668Sbms else 197127668Sbms printf("%04d-%02d-%02d ", 198127668Sbms tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday); 199127668Sbms printf("%02d:%02d:%02d.%06u ", 200127668Sbms s / 3600, (s % 3600) / 60, s % 60, (unsigned)tvp->tv_usec); 20175115Sfenner break; 20217680Spst } 20317680Spst} 20417680Spst 20517680Spst/* 20656893Sfenner * Print a relative number of seconds (e.g. hold time, prune timer) 20756893Sfenner * in the form 5m1s. This does no truncation, so 32230861 seconds 20856893Sfenner * is represented as 1y1w1d1h1m1s. 20956893Sfenner */ 21056893Sfennervoid 21156893Sfennerrelts_print(int secs) 21256893Sfenner{ 21398524Sfenner static const char *lengths[] = {"y", "w", "d", "h", "m", "s"}; 21498524Sfenner static const int seconds[] = {31536000, 604800, 86400, 3600, 60, 1}; 21598524Sfenner const char **l = lengths; 21698524Sfenner const int *s = seconds; 21756893Sfenner 21898524Sfenner if (secs == 0) { 21975115Sfenner (void)printf("0s"); 22075115Sfenner return; 22156893Sfenner } 22298524Sfenner if (secs < 0) { 22398524Sfenner (void)printf("-"); 22498524Sfenner secs = -secs; 22598524Sfenner } 22675115Sfenner while (secs > 0) { 22775115Sfenner if (secs >= *s) { 22875115Sfenner (void)printf("%d%s", secs / *s, *l); 22975115Sfenner secs -= (secs / *s) * *s; 23075115Sfenner } 23175115Sfenner s++; 23275115Sfenner l++; 23375115Sfenner } 23456893Sfenner} 23556893Sfenner 23656893Sfenner/* 237127668Sbms * this is a generic routine for printing unknown data; 238127668Sbms * we pass on the linefeed plus indentation string to 239127668Sbms * get a proper output - returns 0 on error 240127668Sbms */ 241127668Sbms 242127668Sbmsint 243127668Sbmsprint_unknown_data(const u_char *cp,const char *ident,int len) 244127668Sbms{ 245147899Ssam if (len < 0) { 246147899Ssam printf("%sDissector error: print_unknown_data called with negative length", 247147899Ssam ident); 248147899Ssam return(0); 249147899Ssam } 250147899Ssam if (snapend - cp < len) 251147899Ssam len = snapend - cp; 252147899Ssam if (len < 0) { 253147899Ssam printf("%sDissector error: print_unknown_data called with pointer past end of packet", 254147899Ssam ident); 255147899Ssam return(0); 256147899Ssam } 257127668Sbms hex_print(ident,cp,len); 258127668Sbms return(1); /* everything is ok */ 259127668Sbms} 260127668Sbms 261127668Sbms/* 26217680Spst * Convert a token value to a string; use "fmt" if not found. 26317680Spst */ 26417680Spstconst char * 265146773Ssamtok2strbuf(register const struct tok *lp, register const char *fmt, 266146773Ssam register int v, char *buf, size_t bufsize) 26717680Spst{ 268147899Ssam if (lp != NULL) { 269147899Ssam while (lp->s != NULL) { 270147899Ssam if (lp->v == v) 271147899Ssam return (lp->s); 272147899Ssam ++lp; 273147899Ssam } 27417680Spst } 27517680Spst if (fmt == NULL) 27617680Spst fmt = "#%d"; 277146773Ssam 278146773Ssam (void)snprintf(buf, bufsize, fmt, v); 279146773Ssam return (const char *)buf; 28017680Spst} 28117680Spst 28298524Sfenner/* 283146773Ssam * Convert a token value to a string; use "fmt" if not found. 284146773Ssam */ 285146773Ssamconst char * 286146773Ssamtok2str(register const struct tok *lp, register const char *fmt, 287146773Ssam register int v) 288146773Ssam{ 289146773Ssam static char buf[4][128]; 290146773Ssam static int idx = 0; 291146773Ssam char *ret; 292146773Ssam 293146773Ssam ret = buf[idx]; 294146773Ssam idx = (idx+1) & 3; 295146773Ssam return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0])); 296146773Ssam} 297146773Ssam 298146773Ssam/* 299127668Sbms * Convert a bit token value to a string; use "fmt" if not found. 300127668Sbms * this is useful for parsing bitfields, the output strings are comma seperated 301127668Sbms */ 302127668Sbmschar * 303127668Sbmsbittok2str(register const struct tok *lp, register const char *fmt, 304146773Ssam register int v) 305127668Sbms{ 306127668Sbms static char buf[256]; /* our stringbuffer */ 307127668Sbms int buflen=0; 308127668Sbms register int rotbit; /* this is the bit we rotate through all bitpositions */ 309127668Sbms register int tokval; 310127668Sbms 311146773Ssam while (lp->s != NULL && lp != NULL) { 312127668Sbms tokval=lp->v; /* load our first value */ 313127668Sbms rotbit=1; 314127668Sbms while (rotbit != 0) { 315127668Sbms /* 316127668Sbms * lets AND the rotating bit with our token value 317127668Sbms * and see if we have got a match 318127668Sbms */ 319127668Sbms if (tokval == (v&rotbit)) { 320127668Sbms /* ok we have found something */ 321127668Sbms buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s, ",lp->s); 322127668Sbms break; 323127668Sbms } 324127668Sbms rotbit=rotbit<<1; /* no match - lets shift and try again */ 325127668Sbms } 326127668Sbms lp++; 327127668Sbms } 328127668Sbms 329127668Sbms if (buflen != 0) { /* did we find anything */ 330127668Sbms /* yep, set the the trailing zero 2 bytes before to eliminate the last comma & whitespace */ 331127668Sbms buf[buflen-2] = '\0'; 332127668Sbms return (buf); 333127668Sbms } 334127668Sbms else { 335127668Sbms /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */ 336127668Sbms if (fmt == NULL) 337127668Sbms fmt = "#%d"; 338127668Sbms (void)snprintf(buf, sizeof(buf), fmt, v); 339127668Sbms return (buf); 340127668Sbms } 341127668Sbms} 342127668Sbms 343127668Sbms/* 34498524Sfenner * Convert a value to a string using an array; the macro 34598524Sfenner * tok2strary() in <interface.h> is the public interface to 34698524Sfenner * this function and ensures that the second argument is 34798524Sfenner * correct for bounds-checking. 34898524Sfenner */ 34998524Sfennerconst char * 35098524Sfennertok2strary_internal(register const char **lp, int n, register const char *fmt, 35198524Sfenner register int v) 35298524Sfenner{ 35398524Sfenner static char buf[128]; 35417680Spst 35598524Sfenner if (v >= 0 && v < n && lp[v] != NULL) 35698524Sfenner return lp[v]; 35798524Sfenner if (fmt == NULL) 35898524Sfenner fmt = "#%d"; 35998524Sfenner (void)snprintf(buf, sizeof(buf), fmt, v); 36098524Sfenner return (buf); 36198524Sfenner} 36298524Sfenner 363127668Sbms/* 364127668Sbms * Convert a 32-bit netmask to prefixlen if possible 365127668Sbms * the function returns the prefix-len; if plen == -1 366127668Sbms * then conversion was not possible; 367127668Sbms */ 368127668Sbms 369127668Sbmsint 370127668Sbmsmask2plen (u_int32_t mask) 371127668Sbms{ 372127668Sbms u_int32_t bitmasks[33] = { 373127668Sbms 0x00000000, 374127668Sbms 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 375127668Sbms 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000, 376127668Sbms 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000, 377127668Sbms 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000, 378127668Sbms 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000, 379127668Sbms 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00, 380127668Sbms 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, 381127668Sbms 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff 382127668Sbms }; 383127668Sbms int prefix_len = 32; 384127668Sbms 385127668Sbms /* let's see if we can transform the mask into a prefixlen */ 386127668Sbms while (prefix_len >= 0) { 387127668Sbms if (bitmasks[prefix_len] == mask) 388127668Sbms break; 389127668Sbms prefix_len--; 390127668Sbms } 391127668Sbms return (prefix_len); 392127668Sbms} 393127668Sbms 39417680Spst/* VARARGS */ 39575115Sfennervoid 39617680Spsterror(const char *fmt, ...) 39717680Spst{ 39817680Spst va_list ap; 39917680Spst 40017680Spst (void)fprintf(stderr, "%s: ", program_name); 40117680Spst va_start(ap, fmt); 40217680Spst (void)vfprintf(stderr, fmt, ap); 40317680Spst va_end(ap); 40417680Spst if (*fmt) { 40517680Spst fmt += strlen(fmt); 40617680Spst if (fmt[-1] != '\n') 40717680Spst (void)fputc('\n', stderr); 40817680Spst } 40917680Spst exit(1); 41017680Spst /* NOTREACHED */ 41117680Spst} 41217680Spst 41317680Spst/* VARARGS */ 41417680Spstvoid 41517680Spstwarning(const char *fmt, ...) 41617680Spst{ 41717680Spst va_list ap; 41817680Spst 41917680Spst (void)fprintf(stderr, "%s: WARNING: ", program_name); 42017680Spst va_start(ap, fmt); 42117680Spst (void)vfprintf(stderr, fmt, ap); 42217680Spst va_end(ap); 42317680Spst if (*fmt) { 42417680Spst fmt += strlen(fmt); 42517680Spst if (fmt[-1] != '\n') 42617680Spst (void)fputc('\n', stderr); 42717680Spst } 42817680Spst} 42917680Spst 43017680Spst/* 43117680Spst * Copy arg vector into a new buffer, concatenating arguments with spaces. 43217680Spst */ 43317680Spstchar * 43417680Spstcopy_argv(register char **argv) 43517680Spst{ 43617680Spst register char **p; 43717680Spst register u_int len = 0; 43817680Spst char *buf; 43917680Spst char *src, *dst; 44017680Spst 44117680Spst p = argv; 44217680Spst if (*p == 0) 44317680Spst return 0; 44417680Spst 44517680Spst while (*p) 44617680Spst len += strlen(*p++) + 1; 44717680Spst 44817680Spst buf = (char *)malloc(len); 44917680Spst if (buf == NULL) 45017680Spst error("copy_argv: malloc"); 45117680Spst 45217680Spst p = argv; 45317680Spst dst = buf; 45417680Spst while ((src = *p++) != NULL) { 45517680Spst while ((*dst++ = *src++) != '\0') 45617680Spst ; 45717680Spst dst[-1] = ' '; 45817680Spst } 45917680Spst dst[-1] = '\0'; 46017680Spst 46117680Spst return buf; 46217680Spst} 46317680Spst 464127668Sbms/* 465127668Sbms * On Windows, we need to open the file in binary mode, so that 466127668Sbms * we get all the bytes specified by the size we get from "fstat()". 467127668Sbms * On UNIX, that's not necessary. O_BINARY is defined on Windows; 468127668Sbms * we define it as 0 if it's not defined, so it does nothing. 469127668Sbms */ 470127668Sbms#ifndef O_BINARY 471127668Sbms#define O_BINARY 0 472127668Sbms#endif 473127668Sbms 47417680Spstchar * 47517680Spstread_infile(char *fname) 47617680Spst{ 477127668Sbms register int i, fd, cc; 47817680Spst register char *cp; 47917680Spst struct stat buf; 48017680Spst 481127668Sbms fd = open(fname, O_RDONLY|O_BINARY); 48217680Spst if (fd < 0) 48317680Spst error("can't open %s: %s", fname, pcap_strerror(errno)); 48417680Spst 48517680Spst if (fstat(fd, &buf) < 0) 48617680Spst error("can't stat %s: %s", fname, pcap_strerror(errno)); 48717680Spst 48817680Spst cp = malloc((u_int)buf.st_size + 1); 48998524Sfenner if (cp == NULL) 49098524Sfenner error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1, 49198524Sfenner fname, pcap_strerror(errno)); 49298524Sfenner cc = read(fd, cp, (u_int)buf.st_size); 49317680Spst if (cc < 0) 49417680Spst error("read %s: %s", fname, pcap_strerror(errno)); 49517680Spst if (cc != buf.st_size) 49617680Spst error("short read %s (%d != %d)", fname, cc, (int)buf.st_size); 49717680Spst 498127668Sbms close(fd); 499127668Sbms /* replace "# comment" with spaces */ 500127668Sbms for (i = 0; i < cc; i++) { 501127668Sbms if (cp[i] == '#') 502127668Sbms while (i < cc && cp[i] != '\n') 503127668Sbms cp[i++] = ' '; 504127668Sbms } 505127668Sbms cp[cc] = '\0'; 50617680Spst return (cp); 50717680Spst} 50875115Sfenner 50975115Sfennervoid 51075115Sfennersafeputs(const char *s) 51175115Sfenner{ 51275115Sfenner while (*s) { 51375115Sfenner safeputchar(*s); 51475115Sfenner s++; 51575115Sfenner } 51675115Sfenner} 51775115Sfenner 51875115Sfennervoid 51975115Sfennersafeputchar(int c) 52075115Sfenner{ 52175115Sfenner unsigned char ch; 52275115Sfenner 52375115Sfenner ch = (unsigned char)(c & 0xff); 524111726Sfenner if (ch < 0x80 && isprint(ch)) 525111726Sfenner printf("%c", ch); 52675115Sfenner else 527111726Sfenner printf("\\%03o", ch); 52875115Sfenner} 529