1
0
mirror of https://github.com/fwbuilder/fwbuilder synced 2026-03-24 04:07:55 +01:00
fwbuilder/src/pflib/PolicyCompiler_pf.cpp
Vadim Kurland 58355d5aab ********************************
Merge branch inet-addr-changes r61
********************************
2008-04-13 07:06:30 +00:00

1083 lines
35 KiB
C++

/*
Firewall Builder
Copyright (C) 2002 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: PolicyCompiler_pf.cpp 1451 2007-12-09 23:53:22Z vk $
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 "PolicyCompiler_pf.h"
#include "NATCompiler_pf.h"
#include "fwbuilder/FWObjectDatabase.h"
#include "fwbuilder/RuleElement.h"
#include "fwbuilder/IPService.h"
#include "fwbuilder/ICMPService.h"
#include "fwbuilder/TCPService.h"
#include "fwbuilder/UDPService.h"
#include "fwbuilder/Policy.h"
#include "fwbuilder/Interface.h"
#include "fwbuilder/Firewall.h"
#include "fwbuilder/Network.h"
#include "fwbuilder/AddressTable.h"
#include <algorithm>
#include <functional>
#include <iostream>
#include <iomanip>
#include <assert.h>
using namespace libfwbuilder;
using namespace fwcompiler;
using namespace std;
string PolicyCompiler_pf::myPlatformName() { return "pf"; }
int PolicyCompiler_pf::prolog()
{
if (fw->getStr("platform")!=myPlatformName() )
abort(_("Unsupported platform ") + fw->getStr("platform") );
list<FWObject*> l2=fw->getByType(Interface::TYPENAME);
for (list<FWObject*>::iterator i=l2.begin(); i!=l2.end(); ++i)
{
Interface *iface=dynamic_cast<Interface*>(*i);
assert(iface);
if ( iface->isDyn())
{
list<FWObject*> l3=iface->getByType(IPv4::TYPENAME);
if (l3.size()>0)
{
char errstr[256];
sprintf(errstr,
_("Dynamic interface %s should not have an IP address object attached to it. This IP address object will be ignored."),
iface->getName().c_str() );
warning( errstr );
for (list<FWObject*>::iterator j=l3.begin(); j!=l3.end(); ++j)
iface->remove(*j);
}
}
}
if (tables)
{
tables->init(dbcopy);
tables->setRuleSetName(getRuleSetName());
}
return PolicyCompiler::prolog();
}
bool PolicyCompiler_pf::swapAddressTableObjectsInRE::processNext()
{
PolicyCompiler_pf *pf_comp=dynamic_cast<PolicyCompiler_pf*>(compiler);
Rule *rule=prev_processor->getNextRule(); if (rule==NULL) return false;
RuleElement *re=RuleElement::cast( rule->getFirstByType(re_type) );
list<MultiAddress*> cl;
for (FWObject::iterator i=re->begin(); i!=re->end(); i++)
{
FWObject *o= *i;
if (FWReference::cast(o)!=NULL) o=FWReference::cast(o)->getPointer();
/*
* All addressTable objects will be run-time here because we
* switch them in preprocessor. The difference is: if address
* table was originally run-time, at this point it will have
* no children, however if it was compile-time originally, it
* will have children objects. That is how we distinguish
* them in this rule processor. Here we only deal with
* AddressTable objects that originally used to be
* compile-time because we need to create tables for them.
*/
if (AddressTable::cast(o)!=NULL &&
AddressTable::cast(o)->isRunTime() &&
o->size() > 0)
cl.push_back(MultiAddress::cast(o));
}
if (!cl.empty())
{
for (list<MultiAddress*>::iterator i=cl.begin(); i!=cl.end(); i++)
{
MultiAddress *atbl = *i;
string mart_id = atbl->getId()+"_runtime";
MultiAddressRunTime *mart =
MultiAddressRunTime::cast(compiler->dbcopy->findInIndex(mart_id));
if (mart==NULL)
{
mart = new MultiAddressRunTime(atbl);
// need to ensure stable ID for the runtime object, so
// that when the same object is replaced in different
// rulesets by different compiler passes, chosen
// runtime object has the same ID and is identified as
// the same by the compiler.
mart->setId( mart_id );
compiler->dbcopy->addToIndex(mart);
compiler->dbcopy->add(mart);
// register this object as a table
string tblname = atbl->getName();
string tblID = tblname + "_addressTableObject";
pf_comp->tables->registerTable(tblname,tblID,atbl);
}
re->removeRef(atbl);
re->addRef(mart);
}
tmp_queue.push_back(rule);
return true;
}
tmp_queue.push_back(rule);
return true;
}
bool PolicyCompiler_pf::processMultiAddressObjectsInRE::processNext()
{
PolicyCompiler_pf *pf_comp=dynamic_cast<PolicyCompiler_pf*>(compiler);
PolicyRule *rule=getNext(); if (rule==NULL) return false;
RuleElement *re=RuleElement::cast( rule->getFirstByType(re_type) );
bool neg = re->getNeg();
list<FWObject*> maddr_runtime;
try
{
for (FWObject::iterator i=re->begin(); i!=re->end(); i++)
{
FWObject *o= *i;
if (FWReference::cast(o)!=NULL) o=FWReference::cast(o)->getPointer();
MultiAddressRunTime *atrt = MultiAddressRunTime::cast(o);
if (atrt!=NULL &&
atrt->getSubstitutionTypeName()==AddressTable::TYPENAME)
{
if (re->size()>1 && neg)
{
string err = "AddressTable object can not be used with negation in combination with other objects in the same rule element. Rule ";
err += rule->getLabel();
compiler->abort(err);
}
string tblname = o->getName();
string tblID = tblname + "_addressTableObject";
pf_comp->tables->registerTable(tblname,tblID,o);
o->setBool("pf_table",true);
maddr_runtime.push_back(o);
}
}
} catch(FWException &ex) // TableFactory::registerTable throws exception
{
string err;
err = "Can not process MultiAddress object in rule " +
rule->getLabel() + " : " + ex.toString();
compiler->abort( err );
}
if (!maddr_runtime.empty())
{
RuleElement *nre;
for (FWObject::iterator i=maddr_runtime.begin(); i!=maddr_runtime.end(); i++)
{
PolicyRule *r= PolicyRule::cast(compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
nre=RuleElement::cast( r->getFirstByType(re_type) );
nre->clearChildren();
nre->addRef( *i );
tmp_queue.push_back(r);
}
for (FWObject::iterator i=maddr_runtime.begin(); i!=maddr_runtime.end(); i++)
re->removeRef( *i );
if (!re->isAny())
tmp_queue.push_back(rule);
return true;
}
tmp_queue.push_back(rule);
return true;
}
bool PolicyCompiler_pf::splitIfFirewallInSrc::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
PolicyRule *r;
RuleElementSrc *src=rule->getSrc(); assert(src);
if (src->size()==1 || src->getNeg())
{
tmp_queue.push_back(rule);
return true;
}
FWObject *fw_in_src=NULL;
vector<FWObject*> cl;
for (FWObject::iterator i1=src->begin(); i1!=src->end(); ++i1) {
FWObject *o = *i1;
FWObject *obj = NULL;
// if (FWReference::cast(o)!=NULL) obj=FWReference::cast(o)->getPointer();
if (FWReference::cast(o)!=NULL) obj=FWReference::cast(o)->getPointer();
if (obj==NULL) throw FWException(_("Broken Src object in rule: ")+rule->getLabel());
if (obj->getId()==compiler->getFwId()) {
fw_in_src=o; // can not remove right now because remove invalidates iterator
RuleElementSrc *nsrc;
r= PolicyRule::cast(compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
nsrc=r->getSrc();
nsrc->clearChildren();
nsrc->setAnyElement();
nsrc->addRef( compiler->fw );
tmp_queue.push_back(r);
}
}
if (fw_in_src!=NULL) src->remove( fw_in_src );
tmp_queue.push_back(rule);
return true;
}
bool PolicyCompiler_pf::splitIfFirewallInDst::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
PolicyRule *r;
RuleElementDst *dst=rule->getDst(); assert(dst);
if (dst->size()==1 || dst->getNeg())
{
tmp_queue.push_back(rule);
return true;
}
FWObject *fw_in_dst=NULL;
vector<FWObject*> cl;
for (FWObject::iterator i1=dst->begin(); i1!=dst->end(); ++i1)
{
FWObject *o = *i1;
FWObject *obj = NULL;
// if (FWReference::cast(o)!=NULL) obj=FWReference::cast(o)->getPointer();
if (FWReference::cast(o)!=NULL) obj=FWReference::cast(o)->getPointer();
if (obj==NULL) throw FWException(_("Broken Dst in rule: ")+rule->getLabel());
if (obj->getId()==compiler->getFwId()) {
fw_in_dst=o; // can not remove right now because remove invalidates iterator
RuleElementDst *ndst;
r= PolicyRule::cast(compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
ndst=r->getDst();
ndst->clearChildren();
ndst->setAnyElement();
ndst->addRef( compiler->fw );
tmp_queue.push_back(r);
}
}
if (fw_in_dst!=NULL) dst->remove( fw_in_dst );
tmp_queue.push_back(rule);
return true;
}
bool PolicyCompiler_pf::fillDirection::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
tmp_queue.push_back(rule);
/* after interface policies have been merged with global policy, rules
* with empty direction have disappeared. In fact, xslt
* transformation 2.1.1->2.1.2 leaves empty direction in the old
* global policy rules, but the GUI promptly fixes that replacing it
* with "Both" whenever user opens the policy. So, we have to handle
* both the case of an empty direction and direction "Both". To
* preserve old semantics as accurately as possible, I check for a
* combination of empty interface and direction "Both", this is what
* old global rules become after user opens the combined policy in the
* GUI. In fact, it does not matter what direction is set in the rule
* as long as it misses interface - we need to determine direction
* again anyway.
*/
if (rule->getDirectionAsString()=="" || rule->getInterfaceId()=="" )
{
if ( compiler->getCachedFwOpt()->getBool("pass_all_out") )
{
if (!rule->isFallback()) rule->setDirection( PolicyRule::Inbound );
} else
{
rule->setDirection( PolicyRule::Both );
Address *src=compiler->getFirstSrc(rule);
Address *dst=compiler->getFirstDst(rule);
string fwid=compiler->getFwId();
if (src==NULL || dst==NULL)
compiler->abort("Broken src or dst in rule "+rule->getLabel());
if (!src->isAny() && !dst->isAny() &&
compiler->complexMatch(compiler->fw, src) &&
compiler->complexMatch(compiler->fw, dst)) return true;
if (!src->isAny() && compiler->complexMatch(compiler->fw, src))
rule->setDirection( PolicyRule::Outbound );
if (!dst->isAny() && compiler->complexMatch(compiler->fw, dst))
rule->setDirection( PolicyRule::Inbound );
}
}
return true;
}
/*
* add default and auto-generated rules, except when we process rules
* in a branch (i.e. anchor, since this is PF)
*/
void PolicyCompiler_pf::addDefaultPolicyRule()
{
if (!getRuleSetName().empty()) return;
if ( getCachedFwOpt()->getBool("mgmt_ssh") &&
!getCachedFwOpt()->getStr("mgmt_addr").empty() )
{
PolicyRule *r;
TCPService *ssh=TCPService::cast(dbcopy->create(TCPService::TYPENAME) );
ssh->setInt("dst_range_start",22);
ssh->setInt("dst_range_end",22);
ssh->setName("mgmt_ssh");
dbcopy->add(ssh,false);
cacheObj(ssh); // to keep cache consistent
string mgmt_addr = getCachedFwOpt()->getStr("mgmt_addr");
InetAddr addr;
InetNetmask netmask(InetAddr::getAllOnes());
try
{
addr = InetAddr(mgmt_addr);
string::size_type sep = mgmt_addr.find("/");
if (sep != string::npos)
{
addr = InetAddr(mgmt_addr.substr(0,sep));
string nm = mgmt_addr.substr(sep+1);
int o1,o2,o3,o4;
if(sscanf(nm.c_str(), "%3u.%3u.%3u.%3u", &o1, &o2, &o3, &o4)==4)
{
netmask = InetNetmask(nm);
} else
{
sscanf(nm.c_str(),"%u",&o1);
netmask = InetNetmask(o1);
}
}
} catch(FWException &ex)
{
char errstr[256];
sprintf(errstr,
_("Invalid address for the backup ssh access: '%s'"),
mgmt_addr.c_str() );
abort( errstr );
}
Network *mgmt_workstation = Network::cast(dbcopy->create(Network::TYPENAME));
mgmt_workstation->setName("mgmt_addr");
mgmt_workstation->setAddress( addr );
mgmt_workstation->setNetmask( netmask );
// IPv4 *mgmt_workstation = IPv4::cast(dbcopy->create(IPv4::TYPENAME));
// mgmt_workstation->setAddress( getCachedFwOpt()->getStr("mgmt_addr") );
dbcopy->add(mgmt_workstation,false);
cacheObj(mgmt_workstation); // to keep cache consistent
r= PolicyRule::cast(dbcopy->create(PolicyRule::TYPENAME) );
temp_ruleset->add(r);
r->setAction(PolicyRule::Accept);
r->setLogging(false);
r->setDirection(PolicyRule::Inbound);
r->setPosition(9999);
r->setComment(" backup ssh access rule ");
r->setHidden(true);
r->setFallback(false);
r->setLabel("backup ssh access rule");
r->setBool("needs_established",true); // supported in ipfw
RuleElement *src=r->getSrc();
assert(src!=NULL);
src->addRef(mgmt_workstation);
RuleElement *dst=r->getDst();
assert(dst!=NULL);
dst->addRef(fw);
RuleElement *srv=r->getSrv();
assert(srv!=NULL);
srv->addRef(ssh);
combined_ruleset->push_front(r);
}
if ( getCachedFwOpt()->getBool("pass_all_out") )
{
PolicyRule *r;
FWOptions *ruleopt;
r= PolicyRule::cast(dbcopy->create(PolicyRule::TYPENAME) );
temp_ruleset->add(r);
r->setAction(PolicyRule::Accept);
r->setLogging( getCachedFwOpt()->getBool("fallback_log") );
r->setDirection(PolicyRule::Outbound);
r->setPosition(10000);
r->setComment(" fallback rule ");
r->setHidden(true);
r->setFallback(true);
r->setLabel("fallback rule");
combined_ruleset->push_back(r);
r= PolicyRule::cast(dbcopy->create(PolicyRule::TYPENAME) );
temp_ruleset->add(r);
r->setAction(PolicyRule::Deny);
r->setLogging( getCachedFwOpt()->getBool("fallback_log") );
r->setDirection(PolicyRule::Inbound);
r->setPosition(10001);
r->setComment(" fallback rule ");
r->setHidden(true);
r->setFallback(true);
r->setLabel("fallback rule");
ruleopt = r->getOptionsObject();
ruleopt->setBool("stateless", true);
combined_ruleset->push_back(r);
} else
{
PolicyRule *r= PolicyRule::cast(dbcopy->create(PolicyRule::TYPENAME) );
FWOptions *ruleopt;
temp_ruleset->add(r);
r->setAction(PolicyRule::Deny);
r->setLogging( getCachedFwOpt()->getBool("fallback_log") );
r->setDirection(PolicyRule::Both);
r->setPosition(10000);
r->setComment(" fallback rule ");
r->setHidden(true);
r->setFallback(true);
r->setLabel("fallback rule");
ruleopt = r->getOptionsObject();
ruleopt->setBool("stateless", true);
combined_ruleset->push_back(r);
}
}
bool PolicyCompiler_pf::SpecialServices::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
tmp_queue.push_back(rule);
RuleElementSrv *srv=rule->getSrv();
for (FWObject::iterator i=srv->begin(); i!=srv->end(); i++) {
FWObject *o= *i;
if (FWReference::cast(o)!=NULL) o=FWReference::cast(o)->getPointer();
Service *s=Service::cast( o );
assert(s);
if (IPService::cast(s)!=NULL && rule->getAction()==PolicyRule::Accept) {
if (s->getBool("rr") ||
s->getBool("ssrr") ||
s->getBool("ts") )
rule->setBool("allow_opts",true);
}
}
return true;
}
bool PolicyCompiler_pf::SplitDirection::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
if (rule->getDirection()==PolicyRule::Both) {
PolicyRule *r= PolicyRule::cast(
compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
r->setDirection(PolicyRule::Inbound);
tmp_queue.push_back(r);
r= PolicyRule::cast(
compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
r->setDirection(PolicyRule::Outbound);
tmp_queue.push_back(r);
} else
tmp_queue.push_back(rule);
return true;
}
bool PolicyCompiler_pf::ProcessScrubOption::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
FWOptions *ruleopt =rule->getOptionsObject();
if ( ruleopt->getBool("scrub") ) {
if (rule->getAction()!=PolicyRule::Accept) {
ruleopt->setBool("scrub",false);
tmp_queue.push_back(rule);
throw FWException(_("Rule option 'scrub' is supported only for rules with action 'Accept'. Rule: ")+rule->getLabel());
return true;
}
PolicyRule *r= PolicyRule::cast(
compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
r->setAction(PolicyRule::Scrub);
r->getOptionsObject()->setBool("scrub",false);
tmp_queue.push_back(r);
ruleopt->setBool("scrub",false);
tmp_queue.push_back(rule);
return true;
}
/* if service is ip_fragment and action is 'Deny', then add rule with scrub */
Service *srv=compiler->getFirstSrv(rule); assert(srv);
if ( (srv->getBool("short_fragm") || srv->getBool("fragm")) &&
( rule->getAction()==PolicyRule::Deny || rule->getAction()==PolicyRule::Reject) ) {
PolicyRule *r= PolicyRule::cast(
compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
r->setAction(PolicyRule::Scrub);
r->getOptionsObject()->setBool("scrub",false);
tmp_queue.push_back(r);
return true;
}
tmp_queue.push_back(rule);
return true;
}
bool PolicyCompiler_pf::setQuickFlag::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
tmp_queue.push_back(rule);
if ( rule->getAction()!=PolicyRule::Scrub &&
rule->getAction()!=PolicyRule::Accounting &&
rule->getAction()!=PolicyRule::Tag &&
rule->getAction()!=PolicyRule::Branch
) rule->setBool("quick",true);
return true;
}
bool PolicyCompiler_pf::doSrcNegation::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
RuleElementSrc *src=rule->getSrc();
if (src->getNeg()) {
RuleElementSrc *nsrc;
PolicyRule *r;
r= PolicyRule::cast(compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
if (rule->getAction()==PolicyRule::Accept) r->setAction(PolicyRule::Deny);
else r->setAction(PolicyRule::Accept);
nsrc=r->getSrc();
nsrc->setNeg(false);
r->setBool("quick",true);
r->setLogging(false);
tmp_queue.push_back(r);
r= PolicyRule::cast(compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
nsrc=r->getSrc();
nsrc->setNeg(false);
nsrc->clearChildren();
nsrc->setAnyElement();
r->setBool("quick",true);
tmp_queue.push_back(r);
return true;
}
tmp_queue.push_back(rule);
return true;
}
bool PolicyCompiler_pf::doDstNegation::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
RuleElementDst *dst=rule->getDst();
if (dst->getNeg()) {
RuleElementDst *ndst;
PolicyRule *r;
r= PolicyRule::cast(compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
if (rule->getAction()==PolicyRule::Accept) r->setAction(PolicyRule::Deny);
else r->setAction(PolicyRule::Accept);
ndst=r->getDst();
ndst->setNeg(false);
r->setBool("quick",true);
r->setLogging(false);
tmp_queue.push_back(r);
r= PolicyRule::cast(compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
ndst=r->getDst();
ndst->setNeg(false);
ndst->clearChildren();
ndst->setAnyElement();
r->setBool("quick",true);
tmp_queue.push_back(r);
return true;
}
tmp_queue.push_back(rule);
return true;
}
bool PolicyCompiler_pf::doSrvNegation::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
RuleElementSrv *srv=rule->getSrv();
if (srv->getNeg()) {
throw FWException(_("Negation in Srv is not implemented. Rule: ")+rule->getLabel());
return true;
}
tmp_queue.push_back(rule);
return true;
}
bool PolicyCompiler_pf::addLoopbackForRedirect::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
PolicyCompiler_pf *pf_comp=dynamic_cast<PolicyCompiler_pf*>(compiler);
// RuleElementSrc *src=rule->getSrc();
RuleElementDst *dst=rule->getDst();
RuleElementSrv *srv=rule->getSrv();
if (pf_comp->natcmp==NULL)
compiler->abort("addLoopbackForRedirect needs a valid pointer to the NAT compiler object");
tmp_queue.push_back(rule);
const list<NATCompiler_pf::redirectRuleInfo> lst=pf_comp->natcmp->getRedirRulesInfo();
if (lst.empty()) return true;
/*
* struct redirectRuleInfo {
* string natrule_label;
* Address *tdst;
* Service *tsrv;
* };
*/
for (FWObject::iterator i=srv->begin(); i!=srv->end(); i++)
{
FWObject *o1= *i;
if (FWReference::cast(o1)!=NULL) o1=FWReference::cast(o1)->getPointer();
Service *s=Service::cast( o1 );
assert(s);
for (FWObject::iterator j=dst->begin(); j!=dst->end(); j++)
{
FWObject *o2= *j;
if (FWReference::cast(o2)!=NULL) o2=FWReference::cast(o2)->getPointer();
Address *a=Address::cast( o2 );
assert(a);
list<NATCompiler_pf::redirectRuleInfo>::const_iterator k;
for (k=lst.begin(); k!=lst.end(); ++k)
{
if ( *a == *(k->old_tdst) && *s == *(k->tsrv) )
{
// insert address used for redirection in the NAT rule.
dst->addRef( k->new_tdst );
return true;
}
}
}
}
return true;
}
void PolicyCompiler_pf::checkForDynamicInterfacesOfOtherObjects::findDynamicInterfaces(RuleElement *re,
Rule *rule)
{
if (re->isAny()) return;
list<FWObject*> cl;
for (list<FWObject*>::iterator i1=re->begin(); i1!=re->end(); ++i1)
{
FWObject *o = *i1;
FWObject *obj = o;
if (FWReference::cast(o)!=NULL) obj=FWReference::cast(o)->getPointer();
Interface *ifs =Interface::cast( obj );
if (ifs!=NULL &&
ifs->isDyn() &&
ifs->getParent()->getId()!=compiler->fw->getId() &&
! ifs->getParent()->getBool("pf_table") )
{
char errstr[2048];
sprintf(errstr,_("Can not build rule using dynamic interface '%s' of the object '%s' because its address in unknown. Rule %s"),
ifs->getName().c_str(),
ifs->getParent()->getName().c_str(),
rule->getLabel().c_str() );
throw FWException(errstr);
}
}
}
bool PolicyCompiler_pf::checkForDynamicInterfacesOfOtherObjects::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
findDynamicInterfaces( rule->getSrc() , rule );
findDynamicInterfaces( rule->getDst() , rule );
tmp_queue.push_back(rule);
return true;
}
bool PolicyCompiler_pf::splitIfInterfaceInRE::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
RuleElement *re=RuleElement::cast( rule->getFirstByType(re_type) );
if (re->size()<=2)
{
tmp_queue.push_back(rule);
return true;
}
list<FWObject*> cl;
for (FWObject::iterator i=re->begin(); i!=re->end(); i++)
{
FWObject *o= *i;
if (FWReference::cast(o)!=NULL) o=FWReference::cast(o)->getPointer();
Interface *interface_=Interface::cast(o);
if (interface_!=NULL && interface_->isDyn())
cl.push_back(interface_);
}
if (!cl.empty())
{
RuleElement *nre;
PolicyRule *r= PolicyRule::cast(compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
nre=RuleElement::cast( r->getFirstByType(re_type) );
nre->clearChildren();
for (FWObject::iterator i=cl.begin(); i!=cl.end(); i++) nre->addRef( *i );
tmp_queue.push_back(r);
r= PolicyRule::cast(compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
nre=RuleElement::cast( r->getFirstByType(re_type) );
for (FWObject::iterator i=cl.begin(); i!=cl.end(); i++) nre->removeRef( *i );
tmp_queue.push_back(r);
return true;
}
tmp_queue.push_back(rule);
return true;
}
bool PolicyCompiler_pf::separateSrcPort::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
RuleElementSrv *rel= rule->getSrv();
if (rel->size()==1) {
tmp_queue.push_back(rule);
return true;
}
list<Service*> services;
for (FWObject::iterator i=rel->begin(); i!=rel->end(); i++) {
FWObject *o= *i;
if (FWReference::cast(o)!=NULL) o=FWReference::cast(o)->getPointer();
Service *s=Service::cast(o);
assert(s!=NULL);
if ( TCPService::isA(s) || UDPService::isA(s) ) {
int srs=s->getInt("src_range_start");
int sre=s->getInt("src_range_end");
compiler->normalizePortRange(srs,sre);
if (srs!=0 || sre!=0) {
PolicyRule *r= PolicyRule::cast(
compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
RuleElementSrv *nsrv=r->getSrv();
nsrv->clearChildren();
nsrv->addRef( s );
tmp_queue.push_back(r);
services.push_back(s);
}
}
}
for (list<Service*>::iterator i=services.begin(); i!=services.end(); i++)
rel->removeRef( (*i) );
if (!rel->isAny())
tmp_queue.push_back(rule);
return true;
}
bool PolicyCompiler_pf::createTables::processNext()
{
PolicyCompiler_pf *pf_comp=dynamic_cast<PolicyCompiler_pf*>(compiler);
PolicyRule *rule=getNext(); if (rule==NULL) return false;
RuleElementSrc *src=rule->getSrc();
RuleElementDst *dst=rule->getDst();
// RuleElementSrv *srv=rule->getSrv();
if (src->size()!=1) pf_comp->tables->createTablesForRE(src,rule);
if (dst->size()!=1) pf_comp->tables->createTablesForRE(dst,rule);
// if (srv->size()!=1) createTablesForRE(srv,rule);
tmp_queue.push_back(rule);
return true;
}
bool PolicyCompiler_pf::printScrubRule::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
FWOptions* options=compiler->fw->getOptionsObject();
if (!init && options->getBool("pf_do_scrub"))
{
compiler->output << "#" << endl;
compiler->output << "# Defragmentation" << endl;
compiler->output << "#" << endl;
compiler->output << "scrub in from any to any" << endl << endl;
init=true;
}
tmp_queue.push_back(rule);
return true;
}
void PolicyCompiler_pf::compile()
{
try
{
Compiler::compile();
addDefaultPolicyRule();
bool check_for_recursive_groups=true;
if ( fw->getOptionsObject()->getBool ("check_shading") )
{
add( new Begin ("Detecting rule shadowing" ));
add( new printTotalNumberOfRules () );
add( new ItfNegation( "process negation in Itf" ) );
add( new InterfacePolicyRules(
"process interface policy rules and store interface ids"));
add( new recursiveGroupsInSrc("check for recursive groups in SRC"));
add( new recursiveGroupsInDst("check for recursive groups in DST"));
add( new recursiveGroupsInSrv("check for recursive groups in SRV"));
check_for_recursive_groups=false;
add( new ExpandGroups ("expand groups" ) );
add( new eliminateDuplicatesInSRC("eliminate duplicates in SRC") );
add( new eliminateDuplicatesInDST("eliminate duplicates in DST") );
add( new eliminateDuplicatesInSRV("eliminate duplicates in SRV") );
add( new swapAddressTableObjectsInSrc(
"AddressTable -> MultiAddressRunTime in Src") );
add( new swapAddressTableObjectsInDst(
"AddressTable -> MultiAddressRunTime in Dst") );
add( new swapMultiAddressObjectsInSrc(
"MultiAddress -> MultiAddressRunTime in Src") );
add( new swapMultiAddressObjectsInDst(
"MultiAddress -> MultiAddressRunTime in Dst") );
add( new ExpandMultipleAddressesInSRC(
"expand objects with multiple addresses in SRC" ) );
add( new ExpandMultipleAddressesInDST(
"expand objects with multiple addresses in DST" ) );
add( new ConvertToAtomic ("convert to atomic rules") );
add( new DetectShadowing ("Detect shadowing" ) );
add( new simplePrintProgress ( ) );
runRuleProcessors();
deleteRuleProcessors();
}
add( new Begin() );
add( new printTotalNumberOfRules() );
// add( new printScrubRule (" Defragmentation" ));
if (check_for_recursive_groups)
{
add( new recursiveGroupsInSrc("check for recursive groups in SRC"));
add( new recursiveGroupsInDst("check for recursive groups in DST"));
add( new recursiveGroupsInSrv("check for recursive groups in SRV"));
}
add( new emptyGroupsInSrc( "check for empty groups in SRC" ));
add( new emptyGroupsInDst( "check for empty groups in DST" ));
add( new emptyGroupsInSrv( "check for empty groups in SRV" ));
// add( new doSrcNegation( "process negation in Src" ));
// add( new doDstNegation( "process negation in Dst" ));
add( new doSrvNegation( "process negation in Srv" ));
// ExpandGroups opens groups, as well as groups in groups etc.
add( new ExpandGroups( "expand groups" ));
add( new CheckForTCPEstablished(
"check for TCPService objects with flag \"established\"") );
add( new eliminateDuplicatesInSRC("eliminate duplicates in SRC" ));
add( new eliminateDuplicatesInDST("eliminate duplicates in DST" ));
add( new eliminateDuplicatesInSRV("eliminate duplicates in SRV" ));
add( new swapAddressTableObjectsInSrc(
"AddressTable -> MultiAddressRunTime in Src") );
add( new swapAddressTableObjectsInDst(
"AddressTable -> MultiAddressRunTime in Dst") );
add( new swapMultiAddressObjectsInSrc(
"MultiAddress -> MultiAddressRunTime in Src") );
add( new swapMultiAddressObjectsInDst(
"MultiAddress -> MultiAddressRunTime in Dst") );
add( new processMultiAddressObjectsInSrc(
"process MultiAddress objects in Src") );
add( new processMultiAddressObjectsInDst(
"process MultiAddress objects in Dst") );
add( new ItfNegation( "process negation in Itf" ) );
add( new InterfacePolicyRules(
"process interface policy rules and store interface ids") );
add( new splitIfFirewallInSrc( "split rule if firewall is in Src" ));
add( new splitIfFirewallInDst( "split rule if firewall is in Dst" ));
add( new fillDirection( "determine directions" ));
add( new SplitDirection( "split rules with direction 'both'" ));
add( new addLoopbackForRedirect(
"add loopback to rules that permit redirected services" ) );
add( new ExpandMultipleAddresses(
"expand objects with multiple addresses" ) );
add( new checkForDynamicInterfacesOfOtherObjects(
"check for dynamic interfaces of other hosts and firewalls" ));
add( new MACFiltering( "verify for MAC address filtering" ));
add( new checkForUnnumbered( "check for unnumbered interfaces" ));
add( new addressRanges( "expand address range objects" ));
add( new splitServices( "split rules with different protocols"));
add( new separateTCPWithFlags("separate TCP services with flags" ));
add( new separateSrcPort("split on TCP and UDP with source ports"));
add( new verifyCustomServices(
"verify custom services for this platform"));
// add( new ProcessScrubOption( "process 'scrub' option" ));
add( new SpecialServices( "check for special services" ));
add( new setQuickFlag( "set 'quick' flag" ));
add( new checkForZeroAddr( "check for zero addresses" ));
add( new convertInterfaceIdToStr("prepare interface assignments" ));
add( new createTables( "create tables" ));
// add( new PrintTables( "print tables" ));
add( new PrintRule( "generate pf code" ));
add( new simplePrintProgress() );
runRuleProcessors();
} catch (FWException &ex) {
error(ex.toString());
exit(1);
}
}
void PolicyCompiler_pf::epilog()
{
}