text_import: Allow fake IP headers with Raw IP encapsulation

In text2pcap and Import from Hex Dump, allow fake IP headers with
the appropriate versions when the Raw IP, Raw IPv4, and Raw IPv6
encapsulations are specified. In such cases, do not add a dummy
Ethernet header.

Continue to reject other encapsulations besides these, Ethernet,
and Wireshark Upper PDU when appropriate. Add some checks for the
encapsulation type in text_import as well, instead of just assuming
that the callers handle it correctly.
This commit is contained in:
John Thacker 2022-01-09 07:16:26 -05:00
parent a0a67a75fe
commit f85f077b54
7 changed files with 135 additions and 69 deletions

View File

@ -225,7 +225,8 @@ Include dummy IP headers before each packet. Specify the IP protocol
for the packet in decimal. Use this option if your dump is the payload
of an IP packet (i.e. has complete L4 information) but does not have
an IP header with each packet. Note that an appropriate Ethernet header
is automatically included with each packet as well.
is automatically included with each packet as well if the link-layer
type is Ethernet.
Example: __-i 46__ to specify an RSVP packet (IP protocol 46). See
https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml for
the complete list of assigned internet protocol numbers.

View File

@ -58,13 +58,20 @@ They previously shipped with Npcap 1.55.
** Date and time can be given in UTC using ISO 8601 (with 'Z' timezone) or by appending the suffix "UTC" to the legacy formats.
Otherwise local time is used.
* text2pcap:
* text2pcap and "Import from Hex Dump":
** text2pcap supports writing the output file in all the capture file formats
that wiretap library supports, using the same "-F" option as editcap,
mergecap, and tshark.
** text2pcap has been updated to use the new logging output options and the
"-d" flag has been removed. The "debug" log level corresponds to the old
"-d" flag, and the "noisy" log level corresponds to using "-d" multiple times.
** text2pcap and Import from Hex Dump support writing fake IP headers (and fake
TCP, UDP, and SCTP headers) to files with Raw IP, Raw IPv4, and Raw IPv6
encapsulations, in addition to Ethernet encapsulation as previously.
** text2pcap supports scanning the input file using a custom regular expression,
as supported in Import from Hex Dump in Wireshark 3.6.x.
** In general, text2pcap and wireshark's Import from Hex Dump have feature
parity.
* HTTP2 dissector now supports using fake headers to parse the DATAs of streams captured without first HEADERS frames of a long-lived stream (like
gRPC streaming call which allows sending many request or response messages in one HTTP2 stream). User can specify fake headers according to the

View File

@ -230,7 +230,8 @@ print_usage (FILE *output)
" Example: -e 0x806 to specify an ARP packet.\n"
" -i <proto> prepend dummy IP header with specified IP protocol\n"
" (in DECIMAL).\n"
" Automatically prepends Ethernet header as well.\n"
" Automatically prepends Ethernet header as well if\n"
" link-layer type is Ethernet.\n"
" Example: -i 46\n"
" -4 <srcip>,<destip> prepend dummy IPv4 header with specified\n"
" dest and source address.\n"
@ -256,7 +257,6 @@ print_usage (FILE *output)
" Automatically prepends a dummy SCTP DATA\n"
" chunk header with payload protocol identifier ppi.\n"
" Example: -S 30,40,34\n"
"\n"
" -P <dissector> prepend EXPORTED_PDU header with specifieddissector\n"
" as the payload PROTO_NAME tag.\n"
" Automatically sets link type to Upper PDU Export.\n"
@ -278,11 +278,6 @@ print_usage (FILE *output)
* Set the hdr_ip_proto parameter, and set the flag indicate that the
* parameter has been specified.
*
* Also indicate that we should add an Ethernet link-layer header.
* (That's not an *inherent* requirement, as we could write a file
* with a "raw IP packet" link-layer type, meaning that there *is*
* no link-layer header, but it's the way text2pcap currently works.)
*
* XXX - catch the case where two different options set it differently?
*/
static void
@ -290,7 +285,6 @@ set_hdr_ip_proto(guint8 ip_proto)
{
have_hdr_ip_proto = TRUE;
hdr_ip_proto = ip_proto;
hdr_ethernet = TRUE;
}
static void
@ -695,15 +689,6 @@ parse_options(int argc, char *argv[], text_import_info_t * const info, wtap_dump
return INVALID_OPTION;
}
}
if (pcap_link_type != 1 && hdr_ethernet) {
cmdarg_err("Dummy headers (-e, -i, -u, -s, -S -T) cannot be specified with link type override (-l)");
return INVALID_OPTION;
}
if (pcap_link_type != 252 && hdr_export_pdu) {
cmdarg_err("Export PDU (-P) requires WIRESHARK_UPPER_PDU link type (252)");
return INVALID_OPTION;
}
if (have_hdr_ip_proto && !(hdr_ip || hdr_ipv6)) {
/*
@ -727,12 +712,49 @@ parse_options(int argc, char *argv[], text_import_info_t * const info, wtap_dump
hdr_ip = TRUE;
}
if (hdr_ip)
{
hdr_ethernet_proto = 0x0800;
} else if (hdr_ipv6)
{
hdr_ethernet_proto = 0x86DD;
wtap_encap_type = wtap_pcap_encap_to_wtap_encap(pcap_link_type);
if (hdr_export_pdu && wtap_encap_type != WTAP_ENCAP_WIRESHARK_UPPER_PDU) {
cmdarg_err("Export PDU (-P) requires WIRESHARK_UPPER_PDU link type (252)");
return INVALID_OPTION;
}
/* The other dummy headers require a IPv4 or IPv6 header. Allow
* encapsulation types of Ethernet (and add a Ethernet header in that
* case if we haven't already), or the appropriate raw IP types.
*/
if (hdr_ip) {
switch (wtap_encap_type) {
case (WTAP_ENCAP_ETHERNET):
hdr_ethernet = TRUE;
hdr_ethernet_proto = 0x0800;
break;
case (WTAP_ENCAP_RAW_IP):
case (WTAP_ENCAP_RAW_IP4):
break;
default:
cmdarg_err("Dummy IPv4 header not supported with encapsulation %s (%s)", wtap_encap_description(wtap_encap_type), wtap_encap_name(wtap_encap_type));
return INVALID_OPTION;
}
} else if (hdr_ipv6) {
switch (wtap_encap_type) {
case (WTAP_ENCAP_ETHERNET):
hdr_ethernet = TRUE;
hdr_ethernet_proto = 0x86DD;
break;
case (WTAP_ENCAP_RAW_IP):
case (WTAP_ENCAP_RAW_IP6):
break;
default:
cmdarg_err("Dummy IPv6 header not supported with encapsulation %s (%s)", wtap_encap_description(wtap_encap_type), wtap_encap_name(wtap_encap_type));
return INVALID_OPTION;
}
}
if (strcmp(argv[ws_optind], "-") != 0) {
@ -773,7 +795,6 @@ parse_options(int argc, char *argv[], text_import_info_t * const info, wtap_dump
wtap_dump_params_init(params, NULL);
wtap_encap_type = wtap_pcap_encap_to_wtap_encap(pcap_link_type);
params->encap = wtap_encap_type;
params->snaplen = max_offset;
if (file_type_subtype == WTAP_FILE_TYPE_SUBTYPE_UNKNOWN) {

View File

@ -561,6 +561,11 @@ int ImportTextDialog::exec() {
void ImportTextDialog::updateImportButtonState()
{
/* XXX: This requires even buttons that aren't being used to have valid
* entries (addresses, ports, etc.) Fixing that can mean changing the
* encapsulation type in order to enable the line edits, which is a little
* awkward for the user.
*/
if (file_ok_ && timestamp_format_ok_ && ether_type_ok_ &&
proto_ok_ && source_addr_ok_ && dest_addr_ok_ &&
source_port_ok_ && dest_port_ok_ &&
@ -816,7 +821,7 @@ void ImportTextDialog::on_dirOutIndicationLineEdit_textChanged(const QString &ou
* Encapsulation input
*/
void ImportTextDialog::enableHeaderWidgets(bool enable_ethernet_buttons, bool enable_export_pdu_buttons) {
void ImportTextDialog::enableHeaderWidgets(uint encapsulation) {
bool ethertype = false;
bool ipv4_proto = false;
bool ip_address = false;
@ -824,12 +829,20 @@ void ImportTextDialog::enableHeaderWidgets(bool enable_ethernet_buttons, bool en
bool sctp_tag = false;
bool sctp_ppi = false;
bool export_pdu = false;
bool enable_ethernet_buttons = (encapsulation == WTAP_ENCAP_ETHERNET);
bool enable_ip_buttons = (encapsulation == WTAP_ENCAP_RAW_IP || encapsulation == WTAP_ENCAP_RAW_IP4 || encapsulation == WTAP_ENCAP_RAW_IP6);
bool enable_export_pdu_buttons = (encapsulation == WTAP_ENCAP_WIRESHARK_UPPER_PDU);
if (enable_ethernet_buttons) {
if (ti_ui_->ethernetButton->isChecked()) {
ethertype = true;
on_ethertypeLineEdit_textChanged(ti_ui_->ethertypeLineEdit->text());
} else if (ti_ui_->ipv4Button->isChecked()) {
}
enable_ip_buttons = true;
}
if (enable_ip_buttons) {
if (ti_ui_->ipv4Button->isChecked()) {
ipv4_proto = true;
ip_address = true;
on_protocolLineEdit_textChanged(ti_ui_->protocolLineEdit->text());
@ -863,18 +876,27 @@ void ImportTextDialog::enableHeaderWidgets(bool enable_ethernet_buttons, bool en
}
foreach (auto &&rb, encap_buttons->buttons()) {
rb->setEnabled(enable_ethernet_buttons);
rb->setEnabled(enable_ip_buttons);
}
ti_ui_->ethernetButton->setEnabled(enable_ethernet_buttons);
ti_ui_->exportPduButton->setEnabled(enable_export_pdu_buttons);
ti_ui_->noDummyButton->setEnabled(enable_export_pdu_buttons || enable_ethernet_buttons);
ti_ui_->noDummyButton->setEnabled(enable_export_pdu_buttons || enable_ip_buttons);
ti_ui_->ethertypeLabel->setEnabled(ethertype);
ti_ui_->ethertypeLineEdit->setEnabled(ethertype);
ti_ui_->protocolLabel->setEnabled(ipv4_proto);
ti_ui_->protocolLineEdit->setEnabled(ipv4_proto);
ti_ui_->ipVersionLabel->setEnabled(ip_address);
ti_ui_->ipVersionComboBox->setEnabled(ip_address);
if (encapsulation == WTAP_ENCAP_RAW_IP4) {
ti_ui_->ipVersionComboBox->setEnabled(false);
ti_ui_->ipVersionComboBox->setCurrentIndex(0);
} else if (encapsulation == WTAP_ENCAP_RAW_IP6) {
ti_ui_->ipVersionComboBox->setEnabled(false);
ti_ui_->ipVersionComboBox->setCurrentIndex(1);
} else {
ti_ui_->ipVersionComboBox->setEnabled(ip_address);
}
ti_ui_->sourceAddressLabel->setEnabled(ip_address);
ti_ui_->sourceAddressLineEdit->setEnabled(ip_address);
ti_ui_->destinationAddressLabel->setEnabled(ip_address);
@ -889,33 +911,28 @@ void ImportTextDialog::enableHeaderWidgets(bool enable_ethernet_buttons, bool en
ti_ui_->ppiLineEdit->setEnabled(sctp_ppi);
ti_ui_->payloadLabel->setEnabled(export_pdu);
ti_ui_->dissectorComboBox->setEnabled(export_pdu);
if (ti_ui_->noDummyButton->isEnabled() && !(encap_buttons->checkedButton()->isEnabled())) {
ti_ui_->noDummyButton->toggle();
}
}
void ImportTextDialog::on_encapComboBox_currentIndexChanged(int index)
{
QVariant val = ti_ui_->encapComboBox->itemData(index);
bool enabled_ethernet = false;
bool enabled_export_pdu = false;
if (val != QVariant::Invalid) {
import_info_.encapsulation = val.toUInt();
if (import_info_.encapsulation == WTAP_ENCAP_ETHERNET) enabled_ethernet = true;
if (import_info_.encapsulation == WTAP_ENCAP_WIRESHARK_UPPER_PDU) enabled_export_pdu = true;
} else {
import_info_.encapsulation = WTAP_ENCAP_UNKNOWN;
}
enableHeaderWidgets(enabled_ethernet, enabled_export_pdu);
enableHeaderWidgets(import_info_.encapsulation);
}
void ImportTextDialog::encap_buttonsToggled(QAbstractButton *button _U_, bool checked)
{
bool enabled_ethernet = false;
bool enabled_export_pdu = false;
if (import_info_.encapsulation == WTAP_ENCAP_ETHERNET) enabled_ethernet = true;
if (import_info_.encapsulation == WTAP_ENCAP_WIRESHARK_UPPER_PDU) enabled_export_pdu = true;
if (checked) enableHeaderWidgets(enabled_ethernet, enabled_export_pdu);
if (checked) enableHeaderWidgets(import_info_.encapsulation);
}
void ImportTextDialog::on_ipVersionComboBox_currentIndexChanged(int index)

View File

@ -39,7 +39,7 @@ public:
QString &capfileName();
private:
void enableHeaderWidgets(bool enable_ethernet_buttons = true, bool enable_export_pdu_buttons = true);
void enableHeaderWidgets(uint encapsulation = WTAP_ENCAP_ETHERNET);
/* regex fields */
void enableFieldWidgets(bool enable_direction_input = true, bool enable_time_input = true);

View File

@ -755,7 +755,7 @@
<item row="2" column="4">
<widget class="QComboBox" name="ipVersionComboBox">
<property name="toolTip">
<string>The IP Version for to use for the dummy IP header</string>
<string>The IP Version to use for the dummy IP header</string>
</property>
</widget>
</item>

View File

@ -1539,19 +1539,6 @@ text_import(text_import_info_t * const info)
int ret;
struct tm *now_tm;
packet_buf = (guint8 *)g_malloc(sizeof(HDR_ETHERNET) + sizeof(HDR_IP) +
sizeof(HDR_SCTP) + sizeof(HDR_DATA_CHUNK) +
sizeof(HDR_EXPORT_PDU) + WTAP_MAX_PACKET_SIZE_STANDARD);
if (!packet_buf)
{
/* XXX: This doesn't happen, because g_malloc aborts the program on
* error, unlike malloc or g_try_malloc.
*/
report_failure("FATAL ERROR: no memory for packet buffer");
return INIT_FAILED;
}
/* Lets start from the beginning */
state = INIT;
curr_offset = 0;
@ -1633,8 +1620,6 @@ text_import(text_import_info_t * const info)
case HEADER_IPV4:
hdr_ip = TRUE;
hdr_ip_proto = info->protocol;
hdr_ethernet = TRUE;
hdr_ethernet_proto = 0x800;
break;
case HEADER_UDP:
@ -1642,8 +1627,6 @@ text_import(text_import_info_t * const info)
hdr_tcp = FALSE;
hdr_ip = TRUE;
hdr_ip_proto = 17;
hdr_ethernet = TRUE;
hdr_ethernet_proto = 0x800;
break;
case HEADER_TCP:
@ -1651,16 +1634,12 @@ text_import(text_import_info_t * const info)
hdr_udp = FALSE;
hdr_ip = TRUE;
hdr_ip_proto = 6;
hdr_ethernet = TRUE;
hdr_ethernet_proto = 0x800;
break;
case HEADER_SCTP:
hdr_sctp = TRUE;
hdr_ip = TRUE;
hdr_ip_proto = 132;
hdr_ethernet = TRUE;
hdr_ethernet_proto = 0x800;
break;
case HEADER_SCTP_DATA:
@ -1668,8 +1647,6 @@ text_import(text_import_info_t * const info)
hdr_data_chunk = TRUE;
hdr_ip = TRUE;
hdr_ip_proto = 132;
hdr_ethernet = TRUE;
hdr_ethernet_proto = 0x800;
break;
case HEADER_EXPORT_PDU:
@ -1685,12 +1662,55 @@ text_import(text_import_info_t * const info)
hdr_ipv6 = TRUE;
hdr_ip = FALSE;
hdr_ethernet_proto = 0x86DD;
} else {
hdr_ethernet_proto = 0x0800;
}
switch (info->encapsulation) {
case (WTAP_ENCAP_ETHERNET):
hdr_ethernet = TRUE;
break;
case (WTAP_ENCAP_RAW_IP):
break;
case (WTAP_ENCAP_RAW_IP4):
if (info->ipv6) {
report_failure("Encapsulation %s only supports IPv4 headers, not IPv6", wtap_encap_name(info->encapsulation));
return INVALID_OPTION;
}
break;
case (WTAP_ENCAP_RAW_IP6):
if (!info->ipv6) {
report_failure("Encapsulation %s only supports IPv6 headers, not IPv4", wtap_encap_name(info->encapsulation));
return INVALID_OPTION;
}
break;
default:
report_failure("Dummy IP header not supported with encapsulation: %s (%s)", wtap_encap_name(info->encapsulation), wtap_encap_description(info->encapsulation));
return INVALID_OPTION;
}
}
info->num_packets_read = 0;
info->num_packets_written = 0;
packet_buf = (guint8 *)g_malloc(sizeof(HDR_ETHERNET) + sizeof(HDR_IP) +
sizeof(HDR_SCTP) + sizeof(HDR_DATA_CHUNK) +
sizeof(HDR_EXPORT_PDU) + WTAP_MAX_PACKET_SIZE_STANDARD);
if (!packet_buf)
{
/* XXX: This doesn't happen, because g_malloc aborts the program on
* error, unlike malloc or g_try_malloc.
*/
report_failure("FATAL ERROR: no memory for packet buffer");
return INIT_FAILED;
}
if (info->mode == TEXT_IMPORT_HEXDUMP) {
status = text_import_scan(info->hexdump.import_text_FILE);
switch(status) {