diff options
-rw-r--r-- | docbook/wsug_src/wsug_work.adoc | 1 | ||||
-rw-r--r-- | ui/logray/logray_main_window_slots.cpp | 6 | ||||
-rw-r--r-- | ui/qt/address_editor_frame.cpp | 120 | ||||
-rw-r--r-- | ui/qt/address_editor_frame.h | 5 | ||||
-rw-r--r-- | ui/qt/proto_tree.cpp | 5 | ||||
-rw-r--r-- | ui/qt/utils/field_information.cpp | 2 | ||||
-rw-r--r-- | ui/qt/utils/field_information.h | 2 | ||||
-rw-r--r-- | ui/qt/wireshark_main_window_slots.cpp | 6 |
8 files changed, 129 insertions, 18 deletions
diff --git a/docbook/wsug_src/wsug_work.adoc b/docbook/wsug_src/wsug_work.adoc index aac9f1a4fe..deff08bd92 100644 --- a/docbook/wsug_src/wsug_work.adoc +++ b/docbook/wsug_src/wsug_work.adoc @@ -244,6 +244,7 @@ description of each item. |menu:Collapse Subtrees[]|menu:View[]| Collapse the currently selected subtree. |menu:Expand All[]|menu:View[]| Expand all subtrees in all packets in the capture. |menu:Collapse All[]|menu:View[]| Wireshark keeps a list of all the protocol subtrees that are expanded, and uses it to ensure that the correct subtrees are expanded when you display a packet. This menu item collapses the tree view of all packets in the capture list. +|menu:Edit Resolved Name[]|menu:View[]| Allows you to enter a name to resolve for the selected address. |menu:Apply as Column[]|| Use the selected protocol item to create a new column in the packet list. |menu:Apply as Filter[]|menu:Analyze[]| diff --git a/ui/logray/logray_main_window_slots.cpp b/ui/logray/logray_main_window_slots.cpp index 481fd3b298..47c4074a46 100644 --- a/ui/logray/logray_main_window_slots.cpp +++ b/ui/logray/logray_main_window_slots.cpp @@ -2431,8 +2431,10 @@ void LograyMainWindow::editResolvedName() //int column = packet_list_->selectedColumn(); int column = -1; - if (packet_list_->currentIndex().isValid()) { - column = packet_list_->currentIndex().column(); + if (packet_list_->contextMenuActive() || packet_list_->hasFocus()) { + if (packet_list_->currentIndex().isValid()) { + column = packet_list_->currentIndex().column(); + } } main_ui_->addressEditorFrame->editAddresses(capture_file_, column); diff --git a/ui/qt/address_editor_frame.cpp b/ui/qt/address_editor_frame.cpp index 03bda8a65c..c428d19d5a 100644 --- a/ui/qt/address_editor_frame.cpp +++ b/ui/qt/address_editor_frame.cpp @@ -30,6 +30,7 @@ // To do: // - Fill in currently resolved address. +// - Allow editing other kinds of addresses. AddressEditorFrame::AddressEditorFrame(QWidget *parent) : AccordionFrame(parent), @@ -50,6 +51,48 @@ AddressEditorFrame::~AddressEditorFrame() delete ui; } +QString AddressEditorFrame::addressToString(const FieldInformation& finfo) +{ + address addr; + ws_in4_addr ipv4; + const ws_in6_addr* ipv6; + + if (!finfo.isValid()) { + return QString(); + } + + switch (finfo.headerInfo().type) { + + case FT_IPv4: + // FieldInformation.toString gives us the result of + // proto_item_fill_display_label, but that gives us + // the currently resolved version, if resolution is + // available and enabled. We want the unresolved string. + ipv4 = fvalue_get_uinteger(finfo.fieldInfo()->value); + set_address(&addr, AT_IPv4, 4, &ipv4); + return gchar_free_to_qstring(address_to_str(NULL, &addr)); + case FT_IPv6: + ipv6 = fvalue_get_ipv6(finfo.fieldInfo()->value); + set_address(&addr, AT_IPv6, sizeof(ws_in6_addr), ipv6); + return gchar_free_to_qstring(address_to_str(NULL, &addr)); + default: + return QString(); + } +} + +void AddressEditorFrame::addAddresses(const ProtoNode& node, QStringList& addresses) +{ + QString addrString = addressToString(FieldInformation(&node)); + if (!addrString.isEmpty()) { + addresses << addrString; + } + ProtoNode::ChildIterator kids = node.children(); + while (kids.element().isValid()) { + addAddresses(kids.element(), addresses); + kids.next(); + } +} + void AddressEditorFrame::editAddresses(CaptureFile &cf, int column) { cap_file_ = cf.capFile(); @@ -66,10 +109,16 @@ void AddressEditorFrame::editAddresses(CaptureFile &cf, int column) epan_dissect_t edt; QStringList addresses; + QString selectedString; ui->addressComboBox->clear(); - epan_dissect_init(&edt, cap_file_->epan, FALSE, FALSE); + // Dissect the record with a visible tree and fill in the custom + // columns. We don't really need to have a visible tree (we should + // have one in cap_file_->edt->tree as we have a current frame), but + // this is only a single frame that's previously been dissected so + // the performance hit is slight anyway. + epan_dissect_init(&edt, cap_file_->epan, TRUE, TRUE); col_custom_prime_edt(&edt, &cap_file_->cinfo); epan_dissect_run(&edt, cap_file_->cd_t, &cap_file_->rec, @@ -77,23 +126,33 @@ void AddressEditorFrame::editAddresses(CaptureFile &cf, int column) cap_file_->current_frame, &cap_file_->cinfo); epan_dissect_fill_in_columns(&edt, TRUE, TRUE); - /* First check selected column */ - if (isAddressColumn(&cap_file_->cinfo, column)) { - addresses << cap_file_->cinfo.col_expr.col_expr_val[column]; - } - - for (int col = 0; col < cap_file_->cinfo.num_cols; col++) { - /* Then check all columns except the selected */ - if ((col != column) && (isAddressColumn(&cap_file_->cinfo, col))) { - addresses << cap_file_->cinfo.col_expr.col_expr_val[col]; + addAddresses(ProtoNode(edt.tree), addresses); + + if (column >= 0) { + // Check selected column + if (isAddressColumn(&cap_file_->cinfo, column)) { + // This always gets the unresolved value. + // XXX: For multifield custom columns, we don't have a good + // function to return each string separately before joining + // them. Since we know that IP addresses don't include commas, + // we could split on commas here, and check each field value + // to find the first one that is an IP address in our list. + selectedString = cap_file_->cinfo.col_expr.col_expr_val[column]; } + } else if (cap_file_->finfo_selected) { + selectedString = addressToString(FieldInformation(cap_file_->finfo_selected)); } epan_dissect_cleanup(&edt); displayPreviousUserDefinedHostname(); + addresses.removeDuplicates(); ui->addressComboBox->addItems(addresses); + int index = ui->addressComboBox->findText(selectedString); + if (index != -1) { + ui->addressComboBox->setCurrentIndex(index); + } ui->nameLineEdit->setFocus(); updateWidgets(); } @@ -124,6 +183,14 @@ void AddressEditorFrame::keyPressEvent(QKeyEvent *event) void AddressEditorFrame::displayPreviousUserDefinedHostname() { QString addr = ui->addressComboBox->currentText(); + // XXX: If there's a resolved name that wasn't manually entered, + // we should probably display that too. Possibly even if network + // name resolution is off globally, as get_edited_resolved_name() does. + // It's possible to have such names from DNS lookups if the global is + // turned on then turned back off, from NRBs, or from DNS packets. + // There's no clean API call to always get the resolved name, but + // we could access the hash tables directly the way that + // models/resolved_addresses_models.cpp does. resolved_name_t* previous_entry = get_edited_resolved_name(addr.toUtf8().constData()); if (previous_entry) { @@ -176,7 +243,19 @@ void AddressEditorFrame::on_buttonBox_accepted() return; } on_buttonBox_rejected(); - emit redissectPackets(); + // There's no point in redissecting packets if the network resolution + // global is off. There is a use case for editing several names before + // turning on the preference to avoid a lot of expensive redissects. + // (Statistics->Resolved Addresses still displays them even when + // resolution is disabled, so the user can check what has been input.) + // + // XXX: Can entering a new name but having nothing happen because + // network name resolution is off be confusing to the user? The GTK + // dialog had a simple checkbox, the "Name Resolution Preferences..." + // is a little more complicated but hopefully obvious enough. + if (gbl_resolv_flags.network_name) { + emit redissectPackets(); + } } void AddressEditorFrame::on_buttonBox_rejected() @@ -192,12 +271,29 @@ bool AddressEditorFrame::isAddressColumn(epan_column_info *cinfo, int column) if (((cinfo->columns[column].col_fmt == COL_DEF_SRC) || (cinfo->columns[column].col_fmt == COL_RES_SRC) || + (cinfo->columns[column].col_fmt == COL_UNRES_SRC) || (cinfo->columns[column].col_fmt == COL_DEF_DST) || - (cinfo->columns[column].col_fmt == COL_RES_DST)) && + (cinfo->columns[column].col_fmt == COL_RES_DST) || + (cinfo->columns[column].col_fmt == COL_UNRES_DST) || + (cinfo->columns[column].col_fmt == COL_DEF_NET_SRC) || + (cinfo->columns[column].col_fmt == COL_RES_NET_SRC) || + (cinfo->columns[column].col_fmt == COL_UNRES_NET_SRC) || + (cinfo->columns[column].col_fmt == COL_DEF_NET_DST) || + (cinfo->columns[column].col_fmt == COL_RES_NET_DST) || + (cinfo->columns[column].col_fmt == COL_UNRES_NET_DST)) && strlen(cinfo->col_expr.col_expr_val[column])) { return true; } + if ((cinfo->columns[column].col_fmt == COL_CUSTOM) && + cinfo->columns[column].col_custom_fields) { + // We could cycle through all the col_custom_fields_ids and + // see if proto_registrar_get_ftype() says that any of them + // are FT_IPv4 or FT_IPv6, but let's just check the string + // against all the addresses we found from the tree. + return true; + } + return false; } diff --git a/ui/qt/address_editor_frame.h b/ui/qt/address_editor_frame.h index 300e4dd5d6..a4981e350b 100644 --- a/ui/qt/address_editor_frame.h +++ b/ui/qt/address_editor_frame.h @@ -14,6 +14,9 @@ #include "capture_file.h" +#include <ui/qt/utils/field_information.h> +#include <ui/qt/utils/proto_node.h> + namespace Ui { class AddressEditorFrame; } @@ -52,6 +55,8 @@ private: Ui::AddressEditorFrame *ui; capture_file *cap_file_; + static QString addressToString(const FieldInformation& finfo); + static void addAddresses(const ProtoNode& node, QStringList& addresses); bool isAddressColumn(struct epan_column_info *cinfo, int column); }; diff --git a/ui/qt/proto_tree.cpp b/ui/qt/proto_tree.cpp index 9d59d7acdb..33fb733b55 100644 --- a/ui/qt/proto_tree.cpp +++ b/ui/qt/proto_tree.cpp @@ -286,6 +286,11 @@ void ProtoTree::contextMenuEvent(QContextMenuEvent *event) if (! buildForDialog) { + if (finfo->headerInfo().type == FT_IPv4 || finfo->headerInfo().type == FT_IPv6) { + action = window()->findChild<QAction *>("actionViewEditResolvedName"); + ctx_menu->addAction(action); + ctx_menu->addSeparator(); + } action = window()->findChild<QAction *>("actionAnalyzeApplyAsColumn"); ctx_menu->addAction(action); ctx_menu->addSeparator(); diff --git a/ui/qt/utils/field_information.cpp b/ui/qt/utils/field_information.cpp index 584975601b..395bde2fa8 100644 --- a/ui/qt/utils/field_information.cpp +++ b/ui/qt/utils/field_information.cpp @@ -18,7 +18,7 @@ FieldInformation::FieldInformation(field_info *fi, QObject * parent) parent_fi_ = NULL; } -FieldInformation::FieldInformation(ProtoNode *node, QObject * parent) +FieldInformation::FieldInformation(const ProtoNode *node, QObject * parent) :QObject(parent) { fi_ = NULL; diff --git a/ui/qt/utils/field_information.h b/ui/qt/utils/field_information.h index 56e211e315..b0001b716c 100644 --- a/ui/qt/utils/field_information.h +++ b/ui/qt/utils/field_information.h @@ -44,7 +44,7 @@ public: }; explicit FieldInformation(field_info * fi, QObject * parent = Q_NULLPTR); - explicit FieldInformation(ProtoNode * node, QObject * parent = Q_NULLPTR); + explicit FieldInformation(const ProtoNode * node, QObject * parent = Q_NULLPTR); bool isValid() const; bool isLink() const ; diff --git a/ui/qt/wireshark_main_window_slots.cpp b/ui/qt/wireshark_main_window_slots.cpp index 207a4d4d76..d19c9bf019 100644 --- a/ui/qt/wireshark_main_window_slots.cpp +++ b/ui/qt/wireshark_main_window_slots.cpp @@ -2677,8 +2677,10 @@ void WiresharkMainWindow::editResolvedName() //int column = packet_list_->selectedColumn(); int column = -1; - if (packet_list_->currentIndex().isValid()) { - column = packet_list_->currentIndex().column(); + if (packet_list_->contextMenuActive() || packet_list_->hasFocus()) { + if (packet_list_->currentIndex().isValid()) { + column = packet_list_->currentIndex().column(); + } } main_ui_->addressEditorFrame->editAddresses(capture_file_, column); |