mirror of
https://github.com/fwbuilder/fwbuilder
synced 2026-03-20 18:27:16 +01:00
Support for NAT branching for iptables; see #84
This commit is contained in:
parent
0dc0a989f0
commit
7d672c2169
@ -1,3 +1,27 @@
|
||||
2009-10-20 vadim <vadim@vk.crocodile.org>
|
||||
|
||||
* Support for branch rules in NAT rule sets. Currently only
|
||||
supported on iptables and PF. NAT rules get column "Action" for
|
||||
these platforms, with possible acctions "Translate" and "Branch".
|
||||
Action parameters dialog for the Branch action provides drop well
|
||||
where another NAT ruleset object can be dropped (just like with
|
||||
Branch action in the Policy rules). Action "Translate" performs
|
||||
translation as defined in the rule. Objects in the "Translated
|
||||
source/destination/service" are ignored in NAT rules with action
|
||||
"Branch" and a warning is issued at compile time.
|
||||
|
||||
* NATCompiler_ipt.cpp (splitNATBranchRule::processNext): Support
|
||||
for branching NAT rules for iptables. Rules in the branch rule set
|
||||
are processed first and their targets and corresponding chains are
|
||||
recorded. These rules are placed in the user-defined chains with
|
||||
the name composed of the rule set name and the
|
||||
chain ("POSTROUTING" or "PREROUTING") that corresponds to the
|
||||
chosen target. Then top NAT rule set is processed. Branching rules
|
||||
found in it pass control to the chains used for the rules from the
|
||||
branching rule set. IF branching rule set uses a mix of SNAT and
|
||||
DNAT rules, the branching rule in the top rule set is split and
|
||||
placed in both PREROUTING and POSTROUTING chains as appropriate.
|
||||
|
||||
2009-10-14 vadim <vadim@vk.crocodile.org>
|
||||
|
||||
* src/res/configlets/linux24/conntrack: Implemented support for
|
||||
|
||||
@ -548,11 +548,10 @@ void CompilerDriver::findImportedRuleSets(Firewall *fw,
|
||||
{
|
||||
for (list<FWObject*>::iterator r=(*i)->begin(); r!=(*i)->end(); ++r)
|
||||
{
|
||||
PolicyRule *rule = PolicyRule::cast(*r);
|
||||
RuleSet *ruleset = NULL;
|
||||
if (rule->getAction() == PolicyRule::Branch &&
|
||||
(ruleset = rule->getBranch())!=NULL &&
|
||||
!ruleset->isChildOf(fw))
|
||||
Rule *rule = Rule::cast(*r);
|
||||
RuleSet *ruleset = rule->getBranch();
|
||||
|
||||
if (ruleset!=NULL && !ruleset->isChildOf(fw))
|
||||
{
|
||||
ruleset->setTop(false);
|
||||
imported_policies.push_back(ruleset);
|
||||
|
||||
@ -67,8 +67,8 @@ ActionsDialog::ActionsDialog(QWidget *parent) : BaseObjectDialog(parent)
|
||||
m_dialog->setupUi(this);
|
||||
|
||||
m_dialog->iptBranchDropArea->addAcceptedTypes("Policy");
|
||||
m_dialog->iptBranchDropArea->addAcceptedTypes("NAT");
|
||||
m_dialog->iptBranchDropArea->addAcceptedTypes("Routing");
|
||||
//m_dialog->iptBranchDropArea->addAcceptedTypes("NAT");
|
||||
//m_dialog->iptBranchDropArea->addAcceptedTypes("Routing");
|
||||
m_dialog->iptBranchDropArea->setHelperText("Drop rule set object here");
|
||||
connect (m_dialog->iptBranchDropArea,
|
||||
SIGNAL(objectDeleted()),this,SLOT(changed()));
|
||||
@ -76,14 +76,21 @@ ActionsDialog::ActionsDialog(QWidget *parent) : BaseObjectDialog(parent)
|
||||
SIGNAL(objectInserted()),this,SLOT(changed()));
|
||||
|
||||
m_dialog->pfBranchDropArea->addAcceptedTypes("Policy");
|
||||
m_dialog->pfBranchDropArea->addAcceptedTypes("NAT");
|
||||
m_dialog->pfBranchDropArea->addAcceptedTypes("Routing");
|
||||
//m_dialog->pfBranchDropArea->addAcceptedTypes("NAT");
|
||||
//m_dialog->pfBranchDropArea->addAcceptedTypes("Routing");
|
||||
m_dialog->pfBranchDropArea->setHelperText("Drop rule set object here");
|
||||
connect (m_dialog->pfBranchDropArea,
|
||||
SIGNAL(objectDeleted()),this,SLOT(changed()));
|
||||
connect (m_dialog->pfBranchDropArea,
|
||||
SIGNAL(objectInserted()),this,SLOT(changed()));
|
||||
|
||||
m_dialog->natBranchDropArea->addAcceptedTypes("NAT");
|
||||
m_dialog->natBranchDropArea->setHelperText("Drop NAT rule set object here");
|
||||
connect (m_dialog->natBranchDropArea,
|
||||
SIGNAL(objectDeleted()),this,SLOT(changed()));
|
||||
connect (m_dialog->natBranchDropArea,
|
||||
SIGNAL(objectInserted()),this,SLOT(changed()));
|
||||
|
||||
m_dialog->pfTagDropArea->addAcceptedTypes("TagService");
|
||||
connect (m_dialog->pfTagDropArea,
|
||||
SIGNAL(objectDeleted()),this,SLOT(changed()));
|
||||
@ -199,6 +206,13 @@ void ActionsDialog::applyChanges()
|
||||
rule->setBranch(ruleset);
|
||||
}
|
||||
|
||||
if (editor=="NATBranch")
|
||||
{
|
||||
RuleSet *ruleset = RuleSet::cast(m_dialog->natBranchDropArea->getObject());
|
||||
// if ruleset==NULL, setBranch clears setting in the rule
|
||||
rule->setBranch(ruleset);
|
||||
}
|
||||
|
||||
if (m_dialog->useDummyNetPipe->isChecked())
|
||||
ropt->setInt("ipfw_classify_method",DUMMYNETPIPE);
|
||||
else
|
||||
@ -249,7 +263,11 @@ void ActionsDialog::setRule(Rule *r)
|
||||
|
||||
string act;
|
||||
if (policy_rule) act = policy_rule->getActionAsString();
|
||||
if (nat_rule) act = nat_rule->getActionAsString();
|
||||
if (nat_rule)
|
||||
{
|
||||
act = nat_rule->getActionAsString();
|
||||
if (act == "Branch") act = "NATBranch";
|
||||
}
|
||||
|
||||
help_name = string(platform + "_" + act).c_str();
|
||||
|
||||
@ -398,6 +416,12 @@ void ActionsDialog::setRule(Rule *r)
|
||||
RuleSet *ruleset = r->getBranch();
|
||||
m_dialog->iptBranchDropArea->setObject(ruleset);
|
||||
}
|
||||
else if (editor=="NATBranch")
|
||||
{
|
||||
w = m_dialog->NATBranchPage;
|
||||
RuleSet *ruleset = r->getBranch();
|
||||
m_dialog->natBranchDropArea->setObject(ruleset);
|
||||
}
|
||||
else if (editor=="RouteIPT")
|
||||
{
|
||||
w=m_dialog->RouteIPTPage;
|
||||
|
||||
@ -37,7 +37,7 @@
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<property name="currentIndex" >
|
||||
<number>12</number>
|
||||
<number>14</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="TagStrPage" >
|
||||
<layout class="QGridLayout" >
|
||||
@ -1042,6 +1042,65 @@ object properties dialog.</string>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="NATBranchPage" >
|
||||
<layout class="QGridLayout" name="gridLayout_2" >
|
||||
<item row="0" column="0" colspan="2" >
|
||||
<widget class="QLabel" name="label_2" >
|
||||
<property name="text" >
|
||||
<string>NAT Rule set object:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="FWObjectDropArea" native="1" name="natBranchDropArea" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize" >
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>80</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize" >
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>80</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<spacer name="horizontalSpacer" >
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0" >
|
||||
<size>
|
||||
<width>663</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="1" >
|
||||
<spacer name="verticalSpacer" >
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0" >
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>33</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
@ -1057,7 +1116,6 @@ object properties dialog.</string>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<includes/>
|
||||
<resources>
|
||||
<include location="MainRes.qrc" />
|
||||
</resources>
|
||||
|
||||
@ -24,39 +24,22 @@
|
||||
*/
|
||||
|
||||
#include "../../config.h"
|
||||
#include "../../build_num"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <assert.h>
|
||||
#include <cstring>
|
||||
#include <iomanip>
|
||||
#include <memory>
|
||||
|
||||
#include "Configlet.h"
|
||||
#include "CompilerDriver_ipt.h"
|
||||
#include "PolicyCompiler_ipt.h"
|
||||
#include "PolicyCompiler_secuwall.h"
|
||||
#include "MangleTableCompiler_ipt.h"
|
||||
#include "OSConfigurator_linux24.h"
|
||||
#include "OSConfigurator_ipcop.h"
|
||||
#include "OSConfigurator_secuwall.h"
|
||||
|
||||
#include "fwcompiler/Preprocessor.h"
|
||||
#include "fwbuilder/Resources.h"
|
||||
#include "fwbuilder/FWObjectDatabase.h"
|
||||
#include "fwbuilder/FWException.h"
|
||||
#include "fwbuilder/Cluster.h"
|
||||
#include "fwbuilder/ClusterGroup.h"
|
||||
#include "fwbuilder/Firewall.h"
|
||||
#include "fwbuilder/Interface.h"
|
||||
#include "fwbuilder/Policy.h"
|
||||
#include "fwbuilder/Rule.h"
|
||||
#include "fwbuilder/RuleSet.h"
|
||||
|
||||
#include <QStringList>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
using namespace std;
|
||||
@ -191,232 +174,4 @@ string CompilerDriver_ipt::dumpScript(Firewall *fw,
|
||||
return res.str();
|
||||
}
|
||||
|
||||
bool CompilerDriver_ipt::processPolicyRuleSet(
|
||||
Firewall *fw,
|
||||
FWObject *ruleset,
|
||||
const string &single_rule_id,
|
||||
ostringstream &filter_table_stream,
|
||||
ostringstream &mangle_table_stream,
|
||||
ostringstream &automatic_rules_stream,
|
||||
OSConfigurator_linux24 *oscnf,
|
||||
int policy_af,
|
||||
std::map<const std::string, bool> &minus_n_commands_filter,
|
||||
std::map<const std::string, bool> &minus_n_commands_mangle)
|
||||
{
|
||||
int policy_rules_count = 0;
|
||||
int mangle_rules_count = 0;
|
||||
bool have_connmark = false;
|
||||
bool have_connmark_in_output = false;
|
||||
bool empty_output = true;
|
||||
string prolog_place = fw->getOptionsObject()->getStr("prolog_place");
|
||||
string platform = fw->getStr("platform");
|
||||
string host_os = fw->getStr("host_OS");
|
||||
bool flush_and_set_default_policy = Resources::getTargetOptionBool(
|
||||
host_os, "default/flush_and_set_default_policy");
|
||||
string platform_family = Resources::platform_res[platform]->
|
||||
getResourceStr("/FWBuilderResources/Target/family");
|
||||
string os_family = Resources::os_res[host_os]->
|
||||
getResourceStr("/FWBuilderResources/Target/family");
|
||||
|
||||
|
||||
Policy *policy = Policy::cast(ruleset);
|
||||
assignRuleSetChain(policy);
|
||||
string branch_name = policy->getName();
|
||||
|
||||
if (!policy->matchingAddressFamily(policy_af)) return true;
|
||||
|
||||
bool ipv6_policy = (policy_af == AF_INET6);
|
||||
|
||||
std::auto_ptr<MangleTableCompiler_ipt> mangle_compiler(
|
||||
new MangleTableCompiler_ipt(objdb , fw,
|
||||
ipv6_policy , oscnf,
|
||||
&minus_n_commands_mangle ));
|
||||
|
||||
if (!policy->isTop())
|
||||
mangle_compiler->registerRuleSetChain(branch_name);
|
||||
|
||||
mangle_compiler->setSourceRuleSet( policy );
|
||||
mangle_compiler->setRuleSetName(branch_name);
|
||||
|
||||
mangle_compiler->setSingleRuleCompileMode(single_rule_id);
|
||||
mangle_compiler->setDebugLevel( dl );
|
||||
if (rule_debug_on) mangle_compiler->setDebugRule( drp );
|
||||
mangle_compiler->setVerbose( (bool)(verbose) );
|
||||
mangle_compiler->setHaveDynamicInterfaces(have_dynamic_interfaces);
|
||||
if (inTestMode()) mangle_compiler->setTestMode();
|
||||
if (inEmbeddedMode()) mangle_compiler->setEmbeddedMode();
|
||||
|
||||
if ( (mangle_rules_count = mangle_compiler->prolog()) > 0 )
|
||||
{
|
||||
mangle_compiler->compile();
|
||||
mangle_compiler->epilog();
|
||||
|
||||
// We need to generate automatic rules in mangle
|
||||
// table (-j CONNMARK --restore-mark) if CONNMARK
|
||||
// target is present in any ruleset, not only in
|
||||
// the top-level ruleset. So we keep global
|
||||
// boolean flags for this condition which will
|
||||
// become true if any ruleset has such
|
||||
// rules. We'll call
|
||||
// MangleTableCompiler_ipt::flushAndSetDefaultPolicy
|
||||
// later if either of these flags is true after
|
||||
// all rulesets have been processed.
|
||||
|
||||
have_connmark |= mangle_compiler->haveConnMarkRules();
|
||||
have_connmark_in_output |= mangle_compiler->haveConnMarkRulesInOutput();
|
||||
|
||||
long m_str_pos = mangle_table_stream.tellp();
|
||||
|
||||
if (policy->isTop())
|
||||
{
|
||||
ostringstream tmp;
|
||||
|
||||
if (flush_and_set_default_policy)
|
||||
tmp << mangle_compiler->flushAndSetDefaultPolicy();
|
||||
|
||||
tmp << mangle_compiler->printAutomaticRules();
|
||||
|
||||
if (tmp.tellp() > 0)
|
||||
{
|
||||
if (!single_rule_compile_on)
|
||||
{
|
||||
mangle_table_stream << "# ================ Table 'mangle', ";
|
||||
mangle_table_stream << "automatic rules";
|
||||
mangle_table_stream << "\n";
|
||||
}
|
||||
mangle_table_stream << tmp.str();
|
||||
}
|
||||
}
|
||||
|
||||
if (mangle_compiler->getCompiledScriptLength() > 0)
|
||||
{
|
||||
ostringstream tmp;
|
||||
if (mangle_compiler->haveErrorsAndWarnings())
|
||||
{
|
||||
all_errors.push_back(mangle_compiler->getErrors("").c_str());
|
||||
// tmp << "# Policy compiler errors and warnings:" << "\n";
|
||||
// tmp << mangle_compiler->getErrors("# ");
|
||||
}
|
||||
|
||||
tmp << mangle_compiler->getCompiledScript();
|
||||
|
||||
if (tmp.tellp() > 0)
|
||||
{
|
||||
if (!single_rule_compile_on)
|
||||
{
|
||||
mangle_table_stream << "# ================ Table 'mangle', ";
|
||||
mangle_table_stream << "rule set " << branch_name << "\n";
|
||||
}
|
||||
mangle_table_stream << tmp.str();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_str_pos!=mangle_table_stream.tellp())
|
||||
{
|
||||
mangle_table_stream << "\n";
|
||||
empty_output = false;
|
||||
}
|
||||
}
|
||||
|
||||
std::auto_ptr<PolicyCompiler_ipt> policy_compiler;
|
||||
|
||||
if (fw->getStr("host_OS") == "secuwall") {
|
||||
policy_compiler = std::auto_ptr<PolicyCompiler_ipt>(
|
||||
new PolicyCompiler_secuwall(objdb,fw, ipv6_policy, oscnf,
|
||||
&minus_n_commands_filter));
|
||||
} else {
|
||||
policy_compiler = std::auto_ptr<PolicyCompiler_ipt>(
|
||||
new PolicyCompiler_ipt(objdb,fw, ipv6_policy, oscnf,
|
||||
&minus_n_commands_filter));
|
||||
}
|
||||
|
||||
if (policy_compiler.get()==NULL)
|
||||
throw FWException("Unrecognized firewall platform " +
|
||||
fw->getStr("platform") +
|
||||
" (family " + platform_family+")");
|
||||
|
||||
if (!policy->isTop())
|
||||
policy_compiler->registerRuleSetChain(branch_name);
|
||||
|
||||
policy_compiler->setSourceRuleSet( policy );
|
||||
policy_compiler->setRuleSetName(branch_name);
|
||||
|
||||
policy_compiler->setSingleRuleCompileMode(single_rule_id);
|
||||
policy_compiler->setDebugLevel( dl );
|
||||
if (rule_debug_on) policy_compiler->setDebugRule( drp );
|
||||
policy_compiler->setVerbose( (bool)(verbose) );
|
||||
policy_compiler->setHaveDynamicInterfaces(have_dynamic_interfaces);
|
||||
if (inTestMode()) policy_compiler->setTestMode();
|
||||
if (inEmbeddedMode()) policy_compiler->setEmbeddedMode();
|
||||
|
||||
if ( (policy_rules_count=policy_compiler->prolog()) > 0 )
|
||||
{
|
||||
policy_compiler->compile();
|
||||
policy_compiler->epilog();
|
||||
|
||||
if (policy_compiler->getCompiledScriptLength() > 0)
|
||||
{
|
||||
ostringstream tmp;
|
||||
|
||||
if (policy_compiler->haveErrorsAndWarnings())
|
||||
{
|
||||
all_errors.push_back(policy_compiler->getErrors("").c_str());
|
||||
// tmp << "# Policy compiler errors and warnings:" << "\n";
|
||||
// tmp << policy_compiler->getErrors("# ");
|
||||
}
|
||||
tmp << policy_compiler->getCompiledScript();
|
||||
|
||||
if (tmp.tellp() > 0)
|
||||
{
|
||||
empty_output = false;
|
||||
if (!single_rule_compile_on)
|
||||
{
|
||||
filter_table_stream << "# ================ Table 'filter', ";
|
||||
filter_table_stream << "rule set " << branch_name << "\n";
|
||||
}
|
||||
filter_table_stream << tmp.str();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* bug #2550074: "Automatic rules for filter table included twice
|
||||
* in iptables". If user had two policy ruleset objects marked as
|
||||
* "top" rule set, then automaitc rules were added twice. Since we
|
||||
* add rules to automatic_rules_stream only in this one place, it
|
||||
* is sufficient to check if the stream is empty to avoid
|
||||
* duplication. Note that on windows tellp() seems to return -1
|
||||
* if no data has ever been written to the stream.
|
||||
*/
|
||||
long auto_rules_stream_position = automatic_rules_stream.tellp();
|
||||
|
||||
if (policy->isTop() && auto_rules_stream_position <= 0)
|
||||
{
|
||||
ostringstream tmp;
|
||||
|
||||
if (flush_and_set_default_policy)
|
||||
tmp << policy_compiler->flushAndSetDefaultPolicy();
|
||||
|
||||
if (!prolog_done && prolog_place == "after_flush" &&
|
||||
!fw->getOptionsObject()->getBool("use_iptables_restore"))
|
||||
{
|
||||
tmp << "prolog_commands" << endl;
|
||||
prolog_done = true;
|
||||
}
|
||||
|
||||
tmp << policy_compiler->printAutomaticRules();
|
||||
|
||||
if (tmp.tellp() > 0)
|
||||
{
|
||||
empty_output = false;
|
||||
if (!single_rule_compile_on)
|
||||
{
|
||||
automatic_rules_stream
|
||||
<< "# ================ Table 'filter', automatic rules"
|
||||
<< "\n";
|
||||
}
|
||||
automatic_rules_stream << tmp.str();
|
||||
}
|
||||
}
|
||||
return empty_output;
|
||||
}
|
||||
|
||||
|
||||
@ -32,6 +32,8 @@
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
||||
#include <QString>
|
||||
#include <QMap>
|
||||
@ -50,6 +52,19 @@ namespace fwcompiler {
|
||||
|
||||
class CompilerDriver_ipt : public CompilerDriver {
|
||||
|
||||
// commands that pass control to branch chains should go into
|
||||
// POSTROUTING or PREROUTING chains depending on the targets used
|
||||
// inside the branch. Branches that use mixed rules (both SNAT
|
||||
// and DNAT) will be split so that two separate chains are created, one
|
||||
// for all SNAT rules and another for all DNAT rules. Rules in
|
||||
// the top NAT ruleset that pass control to them will be placed into
|
||||
// PREROUTING or POSTROUTING chain depending on the target in the branch.
|
||||
// The following maps targets used in the branch to the ruleset name.
|
||||
// By convention, the chain created for the branch rules will be named
|
||||
// using combination of the ruleset name and word "PREROUTING"
|
||||
// or "POSTROUTING"
|
||||
std::map<std::string, std::list<std::string> > branch_ruleset_to_chain_mapping;
|
||||
|
||||
public:
|
||||
|
||||
CompilerDriver_ipt(libfwbuilder::FWObjectDatabase *db);
|
||||
@ -84,6 +99,16 @@ public:
|
||||
std::map<const std::string, bool> &minus_n_commands_filter,
|
||||
std::map<const std::string, bool> &minus_n_commands_mangle);
|
||||
|
||||
bool processNatRuleSet(
|
||||
libfwbuilder::Firewall *fw,
|
||||
libfwbuilder::FWObject *ruleset,
|
||||
const std::string &single_rule_id,
|
||||
std::ostringstream &nat_stream,
|
||||
fwcompiler::OSConfigurator_linux24 *oscnf,
|
||||
int policy_af,
|
||||
std::map<const std::string, bool> &minus_n_commands_nat);
|
||||
|
||||
|
||||
virtual void processStateSyncGroups(libfwbuilder::Cluster *cluster,
|
||||
libfwbuilder::Firewall *member_fw);
|
||||
|
||||
|
||||
130
src/iptlib/CompilerDriver_ipt_nat.cpp
Normal file
130
src/iptlib/CompilerDriver_ipt_nat.cpp
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
|
||||
Firewall Builder
|
||||
|
||||
Copyright (C) 2009 NetCitadel, LLC
|
||||
|
||||
Author: Vadim Kurland vadim@vk.crocodile.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 "CompilerDriver_ipt.h"
|
||||
#include "NATCompiler_ipt.h"
|
||||
#include "OSConfigurator_linux24.h"
|
||||
|
||||
#include "fwbuilder/FWObjectDatabase.h"
|
||||
#include "fwbuilder/FWException.h"
|
||||
#include "fwbuilder/Firewall.h"
|
||||
#include "fwbuilder/NAT.h"
|
||||
#include "fwbuilder/Resources.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace libfwbuilder;
|
||||
using namespace fwcompiler;
|
||||
|
||||
|
||||
bool CompilerDriver_ipt::processNatRuleSet(
|
||||
Firewall *fw,
|
||||
FWObject *ruleset,
|
||||
const std::string &single_rule_id,
|
||||
std::ostringstream &nat_rules_stream,
|
||||
fwcompiler::OSConfigurator_linux24 *oscnf,
|
||||
int policy_af,
|
||||
std::map<const std::string, bool> &minus_n_commands_nat)
|
||||
{
|
||||
int nat_rules_count = 0;
|
||||
string host_os = fw->getStr("host_OS");
|
||||
bool flush_and_set_default_policy = Resources::getTargetOptionBool(
|
||||
host_os, "default/flush_and_set_default_policy");
|
||||
bool empty_output = true;
|
||||
|
||||
NAT *nat = NAT::cast(ruleset);
|
||||
assignRuleSetChain(nat);
|
||||
string branch_name = nat->getName();
|
||||
|
||||
if (!nat->matchingAddressFamily(policy_af)) return true;
|
||||
|
||||
bool ipv6_policy = (policy_af == AF_INET6);
|
||||
|
||||
// compile NAT rules before policy rules because policy
|
||||
// compiler needs to know the number of virtual addresses
|
||||
// being created for NAT
|
||||
std::auto_ptr<NATCompiler_ipt> nat_compiler(
|
||||
new NATCompiler_ipt(objdb, fw, ipv6_policy,
|
||||
oscnf, &minus_n_commands_nat));
|
||||
|
||||
if (!nat->isTop())
|
||||
nat_compiler->registerRuleSetChain(branch_name);
|
||||
|
||||
nat_compiler->setSourceRuleSet( nat );
|
||||
nat_compiler->setRuleSetName(branch_name);
|
||||
|
||||
nat_compiler->setSingleRuleCompileMode(single_rule_id);
|
||||
nat_compiler->setDebugLevel( dl );
|
||||
if (rule_debug_on) nat_compiler->setDebugRule( drn );
|
||||
nat_compiler->setVerbose( (bool)(verbose) );
|
||||
nat_compiler->setHaveDynamicInterfaces(have_dynamic_interfaces);
|
||||
if (inTestMode()) nat_compiler->setTestMode();
|
||||
if (inEmbeddedMode()) nat_compiler->setEmbeddedMode();
|
||||
|
||||
nat_compiler->setRulesetToChainMapping(&branch_ruleset_to_chain_mapping);
|
||||
|
||||
if ( (nat_rules_count=nat_compiler->prolog()) > 0 )
|
||||
{
|
||||
nat_compiler->compile();
|
||||
nat_compiler->epilog();
|
||||
}
|
||||
|
||||
have_nat = (have_nat || (nat_rules_count > 0));
|
||||
|
||||
if (nat_compiler->getCompiledScriptLength() > 0)
|
||||
{
|
||||
if (!single_rule_compile_on)
|
||||
nat_rules_stream << "# ================ Table 'nat', "
|
||||
<< " rule set "
|
||||
<< branch_name << "\n";
|
||||
|
||||
if (nat_compiler->haveErrorsAndWarnings())
|
||||
{
|
||||
all_errors.push_back(nat_compiler->getErrors("").c_str());
|
||||
}
|
||||
|
||||
if (nat->isTop())
|
||||
{
|
||||
if (flush_and_set_default_policy)
|
||||
nat_rules_stream << nat_compiler->flushAndSetDefaultPolicy();
|
||||
|
||||
nat_rules_stream << nat_compiler->printAutomaticRules();
|
||||
}
|
||||
|
||||
nat_rules_stream << nat_compiler->getCompiledScript();
|
||||
nat_rules_stream << "\n";
|
||||
empty_output = false;
|
||||
|
||||
branch_ruleset_to_chain_mapping[branch_name] = nat_compiler->getUsedChains();
|
||||
}
|
||||
return empty_output;
|
||||
}
|
||||
|
||||
280
src/iptlib/CompilerDriver_ipt_policy.cpp
Normal file
280
src/iptlib/CompilerDriver_ipt_policy.cpp
Normal file
@ -0,0 +1,280 @@
|
||||
/*
|
||||
|
||||
Firewall Builder
|
||||
|
||||
Copyright (C) 2009 NetCitadel, LLC
|
||||
|
||||
Author: Vadim Kurland vadim@vk.crocodile.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 "CompilerDriver_ipt.h"
|
||||
#include "MangleTableCompiler_ipt.h"
|
||||
#include "PolicyCompiler_ipt.h"
|
||||
#include "PolicyCompiler_secuwall.h"
|
||||
#include "OSConfigurator_linux24.h"
|
||||
|
||||
#include "Configlet.h"
|
||||
|
||||
#include "fwbuilder/FWObjectDatabase.h"
|
||||
#include "fwbuilder/FWException.h"
|
||||
#include "fwbuilder/Firewall.h"
|
||||
#include "fwbuilder/Interface.h"
|
||||
#include "fwbuilder/Policy.h"
|
||||
#include "fwbuilder/Resources.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace libfwbuilder;
|
||||
using namespace fwcompiler;
|
||||
|
||||
|
||||
bool CompilerDriver_ipt::processPolicyRuleSet(
|
||||
Firewall *fw,
|
||||
FWObject *ruleset,
|
||||
const string &single_rule_id,
|
||||
ostringstream &filter_table_stream,
|
||||
ostringstream &mangle_table_stream,
|
||||
ostringstream &automatic_rules_stream,
|
||||
OSConfigurator_linux24 *oscnf,
|
||||
int policy_af,
|
||||
std::map<const std::string, bool> &minus_n_commands_filter,
|
||||
std::map<const std::string, bool> &minus_n_commands_mangle)
|
||||
{
|
||||
int policy_rules_count = 0;
|
||||
int mangle_rules_count = 0;
|
||||
bool have_connmark = false;
|
||||
bool have_connmark_in_output = false;
|
||||
bool empty_output = true;
|
||||
string prolog_place = fw->getOptionsObject()->getStr("prolog_place");
|
||||
string platform = fw->getStr("platform");
|
||||
string host_os = fw->getStr("host_OS");
|
||||
bool flush_and_set_default_policy = Resources::getTargetOptionBool(
|
||||
host_os, "default/flush_and_set_default_policy");
|
||||
string platform_family = Resources::platform_res[platform]->
|
||||
getResourceStr("/FWBuilderResources/Target/family");
|
||||
string os_family = Resources::os_res[host_os]->
|
||||
getResourceStr("/FWBuilderResources/Target/family");
|
||||
|
||||
|
||||
Policy *policy = Policy::cast(ruleset);
|
||||
assignRuleSetChain(policy);
|
||||
string branch_name = policy->getName();
|
||||
|
||||
if (!policy->matchingAddressFamily(policy_af)) return true;
|
||||
|
||||
bool ipv6_policy = (policy_af == AF_INET6);
|
||||
|
||||
std::auto_ptr<MangleTableCompiler_ipt> mangle_compiler(
|
||||
new MangleTableCompiler_ipt(objdb , fw,
|
||||
ipv6_policy , oscnf,
|
||||
&minus_n_commands_mangle ));
|
||||
|
||||
if (!policy->isTop())
|
||||
mangle_compiler->registerRuleSetChain(branch_name);
|
||||
|
||||
mangle_compiler->setSourceRuleSet( policy );
|
||||
mangle_compiler->setRuleSetName(branch_name);
|
||||
|
||||
mangle_compiler->setSingleRuleCompileMode(single_rule_id);
|
||||
mangle_compiler->setDebugLevel( dl );
|
||||
if (rule_debug_on) mangle_compiler->setDebugRule( drp );
|
||||
mangle_compiler->setVerbose( (bool)(verbose) );
|
||||
mangle_compiler->setHaveDynamicInterfaces(have_dynamic_interfaces);
|
||||
if (inTestMode()) mangle_compiler->setTestMode();
|
||||
if (inEmbeddedMode()) mangle_compiler->setEmbeddedMode();
|
||||
|
||||
if ( (mangle_rules_count = mangle_compiler->prolog()) > 0 )
|
||||
{
|
||||
mangle_compiler->compile();
|
||||
mangle_compiler->epilog();
|
||||
|
||||
// We need to generate automatic rules in mangle
|
||||
// table (-j CONNMARK --restore-mark) if CONNMARK
|
||||
// target is present in any ruleset, not only in
|
||||
// the top-level ruleset. So we keep global
|
||||
// boolean flags for this condition which will
|
||||
// become true if any ruleset has such
|
||||
// rules. We'll call
|
||||
// MangleTableCompiler_ipt::flushAndSetDefaultPolicy
|
||||
// later if either of these flags is true after
|
||||
// all rulesets have been processed.
|
||||
|
||||
have_connmark |= mangle_compiler->haveConnMarkRules();
|
||||
have_connmark_in_output |= mangle_compiler->haveConnMarkRulesInOutput();
|
||||
|
||||
long m_str_pos = mangle_table_stream.tellp();
|
||||
|
||||
if (policy->isTop())
|
||||
{
|
||||
ostringstream tmp;
|
||||
|
||||
if (flush_and_set_default_policy)
|
||||
tmp << mangle_compiler->flushAndSetDefaultPolicy();
|
||||
|
||||
tmp << mangle_compiler->printAutomaticRules();
|
||||
|
||||
if (tmp.tellp() > 0)
|
||||
{
|
||||
if (!single_rule_compile_on)
|
||||
{
|
||||
mangle_table_stream << "# ================ Table 'mangle', ";
|
||||
mangle_table_stream << "automatic rules";
|
||||
mangle_table_stream << "\n";
|
||||
}
|
||||
mangle_table_stream << tmp.str();
|
||||
}
|
||||
}
|
||||
|
||||
if (mangle_compiler->getCompiledScriptLength() > 0)
|
||||
{
|
||||
ostringstream tmp;
|
||||
if (mangle_compiler->haveErrorsAndWarnings())
|
||||
{
|
||||
all_errors.push_back(mangle_compiler->getErrors("").c_str());
|
||||
// tmp << "# Policy compiler errors and warnings:" << "\n";
|
||||
// tmp << mangle_compiler->getErrors("# ");
|
||||
}
|
||||
|
||||
tmp << mangle_compiler->getCompiledScript();
|
||||
|
||||
if (tmp.tellp() > 0)
|
||||
{
|
||||
if (!single_rule_compile_on)
|
||||
{
|
||||
mangle_table_stream << "# ================ Table 'mangle', ";
|
||||
mangle_table_stream << "rule set " << branch_name << "\n";
|
||||
}
|
||||
mangle_table_stream << tmp.str();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_str_pos!=mangle_table_stream.tellp())
|
||||
{
|
||||
mangle_table_stream << "\n";
|
||||
empty_output = false;
|
||||
}
|
||||
}
|
||||
|
||||
std::auto_ptr<PolicyCompiler_ipt> policy_compiler;
|
||||
|
||||
if (fw->getStr("host_OS") == "secuwall") {
|
||||
policy_compiler = std::auto_ptr<PolicyCompiler_ipt>(
|
||||
new PolicyCompiler_secuwall(objdb,fw, ipv6_policy, oscnf,
|
||||
&minus_n_commands_filter));
|
||||
} else {
|
||||
policy_compiler = std::auto_ptr<PolicyCompiler_ipt>(
|
||||
new PolicyCompiler_ipt(objdb,fw, ipv6_policy, oscnf,
|
||||
&minus_n_commands_filter));
|
||||
}
|
||||
|
||||
if (policy_compiler.get()==NULL)
|
||||
throw FWException("Unrecognized firewall platform " +
|
||||
fw->getStr("platform") +
|
||||
" (family " + platform_family+")");
|
||||
|
||||
if (!policy->isTop())
|
||||
policy_compiler->registerRuleSetChain(branch_name);
|
||||
|
||||
policy_compiler->setSourceRuleSet( policy );
|
||||
policy_compiler->setRuleSetName(branch_name);
|
||||
|
||||
policy_compiler->setSingleRuleCompileMode(single_rule_id);
|
||||
policy_compiler->setDebugLevel( dl );
|
||||
if (rule_debug_on) policy_compiler->setDebugRule( drp );
|
||||
policy_compiler->setVerbose( (bool)(verbose) );
|
||||
policy_compiler->setHaveDynamicInterfaces(have_dynamic_interfaces);
|
||||
if (inTestMode()) policy_compiler->setTestMode();
|
||||
if (inEmbeddedMode()) policy_compiler->setEmbeddedMode();
|
||||
|
||||
if ( (policy_rules_count=policy_compiler->prolog()) > 0 )
|
||||
{
|
||||
policy_compiler->compile();
|
||||
policy_compiler->epilog();
|
||||
|
||||
if (policy_compiler->getCompiledScriptLength() > 0)
|
||||
{
|
||||
ostringstream tmp;
|
||||
|
||||
if (policy_compiler->haveErrorsAndWarnings())
|
||||
{
|
||||
all_errors.push_back(policy_compiler->getErrors("").c_str());
|
||||
// tmp << "# Policy compiler errors and warnings:" << "\n";
|
||||
// tmp << policy_compiler->getErrors("# ");
|
||||
}
|
||||
tmp << policy_compiler->getCompiledScript();
|
||||
|
||||
if (tmp.tellp() > 0)
|
||||
{
|
||||
empty_output = false;
|
||||
if (!single_rule_compile_on)
|
||||
{
|
||||
filter_table_stream << "# ================ Table 'filter', ";
|
||||
filter_table_stream << "rule set " << branch_name << "\n";
|
||||
}
|
||||
filter_table_stream << tmp.str();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* bug #2550074: "Automatic rules for filter table included twice
|
||||
* in iptables". If user had two policy ruleset objects marked as
|
||||
* "top" rule set, then automaitc rules were added twice. Since we
|
||||
* add rules to automatic_rules_stream only in this one place, it
|
||||
* is sufficient to check if the stream is empty to avoid
|
||||
* duplication. Note that on windows tellp() seems to return -1
|
||||
* if no data has ever been written to the stream.
|
||||
*/
|
||||
long auto_rules_stream_position = automatic_rules_stream.tellp();
|
||||
|
||||
if (policy->isTop() && auto_rules_stream_position <= 0)
|
||||
{
|
||||
ostringstream tmp;
|
||||
|
||||
if (flush_and_set_default_policy)
|
||||
tmp << policy_compiler->flushAndSetDefaultPolicy();
|
||||
|
||||
if (!prolog_done && prolog_place == "after_flush" &&
|
||||
!fw->getOptionsObject()->getBool("use_iptables_restore"))
|
||||
{
|
||||
tmp << "prolog_commands" << endl;
|
||||
prolog_done = true;
|
||||
}
|
||||
|
||||
tmp << policy_compiler->printAutomaticRules();
|
||||
|
||||
if (tmp.tellp() > 0)
|
||||
{
|
||||
empty_output = false;
|
||||
if (!single_rule_compile_on)
|
||||
{
|
||||
automatic_rules_stream
|
||||
<< "# ================ Table 'filter', automatic rules"
|
||||
<< "\n";
|
||||
}
|
||||
automatic_rules_stream << tmp.str();
|
||||
}
|
||||
}
|
||||
return empty_output;
|
||||
}
|
||||
@ -163,9 +163,6 @@ string CompilerDriver_ipt::run(const std::string &cluster_id,
|
||||
|
||||
string os_variant = DISTRO;
|
||||
|
||||
bool flush_and_set_default_policy = Resources::getTargetOptionBool(
|
||||
platform, "default/flush_and_set_default_policy");
|
||||
|
||||
/* minimal sanity checking */
|
||||
if (os_family == "ipcop")
|
||||
{
|
||||
@ -203,7 +200,6 @@ string CompilerDriver_ipt::run(const std::string &cluster_id,
|
||||
list<FWObject*> all_policies = fw->getByType(Policy::TYPENAME);
|
||||
list<FWObject*> all_nat = fw->getByType(NAT::TYPENAME);
|
||||
|
||||
int nat_rules_count = 0;
|
||||
int routing_rules_count = 0;
|
||||
bool have_nat = false;
|
||||
bool have_ipv6 = false;
|
||||
@ -223,6 +219,7 @@ string CompilerDriver_ipt::run(const std::string &cluster_id,
|
||||
|
||||
findImportedRuleSets(fw, all_policies);
|
||||
findBranchesInMangleTable(fw, all_policies);
|
||||
findImportedRuleSets(fw, all_nat);
|
||||
|
||||
// command line options -4 and -6 control address family for which
|
||||
// script will be generated. If "-4" is used, only ipv4 part will
|
||||
@ -297,78 +294,52 @@ string CompilerDriver_ipt::run(const std::string &cluster_id,
|
||||
ostringstream nat_rules_stream;
|
||||
|
||||
bool empty_output = true;
|
||||
//MangleTableCompiler_ipt *top_level_mangle_compiler = NULL;
|
||||
|
||||
// First, process branch NAT rulesets, then top NAT ruleset
|
||||
|
||||
NAT *top_nat = NULL;
|
||||
for (list<FWObject*>::iterator p=all_nat.begin();
|
||||
p!=all_nat.end(); ++p )
|
||||
p!=all_nat.end(); ++p)
|
||||
{
|
||||
NAT *nat = NAT::cast(*p);
|
||||
assignRuleSetChain(nat);
|
||||
string branch_name = nat->getName();
|
||||
|
||||
if (!nat->matchingAddressFamily(policy_af)) continue;
|
||||
|
||||
// compile NAT rules before policy rules because policy
|
||||
// compiler needs to know the number of virtual addresses
|
||||
// being created for NAT
|
||||
std::auto_ptr<NATCompiler_ipt> nat_compiler(
|
||||
new NATCompiler_ipt(objdb, fw, ipv6_policy,
|
||||
oscnf.get(), &minus_n_commands_nat));
|
||||
|
||||
nat_compiler->setSourceRuleSet( nat );
|
||||
nat_compiler->setRuleSetName(branch_name);
|
||||
|
||||
nat_compiler->setSingleRuleCompileMode(single_rule_id);
|
||||
nat_compiler->setDebugLevel( dl );
|
||||
if (rule_debug_on) nat_compiler->setDebugRule( drn );
|
||||
nat_compiler->setVerbose( (bool)(verbose) );
|
||||
nat_compiler->setHaveDynamicInterfaces(have_dynamic_interfaces);
|
||||
if (inTestMode()) nat_compiler->setTestMode();
|
||||
if (inEmbeddedMode()) nat_compiler->setEmbeddedMode();
|
||||
|
||||
if ( (nat_rules_count=nat_compiler->prolog()) > 0 )
|
||||
if (nat->isTop())
|
||||
{
|
||||
nat_compiler->compile();
|
||||
nat_compiler->epilog();
|
||||
}
|
||||
|
||||
have_nat = (have_nat || (nat_rules_count > 0));
|
||||
|
||||
if (nat_compiler->getCompiledScriptLength() > 0)
|
||||
{
|
||||
if (!single_rule_compile_on)
|
||||
nat_rules_stream << "# ================ Table 'nat', "
|
||||
<< " rule set "
|
||||
<< branch_name << "\n";
|
||||
|
||||
if (nat_compiler->haveErrorsAndWarnings())
|
||||
{
|
||||
all_errors.push_back(nat_compiler->getErrors("").c_str());
|
||||
|
||||
// nat_rules_stream << "# NAT compiler errors and "
|
||||
// << "warnings:\n";
|
||||
// nat_rules_stream << nat_compiler->getErrors("# ");
|
||||
}
|
||||
|
||||
if (nat->isTop())
|
||||
{
|
||||
if (flush_and_set_default_policy)
|
||||
nat_rules_stream << nat_compiler->flushAndSetDefaultPolicy();
|
||||
|
||||
nat_rules_stream << nat_compiler->printAutomaticRules();
|
||||
}
|
||||
|
||||
nat_rules_stream << nat_compiler->getCompiledScript();
|
||||
nat_rules_stream << "\n";
|
||||
empty_output = false;
|
||||
top_nat = nat;
|
||||
continue;
|
||||
}
|
||||
if (! processNatRuleSet(
|
||||
fw,
|
||||
nat,
|
||||
single_rule_id,
|
||||
nat_rules_stream,
|
||||
oscnf.get(),
|
||||
policy_af,
|
||||
minus_n_commands_nat)) empty_output = false;
|
||||
}
|
||||
|
||||
if (top_nat &&
|
||||
! processNatRuleSet(
|
||||
fw,
|
||||
top_nat,
|
||||
single_rule_id,
|
||||
nat_rules_stream,
|
||||
oscnf.get(),
|
||||
policy_af,
|
||||
minus_n_commands_nat)) empty_output = false;
|
||||
|
||||
Policy *top_policy = NULL;
|
||||
|
||||
for (list<FWObject*>::iterator p=all_policies.begin();
|
||||
p!=all_policies.end(); ++p )
|
||||
{
|
||||
Policy *policy = Policy::cast(*p);
|
||||
if (!policy->matchingAddressFamily(policy_af)) continue;
|
||||
if (policy->isTop())
|
||||
{
|
||||
top_policy = policy;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! processPolicyRuleSet(
|
||||
fw,
|
||||
@ -383,6 +354,21 @@ string CompilerDriver_ipt::run(const std::string &cluster_id,
|
||||
minus_n_commands_mangle)) empty_output = false;
|
||||
}
|
||||
|
||||
if (top_policy &&
|
||||
! processPolicyRuleSet(
|
||||
fw,
|
||||
top_policy,
|
||||
single_rule_id,
|
||||
filter_rules_stream,
|
||||
mangle_rules_stream,
|
||||
automaitc_rules_stream,
|
||||
oscnf.get(),
|
||||
policy_af,
|
||||
minus_n_commands_filter,
|
||||
minus_n_commands_mangle)) empty_output = false;
|
||||
|
||||
|
||||
|
||||
if (!empty_output && !single_rule_compile_on)
|
||||
{
|
||||
if (ipv6_policy)
|
||||
|
||||
@ -213,7 +213,8 @@ string NATCompiler_ipt::PrintRule::_printChainDirectionAndInterface(NATRule *rul
|
||||
|
||||
ostr << rule->getStr("ipt_chain") << " ";
|
||||
|
||||
switch (rule->getRuleType()) {
|
||||
switch (rule->getRuleType())
|
||||
{
|
||||
case NATRule::SNAT:
|
||||
if (!iface_name.empty()) ostr << "-o " << iface_name;
|
||||
break;
|
||||
@ -598,7 +599,9 @@ bool NATCompiler_ipt::PrintRule::processNext()
|
||||
|
||||
string chain = rule->getStr("ipt_chain");
|
||||
if (ipt_comp->chain_usage_counter[chain] == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
tmp_queue.push_back(rule);
|
||||
|
||||
@ -679,7 +682,8 @@ bool NATCompiler_ipt::PrintRule::processNext()
|
||||
|
||||
cmdout << "-j " << rule->getStr("ipt_target") << " ";
|
||||
|
||||
switch (rule->getRuleType()) {
|
||||
switch (rule->getRuleType())
|
||||
{
|
||||
case NATRule::SNAT:
|
||||
if (rule->getStr("ipt_target")=="SNAT")
|
||||
{
|
||||
@ -732,6 +736,10 @@ bool NATCompiler_ipt::PrintRule::processNext()
|
||||
if (!ports.empty()) cmdout << "--to-ports " << ports;
|
||||
}
|
||||
break;
|
||||
|
||||
case NATRule::NATBranch:
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
cmdout << " ";
|
||||
|
||||
@ -157,12 +157,11 @@ string NATCompiler_ipt::debugPrintRule(Rule *r)
|
||||
|
||||
return NATCompiler::debugPrintRule(rule)+
|
||||
" " + FWObjectDatabase::getStringId(rule->getInterfaceId()) +
|
||||
" " + rule->getStr("ipt_chain") +
|
||||
" " + rule->getStr("ipt_target") +
|
||||
" c=" + rule->getStr("ipt_chain") +
|
||||
" t=" + rule->getStr("ipt_target") +
|
||||
" (type="+rule->getRuleTypeAsString()+")";
|
||||
}
|
||||
|
||||
|
||||
void NATCompiler_ipt::verifyPlatform()
|
||||
{
|
||||
string family = Resources::platform_res[fw->getStr("platform")]->
|
||||
@ -480,7 +479,6 @@ bool NATCompiler_ipt::splitSDNATRule::processNext()
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool NATCompiler_ipt::VerifyRules::processNext()
|
||||
{
|
||||
NATRule *rule=getNext(); if (rule==NULL) return false;
|
||||
@ -526,6 +524,19 @@ bool NATCompiler_ipt::VerifyRules::processNext()
|
||||
rule,
|
||||
"Load balancing rules are not supported.");
|
||||
|
||||
if (rule->getRuleType()==NATRule::NATBranch )
|
||||
{
|
||||
RuleSet *branch = rule->getBranch();
|
||||
if (branch == NULL)
|
||||
compiler->abort(
|
||||
rule,
|
||||
"Action 'Branch' needs NAT rule set to point to");
|
||||
if (!NAT::isA(branch))
|
||||
compiler->abort(
|
||||
rule,
|
||||
"Action 'Branch' must point to a NAT rule set "
|
||||
"(points to " + branch->getTypeName() + ")");
|
||||
}
|
||||
|
||||
if (rule->getRuleType()==NATRule::SNAT )
|
||||
{
|
||||
@ -536,7 +547,6 @@ bool NATCompiler_ipt::VerifyRules::processNext()
|
||||
"Can not use network object in translated source.");
|
||||
}
|
||||
|
||||
|
||||
if (rule->getRuleType()==NATRule::SNetnat && !tsrc->isAny() )
|
||||
{
|
||||
Network *a1=Network::cast(compiler->getFirstOSrc(rule));
|
||||
@ -559,9 +569,6 @@ bool NATCompiler_ipt::VerifyRules::processNext()
|
||||
"Original and translated destination should both be networks of the same size .");
|
||||
}
|
||||
|
||||
// Service *osrv_obj = compiler->getFirstOSrv(rule);
|
||||
// Service *tsrv_obj = compiler->getFirstTSrv(rule);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1788,6 +1795,96 @@ bool NATCompiler_ipt::splitNONATRule::processNext()
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Branch rule in NAT rule sets should go into PREROUTING or
|
||||
* POSTROUTING chain depending on the target of the rules in the
|
||||
* branch. Iptables verifies this when a command that passes control
|
||||
* (the one with "-j <branch_ruleset_name>") is entered. If branch
|
||||
* ruleset has -j SNAT, the command that sends control to the branch
|
||||
* should be in POSTROUTING. Attempt to place it in PREROUTING ends
|
||||
* with an error "iptables: Invalid argument".
|
||||
*
|
||||
* Note that if branch rule set contains a mix of rules that use both
|
||||
* SNAT and DNAT targets, the branching rule (that should pass control
|
||||
* to the branch) can not be added to PREROUTING and POSTROUTING
|
||||
* chains, it just gives an error "iptables: Invalid argument" for both.
|
||||
* Tested with iptables 1.4.1.1 10/20/2009
|
||||
*/
|
||||
bool NATCompiler_ipt::splitNATBranchRule::processNext()
|
||||
{
|
||||
NATCompiler_ipt *ipt_comp = dynamic_cast<NATCompiler_ipt*>(compiler);
|
||||
NATRule *rule=getNext(); if (rule==NULL) return false;
|
||||
|
||||
if ( rule->getRuleType()==NATRule::NATBranch)
|
||||
{
|
||||
RuleSet *branch = rule->getBranch();
|
||||
if (branch)
|
||||
{
|
||||
string branch_name = branch->getName();
|
||||
if (ipt_comp->branch_ruleset_to_chain_mapping)
|
||||
{
|
||||
map<string, list<string> >::const_iterator lit =
|
||||
ipt_comp->branch_ruleset_to_chain_mapping->find(branch_name);
|
||||
if (lit!=ipt_comp->branch_ruleset_to_chain_mapping->end())
|
||||
{
|
||||
list<string> chains = lit->second;
|
||||
list<string>::iterator it;
|
||||
for (it=chains.begin(); it!=chains.end(); ++it)
|
||||
{
|
||||
string branch_chain = *it;
|
||||
// If chain in the branch rule set does not
|
||||
// start with its own name plus "_", skip it
|
||||
// because it is one of the standard chains
|
||||
if (branch_chain.find(branch_name + "_") == 0)
|
||||
{
|
||||
// branch chain is <branch_ruleset_name> + "_" + <chain>
|
||||
string my_chain = branch_chain.substr(branch_name.length()+1);
|
||||
NATRule *r = compiler->dbcopy->createNATRule();
|
||||
compiler->temp_ruleset->add(r);
|
||||
r->duplicate(rule);
|
||||
r->setStr("ipt_chain", my_chain);
|
||||
r->setStr("ipt_target", *it);
|
||||
tmp_queue.push_back(r);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} else
|
||||
{
|
||||
compiler->warning(rule,
|
||||
"NAT branching rule does not have information"
|
||||
" about targets used in the branch ruleset"
|
||||
" to choose proper chain in the nat table."
|
||||
" Will split the rule and place it in both"
|
||||
" PREROUTNING and POSTROUTING");
|
||||
NATRule *r = compiler->dbcopy->createNATRule();
|
||||
compiler->temp_ruleset->add(r);
|
||||
r->duplicate(rule);
|
||||
r->setStr("ipt_chain", "POSTROUTING");
|
||||
r->setStr("ipt_target", branch_name);
|
||||
tmp_queue.push_back(r);
|
||||
|
||||
r = compiler->dbcopy->createNATRule();
|
||||
compiler->temp_ruleset->add(r);
|
||||
r->duplicate(rule);
|
||||
r->setStr("ipt_chain", "PREROUTING");
|
||||
r->setStr("ipt_target", branch_name);
|
||||
tmp_queue.push_back(r);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
compiler->abort(rule,
|
||||
"NAT branching rule misses branch rule set.");
|
||||
// in case we are in the test mode and abort() does not really abort
|
||||
rule->setStr("ipt_target", "UNDEFINED");
|
||||
}
|
||||
} else
|
||||
tmp_queue.push_back(rule);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NATCompiler_ipt::localNATRule::processNext()
|
||||
{
|
||||
NATRule *rule=getNext(); if (rule==NULL) return false;
|
||||
@ -1894,24 +1991,45 @@ bool NATCompiler_ipt::DNATforFW::processNext()
|
||||
|
||||
bool NATCompiler_ipt::decideOnChain::processNext()
|
||||
{
|
||||
NATCompiler_ipt *ipt_comp = dynamic_cast<NATCompiler_ipt*>(compiler);
|
||||
NATRule *rule=getNext(); if (rule==NULL) return false;
|
||||
|
||||
tmp_queue.push_back(rule);
|
||||
|
||||
if ( ! rule->getStr("ipt_chain").empty() ) return true; // already defined
|
||||
|
||||
switch (rule->getRuleType()) {
|
||||
case NATRule::SNAT: rule->setStr("ipt_chain","POSTROUTING"); break;
|
||||
case NATRule::SNetnat: rule->setStr("ipt_chain","POSTROUTING"); break;
|
||||
case NATRule::Masq: rule->setStr("ipt_chain","POSTROUTING"); break;
|
||||
case NATRule::DNAT: rule->setStr("ipt_chain","PREROUTING"); break;
|
||||
case NATRule::DNetnat: rule->setStr("ipt_chain","PREROUTING"); break;
|
||||
case NATRule::Redirect: rule->setStr("ipt_chain","PREROUTING"); break;
|
||||
string chain;
|
||||
switch (rule->getRuleType())
|
||||
{
|
||||
case NATRule::SNAT: chain = "POSTROUTING"; break;
|
||||
case NATRule::SNetnat: chain = "POSTROUTING"; break;
|
||||
case NATRule::Masq: chain = "POSTROUTING"; break;
|
||||
case NATRule::DNAT: chain = "PREROUTING"; break;
|
||||
case NATRule::DNetnat: chain = "PREROUTING"; break;
|
||||
case NATRule::Redirect: chain = "PREROUTING"; break;
|
||||
case NATRule::NONAT:
|
||||
// processor splitNONATRule took care of NONAT rule
|
||||
break;
|
||||
case NATRule::NATBranch:
|
||||
// processor splitNATBranchRule took care of NATBranch rule
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
|
||||
if (!rule->getStr("ipt_chain").empty())
|
||||
{
|
||||
if (!compiler->getSourceRuleSet()->isTop() &&
|
||||
ipt_comp->getRuleSetName() == rule->getStr("ipt_chain"))
|
||||
{
|
||||
// this is a NAT branch. Need to rename the chain to add
|
||||
// information about the chain that would have been used
|
||||
// if this was top ruleset
|
||||
string new_chain = compiler->getRuleSetName() + "_" + chain;
|
||||
ipt_comp->registerRuleSetChain(new_chain);
|
||||
rule->setStr("ipt_chain", new_chain);
|
||||
}
|
||||
return true; // already defined
|
||||
}
|
||||
|
||||
if (!chain.empty()) rule->setStr("ipt_chain", chain);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1924,7 +2042,8 @@ bool NATCompiler_ipt::decideOnTarget::processNext()
|
||||
|
||||
if ( ! rule->getStr("ipt_target").empty() ) return true; // already defined
|
||||
|
||||
switch (rule->getRuleType()) {
|
||||
switch (rule->getRuleType())
|
||||
{
|
||||
case NATRule::NONAT: rule->setStr("ipt_target","ACCEPT"); break;
|
||||
case NATRule::SNAT: rule->setStr("ipt_target","SNAT"); break;
|
||||
case NATRule::SNetnat: rule->setStr("ipt_target","NETMAP"); break;
|
||||
@ -1933,6 +2052,9 @@ bool NATCompiler_ipt::decideOnTarget::processNext()
|
||||
case NATRule::Masq: rule->setStr("ipt_target","MASQUERADE"); break;
|
||||
case NATRule::Redirect: rule->setStr("ipt_target","REDIRECT"); break;
|
||||
case NATRule::Return: rule->setStr("ipt_target","RETURN"); break;
|
||||
case NATRule::NATBranch:
|
||||
// this case has been taken care for in splitNATBranchRule()
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
return true;
|
||||
@ -2210,18 +2332,20 @@ bool NATCompiler_ipt::countChainUsage::processNext()
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void NATCompiler_ipt::registerRuleSetChain(const std::string &chain_name)
|
||||
{
|
||||
chain_usage_counter[chain_name] = 1;
|
||||
}
|
||||
|
||||
void NATCompiler_ipt::compile()
|
||||
{
|
||||
// FWOptions* options=fw->getOptionsObject();
|
||||
|
||||
string banner = " Compiling rules for 'nat' table";
|
||||
string banner = " Compiling ruleset " + getRuleSetName() +
|
||||
" for 'nat' table";
|
||||
if (ipv6) banner += ", IPv6";
|
||||
info(banner);
|
||||
|
||||
try {
|
||||
|
||||
try
|
||||
{
|
||||
Compiler::compile();
|
||||
|
||||
add( new NATCompiler::Begin());
|
||||
@ -2322,6 +2446,7 @@ void NATCompiler_ipt::compile()
|
||||
}
|
||||
|
||||
add( new splitNONATRule("NAT rules that request no translation"));
|
||||
add( new splitNATBranchRule("Split Branch rules to use all chains"));
|
||||
add( new localNATRule("process local NAT rules"));
|
||||
// add( new DNATforFW("process DNAT rules for packets originated on the firewall"));
|
||||
add( new decideOnChain( "decide on chain" ) );
|
||||
@ -2448,4 +2573,12 @@ string NATCompiler_ipt::commit()
|
||||
return res;
|
||||
}
|
||||
|
||||
list<string> NATCompiler_ipt::getUsedChains()
|
||||
{
|
||||
list<string> res;
|
||||
for (map<string, int>::iterator it=chain_usage_counter.begin();
|
||||
it!=chain_usage_counter.end(); ++it)
|
||||
res.push_back(it->first);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@ -65,7 +65,10 @@ namespace fwcompiler {
|
||||
// new chains across different compiler runs (used to process
|
||||
// rules in different policy or nat objects)
|
||||
std::map<const std::string, bool> *minus_n_commands;
|
||||
|
||||
|
||||
// This map is located in CompilerDriver_ipt
|
||||
const std::map<std::string, std::list<std::string> > *branch_ruleset_to_chain_mapping;
|
||||
|
||||
static const std::list<std::string>& getStandardChains();
|
||||
std::string getInterfaceVarName(libfwbuilder::FWObject *iface,
|
||||
bool v6=false);
|
||||
@ -98,6 +101,12 @@ namespace fwcompiler {
|
||||
*/
|
||||
DECLARE_NAT_RULE_PROCESSOR(splitSDNATRule);
|
||||
|
||||
/**
|
||||
* this processor spits NAT rule with action Branch to
|
||||
* generate iptables commands in all chains that it needs
|
||||
*/
|
||||
DECLARE_NAT_RULE_PROCESSOR(splitNATBranchRule);
|
||||
|
||||
/**
|
||||
* verifies correctness of the NAT rules
|
||||
*/
|
||||
@ -583,8 +592,17 @@ namespace fwcompiler {
|
||||
have_dynamic_interfaces=false;
|
||||
printRule=NULL;
|
||||
minus_n_commands = m_n_commands_map;
|
||||
branch_ruleset_to_chain_mapping = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* this method registers chain used for the ruleset (most
|
||||
* often branch rule set). Since rules in the same ruleset do
|
||||
* not use this chain as target, rule processor
|
||||
* countChainUsage considers it unused. Registering it makes
|
||||
* sure its usage counter is > 0.
|
||||
*/
|
||||
void registerRuleSetChain(const std::string &chain_name);
|
||||
|
||||
virtual void verifyPlatform();
|
||||
virtual int prolog();
|
||||
@ -597,8 +615,13 @@ namespace fwcompiler {
|
||||
virtual std::string printAutomaticRules();
|
||||
std::string commit();
|
||||
|
||||
std::list<std::string> getUsedChains();
|
||||
|
||||
static std::string getNewTmpChainName(libfwbuilder::NATRule *rule);
|
||||
|
||||
void setRulesetToChainMapping(const std::map<std::string, std::list<std::string> > *m)
|
||||
{ branch_ruleset_to_chain_mapping = m; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -4908,4 +4908,13 @@ PolicyRule* PolicyCompiler_ipt::addMgmtRule(Address* src,
|
||||
return rule;
|
||||
}
|
||||
|
||||
list<string> PolicyCompiler_ipt::getUsedChains()
|
||||
{
|
||||
list<string> res;
|
||||
for (map<string, int>::iterator it=chain_usage_counter.begin();
|
||||
it!=chain_usage_counter.end(); ++it)
|
||||
res.push_back(it->first);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1073,6 +1073,9 @@ namespace fwcompiler
|
||||
bool haveConnMarkRulesInOutput() { return have_connmark_in_output; }
|
||||
|
||||
bool isMangleOnlyRuleSet(const std::string &rule_set_name);
|
||||
|
||||
std::list<std::string> getUsedChains();
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -8,6 +8,8 @@ TEMPLATE = lib
|
||||
SOURCES = CompilerDriver_ipt.cpp \
|
||||
CompilerDriver_ipt_cluster.cpp \
|
||||
CompilerDriver_ipt_run.cpp \
|
||||
CompilerDriver_ipt_policy.cpp \
|
||||
CompilerDriver_ipt_nat.cpp \
|
||||
MangleTableCompiler_ipt.cpp \
|
||||
NATCompiler_PrintRule.cpp \
|
||||
NATCompiler_PrintRuleIptRst.cpp \
|
||||
|
||||
@ -179,6 +179,10 @@ nameif %in %il security%sl
|
||||
<supported>True</supported>
|
||||
<parameter>None</parameter>
|
||||
</Translate>
|
||||
<NATBranch>
|
||||
<supported>False</supported>
|
||||
<parameter>None</parameter>
|
||||
</NATBranch>
|
||||
</actions>
|
||||
</capabilities>
|
||||
|
||||
|
||||
@ -102,6 +102,10 @@ interface %in
|
||||
<supported>False</supported>
|
||||
<parameter>None</parameter>
|
||||
</Translate>
|
||||
<NATBranch>
|
||||
<supported>False</supported>
|
||||
<parameter>None</parameter>
|
||||
</NATBranch>
|
||||
</actions>
|
||||
</capabilities>
|
||||
|
||||
|
||||
@ -83,6 +83,10 @@
|
||||
<supported>True</supported>
|
||||
<parameter>None</parameter>
|
||||
</Translate>
|
||||
<NATBranch>
|
||||
<supported>False</supported>
|
||||
<parameter>None</parameter>
|
||||
</NATBranch>
|
||||
</actions>
|
||||
</capabilities>
|
||||
</Target>
|
||||
|
||||
@ -81,6 +81,10 @@
|
||||
<supported>False</supported>
|
||||
<parameter>None</parameter>
|
||||
</Translate>
|
||||
<NATBranch>
|
||||
<supported>False</supported>
|
||||
<parameter>None</parameter>
|
||||
</NATBranch>
|
||||
</actions>
|
||||
</capabilities>
|
||||
</Target>
|
||||
|
||||
@ -96,6 +96,10 @@
|
||||
<supported>True</supported>
|
||||
<parameter>None</parameter>
|
||||
</Translate>
|
||||
<NATBranch>
|
||||
<supported>True</supported>
|
||||
<parameter>NATBranch</parameter>
|
||||
</NATBranch>
|
||||
</actions>
|
||||
</capabilities>
|
||||
</Target>
|
||||
|
||||
@ -86,6 +86,10 @@
|
||||
<supported>True</supported>
|
||||
<parameter>None</parameter>
|
||||
</Translate>
|
||||
<NATBranch>
|
||||
<supported>True</supported>
|
||||
<parameter>NATBranch</parameter>
|
||||
</NATBranch>
|
||||
</actions>
|
||||
</capabilities>
|
||||
</Target>
|
||||
|
||||
@ -450,6 +450,10 @@ exit
|
||||
<supported>True</supported>
|
||||
<parameter>None</parameter>
|
||||
</Translate>
|
||||
<NATBranch>
|
||||
<supported>False</supported>
|
||||
<parameter>None</parameter>
|
||||
</NATBranch>
|
||||
</actions>
|
||||
</capabilities>
|
||||
</Target>
|
||||
|
||||
@ -73,6 +73,10 @@
|
||||
<supported>False</supported>
|
||||
<parameter>None</parameter>
|
||||
</Translate>
|
||||
<NATBranch>
|
||||
<supported>False</supported>
|
||||
<parameter>None</parameter>
|
||||
</NATBranch>
|
||||
</actions>
|
||||
</capabilities>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user