1
0
mirror of https://github.com/fwbuilder/fwbuilder synced 2026-06-27 11:30:01 +02:00
Files
fwbuilder/src/libgui/RuleOptionsDialog.cpp
2014-09-24 11:29:41 +02:00

576 lines
20 KiB
C++

/*
Firewall Builder
Copyright (C) 2003 NetCitadel, LLC
Author: Vadim Kurland vadim@fwbuilder.org
$Id$
This program is free software which we release under the GNU General Public
License. You may redistribute and/or modify this program under the terms
of that license as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
To get a copy of the GNU General Public License, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "definitions.h"
#include "global.h"
#include "utils.h"
#include "platforms.h"
#include "ProjectPanel.h"
#include "RuleOptionsDialog.h"
#include "RuleSetView.h"
#include "FWWindow.h"
#include "FWCmdRule.h"
#include "FWObjectDropArea.h"
#include "fwbuilder/Firewall.h"
#include "fwbuilder/Cluster.h"
#include "fwbuilder/FailoverClusterGroup.h"
#include "fwbuilder/Rule.h"
#include "fwbuilder/FWOptions.h"
#include "fwbuilder/Resources.h"
#include "fwbuilder/RuleSet.h"
#include "fwbuilder/XMLTools.h"
#include <memory>
#include <qstackedwidget.h>
#include <qpushbutton.h>
#include <qmessagebox.h>
#include <qregexp.h>
#include <qlabel.h>
#include <QSpinBox>
#include <QLineEdit>
#include <QComboBox>
#include <QCheckBox>
#include <QObject>
#include <iostream>
using namespace libfwbuilder;
using namespace std;
RuleOptionsDialog::~RuleOptionsDialog()
{
delete m_dialog;
}
RuleOptionsDialog::RuleOptionsDialog(QWidget *parent) :
BaseObjectDialog(parent)
{
m_dialog = new Ui::RuleOptionsDialog_q;
m_dialog->setupUi(this);
m_dialog->pfTagDropArea->addAcceptedTypes("TagService");
m_dialog->iptTagDropArea->addAcceptedTypes("TagService");
connectSignalsOfAllWidgetsToSlotChange();
firewall = NULL;
init=false;
}
void RuleOptionsDialog::loadFWObject(FWObject *o)
{
obj = o;
firewall = o;
// use Firewall::cast to match both Firewall and Cluster
while (!Firewall::cast(firewall)) firewall = firewall->getParent();
platform = firewall->getStr("platform").c_str();
string version = firewall->getStr("version");
// build a map for combobox so visible combobox items can be localized
QStringList route_options = getRouteOptions_pf_ipf(platform);
QStringList route_load_options = getRouteLoadOptions_pf(platform);
QStringList classify_options_ipfw = getClassifyOptions_ipfw(platform);
Rule *rule = dynamic_cast<Rule*>(o);
FWOptions *ropt = rule->getOptionsObject();
PolicyRule *policy_rule = PolicyRule::cast(rule);
int wid=0;
if (platform=="iptables") wid=1;
if (platform=="ipf") wid=2;
if (platform=="pf") wid=3;
if (platform=="ipfw") wid=4;
if (platform=="pix" || platform=="fwsm") wid=5;
if (platform=="iosacl" || platform=="procurve_acl") wid=6;
if (platform=="junosacl") wid=7;
m_dialog->wStack->widget(wid)->raise();
m_dialog->wStack->setCurrentWidget(m_dialog->wStack->widget(wid));
QStringList logLevels=getLogLevels( obj->getStr("platform").c_str() );
m_dialog->ipt_logLevel->clear();
m_dialog->ipt_logLevel->addItems(getScreenNames(logLevels));
m_dialog->ipf_logLevel->clear();
m_dialog->ipf_logLevel->addItems(getScreenNames(logLevels));
m_dialog->pix_logLevel->clear();
m_dialog->pix_logLevel->addItems(getScreenNames(logLevels));
QStringList logFacilities=getLogFacilities( obj->getStr("platform").c_str());
m_dialog->ipf_logFacility->clear();
m_dialog->ipf_logFacility->addItems(getScreenNames(logFacilities));
QStringList limitSuffixes=getLimitSuffixes( obj->getStr("platform").c_str());
m_dialog->ipt_limitSuffix->clear();
m_dialog->ipt_limitSuffix->addItems(getScreenNames(limitSuffixes));
m_dialog->ipt_hashlimit_suffix->clear();
m_dialog->ipt_hashlimit_suffix->addItems(getScreenNames(limitSuffixes));
fillInterfaces(m_dialog->ipt_iif);
fillInterfaces(m_dialog->ipt_oif);
fillInterfaces(m_dialog->ipf_route_opt_if);
fillInterfaces(m_dialog->pf_route_opt_if);
data.clear();
if (platform=="iptables")
{
data.registerOption(m_dialog->ipt_logPrefix, ropt, "log_prefix");
data.registerOption(m_dialog->ipt_logLevel, ropt,
"log_level", logLevels);
data.registerOption(m_dialog->ipt_nlgroup, ropt, "ulog_nlgroup");
data.registerOption(m_dialog->ipt_limit, ropt, "limit_value");
data.registerOption(m_dialog->ipt_limitSuffix, ropt,
"limit_suffix", limitSuffixes);
data.registerOption(m_dialog->ipt_limit_not, ropt, "limit_value_not");
data.registerOption(m_dialog->ipt_burst, ropt, "limit_burst");
data.registerOption(m_dialog->ipt_connlimit, ropt, "connlimit_value");
data.registerOption(m_dialog->ipt_connlimit_above_not, ropt,
"connlimit_above_not");
data.registerOption(m_dialog->ipt_connlimit_masklen, ropt,
"connlimit_masklen");
data.registerOption(m_dialog->ipt_hashlimit, ropt, "hashlimit_value");
data.registerOption(m_dialog->ipt_hashlimit_suffix, ropt,
"hashlimit_suffix");
data.registerOption(m_dialog->ipt_hashlimit_burst, ropt,
"hashlimit_burst");
data.registerOption(m_dialog->cb_srcip, ropt, "hashlimit_mode_srcip");
data.registerOption(m_dialog->cb_dstip, ropt, "hashlimit_mode_dstip");
data.registerOption(m_dialog->cb_srcport, ropt,
"hashlimit_mode_srcport");
data.registerOption(m_dialog->cb_dstport, ropt,
"hashlimit_mode_dstport");
data.registerOption(m_dialog->ipt_hashlimit_dstlimit, ropt,
"hashlimit_dstlimit");
data.registerOption(m_dialog->ipt_hashlimit_name, ropt,
"hashlimit_name");
data.registerOption(m_dialog->ipt_hashlimit_size, ropt,
"hashlimit_size");
data.registerOption(m_dialog->ipt_hashlimit_max, ropt,
"hashlimit_max");
data.registerOption(m_dialog->ipt_hashlimit_expire, ropt,
"hashlimit_expire");
data.registerOption(m_dialog->ipt_hashlimit_gcinterval, ropt,
"hashlimit_gcinterval");
// in v3.0 attribute "assume fw is part of any" used to be a
// checkbox and therefore stored as boolean in the rule
// options. Old "on" maps to the new "on", which means old "True"
// maps to "1". Old "off" maps to "use global" though.
string old_val = ropt->getStr("firewall_is_part_of_any_and_networks");
if (old_val == "True") ropt->setStr("firewall_is_part_of_any_and_networks", "1");
if (old_val == "False") ropt->setStr("firewall_is_part_of_any_and_networks", "");
QStringList threeStateMapping;
threeStateMapping.push_back(QObject::tr("Follow global setting"));
threeStateMapping.push_back("");
threeStateMapping.push_back(QObject::tr("On"));
threeStateMapping.push_back("1");
threeStateMapping.push_back(QObject::tr("Off"));
threeStateMapping.push_back("0");
data.registerOption(m_dialog->ipt_assume_fw_is_part_of_any, ropt,
"firewall_is_part_of_any_and_networks",
threeStateMapping);
data.registerOption(m_dialog->ipt_stateless, ropt, "stateless");
data.registerOption(m_dialog->ipt_mark_connections, ropt,
"ipt_mark_connections");
data.registerOption(m_dialog->classify_str, ropt, "classify_str");
// Route
data.registerOption(m_dialog->ipt_iif, ropt, "ipt_iif" );
data.registerOption(m_dialog->ipt_oif, ropt, "ipt_oif" );
data.registerOption(m_dialog->ipt_gw, ropt, "ipt_gw" );
data.registerOption(m_dialog->ipt_continue, ropt, "ipt_continue" );
data.registerOption(m_dialog->ipt_tee, ropt, "ipt_tee");
FWObject *o = policy_rule->getTagObject();
m_dialog->iptTagDropArea->setObject(o);
m_dialog->iptTagDropArea->update();
}
if (platform=="ipf")
{
data.registerOption(m_dialog->ipf_logFacility, ropt,
"ipf_log_facility", logFacilities);
data.registerOption(m_dialog->ipf_logLevel, ropt,
"log_level", logLevels);
data.registerOption(m_dialog->ipf_masq_icmp, ropt,
"ipf_return_icmp_as_dest");
data.registerOption(m_dialog->ipf_stateless, ropt, "stateless");
data.registerOption(m_dialog->ipf_keep_frags, ropt, "ipf_keep_frags");
// Route
data.registerOption(m_dialog->ipf_route_option, ropt,
"ipf_route_option", route_options);
data.registerOption(m_dialog->ipf_route_opt_if, ropt,
"ipf_route_opt_if");
data.registerOption(m_dialog->ipf_route_opt_addr, ropt,
"ipf_route_opt_addr");
}
if (platform=="pf")
{
bool ge_4_5 = XMLTools::version_compare(version, "4.5")>=0;
m_dialog->pf_no_sync->setEnabled(ge_4_5);
m_dialog->pf_pflow->setEnabled(ge_4_5);
data.registerOption(m_dialog->pf_logPrefix, ropt,
"log_prefix");
data.registerOption(m_dialog->pf_stateless, ropt,
"stateless");
data.registerOption(m_dialog->pf_keep_state, ropt,
"pf_keep_state");
data.registerOption(m_dialog->pf_no_sync, ropt,
"pf_no_sync");
data.registerOption(m_dialog->pf_pflow, ropt,
"pf_pflow");
data.registerOption(m_dialog->pf_sloppy_tracker, ropt,
"pf_sloppy_tracker");
data.registerOption(m_dialog->pf_rule_max_state, ropt,
"pf_rule_max_state");
data.registerOption(m_dialog->pf_source_tracking, ropt,
"pf_source_tracking");
data.registerOption(m_dialog->pf_max_src_nodes, ropt,
"pf_max_src_nodes");
data.registerOption(m_dialog->pf_max_src_states, ropt,
"pf_max_src_states");
data.registerOption(m_dialog->pf_max_src_conn, ropt,
"pf_max_src_conn");
data.registerOption(m_dialog->pf_overload_table, ropt,
"pf_max_src_conn_overload_table");
data.registerOption(m_dialog->pf_flush, ropt,
"pf_max_src_conn_flush");
data.registerOption(m_dialog->pf_global, ropt,
"pf_max_src_conn_global");
data.registerOption(m_dialog->pf_max_src_conn_rate_num, ropt,
"pf_max_src_conn_rate_num");
data.registerOption(m_dialog->pf_max_src_conn_rate_seconds, ropt,
"pf_max_src_conn_rate_seconds");
data.registerOption(m_dialog->pf_modulate, ropt,
"pf_modulate_state");
data.registerOption(m_dialog->pf_synproxy, ropt,
"pf_synproxy");
// Tag
FWObject *o = policy_rule->getTagObject();
m_dialog->pfTagDropArea->setObject(o);
m_dialog->pfTagDropArea->update();
// Classify
data.registerOption(m_dialog->pf_classify_str, ropt, "pf_classify_str");
// Route
data.registerOption(m_dialog->pf_fastroute, ropt, "pf_fastroute");
data.registerOption(m_dialog->pf_route_load_option, ropt,
"pf_route_load_option", route_load_options);
data.registerOption(m_dialog->pf_route_option, ropt, "pf_route_option",
route_options);
data.registerOption(m_dialog->pf_route_opt_if, ropt, "pf_route_opt_if");
data.registerOption(m_dialog->pf_route_opt_addr, ropt, "pf_route_opt_addr");
}
if (platform=="ipfw")
{
data.registerOption(m_dialog->ipfw_stateless, ropt, "stateless");
/* #2367 */
// Classify
data.registerOption(m_dialog->ipfw_classify_method, ropt,
"ipfw_classify_method", classify_options_ipfw);
data.registerOption(m_dialog->usePortNum, ropt, "ipfw_pipe_queue_num");
}
if (platform=="iosacl" || platform=="procurve_acl")
{
data.registerOption(m_dialog->iosacl_add_mirror_rule,
ropt, "iosacl_add_mirror_rule");
}
if (platform=="pix" || platform=="fwsm")
{
string vers = "version_" + version;
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
if (Resources::platform_res[platform.toAscii().constData()]->getResourceBool(
"/FWBuilderResources/Target/options/" +
vers + "/pix_rule_syslog_settings"))
#else
if (Resources::platform_res[platform.toLatin1().constData()]->getResourceBool(
"/FWBuilderResources/Target/options/" +
vers + "/pix_rule_syslog_settings"))
#endif
{
m_dialog->pix_disable_rule_log->setEnabled(true);
m_dialog->pix_logLevel->setEnabled(true);
m_dialog->pix_log_interval->setEnabled(true);
data.registerOption(m_dialog->pix_disable_rule_log, ropt,
"disable_logging_for_this_rule");
data.registerOption(m_dialog->pix_logLevel, ropt,
"log_level",logLevels);
data.registerOption(m_dialog->pix_log_interval, ropt,
"log_interval");
} else
{
m_dialog->pix_disable_rule_log->setEnabled(false);
m_dialog->pix_logLevel->setEnabled(false);
m_dialog->pix_log_interval->setEnabled(false);
}
}
if (platform=="junosacl")
{
data.registerOption(m_dialog->counterLineEdit, ropt, "counter_name");
}
init = true;
data.loadAll();
m_dialog->pf_max_src_nodes->setEnabled(
m_dialog->pf_source_tracking->isChecked());
m_dialog->pf_max_src_states->setEnabled(
m_dialog->pf_source_tracking->isChecked());
connlimitAboveLabelChange();
limitLabelChange();
//apply->setEnabled(false);
init=false;
}
void RuleOptionsDialog::changed()
{
//apply->setEnabled(true);
m_dialog->pf_max_src_nodes->setEnabled(
m_dialog->pf_source_tracking->isChecked());
m_dialog->pf_max_src_states->setEnabled(
m_dialog->pf_source_tracking->isChecked());
bool enable_overload_options = (
m_dialog->pf_max_src_conn->value()>0 || (
m_dialog->pf_max_src_conn_rate_num->value()>0 &&
m_dialog->pf_max_src_conn_rate_seconds->value()>0)
);
m_dialog->pf_overload_table->setEnabled(enable_overload_options);
m_dialog->pf_flush->setEnabled(enable_overload_options);
m_dialog->pf_global->setEnabled(enable_overload_options);
iptRouteContinueToggled(); // #2367
BaseObjectDialog::changed();
}
void RuleOptionsDialog::validate(bool *res)
{
*res=true;
}
void RuleOptionsDialog::applyChanges()
{
std::auto_ptr<FWCmdChange> cmd( new FWCmdRuleChangeOptions(m_project, obj));
// new_state is a copy of the rule object
FWObject* new_state = cmd->getNewState();
FWOptions* new_rule_options = Rule::cast(new_state)->getOptionsObject();
init = true;
data.saveAll(new_rule_options);
init = false;
/* #2367 */
PolicyRule *policy_rule = PolicyRule::cast(new_state);
if (policy_rule)
{
FWOptions *ropt = policy_rule->getOptionsObject();
if (platform=="iptables")
{
FWObject *tag_object = m_dialog->iptTagDropArea->getObject();
// if tag_object==NULL, setTagObject clears setting in the rule
policy_rule->setTagging(tag_object != NULL);
policy_rule->setTagObject(tag_object);
policy_rule->setClassification(
! ropt->getStr("classify_str").empty());
policy_rule->setRouting( ! ropt->getStr("ipt_iif").empty() ||
! ropt->getStr("ipt_oif").empty() ||
! ropt->getStr("ipt_gw").empty());
}
if (platform=="pf")
{
FWObject *tag_object = m_dialog->pfTagDropArea->getObject();
// if tag_object==NULL, setTagObject clears setting in the rule
policy_rule->setTagging(tag_object != NULL);
policy_rule->setTagObject(tag_object);
policy_rule->setClassification(
! new_rule_options->getStr("pf_classify_str").empty());
policy_rule->setRouting(
! new_rule_options->getStr("pf_route_option").empty() &&
new_rule_options->getStr("pf_route_option") != "none");
}
if (platform=="ipf")
{
policy_rule->setRouting(
! new_rule_options->getStr("ipf_route_option").empty() &&
new_rule_options->getStr("ipf_route_option") != "none");
}
if (platform=="ipfw")
{
policy_rule->setClassification(
new_rule_options->getInt("ipfw_classify_method") > -1);
}
}
if (!cmd->getOldState()->cmp(new_state, true))
{
if (obj->isReadOnly()) return;
m_project->undoStack->push(cmd.release());
}
}
void RuleOptionsDialog::cancelChanges()
{
//apply->setEnabled(false);
close();
}
void RuleOptionsDialog::connlimitAboveLabelChange()
{
if (m_dialog->ipt_connlimit_above_not->isChecked())
m_dialog->ipt_connlimit_above_label->setText(
"Match if the number of existing connections is below this "
"(translates into option ! --connlimit-above)");
else
m_dialog->ipt_connlimit_above_label->setText(
"Match if the number of existing connections is above this "
"(translates into option --connlimit-above)");
changed();
}
void RuleOptionsDialog::limitLabelChange()
{
if (m_dialog->ipt_limit_not->isChecked())
m_dialog->ipt_limit_label->setText(
"Maximum average matching rate (negated) "
"(translates into option ! --limit rate)");
else
m_dialog->ipt_limit_label->setText(
"Maximum average matching rate "
"(translates into option --limit rate)");
changed();
}
void RuleOptionsDialog::iptRouteContinueToggled()
{
if (m_dialog->ipt_continue->isChecked())
{
m_dialog->ipt_iif->setCurrentIndex(0);
m_dialog->ipt_tee->setChecked(false);
}
m_dialog->ipt_iif->setEnabled( ! m_dialog->ipt_continue->isChecked() );
m_dialog->ipt_tee->setEnabled( ! m_dialog->ipt_continue->isChecked() );
}
void RuleOptionsDialog::fillInterfaces(QComboBox* cb)
{
QSet<QString> deduplicated_interface_names;
list<FWObject*> interfaces = firewall->getByTypeDeep(Interface::TYPENAME);
for (list<FWObject*>::iterator i=interfaces.begin(); i!=interfaces.end(); ++i)
{
Interface *iface = Interface::cast(*i);
assert(iface);
if (iface->isLoopback()) continue;
deduplicated_interface_names.insert(iface->getName().c_str());
if (Cluster::isA(firewall))
{
FailoverClusterGroup *failover_group =
FailoverClusterGroup::cast(
iface->getFirstByType(FailoverClusterGroup::TYPENAME));
if (failover_group)
{
for (FWObject::iterator it=failover_group->begin();
it!=failover_group->end(); ++it)
{
FWObject *mi = FWReference::getObject(*it);
if (Interface::isA(mi) && ! iface->isLoopback())
{
deduplicated_interface_names.insert(mi->getName().c_str());
}
}
}
}
}
QStringList sorted_interfaces;
QSetIterator<QString> it(deduplicated_interface_names);
while (it.hasNext())
{
sorted_interfaces << it.next();
}
sorted_interfaces.sort();
cb->clear();
cb->addItem("");
cb->addItems(sorted_interfaces);
}