mirror of
https://github.com/fwbuilder/fwbuilder
synced 2026-03-24 04:07:55 +01:00
2712 lines
84 KiB
C++
2712 lines
84 KiB
C++
/*
|
|
|
|
Firewall Builder
|
|
|
|
Copyright (C) 2002 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 "NATCompiler_ipt.h"
|
|
#include "OSConfigurator_linux24.h"
|
|
|
|
#include "combinedAddress.h"
|
|
|
|
#include "fwcompiler/OSConfigurator.h"
|
|
|
|
#include "fwbuilder/Resources.h"
|
|
#include "fwbuilder/RuleElement.h"
|
|
#include "fwbuilder/NAT.h"
|
|
#include "fwbuilder/AddressRange.h"
|
|
#include "fwbuilder/IPService.h"
|
|
#include "fwbuilder/ICMPService.h"
|
|
#include "fwbuilder/TCPService.h"
|
|
#include "fwbuilder/UDPService.h"
|
|
#include "fwbuilder/CustomService.h"
|
|
#include "fwbuilder/TagService.h"
|
|
#include "fwbuilder/Cluster.h"
|
|
#include "fwbuilder/Host.h"
|
|
#include "fwbuilder/FailoverClusterGroup.h"
|
|
#include "fwbuilder/Network.h"
|
|
#include "fwbuilder/Interface.h"
|
|
#include "fwbuilder/IPv4.h"
|
|
#include "fwbuilder/IPv6.h"
|
|
#include "fwbuilder/Firewall.h"
|
|
#include "fwbuilder/AddressTable.h"
|
|
#include "fwbuilder/DNSName.h"
|
|
|
|
#include "config.h"
|
|
|
|
#include <QString>
|
|
#include <QRegExp>
|
|
|
|
#include <algorithm>
|
|
#include <functional>
|
|
#include <iomanip>
|
|
#include <iostream>
|
|
#include <cstring>
|
|
|
|
#include <assert.h>
|
|
#include <ctype.h>
|
|
|
|
using namespace libfwbuilder;
|
|
using namespace fwcompiler;
|
|
using namespace std;
|
|
|
|
struct subnetInfo {
|
|
Interface *iface;
|
|
IPv4 *ipv4;
|
|
int nmlength;
|
|
subnetInfo() { iface=NULL; ipv4=NULL; nmlength=0; }
|
|
subnetInfo(Interface *i,IPv4 *a,int n) { iface=i; ipv4=a; nmlength=n; }
|
|
};
|
|
|
|
|
|
#if 0
|
|
static int chain_no=0;
|
|
#endif
|
|
|
|
static std::map<std::string,int> tmp_chain_no;
|
|
static std::list<std::string> standard_chains;
|
|
|
|
const std::list<std::string>& NATCompiler_ipt::getStandardChains()
|
|
{
|
|
if (standard_chains.size()==0)
|
|
{
|
|
standard_chains.push_back("POSTROUTING");
|
|
standard_chains.push_back("PREROUTING");
|
|
standard_chains.push_back("SNAT");
|
|
standard_chains.push_back("DNAT");
|
|
standard_chains.push_back("MASQUERADE");
|
|
standard_chains.push_back("REDIRECT");
|
|
standard_chains.push_back("NETMAP");
|
|
standard_chains.push_back("LOG");
|
|
standard_chains.push_back("MARK");
|
|
standard_chains.push_back("ACCEPT");
|
|
standard_chains.push_back("REJECT");
|
|
standard_chains.push_back("DROP");
|
|
standard_chains.push_back("RETURN");
|
|
standard_chains.push_back("OUTPUT");
|
|
}
|
|
return standard_chains;
|
|
}
|
|
|
|
|
|
string NATCompiler_ipt::myPlatformName() { return "iptables"; }
|
|
|
|
string NATCompiler_ipt::getInterfaceVarName(FWObject *iface, bool v6)
|
|
{
|
|
ostringstream ostr;
|
|
string iname=iface->getName();
|
|
string::size_type p1;
|
|
while ( (p1=iname.find("."))!=string::npos) iname=iname.replace(p1,1,"_");
|
|
ostr << "i_" << iname;
|
|
if (v6) ostr << "_v6";
|
|
return ostr.str();
|
|
}
|
|
|
|
string NATCompiler_ipt::getAddressTableVarName(FWObject *at)
|
|
{
|
|
ostringstream ostr;
|
|
string name=at->getName();
|
|
string::size_type p1;
|
|
const char *bad_shell_chars = " !#$&*()-+=\\|{}[]?<>,.";
|
|
for (const char *cptr=bad_shell_chars; *cptr; cptr++)
|
|
{
|
|
while ( (p1=name.find(*cptr))!=string::npos)
|
|
name=name.replace(p1,1,"_");
|
|
}
|
|
ostr << "at_" << name;
|
|
return ostr.str();
|
|
}
|
|
|
|
string NATCompiler_ipt::getNewTmpChainName(NATRule *rule)
|
|
{
|
|
std::ostringstream str;
|
|
string chain_id=rule->getUniqueId();
|
|
int n=tmp_chain_no[chain_id];
|
|
|
|
str << "C" << chain_id;
|
|
str << "." << setw(1) << setfill('0') << n;
|
|
|
|
n++;
|
|
tmp_chain_no[chain_id]=n;
|
|
return str.str();
|
|
|
|
#if 0
|
|
std::ostringstream str;
|
|
str << "ntmp" << setw(3) << setfill('0') << chain_no;
|
|
chain_no++;
|
|
return str.str();
|
|
#endif
|
|
}
|
|
|
|
string NATCompiler_ipt::debugPrintRule(Rule *r)
|
|
{
|
|
NATRule *rule = NATRule::cast(r);
|
|
string iface_name = rule->getInterfaceStr();
|
|
|
|
return NATCompiler::debugPrintRule(rule)+
|
|
" " + FWObjectDatabase::getStringId(rule->getInterfaceId()) +
|
|
" c=" + rule->getStr("ipt_chain") +
|
|
" t=" + rule->getStr("ipt_target") +
|
|
" (type="+rule->getRuleTypeAsString()+")" +
|
|
" intf=" + iface_name;
|
|
}
|
|
|
|
void NATCompiler_ipt::verifyPlatform()
|
|
{
|
|
string family = Resources::platform_res[fw->getStr("platform")]->
|
|
getResourceStr("/FWBuilderResources/Target/family");
|
|
|
|
if (family != myPlatformName())
|
|
abort("Unsupported platform " + fw->getStr("platform") +
|
|
" (family " + family + ")");
|
|
}
|
|
|
|
int NATCompiler_ipt::prolog()
|
|
{
|
|
verifyPlatform();
|
|
|
|
// initialize counters for the standard chains
|
|
for (list<string>::const_iterator i =
|
|
NATCompiler_ipt::getStandardChains().begin();
|
|
i != NATCompiler_ipt::getStandardChains().end(); ++i)
|
|
{
|
|
chain_usage_counter[*i] = 1;
|
|
}
|
|
|
|
int n = NATCompiler::prolog();
|
|
|
|
if ( n>0 )
|
|
{
|
|
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()) iface->setBool("use_var_address",true);
|
|
}
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
|
|
void NATCompiler_ipt::_expandInterface(Interface *iface,
|
|
std::list<FWObject*> &ol)
|
|
{
|
|
std::list<FWObject*> nol;
|
|
|
|
Compiler::_expandInterface(iface,ol);
|
|
|
|
physAddress *pa=iface->getPhysicalAddress();
|
|
/*
|
|
* we use physAddress only if Host option "use_mac_addr_filter" of the
|
|
* parent Host object is true
|
|
*/
|
|
FWObject *p;
|
|
FWOptions *hopt;
|
|
p=iface->getParent();
|
|
bool use_mac= (Host::cast(p)!=NULL &&
|
|
(hopt=Host::cast(p)->getOptionsObject())!=NULL &&
|
|
hopt->getBool("use_mac_addr_filter") );
|
|
|
|
/*
|
|
* Compiler::_expandInterface picks all IPv4 objects under Interface;
|
|
* it can also put interface itself into the list ol.
|
|
*/
|
|
for (std::list<FWObject*>::iterator j=ol.begin(); j!=ol.end(); j++)
|
|
{
|
|
if (physAddress::cast(*j)!=NULL) continue;
|
|
|
|
//const InetAddrMask *ipv4 = Address::cast(*j)->getAddressObjectInetAddrMask();
|
|
const InetAddr *ip_addr = Address::cast(*j)->getAddressPtr();
|
|
const InetAddr *ip_netm = Address::cast(*j)->getNetmaskPtr();
|
|
|
|
|
|
if (ip_addr!=NULL && use_mac && pa!=NULL)
|
|
{
|
|
combinedAddress *ca = new combinedAddress(dbcopy,true);
|
|
dbcopy->add(ca);
|
|
dbcopy->addToIndex(ca);
|
|
ca->setName( "CA("+iface->getName()+")" );
|
|
ca->setAddress( *ip_addr );
|
|
ca->setNetmask( *ip_netm );
|
|
ca->setPhysAddress( pa->getPhysAddress() );
|
|
nol.push_back(ca);
|
|
} else
|
|
nol.push_back(*j); // if this is not IPv4, or we do not need to deal with MAC address
|
|
}
|
|
ol.clear();
|
|
ol=nol;
|
|
}
|
|
|
|
bool compare_addresses_ptr(const InetAddr* a1, const InetAddr* a2)
|
|
{
|
|
return (*a1 < *a2);
|
|
}
|
|
|
|
|
|
/*
|
|
* call this processor after classifyNATRules
|
|
*/
|
|
bool NATCompiler_ipt::ConvertLoadBalancingRules::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
tmp_queue.push_back(rule);
|
|
|
|
if (rule->getRuleType()==NATRule::LB)
|
|
{
|
|
RuleElementTDst *tdst=rule->getTDst(); assert(tdst);
|
|
|
|
list<const InetAddr*> al;
|
|
for(list<FWObject*>::iterator i=tdst->begin(); i!=tdst->end(); i++)
|
|
{
|
|
FWObject *o= *i;
|
|
FWObject *obj = NULL;
|
|
if (FWReference::cast(o)!=NULL)
|
|
obj=FWReference::cast(o)->getPointer();
|
|
//const InetAddrMask *a = Address::cast(obj)->getAddressObjectInetAddrMask();
|
|
const InetAddr *ip_addr = Address::cast(obj)->getAddressPtr();
|
|
al.push_back( ip_addr );
|
|
}
|
|
|
|
al.sort(compare_addresses_ptr);
|
|
|
|
const InetAddr* a1 = al.front();
|
|
list<const InetAddr*>::iterator j=al.begin();
|
|
j++;
|
|
|
|
for ( ; j!=al.end(); j++)
|
|
{
|
|
/* I use temporary AddressRange object here because it takes care of
|
|
* big endian/little endian conversion for me
|
|
*/
|
|
AddressRange tar;
|
|
tar.setRangeStart( *a1 );
|
|
tar.setRangeEnd( *(*j) );
|
|
if ( tar.dimension() != 2 )
|
|
{
|
|
compiler->abort(
|
|
rule,
|
|
"Non-contiguous address range in "
|
|
"Translated Destination in load balancing NAT rule");
|
|
}
|
|
a1 = *j;
|
|
}
|
|
|
|
AddressRange *ar = compiler->dbcopy->createAddressRange();
|
|
ar->setRangeStart( *(al.front()) );
|
|
ar->setRangeEnd( *(al.back()) );
|
|
ar->setName(string("%")+al.front()->toString()
|
|
+"-"+al.back()->toString()+"%" );
|
|
compiler->dbcopy->add(ar,false);
|
|
tdst->clearChildren();
|
|
tdst->addRef(ar);
|
|
|
|
rule->setRuleType(NATRule::DNAT);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* This processor should be called after classifyNATRule. Should call
|
|
* classifyNATRule after this processor again.
|
|
*
|
|
* This algorithm is very much specific to iptables. Platforms where
|
|
* this simple algorithm for SDNAT rules is not appropriate, should
|
|
* either implement equivalent of this processor using different
|
|
* algorithm, or should catch SDNAT rules and abort in their own
|
|
* verifyNATRule processor.
|
|
*/
|
|
bool NATCompiler_ipt::splitSDNATRule::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
if ( rule->getRuleType()==NATRule::SDNAT)
|
|
{
|
|
// RuleElementOSrc *osrc;
|
|
RuleElementODst *odst;
|
|
RuleElementOSrv *osrv;
|
|
RuleElementTSrc *tsrc;
|
|
RuleElementTDst *tdst;
|
|
RuleElementTSrv *tsrv;
|
|
|
|
bool tsrv_translates_src_port = false;
|
|
bool tsrv_translates_dst_port = false;
|
|
|
|
Service *osrv_obj = compiler->getFirstOSrv(rule);
|
|
Service *tsrv_obj = compiler->getFirstTSrv(rule);
|
|
|
|
if (TCPUDPService::cast(osrv_obj) && TCPUDPService::cast(tsrv_obj))
|
|
{
|
|
TCPUDPService *tu_osrv = TCPUDPService::cast(osrv_obj);
|
|
TCPUDPService *tu_tsrv = TCPUDPService::cast(tsrv_obj);
|
|
|
|
tsrv_translates_src_port =
|
|
(tu_tsrv->getSrcRangeStart() != 0 && tu_tsrv->getDstRangeStart() == 0);
|
|
tsrv_translates_dst_port =
|
|
(tu_tsrv->getSrcRangeStart() == 0 && tu_tsrv->getDstRangeStart() != 0);
|
|
|
|
if (tsrv_translates_dst_port &&
|
|
tu_osrv->getDstRangeStart() == tu_tsrv->getDstRangeStart() &&
|
|
tu_osrv->getDstRangeEnd() == tu_tsrv->getDstRangeEnd())
|
|
tsrv_translates_dst_port = false; // osrv and tsrv define the same ports
|
|
|
|
if (tsrv_translates_src_port &&
|
|
tu_osrv->getSrcRangeStart() == tu_tsrv->getSrcRangeStart() &&
|
|
tu_osrv->getSrcRangeEnd() == tu_tsrv->getSrcRangeEnd())
|
|
tsrv_translates_src_port = false; // osrv and tsrv define the same ports
|
|
}
|
|
|
|
/* first rule translates destination and may translate service (depends
|
|
* on the original rule). Set type to Unknown because this may become
|
|
* DNAT or DNetNat - we will decide later.
|
|
*/
|
|
NATRule *r = compiler->dbcopy->createNATRule();
|
|
r->duplicate(rule);
|
|
compiler->temp_ruleset->add(r);
|
|
r->setRuleType(NATRule::Unknown);
|
|
|
|
tsrc = r->getTSrc();
|
|
tsrc->clearChildren();
|
|
tsrc->setAnyElement();
|
|
|
|
/* this rule translates destination and can't deal with source port
|
|
* translation. Leave that to the second rule
|
|
*/
|
|
if (tsrv_translates_src_port)
|
|
{
|
|
tsrv = r->getTSrv();
|
|
tsrv->clearChildren();
|
|
tsrv->setAnyElement();
|
|
}
|
|
|
|
tmp_queue.push_back(r);
|
|
|
|
/* the second rule translates source and uses translated object in
|
|
* ODst. Since the service could have been translated by the first
|
|
* rule, we use TSrv in OSrv
|
|
*/
|
|
r = compiler->dbcopy->createNATRule();
|
|
r->duplicate(rule);
|
|
compiler->temp_ruleset->add(r);
|
|
r->setRuleType(NATRule::Unknown);
|
|
|
|
/* if original rule involved negation in ODst, it should be processed
|
|
* in the first of the two rules we create for SDNAT. Negation in OSrc
|
|
* must be processed in both rules since the first rule does not
|
|
* change OSrc
|
|
*/
|
|
|
|
odst=r->getODst();
|
|
odst->setNeg(false);
|
|
|
|
odst->clearChildren();
|
|
for (FWObject::iterator i=rule->getTDst()->begin(); i!=rule->getTDst()->end(); i++)
|
|
odst->add( *i );
|
|
|
|
if ( ! rule->getTSrv()->isAny())
|
|
{
|
|
/*
|
|
* If the first rule in the pair translated service and
|
|
* changed destination port, we need to match it in the
|
|
* second rule to only trsnslate source in the packets
|
|
* that have been processed by the first rule. However
|
|
* this only applies to the case when destination port has
|
|
* been translated because the first rule uses DNAT which
|
|
* can only translate dest. port. So, if TSrv has zero
|
|
* dest. port range but non-zero source port range, we
|
|
* should not match it here because in this case no
|
|
* dest. port translation occurs. If TSrv translates both
|
|
* source and destination ports, we create new TCP(UDP)
|
|
* service object with only dest. port part and use it to
|
|
* match.
|
|
*/
|
|
Service *tsrv = compiler->getFirstTSrv(rule);
|
|
TCPUDPService *tu_tsrv = TCPUDPService::cast(tsrv);
|
|
if (tu_tsrv && tu_tsrv->getDstRangeStart() != 0)
|
|
{
|
|
TCPUDPService *match_service = NULL;
|
|
if (tu_tsrv->getSrcRangeStart() == 0)
|
|
{
|
|
// no source port tranlsation
|
|
match_service = tu_tsrv;
|
|
} else
|
|
{
|
|
// both source and dest port translation occurs
|
|
match_service = TCPUDPService::cast(
|
|
compiler->dbcopy->create(tsrv->getTypeName()));
|
|
match_service->setName(tsrv->getName() + "_dport");
|
|
compiler->dbcopy->add(match_service);
|
|
match_service->setDstRangeStart(tu_tsrv->getDstRangeStart());
|
|
match_service->setDstRangeEnd(tu_tsrv->getDstRangeEnd());
|
|
}
|
|
osrv = r->getOSrv();
|
|
osrv->clearChildren();
|
|
osrv->addRef(match_service);
|
|
}
|
|
}
|
|
|
|
tdst = r->getTDst();
|
|
tdst->clearChildren();
|
|
tdst->setAnyElement();
|
|
|
|
if (tsrv_translates_dst_port)
|
|
{
|
|
tsrv = r->getTSrv();
|
|
tsrv->clearChildren();
|
|
tsrv->setAnyElement();
|
|
}
|
|
|
|
tmp_queue.push_back(r);
|
|
}
|
|
else
|
|
tmp_queue.push_back(rule);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool NATCompiler_ipt::VerifyRules::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
RuleElementOSrc *osrc=rule->getOSrc(); assert(osrc);
|
|
RuleElementODst *odst=rule->getODst(); assert(odst);
|
|
RuleElementOSrv *osrv=rule->getOSrv(); assert(osrv);
|
|
|
|
RuleElementTSrc *tsrc=rule->getTSrc(); assert(tsrc);
|
|
RuleElementTDst *tdst=rule->getTDst(); assert(tdst);
|
|
RuleElementTSrv *tsrv=rule->getTSrv(); assert(tsrv);
|
|
|
|
if (tsrc->getNeg())
|
|
{
|
|
compiler->abort(
|
|
rule,
|
|
"Can not use negation in translated source ");
|
|
return true;
|
|
}
|
|
|
|
if (tdst->getNeg())
|
|
{
|
|
compiler->abort(
|
|
rule,
|
|
"Can not use negation in translated destination.");
|
|
return true;
|
|
}
|
|
|
|
if (tsrv->getNeg())
|
|
{
|
|
compiler->abort(
|
|
rule,
|
|
"Can not use negation in translated service.");
|
|
return true;
|
|
}
|
|
|
|
if (tsrv->size()!=1)
|
|
{
|
|
compiler->abort(
|
|
rule,
|
|
"Translated service should be 'Original' or should contain single object.");
|
|
return true;
|
|
}
|
|
|
|
if ( Group::cast( compiler->getFirstTSrv(rule) )!=NULL)
|
|
{
|
|
compiler->abort(
|
|
rule,
|
|
"Can not use group in translated service.");
|
|
return true;
|
|
}
|
|
|
|
|
|
if (rule->getRuleType()==NATRule::LB)
|
|
{
|
|
compiler->abort(
|
|
rule,
|
|
"Load balancing rules are not supported.");
|
|
return true;
|
|
}
|
|
|
|
// Note that in -xt mode and in single rule compile compiler->abort
|
|
// does not really abort processing
|
|
if (rule->getRuleType()==NATRule::NATBranch)
|
|
{
|
|
RuleSet *branch = rule->getBranch();
|
|
if (branch == NULL)
|
|
{
|
|
compiler->abort(
|
|
rule,
|
|
"Action 'Branch' needs NAT rule set to point to");
|
|
return true;
|
|
} else
|
|
{
|
|
if (!NAT::isA(branch))
|
|
{
|
|
compiler->abort(
|
|
rule,
|
|
"Action 'Branch' must point to a NAT rule set "
|
|
"(points to " + branch->getTypeName() + ")");
|
|
return true;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if (rule->getRuleType()==NATRule::SNAT )
|
|
{
|
|
FWObject *o1 = FWReference::getObject(tsrc->front());
|
|
if ( ! tsrc->isAny() && Network::cast(o1)!=NULL)
|
|
{
|
|
compiler->abort(
|
|
rule,
|
|
"Can not use network object in translated source.");
|
|
return true;
|
|
}
|
|
|
|
if (Interface::isA(o1) && Interface::cast(o1)->isUnnumbered())
|
|
{
|
|
compiler->abort(
|
|
rule,
|
|
"Can not use unnumbered interface in "
|
|
"Translated Source of a Source translation rule.");
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|
|
if (rule->getRuleType()==NATRule::SNetnat && !tsrc->isAny() )
|
|
{
|
|
Network *a1=Network::cast(compiler->getFirstOSrc(rule));
|
|
Network *a2=Network::cast(compiler->getFirstTSrc(rule));
|
|
if ( a1==NULL || a2==NULL ||
|
|
a1->getNetmaskPtr()->getLength() != a2->getNetmaskPtr()->getLength() )
|
|
{
|
|
compiler->abort(
|
|
rule,
|
|
"Original and translated source should both be networks of the same size.");
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|
|
if (rule->getRuleType()==NATRule::DNetnat && !tsrc->isAny() )
|
|
{
|
|
Network *a1=Network::cast(compiler->getFirstODst(rule));
|
|
Network *a2=Network::cast(compiler->getFirstTDst(rule));
|
|
if ( a1==NULL || a2==NULL ||
|
|
a1->getNetmaskPtr()->getLength() != a2->getNetmaskPtr()->getLength() )
|
|
{
|
|
compiler->abort(
|
|
rule,
|
|
"Original and translated destination should both be networks of the same size .");
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|
|
tmp_queue.push_back(rule);
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* this should be called only after splitServices, so that we have
|
|
* objects of the same type in OSrv and either "any" or a single
|
|
* object in TSrv
|
|
*/
|
|
bool NATCompiler_ipt::VerifyRules2::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
if (rule->getRuleType()!= NATRule::Return)
|
|
{
|
|
RuleElementOSrv *osrv=rule->getOSrv(); assert(osrv);
|
|
RuleElementTSrv *tsrv=rule->getTSrv(); assert(tsrv);
|
|
|
|
Service *s1=compiler->getFirstOSrv(rule);
|
|
Service *s2=compiler->getFirstTSrv(rule);
|
|
|
|
if (osrv->isAny() && ! tsrv->isAny())
|
|
{
|
|
compiler->abort(
|
|
rule,
|
|
"Can not use service object in Translated Service if Original Service is 'Any'.");
|
|
return true;
|
|
}
|
|
|
|
if (!tsrv->isAny() && s1->getProtocolNumber()!=s2->getProtocolNumber())
|
|
{
|
|
compiler->abort(
|
|
rule,
|
|
"Translated Service should be either 'Original' or should contain object of the same type as Original Service.");
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|
|
tmp_queue.push_back(rule);
|
|
return true;
|
|
}
|
|
|
|
bool NATCompiler_ipt::convertToAtomicportForOSrv::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
if (rule->getOSrv()->size()>1 && ! rule->getTSrv()->isAny())
|
|
{
|
|
RuleElementOSrv *osrv=rule->getOSrv(); assert(osrv);
|
|
|
|
for (FWObject::iterator i1=osrv->begin(); i1!=osrv->end(); ++i1)
|
|
{
|
|
NATRule *r = compiler->dbcopy->createNATRule();
|
|
r->duplicate(rule);
|
|
compiler->temp_ruleset->add(r);
|
|
|
|
FWObject *s;
|
|
|
|
s=r->getOSrv(); assert(s);
|
|
s->clearChildren();
|
|
s->add( *i1 );
|
|
|
|
tmp_queue.push_back(r);
|
|
}
|
|
}
|
|
else
|
|
tmp_queue.push_back(rule);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool NATCompiler_ipt::portTranslationRules::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
Address *odst=compiler->getFirstODst(rule);
|
|
// Service *osrv=compiler->getFirstOSrv(rule);
|
|
|
|
Address *tsrc=compiler->getFirstTSrc(rule);
|
|
Address *tdst=compiler->getFirstTDst(rule);
|
|
Service *tsrv=compiler->getFirstTSrv(rule);
|
|
|
|
if (rule->getRuleType() == NATRule::DNAT &&
|
|
tsrc->isAny() && tdst->isAny() && ! tsrv->isAny() && odst->getId()==compiler->fw->getId() )
|
|
{
|
|
rule->getTDst()->addRef( odst );
|
|
}
|
|
|
|
tmp_queue.push_back(rule);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool NATCompiler_ipt::specialCaseWithRedirect::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
Address *tdst=compiler->getFirstTDst(rule);
|
|
|
|
/* we consider rule redirect only if TDst is a firewall object */
|
|
if (rule->getRuleType() == NATRule::DNAT && tdst->getId()==compiler->fw->getId())
|
|
rule->setRuleType(NATRule::Redirect);
|
|
|
|
tmp_queue.push_back(rule);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool NATCompiler_ipt::splitOnODst::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
RuleElementODst *odst=rule->getODst(); assert(odst);
|
|
if (rule->getRuleType()==NATRule::DNAT && odst->size()!=1)
|
|
{
|
|
for(list<FWObject*>::iterator i=odst->begin(); i!=odst->end(); ++i)
|
|
{
|
|
FWObject *o= *i;
|
|
if (FWReference::cast(o)!=NULL) o=FWReference::cast(o)->getPointer();
|
|
Address *a=Address::cast( o );
|
|
assert(a);
|
|
|
|
NATRule *r= compiler->dbcopy->createNATRule();
|
|
compiler->temp_ruleset->add(r);
|
|
r->duplicate(rule);
|
|
RuleElementODst *nodst=r->getODst();
|
|
nodst->clearChildren();
|
|
|
|
nodst->addRef( a );
|
|
|
|
tmp_queue.push_back( r );
|
|
}
|
|
} else
|
|
tmp_queue.push_back(rule);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool NATCompiler_ipt::splitOnOSrv::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
RuleElementOSrv *osrv=rule->getOSrv(); assert(osrv);
|
|
if (osrv->size()!=1)
|
|
{
|
|
for(list<FWObject*>::iterator i=osrv->begin(); i!=osrv->end(); ++i)
|
|
{
|
|
FWObject *o= *i;
|
|
if (FWReference::cast(o)!=NULL) o=FWReference::cast(o)->getPointer();
|
|
Service *s=Service::cast( o );
|
|
assert(s);
|
|
|
|
NATRule *r= compiler->dbcopy->createNATRule();
|
|
compiler->temp_ruleset->add(r);
|
|
r->duplicate(rule);
|
|
RuleElementOSrv *nosrv=r->getOSrv();
|
|
nosrv->clearChildren();
|
|
|
|
nosrv->addRef( s );
|
|
|
|
tmp_queue.push_back( r );
|
|
}
|
|
} else
|
|
tmp_queue.push_back(rule);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool NATCompiler_ipt::fillTranslatedSrv::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
tmp_queue.push_back(rule);
|
|
|
|
Service *osrv_o=compiler->getFirstOSrv(rule);
|
|
Service *tsrv_o=compiler->getFirstTSrv(rule);
|
|
|
|
if ( ! osrv_o->isAny() && tsrv_o->isAny() ) {
|
|
RuleElementTSrv *tsrv=rule->getTSrv();
|
|
tsrv->addRef(osrv_o);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool NATCompiler_ipt::addVirtualAddress::processNext()
|
|
{
|
|
FWOptions* options=compiler->fw->getOptionsObject();
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
tmp_queue.push_back(rule);
|
|
|
|
Address *a=NULL;
|
|
|
|
if (rule->getRuleType()==NATRule::SNAT || rule->getRuleType()==NATRule::DNAT)
|
|
{
|
|
if (rule->getRuleType()==NATRule::SNAT)
|
|
a=compiler->getFirstTSrc(rule);
|
|
else
|
|
a=compiler->getFirstODst(rule);
|
|
|
|
if ( ! a->isAny() && ! compiler->complexMatch(a,compiler->fw) &&
|
|
options->getBool("manage_virtual_addr") )
|
|
{
|
|
if (AddressRange::cast(a)!=NULL)
|
|
{
|
|
compiler->warning(
|
|
|
|
rule,
|
|
string("Adding of virtual address for address range is not implemented (object ") +
|
|
a->getName() + ")" );
|
|
} else
|
|
compiler->osconfigurator->addVirtualAddressForNAT( a );
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
if (rule->getRuleType()==NATRule::SNetnat || rule->getRuleType()==NATRule::DNetnat)
|
|
{
|
|
if (rule->getRuleType()==NATRule::SNetnat)
|
|
a=compiler->getFirstTSrc(rule);
|
|
else
|
|
a=compiler->getFirstODst(rule);
|
|
|
|
if ( ! a->isAny() && Network::cast(a) )
|
|
compiler->osconfigurator->addVirtualAddressForNAT( Network::constcast(a) );
|
|
|
|
return true;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool NATCompiler_ipt::splitRuleIfRuleElementIsDynamicInterface::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
RuleElement *re=RuleElement::cast(rule->getFirstByType(re_type));
|
|
int nre=re->size();
|
|
|
|
vector<FWObject*> cl;
|
|
|
|
for(list<FWObject*>::iterator i=re->begin(); nre>1 && i!=re->end(); ++i)
|
|
{
|
|
FWObject *o= *i;
|
|
FWObject *obj = NULL;
|
|
if (FWReference::cast(o)!=NULL) obj=FWReference::cast(o)->getPointer();
|
|
Interface *iface=Interface::cast(obj);
|
|
if (iface!=NULL && !iface->isRegular())
|
|
{
|
|
cl.push_back(o); // can not remove right now because remove invalidates iterator
|
|
nre--;
|
|
|
|
NATRule *new_rule= compiler->dbcopy->createNATRule();
|
|
compiler->temp_ruleset->add(new_rule);
|
|
new_rule->duplicate(rule);
|
|
RuleElement *new_re=RuleElement::cast(new_rule->getFirstByType(re_type));
|
|
new_re->clearChildren();
|
|
new_re->setAnyElement();
|
|
new_re->addRef( iface );
|
|
tmp_queue.push_back(new_rule);
|
|
}
|
|
}
|
|
if (!cl.empty()) {
|
|
for (vector<FWObject*>::iterator i1=cl.begin(); i1!=cl.end(); ++i1)
|
|
re->remove( (*i1) );
|
|
}
|
|
|
|
tmp_queue.push_back(rule);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
bool NATCompiler_ipt::specialCaseWithUnnumberedInterface::dropUnnumberedInterface(RuleElement *re)
|
|
{
|
|
if (re->isAny()) return true;
|
|
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->isUnnumbered() || ifs->isBridgePort())
|
|
) cl.push_back(obj);
|
|
}
|
|
if (!cl.empty())
|
|
{
|
|
for (list<FWObject*>::iterator i1=cl.begin(); i1!=cl.end(); ++i1)
|
|
re->removeRef( (*i1) );
|
|
}
|
|
return (!re->isAny());
|
|
}
|
|
|
|
bool NATCompiler_ipt::specialCaseWithUnnumberedInterface::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
bool keep_rule=true;
|
|
switch (rule->getRuleType()) {
|
|
case NATRule::Masq:
|
|
case NATRule::SNAT:
|
|
keep_rule=dropUnnumberedInterface( rule->getOSrc() );
|
|
break;
|
|
case NATRule::DNAT:
|
|
keep_rule=dropUnnumberedInterface( rule->getODst() );
|
|
break;
|
|
default: ;
|
|
}
|
|
if (keep_rule) tmp_queue.push_back(rule);
|
|
return true;
|
|
}
|
|
|
|
|
|
/*
|
|
* I assume that there is always only one object in ODst, TSrc and TDst
|
|
* rule elements. This should have been assured by inspector VerifyRules
|
|
*/
|
|
bool NATCompiler_ipt::ReplaceFirewallObjectsODst::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
tmp_queue.push_back(rule);
|
|
|
|
list<FWObject*> cl;
|
|
RuleElementODst *rel;
|
|
Address *obj=NULL;
|
|
|
|
switch (rule->getRuleType()) {
|
|
|
|
case NATRule::Masq:
|
|
// case NATRule::Redirect:
|
|
return true;
|
|
default:
|
|
rel=rule->getODst(); assert(rel);
|
|
obj=compiler->getFirstODst(rule); assert(obj!=NULL);
|
|
|
|
if (obj->getId()==compiler->getFwId() )
|
|
{
|
|
|
|
list<FWObject*> l2=compiler->fw->getByType(Interface::TYPENAME);
|
|
for (list<FWObject*>::iterator i=l2.begin(); i!=l2.end(); ++i)
|
|
{
|
|
Interface *interface_=Interface::cast(*i);
|
|
if (! interface_->isLoopback() ) cl.push_back(interface_);
|
|
}
|
|
if ( ! cl.empty() )
|
|
{
|
|
while (rel->size())
|
|
rel->remove( rel->front() );
|
|
|
|
for (FWObject::iterator i1=cl.begin(); i1!=cl.end(); ++i1)
|
|
{
|
|
rel->addRef( *i1 );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* This processor works together with ConvertToAtomicRules and
|
|
* AssignInterfaces. If firewall object is used in TSrc of SNAT rule,
|
|
* it gets replaced with its interfaces. ConvertToAtomicRules slits
|
|
* this rule onto atomic rules, each of which has one interface object
|
|
* in TSrc. AssigInterfaces then assigns each atomic rule to
|
|
* corresponding interface.
|
|
*
|
|
* it seems the simplest way is just to assign SNAT rule to all
|
|
* interfaces if firewall is used in TSrc. This automatically takes
|
|
* care of weird cases where people use address that belongs to subnet
|
|
* of one interface to do translation of packets going out through
|
|
* another interface. Basically, compiler does not have information
|
|
* about routing, so we have no choice but assume the routing can be
|
|
* anything and assign the rule to all interfaces.
|
|
*/
|
|
bool NATCompiler_ipt::ReplaceFirewallObjectsTSrc::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
tmp_queue.push_back(rule);
|
|
|
|
list<FWObject*> cl;
|
|
RuleElementTSrc *rel;
|
|
Address *obj=NULL;
|
|
|
|
switch (rule->getRuleType()) {
|
|
|
|
case NATRule::Masq:
|
|
case NATRule::Redirect: return true;
|
|
|
|
default:
|
|
rel=rule->getTSrc(); assert(rel);
|
|
obj=compiler->getFirstTSrc(rule); assert(obj!=NULL);
|
|
|
|
if (obj->getId()==compiler->getFwId() )
|
|
{
|
|
RuleElementODst *odstrel = rule->getODst();
|
|
Address *odst = compiler->getFirstODst(rule);
|
|
|
|
rel->clearChildren();
|
|
|
|
Interface *odst_iface =
|
|
compiler->findInterfaceFor(odst, compiler->fw);
|
|
|
|
if (!odst->isAny() && odst_iface!=NULL &&
|
|
!odstrel->getBool("single_object_negation"))
|
|
rel->addRef(odst_iface);
|
|
else
|
|
{
|
|
// else use all interfaces except loopback and unnumbered ones
|
|
// also skip interface connected to ODst if single object
|
|
// negation was detected in ODst
|
|
list<FWObject*> l2=compiler->fw->getByType(Interface::TYPENAME);
|
|
for (list<FWObject*>::iterator i=l2.begin(); i!=l2.end(); ++i)
|
|
{
|
|
Interface *iface = Interface::cast(*i);
|
|
if (iface->isLoopback() ||
|
|
iface->isUnnumbered() ||
|
|
iface->isBridgePort() ) continue;
|
|
if (odstrel->getBool("single_object_negation") && odst_iface &&
|
|
odst_iface->getId()==iface->getId()) continue;
|
|
|
|
rel->addRef( *i );
|
|
}
|
|
|
|
for (FWObject::iterator i1=cl.begin(); i1!=cl.end(); ++i1)
|
|
rel->addRef( *i1 );
|
|
|
|
/* it is an error if rule element is empty at this point. this could have
|
|
* happened if all external interfaces are unnumbered */
|
|
if (rel->size()==0)
|
|
{
|
|
char errmsg[1024];
|
|
sprintf(errmsg,
|
|
"Could not find suitable interface for the NAT rule %s. "
|
|
"Perhaps all interfaces are unnumbered?",
|
|
rule->getLabel().c_str() );
|
|
compiler->abort(rule, errmsg);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool NATCompiler_ipt::dynamicInterfaceInODst::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
tmp_queue.push_back(rule);
|
|
|
|
RuleElementODst *odstrel=rule->getODst(); assert(odstrel);
|
|
Address *odst =compiler->getFirstODst(rule);
|
|
if ( ! odstrel->isAny() )
|
|
{
|
|
Interface *iface =Interface::cast(odst);
|
|
if (iface!=NULL && iface->isDyn())
|
|
{
|
|
;
|
|
// iface->setBool("use_var_address",true);
|
|
// odstrel->clearChildren();
|
|
// odstrel->setAnyElement();
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool NATCompiler_ipt::splitMultiSrcAndDst::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
RuleElementOSrv *osrv=rule->getOSrv();
|
|
RuleElementOSrc *osrc=rule->getOSrc();
|
|
RuleElementODst *odst=rule->getODst();
|
|
RuleElementOSrc *rosrc;
|
|
RuleElementODst *rodst;
|
|
|
|
int nosrv=osrv->size();
|
|
int nosrc=osrc->size();
|
|
int nodst=odst->size();
|
|
|
|
/*
|
|
* Return if service is set - svcs my introduce complications and I'm
|
|
* treading carefully here.
|
|
* We don't handle anything thats redirect, MASQ yet - just NONAT,SNAT & DNAT
|
|
* We also check we've got multiple rules to deal with - we can't optimize
|
|
* 1 src with 1 dst ...
|
|
*/
|
|
|
|
if ((nosrv>1 || !(osrv->isAny())) ||
|
|
(nosrc<1 || osrc->isAny()) ||
|
|
(nodst<1 || odst->isAny()) ||
|
|
(nosrc==1 && nodst==1) )
|
|
{
|
|
tmp_queue.push_back(rule);
|
|
return true;
|
|
}
|
|
|
|
switch (rule->getRuleType()) {
|
|
case NATRule::NONAT:
|
|
case NATRule::SNAT:
|
|
case NATRule::DNAT:
|
|
{
|
|
// get old chain name create new chain name
|
|
string new_chain=NATCompiler_ipt::getNewTmpChainName(rule);
|
|
// create new rule
|
|
NATRule *r= compiler->dbcopy->createNATRule();
|
|
compiler->temp_ruleset->add(r);
|
|
r->duplicate(rule);
|
|
// move existing rule onto new chain
|
|
rule->setStr("ipt_chain",new_chain);
|
|
// we've already tested for interface ....
|
|
rule->setInterfaceStr("nil");
|
|
// new rule points to new chain, continues if no match
|
|
r->setStr("ipt_target",new_chain);
|
|
|
|
// Now decide which way round would be best ...
|
|
if (nosrc < nodst)
|
|
{
|
|
rodst=r->getODst(); rodst->clearChildren(); rodst->setAnyElement();
|
|
osrc->clearChildren(); osrc->setAnyElement();
|
|
} else {
|
|
rosrc=r->getOSrc(); rosrc->clearChildren(); rosrc->setAnyElement();
|
|
odst->clearChildren(); odst->setAnyElement();
|
|
}
|
|
|
|
tmp_queue.push_back(r);
|
|
|
|
}
|
|
break;
|
|
default: ;
|
|
}
|
|
|
|
tmp_queue.push_back(rule);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool NATCompiler_ipt::dynamicInterfaceInTSrc::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
FWOptions *ruleopt =rule->getOptionsObject();
|
|
bool use_snat = ruleopt->getBool("ipt_use_snat_instead_of_masq");
|
|
|
|
tmp_queue.push_back(rule);
|
|
|
|
Address *tsrc = compiler->getFirstTSrc(rule);
|
|
|
|
if (rule->getRuleType()==NATRule::SNAT &&
|
|
Interface::cast(tsrc)!=NULL && !Interface::cast(tsrc)->isRegular())
|
|
{
|
|
if (use_snat)
|
|
{
|
|
// Emulate SNAT with dynamic interface
|
|
//tsrc->setBool("use_var_address", true);
|
|
} else
|
|
{
|
|
rule->setRuleType(NATRule::Masq);
|
|
if (rule->getStr("ipt_target")=="" || rule->getStr("ipt_target")=="SNAT")
|
|
rule->setStr("ipt_target", "MASQUERADE");
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* unlike standard inspector addressRanges in the base class NATCompiler,
|
|
* this one does not expand address ranges in TSrc and TDst because
|
|
* iptables supports ranges in those rule elements
|
|
*/
|
|
bool NATCompiler_ipt::ExpandAddressRanges::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
tmp_queue.push_back(rule);
|
|
|
|
RuleElement *rel;
|
|
|
|
rel=rule->getOSrc(); assert(rel);
|
|
compiler->_expandAddressRanges(rule,rel);
|
|
rel=rule->getODst(); assert(rel);
|
|
compiler->_expandAddressRanges(rule,rel);
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
void NATCompiler_ipt::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->isChildOf(compiler->fw))
|
|
{
|
|
#if 0
|
|
cerr << "NATCompiler_ipt::checkForDynamicInterfacesOfOtherObjects" << endl;
|
|
cerr << "ifs: " << endl;
|
|
ifs->dump(true,true);
|
|
cerr << endl;
|
|
cerr << "fw: " << endl;
|
|
compiler->fw->dump(true,true);
|
|
cerr << endl;
|
|
#endif
|
|
char errstr[2048];
|
|
sprintf(errstr, "Can not build rule using dynamic interface '%s' "
|
|
"of the object '%s' because its address in unknown.",
|
|
ifs->getName().c_str(),
|
|
ifs->getParent()->getName().c_str());
|
|
|
|
compiler->abort(rule, errstr);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool NATCompiler_ipt::checkForDynamicInterfacesOfOtherObjects::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
findDynamicInterfaces( rule->getOSrc() , rule );
|
|
findDynamicInterfaces( rule->getODst() , rule );
|
|
findDynamicInterfaces( rule->getTSrc() , rule );
|
|
findDynamicInterfaces( rule->getTDst() , rule );
|
|
|
|
tmp_queue.push_back(rule);
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
bool NATCompiler_ipt::splitServices::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
RuleElementOSrv *srv=rule->getOSrv();
|
|
|
|
if (srv->size()==1) {
|
|
tmp_queue.push_back(rule);
|
|
return true;
|
|
}
|
|
|
|
map<int, list<Service*> > services;
|
|
|
|
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);
|
|
|
|
int proto=s->getProtocolNumber();
|
|
services[proto].push_back(s);
|
|
}
|
|
|
|
for (map<int, list<Service*> >::iterator i=services.begin(); i!=services.end(); i++) {
|
|
list<Service*> &sl=(*i).second;
|
|
|
|
NATRule *r= compiler->dbcopy->createNATRule();
|
|
compiler->temp_ruleset->add(r);
|
|
r->duplicate(rule);
|
|
RuleElementOSrv *nsrv=r->getOSrv();
|
|
nsrv->clearChildren();
|
|
|
|
for (list<Service*>::iterator j=sl.begin(); j!=sl.end(); j++) {
|
|
nsrv->addRef( (*j) );
|
|
}
|
|
|
|
tmp_queue.push_back(r);
|
|
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool NATCompiler_ipt::separatePortRanges::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
RuleElementOSrv *rel= rule->getOSrv();
|
|
|
|
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=TCPUDPService::cast(s)->getSrcRangeStart();
|
|
int sre=TCPUDPService::cast(s)->getSrcRangeEnd();
|
|
int drs=TCPUDPService::cast(s)->getDstRangeStart();
|
|
int dre=TCPUDPService::cast(s)->getDstRangeEnd();
|
|
|
|
compiler->normalizePortRange(srs,sre);
|
|
compiler->normalizePortRange(drs,dre);
|
|
|
|
if (srs!=sre || drs!=dre) {
|
|
NATRule *r= compiler->dbcopy->createNATRule();
|
|
compiler->temp_ruleset->add(r);
|
|
r->duplicate(rule);
|
|
RuleElementOSrv *nsrv=r->getOSrv();
|
|
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 NATCompiler_ipt::separateSourcePorts::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
RuleElementOSrv *rel= rule->getOSrv();
|
|
|
|
if (rel->size()==1) {
|
|
tmp_queue.push_back(rule);
|
|
return true;
|
|
}
|
|
|
|
NATRule *rule_4_src_ports=NULL;
|
|
RuleElementOSrv *nsrv = NULL;
|
|
|
|
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=TCPUDPService::cast(s)->getSrcRangeStart();
|
|
int sre=TCPUDPService::cast(s)->getSrcRangeEnd();
|
|
|
|
compiler->normalizePortRange(srs,sre);
|
|
|
|
if (srs!=0 || sre!=0)
|
|
{
|
|
if (rule_4_src_ports==NULL)
|
|
{
|
|
rule_4_src_ports= compiler->dbcopy->createNATRule();
|
|
compiler->temp_ruleset->add(rule_4_src_ports);
|
|
rule_4_src_ports->duplicate(rule);
|
|
nsrv=rule_4_src_ports->getOSrv();
|
|
nsrv->clearChildren();
|
|
tmp_queue.push_back(rule_4_src_ports);
|
|
}
|
|
assert(nsrv!=NULL);
|
|
nsrv->addRef( s );
|
|
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 NATCompiler_ipt::separateSourceAndDestinationPorts::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
RuleElementOSrv *rel= rule->getOSrv();
|
|
|
|
if (rel->size()==1) {
|
|
tmp_queue.push_back(rule);
|
|
return true;
|
|
}
|
|
|
|
NATRule *nrule=NULL;
|
|
RuleElementOSrv *nsrv = NULL;
|
|
|
|
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=TCPUDPService::cast(s)->getSrcRangeStart();
|
|
int sre=TCPUDPService::cast(s)->getSrcRangeEnd();
|
|
int drs=TCPUDPService::cast(s)->getDstRangeStart();
|
|
int dre=TCPUDPService::cast(s)->getDstRangeEnd();
|
|
|
|
compiler->normalizePortRange(srs,sre);
|
|
compiler->normalizePortRange(drs,dre);
|
|
|
|
if ( (srs!=0 || sre!=0) && (drs!=0 || dre!=0) )
|
|
{
|
|
if (nrule==NULL)
|
|
{
|
|
nrule= compiler->dbcopy->createNATRule();
|
|
compiler->temp_ruleset->add(nrule);
|
|
nrule->duplicate(rule);
|
|
nsrv=nrule->getOSrv();
|
|
nsrv->clearChildren();
|
|
tmp_queue.push_back(nrule);
|
|
}
|
|
assert(nsrv!=NULL);
|
|
nsrv->addRef( s );
|
|
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 NATCompiler_ipt::prepareForMultiport::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
RuleElementOSrv *rel= rule->getOSrv();
|
|
Service *srv= compiler->getFirstOSrv(rule);
|
|
|
|
if (rel->size()==1) {
|
|
tmp_queue.push_back(rule);
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* processor splitServices should have been called eariler, so now all
|
|
* services in Srv are of the same type
|
|
*/
|
|
if (TCPService::isA(srv) || UDPService::isA(srv))
|
|
{
|
|
rule->setBool("ipt_multiport",true);
|
|
/* make sure we have no more than 15 ports */
|
|
if (rel->size()>15)
|
|
{
|
|
int n=0;
|
|
NATRule *r;
|
|
RuleElementOSrv *nsrv=NULL;
|
|
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);
|
|
|
|
if (n==0)
|
|
{
|
|
r= compiler->dbcopy->createNATRule();
|
|
compiler->temp_ruleset->add(r);
|
|
r->duplicate(rule);
|
|
nsrv=r->getOSrv();
|
|
nsrv->clearChildren();
|
|
tmp_queue.push_back(r);
|
|
}
|
|
assert(nsrv!=NULL);
|
|
nsrv->addRef( s );
|
|
if (++n>=15) n=0;
|
|
}
|
|
} else {
|
|
tmp_queue.push_back(rule);
|
|
}
|
|
|
|
// tmp_queue.push_back(rule);
|
|
} else
|
|
tmp_queue.push_back(rule);
|
|
return true;
|
|
}
|
|
|
|
bool NATCompiler_ipt::splitMultipleICMP::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
RuleElementOSrv *rel= rule->getOSrv();
|
|
Service *srv= compiler->getFirstOSrv(rule);
|
|
|
|
if (rel->size()==1) {
|
|
tmp_queue.push_back(rule);
|
|
return true;
|
|
}
|
|
|
|
if (ICMPService::isA(srv))
|
|
{
|
|
NATRule *r;
|
|
RuleElementOSrv *nsrv;
|
|
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);
|
|
|
|
r= compiler->dbcopy->createNATRule();
|
|
compiler->temp_ruleset->add(r);
|
|
r->duplicate(rule);
|
|
nsrv=r->getOSrv();
|
|
nsrv->clearChildren();
|
|
nsrv->addRef( s );
|
|
tmp_queue.push_back(r);
|
|
}
|
|
} else
|
|
tmp_queue.push_back(rule);
|
|
return true;
|
|
}
|
|
|
|
bool NATCompiler_ipt::singleObjectNegation::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
RuleElement *rel = RuleElement::cast(rule->getFirstByType(re_type));
|
|
assert(rel);
|
|
|
|
if (rel->getNeg() && rel->size()==1)
|
|
{
|
|
FWObject *o = rel->front();
|
|
if (FWReference::cast(o)!=NULL) o=FWReference::cast(o)->getPointer();
|
|
Address *reladdr = Address::cast(o);
|
|
if ( reladdr && reladdr->countInetAddresses(true)==1 &&
|
|
!compiler->complexMatch(reladdr, compiler->fw))
|
|
{
|
|
rel->setNeg(false);
|
|
rel->setBool("single_object_negation", true);
|
|
}
|
|
}
|
|
|
|
tmp_queue.push_back(rule);
|
|
return true;
|
|
}
|
|
|
|
bool NATCompiler_ipt::doOSrcNegation::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
RuleElementOSrc *osrcrel=rule->getOSrc();
|
|
|
|
/* ! A B C */
|
|
|
|
if (osrcrel->getNeg()) {
|
|
NATRule *r;
|
|
RuleElementOSrc *nsrc;
|
|
RuleElementODst *ndst;
|
|
RuleElementOSrv *nsrv;
|
|
|
|
RuleElementTSrc *ntsrc;
|
|
RuleElementTDst *ntdst;
|
|
RuleElementTSrv *ntsrv;
|
|
|
|
string new_chain = NATCompiler_ipt::getNewTmpChainName(rule);
|
|
osrcrel->setNeg(false);
|
|
/*
|
|
* negation in OSrc :
|
|
*
|
|
* CHAIN !A B C RULE_TYPE TARGET
|
|
*-----------------------------------------------
|
|
* ----- any B C SNAT/DNAT TMP_CHAIN
|
|
* TMP_CHAIN A any any RETURN RETURN
|
|
* TMP_CHAIN any any C SNAT/DNAT ---------
|
|
*/
|
|
r= compiler->dbcopy->createNATRule();
|
|
compiler->temp_ruleset->add(r);
|
|
r->duplicate(rule);
|
|
nsrc=r->getOSrc(); nsrc->clearChildren(); nsrc->setAnyElement();
|
|
// ntsrc=r->getTSrc(); ntsrc->clearChildren(); ntsrc->setAnyElement();
|
|
// ntdst=r->getTDst(); ntdst->clearChildren(); ntdst->setAnyElement();
|
|
// r->setRuleType(NATRule::Continue);
|
|
r->setStr("ipt_target",new_chain);
|
|
// r->setBool("rule_added_for_osrc_neg",true);
|
|
tmp_queue.push_back(r);
|
|
|
|
/* TMP_CHAIN A any any RETURN */
|
|
r= compiler->dbcopy->createNATRule();
|
|
compiler->temp_ruleset->add(r);
|
|
r->duplicate(rule);
|
|
ndst=r->getODst(); ndst->clearChildren(); ndst->setAnyElement();
|
|
nsrv=r->getOSrv(); nsrv->clearChildren(); nsrv->setAnyElement();
|
|
ntsrc=r->getTSrc(); ntsrc->clearChildren(); ntsrc->setAnyElement();
|
|
ntdst=r->getTDst(); ntdst->clearChildren(); ntdst->setAnyElement();
|
|
ntsrv=r->getTSrv(); ntsrv->clearChildren(); ntsrv->setAnyElement();
|
|
ndst->setNeg(false);
|
|
nsrv->setNeg(false);
|
|
r->setRuleType(NATRule::Return);
|
|
r->setStr("ipt_target","RETURN");
|
|
r->setStr("ipt_chain",new_chain);
|
|
r->setInterfaceStr("nil");
|
|
r->setBool("rule_added_for_osrc_neg",true);
|
|
tmp_queue.push_back(r);
|
|
|
|
/* TMP_CHAIN any any C ACTION */
|
|
r= compiler->dbcopy->createNATRule();
|
|
compiler->temp_ruleset->add(r);
|
|
r->duplicate(rule);
|
|
nsrc=r->getOSrc(); nsrc->clearChildren(); nsrc->setAnyElement();
|
|
ndst=r->getODst(); ndst->clearChildren(); ndst->setAnyElement();
|
|
nsrv=r->getOSrv();
|
|
ndst->setNeg(false);
|
|
nsrv->setNeg(false);
|
|
r->setStr("ipt_chain",new_chain);
|
|
r->setInterfaceStr("nil");
|
|
r->setBool("rule_added_for_osrc_neg",true);
|
|
tmp_queue.push_back(r);
|
|
|
|
} else
|
|
tmp_queue.push_back(rule);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool NATCompiler_ipt::doODstNegation::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
RuleElementODst *odstrel=rule->getODst();
|
|
|
|
/* ! A B C */
|
|
|
|
if (odstrel->getNeg()) {
|
|
NATRule *r;
|
|
RuleElementOSrc *nsrc;
|
|
RuleElementODst *ndst;
|
|
RuleElementOSrv *nsrv;
|
|
|
|
RuleElementTSrc *ntsrc;
|
|
RuleElementTDst *ntdst;
|
|
RuleElementTSrv *ntsrv;
|
|
|
|
string new_chain=NATCompiler_ipt::getNewTmpChainName(rule);
|
|
odstrel->setNeg(false);
|
|
/*
|
|
* negation in Odst :
|
|
*
|
|
* CHAIN A !B C RULE_TYPE TARGET
|
|
*-----------------------------------------------
|
|
* ----- A any C SNAT/DNAT TMP_CHAIN
|
|
* TMP_CHAIN any B any RETURN RETURN
|
|
* TMP_CHAIN any any C SNAT/DNAT ---------
|
|
*/
|
|
r= compiler->dbcopy->createNATRule();
|
|
compiler->temp_ruleset->add(r);
|
|
r->duplicate(rule);
|
|
ndst=r->getODst(); ndst->clearChildren(); ndst->setAnyElement();
|
|
// ntsrc=r->getTSrc(); ntsrc->clearChildren(); ntsrc->setAnyElement();
|
|
// ntdst=r->getTDst(); ntdst->clearChildren(); ntdst->setAnyElement();
|
|
// r->setRuleType(NATRule::Continue);
|
|
r->setStr("ipt_target",new_chain);
|
|
r->setBool("rule_added_for_odst_neg",true);
|
|
tmp_queue.push_back(r);
|
|
|
|
/* TMP_CHAIN any B any RETURN */
|
|
r= compiler->dbcopy->createNATRule();
|
|
compiler->temp_ruleset->add(r);
|
|
r->duplicate(rule);
|
|
nsrc=r->getOSrc(); nsrc->clearChildren(); nsrc->setAnyElement();
|
|
nsrv=r->getOSrv(); nsrv->clearChildren(); nsrv->setAnyElement();
|
|
ntsrc=r->getTSrc(); ntsrc->clearChildren(); ntsrc->setAnyElement();
|
|
ntdst=r->getTDst(); ntdst->clearChildren(); ntdst->setAnyElement();
|
|
ntsrv=r->getTSrv(); ntsrv->clearChildren(); ntsrv->setAnyElement();
|
|
nsrc->setNeg(false);
|
|
nsrv->setNeg(false);
|
|
r->setRuleType(NATRule::Return);
|
|
r->setStr("ipt_target","RETURN");
|
|
r->setStr("ipt_chain",new_chain);
|
|
r->setInterfaceStr("nil");
|
|
// r->setBool("rule_added_for_odst_neg",true);
|
|
tmp_queue.push_back(r);
|
|
|
|
/* TMP_CHAIN any any C ACTION */
|
|
r= compiler->dbcopy->createNATRule();
|
|
compiler->temp_ruleset->add(r);
|
|
r->duplicate(rule);
|
|
nsrc=r->getOSrc(); nsrc->clearChildren(); nsrc->setAnyElement();
|
|
ndst=r->getODst(); ndst->clearChildren(); ndst->setAnyElement();
|
|
nsrv=r->getOSrv();
|
|
nsrc->setNeg(false);
|
|
nsrv->setNeg(false);
|
|
r->setStr("ipt_chain",new_chain);
|
|
r->setInterfaceStr("nil");
|
|
r->setBool("rule_added_for_odst_neg",true);
|
|
tmp_queue.push_back(r);
|
|
|
|
} else
|
|
tmp_queue.push_back(rule);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool NATCompiler_ipt::doOSrvNegation::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
RuleElementOSrv *osrvrel=rule->getOSrv();
|
|
|
|
/* A B ! C */
|
|
|
|
if (osrvrel->getNeg()) {
|
|
NATRule *r;
|
|
RuleElementOSrc *nsrc;
|
|
RuleElementODst *ndst;
|
|
RuleElementOSrv *nsrv;
|
|
|
|
RuleElementTSrc *ntsrc;
|
|
RuleElementTDst *ntdst;
|
|
|
|
string new_chain=NATCompiler_ipt::getNewTmpChainName(rule);
|
|
osrvrel->setNeg(false);
|
|
/*
|
|
* negation in OSrv :
|
|
*
|
|
* CHAIN A B !C RULE_TYPE TARGET
|
|
*-----------------------------------------------
|
|
* ----- A B any SNAT/DNAT TMP_CHAIN
|
|
* TMP_CHAIN any any C RETURN RETURN
|
|
* TMP_CHAIN any any any SNAT/DNAT ---------
|
|
*/
|
|
r= compiler->dbcopy->createNATRule();
|
|
compiler->temp_ruleset->add(r);
|
|
r->duplicate(rule);
|
|
nsrv=r->getOSrv(); nsrv->clearChildren(); nsrv->setAnyElement();
|
|
// ntsrc=r->getTSrc(); ntsrc->clearChildren(); ntsrc->setAnyElement();
|
|
// ntdst=r->getTDst(); ntdst->clearChildren(); ntdst->setAnyElement();
|
|
// r->setRuleType(NATRule::Continue);
|
|
r->setStr("ipt_target",new_chain);
|
|
r->setBool("rule_added_for_osrv_neg",true);
|
|
tmp_queue.push_back(r);
|
|
|
|
/* TMP_CHAIN any any C RETURN */
|
|
r= compiler->dbcopy->createNATRule();
|
|
compiler->temp_ruleset->add(r);
|
|
r->duplicate(rule);
|
|
nsrc=r->getOSrc(); nsrc->clearChildren(); nsrc->setAnyElement();
|
|
ndst=r->getODst(); ndst->clearChildren(); ndst->setAnyElement();
|
|
ntsrc=r->getTSrc(); ntsrc->clearChildren(); ntsrc->setAnyElement();
|
|
ntdst=r->getTDst(); ntdst->clearChildren(); ntdst->setAnyElement();
|
|
nsrc->setNeg(false);
|
|
ndst->setNeg(false);
|
|
r->setRuleType(NATRule::Return);
|
|
r->setStr("ipt_target","RETURN");
|
|
r->setStr("ipt_chain",new_chain);
|
|
r->setInterfaceStr("nil");
|
|
r->setBool("rule_added_for_osrv_neg",true);
|
|
tmp_queue.push_back(r);
|
|
|
|
/* TMP_CHAIN any any any ACTION */
|
|
r= compiler->dbcopy->createNATRule();
|
|
compiler->temp_ruleset->add(r);
|
|
r->duplicate(rule);
|
|
nsrc=r->getOSrc(); nsrc->clearChildren(); nsrc->setAnyElement();
|
|
ndst=r->getODst(); ndst->clearChildren(); ndst->setAnyElement();
|
|
nsrv=r->getOSrv(); nsrv->clearChildren(); nsrv->setAnyElement();
|
|
nsrc->setNeg(false);
|
|
ndst->setNeg(false);
|
|
r->setStr("ipt_chain",new_chain);
|
|
r->setInterfaceStr("nil");
|
|
// r->setBool("rule_added_for_osrv_neg",true);
|
|
tmp_queue.push_back(r);
|
|
|
|
} else
|
|
tmp_queue.push_back(rule);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool NATCompiler_ipt::splitNONATRule::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
if ( rule->getStr("ipt_chain").empty() && rule->getRuleType()==NATRule::NONAT) {
|
|
|
|
Address *osrc=compiler->getFirstOSrc(rule);
|
|
bool osrcfw= compiler->complexMatch(osrc,compiler->fw);
|
|
/*
|
|
* NONAT is special if OSrc matches firewall. It is not sufficient to
|
|
* only put this rule in the OUTPUT chain because packets originating
|
|
* on the firewall actually cross both OUTPUT and POSTROUTING chains
|
|
* (I tested this). So, we need to make sure we _do not_ translate in
|
|
* both these chains because there may be other rules in POSTROUTING
|
|
* chain that may accidentally match the packet and translate it.
|
|
*/
|
|
NATRule *r= compiler->dbcopy->createNATRule();
|
|
compiler->temp_ruleset->add(r);
|
|
r->duplicate(rule);
|
|
r->setStr("ipt_chain","POSTROUTING");
|
|
tmp_queue.push_back(r);
|
|
|
|
if (osrcfw)
|
|
{
|
|
rule->setStr("ipt_chain","OUTPUT");
|
|
if (osrc->getId()==compiler->fw->getId())
|
|
{
|
|
RuleElementOSrc *src;
|
|
src=rule->getOSrc();
|
|
src->clearChildren();
|
|
src->setAnyElement();
|
|
}
|
|
} else rule->setStr("ipt_chain","PREROUTING");
|
|
|
|
tmp_queue.push_back(rule);
|
|
|
|
} else
|
|
tmp_queue.push_back(rule);
|
|
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. Both the chain and the target are bogus
|
|
// and are needed only to make the compiler continue and
|
|
// produce some output, which will be shown to the user
|
|
// together with the error in single-rule compile mode
|
|
rule->setStr("ipt_chain", "PREROUTING");
|
|
rule->setStr("ipt_target", "UNDEFINED");
|
|
tmp_queue.push_back(rule);
|
|
}
|
|
} else
|
|
tmp_queue.push_back(rule);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool NATCompiler_ipt::localNATRule::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
// if ( rule->getStr("ipt_chain").empty())
|
|
// {
|
|
|
|
Address *osrc = compiler->getFirstOSrc(rule);
|
|
bool osrcfw = compiler->complexMatch(osrc,compiler->fw);
|
|
|
|
switch( rule->getRuleType())
|
|
{
|
|
case NATRule::DNAT:
|
|
case NATRule::DNetnat:
|
|
|
|
/* it should not be necessary to do anything if rule type is NONAT
|
|
* since splitNONATRule takes care of NONAT rules
|
|
*
|
|
* is there any need to split the rule if it is SNAT or DNAT type ? I
|
|
* can't see any reason to do it.
|
|
*
|
|
* Can use OUTPUT chain only for DNAT rules and a like
|
|
*/
|
|
if (osrcfw) rule->setStr("ipt_chain", "OUTPUT");
|
|
if (osrcfw && osrc->getId()==compiler->fw->getId())
|
|
{
|
|
RuleElementOSrc *src;
|
|
src=rule->getOSrc();
|
|
src->clearChildren();
|
|
src->setAnyElement();
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
// }
|
|
|
|
tmp_queue.push_back(rule);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool NATCompiler_ipt::splitIfOSrcAny::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
tmp_queue.push_back(rule);
|
|
|
|
/* do not split rules added to handle negation, these rules have "any"
|
|
* in OSrc but get control only after OSrc is tested by another
|
|
* rule */
|
|
if (rule->getBool("rule_added_for_osrc_neg")) return true;
|
|
if (rule->getBool("rule_added_for_odst_neg")) return true;
|
|
if (rule->getBool("rule_added_for_osrv_neg")) return true;
|
|
|
|
if (rule->getRuleType()==NATRule::DNAT)
|
|
{
|
|
RuleElementOSrc *osrcrel = rule->getOSrc();
|
|
Address *osrc = compiler->getFirstOSrc(rule);
|
|
|
|
// split if osrc is any OR if it has a single object with negation
|
|
if (osrc->isAny() || osrcrel->getBool("single_object_negation"))
|
|
{
|
|
NATRule *r = compiler->dbcopy->createNATRule();
|
|
compiler->temp_ruleset->add(r);
|
|
r->duplicate(rule);
|
|
RuleElementOSrc *nosrcrel = r->getOSrc();
|
|
nosrcrel->addRef(compiler->fw);
|
|
tmp_queue.push_back(r);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/*
|
|
* we assume that splitIfOSrcMatchesFw was called before, so that if firewall
|
|
* was in OSrc, it is now a single object in that rule element
|
|
*/
|
|
bool NATCompiler_ipt::DNATforFW::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
tmp_queue.push_back(rule);
|
|
|
|
if (rule->getRuleType()==NATRule::DNAT)
|
|
{
|
|
Address *osrc=compiler->getFirstOSrc(rule);
|
|
if ( compiler->complexMatch(osrc,compiler->fw) )
|
|
{
|
|
rule->setStr("ipt_chain","OUTPUT");
|
|
if (osrc->getId()==compiler->fw->getId())
|
|
{
|
|
rule->getOSrc()->clearChildren();
|
|
rule->getOSrc()->setAnyElement();
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
bool NATCompiler_ipt::decideOnTarget::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
tmp_queue.push_back(rule);
|
|
|
|
if ( ! rule->getStr("ipt_target").empty() ) return true; // already defined
|
|
|
|
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;
|
|
case NATRule::DNAT: rule->setStr("ipt_target","DNAT"); break;
|
|
case NATRule::DNetnat: rule->setStr("ipt_target","NETMAP"); break;
|
|
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;
|
|
}
|
|
|
|
/*
|
|
* this processor works together with ReplaceFirewallObjectsTSrc and
|
|
* ConvertToAtomicRules. If the first two left interface object in
|
|
* TSrc, AssignInterfaces assigns this rule to the corresponding
|
|
* interface. Rule will be split and assigned to all interfaces here
|
|
* if object in TSrc is not an interface or an address of interface.
|
|
*
|
|
* Summary: SNAT rules are now assigned to interfaces (using "-o
|
|
* iface_name") as follows:
|
|
*
|
|
* - if firewall's interface or its address is in TSrc, the rule the
|
|
* uses its address for "--to-source" and its name for "-o"
|
|
*
|
|
* - if firewall object is in TSrc, then it gets replaced with its
|
|
* interfaces (except unnumbered and loopback interfaces) and rule is
|
|
* processed using each interface as described above
|
|
*
|
|
* - if some other object is in TSrc, the rule is assigned to all
|
|
* interfaces of the firewall (using notation with '+') and address of
|
|
* this object is used for "--to-source". There are reasons why rule
|
|
* has to be explicitly assigned to all interfaces using "-o" as
|
|
* opposed to skipping "-o" all together. consider for example a
|
|
* configuration with an unnumbred tunnel interface (e.g. ipsec0) used
|
|
* for "road varrior" connections where IP address on the other end of
|
|
* the tunnel is unknown. We can not add a "no nat" rule because we do
|
|
* not know address of the net on the other side of the tunnel, but
|
|
* fortunately ipsec0 is skipped in the assignment of SNAT rule
|
|
* because it is unnumbered, so the firewall won't translate packets
|
|
* going through this interface.
|
|
*
|
|
*/
|
|
bool NATCompiler_ipt::AssignInterface::processNext()
|
|
{
|
|
NATCompiler_ipt *ipt_comp = dynamic_cast<NATCompiler_ipt*>(compiler);
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
// Address *a=NULL;
|
|
// FWObject *ref;
|
|
|
|
if (regular_interfaces.size()==0)
|
|
{
|
|
list<FWObject*> l2=compiler->fw->getByType(Interface::TYPENAME);
|
|
for (list<FWObject*>::iterator i=l2.begin(); i!=l2.end(); ++i)
|
|
{
|
|
Interface *iface=Interface::cast(*i);
|
|
assert(iface);
|
|
|
|
if (iface->isLoopback() ||
|
|
iface->isUnnumbered() ||
|
|
iface->isBridgePort()
|
|
) continue;
|
|
|
|
/* Bug #1064: "Dedicated IPv6 interfaces show up in
|
|
* IPv4-NAT rules". Use interface only if it has addresses
|
|
* that match address family we compile for
|
|
*
|
|
* Include interfaces that have no addresses in the list
|
|
* for backwards compatibility.
|
|
*/
|
|
FWObjectTypedChildIterator ipv4_addresses = iface->findByType(IPv4::TYPENAME);
|
|
FWObjectTypedChildIterator ipv6_addresses = iface->findByType(IPv6::TYPENAME);
|
|
|
|
if ((ipt_comp->ipv6 && ipv6_addresses != ipv6_addresses.end()) ||
|
|
(!ipt_comp->ipv6 && ipv4_addresses != ipv4_addresses.end()) ||
|
|
ipv4_addresses == ipv4_addresses.end() && ipv6_addresses == ipv6_addresses.end())
|
|
{
|
|
/*
|
|
* if interface name ends with '*', this is wildcard
|
|
* interface. Just replace '*' with '+'. If interace
|
|
* name does not end with '*', replace numeric
|
|
* interface index with '+'. Either way, cptr points
|
|
* at the first caracter after the 'family' name of
|
|
* the interface (is there a better term?) which will
|
|
* be either a digit or '*'.
|
|
*/
|
|
|
|
QString iname = QString(iface->getName().c_str());
|
|
iname.replace(QRegExp("[0-9]{1,}$"), "+");
|
|
iname.replace("*", "+");
|
|
regular_interfaces.insert(iname);
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (rule->getRuleType())
|
|
{
|
|
case NATRule::SNAT:
|
|
case NATRule::Masq:
|
|
{
|
|
Address* a = compiler->getFirstTSrc(rule);
|
|
Interface *iface = Interface::cast(a);
|
|
|
|
if (IPv4::isA(a) || IPv6::isA(a))
|
|
{
|
|
iface = Interface::cast(a->getParent());
|
|
}
|
|
|
|
if (iface)
|
|
{
|
|
if (Cluster::isA(iface->getParentHost()) &&
|
|
iface->isFailoverInterface())
|
|
{
|
|
FWObject *failover_group =
|
|
iface->getFirstByType(FailoverClusterGroup::TYPENAME);
|
|
|
|
if (failover_group)
|
|
{
|
|
for (FWObjectTypedChildIterator it =
|
|
failover_group->findByType(FWObjectReference::TYPENAME);
|
|
it != it.end(); ++it)
|
|
{
|
|
Interface *fw_iface = Interface::cast(FWObjectReference::getObject(*it));
|
|
assert(fw_iface);
|
|
if (fw_iface->isChildOf(compiler->fw))
|
|
{
|
|
iface = fw_iface;
|
|
rule->setInterfaceId(iface->getId());
|
|
tmp_queue.push_back(rule);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
} else
|
|
{
|
|
if (iface->isChildOf(compiler->fw))
|
|
{
|
|
rule->setInterfaceId(iface->getId());
|
|
tmp_queue.push_back(rule);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* if we appear here, then TSrc is not an interface or address of an
|
|
* interface. This processor will simply pass a rule along if firewall
|
|
* has no interfaces at all. I wonder if I really have to do this,
|
|
* but I do it anyway.
|
|
*/
|
|
int n=0;
|
|
foreach(QString intf_name, regular_interfaces)
|
|
{
|
|
NATRule *r = compiler->dbcopy->createNATRule();
|
|
r->duplicate(rule);
|
|
compiler->temp_ruleset->add(r);
|
|
r->setInterfaceStr(intf_name.toStdString());
|
|
tmp_queue.push_back(r);
|
|
n++;
|
|
}
|
|
if (n==0) tmp_queue.push_back(rule);
|
|
return true;
|
|
}
|
|
break;
|
|
default: ;
|
|
}
|
|
|
|
tmp_queue.push_back(rule);
|
|
return true;
|
|
}
|
|
|
|
bool NATCompiler_ipt::verifyRuleWithMAC::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
RuleElementOSrc *rel = rule->getOSrc();
|
|
if (rel->isAny())
|
|
{
|
|
tmp_queue.push_back(rule);
|
|
return true;
|
|
}
|
|
|
|
string chain = rule->getStr("ipt_chain");
|
|
|
|
if (chain!="PREROUTING" && chain!="FORWARD" && chain!="INPUT" )
|
|
{
|
|
/* scan all objects in OSrc, look for physAddress or combinedAddress
|
|
* with pa present. Objects like that are not allowed in chain POSTROUTING.
|
|
* Issue warning and remove physAddress from the list.
|
|
*/
|
|
list<FWObject*> cl;
|
|
FWObject *pa=NULL;
|
|
for (FWObject::iterator i=rel->begin(); i!=rel->end(); i++)
|
|
{
|
|
FWObject *o= *i;
|
|
FWObject *o1= o;
|
|
if (FWReference::cast(o)!=NULL) o1=FWReference::cast(o)->getPointer();
|
|
|
|
if (physAddress::isA(o1))
|
|
{
|
|
pa=o1;
|
|
cl.push_back(o1);
|
|
}
|
|
combinedAddress *ca=combinedAddress::cast(o1);
|
|
if (ca!=NULL && ca->getPhysAddress()!="" )
|
|
{
|
|
/* there are two possibilities:
|
|
* 1 - combinedAddress consists of the IPv4 component and MAC address component
|
|
* 2 - combinedAddress consists of an empty IPv4 component and MAC address .
|
|
*/
|
|
pa=o1;
|
|
if ( ca->isAny() ) cl.push_back(o1);
|
|
else ca->setPhysAddress("");
|
|
}
|
|
}
|
|
|
|
if (!cl.empty())
|
|
{
|
|
for (list<FWObject*>::iterator i1=cl.begin(); i1!=cl.end(); ++i1)
|
|
rel->removeRef( (*i1) );
|
|
}
|
|
|
|
if (pa!=NULL)
|
|
{
|
|
char errmsg[2048];
|
|
if (rel->isAny())
|
|
{
|
|
sprintf(errmsg,
|
|
"SNAT rule can not match MAC address, however after removing object %s from OSrc it becomes 'Any'",
|
|
pa->getName().c_str());
|
|
compiler->abort(rule, errmsg );
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
sprintf(errmsg,
|
|
"SNAT rule can not match MAC address. Object %s removed from the rule",
|
|
pa->getName().c_str());
|
|
compiler->warning(rule, errmsg );
|
|
}
|
|
}
|
|
}
|
|
|
|
tmp_queue.push_back(rule);
|
|
return true;
|
|
}
|
|
|
|
bool NATCompiler_ipt::processMultiAddressObjectsInRE::processNext()
|
|
{
|
|
NATRule *rule=getNext(); if (rule==NULL) return false;
|
|
|
|
OSConfigurator_linux24 *osconf =
|
|
dynamic_cast<OSConfigurator_linux24*>(compiler->osconfigurator);
|
|
|
|
RuleElement *re=RuleElement::cast( rule->getFirstByType(re_type) );
|
|
|
|
if (re->size()==1)
|
|
{
|
|
FWObject *o = re->front();
|
|
if (FWReference::cast(o)!=NULL) o=FWReference::cast(o)->getPointer();
|
|
MultiAddressRunTime *atrt = MultiAddressRunTime::cast(o);
|
|
if (atrt!=NULL)
|
|
{
|
|
// we have just one object in RE and this object is MutiAddressRunTime
|
|
if (atrt->getSubstitutionTypeName()==AddressTable::TYPENAME)
|
|
{
|
|
rule->setStr("address_table_file",atrt->getSourceName());
|
|
osconf->registerMultiAddressObject(atrt);
|
|
}
|
|
if (atrt->getSubstitutionTypeName()==DNSName::TYPENAME)
|
|
{
|
|
// this is DNSName converted to its run-time counterpart,
|
|
// we do not need to touch it at all
|
|
}
|
|
tmp_queue.push_back(rule);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
list<MultiAddressRunTime*> cl;
|
|
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)
|
|
cl.push_back(atrt);
|
|
}
|
|
|
|
if (!cl.empty())
|
|
{
|
|
RuleElement *nre;
|
|
RuleElement *ore=RuleElement::cast( rule->getFirstByType(re_type) );
|
|
NATRule *r;
|
|
for (list<MultiAddressRunTime*>::iterator i=cl.begin(); i!=cl.end(); i++)
|
|
{
|
|
MultiAddressRunTime *atrt = *i;
|
|
r = compiler->dbcopy->createNATRule();
|
|
compiler->temp_ruleset->add(r);
|
|
r->duplicate(rule);
|
|
nre=RuleElement::cast( r->getFirstByType(re_type) );
|
|
nre->clearChildren();
|
|
nre->addRef( atrt );
|
|
r->setStr("address_table_file",atrt->getSourceName());
|
|
osconf->registerMultiAddressObject(atrt);
|
|
tmp_queue.push_back(r);
|
|
|
|
ore->removeRef( *i );
|
|
}
|
|
}
|
|
|
|
tmp_queue.push_back(rule);
|
|
return true;
|
|
}
|
|
|
|
bool NATCompiler_ipt::countChainUsage::processNext()
|
|
{
|
|
NATCompiler_ipt *ipt_comp = dynamic_cast<NATCompiler_ipt*>(compiler);
|
|
|
|
slurp();
|
|
if (tmp_queue.size()==0) return false;
|
|
|
|
for (deque<Rule*>::iterator k=tmp_queue.begin(); k!=tmp_queue.end(); ++k)
|
|
{
|
|
NATRule *rule = NATRule::cast( *k );
|
|
ipt_comp->chain_usage_counter[rule->getStr("ipt_target")] += 1;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void NATCompiler_ipt::registerRuleSetChain(const std::string &chain_name)
|
|
{
|
|
chain_usage_counter[chain_name] = 1;
|
|
}
|
|
|
|
void NATCompiler_ipt::compile()
|
|
{
|
|
string banner = " Compiling ruleset " + getRuleSetName() +
|
|
" for 'nat' table";
|
|
if (ipv6) banner += ", IPv6";
|
|
info(banner);
|
|
|
|
try
|
|
{
|
|
Compiler::compile();
|
|
|
|
add( new NATCompiler::Begin());
|
|
|
|
add( new printTotalNumberOfRules());
|
|
|
|
add( new singleRuleFilter());
|
|
|
|
add( new recursiveGroupsInOSrc("check for recursive groups in OSRC"));
|
|
add( new recursiveGroupsInODst("check for recursive groups in ODST"));
|
|
add( new recursiveGroupsInOSrv("check for recursive groups in OSRV"));
|
|
|
|
add( new recursiveGroupsInTSrc("check for recursive groups in TSRC"));
|
|
add( new recursiveGroupsInTDst("check for recursive groups in TDST"));
|
|
add( new recursiveGroupsInTSrv("check for recursive groups in TSRV"));
|
|
|
|
add( new emptyGroupsInOSrc("check for empty groups in OSRC" ));
|
|
add( new emptyGroupsInODst("check for empty groups in ODST" ));
|
|
add( new emptyGroupsInOSrv("check for empty groups in OSRV" ));
|
|
|
|
add( new emptyGroupsInTSrc("check for empty groups in TSRC" ));
|
|
add( new emptyGroupsInTDst("check for empty groups in TDST" ));
|
|
add( new emptyGroupsInTSrv("check for empty groups in TSRV"));
|
|
|
|
add( new ExpandGroups("Expand groups"));
|
|
|
|
// processors that expand objects with multiple addresses
|
|
// check addresses against current address family using member
|
|
// ipv6. If all addresses do not match, we may end up with
|
|
// empty rule element.
|
|
add( new dropRuleWithEmptyRE("drop rules with empty rule elements"));
|
|
|
|
if (ipv6)
|
|
add( new DropIPv4Rules("drop ipv4 rules"));
|
|
else
|
|
add( new DropIPv6Rules("drop ipv6 rules"));
|
|
|
|
add( new eliminateDuplicatesInOSRC("eliminate duplicates in OSRC"));
|
|
add( new eliminateDuplicatesInODST("eliminate duplicates in ODST"));
|
|
add( new eliminateDuplicatesInOSRV("eliminate duplicates in OSRV"));
|
|
|
|
add( new swapMultiAddressObjectsInOSrc(
|
|
" swap MultiAddress -> MultiAddressRunTime in OSrc") );
|
|
add( new swapMultiAddressObjectsInODst(
|
|
" swap MultiAddress -> MultiAddressRunTime in ODst") );
|
|
|
|
add( new processMultiAddressObjectsInOSrc(
|
|
"process MultiAddress objects in OSrc") );
|
|
add( new processMultiAddressObjectsInODst(
|
|
"process MultiAddress objects in ODst") );
|
|
|
|
add( new doOSrvNegation( "process negation in OSrv" ));
|
|
|
|
add( new convertToAtomicportForOSrv("convert to atomic rules in OSrv"));
|
|
|
|
add( new classifyNATRule( "classify NAT rule" ));
|
|
add( new splitSDNATRule( "split SDNAT rules" ));
|
|
add( new classifyNATRule( "reclassify rules" ));
|
|
add( new ConvertLoadBalancingRules( "convert load balancing rules"));
|
|
add( new VerifyRules( "verify rules" ));
|
|
#if 0
|
|
// ----------- 10/18/2008
|
|
add( new splitODstForSNAT(
|
|
"split rule if objects in ODst belong to different subnets") );
|
|
add( new ReplaceFirewallObjectsODst("replace firewall in ODst" ) );
|
|
add( new ReplaceFirewallObjectsTSrc("replace firewall in TSrc" ) );
|
|
add( new splitOnDynamicInterfaceInODst(
|
|
"split rule if ODst is dynamic interface" ) );
|
|
add( new splitOnDynamicInterfaceInTSrc(
|
|
"split rule if TSrc is dynamic interface" ) );
|
|
|
|
add( new ExpandMultipleAddresses("expand multiple addresses") );
|
|
add( new dropRuleWithEmptyRE("drop rules with empty rule elements"));
|
|
// -----------
|
|
#endif
|
|
|
|
add( new singleObjectNegationOSrc(
|
|
"negation in OSrc if it holds single object"));
|
|
add( new singleObjectNegationODst(
|
|
"negation in ODst if it holds single object"));
|
|
|
|
add( new doOSrcNegation( "process negation in OSrc" ));
|
|
add( new doODstNegation( "process negation in ODst" ));
|
|
|
|
/* call splitOnODst after processing negation */
|
|
add( new splitOnODst( "split on ODst" ));
|
|
|
|
add( new portTranslationRules( "port translation rules" ));
|
|
add( new specialCaseWithRedirect(
|
|
"special case with redirecting port translation rules" ) );
|
|
|
|
if (fwopt->getBool("local_nat") )
|
|
{
|
|
if ( fwopt->getBool("firewall_is_part_of_any_and_networks") )
|
|
add( new splitIfOSrcAny( "split rule if OSrc is any" ));
|
|
|
|
add( new splitIfOSrcMatchesFw("split rule if OSrc matches FW" ));
|
|
}
|
|
|
|
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" ) );
|
|
add( new decideOnTarget( "decide on target" ) );
|
|
|
|
|
|
// ----------- 10/18/2008
|
|
add( new splitODstForSNAT(
|
|
"split rule if objects in ODst belong to different subnets") );
|
|
add( new ReplaceFirewallObjectsODst("replace firewall in ODst" ) );
|
|
add( new ReplaceFirewallObjectsTSrc("replace firewall in TSrc" ) );
|
|
add( new splitOnDynamicInterfaceInODst(
|
|
"split rule if ODst is dynamic interface" ) );
|
|
add( new splitOnDynamicInterfaceInTSrc(
|
|
"split rule if TSrc is dynamic interface" ) );
|
|
|
|
add( new ExpandMultipleAddresses("expand multiple addresses") );
|
|
add( new dropRuleWithEmptyRE("drop rules with empty rule elements"));
|
|
|
|
|
|
if (ipv6)
|
|
add( new DropIPv4Rules("drop ipv4 rules"));
|
|
else
|
|
add( new DropIPv6Rules("drop ipv6 rules"));
|
|
|
|
add( new dropRuleWithEmptyRE("drop rules with empty rule elements"));
|
|
|
|
add( new specialCaseWithUnnumberedInterface(
|
|
"special cases with dynamic and unnumbered interfaces" ) );
|
|
add( new checkForDynamicInterfacesOfOtherObjects(
|
|
"dynamic interfaces of other hosts and firewalls" ) );
|
|
|
|
add( new verifyRuleWithMAC("verify rules using MAC address filtering"));
|
|
add( new ExpandAddressRanges("expand address ranges") );
|
|
add( new dropRuleWithEmptyRE("drop rules with empty rule elements"));
|
|
|
|
add( new splitMultiSrcAndDst(
|
|
"split rules where multiple srcs and dsts are present" ) );
|
|
|
|
add( new splitServices("split on services") );
|
|
add( new VerifyRules2("check correctness of TSrv") );
|
|
add( new separatePortRanges("separate port ranges") );
|
|
add( new separateSourcePorts("separate objects with src") );
|
|
add( new separateSourceAndDestinationPorts(
|
|
"separate objects with both src and dest ports" ) );
|
|
add( new prepareForMultiport("prepare for multiport") );
|
|
add( new splitMultipleICMP("split rule with multiple ICMP services") );
|
|
|
|
add( new ConvertToAtomicForAddresses("convert to atomic rules") );
|
|
|
|
add( new addVirtualAddress("add virtual addresses") );
|
|
|
|
add( new AssignInterface("assign rules to interfaces") );
|
|
add( new dynamicInterfaceInODst("split if dynamic interface in ODst") );
|
|
add( new dynamicInterfaceInTSrc(
|
|
"set target if dynamic interface in TSrc" ) );
|
|
add( new convertInterfaceIdToStr("prepare interface assignments") );
|
|
|
|
add( new checkForObjectsWithErrors(
|
|
"check if we have objects with errors in rule elements"));
|
|
|
|
add( new countChainUsage("Count chain usage"));
|
|
|
|
if (fwopt->getBool("use_iptables_restore"))
|
|
{
|
|
// bug #1812295: we should use PrintRuleIptRstEcho not only
|
|
// when we have dynamic interfaces, but also when we have
|
|
// address tables expanded at run time. Instead of checking
|
|
// for all these conditions, just always use PrintRuleIptRstEcho
|
|
printRule=new PrintRuleIptRstEcho(
|
|
"generate code for iptables-restore using echo");
|
|
} else
|
|
printRule=new PrintRule("generate iptables shell script");
|
|
|
|
printRule->setContext(this);
|
|
printRule->initialize();
|
|
add( printRule );
|
|
|
|
add( new simplePrintProgress() );
|
|
|
|
runRuleProcessors();
|
|
|
|
|
|
} catch (FWException &ex)
|
|
{
|
|
error(ex.toString());
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
|
|
void NATCompiler_ipt::epilog()
|
|
{
|
|
if (fwopt->getBool("use_iptables_restore"))
|
|
{
|
|
output << "#" << endl;
|
|
}
|
|
}
|
|
|
|
string NATCompiler_ipt::flushAndSetDefaultPolicy()
|
|
{
|
|
string res="";
|
|
|
|
if (fwopt->getBool("use_iptables_restore") && ! inSingleRuleCompileMode())
|
|
{
|
|
res += "echo :PREROUTING ACCEPT [0:0]\n";
|
|
res += "echo :POSTROUTING ACCEPT [0:0]\n";
|
|
res += "echo :OUTPUT ACCEPT [0:0]\n";
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
string NATCompiler_ipt::printAutomaticRules()
|
|
{
|
|
return "";
|
|
}
|
|
|
|
string NATCompiler_ipt::commit()
|
|
{
|
|
string res="";
|
|
|
|
if(printRule!=NULL)
|
|
{
|
|
res += printRule->_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;
|
|
}
|
|
|