Don't do pcap heuristics on a pipe.

Instead, just:

  assume a file with the regular pcap magic number is a regular pcap
  file, not an unhelpfully-modified-without-changing-the-magic-number
  format such as one of the (fortunately, short-lived) memory-mapped
  capture formats or the Nokia format;

  reject a file with the memory-mapped-capture-finally-changed-the-
  magic-number magic number, as they then changed the *new* format
  without changing its magic number;

  and don't even leave a provision for multiple formats using the
  "nanosecond pcap" magic number - not even when reading from a file -
  so we can punish bad behavior (which is what changing the format
  without changing the magic number is).

This should get rid of the last place where, when reading a pcap file
from a pipe, the first packet isn't displayed as soon as it arrives.

Bug: 14345
Change-Id: I2fcb3354dc84cdd2d8ec749a0db883e56971c4b4
Reviewed-on: https://code.wireshark.org/review/25383
Reviewed-by: Guy Harris <guy@alum.mit.edu>
This commit is contained in:
Guy Harris 2018-01-18 23:06:24 -08:00
parent ecced16299
commit 5b9e9b3fe3
3 changed files with 87 additions and 49 deletions

View File

@ -720,6 +720,7 @@ wtap_open_offline(const char *filename, unsigned int type, int *err, char **err_
{ {
int fd; int fd;
ws_statb64 statb; ws_statb64 statb;
gboolean ispipe = FALSE;
wtap *wth; wtap *wth;
unsigned int i; unsigned int i;
gboolean use_stdin = FALSE; gboolean use_stdin = FALSE;
@ -761,6 +762,7 @@ wtap_open_offline(const char *filename, unsigned int type, int *err, char **err_
*err = WTAP_ERR_RANDOM_OPEN_PIPE; *err = WTAP_ERR_RANDOM_OPEN_PIPE;
return NULL; return NULL;
} }
ispipe = TRUE;
} else if (S_ISDIR(statb.st_mode)) { } else if (S_ISDIR(statb.st_mode)) {
/* /*
* Return different errors for "this is a directory" * Return different errors for "this is a directory"
@ -836,6 +838,7 @@ wtap_open_offline(const char *filename, unsigned int type, int *err, char **err_
wth->random_fh = NULL; wth->random_fh = NULL;
/* initialization */ /* initialization */
wth->ispipe = ispipe;
wth->file_encap = WTAP_ENCAP_UNKNOWN; wth->file_encap = WTAP_ENCAP_UNKNOWN;
wth->subtype_sequential_close = NULL; wth->subtype_sequential_close = NULL;
wth->subtype_close = NULL; wth->subtype_close = NULL;

View File

@ -88,12 +88,8 @@ wtap_open_return_val libpcap_open(wtap *wth, int *err, gchar **err_info)
WTAP_FILE_TYPE_SUBTYPE_PCAP_NOKIA WTAP_FILE_TYPE_SUBTYPE_PCAP_NOKIA
}; };
#define N_SUBTYPES_STANDARD G_N_ELEMENTS(subtypes_standard) #define N_SUBTYPES_STANDARD G_N_ELEMENTS(subtypes_standard)
static const int subtypes_nsec[] = {
WTAP_FILE_TYPE_SUBTYPE_PCAP_NSEC
};
#define N_SUBTYPES_NSEC G_N_ELEMENTS(subtypes_nsec)
#define MAX_FIGURES_OF_MERIT \ #define MAX_FIGURES_OF_MERIT \
MAX(MAX(N_SUBTYPES_MODIFIED, N_SUBTYPES_STANDARD), N_SUBTYPES_NSEC) MAX(N_SUBTYPES_MODIFIED, N_SUBTYPES_STANDARD)
int figures_of_merit[MAX_FIGURES_OF_MERIT]; int figures_of_merit[MAX_FIGURES_OF_MERIT];
const int *subtypes; const int *subtypes;
int n_subtypes; int n_subtypes;
@ -362,80 +358,118 @@ wtap_open_return_val libpcap_open(wtap *wth, int *err, gchar **err_info)
* Oh, and if it has the standard magic number, it might, instead, * Oh, and if it has the standard magic number, it might, instead,
* be a Nokia libpcap file, so we may need to try that if * be a Nokia libpcap file, so we may need to try that if
* neither normal nor ss990417 headers work. * neither normal nor ss990417 headers work.
*
* But don't do that if the input is a pipe; that would mean the
* open won't complete until two packets have been written to
* the pipe, unless the pipe is closed after one packet has
* been written, so a program reading from the file won't see
* the first packet until the second packet has been written.
*/ */
if (modified) { if (modified) {
/* /*
* Well, we have the magic number from Alexey's * Well, we have the magic number from Alexey's
* later two patches. Try the subtypes for that. * later two patches. Try the subtypes for that,
* and fail if we're reading from a pipe.
*/ */
wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_UNKNOWN;
subtypes = subtypes_modified; subtypes = subtypes_modified;
n_subtypes = N_SUBTYPES_MODIFIED; n_subtypes = N_SUBTYPES_MODIFIED;
} else { } else {
if (wth->file_tsprec == WTAP_TSPREC_NSEC) { if (wth->file_tsprec == WTAP_TSPREC_NSEC) {
/* /*
* We have nanosecond-format libpcap's magic * We have nanosecond-format libpcap's magic
* number. Try the subtypes for that. * number. There's only one format with that
* magic number (if somebody comes up with
* another one, we'll just refuse to support
* it and tell them to ask The Tcpdump Group
* for another magic number).
*/ */
subtypes = subtypes_nsec; wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_PCAP_NSEC;
n_subtypes = N_SUBTYPES_NSEC; subtypes = NULL;
n_subtypes = 0;
} else { } else {
/* /*
* We have the regular libpcap magic number. * We have the regular libpcap magic number.
* Try the subtypes for that. * Try the subtypes for that, unless we're
* reading from a pipe, in which case we
* just assume it's a regular libpcap file.
*/ */
wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_PCAP;
subtypes = subtypes_standard; subtypes = subtypes_standard;
n_subtypes = N_SUBTYPES_STANDARD; n_subtypes = N_SUBTYPES_STANDARD;
} }
} }
/* /*
* Try all the subtypes. * Do we have any subtypes to try?
*/ */
first_packet_offset = file_tell(wth->fh); if (n_subtypes == 0) {
for (i = 0; i < n_subtypes; i++) { /*
wth->file_type_subtype = subtypes[i]; * No, so just use what we picked.
figures_of_merit[i] = libpcap_try(wth, err, err_info); */
if (figures_of_merit[i] == -1) { goto done;
/* } else if (wth->ispipe) {
* Well, we couldn't even read it. /*
* Give up. * It's a pipe, so use what we picked, unless we picked
*/ * WTAP_FILE_TYPE_SUBTYPE_UNKNOWN, in which case we fail.
*/
if (wth->file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_UNKNOWN) {
*err = WTAP_ERR_UNSUPPORTED;
*err_info = g_strdup("pcap: that type of pcap file can't be read from a pipe");
return WTAP_OPEN_ERROR; return WTAP_OPEN_ERROR;
} }
if (figures_of_merit[i] == 0) { goto done;
/* } else {
* This format doesn't have any issues. first_packet_offset = file_tell(wth->fh);
* Put the seek pointer back, and finish. for (i = 0; i < n_subtypes; i++) {
*/ wth->file_type_subtype = subtypes[i];
if (file_seek(wth->fh, first_packet_offset, SEEK_SET, err) == -1) { figures_of_merit[i] = libpcap_try(wth, err, err_info);
if (figures_of_merit[i] == -1) {
/*
* Well, we couldn't even read it.
* Give up.
*/
return WTAP_OPEN_ERROR; return WTAP_OPEN_ERROR;
} }
goto done; if (figures_of_merit[i] == 0) {
} /*
* This format doesn't have any issues.
* Put the seek pointer back, and finish,
* using that format as the subtype.
*/
if (file_seek(wth->fh, first_packet_offset,
SEEK_SET, err) == -1) {
return WTAP_OPEN_ERROR;
}
goto done;
}
/*
* OK, we've recorded the figure of merit for this one;
* go back to the first packet and try the next one.
*/
if (file_seek(wth->fh, first_packet_offset, SEEK_SET, err) == -1) {
return WTAP_OPEN_ERROR;
}
}
/*
* OK, none are perfect; let's see which one is least bad.
*/
best_subtype = INT_MAX;
for (i = 0; i < n_subtypes; i++) {
/*
* Is this subtype better than the last one we saw?
*/
if (figures_of_merit[i] < best_subtype) {
/* /*
* Yes. Choose it until we find a better one. * OK, we've recorded the figure of merit for this
* one; go back to the first packet and try the
* next one.
*/ */
wth->file_type_subtype = subtypes[i]; if (file_seek(wth->fh, first_packet_offset, SEEK_SET,
best_subtype = figures_of_merit[i]; err) == -1) {
return WTAP_OPEN_ERROR;
}
}
/*
* OK, none are perfect; let's see which one is least bad.
*/
best_subtype = INT_MAX;
for (i = 0; i < n_subtypes; i++) {
/*
* Is this subtype better than the last one we saw?
*/
if (figures_of_merit[i] < best_subtype) {
/*
* Yes. Choose it until we find a better one.
*/
wth->file_type_subtype = subtypes[i];
best_subtype = figures_of_merit[i];
}
} }
} }

View File

@ -47,6 +47,7 @@ typedef gboolean (*subtype_seek_read_func)(struct wtap*, gint64,
struct wtap { struct wtap {
FILE_T fh; FILE_T fh;
FILE_T random_fh; /**< Secondary FILE_T for random access */ FILE_T random_fh; /**< Secondary FILE_T for random access */
gboolean ispipe; /**< TRUE if the file is a pipe */
int file_type_subtype; int file_type_subtype;
guint snapshot_length; guint snapshot_length;
struct Buffer *frame_buffer; struct Buffer *frame_buffer;