util.c revision 146773
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_ = 24146773Ssam "@(#) $Header: /tcpdump/master/tcpdump/util.c,v 1.95 2005/03/21 11:35:55 hannes 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/* 4817680Spst * Print out a 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/* 10817680Spst * Print the timestamp 10917680Spst */ 11017680Spstvoid 11117680Spstts_print(register const struct timeval *tvp) 11217680Spst{ 11317680Spst register int s; 11475115Sfenner struct tm *tm; 11575115Sfenner time_t Time; 11675115Sfenner static unsigned b_sec; 11775115Sfenner static unsigned b_usec; 11817680Spst 119146773Ssam switch (tflag) { 120146773Ssam 121146773Ssam case 0: /* Default */ 12217680Spst s = (tvp->tv_sec + thiszone) % 86400; 12317680Spst (void)printf("%02d:%02d:%02d.%06u ", 12475115Sfenner s / 3600, (s % 3600) / 60, s % 60, 12575115Sfenner (unsigned)tvp->tv_usec); 12675115Sfenner break; 127146773Ssam 128146773Ssam case 1: /* No time stamp */ 129146773Ssam break; 130146773Ssam 131146773Ssam case 2: /* Unix timeval style */ 13275115Sfenner (void)printf("%u.%06u ", 13375115Sfenner (unsigned)tvp->tv_sec, 13475115Sfenner (unsigned)tvp->tv_usec); 13575115Sfenner break; 136146773Ssam 137146773Ssam case 3: /* Microseconds since previous packet */ 13875115Sfenner if (b_sec == 0) { 13975115Sfenner printf("000000 "); 14075115Sfenner } else { 14175115Sfenner int d_usec = tvp->tv_usec - b_usec; 14275115Sfenner int d_sec = tvp->tv_sec - b_sec; 143127668Sbms 14475115Sfenner while (d_usec < 0) { 14575115Sfenner d_usec += 1000000; 14675115Sfenner d_sec--; 14756893Sfenner } 14875115Sfenner if (d_sec) 14975115Sfenner printf("%d. ", d_sec); 15075115Sfenner printf("%06d ", d_usec); 15156893Sfenner } 15275115Sfenner b_sec = tvp->tv_sec; 15375115Sfenner b_usec = tvp->tv_usec; 15475115Sfenner break; 155146773Ssam 156146773Ssam case 4: /* Default + Date*/ 15775115Sfenner s = (tvp->tv_sec + thiszone) % 86400; 15875115Sfenner Time = (tvp->tv_sec + thiszone) - s; 159127668Sbms tm = gmtime (&Time); 160127668Sbms if (!tm) 161127668Sbms printf("Date fail "); 162127668Sbms else 163127668Sbms printf("%04d-%02d-%02d ", 164127668Sbms tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday); 165127668Sbms printf("%02d:%02d:%02d.%06u ", 166127668Sbms s / 3600, (s % 3600) / 60, s % 60, (unsigned)tvp->tv_usec); 16775115Sfenner break; 16817680Spst } 16917680Spst} 17017680Spst 17117680Spst/* 17256893Sfenner * Print a relative number of seconds (e.g. hold time, prune timer) 17356893Sfenner * in the form 5m1s. This does no truncation, so 32230861 seconds 17456893Sfenner * is represented as 1y1w1d1h1m1s. 17556893Sfenner */ 17656893Sfennervoid 17756893Sfennerrelts_print(int secs) 17856893Sfenner{ 17998524Sfenner static const char *lengths[] = {"y", "w", "d", "h", "m", "s"}; 18098524Sfenner static const int seconds[] = {31536000, 604800, 86400, 3600, 60, 1}; 18198524Sfenner const char **l = lengths; 18298524Sfenner const int *s = seconds; 18356893Sfenner 18498524Sfenner if (secs == 0) { 18575115Sfenner (void)printf("0s"); 18675115Sfenner return; 18756893Sfenner } 18898524Sfenner if (secs < 0) { 18998524Sfenner (void)printf("-"); 19098524Sfenner secs = -secs; 19198524Sfenner } 19275115Sfenner while (secs > 0) { 19375115Sfenner if (secs >= *s) { 19475115Sfenner (void)printf("%d%s", secs / *s, *l); 19575115Sfenner secs -= (secs / *s) * *s; 19675115Sfenner } 19775115Sfenner s++; 19875115Sfenner l++; 19975115Sfenner } 20056893Sfenner} 20156893Sfenner 20256893Sfenner/* 203127668Sbms * this is a generic routine for printing unknown data; 204127668Sbms * we pass on the linefeed plus indentation string to 205127668Sbms * get a proper output - returns 0 on error 206127668Sbms */ 207127668Sbms 208127668Sbmsint 209127668Sbmsprint_unknown_data(const u_char *cp,const char *ident,int len) 210127668Sbms{ 211127668Sbms hex_print(ident,cp,len); 212127668Sbms return(1); /* everything is ok */ 213127668Sbms} 214127668Sbms 215127668Sbms/* 21617680Spst * Convert a token value to a string; use "fmt" if not found. 21717680Spst */ 21817680Spstconst char * 219146773Ssamtok2strbuf(register const struct tok *lp, register const char *fmt, 220146773Ssam register int v, char *buf, size_t bufsize) 22117680Spst{ 222146773Ssam while (lp->s != NULL && lp != NULL) { 22317680Spst if (lp->v == v) 22417680Spst return (lp->s); 22517680Spst ++lp; 22617680Spst } 22717680Spst if (fmt == NULL) 22817680Spst fmt = "#%d"; 229146773Ssam 230146773Ssam (void)snprintf(buf, bufsize, fmt, v); 231146773Ssam return (const char *)buf; 23217680Spst} 23317680Spst 23498524Sfenner/* 235146773Ssam * Convert a token value to a string; use "fmt" if not found. 236146773Ssam */ 237146773Ssamconst char * 238146773Ssamtok2str(register const struct tok *lp, register const char *fmt, 239146773Ssam register int v) 240146773Ssam{ 241146773Ssam static char buf[4][128]; 242146773Ssam static int idx = 0; 243146773Ssam char *ret; 244146773Ssam 245146773Ssam ret = buf[idx]; 246146773Ssam idx = (idx+1) & 3; 247146773Ssam return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0])); 248146773Ssam} 249146773Ssam 250146773Ssam/* 251127668Sbms * Convert a bit token value to a string; use "fmt" if not found. 252127668Sbms * this is useful for parsing bitfields, the output strings are comma seperated 253127668Sbms */ 254127668Sbmschar * 255127668Sbmsbittok2str(register const struct tok *lp, register const char *fmt, 256146773Ssam register int v) 257127668Sbms{ 258127668Sbms static char buf[256]; /* our stringbuffer */ 259127668Sbms int buflen=0; 260127668Sbms register int rotbit; /* this is the bit we rotate through all bitpositions */ 261127668Sbms register int tokval; 262127668Sbms 263146773Ssam while (lp->s != NULL && lp != NULL) { 264127668Sbms tokval=lp->v; /* load our first value */ 265127668Sbms rotbit=1; 266127668Sbms while (rotbit != 0) { 267127668Sbms /* 268127668Sbms * lets AND the rotating bit with our token value 269127668Sbms * and see if we have got a match 270127668Sbms */ 271127668Sbms if (tokval == (v&rotbit)) { 272127668Sbms /* ok we have found something */ 273127668Sbms buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s, ",lp->s); 274127668Sbms break; 275127668Sbms } 276127668Sbms rotbit=rotbit<<1; /* no match - lets shift and try again */ 277127668Sbms } 278127668Sbms lp++; 279127668Sbms } 280127668Sbms 281127668Sbms if (buflen != 0) { /* did we find anything */ 282127668Sbms /* yep, set the the trailing zero 2 bytes before to eliminate the last comma & whitespace */ 283127668Sbms buf[buflen-2] = '\0'; 284127668Sbms return (buf); 285127668Sbms } 286127668Sbms else { 287127668Sbms /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */ 288127668Sbms if (fmt == NULL) 289127668Sbms fmt = "#%d"; 290127668Sbms (void)snprintf(buf, sizeof(buf), fmt, v); 291127668Sbms return (buf); 292127668Sbms } 293127668Sbms} 294127668Sbms 295127668Sbms/* 29698524Sfenner * Convert a value to a string using an array; the macro 29798524Sfenner * tok2strary() in <interface.h> is the public interface to 29898524Sfenner * this function and ensures that the second argument is 29998524Sfenner * correct for bounds-checking. 30098524Sfenner */ 30198524Sfennerconst char * 30298524Sfennertok2strary_internal(register const char **lp, int n, register const char *fmt, 30398524Sfenner register int v) 30498524Sfenner{ 30598524Sfenner static char buf[128]; 30617680Spst 30798524Sfenner if (v >= 0 && v < n && lp[v] != NULL) 30898524Sfenner return lp[v]; 30998524Sfenner if (fmt == NULL) 31098524Sfenner fmt = "#%d"; 31198524Sfenner (void)snprintf(buf, sizeof(buf), fmt, v); 31298524Sfenner return (buf); 31398524Sfenner} 31498524Sfenner 315127668Sbms/* 316127668Sbms * Convert a 32-bit netmask to prefixlen if possible 317127668Sbms * the function returns the prefix-len; if plen == -1 318127668Sbms * then conversion was not possible; 319127668Sbms */ 320127668Sbms 321127668Sbmsint 322127668Sbmsmask2plen (u_int32_t mask) 323127668Sbms{ 324127668Sbms u_int32_t bitmasks[33] = { 325127668Sbms 0x00000000, 326127668Sbms 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 327127668Sbms 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000, 328127668Sbms 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000, 329127668Sbms 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000, 330127668Sbms 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000, 331127668Sbms 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00, 332127668Sbms 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, 333127668Sbms 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff 334127668Sbms }; 335127668Sbms int prefix_len = 32; 336127668Sbms 337127668Sbms /* let's see if we can transform the mask into a prefixlen */ 338127668Sbms while (prefix_len >= 0) { 339127668Sbms if (bitmasks[prefix_len] == mask) 340127668Sbms break; 341127668Sbms prefix_len--; 342127668Sbms } 343127668Sbms return (prefix_len); 344127668Sbms} 345127668Sbms 34617680Spst/* VARARGS */ 34775115Sfennervoid 34817680Spsterror(const char *fmt, ...) 34917680Spst{ 35017680Spst va_list ap; 35117680Spst 35217680Spst (void)fprintf(stderr, "%s: ", program_name); 35317680Spst va_start(ap, fmt); 35417680Spst (void)vfprintf(stderr, fmt, ap); 35517680Spst va_end(ap); 35617680Spst if (*fmt) { 35717680Spst fmt += strlen(fmt); 35817680Spst if (fmt[-1] != '\n') 35917680Spst (void)fputc('\n', stderr); 36017680Spst } 36117680Spst exit(1); 36217680Spst /* NOTREACHED */ 36317680Spst} 36417680Spst 36517680Spst/* VARARGS */ 36617680Spstvoid 36717680Spstwarning(const char *fmt, ...) 36817680Spst{ 36917680Spst va_list ap; 37017680Spst 37117680Spst (void)fprintf(stderr, "%s: WARNING: ", program_name); 37217680Spst va_start(ap, fmt); 37317680Spst (void)vfprintf(stderr, fmt, ap); 37417680Spst va_end(ap); 37517680Spst if (*fmt) { 37617680Spst fmt += strlen(fmt); 37717680Spst if (fmt[-1] != '\n') 37817680Spst (void)fputc('\n', stderr); 37917680Spst } 38017680Spst} 38117680Spst 38217680Spst/* 38317680Spst * Copy arg vector into a new buffer, concatenating arguments with spaces. 38417680Spst */ 38517680Spstchar * 38617680Spstcopy_argv(register char **argv) 38717680Spst{ 38817680Spst register char **p; 38917680Spst register u_int len = 0; 39017680Spst char *buf; 39117680Spst char *src, *dst; 39217680Spst 39317680Spst p = argv; 39417680Spst if (*p == 0) 39517680Spst return 0; 39617680Spst 39717680Spst while (*p) 39817680Spst len += strlen(*p++) + 1; 39917680Spst 40017680Spst buf = (char *)malloc(len); 40117680Spst if (buf == NULL) 40217680Spst error("copy_argv: malloc"); 40317680Spst 40417680Spst p = argv; 40517680Spst dst = buf; 40617680Spst while ((src = *p++) != NULL) { 40717680Spst while ((*dst++ = *src++) != '\0') 40817680Spst ; 40917680Spst dst[-1] = ' '; 41017680Spst } 41117680Spst dst[-1] = '\0'; 41217680Spst 41317680Spst return buf; 41417680Spst} 41517680Spst 416127668Sbms/* 417127668Sbms * On Windows, we need to open the file in binary mode, so that 418127668Sbms * we get all the bytes specified by the size we get from "fstat()". 419127668Sbms * On UNIX, that's not necessary. O_BINARY is defined on Windows; 420127668Sbms * we define it as 0 if it's not defined, so it does nothing. 421127668Sbms */ 422127668Sbms#ifndef O_BINARY 423127668Sbms#define O_BINARY 0 424127668Sbms#endif 425127668Sbms 42617680Spstchar * 42717680Spstread_infile(char *fname) 42817680Spst{ 429127668Sbms register int i, fd, cc; 43017680Spst register char *cp; 43117680Spst struct stat buf; 43217680Spst 433127668Sbms fd = open(fname, O_RDONLY|O_BINARY); 43417680Spst if (fd < 0) 43517680Spst error("can't open %s: %s", fname, pcap_strerror(errno)); 43617680Spst 43717680Spst if (fstat(fd, &buf) < 0) 43817680Spst error("can't stat %s: %s", fname, pcap_strerror(errno)); 43917680Spst 44017680Spst cp = malloc((u_int)buf.st_size + 1); 44198524Sfenner if (cp == NULL) 44298524Sfenner error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1, 44398524Sfenner fname, pcap_strerror(errno)); 44498524Sfenner cc = read(fd, cp, (u_int)buf.st_size); 44517680Spst if (cc < 0) 44617680Spst error("read %s: %s", fname, pcap_strerror(errno)); 44717680Spst if (cc != buf.st_size) 44817680Spst error("short read %s (%d != %d)", fname, cc, (int)buf.st_size); 44917680Spst 450127668Sbms close(fd); 451127668Sbms /* replace "# comment" with spaces */ 452127668Sbms for (i = 0; i < cc; i++) { 453127668Sbms if (cp[i] == '#') 454127668Sbms while (i < cc && cp[i] != '\n') 455127668Sbms cp[i++] = ' '; 456127668Sbms } 457127668Sbms cp[cc] = '\0'; 45817680Spst return (cp); 45917680Spst} 46075115Sfenner 46175115Sfennervoid 46275115Sfennersafeputs(const char *s) 46375115Sfenner{ 46475115Sfenner while (*s) { 46575115Sfenner safeputchar(*s); 46675115Sfenner s++; 46775115Sfenner } 46875115Sfenner} 46975115Sfenner 47075115Sfennervoid 47175115Sfennersafeputchar(int c) 47275115Sfenner{ 47375115Sfenner unsigned char ch; 47475115Sfenner 47575115Sfenner ch = (unsigned char)(c & 0xff); 476111726Sfenner if (ch < 0x80 && isprint(ch)) 477111726Sfenner printf("%c", ch); 47875115Sfenner else 479111726Sfenner printf("\\%03o", ch); 48075115Sfenner} 481