1
0
mirror of https://github.com/fwbuilder/fwbuilder synced 2026-03-20 10:17:16 +01:00

attribute "mangle_table_only" for iptables policy rulesets

This commit is contained in:
Vadim Kurland 2008-10-12 04:03:22 +00:00
parent 7ab63cf0ef
commit c710c1003d
8 changed files with 283 additions and 87 deletions

View File

@ -1,5 +1,21 @@
2008-10-11 Vadim Kurland <vadim@vk.crocodile.org>
* PolicyCompiler_ipt.cpp (finalizeChain::processNext): Always
placing rules with action "Accept" in table mangle in chain
PREROUTING
* RuleSetDialog.cpp (RuleSetDialog::loadFWObject): Added attribute
to the Policy object for iptables to indicate that this policy
ruleset should be compiled into filter and mangle tables or only
for the mangle table. This makes sense (and is only shown) for
iptables firewalls. By default the attribute is set to
"filter+mangle" which means compiler will try to figure out which
table each rule should go to. However some combinations of service
objects and actions are ambiguous and can be used in both filter
and mangle tables. In cases like these, user can help by creating
separate Policy ruleset that will be translated only into iptables
rules in the mangle table.
* PolicyCompiler_ipt.cpp (singleSrvNegation::processNext): fixed
bug #2148378: "Negation does not work on Tag Service". Policy
compiler for iptables should be able to use "!" single-object

View File

@ -72,7 +72,7 @@ void RuleSetDialog::loadFWObject(FWObject *o)
RuleSet *s = dynamic_cast<RuleSet*>(obj);
assert(s!=NULL);
init=true;
init = true;
m_dialog->obj_name->setText( QString::fromUtf8(s->getName().c_str()) );
m_dialog->comment->setText( QString::fromUtf8(s->getComment().c_str()) );
@ -84,8 +84,10 @@ void RuleSetDialog::loadFWObject(FWObject *o)
FWObject *fw = o;
while (fw && fw->getTypeName()!="Firewall") fw = fw->getParent();
if (fw) platform = fw->getStr("platform");
FWOptions *fwopt = Firewall::cast(fw)->getOptionsObject();
if (platform == "iptables")
{
m_dialog->top_rule_set->setToolTip(
QApplication::translate("RuleSetDialog_q",
"On iptables \"top\" rule set goes into \n"
@ -96,6 +98,27 @@ void RuleSetDialog::loadFWObject(FWObject *o)
"the rule set.",
0, QApplication::UnicodeUTF8));
if (Policy::isA(obj))
{
// if this attribute is absent, we consider it False, so for
// backwards compatibility the rule set is considered
// filter+mangle rather than mangle only.
m_dialog->iptables_only->show();
QStringList mangle_rulesets =
QString(fwopt->getStr("ipt_mangle_only_rulesets").c_str()).
split(" ");
bool f = (mangle_rulesets.indexOf(s->getName().c_str()) >= 0);
m_dialog->ipt_filter_table->setChecked(!f);
m_dialog->ipt_mangle_table->setChecked(f);
} else
m_dialog->iptables_only->hide();
} else
{
m_dialog->iptables_only->hide();
}
if (platform == "pf")
m_dialog->top_rule_set->setToolTip(
QApplication::translate("RuleSetDialog_q",
@ -161,6 +184,10 @@ void RuleSetDialog::applyChanges()
RuleSet *s = dynamic_cast<RuleSet*>(obj);
assert(s!=NULL);
FWObject *fw = obj;
while (fw && fw->getTypeName()!="Firewall") fw = fw->getParent();
FWOptions *fwopt = Firewall::cast(fw)->getOptionsObject();
string oldname=obj->getName();
obj->setName( string(m_dialog->obj_name->text().toUtf8().constData()) );
obj->setComment(
@ -168,6 +195,14 @@ void RuleSetDialog::applyChanges()
s->setV6(m_dialog->ipv6_rule_set->isChecked());
s->setTop(m_dialog->top_rule_set->isChecked());
QStringList mangle_rulesets =
QString(fwopt->getStr("ipt_mangle_only_rulesets").c_str()).
split(" ");
if (mangle_rulesets.indexOf(s->getName().c_str()) < 0)
mangle_rulesets.push_back(s->getName().c_str());
fwopt->setStr("ipt_mangle_only_rulesets",
mangle_rulesets.join(" ").toAscii().constData());
mw->updateObjName(obj,QString::fromUtf8(oldname.c_str()));
init=true;

View File

@ -34,6 +34,9 @@
#include "fwbuilder/Rule.h"
#include <iostream>
#include <list>
#include <algorithm>
#include <iterator>
using namespace libfwbuilder;
using namespace fwcompiler;
@ -41,6 +44,7 @@ using namespace std;
string MangleTableCompiler_ipt::myPlatformName() { return "iptables"; }
int MangleTableCompiler_ipt::prolog()
{
return PolicyCompiler_ipt::prolog();
@ -63,49 +67,57 @@ int MangleTableCompiler_ipt::prolog()
bool MangleTableCompiler_ipt::keepMangleTableRules::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
FWOptions *ruleopt =rule->getOptionsObject();
PolicyRule *rule = getNext(); if (rule==NULL) return false;
FWOptions *ruleopt = rule->getOptionsObject();
PolicyCompiler_ipt *ipt_comp = dynamic_cast<PolicyCompiler_ipt*>(compiler);
if (rule->getAction() == PolicyRule::Branch &&
ruleopt->getBool("ipt_branch_in_mangle"))
{
PolicyRule* r;
// this is a branching rule for mangle table. Need to put it
// into PREROUTING and POSTROUTING chains as well because some
// targets that work with mangle table can only go into these
// chains, yet we do not know what kind of rules will user
// place in the branch
if (rule->getDirection()==PolicyRule::Undefined ||
rule->getDirection()==PolicyRule::Both ||
rule->getDirection()==PolicyRule::Inbound)
{
r= PolicyRule::cast(compiler->dbcopy->create(PolicyRule::TYPENAME));
compiler->temp_ruleset->add(r);
r->duplicate(rule);
r->setStr("ipt_chain","PREROUTING");
tmp_queue.push_back(r);
}
if (rule->getDirection()==PolicyRule::Undefined ||
rule->getDirection()==PolicyRule::Both ||
rule->getDirection()==PolicyRule::Outbound)
{
r= PolicyRule::cast(compiler->dbcopy->create(PolicyRule::TYPENAME));
compiler->temp_ruleset->add(r);
r->duplicate(rule);
r->setStr("ipt_chain","POSTROUTING");
tmp_queue.push_back(r);
}
string ruleset_name = compiler->getRuleSetName();
if (ipt_comp->isMangleOnlyRuleSet(ruleset_name))
tmp_queue.push_back(rule);
}
else
{
if (rule->getAction() == PolicyRule::Branch &&
ruleopt->getBool("ipt_branch_in_mangle"))
{
PolicyRule* r;
// this is a branching rule for mangle table. Need to put it
// into PREROUTING and POSTROUTING chains as well because some
// targets that work with mangle table can only go into these
// chains, yet we do not know what kind of rules will user
// place in the branch
if (rule->getAction() == PolicyRule::Tag ||
rule->getAction() == PolicyRule::Route ||
rule->getAction() == PolicyRule::Classify ||
ruleopt->getBool("put_in_mangle_table")) tmp_queue.push_back(rule);
if (rule->getDirection()==PolicyRule::Undefined ||
rule->getDirection()==PolicyRule::Both ||
rule->getDirection()==PolicyRule::Inbound)
{
r= PolicyRule::cast(compiler->dbcopy->create(PolicyRule::TYPENAME));
compiler->temp_ruleset->add(r);
r->duplicate(rule);
r->setStr("ipt_chain","PREROUTING");
tmp_queue.push_back(r);
}
if (rule->getDirection()==PolicyRule::Undefined ||
rule->getDirection()==PolicyRule::Both ||
rule->getDirection()==PolicyRule::Outbound)
{
r= PolicyRule::cast(compiler->dbcopy->create(PolicyRule::TYPENAME));
compiler->temp_ruleset->add(r);
r->duplicate(rule);
r->setStr("ipt_chain","POSTROUTING");
tmp_queue.push_back(r);
}
tmp_queue.push_back(rule);
}
if (rule->getAction() == PolicyRule::Tag ||
rule->getAction() == PolicyRule::Route ||
rule->getAction() == PolicyRule::Classify ||
ruleopt->getBool("put_in_mangle_table")) tmp_queue.push_back(rule);
}
return true;
}
@ -118,7 +130,8 @@ void MangleTableCompiler_ipt::addRuleFilter()
string MangleTableCompiler_ipt::flushAndSetDefaultPolicy()
{
return "";
return printAutomaticRulesForMangleTable(have_connmark,
have_connmark_in_output);
}

View File

@ -41,6 +41,7 @@ namespace fwcompiler {
* this processor drops all rules except for those that require mangle table
*/
DECLARE_POLICY_RULE_PROCESSOR(keepMangleTableRules);
friend class keepMangleTableRules;
public:

View File

@ -64,6 +64,8 @@
#include <iomanip>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <iterator>
#include <assert.h>
@ -341,7 +343,15 @@ int PolicyCompiler_ipt::prolog()
if (fw->getStr("platform")!="iptables")
abort(_("Unsupported platform ") + fw->getStr("platform") );
int n= PolicyCompiler::prolog();
int n = PolicyCompiler::prolog();
FWOptions *fwopt = getCachedFwOpt();
istringstream is(fwopt->getStr("ipt_mangle_only_rulesets"));
std::copy(istream_iterator<string>(is),
istream_iterator<string>(),
back_inserter(mangle_only_rulesets));
// initialize counters for the standard chains
for (list<string>::const_iterator i =
@ -396,7 +406,6 @@ int PolicyCompiler_ipt::prolog()
cacheObj(bcast255);
FWOptions *fwopt = getCachedFwOpt();
bool afpa = fwopt->getBool("firewall_is_part_of_any_and_networks");
for(FWObject::iterator i=combined_ruleset->begin();
@ -734,6 +743,11 @@ bool PolicyCompiler_ipt::Route::processNext()
bool PolicyCompiler_ipt::dropMangleTableRules::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
PolicyCompiler_ipt *ipt_comp = dynamic_cast<PolicyCompiler_ipt*>(compiler);
string ruleset_name = compiler->getRuleSetName();
if (ipt_comp->isMangleOnlyRuleSet(ruleset_name)) return true;
if (rule->getAction() == PolicyRule::Tag ||
rule->getAction() == PolicyRule::Route ||
@ -2869,20 +2883,26 @@ bool PolicyCompiler_ipt::finalizeChain::processNext()
rule->setStr("ipt_chain","FORWARD");
break;
}
if (rule->getAction() == PolicyRule::Accept)
rule->setStr("ipt_chain","PREROUTING");
} else
{
// RuleElementSrc *srcrel=rule->getSrc();
Address *src =compiler->getFirstSrc(rule);
Address *src = compiler->getFirstSrc(rule);
if (src==NULL)
compiler->abort(string("finalizeChain: Empty Source rule element in rule ") +
rule->getLabel());
compiler->abort(
string("finalizeChain: Empty Source rule element in rule ") +
rule->getLabel());
// RuleElementDst *dstrel=rule->getDst();
Address *dst =compiler->getFirstDst(rule);
if (dst==NULL)
compiler->abort(string("finalizeChain: Empty Destination rule element in rule ") +
rule->getLabel());
compiler->abort(
string("finalizeChain: Empty Destination rule element in rule ") +
rule->getLabel());
bool b,m;
/*
@ -3974,8 +3994,8 @@ void PolicyCompiler_ipt::compile()
add( new decideOnChainIfLoopback("any-any rule on loopback" ) );
// add( new decideOnChainForClassify("set chain if action is Classify"));
add( new finalizeChain( "decide on chain" ) );
add( new decideOnTarget( "decide on target" ) );
add( new finalizeChain( "decide on chain" ) );
add( new decideOnTarget( "decide on target" ) );
add( new checkForRestoreMarkInOutput(
"check if we need -A OUTPUT -j CONNMARK --restore-mark"));
@ -4243,4 +4263,11 @@ bool PolicyCompiler_ipt::newIptables(const string &version)
XMLTools::version_compare(version, "1.2.6")>0);
}
bool PolicyCompiler_ipt::isMangleOnlyRuleSet(const string &ruleset_name)
{
return (std::find(mangle_only_rulesets.begin(),
mangle_only_rulesets.end(),
ruleset_name) != mangle_only_rulesets.end());
}

View File

@ -75,6 +75,7 @@ namespace fwcompiler {
bool have_connmark;
bool have_connmark_in_output;
std::string my_table;
std::list<std::string> mangle_only_rulesets;
std::map<std::string, int> tmp_chain_no;
std::map<std::string, int> chain_usage_counter;
@ -996,7 +997,8 @@ namespace fwcompiler {
bool haveConnMarkRules() { return have_connmark; }
bool haveConnMarkRulesInOutput() { return have_connmark_in_output; }
bool isMangleOnlyRuleSet(const std::string &rule_set_name);
};

View File

@ -783,27 +783,27 @@ _("Dynamic interface %s should not have an IP address object attached to it. Thi
if (policy->isV6()!=ipv6_policy) continue;
MangleTableCompiler_ipt *m = new MangleTableCompiler_ipt(
MangleTableCompiler_ipt m(
objdb , fwobjectname.toUtf8().constData(),
ipv6_policy , oscnf,
&minus_n_commands_mangle );
if (!policy->isTop())
m->registerRuleSetChain(branch_name);
m.registerRuleSetChain(branch_name);
m->setSourceRuleSet( policy );
m->setRuleSetName(branch_name);
m.setSourceRuleSet( policy );
m.setRuleSetName(branch_name);
m->setDebugLevel( dl );
m->setDebugRule( drp );
m->setVerbose( (bool)(verbose) );
m->setHaveDynamicInterfaces(have_dynamic_interfaces);
if (test_mode) m->setTestMode();
m.setDebugLevel( dl );
m.setDebugRule( drp );
m.setVerbose( (bool)(verbose) );
m.setHaveDynamicInterfaces(have_dynamic_interfaces);
if (test_mode) m.setTestMode();
if ( (mangle_rules_count = m->prolog()) > 0 )
if ( (mangle_rules_count = m.prolog()) > 0 )
{
m->compile();
m->epilog();
m.compile();
m.epilog();
// We need to generate automatic rules in mangle
// table (-j CONNMARK --restore-mark) if CONNMARK
@ -816,30 +816,36 @@ _("Dynamic interface %s should not have an IP address object attached to it. Thi
// later if either of these flags is true after
// all rulesets have been processed.
have_connmark |= m->haveConnMarkRules();
have_connmark_in_output |= m->haveConnMarkRulesInOutput();
have_connmark |= m.haveConnMarkRules();
have_connmark_in_output |= m.haveConnMarkRulesInOutput();
long m_str_pos = m_str.tellp();
if (policy->isTop()) top_level_mangle_compiler = m;
if (policy->isTop())
{
m_str << "# ================ Table 'mangle', ";
m_str << "automatic rules";
m_str << endl;
m_str << m.flushAndSetDefaultPolicy();
}
if (m->getCompiledScriptLength() > 0)
if (m.getCompiledScriptLength() > 0)
{
m_str << "# ================ Table 'mangle', rule set "
<< branch_name << endl;
if (m->haveErrorsAndWarnings())
if (m.haveErrorsAndWarnings())
{
m_str << "# Policy compiler errors and warnings:"
<< endl;
m_str << m->getErrors("# ");
m_str << m.getErrors("# ");
}
m_str << m->getCompiledScript();
m_str << m.getCompiledScript();
}
if (m_str_pos!=m_str.tellp())
{
m_str << m->commit();
m_str << m.commit();
m_str << endl;
empty_output = false;
}
@ -847,7 +853,7 @@ _("Dynamic interface %s should not have an IP address object attached to it. Thi
PolicyCompiler_ipt c(
objdb, fwobjectname.toUtf8().constData(), ipv6_policy, oscnf,
objdb,fwobjectname.toUtf8().constData(), ipv6_policy, oscnf,
&minus_n_commands_filter);
if (!policy->isTop())
@ -895,18 +901,6 @@ _("Dynamic interface %s should not have an IP address object attached to it. Thi
}
string mangle_table_script = "";
if (top_level_mangle_compiler &&
(have_connmark || have_connmark_in_output))
{
mangle_table_script = "# ================ Table 'mangle', ";
mangle_table_script += "automatic rules";
mangle_table_script += "\n";
mangle_table_script +=
top_level_mangle_compiler->printAutomaticRulesForMangleTable(
have_connmark, have_connmark_in_output);
}
if (!empty_output)
{
if (ipv6_policy)
@ -925,7 +919,7 @@ _("Dynamic interface %s should not have an IP address object attached to it. Thi
generated_script += dumpScript(nocomm, fw,
reset_rules.str(),
n_str.str(),
mangle_table_script + m_str.str(),
m_str.str(),
c_str.str(),
ipv6_policy);
}

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE FWObjectDatabase SYSTEM "fwbuilder.dtd">
<FWObjectDatabase xmlns="http://www.fwbuilder.org/1.0/" version="10" lastModified="1223765455" id="root">
<FWObjectDatabase xmlns="http://www.fwbuilder.org/1.0/" version="10" lastModified="1223783524" id="root">
<Library id="sysid99" name="Deleted Objects" comment="" ro="False">
<ICMP6Service id="idE0C27650" code="0" type="1" name="ipv6 dest unreachable" comment="No route to destination" ro="False"/>
<IPv4 id="id41D295E2" name="firewall30:ppp.200*:ip" comment="" ro="False" address="192.168.1.1" netmask="255.255.255.0"/>
@ -601,6 +601,8 @@
<ObjectRef ref="id4834B9206131"/>
<ObjectRef ref="id86936X27543"/>
<ServiceRef ref="sysid1"/>
<ServiceRef ref="sysid1"/>
<ServiceRef ref="sysid1"/>
</Library>
<Library id="syslib001" color="#d2ffd0" name="User" comment="User defined objects" ro="False">
<ObjectGroup id="stdid01_1" name="Objects" comment="" ro="False">
@ -19340,7 +19342,7 @@ echo '%FWBPROMPT%'; sh /tmp/%FWSCRIPT%
<Option name="verify_interfaces">True</Option>
</FirewallOptions>
</Firewall>
<Firewall id="id43BB80919745" host_OS="linux24" inactive="False" lastCompiled="1223772424" lastInstalled="1142003872" lastModified="1223772593" platform="iptables" version="" name="firewall37" comment="testing TAG and CLASSIFY rules&#10;&#10;normal script mode (not using iptables-restore)" ro="False">
<Firewall id="id43BB80919745" host_OS="linux24" inactive="False" lastCompiled="1223783631" lastInstalled="1142003872" lastModified="1223783606" platform="iptables" version="" name="firewall37" comment="testing TAG and CLASSIFY rules&#10;&#10;normal script mode (not using iptables-restore)" ro="False">
<NAT id="id43BB80B09745" name="NAT" comment="" ro="False" ipv6_rule_set="False" top_rule_set="True">
<NATRule id="id43BB814D9745" disabled="False" position="0" comment="">
<OSrc neg="False">
@ -20664,6 +20666,111 @@ echo '%FWBPROMPT%'; sh /tmp/%FWSCRIPT%
</PolicyRuleOptions>
</PolicyRule>
</Policy>
<Policy id="id39898X29169" name="mangle_rules" comment="" ro="False" ipv6_rule_set="False" top_rule_set="False">
<PolicyRule id="id39899X29169" action="Accept" direction="Both" disabled="False" log="False" position="0" comment="">
<Src neg="False">
<ObjectRef ref="sysid0"/>
</Src>
<Dst neg="False">
<ObjectRef ref="sysid0"/>
</Dst>
<Srv neg="True">
<ServiceRef ref="id37422X26379"/>
</Srv>
<Itf neg="False">
<ObjectRef ref="sysid0"/>
</Itf>
<When neg="False">
<IntervalRef ref="sysid2"/>
</When>
<PolicyRuleOptions>
<Option name="stateless">False</Option>
</PolicyRuleOptions>
</PolicyRule>
<PolicyRule id="id56804X29169" action="Tag" direction="Both" disabled="False" group="" log="False" position="1" comment="">
<Src neg="False">
<ObjectRef ref="sysid0"/>
</Src>
<Dst neg="False">
<ObjectRef ref="sysid0"/>
</Dst>
<Srv neg="False">
<ServiceRef ref="tcp-HTTP"/>
</Srv>
<Itf neg="False">
<ObjectRef ref="sysid0"/>
</Itf>
<When neg="False">
<IntervalRef ref="sysid2"/>
</When>
<PolicyRuleOptions>
<Option name="action_on_reject"></Option>
<Option name="classify_str"></Option>
<Option name="custom_str"></Option>
<Option name="ipf_route_opt_addr"></Option>
<Option name="ipf_route_opt_if"></Option>
<Option name="ipf_route_option">route_through</Option>
<Option name="ipfw_classify_method">2</Option>
<Option name="ipfw_pipe_port_num">0</Option>
<Option name="ipfw_pipe_queue_num">0</Option>
<Option name="ipt_continue">False</Option>
<Option name="ipt_gw"></Option>
<Option name="ipt_iif"></Option>
<Option name="ipt_mark_connections">True</Option>
<Option name="ipt_oif"></Option>
<Option name="ipt_tee">False</Option>
<Option name="pf_fastroute">False</Option>
<Option name="pf_route_load_option">none</Option>
<Option name="pf_route_opt_addr"></Option>
<Option name="pf_route_opt_if"></Option>
<Option name="pf_route_option">route_through</Option>
<Option name="rule_name_accounting"></Option>
<Option name="stateless">False</Option>
<Option name="tagobject_id">id449328D824380</Option>
</PolicyRuleOptions>
</PolicyRule>
<PolicyRule id="id56817X29169" action="Classify" direction="Both" disabled="False" group="" log="False" position="2" comment="">
<Src neg="False">
<ObjectRef ref="sysid0"/>
</Src>
<Dst neg="False">
<ObjectRef ref="sysid0"/>
</Dst>
<Srv neg="False">
<ServiceRef ref="id449328D824380"/>
</Srv>
<Itf neg="False">
<ObjectRef ref="sysid0"/>
</Itf>
<When neg="False">
<IntervalRef ref="sysid2"/>
</When>
<PolicyRuleOptions>
<Option name="action_on_reject"></Option>
<Option name="classify_str">1:12</Option>
<Option name="custom_str"></Option>
<Option name="ipf_route_opt_addr"></Option>
<Option name="ipf_route_opt_if"></Option>
<Option name="ipf_route_option">route_through</Option>
<Option name="ipfw_classify_method">2</Option>
<Option name="ipfw_pipe_port_num">0</Option>
<Option name="ipfw_pipe_queue_num">0</Option>
<Option name="ipt_continue">False</Option>
<Option name="ipt_gw"></Option>
<Option name="ipt_iif"></Option>
<Option name="ipt_mark_connections">False</Option>
<Option name="ipt_oif"></Option>
<Option name="ipt_tee">False</Option>
<Option name="pf_fastroute">False</Option>
<Option name="pf_route_load_option">none</Option>
<Option name="pf_route_opt_addr"></Option>
<Option name="pf_route_opt_if"></Option>
<Option name="pf_route_option">route_through</Option>
<Option name="rule_name_accounting"></Option>
<Option name="stateless">True</Option>
</PolicyRuleOptions>
</PolicyRule>
</Policy>
<Routing id="id43BB81789745" name="Routing" comment="" ro="False" ipv6_rule_set="False" top_rule_set="True"/>
<Interface id="id43BB81799745" bridgeport="False" dyn="False" label="" mgmt="True" security_level="100" unnum="False" unprotected="False" name="eth0" comment="" ro="False">
<IPv4 id="id43BB817B9745" name="firewall37:eth0:ip" comment="" ro="False" address="192.168.1.22" netmask="255.255.255.0"/>
@ -20699,6 +20806,7 @@ echo '%FWBPROMPT%'; sh /tmp/%FWSCRIPT%
<Option name="firewall_dir"></Option>
<Option name="firewall_is_part_of_any_and_networks">True</Option>
<Option name="ignore_empty_groups">True</Option>
<Option name="ipt_mangle_only_rulesets"> mangle_rules</Option>
<Option name="ipv4_6_order">ipv4_first</Option>
<Option name="limit_suffix"></Option>
<Option name="limit_value">0</Option>