support for configuring static routes on BSD". Implemented support
for simple static routing rules. ECMP and routing via interface
(routing to directly reachable subnets) are not
supported. Generated script preserves static routing entries that
existed before and attempts to recover in case of error. Needs
testing.
This commit is contained in:
Vadim Kurland
2011-01-31 18:29:20 -08:00
parent bffebde77c
commit dd86fcc5e2
41 changed files with 1567 additions and 473 deletions
+10
View File
@@ -1,3 +1,13 @@
2011-01-31 Vadim Kurland <vadim@netcitadel.com>
* RoutingCompiler_bsd_writers.cpp (_printAddr): see #1890 "Add
support for configuring static routes on BSD". Implemented support
for simple static routing rules. ECMP and routing via interface
(routing to directly reachable subnets) are not
supported. Generated script preserves static routing entries that
existed before and attempts to recover in case of error. Needs
testing.
2011-01-30 vadim <vadim@netcitadel.com>
* FWWindow_editor.cpp (clearEditorAndSearchPanels): see #2006
@@ -501,7 +501,24 @@ bool RoutingCompiler::contradictionRGtwAndRItf::processNext()
}
return true;
}
bool RoutingCompiler::interfaceOrGateway::processNext()
{
RoutingRule *rule = getNext(); if (rule==NULL) return false;
tmp_queue.push_back(rule);
RuleElementRItf *itfrel = rule->getRItf();
RuleElementRGtw *gtwrel = rule->getRGtw();
if (!itfrel->isAny() && !gtwrel->isAny())
{
compiler->abort(rule,
"Use either gateway or interface in a routing rule "
"but not both at the same time");
}
return true;
}
bool RoutingCompiler::rItfChildOfFw::processNext()
@@ -527,7 +544,8 @@ bool RoutingCompiler::rItfChildOfFw::processNext()
{
list<Firewall*> members;
cluster->getMembersList(members);
if (std::find(members.begin(), members.end(), compiler->fw) != members.end())
if (std::find(members.begin(), members.end(),
compiler->fw) != members.end())
return true;
}
}
@@ -542,6 +560,55 @@ bool RoutingCompiler::rItfChildOfFw::processNext()
return true;
}
/*
* Call this after converting to atomic rules by DST to be sure there
* is just one object in DST.
*/
bool RoutingCompiler::sameDestinationDifferentGateways::processNext()
{
slurp();
if (tmp_queue.size()==0) return false;
// map destination to gateway.
std::map<string, string> dst_to_gw;
std::map<string, string> dst_to_rule;
for (deque<Rule*>::iterator k=tmp_queue.begin(); k!=tmp_queue.end(); ++k)
{
RoutingRule *rule = RoutingRule::cast( *k );
RuleElementRDst *dstrel = rule->getRDst();
Address *dst = Address::cast(FWReference::getObject(dstrel->front()));
const InetAddr* dst_addr = dst->getAddressPtr();
const InetAddr* dst_netm = dst->getNetmaskPtr();
string key = dst_addr->toString() + "/" + dst_netm->toString();
RuleElementRItf *itfrel = rule->getRItf();
FWObject *itf = FWReference::cast(itfrel->front())->getPointer();
RuleElementRGtw *gtwrel = rule->getRGtw();
Address *gtw = Address::cast(FWReference::getObject(gtwrel->front()));
const InetAddr* gtw_addr = gtw->getAddressPtr();
const InetAddr* gtw_netm = gtw->getNetmaskPtr();
string val = gtw_addr->toString() + "/" + gtw_netm->toString();
if (!dst_to_gw[key].empty() && dst_to_gw[key] != val)
{
compiler->abort(
rule,
"Rules " + dst_to_rule[key] + " and " + rule->getLabel() +
" define routes to the same destination " + key +
" via different gateways. This configuration is not supported"
" for " + compiler->fw->getStr("host_OS"));
} else
{
dst_to_gw[key] = val;
dst_to_rule[key] = rule->getLabel();
}
}
return true;
}
bool RoutingCompiler::competingRules::processNext()
{
@@ -611,10 +678,16 @@ bool RoutingCompiler::competingRules::processNext()
if(false)
{
// TODO_lowPrio: if ( !compiler->fw->getOptionsObject()->getBool ("equal_cost_multi_path") ) ...If multipath is turned off, perform this check.
// iterate all gtwitf combis in the map dest_it->second and search for the current metric
// TODO_lowPrio: if (
// !compiler->fw->getOptionsObject()->getBool
// ("equal_cost_multi_path") ) ...If multipath is
// turned off, perform this check.
// iterate all gtwitf combis in the map
// dest_it->second and search for the current metric
// ... but has the same metric => what route should I use for this destination? => abort
// ... but has the same metric => what route should I
// use for this destination? => abort
string msg;
msg = "Routing rules " + gtwitf_it->second.second + " and " +
@@ -625,14 +698,14 @@ bool RoutingCompiler::competingRules::processNext()
"enable ECMP (Equal Cost MultiPath) routing";
compiler->abort( msg.c_str() );
} else {
} else
{
// ... and different metric OR equal_cost_multi_path enabled => OK
tmp_queue.push_back(rule);
}
dest_it->second[combiId] = pair< string, string>( metric, rule->getLabel());
dest_it->second[combiId] =
pair< string, string>( metric, rule->getLabel());
}
} else {
@@ -140,6 +140,19 @@ namespace fwcompiler {
*/
DECLARE_ROUTING_RULE_PROCESSOR(rItfChildOfFw);
/**
* some OS (e.g. BSD) allow me to set up static route via
* gateway or via interface, but not both in one rule.
*/
DECLARE_ROUTING_RULE_PROCESSOR(interfaceOrGateway);
/**
* for OS where we do not support ECMP, detect rules that
* define routes for the same destination via different
* gateways and abort.
*/
DECLARE_ROUTING_RULE_PROCESSOR(sameDestinationDifferentGateways);
/**
* checks for competing rules
*/
+9 -4
View File
@@ -1554,13 +1554,16 @@ void RoutingModel::configure()
{
//if (fwbdebug) qDebug() << "RoutingModel::configure";
supports_routing_itf = false;
supports_metric = false;
if (getFirewall())
{
try {
supports_routing_itf =
Resources::getTargetCapabilityBool(
getFirewall()->getStr("platform"), "supports_routing_itf");
getFirewall()->getStr("host_OS"), "supports_routing_itf");
supports_metric = Resources::getTargetCapabilityBool(
getFirewall()->getStr("host_OS"), "supports_metric");
} catch(FWException &ex) { }
}
@@ -1570,9 +1573,11 @@ void RoutingModel::configure()
if (supports_routing_itf)
header << ColDesc(RuleElementRItf::TYPENAME, ColDesc::Object);
header << ColDesc("Metric", ColDesc::Metric)
<< ColDesc("Options", ColDesc::Options)
<< ColDesc("Comment", ColDesc::Comment);
if (supports_metric)
header << ColDesc("Metric", ColDesc::Metric);
header << ColDesc("Options", ColDesc::Options)
<< ColDesc("Comment", ColDesc::Comment);
}
QVariant RoutingModel::getRuleDataForDisplayRole(const QModelIndex &index, RuleNode* node) const
+13 -12
View File
@@ -45,9 +45,9 @@ namespace libfwbuilder
class RuleSetModel;
//////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// RuleSetModelIterator
//////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
class RuleSetModelIterator
{
@@ -76,9 +76,9 @@ private:
QModelIndex parent;
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// ActionDesc
//////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
class ActionDesc
{
@@ -91,9 +91,9 @@ class ActionDesc
Q_DECLARE_METATYPE(ActionDesc)
//////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// RuleSetModel
//////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
class RuleSetModel : public QAbstractItemModel
{
@@ -208,9 +208,9 @@ private:
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// PolicyModel
//////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
class PolicyModel : public RuleSetModel
{
@@ -232,9 +232,9 @@ private:
void configure();
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// NatModel
//////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
class NatModel : public RuleSetModel
{
@@ -252,9 +252,9 @@ private:
void configure();
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// RoutingModel
//////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
class RoutingModel : public RuleSetModel
{
@@ -266,6 +266,7 @@ public:
private:
bool supports_routing_itf;
bool supports_metric;
QVariant getRuleDataForDisplayRole(const QModelIndex &index, RuleNode* node) const;
QStringList getRuleOptions(libfwbuilder::Rule* r) const;
+4 -1
View File
@@ -68,7 +68,8 @@ class MapTableFactory : public std::map<std::string, fwcompiler::TableFactory*>
namespace fwcompiler {
class CompilerDriver_pf : public CompilerDriver {
class CompilerDriver_pf : public CompilerDriver
{
// Note that in the following maps ruleset name will be
// "__main__" for both main Policy and NAT rulesets.
@@ -100,6 +101,8 @@ namespace fwcompiler {
const std::string &remote_file_name);
protected:
std::string routing_script;
std::string getConfFileName(const std::string &ruleset_name,
const std::string &fwobjectname,
+42 -3
View File
@@ -43,6 +43,7 @@
#include "NATCompiler_pf.h"
#include "TableFactory.h"
#include "Preprocessor_pf.h"
#include "RoutingCompiler_bsd.h"
#include "OSConfigurator_openbsd.h"
#include "OSConfigurator_freebsd.h"
@@ -56,6 +57,7 @@
#include "fwbuilder/Interface.h"
#include "fwbuilder/Policy.h"
#include "fwbuilder/NAT.h"
#include "fwbuilder/Routing.h"
#include "fwcompiler/Preprocessor.h"
#include "fwcompiler/exceptions.h"
@@ -172,14 +174,19 @@ QString CompilerDriver_pf::assembleFwScript(Cluster *cluster,
Configlet script_skeleton(fw, "pf", "script_skeleton");
Configlet top_comment(fw, "pf", "top_comment");
script_skeleton.setVariable("routing_script",
QString::fromUtf8(routing_script.c_str()));
assembleFwScriptInternal(
cluster, fw, cluster_member, oscnf, &script_skeleton, &top_comment, "#");
if (fw->getStr("platform") == "pf")
{
script_skeleton.setVariable("pf_flush_states", options->getBool("pf_flush_states"));
script_skeleton.setVariable("pf_version_ge_4_x", // fw->getStr("version")=="4.x");
XMLTools::version_compare(fw->getStr("version"), "4.0")>=0);
script_skeleton.setVariable(
"pf_flush_states", options->getBool("pf_flush_states"));
script_skeleton.setVariable(
"pf_version_ge_4_x", // fw->getStr("version")=="4.x");
XMLTools::version_compare(fw->getStr("version"), "4.0")>=0);
} else
{
@@ -268,6 +275,8 @@ QString CompilerDriver_pf::run(const std::string &cluster_id,
list<FWObject*> all_policies = fw->getByType(Policy::TYPENAME);
list<FWObject*> all_nat = fw->getByType(NAT::TYPENAME);
int routing_rules_count = 0;
findImportedRuleSets(fw, all_policies);
findImportedRuleSets(fw, all_nat);
@@ -511,6 +520,35 @@ QString CompilerDriver_pf::run(const std::string &cluster_id,
}
}
std::auto_ptr<RoutingCompiler_bsd> routing_compiler(
new RoutingCompiler_bsd(objdb, fw, false, oscnf.get()));
RuleSet *routing = RuleSet::cast(fw->getFirstByType(Routing::TYPENAME));
if (routing)
{
routing_compiler->setSourceRuleSet(routing);
routing_compiler->setRuleSetName(routing->getName());
routing_compiler->setSingleRuleCompileMode(single_rule_id);
routing_compiler->setDebugLevel( dl );
if (rule_debug_on) routing_compiler->setDebugRule(drp);
routing_compiler->setVerbose( verbose );
if (inTestMode()) routing_compiler->setTestMode();
if (inEmbeddedMode()) routing_compiler->setEmbeddedMode();
if ( (routing_rules_count=routing_compiler->prolog()) > 0 )
{
routing_compiler->compile();
routing_compiler->epilog();
}
if (routing_compiler->haveErrorsAndWarnings())
all_errors.push_back(routing_compiler->getErrors("").c_str());
routing_script += routing_compiler->getCompiledScript();
}
if (haveErrorsAndWarnings())
{
all_errors.push_front(getErrors("").c_str());
@@ -529,6 +567,7 @@ QString CompilerDriver_pf::run(const std::string &cluster_id,
ostringstream *strm = fi->second;
pf_str << table_factories[ruleset_name]->PrintTables();
pf_str << QString::fromUtf8(strm->str().c_str());
pf_str << QString::fromUtf8(routing_script.c_str());
}
// clear() calls destructors of all elements in the container
+232
View File
@@ -0,0 +1,232 @@
/*
Firewall Builder
Copyright (C) 2011 NetCitadel, LLC
Author: Vadim Kurland vadim@fwbuilder.org
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 "RoutingCompiler_bsd.h"
#include "fwbuilder/Resources.h"
#include "fwbuilder/FWObjectDatabase.h"
#include "fwbuilder/RuleElement.h"
#include "fwbuilder/Routing.h"
#include "fwbuilder/Interface.h"
#include "fwbuilder/IPv4.h"
#include "fwbuilder/Firewall.h"
#include "fwbuilder/Network.h"
#include <stack>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <string>
#include <assert.h>
#include <QStringList>
using namespace libfwbuilder;
using namespace fwcompiler;
using namespace std;
static std::map<std::string,int> tmp_chain_no;
string RoutingCompiler_bsd::myPlatformName() { return "pf"; }
void RoutingCompiler_bsd::verifyOS()
{
QStringList supported_os = QString(
Resources::platform_res[fw->getStr("platform")]->
getResourceStr("/FWBuilderResources/Target/supported_os").c_str())
.split(",");
QString host_os = fw->getStr("host_OS").c_str();
if (!supported_os.contains(host_os))
abort("Unsupported host OS " + host_os.toStdString());
}
int RoutingCompiler_bsd::prolog()
{
int n = RoutingCompiler::prolog();
verifyOS();
return n;
}
bool RoutingCompiler_bsd::addressRangesInDst::processNext()
{
RoutingRule *rule;
rule=getNext(); if (rule==NULL) return false;
RuleElementRDst *dstrel = rule->getRDst();
compiler->_expandAddressRanges(rule, dstrel);
tmp_queue.push_back(rule);
return true;
}
bool RoutingCompiler_bsd::FindDefaultRoute::processNext()
{
RoutingCompiler_bsd *bsd_comp = dynamic_cast<RoutingCompiler_bsd*>(compiler);
RoutingRule *rule;
rule=getNext(); if (rule==NULL) return false;
RuleElementRDst *dstrel = rule->getRDst();
FWObject *ref = dstrel->front();
Address *dst = Address::cast(FWReference::cast(ref)->getPointer());
if (dst->isAny()) bsd_comp->have_default_route = true;
tmp_queue.push_back(rule);
return true;
}
/**
*-----------------------------------------------------------------------
*/
void RoutingCompiler_bsd::compile()
{
string banner = " Compiling routing rules for " + fw->getName();
info(banner);
Compiler::compile();
//bool check_for_recursive_groups=true;
add(new RoutingCompiler::Begin());
add(new printTotalNumberOfRules());
add( new singleRuleFilter());
add(new recursiveGroupsInRDst("Check for recursive Groups in RDst"));
add(new emptyGroupsInRDst("Check for empty Groups in RDst"));
add(new emptyRDstAndRItf("Check if RDst and RItf are both empty"));
add(new singleAdressInRGtw(
"Check if RGtw object has exactly one IP adress"));
add(new rItfChildOfFw("Check if RItf is an Iterface of this firewall"));
add(new interfaceOrGateway(
"Check that the rule has either gw or interface but not both"));
add(new validateNetwork("Validate network addresses"));
add(new reachableAddressInRGtw(
"Check if RGtw is reachable via local networks"));
add(new contradictionRGtwAndRItf(
"Check if RGtw is in a network of RItf"));
add(new ExpandGroups("Expand groups in DST"));
add(new ExpandMultipleAddresses(
"Expand objects with multiple addresses in DST"));
add(new addressRangesInDst("process address ranges"));
//add(new eliminateDuplicatesInDST("Eliminate duplicates in DST"));
add(new FindDefaultRoute("Find rules that install default route"));
#ifdef ECMP_SUPPORT_OLD_STYLE
add(new createSortedDstIdsLabel(
"Create label with a sorted dst-id-list for 'competingRules'"));
add(new competingRules("Check for competing rules"));
#endif
add(new ConvertToAtomicForDST(
"Convert to atomic rules by dst address elements"));
add(new sameDestinationDifferentGateways(
"detect rules with the same destination but different gateways. We do not "
"support ECMP at this time"));
// add(new createSortedDstIdsLabel(
// "Create label with a sorted dst-id-list for 'classifyRoutingRules'"));
// add(new classifyRoutingRules(
// "Classify into single path or part of a multi path rule"));
#ifdef ECMP_SUPPORT_OLD_STYLE
add(new optimize3(
"Eliminate duplicate rules generated from a single gui-rule"));
add(new eliminateDuplicateRules(
"Eliminate duplicate rules over the whole table"));
#endif
add( new checkForObjectsWithErrors(
"check if we have objects with errors in rule elements"));
add(new PrintRule("generate ip code"));
add(new simplePrintProgress());
runRuleProcessors();
}
string RoutingCompiler_bsd::debugPrintRule(Rule *r)
{
RoutingRule *rule=RoutingRule::cast(r);
string s= RoutingCompiler::debugPrintRule(rule);
return s;
}
void RoutingCompiler_bsd::epilog()
{
///int total = ecmp_comments_buffer.size();
int nb = 0;
// ecmp roules can only be generated after all the rules have been
// parsed, that is the reason for putting this code in the epilog
// function
if (ecmp_rules_buffer.size() > 0)
{
output << "\n#\n# ============== EQUAL COST MULTI PATH ============\n#"
<< endl;
output << "echo \"Activating ecmp routing rules...\"" << endl;
for (map<string,string>::iterator
ecmp_comments_buffer_it = ecmp_comments_buffer.begin();
ecmp_comments_buffer_it != ecmp_comments_buffer.end();
++ecmp_comments_buffer_it)
{
output << ecmp_comments_buffer_it->second << "#\n" << flush;
output << ecmp_rules_buffer[ecmp_comments_buffer_it->first] << flush;
output << " \\\n|| route_command_error " << "\"" << ++nb << "\"" << endl;
//echo \"Error: The ECMP routing rule #" << ++nb <<" couldn't be activated! Please make sure your kernel is compiled with the CONFIG_IP_ROUTE_MULTIPATH option.\"" << endl;
}
}
if (!inSingleRuleCompileMode() && defined_restore_script_output)
{
// function restore_script_output may not be defined if we
// have no rules or all rules are disabled
output << endl;
output << "restore_script_output" << endl;
output << "echo \"...done.\"" << endl;
}
}
+133
View File
@@ -0,0 +1,133 @@
/*
Firewall Builder
Copyright (C) 2011 NetCitadel, LLC
Author: Vadim Kurland vadim@fwbuilder.org
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
*/
#ifndef __ROUTINGCOMPILER_BSD_HH__
#define __ROUTINGCOMPILER_BSD_HH__
#include <fwbuilder/libfwbuilder-config.h>
#include "fwcompiler/RoutingCompiler.h"
#include "fwbuilder/RuleElement.h"
#include "config.h"
namespace libfwbuilder {
class RuleElementRDst;
class RuleElementRItf;
class RuleElementRGtw;
};
namespace fwcompiler
{
class RoutingCompiler_bsd : public RoutingCompiler
{
protected:
/**
* prints rule in some universal format (close to that visible
* to user in the GUI). Used for debugging purposes. This method
* calls RoutingCompiler::debugPrintRule
*/
virtual std::string debugPrintRule(libfwbuilder::Rule *rule);
/**
* expand address range objects in destination
*/
DECLARE_ROUTING_RULE_PROCESSOR(addressRangesInDst);
/**
* check if we have to install default route
*/
DECLARE_ROUTING_RULE_PROCESSOR(FindDefaultRoute);
/**
* prints single policy rule, assuming all groups have been
* expanded, destination holds exactly one object, and this
* object is not a group. Negation should also have been taken
* care of before this method is called.
*
* This processor is not necessarily the last in the
* conveyor, so it should push rules back to tmp_queue (for
* example there could be progress indicator processor after
* this one)
*/
class PrintRule : public RoutingRuleProcessor
{
bool print_once_on_top;
std::string current_rule_label;
virtual std::string _printAddr(libfwbuilder::Address *o);
public:
PrintRule(const std::string &name);
virtual bool processNext();
std::string RoutingRuleToString(libfwbuilder::RoutingRule *r);
std::string _printRGtw(libfwbuilder::RoutingRule *r);
std::string _printRItf(libfwbuilder::RoutingRule *r);
std::string _printRDst(libfwbuilder::RoutingRule *r);
};
friend class RoutingCompiler_bsd::PrintRule;
virtual std::string myPlatformName();
// These buffers are needed to collect output generated from
// the single ECMP rules belonging to one destination,
// because all these routes have to be activated with a single
// ip command. So ECMP ip commands are built up gradually
// during compilation and inserted in the shell script after
// all rules are processed.
std::map< std::string, std::string> ecmp_rules_buffer; // sortedDstId+metric-->nexthops
std::map< std::string, std::string> ecmp_comments_buffer; // sortedDstId+metric-->rule's info for the fw script
bool have_default_route;
bool defined_restore_script_output;
public:
RoutingCompiler_bsd(libfwbuilder::FWObjectDatabase *_db,
libfwbuilder::Firewall *fw, bool ipv6_policy,
fwcompiler::OSConfigurator *_oscnf) :
RoutingCompiler(_db, fw, ipv6_policy, _oscnf)
{
have_default_route = false;
defined_restore_script_output = false;
}
virtual void verifyOS();
virtual int prolog();
virtual void compile();
virtual void epilog();
};
}
#endif
+291
View File
@@ -0,0 +1,291 @@
/*
Firewall Builder
Copyright (C) 2011 NetCitadel, LLC
Author: Vadim Kurland vadim@fwbuilder.org
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 "RoutingCompiler_bsd.h"
#include "Configlet.h"
#include "fwbuilder/RuleElement.h"
#include "fwbuilder/Routing.h"
#include "fwbuilder/Network.h"
#include "fwbuilder/FWObjectDatabase.h"
#include "fwbuilder/RuleElement.h"
#include "fwbuilder/Routing.h"
#include "fwbuilder/Interface.h"
#include "fwbuilder/IPv4.h"
#include "fwbuilder/Firewall.h"
#include "fwbuilder/FWOptions.h"
#include "fwbuilder/Resources.h"
#include <QStringList>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <assert.h>
using namespace libfwbuilder;
using namespace fwcompiler;
using namespace std;
/**
*-----------------------------------------------------------------------
* Methods for printing
*/
string RoutingCompiler_bsd::PrintRule::_printAddr(Address *o)
{
ostringstream ostr;
if (Interface::cast(o)!=NULL)
{
Interface *iface = Interface::cast(o);
if (iface->isDyn())
ostr << "$interface_" << iface->getName() << " ";
return ostr.str();
}
const InetAddr *addr;
const InetAddr *mask;
addr = o->getAddressPtr();
mask = o->getNetmaskPtr();
if (addr==NULL)
{
FWObject *obj=o;
/*
* check if this is object of class Address. since we want to
* distinguish between Host, Interface and Address, and both Host and
* Interface are inherited from Address, we can't use cast. Use isA
* instead
*/
while (obj!=NULL &&
!Host::isA(obj) &&
!Firewall::isA(obj) &&
!Network::isA(obj)) obj=obj->getParent();
compiler->abort(
"Problem with address or netmask in the object or "
"one of its interfaces: '" + obj->getName() + "'");
}
if (addr->isAny() && mask->isAny())
{
ostr << "default ";
} else
{
ostr << addr->toString();
if (Interface::cast(o)==NULL &&
Address::cast(o)->dimension() > 1 &&
!mask->isHostMask())
{
ostr << "/" << mask->getLength();
}
ostr << " ";
}
return ostr.str();
}
RoutingCompiler_bsd::PrintRule::PrintRule(const std::string &name) :
RoutingRuleProcessor(name)
{
print_once_on_top = true;
}
bool RoutingCompiler_bsd::PrintRule::processNext()
{
RoutingCompiler_bsd *bsd_comp =
dynamic_cast<RoutingCompiler_bsd*>(compiler);
RoutingRule *rule = getNext();
if (rule==NULL) return false;
tmp_queue.push_back(rule);
if (print_once_on_top && !compiler->inSingleRuleCompileMode())
{
Configlet routing_functions(compiler->fw,
"bsd", "routing_functions");
// we should delete default route if we have a new one to
// install. IF user did not define any routes that look like
// default (i.e. where destination is "any"), then we should
// preserve default so that we won't leave machine with no
// default at all.
QString route_pattern = "";
if (bsd_comp->have_default_route)
{
// If we will install default route, delete it now
route_pattern = "'lo0'";
} else
{
// do not delete default if we won't install new one
route_pattern = "'lo0|default'";
}
routing_functions.setVariable("route_filter", route_pattern);
compiler->output << routing_functions.expand().toStdString();
bsd_comp->defined_restore_script_output = true;
print_once_on_top = false;
}
// TODO: convert this into virtual function RoutingCompiler::printComment()
string rl = rule->getLabel();
if (!compiler->inSingleRuleCompileMode() && rl!=current_rule_label)
{
compiler->output << "# " << endl;
compiler->output << "# Rule " << rl << endl;
//compiler->output << "# " << rule->getRuleTypeAsString() << endl;
compiler->output << "# " << endl;
compiler->output << "echo \"Routing rule " << rl << "\"" << endl;
compiler->output << "# " << endl;
}
if (rule->getRuleType() != RoutingRule::MultiPath )
{
if (!compiler->inSingleRuleCompileMode() && rl!=current_rule_label)
{
QStringList comment = QString::fromUtf8(
rule->getComment().c_str()).split("\n");
int comment_lines = 0;
foreach (QString str, comment)
{
if (!str.isEmpty())
{
compiler->output << "# " << str.toUtf8().data() << endl;
++comment_lines;
}
}
if (comment_lines) compiler->output << "#" << endl;
current_rule_label = rl;
}
string err = rule->getStr(".error_msg");
if (!err.empty()) compiler->output << "# " << err << endl;
string command_line = RoutingRuleToString(rule);
compiler->output << command_line;
}
return true;
}
string RoutingCompiler_bsd::PrintRule::RoutingRuleToString(RoutingRule *rule)
{
RuleElementRDst *dstrel = rule->getRDst();
Address *dst = Address::cast(FWReference::getObject(dstrel->front()));
RuleElementRItf *itfrel = rule->getRItf();
Interface *itf = Interface::cast(FWReference::getObject(itfrel->front()));
RuleElementRGtw *gtwrel = rule->getRGtw();
Address *gtw = Address::cast(FWReference::getObject(gtwrel->front()));
if(dst==NULL) compiler->abort(rule, "Broken DST");
ostringstream command_line;
command_line << "route add ";
if (gtwrel->isAny() && itf != NULL) command_line << "-interface ";
command_line << _printRDst(rule);
if (gtw != NULL) command_line << _printRGtw(rule);
if (itf != NULL) command_line << _printRItf(rule);
// to make generated script more readable in single rule compile mode,
// skip the part that rolls back in case of an error
if (!compiler->inSingleRuleCompileMode())
{
command_line << "|| ";
FWObject *opt_dummy =
rule->getFirstByType(RoutingRuleOptions::TYPENAME);
RoutingRuleOptions *opt =
opt_dummy ? RoutingRuleOptions::cast(opt_dummy) : 0;
if ( opt && opt->getBool("no_fail") )
{
command_line << "echo \"*** Warning: routing rule "
<< rule->getLabel() << " failed. ignored. ***\"\n";
} else
{
command_line << "route_command_error "
<< "\"" << rule->getLabel() << "\"" << endl;;
}
}
command_line << endl;
return command_line.str();
}
string RoutingCompiler_bsd::PrintRule::_printRGtw(RoutingRule *rule)
{
RuleElementRGtw *gtwrel = rule->getRGtw();
Address *gtw = Address::cast(FWReference::getObject(gtwrel->front()));
if(gtw==NULL)
compiler->abort(rule, "Broken GTW");
string gateway = _printAddr(gtw);
if( gateway != "default ") return gateway;
else return "";
}
string RoutingCompiler_bsd::PrintRule::_printRItf(RoutingRule *rule)
{
RuleElementRItf *itfrel = rule->getRItf();
Interface *itf = Interface::cast(FWReference::getObject(itfrel->front()));
if(itf != NULL)
{
IPv4 *addr = IPv4::cast(itf->getFirstByType(IPv4::TYPENAME));
if (addr == NULL)
{
QString err("Can not configure static route via interface %1 "
"because its address is unknown");
compiler->abort(rule, err.arg(itf->getName().c_str()).toStdString());
}
const InetAddr* ia = addr->getAddressPtr();
return ia->toString();
}
else return "";
}
string RoutingCompiler_bsd::PrintRule::_printRDst(RoutingRule *rule)
{
RuleElementRDst *dstrel = rule->getRDst();
Address *dst = Address::cast(FWReference::getObject(dstrel->front()));
if(dst==NULL)
compiler->abort(rule, "Broken DST");
return _printAddr(dst);
}
+3
View File
@@ -32,6 +32,8 @@ SOURCES = TableFactory.cpp \
CompilerDriver_ipf_run.cpp \
CompilerDriver_ipfw.cpp \
CompilerDriver_ipfw_run.cpp \
RoutingCompiler_bsd.cpp \
RoutingCompiler_bsd_writers.cpp
HEADERS = ../../config.h \
OSData.h \
@@ -51,6 +53,7 @@ HEADERS = ../../config.h \
CompilerDriver_pf.h \
CompilerDriver_ipf.h \
CompilerDriver_ipfw.h \
RoutingCompiler_bsd.h
macx:LIBS += $$LIBS_FWCOMPILER
+60
View File
@@ -0,0 +1,60 @@
## -*- mode: shell-script; -*-
##
## To be able to make changes to the part of configuration created
## from this configlet you need to copy this file to the directory
## fwbuilder/configlets/bsd/ in your home directory and modify it.
## Double "##" comments are removed during processing but single "#"
## comments are be retained and appear in the generated script. Empty
## lines are removed as well.
##
## Configlets support simple macro language with these constructs:
## {{$var}} is variable expansion
## {{if var}} is conditional operator.
##
# ============== ROUTING RULES ==============
TMPDIRNAME="/tmp/.fwbuilder.tempdir.$$"
TMPFILENAME="$TMPDIRNAME/.fwbuilder.out"
(umask 077 && mkdir $TMPDIRNAME) || exit 1
#
# This function stops stdout redirection
# and sends previously saved output to terminal
restore_script_output()
{
exec 1>&3 2>&1
cat $TMPFILENAME
rm -rf $TMPDIRNAME
}
# if any routing rule fails we do our best to prevent freezing the firewall
route_command_error()
{
echo "Error: Routing rule $1 couldn't be activated"
echo "Recovering previous routing configuration..."
# delete current routing rules
route -n show -inet | grep S | grep -Ev 'lo0' | \
while read route gw rest; do route delete $route $gw; done
# restore old routing rules
(IFS="
"; for route_cmd in $oldRoutes; do (IFS=' '; $route_cmd); done)
echo "...done"
restore_script_output
epilog_commands
exit 1
}
# redirect output to prevent ssh session from stalling
exec 3>&1
exec 1> $TMPFILENAME
exec 2>&1
oldRoutes=$(route -n show -inet | awk '{printf "route add %s %s\n",$1,$2;}')
echo "Deleting routing rules previously set by user space processes..."
route -n show -inet | grep S | grep -Ev {{route_filter}} | \
while read route gw rest; do route delete $route $gw; done
echo "Activating routing rules..."
+2
View File
@@ -67,4 +67,6 @@ $PFCTL -F states
{{endif}}
{{endif}}
{{$routing_script}}
epilog_commands
+2
View File
@@ -34,6 +34,8 @@
<capabilities>
<supports_routing>True</supports_routing>
<supports_metric>True</supports_metric>
<supports_routing_itf>True</supports_routing_itf>
<supports_subinterfaces>True</supports_subinterfaces>
<supports_advanced_interface_options>True</supports_advanced_interface_options>
<supports_cluster>True</supports_cluster>
+2
View File
@@ -34,6 +34,8 @@
<capabilities>
<supports_routing>True</supports_routing>
<supports_metric>True</supports_metric>
<supports_routing_itf>True</supports_routing_itf>
<supports_subinterfaces>True</supports_subinterfaces>
<supports_advanced_interface_options>True</supports_advanced_interface_options>
<supports_cluster>True</supports_cluster>
+2
View File
@@ -34,6 +34,8 @@
<capabilities>
<supports_routing>True</supports_routing>
<supports_metric>True</supports_metric>
<supports_routing_itf>True</supports_routing_itf>
<supports_advanced_interface_options>False</supports_advanced_interface_options>
</capabilities>
+3 -1
View File
@@ -23,7 +23,9 @@
</options>
<capabilities>
<supports_routing>False</supports_routing>
<supports_routing>True</supports_routing>
<supports_metric>False</supports_metric>
<supports_routing_itf>False</supports_routing_itf>
<supports_subinterfaces>True</supports_subinterfaces>
<supports_advanced_interface_options>True</supports_advanced_interface_options>
<supports_cluster>True</supports_cluster>
+3 -1
View File
@@ -14,7 +14,9 @@
</options>
<capabilities>
<supports_routing>False</supports_routing>
<supports_routing>True</supports_routing>
<supports_metric>True</supports_metric>
<supports_routing_itf>True</supports_routing_itf>
<supports_advanced_interface_options>False</supports_advanced_interface_options>
</capabilities>
+3
View File
@@ -19,6 +19,9 @@
</options>
<capabilities>
<supports_routing>True</supports_routing>
<supports_metric>True</supports_metric>
<supports_routing_itf>True</supports_routing_itf>
<supports_advanced_interface_options>False</supports_advanced_interface_options>
</capabilities>
+2
View File
@@ -34,6 +34,8 @@
<capabilities>
<supports_routing>True</supports_routing>
<supports_metric>True</supports_metric>
<supports_routing_itf>True</supports_routing_itf>
<supports_advanced_interface_options>False</supports_advanced_interface_options>
</capabilities>
+2
View File
@@ -31,6 +31,8 @@
<capabilities>
<supports_routing>True</supports_routing>
<supports_routing_itf>True</supports_routing_itf>
<supports_metric>True</supports_metric>
<supports_subinterfaces>True</supports_subinterfaces>
<supports_advanced_interface_options>True</supports_advanced_interface_options>
<supports_cluster>True</supports_cluster>
+2
View File
@@ -22,6 +22,8 @@
<capabilities>
<supports_routing>False</supports_routing>
<supports_metric>False</supports_metric>
<supports_routing_itf>False</supports_routing_itf>
<supports_advanced_interface_options>False</supports_advanced_interface_options>
</capabilities>
+2
View File
@@ -34,6 +34,8 @@
<capabilities>
<supports_routing>True</supports_routing>
<supports_metric>True</supports_metric>
<supports_routing_itf>True</supports_routing_itf>
<supports_advanced_interface_options>False</supports_advanced_interface_options>
</capabilities>
+3 -1
View File
@@ -22,7 +22,9 @@
</options>
<capabilities>
<supports_routing>False</supports_routing>
<supports_routing>True</supports_routing>
<supports_metric>False</supports_metric>
<supports_routing_itf>False</supports_routing_itf>
<supports_subinterfaces>True</supports_subinterfaces>
<supports_advanced_interface_options>True</supports_advanced_interface_options>
<supports_cluster>True</supports_cluster>
+2
View File
@@ -34,6 +34,8 @@
<capabilities>
<supports_routing>True</supports_routing>
<supports_metric>True</supports_metric>
<supports_routing_itf>True</supports_routing_itf>
<supports_subinterfaces>True</supports_subinterfaces>
<supports_advanced_interface_options>True</supports_advanced_interface_options>
<supports_cluster>True</supports_cluster>
+3 -1
View File
@@ -22,7 +22,9 @@
</options>
<capabilities>
<supports_routing>False</supports_routing>
<supports_routing>True</supports_routing>
<supports_metric>True</supports_metric>
<supports_routing_itf>True</supports_routing_itf>
<supports_subinterfaces>True</supports_subinterfaces>
<supports_advanced_interface_options>True</supports_advanced_interface_options>
<supports_cluster>True</supports_cluster>
+2
View File
@@ -21,6 +21,8 @@
<capabilities>
<supports_routing>True</supports_routing>
<supports_metric>True</supports_metric>
<supports_routing_itf>True</supports_routing_itf>
<supports_subinterfaces>False</supports_subinterfaces>
<supports_advanced_interface_options>True</supports_advanced_interface_options>
<supports_cluster>False</supports_cluster>
+2
View File
@@ -41,6 +41,8 @@
<capabilities>
<supports_routing>True</supports_routing>
<supports_metric>True</supports_metric>
<supports_routing_itf>True</supports_routing_itf>
<supports_subinterfaces>True</supports_subinterfaces>
<supports_advanced_interface_options>True</supports_advanced_interface_options>
<supports_cluster>True</supports_cluster>
+2
View File
@@ -22,6 +22,8 @@
<capabilities>
<supports_routing>False</supports_routing>
<supports_metric>False</supports_metric>
<supports_routing_itf>False</supports_routing_itf>
<supports_advanced_interface_options>False</supports_advanced_interface_options>
</capabilities>
+2
View File
@@ -32,6 +32,8 @@
<capabilities>
<supports_routing>True</supports_routing>
<supports_metric>True</supports_metric>
<supports_routing_itf>True</supports_routing_itf>
<supports_advanced_interface_options>False</supports_advanced_interface_options>
</capabilities>
+2
View File
@@ -20,6 +20,8 @@
<capabilities>
<supports_routing>False</supports_routing>
<supports_metric>False</supports_metric>
<supports_routing_itf>False</supports_routing_itf>
<supports_advanced_interface_options>False</supports_advanced_interface_options>
</capabilities>
-1
View File
@@ -235,7 +235,6 @@ nameif %in %il security%sl
<actions_in_nat>False</actions_in_nat>
<supports_time>False</supports_time>
<supports_accounting>False</supports_accounting>
<supports_routing_itf>True</supports_routing_itf>
<security_levels>True</security_levels>
<network_zones>True</network_zones>
<unprotected_interfaces>False</unprotected_interfaces>
-1
View File
@@ -111,7 +111,6 @@ interface %in
<actions_in_nat>False</actions_in_nat>
<supports_time>False</supports_time>
<supports_accounting>False</supports_accounting>
<supports_routing_itf>True</supports_routing_itf>
<security_levels>False</security_levels>
<network_zones>False</network_zones>
<unprotected_interfaces>True</unprotected_interfaces>
-1
View File
@@ -32,7 +32,6 @@
<actions_in_nat>False</actions_in_nat>
<supports_time>False</supports_time>
<supports_accounting>True</supports_accounting>
<supports_routing_itf>True</supports_routing_itf>
<security_levels>False</security_levels>
<network_zones>False</network_zones>
<unprotected_interfaces>False</unprotected_interfaces>
-1
View File
@@ -30,7 +30,6 @@
<actions_in_nat>False</actions_in_nat>
<supports_time>False</supports_time>
<supports_accounting>True</supports_accounting>
<supports_routing_itf>True</supports_routing_itf>
<security_levels>False</security_levels>
<network_zones>False</network_zones>
<unprotected_interfaces>False</unprotected_interfaces>
-1
View File
@@ -41,7 +41,6 @@
<actions_in_nat>True</actions_in_nat>
<supports_time>True</supports_time>
<supports_accounting>True</supports_accounting>
<supports_routing_itf>True</supports_routing_itf>
<security_levels>False</security_levels>
<network_zones>False</network_zones>
<unprotected_interfaces>False</unprotected_interfaces>
-1
View File
@@ -35,7 +35,6 @@
<actions_in_nat>True</actions_in_nat>
<supports_time>False</supports_time>
<supports_accounting>True</supports_accounting>
<supports_routing_itf>True</supports_routing_itf>
<security_levels>False</security_levels>
<network_zones>False</network_zones>
<unprotected_interfaces>True</unprotected_interfaces>
-1
View File
@@ -641,7 +641,6 @@
<actions_in_nat>False</actions_in_nat>
<supports_time>False</supports_time>
<supports_accounting>False</supports_accounting>
<supports_routing_itf>True</supports_routing_itf>
<security_levels>True</security_levels>
<network_zones>True</network_zones>
<unprotected_interfaces>True</unprotected_interfaces>
-1
View File
@@ -48,7 +48,6 @@ interface %in
<actions_in_nat>False</actions_in_nat>
<supports_time>False</supports_time>
<supports_accounting>False</supports_accounting>
<supports_routing_itf>True</supports_routing_itf>
<security_levels>False</security_levels>
<network_zones>False</network_zones>
<unprotected_interfaces>True</unprotected_interfaces>
-1
View File
@@ -22,7 +22,6 @@
<actions_in_nat>False</actions_in_nat>
<supports_time>False</supports_time>
<supports_accounting>False</supports_accounting>
<supports_routing_itf>False</supports_routing_itf>
<security_levels>False</security_levels>
<network_zones>False</network_zones>
<unprotected_interfaces>False</unprotected_interfaces>
File diff suppressed because it is too large Load Diff