pcap: process the subfields of the link-layer-type-plus-stuff field.

Extract the FCS length information from that field, and reject captures
that have a non-zero "class" field (the 10-bit reserved field that was
once intended to allow other "classes" of link layer type, with class 0
being "LINKTYPE_ values", but the original use case doesn't appear ever
to have been used).
This commit is contained in:
Guy Harris 2022-03-04 16:23:02 -08:00
parent 5db8d0930a
commit e999b0a4d2
1 changed files with 91 additions and 41 deletions

View File

@ -55,6 +55,7 @@ typedef struct {
guint16 version_major;
guint16 version_minor;
pcap_variant_t variant;
int fcs_len;
void *encap_priv;
} libpcap_t;
@ -87,6 +88,62 @@ static gboolean libpcap_dump_pcap_ss991029(wtap_dumper *wdh,
static gboolean libpcap_dump_pcap_nokia(wtap_dumper *wdh, const wtap_rec *rec,
const guint8 *pd, int *err, gchar **err_info);
/*
* Subfields of the field containing the link-layer header type.
*
* Link-layer header types are assigned for both pcap and
* pcapng, and the same value must work with both. In pcapng,
* the link-layer header type field in an Interface Description
* Block is 16 bits, so only the bottommost 16 bits of the
* link-layer header type in a pcap file can be used for the
* header type value.
*
* In libpcap, the upper 16 bits, from the top down, are divided into:
*
* A 4-bit "FCS length" field, to allow the FCS length to
* be specified, just as it can be specified in the if_fcslen
* field of the pcapng IDB. The field is in units of 16 bits,
* i.e. 1 means 16 bits of FCS, 2 means 32 bits of FCS, etc..
*
* A reserved bit, which must be zero.
*
* An "FCS length present" flag; if 0, the "FCS length" field
* should be ignored, and if 1, the "FCS length" field should
* be used.
*
* 10 reserved bits, which must be zero. They were originally
* intended to be used as a "class" field, allowing additional
* classes of link-layer types to be defined, with a class value
* of 0 indicating that the link-layer type is a LINKTYPE_ value.
* A value of 0x224 was, at one point, used by NetBSD to define
* "raw" packet types, with the lower 16 bits containing a
* NetBSD AF_ value; see
*
* https://marc.info/?l=tcpdump-workers&m=98296750229149&w=2
*
* It's unknown whether those were ever used in capture files,
* or if the intent was just to use it as a link-layer type
* for BPF programs; NetBSD's libpcap used to support them in
* the BPF code generator, but it no longer does so. If it
* was ever used in capture files, or if classes other than
* "LINKTYPE_ value" are ever useful in capture files, we could
* re-enable this, and use the reserved 16 bits following the
* link-layer type in pcapng files to hold the class information
* there. (Note, BTW, that LINKTYPE_RAW/DLT_RAW is now being
* interpreted by libpcap, tcpdump, and Wireshark as "raw IP",
* including both IPv4 and IPv6, with the version number in the
* header being checked to see which it is, not just "raw IPv4";
* there are LINKTYPE_IPV4/DLT_IPV4 and LINKTYPE_IPV6/DLT_IPV6
* values if "these are IPv{4,6} and only IPv{4,6} packets"
* types are needed.)
*/
#define LT_LINKTYPE(x) ((x) & 0x0000FFFF)
#define LT_CLASS(x) (((x) & 0x3FFF0000) >> 16)
#define LT_CLASS_LINKTYPE 0x0000
#define LT_FCS_LENGTH_PRESENT(x) ((x) & 0x04000000)
#define LT_FCS_LENGTH(x) (((x) & 0xF0000000) >> 28)
#define LT_FCS_DATALINK_EXT(x) (((x) & 0xF) << 28) | 0x04000000)
/*
* Private file type/subtype values; pcap and nanosecond-resolution
* pcap are imported from wiretap/file_access.c.
@ -359,51 +416,44 @@ wtap_open_return_val libpcap_open(wtap *wth, int *err, gchar **err_info)
break;
}
}
/*
* Map the "network" field from the header to a Wiretap
* encapsulation.
*
* Link-layer header types are assigned for both pcap and
* pcapng, and the same value must work with both. In pcapng,
* the link-layer header type field in an Interface Description
* Block is 16 bits, so only the bottommost 16 bits of the
* link-layer header type in a pcap file can be used for the
* header type value.
*
* In libpcap, the upper 16 bits are divided into:
*
* A "class" field, to support non-standard link-layer
* header types; class 0 is for standard header types,
* class 0x224 was reserved for a NetBSD feature, and
* all other class values are reserved. That is in the
* lower 10 bits of the upper 16 bits.
*
* An "FCS length" field, to allow the FCS length to
* be specified, just as it can be specified in the
* if_fcslen field of the pcapng IDB. That is in the
* topmost 4 bits of the upper 16 bits. The field is
* in units of 16 bits, i.e. 1 means 16 bits of FCS,
* 2 means 32 bits of FCS, etc..
*
* An "FCS length present" flag; if 0, the "FCS length"
* field should be ignored, and if 1, the "FCS length"
* field should be used. That is in the bit just above
* the "class" field.
*
* The one remaining bit is reserved.
*
* We ignore the FCS information and reserved bit; we include
* the "class" field, in case there's ever a need to implement
* it - currently, any link-layer header type with a non-zero
* class value will fail.
* Check the "class" field of the "network" field in the header.
*/
wth->file_encap = wtap_pcap_encap_to_wtap_encap(hdr.network & 0x03FFFFFF);
if (wth->file_encap == WTAP_ENCAP_UNKNOWN) {
switch (LT_CLASS(hdr.network)) {
case LT_CLASS_LINKTYPE:
/*
* Map the link-layer type from the "network" field in
* the header to a Wiretap encapsulation.
*/
wth->file_encap = wtap_pcap_encap_to_wtap_encap(LT_LINKTYPE(hdr.network));
if (wth->file_encap == WTAP_ENCAP_UNKNOWN) {
*err = WTAP_ERR_UNSUPPORTED;
*err_info = ws_strdup_printf("pcap: network type %u unknown or unsupported",
hdr.network);
return WTAP_OPEN_ERROR;
}
break;
default:
*err = WTAP_ERR_UNSUPPORTED;
*err_info = ws_strdup_printf("pcap: network type %u unknown or unsupported",
hdr.network);
*err_info = ws_strdup_printf("pcap: network type class 0x%04x not supported",
LT_CLASS(hdr.network));
return WTAP_OPEN_ERROR;
}
/*
* Extract the FCS information, if present.
*/
libpcap->fcs_len = -1;
if (LT_FCS_LENGTH_PRESENT(hdr.network)) {
/*
* We have an FCS length.
*/
libpcap->fcs_len = LT_FCS_LENGTH(hdr.network) * 16;
}
libpcap->encap_priv = NULL;
/*
@ -967,7 +1017,7 @@ libpcap_read_packet(wtap *wth, FILE_T fh, wtap_rec *rec,
return FALSE; /* failed */
pcap_read_post_process(is_nokia, wth->file_encap, rec,
ws_buffer_start_ptr(buf), libpcap->byte_swapped, -1);
ws_buffer_start_ptr(buf), libpcap->byte_swapped, libpcap->fcs_len);
return TRUE;
}