X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/b83e04bd09ac42db9e362a627568a8efbe099c22..b226ebedc9f7762b07029d77bd3b4a107ae1c087:/util.c diff --git a/util.c b/util.c index 6a827dce..4a20a4b5 100644 --- a/util.c +++ b/util.c @@ -35,7 +35,6 @@ * FOR A PARTICULAR PURPOSE. */ -#define NETDISSECT_REWORKED #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -54,685 +53,6 @@ #include "interface.h" -/* - * Print out a null-terminated filename (or other ascii string). - * If ep is NULL, assume no truncation check is needed. - * Return true if truncated. - */ -int -fn_print(netdissect_options *ndo, - register const u_char *s, register const u_char *ep) -{ - register int ret; - register u_char c; - - ret = 1; /* assume truncated */ - while (ep == NULL || s < ep) { - c = *s++; - if (c == '\0') { - ret = 0; - break; - } - if (!ND_ISASCII(c)) { - c = ND_TOASCII(c); - ND_PRINT((ndo, "M-")); - } - if (!ND_ISPRINT(c)) { - c ^= 0x40; /* DEL to ?, others to alpha */ - ND_PRINT((ndo, "^")); - } - ND_PRINT((ndo, "%c", c)); - } - return(ret); -} - -/* - * Print out a counted filename (or other ascii string). - * If ep is NULL, assume no truncation check is needed. - * Return true if truncated. - */ -int -fn_printn(netdissect_options *ndo, - register const u_char *s, register u_int n, register const u_char *ep) -{ - register u_char c; - - while (n > 0 && (ep == NULL || s < ep)) { - n--; - c = *s++; - if (!ND_ISASCII(c)) { - c = ND_TOASCII(c); - ND_PRINT((ndo, "M-")); - } - if (!ND_ISPRINT(c)) { - c ^= 0x40; /* DEL to ?, others to alpha */ - ND_PRINT((ndo, "^")); - } - ND_PRINT((ndo, "%c", c)); - } - return (n == 0) ? 0 : 1; -} - -/* - * Print out a null-padded filename (or other ascii string). - * If ep is NULL, assume no truncation check is needed. - * Return true if truncated. - */ -int -fn_printzp(netdissect_options *ndo, - register const u_char *s, register u_int n, - register const u_char *ep) -{ - register int ret; - register u_char c; - - ret = 1; /* assume truncated */ - while (n > 0 && (ep == NULL || s < ep)) { - n--; - c = *s++; - if (c == '\0') { - ret = 0; - break; - } - if (!ND_ISASCII(c)) { - c = ND_TOASCII(c); - ND_PRINT((ndo, "M-")); - } - if (!ND_ISPRINT(c)) { - c ^= 0x40; /* DEL to ?, others to alpha */ - ND_PRINT((ndo, "^")); - } - ND_PRINT((ndo, "%c", c)); - } - return (n == 0) ? 0 : ret; -} - -/* - * Format the timestamp - */ -static char * -ts_format(netdissect_options *ndo -#ifndef HAVE_PCAP_SET_TSTAMP_PRECISION -_U_ -#endif -, int sec, int usec) -{ - static char buf[sizeof("00:00:00.000000000")]; - const char *format; - -#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION - switch (ndo->ndo_tstamp_precision) { - - case PCAP_TSTAMP_PRECISION_MICRO: - format = "%02d:%02d:%02d.%06u"; - break; - - case PCAP_TSTAMP_PRECISION_NANO: - format = "%02d:%02d:%02d.%09u"; - break; - - default: - format = "%02d:%02d:%02d.{unknown precision}"; - break; - } -#else - format = "%02d:%02d:%02d.%06u"; -#endif - - snprintf(buf, sizeof(buf), format, - sec / 3600, (sec % 3600) / 60, sec % 60, usec); - - return buf; -} - -/* - * Print the timestamp - */ -void -ts_print(netdissect_options *ndo, - register const struct timeval *tvp) -{ - register int s; - struct tm *tm; - time_t Time; - static unsigned b_sec; - static unsigned b_usec; - int d_usec; - int d_sec; - - switch (ndo->ndo_tflag) { - - case 0: /* Default */ - s = (tvp->tv_sec + thiszone) % 86400; - ND_PRINT((ndo, "%s ", ts_format(ndo, s, tvp->tv_usec))); - break; - - case 1: /* No time stamp */ - break; - - case 2: /* Unix timeval style */ - ND_PRINT((ndo, "%u.%06u ", - (unsigned)tvp->tv_sec, - (unsigned)tvp->tv_usec)); - break; - - case 3: /* Microseconds since previous packet */ - case 5: /* Microseconds since first packet */ - if (b_sec == 0) { - /* init timestamp for first packet */ - b_usec = tvp->tv_usec; - b_sec = tvp->tv_sec; - } - - d_usec = tvp->tv_usec - b_usec; - d_sec = tvp->tv_sec - b_sec; - - while (d_usec < 0) { - d_usec += 1000000; - d_sec--; - } - - ND_PRINT((ndo, "%s ", ts_format(ndo, d_sec, d_usec))); - - if (ndo->ndo_tflag == 3) { /* set timestamp for last packet */ - b_sec = tvp->tv_sec; - b_usec = tvp->tv_usec; - } - break; - - case 4: /* Default + Date*/ - s = (tvp->tv_sec + thiszone) % 86400; - Time = (tvp->tv_sec + thiszone) - s; - tm = gmtime (&Time); - if (!tm) - ND_PRINT((ndo, "Date fail ")); - else - ND_PRINT((ndo, "%04d-%02d-%02d %s ", - tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, - ts_format(ndo, s, tvp->tv_usec))); - break; - } -} - -/* - * Print a relative number of seconds (e.g. hold time, prune timer) - * in the form 5m1s. This does no truncation, so 32230861 seconds - * is represented as 1y1w1d1h1m1s. - */ -void -relts_print(netdissect_options *ndo, - int secs) -{ - static const char *lengths[] = {"y", "w", "d", "h", "m", "s"}; - static const int seconds[] = {31536000, 604800, 86400, 3600, 60, 1}; - const char **l = lengths; - const int *s = seconds; - - if (secs == 0) { - ND_PRINT((ndo, "0s")); - return; - } - if (secs < 0) { - ND_PRINT((ndo, "-")); - secs = -secs; - } - while (secs > 0) { - if (secs >= *s) { - ND_PRINT((ndo, "%d%s", secs / *s, *l)); - secs -= (secs / *s) * *s; - } - s++; - l++; - } -} - -/* - * this is a generic routine for printing unknown data; - * we pass on the linefeed plus indentation string to - * get a proper output - returns 0 on error - */ - -int -print_unknown_data(netdissect_options *ndo, const u_char *cp,const char *ident,int len) -{ - if (len < 0) { - ND_PRINT((ndo,"%sDissector error: print_unknown_data called with negative length", - ident)); - return(0); - } - if (ndo->ndo_snapend - cp < len) - len = ndo->ndo_snapend - cp; - if (len < 0) { - ND_PRINT((ndo,"%sDissector error: print_unknown_data called with pointer past end of packet", - ident)); - return(0); - } - hex_print(ndo, ident,cp,len); - return(1); /* everything is ok */ -} - -/* - * Convert a token value to a string; use "fmt" if not found. - */ -const char * -tok2strbuf(register const struct tok *lp, register const char *fmt, - register u_int v, char *buf, size_t bufsize) -{ - if (lp != NULL) { - while (lp->s != NULL) { - if (lp->v == v) - return (lp->s); - ++lp; - } - } - if (fmt == NULL) - fmt = "#%d"; - - (void)snprintf(buf, bufsize, fmt, v); - return (const char *)buf; -} - -/* - * Convert a token value to a string; use "fmt" if not found. - */ -const char * -tok2str(register const struct tok *lp, register const char *fmt, - register int v) -{ - static char buf[4][128]; - static int idx = 0; - char *ret; - - ret = buf[idx]; - idx = (idx+1) & 3; - return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0])); -} - -/* - * Convert a bit token value to a string; use "fmt" if not found. - * this is useful for parsing bitfields, the output strings are seperated - * if the s field is positive. - */ -static char * -bittok2str_internal(register const struct tok *lp, register const char *fmt, - register int v, register int sep) -{ - static char buf[256]; /* our stringbuffer */ - int buflen=0; - register int rotbit; /* this is the bit we rotate through all bitpositions */ - register int tokval; - const char * sepstr = ""; - - while (lp != NULL && lp->s != NULL) { - tokval=lp->v; /* load our first value */ - rotbit=1; - while (rotbit != 0) { - /* - * lets AND the rotating bit with our token value - * and see if we have got a match - */ - if (tokval == (v&rotbit)) { - /* ok we have found something */ - buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s%s", - sepstr, lp->s); - sepstr = sep ? ", " : ""; - break; - } - rotbit=rotbit<<1; /* no match - lets shift and try again */ - } - lp++; - } - - if (buflen == 0) - /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */ - (void)snprintf(buf, sizeof(buf), fmt == NULL ? "#%d" : fmt, v); - return (buf); -} - -/* - * Convert a bit token value to a string; use "fmt" if not found. - * this is useful for parsing bitfields, the output strings are not seperated. - */ -char * -bittok2str_nosep(register const struct tok *lp, register const char *fmt, - register int v) -{ - return (bittok2str_internal(lp, fmt, v, 0)); -} - -/* - * Convert a bit token value to a string; use "fmt" if not found. - * this is useful for parsing bitfields, the output strings are comma seperated. - */ -char * -bittok2str(register const struct tok *lp, register const char *fmt, - register int v) -{ - return (bittok2str_internal(lp, fmt, v, 1)); -} - -/* - * Convert a value to a string using an array; the macro - * tok2strary() in is the public interface to - * this function and ensures that the second argument is - * correct for bounds-checking. - */ -const char * -tok2strary_internal(register const char **lp, int n, register const char *fmt, - register int v) -{ - static char buf[128]; - - if (v >= 0 && v < n && lp[v] != NULL) - return lp[v]; - if (fmt == NULL) - fmt = "#%d"; - (void)snprintf(buf, sizeof(buf), fmt, v); - return (buf); -} - -/* - * Convert a 32-bit netmask to prefixlen if possible - * the function returns the prefix-len; if plen == -1 - * then conversion was not possible; - */ - -int -mask2plen(uint32_t mask) -{ - uint32_t bitmasks[33] = { - 0x00000000, - 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, - 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000, - 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000, - 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000, - 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000, - 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00, - 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, - 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff - }; - int prefix_len = 32; - - /* let's see if we can transform the mask into a prefixlen */ - while (prefix_len >= 0) { - if (bitmasks[prefix_len] == mask) - break; - prefix_len--; - } - return (prefix_len); -} - -#ifdef INET6 -int -mask62plen(const u_char *mask) -{ - u_char bitmasks[9] = { - 0x00, - 0x80, 0xc0, 0xe0, 0xf0, - 0xf8, 0xfc, 0xfe, 0xff - }; - int byte; - int cidr_len = 0; - - for (byte = 0; byte < 16; byte++) { - u_int bits; - - for (bits = 0; bits < (sizeof (bitmasks) / sizeof (bitmasks[0])); bits++) { - if (mask[byte] == bitmasks[bits]) { - cidr_len += bits; - break; - } - } - - if (mask[byte] != 0xff) - break; - } - return (cidr_len); -} -#endif /* INET6 */ - -/* - * Routine to print out information for text-based protocols such as FTP, - * HTTP, SMTP, RTSP, SIP, .... - */ -#define MAX_TOKEN 128 - -/* - * Fetch a token from a packet, starting at the specified index, - * and return the length of the token. - * - * Returns 0 on error; yes, this is indistinguishable from an empty - * token, but an "empty token" isn't a valid token - it just means - * either a space character at the beginning of the line (this - * includes a blank line) or no more tokens remaining on the line. - */ -static int -fetch_token(netdissect_options *ndo, const u_char *pptr, u_int idx, u_int len, - u_char *tbuf, size_t tbuflen) -{ - size_t toklen = 0; - - for (; idx < len; idx++) { - if (!ND_TTEST(*(pptr + idx))) { - /* ran past end of captured data */ - return (0); - } - if (!isascii(*(pptr + idx))) { - /* not an ASCII character */ - return (0); - } - if (isspace(*(pptr + idx))) { - /* end of token */ - break; - } - if (!isprint(*(pptr + idx))) { - /* not part of a command token or response code */ - return (0); - } - if (toklen + 2 > tbuflen) { - /* no room for this character and terminating '\0' */ - return (0); - } - tbuf[toklen] = *(pptr + idx); - toklen++; - } - if (toklen == 0) { - /* no token */ - return (0); - } - tbuf[toklen] = '\0'; - - /* - * Skip past any white space after the token, until we see - * an end-of-line (CR or LF). - */ - for (; idx < len; idx++) { - if (!ND_TTEST(*(pptr + idx))) { - /* ran past end of captured data */ - break; - } - if (*(pptr + idx) == '\r' || *(pptr + idx) == '\n') { - /* end of line */ - break; - } - if (!isascii(*(pptr + idx)) || !isprint(*(pptr + idx))) { - /* not a printable ASCII character */ - break; - } - if (!isspace(*(pptr + idx))) { - /* beginning of next token */ - break; - } - } - return (idx); -} - -/* - * Scan a buffer looking for a line ending - LF or CR-LF. - * Return the index of the character after the line ending or 0 if - * we encounter a non-ASCII or non-printable character or don't find - * the line ending. - */ -static u_int -print_txt_line(netdissect_options *ndo, const char *protoname, - const char *prefix, const u_char *pptr, u_int idx, u_int len) -{ - u_int startidx; - u_int linelen; - - startidx = idx; - while (idx < len) { - ND_TCHECK(*(pptr+idx)); - if (*(pptr+idx) == '\n') { - /* - * LF without CR; end of line. - * Skip the LF and print the line, with the - * exception of the LF. - */ - linelen = idx - startidx; - idx++; - goto print; - } else if (*(pptr+idx) == '\r') { - /* CR - any LF? */ - if ((idx+1) >= len) { - /* not in this packet */ - return (0); - } - ND_TCHECK(*(pptr+idx+1)); - if (*(pptr+idx+1) == '\n') { - /* - * CR-LF; end of line. - * Skip the CR-LF and print the line, with - * the exception of the CR-LF. - */ - linelen = idx - startidx; - idx += 2; - goto print; - } - - /* - * CR followed by something else; treat this - * as if it were binary data, and don't print - * it. - */ - return (0); - } else if (!isascii(*(pptr+idx)) || - (!isprint(*(pptr+idx)) && *(pptr+idx) != '\t')) { - /* - * Not a printable ASCII character and not a tab; - * treat this as if it were binary data, and - * don't print it. - */ - return (0); - } - idx++; - } - - /* - * All printable ASCII, but no line ending after that point - * in the buffer; treat this as if it were truncated. - */ -trunc: - ND_PRINT((ndo, "%s%.*s[!%s]", prefix, (int)linelen, pptr + startidx, - protoname)); - return (0); - -print: - ND_PRINT((ndo, "%s%.*s", prefix, (int)linelen, pptr + startidx)); - return (idx); -} - -void -txtproto_print(netdissect_options *ndo, const u_char *pptr, u_int len, - const char *protoname, const char **cmds, u_int flags) -{ - u_int idx, eol; - u_char token[MAX_TOKEN+1]; - const char *cmd; - int is_reqresp = 0; - const char *pnp; - - if (cmds != NULL) { - /* - * This protocol has more than just request and - * response lines; see whether this looks like a - * request or response. - */ - idx = fetch_token(ndo, pptr, 0, len, token, sizeof(token)); - if (idx != 0) { - /* Is this a valid request name? */ - while ((cmd = *cmds++) != NULL) { - if (strcasecmp((const char *)token, cmd) == 0) { - /* Yes. */ - is_reqresp = 1; - break; - } - } - - /* - * No - is this a valid response code (3 digits)? - * - * Is this token the response code, or is the next - * token the response code? - */ - if (flags & RESP_CODE_SECOND_TOKEN) { - /* - * Next token - get it. - */ - idx = fetch_token(ndo, pptr, idx, len, token, - sizeof(token)); - } - if (idx != 0) { - if (isdigit(token[0]) && isdigit(token[1]) && - isdigit(token[2]) && token[3] == '\0') { - /* Yes. */ - is_reqresp = 1; - } - } - } - } else { - /* - * This protocol has only request and response lines - * (e.g., FTP, where all the data goes over a - * different connection); assume the payload is - * a request or response. - */ - is_reqresp = 1; - } - - /* Capitalize the protocol name */ - for (pnp = protoname; *pnp != '\0'; pnp++) - ND_PRINT((ndo, "%c", toupper(*pnp))); - - if (is_reqresp) { - /* - * In non-verbose mode, just print the protocol, followed - * by the first line as the request or response info. - * - * In verbose mode, print lines as text until we run out - * of characters or see something that's not a - * printable-ASCII line. - */ - if (ndo->ndo_vflag) { - /* - * We're going to print all the text lines in the - * request or response; just print the length - * on the first line of the output. - */ - ND_PRINT((ndo, ", length: %u", len)); - for (idx = 0; - idx < len && (eol = print_txt_line(ndo, protoname, "\n\t", pptr, idx, len)) != 0; - idx = eol) - ; - } else { - /* - * Just print the first text line. - */ - print_txt_line(ndo, protoname, ": ", pptr, 0, len); - } - } -} - /* VARARGS */ void error(const char *fmt, ...) @@ -847,43 +167,3 @@ read_infile(char *fname) cp[cc] = '\0'; return (cp); } - -void -safeputs(netdissect_options *ndo, - const u_char *s, const u_int maxlen) -{ - u_int idx = 0; - - while (*s && idx < maxlen) { - safeputchar(ndo, *s); - idx++; - s++; - } -} - -void -safeputchar(netdissect_options *ndo, - const u_char c) -{ - ND_PRINT((ndo, (c < 0x80 && ND_ISPRINT(c)) ? "%c" : "\\0x%02x", c)); -} - -#ifdef LBL_ALIGN -/* - * Some compilers try to optimize memcpy(), using the alignment constraint - * on the argument pointer type. by using this function, we try to avoid the - * optimization. - */ -void -unaligned_memcpy(void *p, const void *q, size_t l) -{ - memcpy(p, q, l); -} - -/* As with memcpy(), so with memcmp(). */ -int -unaligned_memcmp(const void *p, const void *q, size_t l) -{ - return (memcmp(p, q, l)); -} -#endif