wireshark/ui/qt/firewall_rules_dialog.cpp

207 lines
6.7 KiB
C++

/* firewall_rules_dialog.cpp
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config.h>
#include "firewall_rules_dialog.h"
#include <ui_firewall_rules_dialog.h>
#include "epan/packet_info.h"
#include "epan/to_str.h"
#include "ui/all_files_wildcard.h"
#include "ui/firewall_rules.h"
#include "ui/help_url.h"
#include "wsutil/file_util.h"
#include "wsutil/utf8_entities.h"
#include "main_application.h"
#include "ui/qt/widgets/wireshark_file_dialog.h"
#include <QClipboard>
#include <QMessageBox>
#include <QPushButton>
#include <QTextCursor>
// XXX As described in bug 2482, some of the generated rules don't
// make sense. We could generate rules for every conceivable use case,
// but that would add complexity. We could also add controls to let
// users fine-tune rule output, but that would also add complexity.
FirewallRulesDialog::FirewallRulesDialog(QWidget &parent, CaptureFile &cf) :
WiresharkDialog(parent, cf),
ui(new Ui::FirewallRulesDialog),
prod_(0)
{
ui->setupUi(this);
setWindowSubtitle(tr("Firewall ACL Rules"));
ui->buttonBox->button(QDialogButtonBox::Apply)->setText(tr("Copy"));
file_name_ = cf.fileName(); // XXX Add extension?
packet_num_ = cf.packetInfo()->num;
packet_info *pinfo = cf.packetInfo();
copy_address(&dl_src_, &(pinfo->dl_src));
copy_address(&dl_dst_, &(pinfo->dl_dst));
copy_address(&net_src_, &(pinfo->net_src));
copy_address(&net_dst_, &(pinfo->net_dst));
ptype_ = pinfo->ptype;
src_port_ = pinfo->srcport;
dst_port_ = pinfo->destport;
int nf_item = 0;
for (size_t prod = 0; prod < firewall_product_count(); prod++) {
QString prod_name = firewall_product_name(prod);
// Default to Netfilter since it's likely the most popular.
if (prod_name.contains("Netfilter")) nf_item = ui->productComboBox->count();
ui->productComboBox->addItem(prod_name);
}
ui->productComboBox->setCurrentIndex(nf_item);
ui->buttonBox->button(QDialogButtonBox::Close)->setDefault(true);
}
FirewallRulesDialog::~FirewallRulesDialog()
{
delete ui;
}
void FirewallRulesDialog::updateWidgets()
{
WiresharkDialog::updateWidgets();
QString comment_pfx = firewall_product_comment_prefix(prod_);
QString rule_hint = firewall_product_rule_hint(prod_);
QString rule_line;
rule_line = QString("%1 %2 rules for %3, packet %4.")
.arg(comment_pfx)
.arg(firewall_product_name(prod_))
.arg(file_name_)
.arg(packet_num_);
if (!rule_hint.isEmpty()) rule_line += " " + rule_hint;
ui->textBrowser->clear();
ui->textBrowser->append(rule_line);
syntax_func v4_func = firewall_product_ipv4_func(prod_);
syntax_func port_func = firewall_product_port_func(prod_);
syntax_func v4_port_func = firewall_product_ipv4_port_func(prod_);
syntax_func mac_func = firewall_product_mac_func(prod_);
if (v4_func && net_src_.type == AT_IPv4) {
addRule(tr("IPv4 source address."), v4_func, &net_src_, src_port_);
addRule(tr("IPv4 destination address."), v4_func, &net_dst_, dst_port_);
}
if (port_func && (ptype_ == PT_TCP || ptype_ == PT_UDP)) {
addRule(tr("Source port."), port_func, &net_src_, src_port_);
addRule(tr("Destination port."), port_func, &net_dst_, dst_port_);
}
if (v4_port_func && net_src_.type == AT_IPv4 &&
(ptype_ == PT_TCP || ptype_ == PT_UDP)) {
addRule(tr("IPv4 source address and port."), v4_port_func, &net_src_, src_port_);
addRule(tr("IPv4 destination address and port."), v4_port_func, &net_dst_, dst_port_);
}
if (mac_func && dl_src_.type == AT_ETHER) {
addRule(tr("MAC source address."), mac_func, &dl_src_, src_port_);
addRule(tr("MAC destination address."), mac_func, &dl_dst_, dst_port_);
}
ui->textBrowser->moveCursor(QTextCursor::Start);
ui->inboundCheckBox->setEnabled(firewall_product_does_inbound(prod_));
}
#define ADDR_BUF_LEN 200
void FirewallRulesDialog::addRule(QString description, syntax_func rule_func, address *addr, guint32 port)
{
if (!rule_func) return;
char addr_buf[ADDR_BUF_LEN];
QString comment_pfx = firewall_product_comment_prefix(prod_);
GString *rule_str = g_string_new("");
gboolean inbound = ui->inboundCheckBox->isChecked();
gboolean deny = ui->denyCheckBox->isChecked();
address_to_str_buf(addr, addr_buf, ADDR_BUF_LEN);
rule_func(rule_str, addr_buf, port, ptype_, inbound, deny);
ui->textBrowser->append(QString());
QString comment_line = comment_pfx + " " + description;
ui->textBrowser->append(comment_line);
ui->textBrowser->append(rule_str->str);
g_string_free(rule_str, TRUE);
}
void FirewallRulesDialog::on_productComboBox_currentIndexChanged(int new_idx)
{
prod_ = (size_t) new_idx;
updateWidgets();
}
void FirewallRulesDialog::on_inboundCheckBox_toggled(bool)
{
updateWidgets();
}
void FirewallRulesDialog::on_denyCheckBox_toggled(bool)
{
updateWidgets();
}
void FirewallRulesDialog::on_buttonBox_clicked(QAbstractButton *button)
{
if (button == ui->buttonBox->button(QDialogButtonBox::Save)) {
QString save_title = QString("Save %1 rules as" UTF8_HORIZONTAL_ELLIPSIS)
.arg(firewall_product_name(prod_));
QByteArray file_name = WiresharkFileDialog::getSaveFileName(this,
save_title,
mainApp->lastOpenDir().canonicalPath(),
tr("Text file (*.txt);;All Files (" ALL_FILES_WILDCARD ")")
).toUtf8();
if (file_name.length() > 0) {
QFile save_file(file_name);
QByteArray rule_text = ui->textBrowser->toPlainText().toUtf8();
save_file.open(QIODevice::WriteOnly);
save_file.write(rule_text);
save_file.close();
if (save_file.error() != QFile::NoError) {
QMessageBox::warning(this, tr("Warning"), tr("Unable to save %1").arg(save_file.fileName()));
return;
}
/* Save the directory name for future file dialogs. */
mainApp->setLastOpenDirFromFilename(file_name);
}
} else if (button == ui->buttonBox->button(QDialogButtonBox::Apply)) {
if (ui->textBrowser->textCursor().hasSelection()) {
ui->textBrowser->copy();
} else {
mainApp->clipboard()->setText(ui->textBrowser->toPlainText());
}
}
}
void FirewallRulesDialog::on_buttonBox_helpRequested()
{
mainApp->helpTopicAction(HELP_FIREWALL_DIALOG);
}