diff --git a/tcpdump/netdissect.h b/tcpdump/netdissect.h index 72b05f3..de9e303 100644 --- a/tcpdump/netdissect.h +++ b/tcpdump/netdissect.h @@ -431,6 +431,9 @@ extern void ts_print(netdissect_options *, const struct timeval *); extern void signed_relts_print(netdissect_options *, int32_t); extern void unsigned_relts_print(netdissect_options *, uint32_t); +extern const char *nd_format_time(char *buf, size_t bufsize, + const char *format, const struct tm *timeptr); + extern void fn_print_char(netdissect_options *, u_char); extern void fn_print_str(netdissect_options *, const u_char *); extern u_int nd_printztn(netdissect_options *, const u_char *, u_int, const u_char *); diff --git a/tcpdump/ntp.c b/tcpdump/ntp.c index 4d17932..ec8f659 100644 --- a/tcpdump/ntp.c +++ b/tcpdump/ntp.c @@ -48,15 +48,14 @@ p_ntp_time(netdissect_options *ndo, f = (uint32_t)(ff * 1000000000.0); /* treat fraction as parts per billion */ ND_PRINT("%u.%09u", i, f); -#ifdef HAVE_STRFTIME /* * print the UTC time in human-readable format. */ if (i) { int64_t seconds_64bit = (int64_t)i - JAN_1970; time_t seconds; - struct tm *tm; char time_buf[128]; + const char *time_string; seconds = (time_t)seconds_64bit; if (seconds != seconds_64bit) { @@ -64,22 +63,12 @@ p_ntp_time(netdissect_options *ndo, * It doesn't fit into a time_t, so we can't hand it * to gmtime. */ - ND_PRINT(" (unrepresentable)"); + time_string = "[Time is too large to fit into a time_t]"; } else { - tm = gmtime(&seconds); - if (tm == NULL) { - /* - * gmtime() can't handle it. - * (Yes, that might happen with some version of - * Microsoft's C library.) - */ - ND_PRINT(" (unrepresentable)"); - } else { - /* use ISO 8601 (RFC3339) format */ - strftime(time_buf, sizeof (time_buf), "%Y-%m-%dT%H:%M:%SZ", tm); - ND_PRINT(" (%s)", time_buf); - } + /* use ISO 8601 (RFC3339) format */ + time_string = nd_format_time(time_buf, sizeof (time_buf), + "%Y-%m-%dT%H:%M:%SZ", gmtime(&seconds)); } + ND_PRINT(" (%s)", time_string); } -#endif } diff --git a/tcpdump/print-ahcp.c b/tcpdump/print-ahcp.c index 9859f76..d57edda 100644 --- a/tcpdump/print-ahcp.c +++ b/tcpdump/print-ahcp.c @@ -102,18 +102,14 @@ ahcp_time_print(netdissect_options *ndo, const u_char *cp, uint8_t len) { time_t t; - struct tm *tm; - char buf[BUFSIZE]; + char buf[sizeof("-yyyyyyyyyy-mm-dd hh:mm:ss UTC")]; if (len != 4) goto invalid; t = GET_BE_U_4(cp); - if (NULL == (tm = gmtime(&t))) - ND_PRINT(": gmtime() error"); - else if (0 == strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm)) - ND_PRINT(": strftime() error"); - else - ND_PRINT(": %s UTC", buf); + ND_PRINT(": %s", + nd_format_time(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S UTC", + gmtime(&t))); return; invalid: diff --git a/tcpdump/print-arista.c b/tcpdump/print-arista.c index 0d1d5d9..9efabb7 100644 --- a/tcpdump/print-arista.c +++ b/tcpdump/print-arista.c @@ -32,16 +32,13 @@ arista_print_date_hms_time(netdissect_options *ndo, uint32_t seconds, uint32_t nanoseconds) { time_t ts; - struct tm *tm; - char buf[BUFSIZE]; + char buf[sizeof("-yyyyyyyyyy-mm-dd hh:mm:ss")]; ts = seconds + (nanoseconds / 1000000000); - if (NULL == (tm = gmtime(&ts))) - ND_PRINT(": gmtime() error"); - else if (0 == strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm)) - ND_PRINT(": strftime() error"); - else - ND_PRINT(": %s, %09u ns, ", buf, nanoseconds); + nanoseconds %= 1000000000; + ND_PRINT("%s, %09u ns, ", + nd_format_time(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", + gmtime(&ts)), nanoseconds); } int @@ -66,7 +63,7 @@ arista_ethertype_print(netdissect_options *ndo, const u_char *bp, u_int len _U_) // TapAgg Header Timestamping if (subTypeId == ARISTA_SUBTYPE_TIMESTAMP) { // Timestamp has 32-bit lsb in nanosec and remaining msb in sec - ND_PRINT("Timestamp %s", tok2str(ts_version_name, + ND_PRINT("Timestamp %s: ", tok2str(ts_version_name, "Unknown timestamp Version 0x%04x ", version)); switch (version) { case ARISTA_TIMESTAMP_64_TAI: @@ -78,7 +75,7 @@ arista_ethertype_print(netdissect_options *ndo, const u_char *bp, u_int len _U_) break; case ARISTA_TIMESTAMP_48_TAI: case ARISTA_TIMESTAMP_48_UTC: - ND_PRINT(": Seconds %u,", GET_BE_U_2(bp)); + ND_PRINT("Seconds %u,", GET_BE_U_2(bp)); ND_PRINT(" Nanoseconds %u, ", GET_BE_U_4(bp + 2)); bytesConsumed += size + 6; break; diff --git a/tcpdump/print-ntp.c b/tcpdump/print-ntp.c index 99c0896..4b02917 100644 --- a/tcpdump/print-ntp.c +++ b/tcpdump/print-ntp.c @@ -38,9 +38,7 @@ #include "netdissect-stdinc.h" -#ifdef HAVE_STRFTIME #include -#endif #include "netdissect.h" #include "addrtoname.h" diff --git a/tcpdump/print-rx.c b/tcpdump/print-rx.c index b8ee5a8..469cf8f 100644 --- a/tcpdump/print-rx.c +++ b/tcpdump/print-rx.c @@ -794,12 +794,12 @@ rx_cache_find(netdissect_options *ndo, const struct rx_header *rxh, ND_PRINT(" %" PRIu64, _i); \ } -#define DATEOUT() { time_t _t; struct tm *tm; char str[256]; \ +#define DATEOUT() { time_t _t; char str[256]; \ _t = (time_t) GET_BE_S_4(bp); \ bp += sizeof(int32_t); \ - tm = localtime(&_t); \ - strftime(str, 256, "%Y/%m/%d %H:%M:%S", tm); \ - ND_PRINT(" %s", str); \ + ND_PRINT(" %s", \ + nd_format_time(str, sizeof(str), \ + "%Y/%m/%d %H:%M:%S", localtime(&_t))); \ } #define STOREATTROUT() { uint32_t mask, _i; \ diff --git a/tcpdump/print-zep.c b/tcpdump/print-zep.c index e10ecb3..0af18cd 100644 --- a/tcpdump/print-zep.c +++ b/tcpdump/print-zep.c @@ -77,20 +77,17 @@ static void zep_print_ts(netdissect_options *ndo, const u_char *p) billion */ ND_PRINT("%u.%09d", i, f); -#ifdef HAVE_STRFTIME /* * print the time in human-readable format. */ if (i) { time_t seconds = i - JAN_1970; - struct tm *tm; char time_buf[128]; - tm = localtime(&seconds); - strftime(time_buf, sizeof (time_buf), "%Y/%m/%d %H:%M:%S", tm); - ND_PRINT(" (%s)", time_buf); + ND_PRINT(" (%s)", + nd_format_time(time_buf, sizeof (time_buf), "%Y/%m/%d %H:%M:%S", + localtime(&seconds))); } -#endif } /* diff --git a/tcpdump/smbutil.c b/tcpdump/smbutil.c index ff32ecc..f33a323 100644 --- a/tcpdump/smbutil.c +++ b/tcpdump/smbutil.c @@ -768,8 +768,8 @@ smb_fdata1(netdissect_options *ndo, case 'T': { time_t t; - struct tm *lt; const char *tstring; + char buffer[sizeof("Www Mmm dd hh:mm:ss yyyyy")]; uint32_t x; switch (atoi(fmt + 1)) { @@ -799,14 +799,11 @@ smb_fdata1(netdissect_options *ndo, break; } if (t != 0) { - lt = localtime(&t); - if (lt != NULL) - tstring = asctime(lt); - else - tstring = "(Can't convert time)\n"; + tstring = nd_format_time(buffer, sizeof(buffer), "%a %b %e %T %Y", + localtime(&t)); } else - tstring = "NULL\n"; - ND_PRINT("%s", tstring); + tstring = "NULL"; + ND_PRINT("%s\n", tstring); fmt++; while (ND_ASCII_ISDIGIT(*fmt)) fmt++; diff --git a/tcpdump/tcpdump.c b/tcpdump/tcpdump.c index 88d2c26..d13e7b1 100644 --- a/tcpdump/tcpdump.c +++ b/tcpdump/tcpdump.c @@ -933,6 +933,8 @@ MakeFilename(char *buffer, char *orig_name, int cnt, int max_chars) char *filename = malloc(PATH_MAX + 1); if (filename == NULL) error("%s: malloc", __func__); + if (strlen(orig_name) == 0) + error("an empty string is not a valid file name"); /* Process with strftime if Gflag is set. */ if (Gflag != 0) { @@ -944,9 +946,25 @@ MakeFilename(char *buffer, char *orig_name, int cnt, int max_chars) } /* There's no good way to detect an error in strftime since a return - * value of 0 isn't necessarily failure. + * value of 0 isn't necessarily failure; if orig_name is an empty + * string, the formatted string will be empty. + * + * However, the C90 standard says that, if there *is* a + * buffer overflow, the content of the buffer is undefined, + * so we must check for a buffer overflow. + * + * So we check above for an empty orig_name, and only call + * strftime() if it's non-empty, in which case the return + * value will only be 0 if the formatted date doesn't fit + * in the buffer. + * + * (We check above because, even if we don't use -G, we + * want a better error message than "tcpdump: : No such + * file or directory" for this case.) */ - strftime(filename, PATH_MAX, orig_name, local_tm); + if (strftime(filename, PATH_MAX, orig_name, local_tm) == 0) { + error("%s: strftime", __func__); + } } else { strncpy(filename, orig_name, PATH_MAX); } diff --git a/tcpdump/tests/TESTonce.sh b/tcpdump/tests/TESTonce.sh index 40edd6d..04f2227 100755 --- a/tcpdump/tests/TESTonce.sh +++ b/tcpdump/tests/TESTonce.sh @@ -17,7 +17,7 @@ input="$2" output="$3" options="$4" -echo "$" "${TCPDUMP_BIN}" "--apple-arp-plain -# -n -r $input $options" >>verbose-outputs.txt +echo "$" "${TCPDUMP_BIN}" "--apple-ext-fmt 0 -# -n -r $input $options" >>verbose-outputs.txt #use eval otherwise $option may contain double quotes '"' eval ${TCPDUMP_BIN} 2>>verbose-outputs.txt --apple-ext-fmt 0 -\# -n -r $input $options >NEW/$output diff --git a/tcpdump/util-print.c b/tcpdump/util-print.c index c32161c..ef4e21e 100644 --- a/tcpdump/util-print.c +++ b/tcpdump/util-print.c @@ -230,7 +230,8 @@ ts_date_hmsfrac_print(netdissect_options *ndo, long sec, long usec, { time_t Time = sec; struct tm *tm; - char timestr[32]; + char timebuf[32]; + const char *timestr; if ((unsigned)sec & 0x80000000) { ND_PRINT("[Error converting time]"); @@ -242,14 +243,13 @@ ts_date_hmsfrac_print(netdissect_options *ndo, long sec, long usec, else tm = gmtime(&Time); - if (!tm) { - ND_PRINT("[Error converting time]"); - return; + if (date_flag == WITH_DATE) { + timestr = nd_format_time(timebuf, sizeof(timebuf), + "%Y-%m-%d %H:%M:%S", tm); + } else { + timestr = nd_format_time(timebuf, sizeof(timebuf), + "%H:%M:%S", tm); } - if (date_flag == WITH_DATE) - strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", tm); - else - strftime(timestr, sizeof(timestr), "%H:%M:%S", tm); ND_PRINT("%s", timestr); ts_frac_print(ndo, usec); @@ -500,6 +500,26 @@ signed_relts_print(netdissect_options *ndo, unsigned_relts_print(ndo, secs); } +/* + * Format a struct tm with strftime(). + * If the pointer to the struct tm is null, that means that the + * routine to convert a time_t to a struct tm failed; the localtime() + * and gmtime() in the Microsoft Visual Studio C library will fail, + * returning null, if the value is before the UNIX Epoch. + */ +const char * +nd_format_time(char *buf, size_t bufsize, const char *format, + const struct tm *timeptr) +{ + if (timeptr != NULL) { + if (strftime(buf, bufsize, format, timeptr) != 0) + return (buf); + else + return ("[nd_format_time() buffer is too small]"); + } else + return ("[localtime() or gmtime() couldn't convert the date and time]"); +} + /* Print the truncated string */ void nd_print_trunc(netdissect_options *ndo) {