1 /* firewall_rules_dialog.cpp
2 *
3 * Wireshark - Network traffic analyzer
4 * By Gerald Combs <gerald@wireshark.org>
5 * Copyright 1998 Gerald Combs
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include <config.h>
11
12 #include "firewall_rules_dialog.h"
13 #include <ui_firewall_rules_dialog.h>
14
15 #include "epan/packet_info.h"
16 #include "epan/to_str.h"
17
18 #include "ui/all_files_wildcard.h"
19 #include "ui/firewall_rules.h"
20 #include "ui/help_url.h"
21
22 #include "wsutil/file_util.h"
23 #include "wsutil/utf8_entities.h"
24
25 #include "wireshark_application.h"
26 #include "ui/qt/widgets/wireshark_file_dialog.h"
27
28 #include <QClipboard>
29 #include <QMessageBox>
30 #include <QPushButton>
31 #include <QTextCursor>
32
33 // XXX As described in bug 2482, some of the generated rules don't
34 // make sense. We could generate rules for every conceivable use case,
35 // but that would add complexity. We could also add controls to let
36 // users fine-tune rule output, but that would also add complexity.
37
FirewallRulesDialog(QWidget & parent,CaptureFile & cf)38 FirewallRulesDialog::FirewallRulesDialog(QWidget &parent, CaptureFile &cf) :
39 WiresharkDialog(parent, cf),
40 ui(new Ui::FirewallRulesDialog),
41 prod_(0)
42 {
43 ui->setupUi(this);
44
45 setWindowSubtitle(tr("Firewall ACL Rules"));
46
47 ui->buttonBox->button(QDialogButtonBox::Apply)->setText(tr("Copy"));
48
49 file_name_ = cf.fileName(); // XXX Add extension?
50 packet_num_ = cf.packetInfo()->num;
51
52 packet_info *pinfo = cf.packetInfo();
53 copy_address(&dl_src_, &(pinfo->dl_src));
54 copy_address(&dl_dst_, &(pinfo->dl_dst));
55 copy_address(&net_src_, &(pinfo->net_src));
56 copy_address(&net_dst_, &(pinfo->net_dst));
57 ptype_ = pinfo->ptype;
58 src_port_ = pinfo->srcport;
59 dst_port_ = pinfo->destport;
60 int nf_item = 0;
61
62 for (size_t prod = 0; prod < firewall_product_count(); prod++) {
63 QString prod_name = firewall_product_name(prod);
64
65 // Default to Netfilter since it's likely the most popular.
66 if (prod_name.contains("Netfilter")) nf_item = ui->productComboBox->count();
67 ui->productComboBox->addItem(prod_name);
68 }
69 ui->productComboBox->setCurrentIndex(nf_item);
70
71 ui->buttonBox->button(QDialogButtonBox::Close)->setDefault(true);
72 }
73
~FirewallRulesDialog()74 FirewallRulesDialog::~FirewallRulesDialog()
75 {
76 delete ui;
77 }
78
updateWidgets()79 void FirewallRulesDialog::updateWidgets()
80 {
81 WiresharkDialog::updateWidgets();
82
83 QString comment_pfx = firewall_product_comment_prefix(prod_);
84 QString rule_hint = firewall_product_rule_hint(prod_);
85 QString rule_line;
86
87 rule_line = QString("%1 %2 rules for %3, packet %4.")
88 .arg(comment_pfx)
89 .arg(firewall_product_name(prod_))
90 .arg(file_name_)
91 .arg(packet_num_);
92
93 if (!rule_hint.isEmpty()) rule_line += " " + rule_hint;
94
95 ui->textBrowser->clear();
96 ui->textBrowser->append(rule_line);
97
98 syntax_func v4_func = firewall_product_ipv4_func(prod_);
99 syntax_func port_func = firewall_product_port_func(prod_);
100 syntax_func v4_port_func = firewall_product_ipv4_port_func(prod_);
101 syntax_func mac_func = firewall_product_mac_func(prod_);
102
103 if (v4_func && net_src_.type == AT_IPv4) {
104 addRule(tr("IPv4 source address."), v4_func, &net_src_, src_port_);
105 addRule(tr("IPv4 destination address."), v4_func, &net_dst_, dst_port_);
106 }
107
108 if (port_func && (ptype_ == PT_TCP || ptype_ == PT_UDP)) {
109 addRule(tr("Source port."), port_func, &net_src_, src_port_);
110 addRule(tr("Destination port."), port_func, &net_dst_, dst_port_);
111 }
112
113 if (v4_port_func && net_src_.type == AT_IPv4 &&
114 (ptype_ == PT_TCP || ptype_ == PT_UDP)) {
115 addRule(tr("IPv4 source address and port."), v4_port_func, &net_src_, src_port_);
116 addRule(tr("IPv4 destination address and port."), v4_port_func, &net_dst_, dst_port_);
117 }
118
119 if (mac_func && dl_src_.type == AT_ETHER) {
120 addRule(tr("MAC source address."), mac_func, &dl_src_, src_port_);
121 addRule(tr("MAC destination address."), mac_func, &dl_dst_, dst_port_);
122 }
123
124 ui->textBrowser->moveCursor(QTextCursor::Start);
125
126 ui->inboundCheckBox->setEnabled(firewall_product_does_inbound(prod_));
127 }
128
129 #define ADDR_BUF_LEN 200
addRule(QString description,syntax_func rule_func,address * addr,guint32 port)130 void FirewallRulesDialog::addRule(QString description, syntax_func rule_func, address *addr, guint32 port)
131 {
132 if (!rule_func) return;
133
134 char addr_buf[ADDR_BUF_LEN];
135 QString comment_pfx = firewall_product_comment_prefix(prod_);
136 GString *rule_str = g_string_new("");
137 gboolean inbound = ui->inboundCheckBox->isChecked();
138 gboolean deny = ui->denyCheckBox->isChecked();
139
140 address_to_str_buf(addr, addr_buf, ADDR_BUF_LEN);
141 rule_func(rule_str, addr_buf, port, ptype_, inbound, deny);
142 ui->textBrowser->append(QString());
143
144 QString comment_line = comment_pfx + " " + description;
145 ui->textBrowser->append(comment_line);
146 ui->textBrowser->append(rule_str->str);
147
148 g_string_free(rule_str, TRUE);
149 }
150
151
on_productComboBox_currentIndexChanged(int new_idx)152 void FirewallRulesDialog::on_productComboBox_currentIndexChanged(int new_idx)
153 {
154 prod_ = (size_t) new_idx;
155 updateWidgets();
156 }
157
on_inboundCheckBox_toggled(bool)158 void FirewallRulesDialog::on_inboundCheckBox_toggled(bool)
159 {
160 updateWidgets();
161 }
162
on_denyCheckBox_toggled(bool)163 void FirewallRulesDialog::on_denyCheckBox_toggled(bool)
164 {
165 updateWidgets();
166 }
167
on_buttonBox_clicked(QAbstractButton * button)168 void FirewallRulesDialog::on_buttonBox_clicked(QAbstractButton *button)
169 {
170 if (button == ui->buttonBox->button(QDialogButtonBox::Save)) {
171 QString save_title = QString("Save %1 rules as" UTF8_HORIZONTAL_ELLIPSIS)
172 .arg(firewall_product_name(prod_));
173 QByteArray file_name = WiresharkFileDialog::getSaveFileName(this,
174 save_title,
175 wsApp->lastOpenDir().canonicalPath(),
176 tr("Text file (*.txt);;All Files (" ALL_FILES_WILDCARD ")")
177 ).toUtf8();
178 if (file_name.length() > 0) {
179 QFile save_file(file_name);
180 QByteArray rule_text = ui->textBrowser->toPlainText().toUtf8();
181
182 save_file.open(QIODevice::WriteOnly);
183 save_file.write(rule_text);
184 save_file.close();
185
186 if (save_file.error() != QFile::NoError) {
187 QMessageBox::warning(this, tr("Warning"), tr("Unable to save %1").arg(save_file.fileName()));
188 return;
189 }
190
191 /* Save the directory name for future file dialogs. */
192 wsApp->setLastOpenDirFromFilename(file_name);
193 }
194 } else if (button == ui->buttonBox->button(QDialogButtonBox::Apply)) {
195 if (ui->textBrowser->textCursor().hasSelection()) {
196 ui->textBrowser->copy();
197 } else {
198 wsApp->clipboard()->setText(ui->textBrowser->toPlainText());
199 }
200 }
201 }
202
on_buttonBox_helpRequested()203 void FirewallRulesDialog::on_buttonBox_helpRequested()
204 {
205 wsApp->helpTopicAction(HELP_FIREWALL_DIALOG);
206 }
207