1
0
mirror of https://github.com/fwbuilder/fwbuilder synced 2026-03-25 04:37:22 +01:00

merging cisco and pix modules

This commit is contained in:
Vadim Kurland 2008-03-19 03:43:11 +00:00
parent 9c966dbc91
commit 3dc8099fc3
47 changed files with 27812 additions and 7 deletions

View File

@ -25,6 +25,9 @@ for d in src/ \
src/pf/ \
src/ipf/ \
src/ipfw/ \
src/cisco_lib \
src/iosacl \
src/pix \
src/parsers/
do
(cd $d; ${QMAKE} $C)

86
src/cisco_lib/ACL.cpp Normal file
View File

@ -0,0 +1,86 @@
/*
Firewall Builder
Copyright (C) 2004 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: ACL.cpp,v 1.1 2008/03/06 06:48:55 vkurland Exp $
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 "ACL.h"
#include <sstream>
using namespace std;
string ciscoACL::addLine(const std::string &s)
{
acl.push_back(s);
nlines++;
return printLastLine();
}
/*
* Adds remark to access list. Checks and adds each remark only
* once. We use rule labels for remarks
*/
string ciscoACL::addRemark(const std::string &rl)
{
if (_last_rule_label!=rl)
{
acl.push_back(" remark "+rl);
_last_rule_label=rl;
nlines++;
return printLastLine();
}
return "";
}
string ciscoACL::print()
{
ostringstream str;
for (list<string>::iterator s=acl.begin(); s!=acl.end(); s++)
str << printLine(*s);
return str.str();
}
string ciscoACL::printLastLine()
{
return printLine(acl.back());
}
string ciscoACL::printLine(const string &s)
{
ostringstream str;
// _ip_acl means Cisco IOS "ip access-list extended <name>" style ACL
// actual lines of the access list just start with "permit" or "deny"
if ( s.find('!')!=0 )
{
if (_ip_acl) str << " ";
else str << "access-list " << _workName << " ";
}
str << s << endl;
return str.str();
}

99
src/cisco_lib/ACL.h Normal file
View File

@ -0,0 +1,99 @@
/*
Firewall Builder
Copyright (C) 2004 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: ACL.h,v 1.1 2008/03/06 06:48:55 vkurland Exp $
This program is free software which we release under the GNU General Public
License. You may redistribute and/or modify this program under the terms
of that license as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
To get a copy of the GNU General Public License, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __ACL_H
#define __ACL_H
#include <string>
#include <list>
#include "fwbuilder/Interface.h"
class ciscoACL {
bool _ip_acl;
std::string _name;
std::string _workName;
libfwbuilder::Interface *_interface;
std::string _dir;
std::string _last_rule_label;
int nlines;
std::list<std::string> acl;
std::string printLine(const std::string &s);
public:
ciscoACL() {
_ip_acl = false;
_name = "";
_workName = "";
_interface = NULL;
_dir = "in";
nlines = 0;
_last_rule_label = "";
}
ciscoACL(const std::string &n,
libfwbuilder::Interface *intf,
const std::string &d="in",
bool _ip_list=false)
{
_ip_acl = _ip_list;
_name = n;
_workName = "";
_interface = intf;
_dir = d;
nlines = 0;
_last_rule_label = "";
}
std::string addLine(const std::string &s);
/*
* Adds remark to access list. Checks and adds each remark only
* once. We use rule labels for remarks
*/
std::string addRemark(const std::string &rl);
void setName(const std::string &s) { _name=s; }
std::string name() { return _name; }
void setWorkName(const std::string &s) { _workName=s; }
std::string workName() { return _workName; }
void setInterface(libfwbuilder::Interface *intf) { _interface=intf; }
libfwbuilder::Interface* getInterface() { return _interface; }
void setDirection(const std::string &d) { _dir=d; }
std::string direction() { return _dir; }
std::string print();
std::string printLastLine();
int size() { return nlines; }
};
#endif

255
src/cisco_lib/Helper.cpp Normal file
View File

@ -0,0 +1,255 @@
/*
Firewall Builder
Copyright (C) 2002 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: Helper.cpp,v 1.1 2008/03/06 06:48:56 vkurland Exp $
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 "Helper.h"
#include <fwbuilder/Interface.h>
#include <fwbuilder/ObjectGroup.h>
#include <fwbuilder/IPAddress.h>
#include <fwbuilder/FWObjectDatabase.h>
#include <fwbuilder/RuleElement.h>
#include <fwbuilder/Rule.h>
#include "fwbuilder/Resources.h"
#include <assert.h>
#include <limits.h>
using namespace libfwbuilder;
using namespace fwcompiler;
using namespace std;
bool Helper::belongsTo(Address *obj, const IPAddress &a)
{
const IPNetwork n1( obj->getAddress() ,
(Interface::cast(obj))?Netmask("255.255.255.255"):obj->getNetmask() );
return n1.belongs(a);
}
bool Helper::belongsTo(Address *obj, Address *addr)
{
return belongsTo(obj,addr->getAddress());
}
static unsigned long calculateDimension(FWObject* obj)
{
if (Group::cast(obj)!=NULL) {
unsigned long res=0;
for (FWObject::iterator i1=obj->begin(); i1!=obj->end(); ++i1)
{
unsigned long n=calculateDimension( *i1 );
if (n==LONG_MAX) return n;
if (LONG_MAX-res<n) return LONG_MAX; // prevent overflow
res+=n;
}
return res;
} else
{
Address *a=Address::cast(obj);
if (a!=NULL)
{
if (a->isAny()) return LONG_MAX;
return a->dimension();
}
}
return 0;
}
void Helper::expand_group_recursive_no_cache(FWObject *o,list<FWObject*> &ol)
{
if (Group::cast( o )!=NULL) {
for (FWObject::iterator i2=o->begin(); i2!=o->end(); ++i2)
{
FWObject *o1= *i2;
if (FWReference::cast(o1)!=NULL) o1=FWReference::cast(o1)->getPointer();
assert(o1);
expand_group_recursive_no_cache(o1,ol);
}
} else {
ol.push_back( o );
}
}
void Helper::expand_group_recursive(FWObject *o,list<FWObject*> &ol)
{
if (Group::cast( o )!=NULL) {
for (FWObject::iterator i2=o->begin(); i2!=o->end(); ++i2)
{
FWObject *o1= *i2;
if (FWReference::cast(o1)!=NULL) o1=FWReference::cast(o1)->getPointer();
assert(o1);
expand_group_recursive(o1,ol);
}
} else {
ol.push_back( o );
}
}
string Helper::findInterfaceByAddress(libfwbuilder::Address *obj)
{
return findInterfaceByAddress(obj->getAddress());
}
string Helper::findInterfaceByAddress(const libfwbuilder::IPAddress &addr)
{
Firewall *fw=compiler->fw;
list<FWObject*> l2=fw->getByType(Interface::TYPENAME);
for (list<FWObject*>::iterator i=l2.begin(); i!=l2.end(); ++i) {
Interface *iface=Interface::cast(*i);
IPNetwork n( iface->getAddress() , iface->getNetmask() );
if ( n.belongs( addr ) ) return iface->getId();
}
return "";
}
string Helper::findInterfaceByNetzone(Address *obj)
{
return findInterfaceByNetzone(obj->getAddress());
}
string Helper::findInterfaceByNetzone(const IPAddress &addr) throw(string)
{
Firewall *fw=compiler->fw;
map<string,FWObject*> zones;
FWObjectTypedChildIterator i=fw->findByType(Interface::TYPENAME);
for ( ; i!=i.end(); ++i)
{
string netzone_id = (*i)->getStr("network_zone");
if (netzone_id != "")
{
FWObject *netzone=fw->getRoot()->findInIndex(netzone_id);
for (list<FWObject*>::iterator j=netzone->begin();
j!=netzone->end(); ++j)
{
assert(Address::cast(*j)!=NULL);
if ( belongsTo( Address::cast(*j) , addr ) )
zones[(*i)->getId()]=netzone;
}
}
}
/*
* now compare dimensions of all netzones that contain address obj and
* pick the one with smallest dimension
*/
string res_id;
unsigned long res_dim=LONG_MAX;
for (map<string,FWObject*>::iterator i=zones.begin(); i!=zones.end(); ++i)
{
string iface_id=(*i).first;
FWObject *netzone=(*i).second;
unsigned long dim=calculateDimension(netzone);
if (dim<=res_dim)
{
res_id=iface_id;
res_dim=dim;
}
}
/*
* Subnets defined by addresses of interfaces are automatically part
* of the corresponding network zones
*/
if (res_id.empty())
res_id=findInterfaceByAddress( addr );
if (res_id.empty())
throw( string("Can not find interface with network zone that includes address ") + addr.toString());
return res_id;
}
list<string> Helper::getAllInterfaceIDs()
{
Firewall *fw=compiler->fw;
list<string> intf_id_list;
FWObjectTypedChildIterator i=fw->findByType(Interface::TYPENAME);
for ( ; i!=i.end(); ++i)
{
Interface *ifs = Interface::cast(*i);
assert(ifs);
if (ifs->isUnprotected()) continue; // skip!
intf_id_list.push_back( (*i)->getId() );
}
return intf_id_list;
}
list<string> Helper::findInterfaceByNetzoneOrAll(RuleElement *re)
{
Firewall *fw=compiler->fw;
list<string> intf_id_list;
if (re->isAny())
{
return getAllInterfaceIDs();
} else
{
FWObject *fo = re->front();
if (FWReference::cast(fo)!=NULL) fo=FWReference::cast(fo)->getPointer();
Address *a = Address::cast(fo);
if (a==NULL)
{
Rule *rule = Rule::cast(re->getParent());
compiler->abort(string("findInterfaceByNetzoneOrAll failed to retrieve first object from the rule element; is argument not of the type RuleElementSrc or RuleElementDst ? Rule ") + rule->getLabel());
}
try
{
intf_id_list.push_back( findInterfaceByNetzone( a ) );
} catch(string err)
{
// could not find interface with netzone to match address 'a'
// will assign rule to all interfaces. Act as if all interfaces
// had network zone 'any' and each matches this address.
// issue warning only if platform uses netwrk zones.
bool supports_network_zones =
Resources::getTargetCapabilityBool(
compiler->fw->getStr("platform"), "network_zones");
if (supports_network_zones) compiler->warning(err);
FWObjectTypedChildIterator i = compiler->fw->findByType(Interface::TYPENAME);
for ( ; i!=i.end(); ++i)
{
Interface *ifs = Interface::cast(*i);
intf_id_list.push_back( ifs->getId() );
}
}
}
return intf_id_list;
}
string triplet::hash()
{
return string(src->getAddress()) + "." +
string(dst->getAddress()) + "." +
srv->getId();
}

109
src/cisco_lib/Helper.h Normal file
View File

@ -0,0 +1,109 @@
/*
Firewall Builder
Copyright (C) 2002 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: Helper.h,v 1.1 2008/03/06 06:48:56 vkurland Exp $
This program is free software which we release under the GNU General Public
License. You may redistribute and/or modify this program under the terms
of that license as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
To get a copy of the GNU General Public License, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __HELPER_HH
#define __HELPER_HH
#include <fwcompiler/Compiler.h>
#include <fwbuilder/FWObject.h>
#include <fwbuilder/Address.h>
#include <fwbuilder/Firewall.h>
namespace fwcompiler {
class Helper
{
fwcompiler::Compiler *compiler;
/**
* this methods checks if object addr belongs to network or address obj
*/
bool belongsTo(libfwbuilder::Address *obj,
const libfwbuilder::IPAddress &a);
bool belongsTo(libfwbuilder::Address *obj,
libfwbuilder::Address *addr);
public:
Helper(fwcompiler::Compiler *comp) { compiler=comp; }
/**
* finds interface of the firewall to whose subnet object
* 'obj' belongs to. Returns interface ID
*/
std::string findInterfaceByAddress(const libfwbuilder::IPAddress &a);
std::string findInterfaceByAddress(libfwbuilder::Address *obj);
/**
* finds interface of the firewall associated with the netzone
* that object 'obj' belongs to. Returns interface ID
*/
std::string findInterfaceByNetzone(const libfwbuilder::IPAddress &a)
throw(std::string);
std::string findInterfaceByNetzone(libfwbuilder::Address *obj);
std::list<std::string> findInterfaceByNetzoneOrAll(
libfwbuilder::RuleElement *re);
std::list<std::string> getAllInterfaceIDs();
/**
* recursively expands object 'o' and places all its children
* objects in the list 'ol'. Uses cache in compiler.
*/
void expand_group_recursive(libfwbuilder::FWObject *o,
std::list<libfwbuilder::FWObject*> &ol);
/**
* recursively expands object 'o' and places all its children
* objects in the list 'ol'. Does not use cache in compiler,
* therefore can be called even if compiler object has not
* been created yet.
*/
void expand_group_recursive_no_cache(libfwbuilder::FWObject *o,
std::list<libfwbuilder::FWObject*> &ol);
};
};
class triplet {
public:
libfwbuilder::Address *src;
libfwbuilder::Address *dst;
libfwbuilder::Service *srv;
triplet() {src=NULL; dst=NULL; srv=NULL;}
triplet(libfwbuilder::Address *s,
libfwbuilder::Address *d,
libfwbuilder::Service *v) {src=s; dst=d; srv=v;}
std::string hash();
};
#endif

View File

@ -0,0 +1,882 @@
/*
Firewall Builder
Copyright (C) 2002 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: PolicyCompiler_cisco.cpp,v 1.1 2008/03/06 06:48:56 vkurland Exp $
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_cisco.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/Network.h"
#include "fwbuilder/Policy.h"
#include "fwbuilder/Interface.h"
#include "fwbuilder/Management.h"
#include "fwbuilder/Resources.h"
#include "fwbuilder/AddressTable.h"
#include <iostream>
#if __GNUC__ > 3 || \
(__GNUC__ == 3 && (__GNUC_MINOR__ > 2 || (__GNUC_MINOR__ == 2 ) ) ) || \
_MSC_VER
# include <streambuf>
#else
# include <streambuf.h>
#endif
#include <iomanip>
#include <algorithm>
#include <functional>
#include <assert.h>
using namespace libfwbuilder;
using namespace fwcompiler;
using namespace std;
string PolicyCompiler_cisco::myPlatformName() { return ""; }
PolicyCompiler_cisco::PolicyCompiler_cisco(FWObjectDatabase *_db,
const std::string &fwname,
OSConfigurator *_oscnf) :
PolicyCompiler(_db,fwname,_oscnf) , helper(this)
{
}
int PolicyCompiler_cisco::prolog()
{
return PolicyCompiler::prolog();
}
string PolicyCompiler_cisco::createRuleLabel(const string &txt,
Interface *iface,
int rule_num)
{
ostringstream str;
str << rule_num;
if (iface!=NULL) str << "(" << iface->getLabel() << ")";
else str << "(" << txt << ")";
return str.str();
}
string PolicyCompiler_cisco::debugPrintRule(Rule *r)
{
PolicyRule *rule=PolicyRule::cast(r);
Interface *rule_iface = getCachedFwInterface(rule->getInterfaceId());
string iname=(rule_iface!=NULL)?rule_iface->getName():"";
string dir= rule->getDirectionAsString();
return PolicyCompiler::debugPrintRule(rule)+
" "+dir+" "+iname+" "+rule->getStr("acl");
}
void PolicyCompiler_cisco::addDefaultPolicyRule()
{
/*
* set up backup ssh access to the firewall if told to do so
*/
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);
dbcopy->add(ssh,false);
cacheObj(ssh); // to keep cache consistent
Network *mgmt_workstation = Network::cast(dbcopy->create(Network::TYPENAME));
*mgmt_workstation = 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(-1);
r->setComment(" backup ssh access rule ");
r->setHidden(true);
r->setFallback(false);
r->setLabel("backup ssh access rule");
RuleElement *src=RuleElement::cast(
r->getFirstByType(RuleElementSrc::TYPENAME) );
src->addRef(mgmt_workstation);
RuleElement *dst=RuleElement::cast(
r->getFirstByType(RuleElementDst::TYPENAME) );
dst->addRef(fw);
RuleElement *srv=RuleElement::cast(
r->getFirstByType(RuleElementSrv::TYPENAME) );
srv->addRef(ssh);
combined_ruleset->push_front(r);
}
// Ciscos provide built-in fallback rule so we do not need
// this. Besides, desired behavior is that if the user did not
// create any rules for a given interface (at all), then generated
// config file should have none. Adding fallback rule here creates
// 'deny any any' rule for such interfaces and screws things big
// time.
#if 0
PolicyRule *r= PolicyRule::cast(dbcopy->create(PolicyRule::TYPENAME) );
temp_ruleset->add(r);
r->setAction(PolicyRule::Deny);
r->setLogging(false);
// r->setDirection(PolicyRule::Both);
r->setPosition(10000);
r->setComment(" fallback rule ");
r->setLabel("fallback rule");
r->setFallback(true);
r->setHidden(true);
combined_ruleset->push_back(r);
#endif
}
bool PolicyCompiler_cisco::splitIfSrcAny::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
RuleElementSrc *srcrel=rule->getSrc();
Address *src = compiler->getFirstSrc(rule);
if ( rule->getDirection()!=PolicyRule::Inbound &&
(
srcrel->isAny() ||
( srcrel->size()==1 && src!=NULL &&
!compiler->complexMatch(src,compiler->fw) &&
srcrel->getBool("single_object_negation"))
)
)
{
PolicyRule *r= PolicyRule::cast(
compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
r->setDirection( PolicyRule::Outbound );
RuleElementSrc *nsrc=r->getSrc();
nsrc->clearChildren();
nsrc->addRef(compiler->fw);
tmp_queue.push_back(r);
}
tmp_queue.push_back(rule); // add old rule anyway
return true;
}
bool PolicyCompiler_cisco::splitIfDstAny::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
RuleElementSrv *srvrel=rule->getSrv();
RuleElementDst *dstrel=rule->getDst();
Address *dst=compiler->getFirstDst(rule);
std::list<FWObject*> cl;
for (list<FWObject*>::iterator i1=srvrel->begin(); i1!=srvrel->end(); ++i1)
{
FWObject *o = *i1;
FWObject *obj = NULL;
if (FWReference::cast(o)!=NULL) obj=FWReference::cast(o)->getPointer();
Service *s=Service::cast(obj);
assert(s!=NULL);
if (ICMPService::isA(s)) cl.push_back(s);
if (TCPService::isA(s) &&
s->getInt("dst_range_start")==22 &&
s->getInt("dst_range_end")==22) cl.push_back(s);
if (TCPService::isA(s) &&
s->getInt("dst_range_start")==23 &&
s->getInt("dst_range_end")==23) cl.push_back(s);
}
if ( !cl.empty() && rule->getDirection()!=PolicyRule::Outbound &&
(
dstrel->isAny() ||
( dstrel->size()==1 && dst!=NULL &&
!compiler->complexMatch(dst,compiler->fw) &&
dstrel->getBool("single_object_negation"))
)
)
{
PolicyRule *r= PolicyRule::cast(
compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
r->setDirection( PolicyRule::Inbound );
RuleElementDst *ndst=r->getDst();
ndst->clearChildren();
ndst->addRef(compiler->fw);
RuleElementSrv *nsrv=r->getSrv();
nsrv->clearChildren();
for (list<FWObject*>::iterator i=cl.begin(); i!=cl.end(); ++i)
nsrv->addRef( (*i) );
tmp_queue.push_back(r);
}
tmp_queue.push_back(rule); // add old rule in any case
return true;
}
bool PolicyCompiler_cisco::NegationPhase1::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
return true;
#ifdef DO_NEGATION
if (compiler->debug>=5) {
cerr << rule->getLabel() + " >>> neg 1 >>>>>>>>>>>>>>>>>>>>>>>>>>>>\n";
cerr << rule << " " << compiler->atomicRuleToString( rule );
}
RuleElementSrc *src=rule->getSrc(); assert(src);
RuleElementDst *dst=rule->getDst(); assert(dst);
RuleElementSrv *srv=rule->getSrv(); assert(srv);
/* do not use clearChildren because it
* destroys children objects (can delete
* rules created on the previous pass)
*/
compiler->temp_ruleset->clear();
if (src->getNeg()) {
PolicyRule *r= PolicyRule::cast(
getCompiler()->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
r->setStr("action","CONTINUE");
RuleElementSrc *nsrc=r->getSrc();
nsrc->setNeg(false);
vr->push_back(r);
r= PolicyRule::cast(
getCompiler()->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
nsrc=r->getSrc();
nsrc->clearChildren();
nsrc->setAnyElement();
nsrc->setNeg(false);
vr->push_back(r);
}
if (dst->getNeg()) {
PolicyRule *r= PolicyRule::cast(
getCompiler()->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
r->setStr("action","CONTINUE");
RuleElementDst *ndst=r->getDst();;
ndst->setNeg(false);
vr->push_back(r);
r= PolicyRule::cast(
getCompiler()->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
ndst=r->getDst();;
ndst->clearChildren();
ndst->setAnyElement();
ndst->setNeg(false);
vr->push_back(r);
}
if (srv->getNeg()) {
PolicyRule *r= PolicyRule::cast(
getCompiler()->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
r->setStr("action","CONTINUE");
RuleElementSrv *nsrv=r->getSrv();
nsrv->setNeg(false);
vr->push_back(r);
r= PolicyRule::cast(
getCompiler()->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
nsrv=r->getSrv();
nsrv->clearChildren();
nsrv->setAnyElement();
nsrv->setNeg(false);
vr->push_back(r);
}
if (vr->empty()) {
PolicyRule *r= PolicyRule::cast(
getCompiler()->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
if (compiler->debug>=5) {
cerr << "****************** copying rule\n";
rule->dump(true,true);
}
r->duplicate(rule);
vr->push_back(r);
}
if (compiler->debug>=5) {
cerr << rule->getLabel() + " <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n";
rule->dump(true,true);
cerr << " ------------------------------------------------\n";
for (vector<Rule*>::iterator i=vr->begin(); i!=vr->end(); i++) {
Rule *r=(*i);
r->dump(true,true);
cerr << r << " " << compiler->atomicRuleToString( r );
}
}
#endif
}
/**
* re_type can be either RuleElementSrc::TYPENAME or RuleElementDst::TYPENAME
*
* TODO: this has to move to class PolicyRuleProcessor
*/
bool PolicyCompiler_cisco::splitIfRuleElementMatchesFW::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
PolicyCompiler_cisco *cisco_comp=dynamic_cast<PolicyCompiler_cisco*>(compiler);
RuleElement *re=RuleElement::cast(rule->getFirstByType(re_type));
int nre=re->size();
list<FWObject*> cl;
for (list<FWObject*>::iterator i1=re->begin(); nre>1 && i1!=re->end(); ++i1)
{
FWObject *o = *i1;
FWObject *obj = NULL;
if (FWReference::cast(o)!=NULL) obj=FWReference::cast(o)->getPointer();
Address *a=Address::cast(obj);
assert(a!=NULL);
// IPAddress obj_addr=a->getAddress();
if (cisco_comp->complexMatch(a,cisco_comp->fw)) {
cl.push_back(o); // can not remove right now because remove invalidates iterator
nre--;
PolicyRule *new_rule= PolicyRule::cast(compiler->dbcopy->create(PolicyRule::TYPENAME) );
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( a );
tmp_queue.push_back(new_rule);
}
}
if (!cl.empty())
{
for (list<FWObject*>::iterator i1=cl.begin(); i1!=cl.end(); ++i1)
re->remove( (*i1) );
}
tmp_queue.push_back(rule);
return true;
}
bool PolicyCompiler_cisco::specialCaseWithDynInterface::dropDynamicInterface(
PolicyRule *rule, PolicyRule::Direction cmp_dir, RuleElement *re)
{
PolicyRule::Direction dir=rule->getDirection();
Interface *rule_iface = compiler->getCachedFwInterface(rule->getInterfaceId());
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())
{
if (ifs->getId()==rule_iface->getId() && dir==cmp_dir)
cl.push_back(obj); // keep it
else
continue; // remove it
} else
cl.push_back(obj);
}
if (re->size()==1 && cl.empty()) // remove the whole rule
return false;
if (!cl.empty())
{
re->clearChildren();
for (list<FWObject*>::iterator i1=cl.begin(); i1!=cl.end(); ++i1)
{
FWObject *oo = *i1;
re->addRef( oo );
}
}
return true;
}
/**
* checks for the following situations:
*
* assuming interface 'INT' is dynamic
*
* src. rule bound to interface direction decision
* -----------------------------------------------------------------
* INT INT outbound keep
* INT any other outbound remove
* INT INT inbound remove
* INT any other inbound remove
*
* dest. rule bound to interface direction decision
* -------------------------------------------------------------------
* INT INT inbound keep
* INT any other inbound remove
* INT INT outbound remove
* INT any other outbound remove
*
*/
bool PolicyCompiler_cisco::specialCaseWithDynInterface::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
if ( dropDynamicInterface( rule, PolicyRule::Outbound, rule->getSrc() ) &&
dropDynamicInterface( rule, PolicyRule::Inbound, rule->getDst() ) )
tmp_queue.push_back(rule);
return true;
}
/*
* processor splitIfRuleElementMatchesFW (or one derived from it)
* should have been called before tcpServiceToFW. This way we know
* that if dst is a firewall, it is a single object there.
*/
bool PolicyCompiler_cisco::tcpServiceToFW::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
PolicyCompiler_cisco *cisco_comp=dynamic_cast<PolicyCompiler_cisco*>(compiler);
// RuleElementSrc *src=rule->getSrc();
// RuleElementDst *dst=rule->getDst();
RuleElementSrv *srv=rule->getSrv();
Address *a=compiler->getFirstDst(rule);
assert(a!=NULL);
if (rule->getAction()==PolicyRule::Accept &&
compiler->complexMatch(a,cisco_comp->fw))
{
std::list<FWObject*> cl;
for (list<FWObject*>::iterator i1=srv->begin(); i1!=srv->end(); ++i1)
{
FWObject *o = *i1;
FWObject *obj = NULL;
if (FWReference::cast(o)!=NULL) obj=FWReference::cast(o)->getPointer();
Service *s=Service::cast(obj);
assert(s!=NULL);
if (TCPService::isA(s) &&
s->getInt("dst_range_start")==port &&
s->getInt("dst_range_end")==port) cl.push_back(o);
}
if (!cl.empty())
{
PolicyRule *r= PolicyRule::cast(compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
RuleElementDst *ndst=r->getDst();
ndst->clearChildren();
ndst->setAnyElement();
// ndst->addRef( compiler->fw );
RuleElementSrv *nsrv=r->getSrv();
nsrv->clearChildren();
nsrv->add( cl.front() );
r->setBool("ssh_telnet_cmd",true);
tmp_queue.push_back(r);
for (list<FWObject*>::iterator i1=cl.begin(); i1!=cl.end(); ++i1)
srv->remove( (*i1) );
if (srv->size()>0)
tmp_queue.push_back(rule);
} else
tmp_queue.push_back(rule);
} else
tmp_queue.push_back(rule);
return true;
}
/*
* firewall should be a single object in SRC. If object in SRC matches
* firewall (in a sence of complexMatch) but is not actual firewall object,
* do nothing assuming user wanted it that way.
*/
bool PolicyCompiler_cisco::replaceFWinSRCInterfacePolicy::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
Interface *rule_iface = compiler->getCachedFwInterface(rule->getInterfaceId());
if (rule_iface!=NULL && rule->getDirection()==PolicyRule::Outbound)
{
RuleElementSrc *src=rule->getSrc();
if (compiler->getFirstSrc(rule)->getId()==compiler->fw->getId())
{
src->clearChildren();
src->addRef(rule_iface);
}
}
tmp_queue.push_back(rule);
return true;
}
bool PolicyCompiler_cisco::replaceFWinDSTInterfacePolicy::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
Interface *rule_iface = compiler->getCachedFwInterface(rule->getInterfaceId());
if (rule_iface!=NULL && rule->getDirection()==PolicyRule::Inbound)
{
RuleElementDst *dst=rule->getDst();
if (compiler->getFirstDst(rule)->getId()==compiler->fw->getId())
{
dst->clearChildren();
dst->addRef(rule_iface);
}
}
tmp_queue.push_back(rule);
return true;
}
/*
* dst should contain objects that belong to the network zone of the
* same interface (use splitByNetworkZonesForRE for that)
*/
bool PolicyCompiler_cisco::replaceFWinDSTPolicy::processNext()
{
Helper helper(compiler);
PolicyRule *rule=getNext(); if (rule==NULL) return false;
Interface *rule_iface = compiler->getCachedFwInterface(rule->getInterfaceId());
if (rule_iface==NULL)
{
RuleElementSrc *src=rule->getSrc();
RuleElementDst *dst=rule->getDst();
if (!src->isAny() && compiler->getFirstDst(rule)->getId()==compiler->fw->getId())
{
try
{
string iface_id=helper.findInterfaceByNetzone(compiler->getFirstSrc(rule));
Interface *iface = compiler->getCachedFwInterface(iface_id);
dst->clearChildren();
dst->addRef(iface);
} catch (string addr)
{
ostringstream str;
str << "Address " << addr
<< " does not match address or network zone of any interface. Rule "
<< rule->getLabel()
<< endl;
compiler->abort(str.str());
}
}
}
tmp_queue.push_back(rule);
return true;
}
void PolicyCompiler_cisco::splitByNetworkZonesForRE::AddToInterface(
const std::string &interface_id,
libfwbuilder::Address *addr,
PolicyRule *rule)
{
PolicyRule *new_rule;
RuleElement *new_re;
new_rule=rules[interface_id];
if (new_rule==NULL)
{
new_rule= PolicyRule::cast(compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(new_rule);
new_rule->duplicate(rule);
rules[interface_id]=new_rule;
new_re=RuleElement::cast(new_rule->getFirstByType(re_type));
new_re->clearChildren();
new_re->setAnyElement();
}
new_re=RuleElement::cast(new_rule->getFirstByType(re_type));
new_re->addRef( addr );
}
bool PolicyCompiler_cisco::splitByNetworkZonesForRE::processNext()
{
Helper helper(compiler);
PolicyRule *rule=getNext(); if (rule==NULL) return false;
RuleElement *re=RuleElement::cast(rule->getFirstByType(re_type));
if (re->size()==1)
{
tmp_queue.push_back(rule);
return true;
}
rules.clear();
std::list<FWObject*> cl;
for (list<FWObject*>::iterator i1=re->begin(); i1!=re->end(); ++i1)
{
FWObject *o = *i1;
FWObject *obj = NULL;
if (FWReference::cast(o)!=NULL) obj=FWReference::cast(o)->getPointer();
Address *a=Address::cast(obj);
assert(a!=NULL);
// IPAddress obj_addr=a->getAddress();
try
{
string interface_id=helper.findInterfaceByNetzone(a);
AddToInterface(interface_id, a, rule);
} catch (string err)
{
// could not find interface with netzone to match address 'a'
// will assign rule to all interfaces. Act as if all interfaces
// had network zone 'any' and each matches this address.
// issue warning only if platform uses netwrk zones.
bool supports_network_zones =
Resources::getTargetCapabilityBool(
compiler->fw->getStr("platform"), "network_zones");
if (supports_network_zones)
compiler->warning(err + " Rule " + rule->getLabel());
FWObjectTypedChildIterator i =
compiler->fw->findByType(Interface::TYPENAME);
for ( ; i!=i.end(); ++i)
{
Interface *ifs = Interface::cast(*i);
AddToInterface(ifs->getId(), a, rule);
}
}
}
for (std::map<std::string,PolicyRule*>::iterator i=rules.begin();
i!=rules.end(); ++i)
{
tmp_queue.push_back((*i).second);
}
return true;
}
bool PolicyCompiler_cisco::equalObjCISCO::operator()(FWObject *o)
{
if (ICMPService::cast(obj)!=NULL && ICMPService::cast(o)!=NULL)
{
return (obj->getInt("type")==o->getInt("type"));
} else
return o->getId()==obj->getId();
}
/* re_type can be either RuleElementSrc::TYPENAME or RuleElementDst::TYPENAME */
bool PolicyCompiler_cisco::removeRedundantAddresses::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
RuleElement *re=RuleElement::cast(rule->getFirstByType(re_type));
if (re->size()==1)
{
tmp_queue.push_back(rule);
return true;
}
std::map<Address*,FWObject*> addrmap;
std::list<FWObject*> cl;
for (list<FWObject*>::iterator i1=re->begin(); i1!=re->end(); ++i1)
{
FWObject *obj = *i1;
if (FWReference::cast(obj)!=NULL) obj=FWReference::cast(obj)->getPointer();
Address *a=Address::cast(obj);
assert(a!=NULL); // assuming all objects are addresses.
addrmap[a] = *i1;
}
for (std::map<Address*,FWObject*>::iterator i1=addrmap.begin();
i1!=addrmap.end(); ++i1)
{
Address *a1 = i1->first;
for (std::map<Address*,FWObject*>::iterator i2=addrmap.begin();
i2!=addrmap.end(); ++i2)
{
Address *a2 = i2->first;
if (a1==a2) continue;
if (fwcompiler::checkForShadowing(*a1, *a2) ) cl.push_back(i1->second);
}
}
if (!cl.empty()) {
for (list<FWObject*>::iterator i1=cl.begin(); i1!=cl.end(); ++i1)
re->remove( (*i1) );
}
tmp_queue.push_back(rule);
return true;
}
bool PolicyCompiler_cisco::processMultiAddressObjectsInRE::processNext()
{
PolicyRule *rule = getNext(); if (rule==NULL) return false;
RuleElement *re = RuleElement::cast( rule->getFirstByType(re_type) );
for (FWObject::iterator i=re->begin(); i!=re->end(); i++)
{
FWObject *o = *i;
if (FWReference::cast(o)!=NULL) o = FWReference::cast(o)->getPointer();
MultiAddress *atrt = MultiAddress::cast(o);
if (atrt!=NULL && atrt->isRunTime())
compiler->abort("Run-time AddressTable and DNSName objects are not supported. Rule " + rule->getLabel());
}
tmp_queue.push_back(rule);
return true;
}
void PolicyCompiler_cisco::compile()
{
}
class acl_sort_order
{
public:
acl_sort_order() {};
bool operator()(const string &a, const string &b)
{
string::size_type i1,i2;
i1=a.find(' ',a.find(' ')+1);
i2=b.find(' ',b.find(' ')+1);
return a.substr(0,i1) < b.substr(0,i2);
}
};
void PolicyCompiler_cisco::regroup()
{
list<string> commands;
map<string,list<string> > script;
commands.push_back("THE_REST");
commands.push_back("access-list ");
commands.push_back("access-group ");
commands.push_back("icmp ");
commands.push_back("ssh ");
commands.push_back("telnet ");
string acl, agrp, icmp, telnet, ssh;
string new_output;
char buf[1024];
istringstream in(output.str());
while (in)
{
in.getline(buf, 1023, '\n');
strcat(buf,"\n");
if (buf[0]=='!') continue;
string slot="THE_REST";
string cmd(buf);
string::size_type n=cmd.find(' ');
list<string>::iterator s = ::find(commands.begin(),commands.end(),cmd.substr(0,n+1));
if (s!=commands.end()) slot = *s;
script[slot].push_back(buf);
}
script["access-list "].sort(acl_sort_order());
output.str("");
for (list<string>::iterator i=commands.begin(); i!=commands.end(); ++i)
{
for (list<string>::iterator j=script[*i].begin(); j!=script[*i].end(); ++j)
output << *j;
output << "! \n";
output << "! \n";
}
}
void PolicyCompiler_cisco::epilog()
{
}

View File

@ -0,0 +1,460 @@
/*
Firewall Builder
Copyright (C) 2002 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: PolicyCompiler_cisco.h,v 1.1 2008/03/06 06:48:56 vkurland Exp $
This program is free software which we release under the GNU General Public
License. You may redistribute and/or modify this program under the terms
of that license as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
To get a copy of the GNU General Public License, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __POLICYCOMPILER_CISCO_HH
#define __POLICYCOMPILER_CISCO_HH
#include <fwbuilder/libfwbuilder-config.h>
#include "fwcompiler/PolicyCompiler.h"
#include "fwbuilder/RuleElement.h"
#include "Helper.h"
#include "ACL.h"
namespace libfwbuilder {
class IPService;
class ICMPService;
class TCPService;
class UDPService;
class RuleElementSrc;
class RuleElementDst;
class RuleElementSrv;
class Group;
};
namespace fwcompiler {
class PolicyCompiler_cisco : public PolicyCompiler {
protected:
/**
* our firewall policy must block everything by default even
* if there are no rules. In iptables we do this by setting
* default chain policies to DROP. Here we do this by adding
* this unconditional blocking rule in the end. See also comment
* in the code regarding "pass_all_out" option
*/
void addDefaultPolicyRule();
/**
* prints rule in some universal format (close to that visible
* to user in the GUI). Used for debugging purposes. This method
* calls PolicyCompiler::_internalPrintPolicyRule and then adds
* fields specific to PIX rules at the end of the printout
*/
virtual std::string debugPrintRule(libfwbuilder::Rule *rule);
/**
* drops dynamic interface from the rule in the following
* cases because its address is unknown and we can not build
* ACL rule for it.
*
* assuming interface 'INT' is dynamic
*
* src. rule bound to interface direction decision
* -----------------------------------------------------------------
* INT INT outbound keep
* INT any other outbound remove
* INT INT inbound remove
* INT any other inbound remove
*
* dest. rule bound to interface direction decision
* -------------------------------------------------------------------
* INT INT inbound keep
* INT any other inbound remove
* INT INT outbound remove
* INT any other outbound remove
*
*
*/
friend class specialCaseWithDynInterface;
class specialCaseWithDynInterface : public PolicyRuleProcessor
{
bool dropDynamicInterface(libfwbuilder::PolicyRule *rule,
libfwbuilder::PolicyRule::Direction dir,
libfwbuilder::RuleElement *re);
public:
specialCaseWithDynInterface(const std::string &name) : PolicyRuleProcessor(name) {}
virtual bool processNext();
};
/**
* only for rules with interface element 'all' and direction
* 'both' or 'inbound'; for interfaces with zones that match
* src: create rule with that interface, direction
* inbound. 'Any' in src matches all interfaces.
*
* Set flag (boolean) 'interface_and_direction_set_from_src'
* so other rule processors in the same batch can skip the
* rule.
*/
DECLARE_POLICY_RULE_PROCESSOR( setInterfaceAndDirectionBySrc );
/**
* only for rules with interface element 'all'and direction
* 'both' or 'outbound'; for interfaces with zones that match
* dst: create rule with that interface, direction
* outbound. 'Any' in dst matches all interfaces.
*
* Set flag (boolean) 'interface_and_direction_set_from_dst'
* so other rule processors in the same batch can skip the
* rule.
*/
DECLARE_POLICY_RULE_PROCESSOR( setInterfaceAndDirectionByDst );
/**
* for rules with interface element not 'all' and direction
* 'both': create two rules with the same interface and
* directions Inbound and Outbound
*
* for rules with interface element not 'all' and direction
* 'inbound' or 'outbound': setInterfaceId to this interface
*
* Skip rule if flag 'interface_and_direction_set_from_src' or
* 'interface_and_direction_set_from_dst' is set
*
* Set flag (boolean) 'interface_and_direction_set'
* so other rule processors in the same batch can skip the
* rule.
*/
DECLARE_POLICY_RULE_PROCESSOR( setInterfaceAndDirectionIfInterfaceSet );
/**
* determine acl rules should belong to
*/
class pickACL : public PolicyRuleProcessor
{
bool using_named_acl;
public:
pickACL(bool use_named_acl,const std::string &name) :
PolicyRuleProcessor(name) {using_named_acl = use_named_acl;}
virtual bool processNext();
};
friend class PolicyCompiler_cisco::pickACL;
/**
* split rule if Src==any
*
* This is special case since we assume that "any" includes
* also a firewall object. Packets headed to or from the
* firewall must be inspected by INPUT or OUTPUT chain, while
* packets crossing the firewall are inspected by FORWARD
* chain. If we assume that "any" also includes firewall
* itself, then we need to generate code for both FORWARD and
* INPUT/OUTPUT chains from the same rule. This processor
* splits the rule onto two and sets chain and direction in
* the second copy appropriately. It preserve original src and
* dst in both copies, it only changes chain and direction in
* the second copy.
*/
DECLARE_POLICY_RULE_PROCESSOR(splitIfSrcAny);
/**
* split rule if Dst==any. See comment in splitIfSrcAny
*/
DECLARE_POLICY_RULE_PROCESSOR(splitIfDstAny);
/**
* TODO: move this processor to class PolicyCompiler. The same
* processor is used in ipt and in pf (although in pf there it
* is present in two copies that have different names
* splitIfFirewallInSrc and splitIfFirewallInDst). Move also
* splitIfSrcMatchesFw and splitIfDstMatchesFw
*/
friend class splitIfRuleElementMatchesFW;
class splitIfRuleElementMatchesFW : public PolicyRuleProcessor
{
std::string re_type;
public:
splitIfRuleElementMatchesFW(const std::string &n,
std::string _type) :
PolicyRuleProcessor(n) { re_type=_type; }
virtual bool processNext();
};
friend class splitIfSrcMatchesFw;
class splitIfSrcMatchesFw : public splitIfRuleElementMatchesFW
{
public:
splitIfSrcMatchesFw (const std::string &n) :
splitIfRuleElementMatchesFW(n,libfwbuilder::RuleElementSrc::TYPENAME) {}
};
class splitIfDstMatchesFw : public splitIfRuleElementMatchesFW
{
public:
splitIfDstMatchesFw (const std::string &n) :
splitIfRuleElementMatchesFW(n,libfwbuilder::RuleElementDst::TYPENAME) {}
};
friend class PolicyCompiler_cisco::splitIfDstMatchesFw;
/**
* find redundant objects in rule element and eliminate
* them. This only works for SRC and DST since all objects are
* assumed to be addresses. Redundant object is such that has
* narrower address range than some other object in the same
* rule element.
*/
friend class removeRedundantAddresses;
class removeRedundantAddresses : public PolicyRuleProcessor
{
std::string re_type;
public:
removeRedundantAddresses(const std::string &n,std::string _type) :
PolicyRuleProcessor(n) { re_type=_type; }
virtual bool processNext();
};
friend class removeRedundantAddressesFromSrc;
class removeRedundantAddressesFromSrc : public removeRedundantAddresses
{
public:
removeRedundantAddressesFromSrc (const std::string &n) :
removeRedundantAddresses(n,libfwbuilder::RuleElementSrc::TYPENAME) {}
};
friend class removeRedundantAddressesFromDst;
class removeRedundantAddressesFromDst : public removeRedundantAddresses
{
public:
removeRedundantAddressesFromDst (const std::string &n) :
removeRedundantAddresses(n,libfwbuilder::RuleElementDst::TYPENAME) {}
};
/**
* this processor splits rules if it finds rule that controls
* access for tcp service with port number "port" to the firewall
*/
class tcpServiceToFW : public PolicyRuleProcessor
{
int port;
public:
tcpServiceToFW(int p,const std::string &name) :
PolicyRuleProcessor(name) {port=p;}
virtual bool processNext();
};
friend class PolicyCompiler_cisco::tcpServiceToFW;
/**
* this processor splits rules if it finds telnet to firewall
*/
class telnetToFirewall : public tcpServiceToFW
{
public:
telnetToFirewall(const std::string &n):tcpServiceToFW(23,n) {}
};
friend class telnetToFirewall;
/**
* this processor splits rules if it finds ssh to firewall
*/
class sshToFirewall : public tcpServiceToFW
{
public:
sshToFirewall(const std::string &n):tcpServiceToFW(22,n) {}
};
friend class sshToFirewall;
/**
* replace fw with one of its interfaces in SRC in interface
* policy rule
*/
DECLARE_POLICY_RULE_PROCESSOR( replaceFWinSRCInterfacePolicy );
/**
* replace fw with one of its interfaces in DST in interface
* policy rule
*/
DECLARE_POLICY_RULE_PROCESSOR( replaceFWinDSTInterfacePolicy );
/**
* replace fw with one of its interfaces in DST in global
* policy rule
*/
DECLARE_POLICY_RULE_PROCESSOR( replaceFWinDSTPolicy );
/**
* this processor splits rules if objects in rule element
* re_type belong to different network zones
*/
class splitByNetworkZonesForRE : public PolicyRuleProcessor
{
std::string re_type;
std::map<std::string,libfwbuilder::PolicyRule*> rules;
void AddToInterface(const std::string &interface_id,
libfwbuilder::Address *addr,
libfwbuilder::PolicyRule *rule);
public:
splitByNetworkZonesForRE(const std::string &name,const std::string &_type) :
PolicyRuleProcessor(name) {re_type=_type; }
virtual bool processNext();
};
class splitByNetworkZonesForSrc : public splitByNetworkZonesForRE
{
public:
splitByNetworkZonesForSrc(const std::string &n):
splitByNetworkZonesForRE(n,libfwbuilder::RuleElementSrc::TYPENAME) {}
};
class splitByNetworkZonesForDst : public splitByNetworkZonesForRE
{
public:
splitByNetworkZonesForDst(const std::string &n):
splitByNetworkZonesForRE(n,libfwbuilder::RuleElementDst::TYPENAME) {}
};
/**
* this processor deals with negation in all fields by
* splitting the rule and using temporary action
* "CONTINUE". Rules must be filtered through NegationPhase2
* later
*/
DECLARE_POLICY_RULE_PROCESSOR( NegationPhase1 );
/**
* eliminates duplicate objects in rule element
* 're_type'. Uses special comparison function class to
* detect equivalent ICMP objects
*/
class equalObjCISCO : public PolicyCompiler::equalObj
{
public:
virtual bool operator()(libfwbuilder::FWObject *o);
};
class eliminateDuplicatesInRE_cisco : public PolicyCompiler::eliminateDuplicatesInRE
{
public:
eliminateDuplicatesInRE_cisco(const std::string &n,const std::string &re_type) :
eliminateDuplicatesInRE(n,re_type) { comparator=new equalObjCISCO(); }
};
/**
* eliminates duplicate objects in SRC.
*/
class eliminateDuplicatesInSRC : public eliminateDuplicatesInRE_cisco
{
public:
eliminateDuplicatesInSRC(const std::string &n) :
eliminateDuplicatesInRE_cisco(n,libfwbuilder::RuleElementSrc::TYPENAME) {}
};
/**
* eliminates duplicate objects in DST.
*/
class eliminateDuplicatesInDST : public eliminateDuplicatesInRE_cisco
{
public:
eliminateDuplicatesInDST(const std::string &n) :
eliminateDuplicatesInRE_cisco(n,libfwbuilder::RuleElementDst::TYPENAME) {}
};
/**
* eliminates duplicate objects in SRV
*/
class eliminateDuplicatesInSRV : public eliminateDuplicatesInRE_cisco
{
public:
eliminateDuplicatesInSRV(const std::string &n) :
eliminateDuplicatesInRE_cisco(n,libfwbuilder::RuleElementSrv::TYPENAME) {}
};
/**
* Placeholders for MultiAddressRunTime objects which are not
* supported for Cisco devices (IOS and PIX, at least)
*/
class processMultiAddressObjectsInRE : public PolicyRuleProcessor
{
std::string re_type;
public:
processMultiAddressObjectsInRE(const std::string &name,
const std::string &t) : PolicyRuleProcessor(name) { re_type=t; }
virtual bool processNext();
};
class processMultiAddressObjectsInSrc : public processMultiAddressObjectsInRE
{
public:
processMultiAddressObjectsInSrc(const std::string &n) :
processMultiAddressObjectsInRE(n,libfwbuilder::RuleElementSrc::TYPENAME) {}
};
class processMultiAddressObjectsInDst : public processMultiAddressObjectsInRE
{
public:
processMultiAddressObjectsInDst(const std::string &n) :
processMultiAddressObjectsInRE(n,libfwbuilder::RuleElementDst::TYPENAME) {}
};
protected:
Helper helper;
std::map<std::string,ciscoACL*> acls;
virtual std::string myPlatformName();
std::string mangleInterfaceName(const std::string &interface_name);
public:
PolicyCompiler_cisco(libfwbuilder::FWObjectDatabase *_db,
const std::string &fwname,
fwcompiler::OSConfigurator *_oscnf);
virtual ~PolicyCompiler_cisco() {}
virtual std::string createRuleLabel(const std::string &txt,
libfwbuilder::Interface *iface,
int rule_num);
virtual int prolog();
virtual void compile();
virtual void epilog();
/**
* sort commands ('icmp', 'telnet', 'ssh') and access lists
* in some kind of 'natural' order. Useful for both IOS and PIX
*/
void regroup();
};
}
#endif

View File

@ -0,0 +1,320 @@
/*
Firewall Builder
Copyright (C) 2002 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: PolicyCompiler_cisco_acls.cpp,v 1.1 2008/03/06 06:48:57 vkurland Exp $
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_cisco.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/Network.h"
#include "fwbuilder/Policy.h"
#include "fwbuilder/Interface.h"
#include "fwbuilder/Management.h"
#include "fwbuilder/Resources.h"
#include "fwbuilder/AddressTable.h"
#include <iostream>
#if __GNUC__ > 3 || \
(__GNUC__ == 3 && (__GNUC_MINOR__ > 2 || (__GNUC_MINOR__ == 2 ) ) ) || \
_MSC_VER
# include <streambuf>
#else
# include <streambuf.h>
#endif
#include <iomanip>
#include <algorithm>
#include <functional>
#include <map>
#include <assert.h>
#include <cctype>
using namespace libfwbuilder;
using namespace fwcompiler;
using namespace std;
bool PolicyCompiler_cisco::setInterfaceAndDirectionBySrc::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
Helper helper(compiler);
RuleElementItf *itfre=rule->getItf();
RuleElementSrc *srcre=rule->getSrc();
list<string> intf_id_list;
if (rule->getInterfaceId().empty())
{
if (rule->getDirection()==PolicyRule::Both)
intf_id_list = helper.findInterfaceByNetzoneOrAll( srcre );
if (rule->getDirection()==PolicyRule::Inbound)
intf_id_list = helper.getAllInterfaceIDs();
for (list<string>::iterator i = intf_id_list.begin(); i!=intf_id_list.end(); ++i)
{
string intf_id = *i;
Interface *ifs = Interface::cast(
rule->getRoot()->findInIndex(intf_id) );
assert(ifs);
if (ifs->isUnprotected()) continue; // skip!
PolicyRule *new_rule= PolicyRule::cast(compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(new_rule);
new_rule->duplicate(rule);
new_rule->setInterfaceId(intf_id);
new_rule->setDirection(PolicyRule::Inbound);
new_rule->setBool("interface_and_direction_set_from_src",true);
tmp_queue.push_back(new_rule);
}
// preserve original rule as well to let
// setInterfaceAndDirectionByDst work on it.
tmp_queue.push_back(rule);
return true;
}
tmp_queue.push_back(rule);
return true;
}
bool PolicyCompiler_cisco::setInterfaceAndDirectionByDst::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
Helper helper(compiler);
if (rule->getBool("interface_and_direction_set_from_src"))
{
tmp_queue.push_back(rule);
return true;
}
RuleElementItf *itfre=rule->getItf();
RuleElementDst *dstre=rule->getDst();
list<string> intf_id_list;
if (rule->getInterfaceId().empty())
{
if (rule->getDirection()==PolicyRule::Both)
intf_id_list = helper.findInterfaceByNetzoneOrAll( dstre );
if (rule->getDirection()==PolicyRule::Outbound)
intf_id_list = helper.getAllInterfaceIDs();
for (list<string>::iterator i = intf_id_list.begin(); i!=intf_id_list.end(); ++i)
{
string intf_id = *i;
Interface *ifs = Interface::cast(
rule->getRoot()->findInIndex(intf_id) );
assert(ifs);
if (ifs->isUnprotected()) continue; // skip!
PolicyRule *new_rule= PolicyRule::cast(compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(new_rule);
new_rule->duplicate(rule);
new_rule->setInterfaceId(intf_id);
new_rule->setDirection(PolicyRule::Outbound);
new_rule->setBool("interface_and_direction_set_from_dst",true);
tmp_queue.push_back(new_rule);
}
return true;
}
tmp_queue.push_back(rule);
return true;
}
bool PolicyCompiler_cisco::setInterfaceAndDirectionIfInterfaceSet::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
RuleElementItf *itfre=rule->getItf();
if (rule->getInterfaceId().empty() ||
rule->getBool("interface_and_direction_set_from_src") ||
rule->getBool("interface_and_direction_set_from_dst"))
{
tmp_queue.push_back(rule);
return true;
}
PolicyRule *new_rule;
if ( ! rule->getInterfaceId().empty() )
{
string rule_iface_id = rule->getInterfaceId();
if (rule->getDirection()==PolicyRule::Both)
{
new_rule =
PolicyRule::cast(compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(new_rule);
new_rule->duplicate(rule);
new_rule->setInterfaceId( rule_iface_id );
new_rule->setDirection(PolicyRule::Inbound);
new_rule->setBool("interface_and_direction_set",true);
tmp_queue.push_back(new_rule);
new_rule =
PolicyRule::cast(compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(new_rule);
new_rule->duplicate(rule);
new_rule->setInterfaceId( rule_iface_id );
new_rule->setDirection(PolicyRule::Outbound);
new_rule->setBool("interface_and_direction_set",true);
tmp_queue.push_back(new_rule);
} else
{
new_rule =
PolicyRule::cast(compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(new_rule);
new_rule->duplicate(rule);
new_rule->setInterfaceId( rule_iface_id );
// direction is copied from the original rule
new_rule->setBool("interface_and_direction_set",true);
tmp_queue.push_back(new_rule);
}
}
return true;
}
bool PolicyCompiler_cisco::pickACL::processNext()
{
PolicyCompiler_cisco *cisco_comp=dynamic_cast<PolicyCompiler_cisco*>(compiler);
PolicyRule *rule=getNext(); if (rule==NULL) return false;
Interface *rule_iface = compiler->getCachedFwInterface(rule->getInterfaceId());
if(rule_iface==NULL)
{
compiler->abort("Missing interface assignment for rule "+rule->getLabel());
}
/*
* option 'Generate outbound access lists' is called
* 'pix_generate_out_acl' for PIX and 'generate_out_acl' for
* IOS. Need to check the right one depending on what platform
* this compiler is for. Class PolicyCompiler_cisco is base class
* and can be used for both.
*/
bool generate_out_acl = false;
if (compiler->myPlatformName()=="pix")
generate_out_acl = compiler->fw->getOptionsObject()->
getBool("pix_generate_out_acl");
else
{
if (compiler->myPlatformName()=="iosacl")
generate_out_acl = true;
else
generate_out_acl = compiler->fw->getOptionsObject()->
getBool("generate_out_acl");
}
if (rule->getDirection() == PolicyRule::Outbound && !generate_out_acl)
compiler->abort("Rule with direction 'Outbound' requires outbound ACL but option 'Generate outbound access lists' is OFF. Rule " + rule->getLabel());
/* The choice of the ACL name depends on whether this is a named
* acl or not. If not, should use unique numbers. Also need to
* pass this flag to the ciscoACL object.
*/
string acl_name = rule_iface->getLabel();
if (acl_name.empty()) acl_name = rule_iface->getName();
acl_name = cisco_comp->mangleInterfaceName(acl_name) + "_acl";
string dir = "in";
if (rule->getDirection() == PolicyRule::Inbound) { acl_name += "_in"; dir="in"; }
if (rule->getDirection() == PolicyRule::Outbound) { acl_name += "_out"; dir="out"; }
rule->setStr("acl",acl_name);
ciscoACL *acl = new ciscoACL(acl_name, rule_iface, dir, using_named_acl);
cisco_comp->acls[acl_name] = acl;
acl->setWorkName(acl_name);
tmp_queue.push_back(rule);
return true;
}
/*
* Take interface name as an argument and produce
* shortened, space-free string that uniquely identifies interface
* in a human-readable way.
*/
std::string PolicyCompiler_cisco::mangleInterfaceName(const string &interface_name)
{
string::size_type n;
string s = interface_name;
// lowercase all characters
transform (s.begin(), s.end(), // source
s.begin(), // destination
::tolower); // operation
map<string,string> name_mapping;
map<string,string>::iterator nmi;
name_mapping["async"] = "as";
name_mapping["atm"] = "atm";
name_mapping["bri"] = "bri";
name_mapping["ethernet"] = "e";
name_mapping["fastethernet"] = "fe";
name_mapping["fddi"] = "fddi";
name_mapping["gigabitethernet"] = "ge";
name_mapping["hssi"] = "h";
name_mapping["loopback"] = "l";
name_mapping["port-channel"] = "pc";
name_mapping["pos"] = "pos";
name_mapping["serial"] = "s";
name_mapping["switch"] = "sw";
name_mapping["tokenring"] = "tr";
name_mapping["tunnel"] = "tun";
name_mapping["tengigabitethernet"] = "te";
name_mapping["sonet"] = "so";
name_mapping["vg-anylan"] = "vg";
for (nmi=name_mapping.begin(); nmi!=name_mapping.end(); nmi++)
{
if (s.find( nmi->first )==0)
{
s.replace(0, nmi->first.size(), nmi->second);
break;
}
}
while ( (n=s.find(" "))!=string::npos)
{
s.replace(n,1,"_");
}
while ( (n=s.find("/"))!=string::npos)
{
s.replace(n,1,"_");
}
return s;
}

View File

@ -0,0 +1,24 @@
#-*- mode: makefile; tab-width: 4; -*-
#
include(../../qmake.inc)
#
TEMPLATE = lib
#
SOURCES = PolicyCompiler_cisco.cpp \
PolicyCompiler_cisco_acls.cpp \
ACL.cpp \
Helper.cpp
HEADERS = ../../config.h \
ACL.h \
Helper.h \
PolicyCompiler_cisco.h
!macx:LIBS += $$LIBS_FWCOMPILER
# macx:LIBS += -L../../../libfwbuilder2-2.0.0/src/fwcompiler -lfwcompiler-2.0
CONFIG += staticlib
TARGET = fwbcisco
INSTALLS -= target

View File

@ -117,12 +117,6 @@ void init(char * const *argv)
if (n0!=string::npos) appRootDir=argv0.substr(0,n0) + FS_SEPARATOR;
else appRootDir="";
if (fwbdebug)
{
qDebug(QString("argv0=%1").arg(argv0.c_str()).toAscii().constData());
qDebug(QString("appRootDir=%1").arg(appRootDir.c_str()).toAscii().constData());
}
libfwbuilder::init();
#if defined(Q_OS_WIN32) || defined(Q_OS_MACX)

View File

@ -0,0 +1,230 @@
/*
Firewall Builder
Copyright (C) 2007 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: OSConfigurator_ios.cpp,v 1.1 2008/03/06 06:48:57 vkurland Exp $
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 "OSConfigurator_ios.h"
#include "Helper.h"
#include "fwbuilder/Resources.h"
#include "fwbuilder/Firewall.h"
#include "fwbuilder/FWOptions.h"
#include "fwbuilder/Interface.h"
#include "fwbuilder/Management.h"
#include "fwbuilder/Resources.h"
#include <list>
#include <algorithm>
#include <functional>
#include <assert.h>
#include <iostream>
using namespace libfwbuilder;
using namespace fwcompiler;
using namespace std;
string OSConfigurator_ios::myPlatformName() { return "ios"; }
int OSConfigurator_ios::prolog()
{
string host_os = fw->getStr("host_OS");
if (host_os!="ios")
abort("Unsupported OS " + host_os );
return Compiler::prolog();
}
void OSConfigurator_ios::processFirewallOptions()
{
// FWOptions* options=fw->getOptionsObject();
string s;
// int i;
string version = fw->getStr("version");
string platform = fw->getStr("platform");
if ( fw->getOptionsObject()->getBool("ios_set_host_name") )
{
output << "hostname " << fw->getName() << endl;
output << endl;
}
output << _printNameif();
output << endl;
output << _printIPAddress();
output << endl;
output << _printLogging();
output << endl;
}
string OSConfigurator_ios::_printNameif()
{
ostringstream res;
string version = fw->getStr("version");
string platform = fw->getStr("platform");
string::size_type n;
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);
string nameifCmd = Resources::platform_res[platform]->getResourceStr(
string("/FWBuilderResources/Target/options/version_")+
version+"/ios_commands/nameif");
if ((n = nameifCmd.find("%il"))!=string::npos)
nameifCmd.replace(n,3,iface->getLabel());
if ((n = nameifCmd.find("%in"))!=string::npos)
nameifCmd.replace(n,3,iface->getName());
res << nameifCmd;
}
res << endl;
return res.str();
}
string OSConfigurator_ios::_printIPAddress()
{
ostringstream res;
string version = fw->getStr("version");
string platform = fw->getStr("platform");
string setAddrCmd;
string::size_type n;
if ( fw->getOptionsObject()->getBool("ios_ip_address") )
{
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())
{
setAddrCmd = Resources::platform_res[platform]->getResourceStr(
string("/FWBuilderResources/Target/options/version_")+
version+"/ios_commands/ip_addr_dyn");
}
else
{
if (iface->isUnnumbered())
{
setAddrCmd = "";
} else
{
setAddrCmd = Resources::platform_res[platform]->getResourceStr(
string("/FWBuilderResources/Target/options/version_")+
version+"/ios_commands/ip_addr_static");
}
}
if ((n = setAddrCmd.find("%il"))!=string::npos)
setAddrCmd.replace(n,3,iface->getLabel());
if ((n = setAddrCmd.find("%in"))!=string::npos)
setAddrCmd.replace(n,3,iface->getName());
if ((n = setAddrCmd.find("%a"))!=string::npos)
setAddrCmd.replace(n,2,iface->getAddress().toString());
if ((n = setAddrCmd.find("%n"))!=string::npos)
setAddrCmd.replace(n,2,iface->getNetmask().toString());
res << setAddrCmd;
}
}
res << endl;
return res.str();
}
string OSConfigurator_ios::_printLogging()
{
Helper helper(this);
ostringstream str;
bool logging_on=false;
string syslog_host = fw->getOptionsObject()->getStr("ios_syslog_host");
string syslog_facility= fw->getOptionsObject()->getStr("ios_syslog_facility");
string trap_level= fw->getOptionsObject()->getStr("ios_logging_trap_level");
bool buffered= fw->getOptionsObject()->getBool("ios_logging_buffered");
string buffered_level= fw->getOptionsObject()->getStr("ios_logging_buffered_level");
bool console= fw->getOptionsObject()->getBool("ios_logging_console");
string console_level= fw->getOptionsObject()->getStr("ios_logging_console_level");
bool timestamp= fw->getOptionsObject()->getBool("ios_logging_timestamp");
if ( ! timestamp ) str << "no ";
str << "service timestamp log datetime localtime" << endl;
if ( ! syslog_host.empty() )
{
str << endl;
str << "logging host " << syslog_host << endl;
if ( ! syslog_facility.empty() )
str << "logging facility " << syslog_facility << endl;
if ( ! trap_level.empty() )
str << "logging trap " << trap_level << endl;
logging_on=true;
}
if ( ! buffered ) str << "no logging buffered" << endl;
else
{
str << "logging buffered " << buffered_level << endl;
logging_on=true;
}
if ( ! console ) str << "no logging console" << endl;
else
{
str << "logging console " << console_level << endl;
logging_on=true;
}
str << endl;
return str.str();
}
void OSConfigurator_ios::addVirtualAddressForNAT(const Address *addr)
{
if (addr==NULL) ;
}
void OSConfigurator_ios::addVirtualAddressForNAT(const Network *nw)
{
if (nw==NULL) ;
}

View File

@ -0,0 +1,59 @@
/*
Firewall Builder
Copyright (C) 2007 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: OSConfigurator_ios.h,v 1.1 2008/03/06 06:48:58 vkurland Exp $
This program is free software which we release under the GNU General Public
License. You may redistribute and/or modify this program under the terms
of that license as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
To get a copy of the GNU General Public License, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _OSNETWORKCONFIGURATOR_IOS_HH
#define _OSNETWORKCONFIGURATOR_IOS_HH
#include "config.h"
#include "fwcompiler/OSConfigurator.h"
#include <map>
namespace fwcompiler {
class OSConfigurator_ios : public OSConfigurator {
std::string _printNameif();
std::string _printIPAddress();
std::string _printLogging();
public:
virtual ~OSConfigurator_ios() {};
OSConfigurator_ios(libfwbuilder::FWObjectDatabase *_db,const std::string &fwname) :
OSConfigurator(_db,fwname) {}
virtual int prolog();
virtual std::string myPlatformName();
virtual void processFirewallOptions();
virtual void addVirtualAddressForNAT(const libfwbuilder::Address *addr);
virtual void addVirtualAddressForNAT(const libfwbuilder::Network *nw);
};
};
#endif

View File

@ -0,0 +1,404 @@
/*
Firewall Builder
Copyright (C) 2007 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: PolicyCompiler_iosacl.cpp,v 1.1 2008/03/06 06:48:58 vkurland Exp $
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_iosacl.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/Network.h"
#include "fwbuilder/Policy.h"
#include "fwbuilder/Interface.h"
#include "fwbuilder/Management.h"
#include "fwbuilder/Resources.h"
#include "fwbuilder/AddressTable.h"
#include <iostream>
#if __GNUC__ > 3 || \
(__GNUC__ == 3 && (__GNUC_MINOR__ > 2 || (__GNUC_MINOR__ == 2 ) ) ) || \
_MSC_VER
# include <streambuf>
#else
# include <streambuf.h>
#endif
#include <iomanip>
#include <algorithm>
#include <functional>
#include <assert.h>
using namespace libfwbuilder;
using namespace fwcompiler;
using namespace std;
string PolicyCompiler_iosacl::myPlatformName() { return "iosacl"; }
PolicyCompiler_iosacl::PolicyCompiler_iosacl(FWObjectDatabase *_db,
const std::string &fwname,
OSConfigurator *_oscnf) :
PolicyCompiler_cisco(_db,fwname,_oscnf)
{
resetinbound=false;
fragguard=false;
}
int PolicyCompiler_iosacl::prolog()
{
string version = fw->getStr("version");
string platform = fw->getStr("platform");
string host_os = fw->getStr("host_OS");
if (platform!="iosacl")
abort("Unsupported platform " + platform );
object_groups = new Group();
dbcopy->add( object_groups );
output << "!################" << endl;
if ( fw->getOptionsObject()->getBool("iosacl_acl_substitution") )
{
/* Generate short temporary ACL and assign it to all
* interfaces. This ACL permits IPSEC (IP proto 50 and UDP port 500)
as well as ssh from given subnet to any.
*/
string temp_acl = "tmp_acl";
string temp_acl_addr = fw->getOptionsObject()->getStr("iosacl_acl_temp_addr");
if (temp_acl_addr.empty())
{
abort("Missing address for management host or subnet for temporary ACL.\nPlease enter it in the tab 'Script options' in 'Firewall Settings' dialog");
}
string::size_type slash_idx = temp_acl_addr.find('/');
string addr = temp_acl_addr;
string netmask = "255.255.255.255";
if (slash_idx!=string::npos)
{
addr = temp_acl_addr.substr(0,slash_idx);
netmask = temp_acl_addr.substr(slash_idx+1);
try
{
if (netmask.find(".")!=string::npos)
{
Netmask nm(netmask);
nm.to32BitInt(); // to avoid warning abt unused var
} else
{
int nm_length;
istringstream str(netmask);
str >> nm_length;
Netmask nm(nm_length);
netmask = nm.toString();
}
} catch(FWException &ex)
{
abort("Invalid netmask for management subnet: '"+netmask+"'");
}
}
try
{
IPAddress a(addr);
a.to32BitInt();
} catch(FWException &ex)
{
abort("Invalid address for management subnet: '"+addr+"'");
}
string clearACLcmd = Resources::platform_res[platform]->getResourceStr(
string("/FWBuilderResources/Target/options/")+
"version_"+version+"/iosacl_commands/clear_ip_acl");
output << endl;
// cisco uses "wildcards" instead of netmasks
long nm = Netmask(netmask).to32BitInt();
struct in_addr na;
na.s_addr = ~nm;
IPAddress nnm(&na);
output << clearACLcmd << " " << temp_acl << endl;
output << "ip access-list extended " << temp_acl << endl;
output << " permit ip " << addr << " " << nnm.toString() << " any " << endl;
output << " deny ip any any " << endl;
output << "exit" << endl;
output << endl;
// find management interface
int nmi = 0;
list<FWObject*> ll = fw->getByType(Interface::TYPENAME);
for (FWObject::iterator i=ll.begin(); i!=ll.end(); i++)
{
Interface *intf = Interface::cast( *i );
if (intf->isManagement())
{
nmi++;
output << "interface " << intf->getName() << endl;
output << " no ip access-group in" << endl;
output << " no ip access-group out" << endl;
output << " ip access-group " << temp_acl << " in" << endl;
output << "exit" << endl;
}
}
if (nmi==0)
{
abort("One of the interfaces of the firewall must be marked as management interface.");
}
output << endl;
}
return PolicyCompiler::prolog();
}
bool PolicyCompiler_iosacl::checkForDynamicInterface::findDynamicInterface(
PolicyRule *rule, RuleElement *rel)
{
string vers=compiler->fw->getStr("version");
for (list<FWObject*>::iterator i1=rel->begin(); i1!=rel->end(); ++i1)
{
FWObject *o = *i1;
FWObject *obj = NULL;
if (FWReference::cast(o)!=NULL) obj=FWReference::cast(o)->getPointer();
Interface *iface=Interface::cast(obj);
if (iface!=NULL && iface->isDyn())
compiler->abort("Dynamic interface can not be used in the IOS ACL rules. Rule "+rule->getLabel());
}
return true;
}
bool PolicyCompiler_iosacl::checkForDynamicInterface::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
findDynamicInterface(rule,rule->getSrc());
findDynamicInterface(rule,rule->getDst());
tmp_queue.push_back(rule);
return true;
}
bool PolicyCompiler_iosacl::SpecialServices::processNext()
{
PolicyCompiler_iosacl *iosacl_comp=dynamic_cast<PolicyCompiler_iosacl*>(compiler);
PolicyRule *rule=getNext(); if (rule==NULL) return false;
Service *s=compiler->getFirstSrv(rule);
if (IPService::cast(s)!=NULL)
{
if (s->getBool("rr") ||
s->getBool("ssrr") ||
s->getBool("ts") )
compiler->abort("IOS ACL does not support checking for IP options in ACLs. Rule: "+rule->getLabel());
}
if (TCPService::cast(s)!=NULL) {
if (s->getBool("ack_flag") ||
s->getBool("fin_flag") ||
s->getBool("rst_flag") ||
s->getBool("syn_flag") )
compiler->abort("IOS ACL does not support checking for TCP options in ACLs. Rule: "+rule->getLabel());
}
tmp_queue.push_back(rule);
return true;
}
void PolicyCompiler_iosacl::compile()
{
cout << " Compiling policy for " << fw->getName() << " ..." << endl << flush;
try
{
string vers = fw->getStr("version");
string platform = fw->getStr("platform");
Compiler::compile();
addDefaultPolicyRule();
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"));
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 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 (" Start processing rules" ) );
add( new printTotalNumberOfRules ( ) );
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 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 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 splitServices ("split rules with different protocols" ) );
add( new ExpandMultipleAddressesInSRC(
"expand objects with multiple addresses in SRC" ) );
add( new MACFiltering ("check for MAC address filtering" ) );
// add( new splitByNetworkZonesForSrc ("split rule if objects in Src belong to different network zones " ) );
// add( new replaceFWinDSTPolicy ("replace fw with its interface in DST in global policy rules") );
add( new ExpandMultipleAddressesInDST(
"expand objects with multiple addresses in DST" ) );
add( new MACFiltering(
"check for MAC address filtering" ) );
// add( new splitByNetworkZonesForDst ("split rule if objects in Dst belong to different network zones " ) );
add( new checkForUnnumbered(
"check for unnumbered interfaces" ) );
add( new addressRanges ("process address ranges" ) );
add( new setInterfaceAndDirectionBySrc(
"Set interface and direction for rules with interface 'all' using SRC"));
add( new setInterfaceAndDirectionByDst(
"Set interface and direction for rules with interface 'all' using DST"));
add( new setInterfaceAndDirectionIfInterfaceSet(
"Set direction for rules with interface not 'all'"));
add( new specialCaseWithDynInterface(
"check for a special cases with dynamic interface" ) );
// first arg is true because we use "ip access-list" for IOS.
add( new pickACL( true, "assign ACLs" ) );
add( new SpecialServices( "check for special services" ) );
add( new checkForZeroAddr( "check for zero addresses" ) );
add( new checkForDynamicInterface("check for dynamic interfaces" ) );
/* remove redundant objects only after all splits has been
* done, right before object groups are created
*/
add( new removeRedundantAddressesFromSrc(
"remove redundant addresses from Src") );
add( new removeRedundantAddressesFromDst(
"remove redundant addresses from Dst") );
add( new ConvertToAtomic ("convert to atomic rules" ) );
add( new simplePrintProgress());
add( new createNewCompilerPass ("Creating ACLs ..."));
// add( new ClearACLs("Clear ACLs"));
// This processor prints each ACL separately in one block.
// It adds comments inside to denote original rules.
//
add( new PrintCompleteACLs("Print ACLs"));
// add( new PrintRule("generate code for ACLs"));
add( new simplePrintProgress());
runRuleProcessors();
} catch (FWException &ex) {
error(ex.toString());
exit(1);
}
}
string PolicyCompiler_iosacl::printAccessGroupCmd(ciscoACL *acl)
{
ostringstream str;
string dir;
if (acl->direction()=="in" || acl->direction()=="Inbound") dir="in";
if (acl->direction()=="out" || acl->direction()=="Outbound") dir="out";
str << "interface " << acl->getInterface()->getName() << endl;
str << " ip access-group " << acl->workName() << " " << dir << endl;
str << "exit" << endl;
return str.str();
}
void PolicyCompiler_iosacl::epilog()
{
output << endl;
for (map<string,ciscoACL*>::iterator i=acls.begin(); i!=acls.end(); ++i)
{
ciscoACL *acl=(*i).second;
if (acl->size()!=0) output << printAccessGroupCmd(acl);
}
output << endl;
if ( fw->getOptionsObject()->getBool("iosacl_regroup_commands") )
{
cout << " Regrouping commands \n" << flush;
regroup();
}
}

View File

@ -0,0 +1,267 @@
/*
Firewall Builder
Copyright (C) 2007 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: PolicyCompiler_iosacl.h,v 1.1 2008/03/06 06:48:58 vkurland Exp $
This program is free software which we release under the GNU General Public
License. You may redistribute and/or modify this program under the terms
of that license as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
To get a copy of the GNU General Public License, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __POLICYCOMPILER_IOSACL_HH
#define __POLICYCOMPILER_IOSACL_HH
#include <fwbuilder/libfwbuilder-config.h>
#include "fwcompiler/PolicyCompiler.h"
#include "fwbuilder/RuleElement.h"
#include "Helper.h"
#include "ACL.h"
#include "PolicyCompiler_cisco.h"
#include <functional>
namespace libfwbuilder {
class IPService;
class ICMPService;
class TCPService;
class UDPService;
class RuleElementSrc;
class RuleElementDst;
class RuleElementSrv;
class Group;
};
namespace fwcompiler {
class PolicyCompiler_iosacl : public PolicyCompiler_cisco {
protected:
/**
* dynamic interfaces can not be used in policy rules in IOS ACLs
*/
friend class checkForDynamicInterface;
class checkForDynamicInterface : public PolicyRuleProcessor
{
bool findDynamicInterface(libfwbuilder::PolicyRule *rule,
libfwbuilder::RuleElement *re);
public:
checkForDynamicInterface(const std::string &name) : PolicyRuleProcessor(name) {}
virtual bool processNext();
};
/*
*************************************************************************
*
* the following rule processors are intended for IOSACL < 7.0
* the code is in the module PolicyCompiler_iosacl_v6_acls.cpp
*
*************************************************************************
*/
/**
* verifies combination of interface and direction and
* fills interface and direction. After this predicate it
* is guaranteed that both interface and direction have
* some value. In certain situations interface ID may be
* set to "nil" though (e.g. global policy rules).
*/
DECLARE_POLICY_RULE_PROCESSOR( InterfaceAndDirection_v6 );
/**
* if interface has not been defined (this is global policy
* rule), then multiply the rule for each interface and set
* direction to "Inbound"
*/
DECLARE_POLICY_RULE_PROCESSOR( assignRuleToInterface_v6 );
/**
* split rules with direction "both".
* TODO: This is used in OpenBSD pf. Move to class PolicyCompiler
*/
DECLARE_POLICY_RULE_PROCESSOR( SplitDirection_v6 );
/**
* in IOSACL, ACLs are always applied on interface and direction
* can only be "inbound". We emulate outbound ACLs though.
*/
DECLARE_POLICY_RULE_PROCESSOR( EmulateOutboundACL_v6 );
/**
* determine acl rules should belong to
*/
DECLARE_POLICY_RULE_PROCESSOR( pickACL_v6 );
friend class PolicyCompiler_iosacl::pickACL_v6;
/*
*************************************************************************
*
* end of module PolicyCompiler_iosacl_v6_acls.cpp
*
*************************************************************************
*/
/*
*************************************************************************
*
* rule processors intended to manage ACLs for IOSACL < 7.0 are inherited
* from PolicyCompiler_cisco.
* The code is in the module PolicyCompiler_cisco_acls.cpp
*
* The processors assume that all objects in src and dst
* belong to the same network zone (respectively)
*
* All these rule processors assume outbound ACLs are supported.
* Check corresponding capability flag and do not include these
* processors in the processors chain in iosacl.cpp if outbound acls
* are not supported.
*
*************************************************************************
*/
/**
* this processor checks for the services which require
* special treatment. Some of these will be checking for
* source or destination object as well because special
* command may need to be generated in case source or
* destination is a firewall itself. Therefore this processor
* should be called after converting to atomic rules, but
* before interface addresses in source and destination are
* expanded.
*/
DECLARE_POLICY_RULE_PROCESSOR( SpecialServices );
friend class PolicyCompiler_iosacl::SpecialServices;
/**
* to implement action "Reject" add command "service resetinbound"
*/
DECLARE_POLICY_RULE_PROCESSOR( RejectAction );
friend class PolicyCompiler_iosacl::RejectAction;
/**
* this processor accumulates all rules fed to it by previous
* * processors, prints commands to clear access-lists, then
* feeds all rules to the next processor. Usually this
* processor is in chain right before PrintRules.
*
* We use this processor to print "clear" commands because
* they need to be generated when all access lists have been
* created but before they are printed.
*/
class ClearACLs : public PolicyRuleProcessor
{
public:
ClearACLs(const std::string &n) : PolicyRuleProcessor(n) {}
virtual bool processNext();
};
friend class PolicyCompiler_iosacl::ClearACLs;
/**
* this processor prints single policy rule, assuming all
* groups have been expanded, so source, destination and
* service hold exactly one object each, and this object is
* not a group. Negation should also have been taken care of
* before this method is called.
*/
class PrintRule : public PolicyRuleProcessor
{
protected:
std::string current_rule_label1;
std::map<std::string,std::string> current_rule_label2;
int aclLineCounter;
std::string _printSrcService(libfwbuilder::Service *srv);
std::string _printDstService(libfwbuilder::Service *srv);
std::string _printAddr(libfwbuilder::Address *o);
std::string _printAction(libfwbuilder::PolicyRule *r);
std::string _printACL(libfwbuilder::PolicyRule *r);
std::string _printLog(libfwbuilder::PolicyRule *r);
std::string _printFragm(libfwbuilder::Service *srv);
std::string _printRule(libfwbuilder::PolicyRule *rule);
public:
PrintRule(const std::string &name) : PolicyRuleProcessor(name) { aclLineCounter=0; }
virtual bool processNext();
};
friend class PolicyCompiler_iosacl::PrintRule;
/**
* this processor accumulates all rules fed to it by previous
* * processors, prints commands to clear access-lists, then
* generates commands for the new ACLs.
*
*/
class PrintCompleteACLs : public PrintRule
{
public:
PrintCompleteACLs(const std::string &n) : PrintRule(n) {}
virtual bool processNext();
struct printRulesForACL : public std::unary_function<libfwbuilder::Rule*, void>
{
ciscoACL *acl;
std::stringstream *output;
PolicyCompiler_iosacl *iosacl_comp;
PolicyCompiler_iosacl::PrintCompleteACLs *print_acl_p;
printRulesForACL(PolicyCompiler_iosacl *_comp,
PolicyCompiler_iosacl::PrintCompleteACLs *pp,
ciscoACL* _acl,
std::stringstream *_out)
{ iosacl_comp = _comp; print_acl_p = pp; acl = _acl; output = _out; }
// print rule if it belongs to ACL <acl>
void operator() (libfwbuilder::Rule* x);
};
friend struct PrintCompleteACLs::printRulesForACL;
};
friend class PolicyCompiler_iosacl::PrintCompleteACLs;;
bool resetinbound;
bool fragguard;
// storage for object groups created to be used with IOSACL command object-group
libfwbuilder::Group *object_groups;
protected:
virtual std::string myPlatformName();
std::string printAccessGroupCmd(ciscoACL *acl);
public:
PolicyCompiler_iosacl(libfwbuilder::FWObjectDatabase *_db,
const std::string &fwname,
fwcompiler::OSConfigurator *_oscnf);
virtual ~PolicyCompiler_iosacl() {}
virtual int prolog();
virtual void compile();
virtual void epilog();
};
}
#endif

View File

@ -0,0 +1,434 @@
/*
Firewall Builder
Copyright (C) 2007 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: PolicyCompiler_iosacl_writers.cpp,v 1.1 2008/03/06 06:48:58 vkurland Exp $
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 "PolicyCompiler_iosacl.h"
#include "fwbuilder/Firewall.h"
#include "fwbuilder/AddressRange.h"
#include "fwbuilder/RuleElement.h"
#include "fwbuilder/IPService.h"
#include "fwbuilder/ICMPService.h"
#include "fwbuilder/TCPService.h"
#include "fwbuilder/UDPService.h"
#include "fwbuilder/CustomService.h"
#include "fwbuilder/Policy.h"
#include "fwbuilder/FWOptions.h"
#include "fwbuilder/FWObjectDatabase.h"
#include "fwbuilder/Interface.h"
#include "fwbuilder/IPv4.h"
#include "fwbuilder/Network.h"
#include "fwbuilder/Management.h"
#include "fwbuilder/Resources.h"
#include <iostream>
#if __GNUC__ > 3 || \
(__GNUC__ == 3 && (__GNUC_MINOR__ > 2 || (__GNUC_MINOR__ == 2 ) ) ) || \
_MSC_VER
# include <streambuf>
#else
# include <streambuf.h>
#endif
#include <iomanip>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <functional>
#include <assert.h>
using namespace libfwbuilder;
using namespace fwcompiler;
using namespace std;
bool PolicyCompiler_iosacl::ClearACLs::processNext()
{
PolicyCompiler_iosacl *iosacl_comp=dynamic_cast<PolicyCompiler_iosacl*>(compiler);
string vers = compiler->fw->getStr("version");
string platform = compiler->fw->getStr("platform");
string clearACLcmd = Resources::platform_res[platform]->getResourceStr(
string("/FWBuilderResources/Target/options/")+
"version_"+vers+"/iosacl_commands/clear_acl");
slurp();
if (tmp_queue.size()==0) return false;
if ( compiler->fw->getOptionsObject()->getBool("iosacl_acl_basic") )
{
compiler->output << clearACLcmd << endl;
}
if (compiler->fw->getOptionsObject()->getBool("iosacl_acl_substitution"))
{
for (map<string,ciscoACL*>::iterator i=iosacl_comp->acls.begin();
i!=iosacl_comp->acls.end(); ++i)
{
ciscoACL *acl=(*i).second;
compiler->output << clearACLcmd << " " << acl->workName() << endl;
}
compiler->output << endl;
}
if ( !compiler->fw->getOptionsObject()->getBool("iosacl_acl_no_clear") )
{
string clearICMPcmd = Resources::platform_res[platform]->getResourceStr(
string("/FWBuilderResources/Target/options/")+
"version_"+vers+"/iosacl_commands/clear_icmp");
string clearTelnetcmd = Resources::platform_res[platform]->getResourceStr(
string("/FWBuilderResources/Target/options/")+
"version_"+vers+"/iosacl_commands/clear_telnet");
string clearSSHcmd = Resources::platform_res[platform]->getResourceStr(
string("/FWBuilderResources/Target/options/")+
"version_"+vers+"/iosacl_commands/clear_ssh");
//compiler->output << clearICMPcmd << endl;
//compiler->output << clearTelnetcmd << endl;
//compiler->output << clearSSHcmd << endl;
}
return true;
}
void PolicyCompiler_iosacl::PrintCompleteACLs::printRulesForACL::operator()(
Rule* rule)
{
// print rule if it belongs to ACL <acl>
PolicyRule *prule = PolicyRule::cast(rule);
string acl_name = prule->getStr("acl");
assert (acl_name!="");
ciscoACL *rule_acl = iosacl_comp->acls[acl_name];
assert(rule_acl!=NULL);
if (acl == rule_acl)
{
*output << print_acl_p->_printRule(prule);
}
}
bool PolicyCompiler_iosacl::PrintCompleteACLs::processNext()
{
PolicyCompiler_iosacl *iosacl_comp=dynamic_cast<PolicyCompiler_iosacl*>(compiler);
string vers = compiler->fw->getStr("version");
string platform = compiler->fw->getStr("platform");
string clearACLCmd = Resources::platform_res[platform]->getResourceStr(
string("/FWBuilderResources/Target/options/")+
"version_"+vers+"/iosacl_commands/clear_ip_acl");
assert( !clearACLCmd.empty());
slurp();
if (tmp_queue.size()==0) return false;
if ( compiler->fw->getOptionsObject()->getBool("iosacl_acl_basic") ||
compiler->fw->getOptionsObject()->getBool("iosacl_acl_substitution"))
{
for (map<string,ciscoACL*>::iterator i=iosacl_comp->acls.begin();
i!=iosacl_comp->acls.end(); ++i)
{
ciscoACL *acl=(*i).second;
compiler->output << clearACLCmd << " " << acl->workName() << endl;
}
compiler->output << endl;
}
for (map<string,ciscoACL*>::iterator i=iosacl_comp->acls.begin();
i!=iosacl_comp->acls.end(); ++i)
{
ciscoACL *acl=(*i).second;
compiler->output << "ip access-list extended " << acl->workName() << endl;
std::for_each(tmp_queue.begin(), tmp_queue.end(),
printRulesForACL(iosacl_comp, this, acl, &(compiler->output)));
compiler->output << "exit" << endl;
compiler->output << endl;
}
return true;
}
string PolicyCompiler_iosacl::PrintRule::_printRule(PolicyRule *rule)
{
PolicyCompiler_iosacl *iosacl_comp =
dynamic_cast<PolicyCompiler_iosacl*>(compiler);
FWOptions *ruleopt =rule->getOptionsObject();
bool write_comments =
compiler->fw->getOptionsObject()->getBool("iosacl_include_comments");
ostringstream ruleout;
ostringstream aclstr;
string rl=rule->getLabel();
if (write_comments)
{
if (rl!=current_rule_label1)
{
ruleout << "! " << endl;
ruleout << "! Rule " << rl << endl;
string comm=rule->getComment();
string::size_type c1,c2;
c1=0;
while ( (c2=comm.find('\n',c1))!=string::npos ) {
ruleout << "! " << comm.substr(c1,c2-c1) << endl;
c1=c2+1;
}
ruleout << "! " << comm.substr(c1) << endl;
ruleout << "! " << endl;
current_rule_label1=rl;
}
}
/*
* all three rule elements contain exactly one object, which can
* be either group (in case processor CreateObjectGroups created
* object group for it) or a regular object
*/
RuleElementSrc *src=rule->getSrc();
RuleElementDst *dst=rule->getDst();
RuleElementSrv *srv=rule->getSrv();
assert(src->size()==1);
assert(dst->size()==1);
assert(srv->size()==1);
FWObject *srcobj=src->front();
FWObject *dstobj=dst->front();
FWObject *srvobj=srv->front();
assert(srcobj);
assert(dstobj);
assert(srvobj);
if (FWReference::cast(srcobj)!=NULL)
{
srcobj=FWReference::cast(srcobj)->getPointer();
assert(srcobj);
}
if (FWReference::cast(dstobj)!=NULL)
{
dstobj=FWReference::cast(dstobj)->getPointer();
assert(dstobj);
}
if (FWReference::cast(srvobj)!=NULL)
{
srvobj=FWReference::cast(srvobj)->getPointer();
assert(srvobj);
}
string acl_name=rule->getStr("acl");
assert (acl_name!="");
ciscoACL *acl = iosacl_comp->acls[acl_name];
assert(acl!=NULL);
/*
* Assemble ACL command in aclstr
*/
aclstr << _printAction(rule);
aclstr << Service::cast(srvobj)->getProtocolName();
aclstr << " ";
aclstr << _printAddr( compiler->getFirstSrc(rule) );
aclstr << _printSrcService( compiler->getFirstSrv(rule) );
aclstr << _printAddr( compiler->getFirstDst(rule) );
aclstr << _printDstService( compiler->getFirstSrv(rule) );
aclstr << _printLog( rule );
// "fragments" should be the last option in the access-list command
aclstr << _printFragm( compiler->getFirstSrv(rule) );
// aclstr << endl;
ruleout << acl->addLine(aclstr.str());
return ruleout.str();
}
string PolicyCompiler_iosacl::PrintRule::_printAction(PolicyRule *rule)
{
ostringstream str;
switch (rule->getAction()) {
case PolicyRule::Accept: str << "permit "; break;
case PolicyRule::Deny: str << "deny "; break;
case PolicyRule::Reject: str << "deny "; break;
default: str << rule->getActionAsString() << " ";
}
return str.str();
}
string PolicyCompiler_iosacl::PrintRule::_printACL(PolicyRule *rule)
{
// PolicyCompiler_iosacl *iosacl_comp=dynamic_cast<PolicyCompiler_iosacl*>(compiler);
string acl_name=rule->getStr("acl");
assert (acl_name!="");
return acl_name+" ";
}
string PolicyCompiler_iosacl::PrintRule::_printLog(PolicyRule *rule)
{
if (rule->getLogging())
{
FWOptions *ruleopt =rule->getOptionsObject();
if (ruleopt->getBool("iosacl_log_input")) return "log-input ";
return "log ";
}
return "";
}
string PolicyCompiler_iosacl::PrintRule::_printSrcService(libfwbuilder::Service *srv)
{
ostringstream str;
if (TCPService::isA(srv) || UDPService::isA(srv))
{
int rs=srv->getInt("src_range_start");
int re=srv->getInt("src_range_end");
if (rs<0) rs=0;
if (re<0) re=0;
if (rs>0 || re>0) {
if (rs==re) str << "eq " << rs << " ";
else
if (rs==0 && re!=0) str << "lt " << re << " ";
else
if (rs!=0 && re==65535) str << "gt " << rs << " ";
else
str << "range " << rs << " " << re << " ";
}
}
return str.str();
}
string PolicyCompiler_iosacl::PrintRule::_printFragm(Service *srv)
{
if (IPService::isA(srv) && (srv->getBool("fragm") || srv->getBool("short_fragm")))
return "fragments ";
return "";
}
string PolicyCompiler_iosacl::PrintRule::_printDstService(Service *srv)
{
ostringstream str;
if (TCPService::isA(srv) || UDPService::isA(srv))
{
int rs=srv->getInt("dst_range_start");
int re=srv->getInt("dst_range_end");
if (rs<0) rs=0;
if (re<0) re=0;
if (rs>0 || re>0) {
if (rs==re) str << "eq " << rs << " ";
else
if (rs==0 && re!=0) str << "lt " << re << " ";
else
if (rs!=0 && re==65535) str << "gt " << rs << " ";
else
str << "range " << rs << " " << re << " ";
}
}
if (TCPService::isA(srv) && srv->getBool("established"))
str << "established ";
if (ICMPService::isA(srv) && srv->getInt("type")!=-1)
str << srv->getStr("type") << " ";
return str.str();
}
string PolicyCompiler_iosacl::PrintRule::_printAddr(libfwbuilder::Address *o)
{
ostringstream str;
IPAddress srcaddr=o->getAddress();
Netmask srcmask=o->getNetmask();
if (Interface::cast(o)!=NULL)
{
Interface *interface_=Interface::cast(o);
if (interface_->isDyn())
{
return string("interface ") + interface_->getLabel() + " ";
}
srcmask=Netmask("255.255.255.255");
}
if (IPv4::cast(o)!=NULL)
srcmask=Netmask("255.255.255.255");
if (srcaddr.toString()=="0.0.0.0" && srcmask.toString()=="0.0.0.0")
{
str << "any ";
} else {
if (srcmask.toString()=="255.255.255.255")
{
str << "host " << srcaddr.toString() << " ";
} else
{
str << srcaddr.toString() << " ";
// cisco uses "wildcards" instead of netmasks
long nm = srcmask.to32BitInt();
struct in_addr na;
na.s_addr = ~nm;
IPAddress nnm(&na);
str << nnm.toString() << " ";
}
}
return str.str();
}
/*
* the following additional attributes should have been defined by now:
*
* "acl" - string, name of the access list
* choices are: outside-in, outside-out, inside-in, indside-out,
* dmz-in, dmz-out etc.
* General rule for the acl name: "iface_name-{in,out}"
*/
bool PolicyCompiler_iosacl::PrintRule::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
tmp_queue.push_back(rule);
compiler->output << _printRule(rule);
return true;
}

429
src/iosacl/iosacl.cpp Normal file
View File

@ -0,0 +1,429 @@
/*
Firewall Builder
Copyright (C) 2007 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: iosacl.cpp,v 1.2 2008/03/09 05:13:55 vkurland Exp $
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 <qsettings.h>
#include <fstream>
#include <iostream>
#include <sstream>
#include <map>
#include <algorithm>
#include <functional>
#ifdef _WIN32
# include <direct.h>
#else
# include <unistd.h>
#endif
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>
#include <assert.h>
#include "PolicyCompiler_iosacl.h"
#include "OSConfigurator_ios.h"
#include "fwcompiler/Preprocessor.h"
#include "fwbuilder/Resources.h"
#include "fwbuilder/FWObjectDatabase.h"
#include "fwbuilder/Firewall.h"
#include "fwbuilder/Interface.h"
#include "fwbuilder/IPv4.h"
#include "fwbuilder/XMLTools.h"
#include "fwbuilder/FWException.h"
#include "fwbuilder/Tools.h"
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#else
#ifdef _WIN32
#include <getopt.h>
#else
#include <stdlib.h>
#endif
#endif
#include "../common/init.cpp"
using namespace std;
using namespace libfwbuilder;
using namespace fwcompiler;
static const char *filename = NULL;
static const char *wdir = NULL;
static const char *fwobjectname = NULL;
static string ofname = "";
static int dl = 0;
static int drp = -1;
static int drn = -1;
static int verbose = 0;
static int test_mode = 0;
FWObjectDatabase *objdb = NULL;
class UpgradePredicate: public XMLTools::UpgradePredicate
{
public:
virtual bool operator()(const string &msg) const
{
msg.size(); // to make compiler happy about unused parameter
cout << "Data file has been created in the old version of Firewall Builder.\nLoad it in the GUI to convert it to the new version." << endl;
return false;
}
};
void usage(const char *name)
{
cout << "Firewall Builder: policy compiler for Cisco IOS ACL" << endl;
cout << "Copyright 2002-2004 NetCitadel, LLC" << endl;
cout << "Version " << VERSION << "-" << RELEASE_NUM << endl;
cout << "Usage: " << name << " [-tvV] [-f filename.xml] [-d destdir] [-o output.fw] firewall_object_name" << endl;
}
int main(int argc, char * const * argv)
{
if (argc<=1)
{
usage(argv0.c_str());
exit(1);
}
int opt;
while( (opt=getopt(argc,argv,"x:vVf:d:r:tLo:")) != EOF )
{
switch(opt)
{
case 'd':
wdir = strdup(optarg);
break;
case 'r':
respath = string(optarg);
break;
case 'f':
filename = strdup(optarg);
break;
case 'o':
ofname = string(optarg);
break;
case 'x':
if (*optarg=='p') {
++optarg;
drp = atoi(optarg);
} else {
if (*optarg=='n') {
++optarg;
drn = atoi(optarg);
} else {
if (isdigit(*optarg)) dl=atoi(optarg); // increase debug level
else {
usage(argv[0]);
exit(1);
}
}
}
break;
case 't':
test_mode++;
break;
case 'v':
verbose++;
break;
case 'V':
usage(argv[0]);
exit(1);
case 'h':
usage(argv[0]);
exit(1);
}
}
init(argv);
if((argc-1) != optind)
{
usage(argv[0]);
exit(1);
}
fwobjectname = strdup( argv[optind++] );
if (ofname.empty())
{
ofname=string(fwobjectname)+".fw";
}
if (filename==NULL || fwobjectname==NULL)
{
usage(argv[0]);
exit(1);
}
if (wdir==0) wdir="./";
if (
#ifdef _WIN32
_chdir(wdir)
#else
chdir(wdir)
#endif
) {
cerr << "Can't change working directory to: " << wdir << endl;
exit(1);
}
if (test_mode)
cout << "*** Running in test mode, all errors are ignored" << endl << endl;
try
{
new Resources(respath+FS_SEPARATOR+"resources.xml");
/* create database */
objdb = new FWObjectDatabase();
/* load the data file */
UpgradePredicate upgrade_predicate;
if (verbose) cout << " *** Loading data ...";
objdb->setReadOnly( false );
objdb->load( filename, &upgrade_predicate, librespath);
objdb->setFileName(filename);
objdb->reIndex();
if (verbose) cout << " done\n";
/* why do I do this ?
FWObject *slib = objdb->findInIndex("syslib000");
if ( slib->isReadOnly()) slib->setReadOnly(false);
*/
/*
* some general sanity checks first
*/
Firewall* fw=objdb->findFirewallByName(fwobjectname);
FWOptions* options=fw->getOptionsObject();
string fwvers = fw->getStr("version");
if (fwvers == "") fw->setStr("version", "12.x");
bool ios_acl_basic=options->getBool("ios_acl_basic");
bool ios_acl_no_clear=options->getBool("ios_acl_no_clear");
bool ios_acl_substitution=options->getBool("ios_acl_substitution");
bool ios_add_clear_statements=options->getBool("ios_add_clear_statements");
if ( !ios_acl_basic &&
!ios_acl_no_clear &&
!ios_acl_substitution )
{
if ( ios_add_clear_statements ) options->setBool("ios_acl_basic",true);
else options->setBool("ios_acl_no_clear",true);
}
Helper helper(NULL);
std::list<FWObject*> l2=fw->getByType(Interface::TYPENAME);
for (std::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];
for (list<FWObject*>::iterator j=l3.begin(); j!=l3.end(); ++j)
if ( objdb->findAllReferences(*j).size()!=0 )
{
sprintf(errstr,
_("Dynamic interface %s has an IP address that is used in the firewall policy rule.\n"),
iface->getName().c_str() );
throw FWException(errstr);
}
sprintf(errstr,
_("Dynamic interface %s should not have an IP address object attached to it. This IP address object will be ignored.\n"),
iface->getName().c_str() );
cerr << errstr;
for (list<FWObject*>::iterator j=l3.begin(); j!=l3.end(); ++j)
iface->remove(*j);
}
}
/*
* no address
*/
if (iface->isRegular())
{
FWObject *ipv4=iface->getFirstByType(IPv4::TYPENAME);
if (ipv4==NULL)
throw FWException(
"Interface "+
iface->getName()+" ("+iface->getLabel()+") has no address." );
}
}
char timestr[256];
time_t tm;
tm=time(NULL);
strcpy(timestr,ctime(&tm));
timestr[ strlen(timestr)-1 ]='\0';
#ifdef _WIN32
char* user_name=getenv("USERNAME");
#else
char* user_name=getenv("USER");
#endif
if (user_name==NULL)
throw FWException("Can't figure out your user name, aborting");
Preprocessor* prep=new Preprocessor(objdb , fwobjectname);
prep->compile();
/*
* Process firewall options, build OS network configuration script
*/
OSConfigurator *oscnf=NULL;
oscnf=new OSConfigurator_ios(objdb , fwobjectname);
oscnf->prolog();
oscnf->processFirewallOptions();
/* create compilers and run the whole thing */
PolicyCompiler_iosacl *c = new PolicyCompiler_iosacl(objdb,
fwobjectname,
oscnf);
if (test_mode) c->setTestMode();
c->setDebugLevel( dl );
c->setDebugRule( drp );
c->setVerbose( verbose );
if ( c->prolog() > 0 ) {
c->compile();
c->epilog();
} else
cout << " Nothing to compile in Policy \n" << flush;
#ifdef _WIN32
ofstream ofile(ofname.c_str(), ios::out|ios::binary);
#else
ofstream ofile(ofname.c_str());
#endif
ofile << "!\n\
! This is automatically generated file. DO NOT MODIFY !\n\
!\n\
! Firewall Builder fwb_iosacl v" << VERSION << "-" << RELEASE_NUM << " \n\
!\n\
! Generated " << timestr
<< " "
<< tzname[0]
<< " by "
<< user_name;
ofile << endl;
string vers = fw->getStr("version");
string platform = fw->getStr("platform");
ofile << "!" << endl;
ofile << "!" << " Compiled for " << platform << " " << vers << endl;
ofile << "!" << endl;
ofile << "!" << MANIFEST_MARKER << "* " << ofname << endl;
ofile << "!" << endl;
ofile << endl;
ofile << "!" << endl;
ofile << "! Prolog script:" << endl;
ofile << "!" << endl;
string pre_hook= fw->getOptionsObject()->getStr("ios_prolog_script");
ofile << pre_hook << endl;
ofile << "!" << endl;
ofile << "! End of prolog script:" << endl;
ofile << "!" << endl;
ofile << oscnf->getCompiledScript();
ofile << endl;
ofile << c->getCompiledScript();
ofile << endl;
ofile << endl;
ofile << "!" << endl;
ofile << "! Epilog script:" << endl;
ofile << "!" << endl;
string post_hook= fw->getOptionsObject()->getStr("ios_epilog_script");
ofile << post_hook << endl;
ofile << endl;
ofile << "! End of epilog script:" << endl;
ofile << "!" << endl;
ofile.close();
cout << _(" Compiled successfully") << endl << flush;
} catch(libfwbuilder::FWException &ex) {
cerr << ex.toString() << endl;
return 1;
} catch (std::string s) {
cerr << s << endl;
return 1;
} catch (std::exception ex) {
cerr << "exception: " << ex.what() << endl;
return 1;
} catch (...) {
cerr << "Unsupported exception";
return 1;
}
return 0;
}

36
src/iosacl/iosacl.pro Normal file
View File

@ -0,0 +1,36 @@
#-*- mode: makefile; tab-width: 4; -*-
#
include(../../qmake.inc)
#
#
# PACKAGE = fwbuilder-iosacl-$$FWB_VERSION
#
# QMAKE_CXXFLAGS_DEBUG += -DPACKAGE="\"$$PACKAGE\""
# QMAKE_CXXFLAGS_RELEASE += -DPACKAGE="\"$$PACKAGE\""
SOURCES = OSConfigurator_ios.cpp \
iosacl.cpp \
PolicyCompiler_iosacl.cpp \
PolicyCompiler_iosacl_writers.cpp \
HEADERS = ../../config.h \
OSConfigurator_ios.h \
PolicyCompiler_iosacl.h \
../cisco_lib/PolicyCompiler_cisco.h \
../cisco_lib/ACL.h \
../cisco_lib/Helper.h
# CONFIG -= qt
QMAKE_COPY = /usr/bin/install -m 0755 -s
win32:CONFIG += console
INCLUDEPATH += ../cisco_lib/
win32:LIBS += $$PREFIX/fwbcisco.lib
!win32:LIBS += ../cisco_lib/libfwbcisco.a
LIBS += $$LIBS_FWCOMPILER
TARGET = fwb_iosacl

1590
src/pix/NATCompiler_pix.cpp Normal file
View File

@ -0,0 +1,1590 @@
/*
Firewall Builder
Copyright (C) 2002 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: NATCompiler_pix.cpp,v 1.1 2008/03/06 06:48:59 vkurland Exp $
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 "NATCompiler_pix.h"
#include "fwbuilder/FWObjectDatabase.h"
#include "fwbuilder/RuleElement.h"
#include "fwbuilder/NAT.h"
#include "fwbuilder/AddressRange.h"
#include "fwbuilder/ICMPService.h"
#include "fwbuilder/TCPService.h"
#include "fwbuilder/UDPService.h"
#include "fwbuilder/Interface.h"
#include "fwbuilder/IPv4.h"
#include "fwbuilder/IPAddress.h"
#include "fwbuilder/Network.h"
#include "fwbuilder/Resources.h"
#include "fwbuilder/AddressTable.h"
#include <algorithm>
#include <functional>
#include <iostream>
#include <assert.h>
using namespace libfwbuilder;
using namespace fwcompiler;
using namespace std;
string NATCompiler_pix::myPlatformName() { return "pix"; }
NATCompiler_pix::NATCompiler_pix(FWObjectDatabase *_db,
const std::string &fwname,
OSConfigurator *_oscnf) :
NATCompiler(_db,fwname,_oscnf) , helper(this)
{
}
string NATCompiler_pix::getNATACLname(Rule *rule,int nat_id)
{
int n=-1;
string res;
do
{
n++;
ostringstream os;
os << rule->getUniqueId() << "." << nat_id << "." << n;
res=os.str();
} while (nat_acl_names.count(res)!=0);
return res;
}
string NATCompiler_pix::getNATACLname(Rule *rule,string suffix)
{
int n=-1;
string res;
do
{
n++;
ostringstream os;
os << rule->getUniqueId();
if (!suffix.empty()) os << "." << suffix;
os << "." << n;
res=os.str();
} while (nat_acl_names.count(res)!=0);
return res;
}
int NATCompiler_pix::prolog()
{
global_pool_no=1;
final_ruleset=new NAT();
fw->add( final_ruleset );
return NATCompiler::prolog();
}
string NATCompiler_pix::debugPrintRule(Rule *r)
{
NATRule *rule=NATRule::cast(r);
Interface *iface1 = getCachedFwInterface( rule->getStr("nat_iface_orig") );
Interface *iface2 = getCachedFwInterface( rule->getStr("nat_iface_trn") );
string iface1_name=(iface1!=NULL)?iface1->getName():"";
string iface2_name=(iface2!=NULL)?iface2->getName():"";
ostringstream os;
switch (rule->getRuleType())
{
case NATRule::NONAT:
break;
case NATRule::SNAT:
{
if ( ! rule->exists("nat_cmd") ) break;
NATCmd *natcmd=nat_commands[ rule->getInt("nat_cmd") ];
if (natcmd!=NULL)
{
os <<" NATCmd: ";
os << " rule=[" << natcmd->rule_label << "]";
os << " id=" << natcmd->nat_id;
os << " rule=" << natcmd->rule_label;
os << " nat_acl_name=" << natcmd->nat_acl_name;
os << " (" << nat_acl_names[natcmd->nat_acl_name] << ")";
os << " o_src=" << natcmd->o_src->getAddress().toString();
os << " o_dst=" << natcmd->o_dst->getAddress().toString();
os << " o_srv=" << natcmd->o_srv->getName();
os << " o_iface=" << natcmd->o_iface->getLabel();
os << " t_addr=" << natcmd->t_addr->getAddress().toString();
os << " t_iface=" << natcmd->t_iface->getLabel();
os << " ignore_global=" << string((natcmd->ignore_global)?"1":"0");
os << " ignore_nat=" << string((natcmd->ignore_nat)?"1":"0");
os << " ignore_nat_and_print_acl=" << string((natcmd->ignore_nat_and_print_acl)?"1":"0");
os << " use_nat_0_0=" << string((rule->getBool("use_nat_0_0"))?"1":"0");
}
}
break;
case NATRule::DNAT:
{
if ( ! rule->exists("sc_cmd") ) break;
StaticCmd *scmd=static_commands[ rule->getInt("sc_cmd") ];
if (scmd!=NULL)
{
os << " StaticCmd:";
os << " acl=" << scmd->acl_name;
os << " (" << nat_acl_names[scmd->acl_name] << ")";
os << " iaddr=" << scmd->iaddr->getAddress().toString();
os << " oaddr=" << scmd->oaddr->getAddress().toString();
os << " osrc=" << scmd->osrc->getAddress().toString();
os << " osrv=" << scmd->osrv->getName();
os << " tsrv=" << scmd->tsrv->getName();
}
}
break;
default: ; // TODO: should actually be always_assert
}
return NATCompiler::debugPrintRule(rule)+
" "+iface1_name+" "+iface2_name+
" (type="+rule->getRuleTypeAsString()+") "+
"use_nat_0_0=" + string((rule->getBool("use_nat_0_0"))?"1":"0") + " " +
os.str();
}
bool NATCompiler_pix::storeProcessedRules::processNext()
{
NATCompiler_pix *pix_comp=dynamic_cast<NATCompiler_pix*>(compiler);
NATRule *rule=getNext(); if (rule==NULL) return false;
tmp_queue.push_back(rule);
pix_comp->final_ruleset->add(rule);
return true;
}
list<triplet> NATCompiler_pix::findDNATForAddress(Address *src,
Address *dst,
Service *srv)
{
list<triplet> res;
map<string,triplet> res_dict;
for (FWObject::iterator i=final_ruleset->begin();
i!=final_ruleset->end(); ++i)
{
NATRule *rule=NATRule::cast(*i);
switch (rule->getRuleType())
{
case NATRule::DNAT:
{
Address *osrc=getFirstOSrc(rule); assert(osrc);
Address *odst=getFirstODst(rule); assert(odst);
Service *osrv=getFirstOSrv(rule); assert(osrv);
Address *tsrc=getFirstTSrc(rule); assert(tsrc);
Address *tdst=getFirstTDst(rule); assert(tdst);
Service *tsrv=getFirstTSrv(rule); assert(tsrv);
if (src->getAddress()==osrc->getAddress() &&
(osrv->isAny() || srv->getId()==tsrv->getId()) &&
dst->getAddress()==tdst->getAddress())
{
if (osrv->isAny())
{
triplet tr(src,odst,srv);
res_dict[tr.hash()] = tr;
}
else
{
triplet tr(src,odst,osrv);
res_dict[tr.hash()] = tr;
}
}
}
break;
default: ; // TODO: should actually be always_assert
}
}
for (map<string,triplet>::iterator i=res_dict.begin();
i!=res_dict.end(); ++i)
{
res.push_back(i->second);
}
return res;
}
bool NATCompiler_pix::VerifyRules::processNext()
{
NATRule *rule=getNext(); if (rule==NULL) return false;
string vers=compiler->fw->getStr("version");
tmp_queue.push_back(rule);
bool version_lt_63= ( compiler->fw->getStr("platform")=="pix" &&
libfwbuilder::XMLTools::version_compare(compiler->fw->getStr("version"),"6.3")<0); // fwsm is always above 6.3 - its OS is based on 6.3
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 (rule->getRuleType()==NATRule::LB)
compiler->abort("Load balancing rules are not supported. Rule "+rule->getLabel());
if (rule->getRuleType()==NATRule::NONAT && (!osrv->isAny() || !tsrv->isAny()))
compiler->abort("'no nat' rules should have no services");
if (osrc->getNeg() ||
odst->getNeg() ||
osrv->getNeg() ||
tsrc->getNeg() ||
tdst->getNeg() ||
tsrv->getNeg())
compiler->abort("Negation is not supported in NAT rules. Rule "+rule->getLabel());
if (rule->getRuleType()==NATRule::SNAT)
{
// if ( tsrc->size()!=1)
// compiler->abort("There should be no more than one object in translated source in the rule "+rule->getLabel());
if ( ! odst->isAny() && version_lt_63) // can do on fwsm
{
compiler->warning("Original destination is ignored in 'nat' NAT rules when compiling for PIX v6.2 and earlier. Rule "+rule->getLabel());
odst->clearChildren();
odst->setAnyElement();
}
}
if (rule->getRuleType()==NATRule::DNAT)
{
if ( odst->size()!=1 && version_lt_63)
compiler->abort("There should be no more than one object in original destination in the rule "+rule->getLabel());
if ( ! osrc->isAny() && version_lt_63)
compiler->warning("Original source is ignored in 'static' NAT rules when compiling for PIX v6.2 and earlier. Rule "+rule->getLabel());
}
if (osrv->size()!=1 && !tsrv->isAny())
compiler->abort("Can not translate multiple services into one service in one rule. Rule: "+rule->getLabel());
if (tsrv->size()!=1)
compiler->abort("Translated service should be 'Original' or should contain single object. Rule: "+rule->getLabel());
if ( Group::cast( compiler->getFirstTSrv(rule) )!=NULL)
compiler->abort("Can not use group in translated service. Rule "+rule->getLabel());
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->getNetmask().getLength()!=a2->getNetmask().getLength() )
compiler->abort("Original and translated source should both be networks of the same size . Rule "+rule->getLabel());
}
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->getNetmask().getLength()!=a2->getNetmask().getLength() )
compiler->abort("Original and translated destination should both be networks of the same size . Rule "+rule->getLabel());
}
if (rule->getRuleType()==NATRule::SNetnat) rule->setRuleType(NATRule::SNAT);
if (rule->getRuleType()==NATRule::DNetnat) rule->setRuleType(NATRule::DNAT);
return true;
}
bool NATCompiler_pix::AssignInterface::processNext()
{
Helper helper(compiler);
NATRule *rule=getNext(); if (rule==NULL) return false;
tmp_queue.push_back(rule);
Address *a1=NULL;
Address *a2=NULL;
if (rule->getRuleType()==NATRule::SNAT) {
a1=compiler->getFirstOSrc(rule);
a2=compiler->getFirstTSrc(rule);
}
if (rule->getRuleType()==NATRule::DNAT) {
a1=compiler->getFirstODst(rule);
a2=compiler->getFirstTDst(rule);
}
if (rule->getRuleType()==NATRule::NONAT) {
a1=compiler->getFirstOSrc(rule);
a2=compiler->getFirstODst(rule);
}
assert(a1!=NULL && a2!=NULL);
rule->setStr("nat_iface_orig",helper.findInterfaceByNetzone(a1));
rule->setStr("nat_iface_trn", helper.findInterfaceByNetzone(a2));
if ( rule->getStr("nat_iface_orig")=="" )
compiler->abort("Object '"+a1->getName()+"' does not belong to any known network zone. Rule: "+rule->getLabel());
if ( rule->getStr("nat_iface_trn")=="" )
compiler->abort("Object '"+a2->getName()+"' does not belong to any known network zone. Rule: "+rule->getLabel());
// if ( rule->getStr("nat_iface_orig")==rule->getStr("nat_iface_trn"))
// compiler->abort("Objects '"+a1->getName()+"' and '"+a2->getName()+"' belong to the same network zone. Can not build NAT configuration. Rule: "+rule->getLabel());
return true;
}
bool NATCompiler_pix::verifyInterfaces::processNext()
{
NATRule *rule=getNext(); if (rule==NULL) return false;
tmp_queue.push_back(rule);
#ifdef WRONG_CHECK
if ( rule->getStr("nat_iface_orig")!=rule->getStr("nat_iface_trn") )
{
if (rule->getRuleType()==NATRule::SNAT) {
Interface *iface1=
Interface::cast( rule->getRoot()->findInIndex(rule->getStr("nat_iface_orig")) );
Interface *iface2=
Interface::cast( rule->getRoot()->findInIndex(rule->getStr("nat_iface_trn")) );
if ( iface1->getSecurityLevel() <= iface2->getSecurityLevel() ) {
char lvl1[32];
char lvl2[32];
sprintf(lvl1,"%d",iface1->getSecurityLevel());
sprintf(lvl2,"%d",iface2->getSecurityLevel());
compiler->abort(
"Security level of internal interface "+
iface1->getName() + " (level "+ lvl1 +") "+
" set lower than that of external interface "+
iface2->getName() + " (level "+ lvl2 +") "+
" for NAT rule "+rule->getLabel());
}
}
}
#endif
return true;
}
bool NATCompiler_pix::verifyRuleElements::processNext()
{
NATRule *rule=getNext(); if (rule==NULL) return false;
tmp_queue.push_back(rule);
Address *osrc=compiler->getFirstOSrc(rule); assert(osrc);
Address *odst=compiler->getFirstODst(rule); assert(odst);
Service *osrv=compiler->getFirstOSrv(rule); assert(osrv);
Address *tsrc=compiler->getFirstTSrc(rule); assert(tsrc);
Address *tdst=compiler->getFirstTDst(rule); assert(tdst);
Service *tsrv=compiler->getFirstTSrv(rule); assert(tsrv);
bool version_lt_63=libfwbuilder::XMLTools::version_compare(compiler->fw->getStr("version"),"6.3")<0;
if (rule->getRuleType()==NATRule::SNAT)
{
if ((! osrv->isAny() || ! tsrv->isAny()) && version_lt_63)
compiler->abort("only PIX v6.3 recognizes services in global NAT. Rule: "+rule->getLabel() );
}
if (rule->getRuleType()==NATRule::DNAT)
{
if (AddressRange::cast(odst) || AddressRange::cast(tdst))
compiler->abort(
"Address ranges are not supported in original destination or translated destination in NAT rule "+rule->getLabel() );
if (Network::isA(odst) && Network::isA(tdst))
{
Netmask n1=(Interface::cast(odst))?Netmask("255.255.255.255"):odst->getNetmask();
Netmask n2=(Interface::cast(tdst))?Netmask("255.255.255.255"):tdst->getNetmask();
if ( !(n1==n2) )
compiler->abort(
"Original and translated destination must be of the same size in the NAT rule "+rule->getLabel());
}
if (osrv->getTypeName()!=tsrv->getTypeName())
compiler->abort("Original and translated services must be of the same type. Rule: "+rule->getLabel());
if (ICMPService::isA(osrv))
compiler->abort("ICMP services are not supported in static NAT. Rule: "+rule->getLabel());
if (TCPService::isA(osrv) || UDPService::isA(osrv))
{
int drs=osrv->getInt("dst_range_start");
int dre=osrv->getInt("dst_range_end");
if (drs!=dre)
compiler->abort("TCP or UDP service with a port range is not supported in NAT. Rule "+rule->getLabel());
}
if (TCPService::isA(tsrv) || UDPService::isA(tsrv))
{
int drs=tsrv->getInt("dst_range_start");
int dre=tsrv->getInt("dst_range_end");
if (drs!=dre)
compiler->abort("TCP or UDP service with a port range is not supported in NAT. Rule "+rule->getLabel());
}
}
return true;
}
bool NATCompiler_pix::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;
}
/**
* unlike standard inspector addressRanges in the base class NATCompiler,
* this one does not expand address ranges in TSrc and TDst
*/
bool NATCompiler_pix::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);
#if 0
// if we want to support NAT rules with address ranges. For example,
// could compile these as a bunch of individual host translations
switch (rule->getRuleType())
{
case NATRule::SNAT:
rel=rule->getTSrc(); assert(rel);
compiler->_expandAddressRanges(rule,rel);
break;
case NATRule::DNAT:
rel=rule->getTDst(); assert(rel);
compiler->_expandAddressRanges(rule,rel);
break;
}
#endif
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_pix::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;
case NATRule::DNAT:
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() &&
interface_->isExt() ) 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 );
}
}
}
default: ; // TODO: should actually be always_assert
}
return true;
}
bool NATCompiler_pix::ReplaceFirewallObjectsTSrc::processNext()
{
Helper helper(compiler);
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;
case NATRule::SNAT:
{
int osrc_level=100;
Address *osrc=NULL;
Interface *osrc_iface=NULL;
if ( ! rule->getOSrc()->isAny())
{
osrc=compiler->getFirstOSrc(rule); assert(osrc!=NULL);
osrc_iface=compiler->getCachedFwInterface( helper.findInterfaceByNetzone(osrc ) );
osrc_level=osrc_iface->getSecurityLevel();
}
rel=rule->getTSrc(); assert(rel);
obj=compiler->getFirstTSrc(rule); assert(obj!=NULL);
if (obj->getId()==compiler->getFwId() )
{
/* if ODst is 'any', pick all interfaces with security level _less_ than
* level of the interface OSrc is associated with. If ODst is not 'any',
* find interface it is associated with and use only it.
*/
if (rule->getODst()->isAny())
{
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_->getSecurityLevel()<osrc_level )
cl.push_back(interface_);
}
} else
{
Address *odst=compiler->getFirstODst(rule); assert(odst!=NULL);
Interface *odst_iface=compiler->getCachedFwInterface( helper.findInterfaceByNetzone(odst ) );
if (odst_iface!=NULL) cl.push_back(odst_iface);
}
if ( ! cl.empty() ) {
while (rel->size())
rel->remove( rel->front() );
for (FWObject::iterator i1=cl.begin(); i1!=cl.end(); ++i1)
{
rel->addRef( *i1 );
}
}
}
}
break;
default: ; // TODO: should actually be always_assert
}
return true;
}
void NATCompiler_pix::UseFirewallInterfaces::scanInterfaces(RuleElement *rel)
{
FWObject *o= rel->front();
if (FWReference::cast(o)!=NULL) o=FWReference::cast(o)->getPointer();
Address *obj=Address::cast(o);
if(obj==NULL)
compiler->abort("Broken rule element "+
rel->getTypeName()+
" in rule "+
NATRule::cast(rel->getParent())->getLabel()+
" ( found object with type "+
string((o!=NULL)?o->getTypeName():"<NULL>") +
")");
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_->getAddress()==obj->getAddress())
{
rel->removeRef(obj);
rel->addRef(interface_);
return;
}
}
}
bool NATCompiler_pix::UseFirewallInterfaces::processNext()
{
NATRule *rule=getNext(); if (rule==NULL) return false;
tmp_queue.push_back(rule);
RuleElement *rel;
rel=rule->getODst(); assert(rel);
if (!rel->isAny()) scanInterfaces(rel);
rel=rule->getTSrc(); assert(rel);
if (!rel->isAny()) scanInterfaces(rel);
return true;
}
bool NATCompiler_pix::processNONATRules::processNext()
{
Helper helper(compiler);
NATCompiler_pix *pix_comp=dynamic_cast<NATCompiler_pix*>(compiler);
NATRule *rule=getNext(); if (rule==NULL) return false;
tmp_queue.push_back(rule);
if (rule->getRuleType()==NATRule::NONAT) {
Address *osrc=compiler->getFirstOSrc(rule); assert(osrc);
Address *odst=compiler->getFirstODst(rule); assert(odst);
Interface *osrc_iface=compiler->getCachedFwInterface( helper.findInterfaceByNetzone(osrc ) );
Interface *odst_iface=compiler->getCachedFwInterface( helper.findInterfaceByNetzone(odst ) );
int osrc_level=osrc_iface->getSecurityLevel();
int odst_level=odst_iface->getSecurityLevel();
/*
* PIX has two types of NONAT rules, one is when connection goes from
* low security interface to the high security interface and another
* for the opposite
*/
if (osrc_level>odst_level)
{
rule->setInt("nonat_type",NONAT_NAT0);
nonat n0;
n0.i_iface=osrc_iface;
n0.o_iface=odst_iface;
n0.src=osrc;
n0.dst=odst;
n0.acl_name="nat0."+osrc_iface->getLabel();
n0.last=true;
pix_comp->nonat_rules[rule->getId()]= n0;
pix_comp->registerACL(n0.acl_name);
if ( pix_comp->first_nonat_rule_id[osrc_iface->getId()].empty() )
pix_comp->first_nonat_rule_id[osrc_iface->getId()]=rule->getId();
} else
{
rule->setInt("nonat_type",NONAT_STATIC);
}
}
return true;
}
bool NATCompiler_pix::createNATCmd::processNext()
{
// Helper helper(compiler);
NATCompiler_pix *pix_comp=dynamic_cast<NATCompiler_pix*>(compiler);
NATRule *rule=getNext(); if (rule==NULL) return false;
tmp_queue.push_back(rule);
if (rule->getRuleType()==NATRule::SNAT)
{
Address *osrc=compiler->getFirstOSrc(rule); assert(osrc);
Address *odst=compiler->getFirstODst(rule); assert(osrc);
Service *osrv=compiler->getFirstOSrv(rule); assert(osrv);
Address *tsrc=compiler->getFirstTSrc(rule); assert(tsrc);
NATCmd *natcmd=new NATCmd();
natcmd->nat_id=nat_id_counter;
natcmd->rule_label=rule->getLabel();
natcmd->o_src = osrc;
natcmd->o_dst = odst;
natcmd->o_srv = osrv;
natcmd->o_iface = compiler->getCachedFwInterface( rule->getStr("nat_iface_orig") );
natcmd->t_addr = tsrc;
natcmd->t_iface = compiler->getCachedFwInterface( rule->getStr("nat_iface_trn" ) );
natcmd->nat_acl_name = pix_comp->getNATACLname(rule,"");
pix_comp->registerACL(natcmd->nat_acl_name);
if (Interface::cast(tsrc)!=NULL || natcmd->t_iface->isDyn())
{
natcmd->type=INTERFACE;
} else {
if (Network::cast(tsrc))
{
natcmd->type=NETWORK_ADDRESS;
} else {
if (AddressRange::cast(tsrc)) natcmd->type=ADDRESS_RANGE;
else natcmd->type=SINGLE_ADDRESS;
}
}
natcmd->ignore_nat=natcmd->ignore_nat_and_print_acl=natcmd->ignore_global=false;
natcmd->use_nat_0_0 = rule->getBool("use_nat_0_0");
/*
* "nat ... outside" is only supported in PIX 6.2
*/
natcmd->outside= ( natcmd->o_iface->getSecurityLevel()<natcmd->t_iface->getSecurityLevel());
if (natcmd->outside && compiler->fw->getStr("platform")=="pix" &&
libfwbuilder::XMLTools::version_compare(compiler->fw->getStr("version"),"6.2")<0 )
compiler->abort("Bi-Directional NAT of source addresses is only supported in PIX 6.2 and newer. Rule "+rule->getLabel());
/*
* map is sorted container, this means that objects are going to be arranged
* in nat_commands in the order of the key.
*/
pix_comp->nat_commands[nat_id_counter]= natcmd;
rule->setInt("nat_cmd",nat_id_counter);
nat_id_counter++;
}
return true;
}
bool NATCompiler_pix::createStaticCmd::processNext()
{
NATCompiler_pix *pix_comp=dynamic_cast<NATCompiler_pix*>(compiler);
NATRule *rule=getNext(); if (rule==NULL) return false;
tmp_queue.push_back(rule);
if (rule->getRuleType()==NATRule::DNAT)
{
Address *osrc=compiler->getFirstOSrc(rule); assert(osrc);
Address *odst=compiler->getFirstODst(rule); assert(odst);
Service *osrv=compiler->getFirstOSrv(rule); assert(osrv);
Address *tdst=compiler->getFirstTDst(rule); assert(tdst);
Service *tsrv=compiler->getFirstTSrv(rule); assert(tsrv);
StaticCmd *scmd=new StaticCmd();
scmd->acl_name = pix_comp->getNATACLname(rule,"");
pix_comp->registerACL(scmd->acl_name);
scmd->rule=rule->getLabel();
// source and destination addresses are swapped here because
// access lists used for NAT should have 'real' addresses in source
scmd->iaddr=tdst;
scmd->oaddr=odst;
scmd->osrc= osrc;
scmd->osrv= osrv;
scmd->tsrv= tsrv;
scmd->ignore_scmd_and_print_acl=false;
pix_comp->static_commands[sc_id_counter]=scmd;
rule->setInt("sc_cmd",sc_id_counter);
sc_id_counter++;
}
return true;
}
/*
* this processor uses slurp to make sure all previous processors ran before
* it starts scanning rules.
*/
bool NATCompiler_pix::mergeNATCmd::processNext()
{
NATCompiler_pix *pix_comp=dynamic_cast<NATCompiler_pix*>(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 );
if (rule->getRuleType()==NATRule::DNAT)
{
StaticCmd *scmd=pix_comp->static_commands[rule->getInt("sc_cmd")];
for (map<int,StaticCmd*>::iterator i1=pix_comp->static_commands.begin();
i1!=pix_comp->static_commands.end(); ++i1)
{
StaticCmd *sc=(*i1).second;
if (scmd==sc) break;
if (*(scmd->oaddr) == *(sc->oaddr) &&
*(scmd->iaddr) == *(sc->iaddr) &&
*(scmd->osrv) == *(sc->osrv) &&
*(scmd->tsrv) == *(sc->tsrv))
{
/* rule 'sc' is above rule 'scmd', we need to print 'static' command
* only in the last rule using the same access list. That's why we set
* flag ignore_scmd_and_print acl in sc and not in scmd
*/
scmd->acl_name = sc->acl_name;
sc->ignore_scmd_and_print_acl=true;
}
}
}
if (rule->getRuleType()==NATRule::SNAT)
{
NATCmd *natcmd=pix_comp->nat_commands[ rule->getInt("nat_cmd") ];
for (map<int,NATCmd*>::iterator i1=pix_comp->nat_commands.begin();
i1!=pix_comp->nat_commands.end(); ++i1)
{
NATCmd *nc=(*i1).second;
/* since map nat_commands is sorted by the key, we only have to scan it
* until we hit natcmd
*/
if (natcmd==nc) break;
IPAddress a1=natcmd->t_addr->getAddress();
IPAddress a2=nc->t_addr->getAddress();
Interface *int1=natcmd->t_iface;
Interface *int2=nc->t_iface;
if ( a1 == a2 && int1->getId()==int2->getId() )
{
natcmd->ignore_global=true;
natcmd->nat_id=nc->nat_id;
}
}
for (map<int,NATCmd*>::iterator i1=pix_comp->nat_commands.begin();
i1!=pix_comp->nat_commands.end(); ++i1)
{
NATCmd *nc=(*i1).second;
/* since map nat_commands is sorted by the key, we only have to scan it
* until we hit natcmd
*/
if (natcmd==nc) break;
if (nc->ignore_nat) continue;
/* using operator==(const Address &o1,const Address &o2) here */
if ( *(natcmd->o_src) == *(nc->o_src) &&
*(natcmd->o_dst) == *(nc->o_dst) &&
*(natcmd->o_srv) == *(nc->o_srv) &&
natcmd->o_iface->getId() == nc->o_iface->getId() )
{
/*
* there is another nat rule (rule #2) with the same "original"
* addresses and the same interface. We can drop this nat rule, but need
* to merge its global pool with pool of the rule #2.
*
* This nat rule could have been sharing a global pool with some other
* nat rule; in this case we need to find this other rule and also
* reassign it to the global pool of the rule #2.
*/
natcmd->ignore_nat=true;
for (map<int,NATCmd*>::iterator i2=pix_comp->nat_commands.begin();
i2!=pix_comp->nat_commands.end(); ++i2)
{
NATCmd *nc2=i2->second;
if (natcmd->nat_id == nc2->nat_id)
nc2->nat_id=nc->nat_id;
}
natcmd->nat_id=nc->nat_id;
}
}
if (!natcmd->use_nat_0_0)
{
for (map<int,NATCmd*>::iterator i1=pix_comp->nat_commands.begin();
i1!=pix_comp->nat_commands.end(); ++i1)
{
NATCmd *nc=(*i1).second;
/* since map nat_commands is sorted by the key, we only have to scan it
* until we hit natcmd
*/
if (natcmd==nc) break;
/* ignore nat natcmd entries for rules where we won't print 'nat'
* command or use 'nat 0' command since this means we won't print
* access-list for those rules and hense can not merge lists
*/
if (nc->ignore_nat) continue;
if (nc->use_nat_0_0) continue;
if ( natcmd->nat_id==nc->nat_id &&
natcmd->t_addr == nc->t_addr &&
natcmd->o_iface->getId() == nc->o_iface->getId() )
{
/* two nat commands with the same id, the same interface and the same
* translated address, but different osrc and odst. OSrc and ODst must
* be different, otherwise these two commands would have been merged
* in the previous cycle. We can merge access lists and drop one of
* these nat commands. We merge ACLs by assigning them the same name.
*/
natcmd->nat_acl_name = nc->nat_acl_name;
nc->ignore_nat_and_print_acl=true;
}
}
}
}
}
return true;
}
/*
* The goal of this processor is to find SNAT rules that could be
* translated as "nat (interface) 0.0.0.0 0.0.0.0. These rules should
* have the same network object in OSrc that is used to define
* interface's network zone. The logic is simple: if network "A" is a
* network zone for internal interface, then only packets from this
* network can hit it and therefore there is no need to check source
* address once more in the "nat" rule.
*
* We also check for ODst and OSrv, because if the destination or the
* service are defined, then this optimization can not be done.
*
* This optimization can be turned off using checkbutton in the
* "Firewall" tab.
*
* call this processor really early, when groups have not been
* expanded yet. At this point both NAT rule type and interfaces it
* is associated with are unknown yet. We have to partially repeat
* algorithms used in other rule processors to determine NAT rule type
* and interface.
*
* We do this optimization in two steps:
*
* 1. in this rule processor we replace object in OSrc with firewall's
* interface. This way we can still use other rule processors that
* determine rule type and assign it to interfaces, but rule won't be
* split onto multiple rules because of objects in OSrc. We also set
* boolean flags "clear_osrc" and "use_nat_0_0" on the rule.
*
* 2. further down in rule processor clearOSrc we check the flag and
* clear OSrc if it is set.
*
* 3. flag "use_nat_0_0" is used in printRule processor.
*/
bool NATCompiler_pix::optimizeDefaultNAT::processNext()
{
// NATCompiler_pix *pix_comp=dynamic_cast<NATCompiler_pix*>(compiler);
NATRule *rule=getNext(); if (rule==NULL) return false;
tmp_queue.push_back(rule);
RuleElementOSrc *osrc=rule->getOSrc();
RuleElementOSrv *osrv=rule->getOSrv();
RuleElementODst *odst=rule->getODst();
RuleElementTSrc *tsrc=rule->getTSrc();
RuleElementTDst *tdst=rule->getTDst();
if (osrc->size()>1) return true;
if (osrc->isAny()) return true;
if (!osrv->isAny()) return true;
if (!odst->isAny()) return true;
/*
* can't use RuleElementOSrc::getFirst(bool dereference) because it
* returns Address::cast(o), but child element of rule element may be
* a group when this processor is called.
*/
FWObject *o=osrc->front();
string osrc_id;
if (FWReference::cast(o)!=NULL) osrc_id=FWReference::cast(o)->getPointerId();
else osrc_id=o->getId();
if ( ( !tsrc->isAny() && tdst->isAny()) ||
( !osrc->isAny() && odst->isAny() && tsrc->isAny() && tdst->isAny() )
)
{
// this rule type is SNAT or NONAT
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->getStr("orig_netzone_id")==osrc_id )
{
rule->setBool("clear_osrc",true);
rule->setBool("use_nat_0_0",true);
osrc->clearChildren();
osrc->addRef(iface);
break;
}
}
}
return true;
}
bool NATCompiler_pix::clearOSrc::processNext()
{
// NATCompiler_pix *pix_comp=dynamic_cast<NATCompiler_pix*>(compiler);
NATRule *rule=getNext(); if (rule==NULL) return false;
if (rule->getBool("clear_osrc"))
{
RuleElementOSrc *osrc=rule->getOSrc();
osrc->clearChildren();
osrc->setAnyElement();
}
tmp_queue.push_back(rule);
return true;
}
bool NATCompiler_pix::processMultiAddressObjectsInRE::processNext()
{
NATRule *rule=getNext(); if (rule==NULL) return false;
RuleElement *re=RuleElement::cast( rule->getFirstByType(re_type) );
for (FWObject::iterator i=re->begin(); i!=re->end(); i++)
{
FWObject *o= *i;
if (FWReference::cast(o)!=NULL) o=FWReference::cast(o)->getPointer();
MultiAddress *atrt = MultiAddress::cast(o);
if (atrt!=NULL && atrt->isRunTime())
compiler->abort("Run-time AddressTable and DNSName objects are not supported. Rule " + rule->getLabel());
}
tmp_queue.push_back(rule);
return true;
}
bool NATCompiler_pix::SuppressDuplicateNONATStatics::processNext()
{
Helper helper(compiler);
// NATCompiler_pix *pix_comp=dynamic_cast<NATCompiler_pix*>(compiler);
NATRule *rule=getNext(); if (rule==NULL) return false;
if (rule->getRuleType()== NATRule::NONAT &&
rule->getInt("nonat_type")==NONAT_STATIC)
{
Address *osrc=compiler->getFirstOSrc(rule); assert(osrc);
Address *odst=compiler->getFirstODst(rule); assert(odst);
nonat_static_parameters sp;
sp.iface1= helper.findInterfaceByNetzone(osrc );
sp.iface2= helper.findInterfaceByNetzone(odst );
sp.addr=odst->getAddress();
sp.mask=odst->getNetmask();
for (deque<nonat_static_parameters>::iterator i=all_nonat_statics.begin();
i!=all_nonat_statics.end(); ++i )
{
if ( i->iface1==sp.iface1 &&
i->iface2==sp.iface2 &&
i->addr==sp.addr &&
i->mask==sp.mask ) return true;
}
all_nonat_statics.push_back(sp);
}
tmp_queue.push_back(rule);
return true;
}
NATCompiler_pix::DetectOverlap::~DetectOverlap() {};
bool NATCompiler_pix::DetectOverlap::checkOverlapping(
const libfwbuilder::Address &addr1,
const libfwbuilder::IPAddress &addr2)
{
if (AddressRange::isA(&addr1))
{
const IPAddress a1=AddressRange::constcast(&addr1)->getRangeStart();
const IPAddress a2=AddressRange::constcast(&addr1)->getRangeEnd();
return (addr2==a1 || addr2==a2 || (addr2>a1 && addr2<a2));
} else
{
return addr1.getAddress() == addr2 ||
IPNetwork(addr1.getAddress(),addr1.getNetmask()).belongs(addr2);
}
}
string NATCompiler_pix::DetectOverlap::printGlobalPoolAddress(const Address &pool)
{
if (AddressRange::isA(&pool))
{
const IPAddress a1=AddressRange::constcast(&pool)->getRangeStart();
const IPAddress a2=AddressRange::constcast(&pool)->getRangeEnd();
return a1.toString()+"-"+a2.toString();
} else
{
return pool.getAddress().toString()+"/"+pool.getNetmask().toString();
}
}
bool NATCompiler_pix::DetectGlobalPoolProblems::processNext()
{
NATCompiler_pix *pix_comp=dynamic_cast<NATCompiler_pix*>(compiler);
NATRule *rule=getNext(); if (rule==NULL) return false;
tmp_queue.push_back(rule);
if (rule->getRuleType()== NATRule::SNAT )
{
NATCmd *natcmd=pix_comp->nat_commands[ rule->getInt("nat_cmd") ];
if (natcmd->ignore_global) return true;
if (natcmd->type!= INTERFACE)
{
if (checkOverlapping(*(natcmd->t_addr),
natcmd->t_iface->getAddress()))
compiler->abort("Global pool "
+printGlobalPoolAddress(*(natcmd->t_addr))
+" overlaps with interface address. Rule "
+rule->getLabel());
IPNetwork iface_net(natcmd->t_iface->getAddress(),
natcmd->t_iface->getNetmask());
if (checkOverlapping(*(natcmd->t_addr),
iface_net.getBroadcastAddress()) ||
checkOverlapping(*(natcmd->t_addr),
iface_net.getAddress()) )
compiler->warning("Global pool "
+printGlobalPoolAddress(*(natcmd->t_addr))
+" overlaps with broadcast address. Rule "
+rule->getLabel());
}
for (map<int,NATCmd*>::iterator i1=pix_comp->nat_commands.begin();
i1!=pix_comp->nat_commands.end(); ++i1)
{
NATCmd *nc=(*i1).second;
/* since map nat_commands is sorted by the key, we only have to scan it
* until we hit natcmd
*/
if (nc->ignore_global) continue;
if (natcmd==nc) break;
Interface *int1=natcmd->t_iface;
Interface *int2=nc->t_iface;
if ( int1->getId()==int2->getId() )
{
if ( ! fwcompiler::_find_obj_intersection(natcmd->t_addr,nc->t_addr).empty() )
{
compiler->abort(string("Global pool overlapping: \n")
+" "+rule->getLabel()+" : "
+printGlobalPoolAddress(*(natcmd->t_addr))
+"\n"
+" "+nc->rule_label+" : "
+printGlobalPoolAddress(*(nc->t_addr)) );
}
}
}
}
return true;
}
bool NATCompiler_pix::DetectOverlappingGlobalPoolsAndStaticRules::processNext()
{
NATCompiler_pix *pix_comp=dynamic_cast<NATCompiler_pix*>(compiler);
NATRule *rule=getNext(); if (rule==NULL) return false;
tmp_queue.push_back(rule);
if (rule->getRuleType()== NATRule::DNAT )
{
Address *outa=compiler->getFirstODst(rule); assert(outa);
Address *insa=compiler->getFirstTDst(rule); assert(insa);
for (map<int,NATCmd*>::iterator i=pix_comp->nat_commands.begin();
i!=pix_comp->nat_commands.end(); ++i)
{
NATCmd *natcmd=(*i).second;
if (natcmd->ignore_global) return true;
/* in this case natcmd->t_addr is interface. Interface creates
* single-address global pool, but since it has netmask,
* method checkOverlapping would treat it as network. I create
* temporary substitution Address object to avoid this .
*
* If interface is used for a global pool (SNAT rule) and
* for a static (DNAT rule), then this is ok even though
* such global pool overlaps with such static (added 10/17/03)
*
* But first I need to check if this interface has dynamic
* address, in which case I can not really do this check
* at all.
*/
IPv4 addr;
Interface *iface=Interface::cast(natcmd->t_addr);
if (iface!=NULL && iface->isDyn()) return true;
if (iface!=NULL && iface->getId()==outa->getId()) return true;
addr.setAddress(natcmd->t_addr->getAddress());
addr.setNetmask(natcmd->t_addr->getNetmask());
if (natcmd->type== INTERFACE)
{
addr.setNetmask("255.255.255.255");
}
if ( checkOverlapping( addr, outa->getAddress()) ||
checkOverlapping( *outa, addr.getAddress()) )
compiler->abort("Global pool "
+printGlobalPoolAddress(addr)
+" from rule "
+natcmd->rule_label
+" overlaps with static translation address in rule "
+rule->getLabel());
}
}
return true;
}
bool NATCompiler_pix::DetectDuplicateNAT::processNext()
{
NATCompiler_pix *pix_comp=dynamic_cast<NATCompiler_pix*>(compiler);
NATRule *rule=getNext(); if (rule==NULL) return false;
tmp_queue.push_back(rule);
if (rule->getRuleType()== NATRule::SNAT)
{
NATCmd *natcmd=pix_comp->nat_commands[ rule->getInt("nat_cmd") ];
if (natcmd->ignore_nat) return true;
for (map<int,NATCmd*>::iterator i1=pix_comp->nat_commands.begin();
i1!=pix_comp->nat_commands.end(); ++i1)
{
NATCmd *nc=(*i1).second;
/* since map nat_commands is sorted by the key, we only have to scan it
* until we hit natcmd
*/
if (nc->ignore_nat) continue;
if (natcmd==nc) break;
Interface *int1=natcmd->t_iface;
Interface *int2=nc->t_iface;
// IPAddress a1=natcmd->o_addr->getAddress();
// IPAddress a2=nc->o_addr->getAddress();
//
// Netmask m1=natcmd->o_addr->getNetmask();
// Netmask m2=nc->o_addr->getNetmask();
if ( int1->getId()==int2->getId() &&
natcmd->o_src==nc->o_src &&
natcmd->o_dst==nc->o_dst &&
*(natcmd->o_srv)==*(nc->o_srv)
)
{
compiler->abort("Duplicate NAT detected: rules "
+rule->getLabel()
+" and "+nc->rule_label
+" : "+natcmd->o_src->getAddress().toString()
+"/"+natcmd->o_src->getNetmask().toString()
+ " "
+ natcmd->o_srv->getProtocolName()
+ natcmd->o_srv->getStr("src_range_start")+":"
+ natcmd->o_srv->getStr("src_range_end")+":"
+ " "
+"->"+natcmd->o_dst->getAddress().toString()
+"/"+natcmd->o_dst->getNetmask().toString()
+ " "
+ natcmd->o_srv->getStr("dst_range_start")+"/"
+ natcmd->o_srv->getStr("dst_range_end"));
}
}
}
return true;
}
bool NATCompiler_pix::DetectOverlappingStatics::processNext()
{
NATCompiler_pix *pix_comp=dynamic_cast<NATCompiler_pix*>(compiler);
NATRule *rule=getNext(); if (rule==NULL) return false;
tmp_queue.push_back(rule);
if (rule->getRuleType()== NATRule::DNAT )
{
StaticCmd *scmd=pix_comp->static_commands[ rule->getInt("sc_cmd") ];
IPNetwork nn1( scmd->iaddr->getAddress(), scmd->iaddr->getNetmask() );
IPNetwork nn2( scmd->oaddr->getAddress(), scmd->oaddr->getNetmask() );
for (map<int,StaticCmd*>::iterator i1=pix_comp->static_commands.begin();
i1!=pix_comp->static_commands.end(); i1++ )
{
// int scid=i1->first;
StaticCmd *sc= i1->second;
if (sc->ignore_scmd_and_print_acl) continue;
if (sc==scmd) break;
if (Interface::isA(scmd->oaddr) && Interface::isA(sc->oaddr))
{
if ( *(sc->osrv) == *(scmd->osrv) &&
*(sc->tsrv) == *(scmd->tsrv) &&
*(sc->osrc) == *(scmd->osrc) &&
sc->oaddr->getId() == scmd->oaddr->getId())
compiler->abort("Static NAT rules overlap or are redundant : rules "+
sc->rule+" and "+scmd->rule+" : "+
"outside address: "+
"interface "+Interface::cast(scmd->oaddr)->getLabel()+
" inside address: "+
scmd->iaddr->getAddress().toString()+"/"+
scmd->iaddr->getNetmask().toString());
} else
{
IPNetwork n1( sc->iaddr->getAddress(), sc->iaddr->getNetmask() );
IPNetwork n2( sc->oaddr->getAddress(), sc->oaddr->getNetmask() );
if ( *(sc->osrv) == *(scmd->osrv) &&
*(sc->tsrv) == *(scmd->tsrv) &&
*(sc->osrc) == *(scmd->osrc) &&
( ! getOverlap(nn1,n1).empty() || ! getOverlap(nn2,n2).empty() ) )
compiler->abort("Static NAT rules overlap or are redundant : rules "+
sc->rule+" and "+scmd->rule+" : "+
"outside address: "+
scmd->oaddr->getAddress().toString()+"/"+
scmd->oaddr->getNetmask().toString()+
" inside address: "+
scmd->iaddr->getAddress().toString()+"/"+
scmd->iaddr->getNetmask().toString());
}
}
}
return true;
}
void NATCompiler_pix::compile()
{
cout << " Compiling NAT rules for " << fw->getName() << " ..." << endl << flush;
try {
Compiler::compile();
add( new Begin( "Begin processing"));
add( new printTotalNumberOfRules());
if (fw->getOptionsObject()->getBool( "pix_optimize_default_nat"))
add (new optimizeDefaultNAT(
"optimize commands 'nat (interface) 0.0.0.0 0.0.0.0'"));
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"));
add( new eliminateDuplicatesInOSRC("eliminate duplicates in OSRC"));
add( new eliminateDuplicatesInODST("eliminate duplicates in ODST"));
add( new eliminateDuplicatesInOSRV("eliminate duplicates in OSRV"));
add( new processMultiAddressObjectsInOSrc(
"process MultiAddress objects in OSrc"));
add( new processMultiAddressObjectsInODst(
"process MultiAddress objects in ODst"));
add( new ExpandMultipleAddresses("expand multiple addresses"));
add( new MACFiltering( "check for MAC address filtering"));
add( new ExpandAddressRanges("expand address range objects"));
add( new checkForUnnumbered("check for unnumbered interfaces"));
// add( new ConvertToAtomic("convert to atomic rules"));
add( new classifyNATRule("determine NAT rule types"));
// add( new fillTranslatedSrv("fill translated service element"));
add( new VerifyRules("verify rules" ));
add( new ReplaceFirewallObjectsODst("replace fw object in ODst" ));
add( new ReplaceFirewallObjectsTSrc("replace fw object in TSrc" ));
add( new UseFirewallInterfaces(
"replace host objects with firewall's interfaces if the have the same address"));
add( new ConvertToAtomic("convert to atomic rules" ));
add( new AssignInterface("assign rules to interfaces" ));
add( new verifyInterfaces("verify interfaces assignment" ));
add( new fillTranslatedSrv("fill translated service element" ));
add( new verifyRuleElements(
"verify rule elements for static NAT rules"));
add( new processNONATRules("process NONAT" ));
if (fw->getOptionsObject()->getBool("pix_optimize_default_nat"))
add (new clearOSrc ("clear OSrc" ));
add( new createNATCmd ("create NAT commands" ));
add( new createStaticCmd ("create static commands" ));
add( new mergeNATCmd ("merge NAT commands" ));
add( new SuppressDuplicateNONATStatics(
"suppress duplicate NONAT statics" ));
add( new PrintClearCommands( "Clear ACLs" ));
add( new PrintRule ("generate PIX code" ));
add( new storeProcessedRules ("store processed rules" ));
add( new simplePrintProgress ());
bool pix_check_duplicate_nat =
fw->getOptionsObject()->getBool("pix_check_duplicate_nat");
bool pix_check_overlapping_global_pools =
fw->getOptionsObject()->getBool("pix_check_overlapping_global_pools");
bool pix_check_overlapping_statics =
fw->getOptionsObject()->getBool("pix_check_overlapping_statics");
bool pix_check_overlapping_global_statics =
fw->getOptionsObject()->getBool("pix_check_overlapping_global_statics");
if ( pix_check_duplicate_nat ||
pix_check_overlapping_global_pools ||
pix_check_overlapping_statics ||
pix_check_overlapping_global_statics )
{
add( new createNewCompilerPass(" Detecting nat problems ..."));
if ( pix_check_duplicate_nat )
add( new DetectDuplicateNAT(" Detect duplicate nat entries"));
if ( pix_check_overlapping_global_pools )
add( new DetectGlobalPoolProblems(
" Detect global pool overlapping" ));
if ( pix_check_overlapping_statics )
add( new DetectOverlappingStatics(
" Detect overlapping statics" ));
if ( pix_check_overlapping_global_statics )
add( new DetectOverlappingGlobalPoolsAndStaticRules(
" Detect overlapping global pools and statics" ));
add( new simplePrintProgress ( ));
}
runRuleProcessors();
} catch (FWException &ex) {
error(ex.toString());
exit(1);
}
}
void NATCompiler_pix::regroup()
{
list<string> commands;
map<string,list<string> > script;
commands.push_back("THE_REST");
commands.push_back("access-list ");
commands.push_back("global ");
commands.push_back("nat ");
commands.push_back("static ");
string acl, agrp, icmp, telnet, ssh;
string new_output;
char buf[1024];
istringstream in(output.str());
while (in)
{
in.getline(buf, 1023, '\n');
strcat(buf,"\n");
if (buf[0]=='!') continue;
string slot="THE_REST";
for (list<string>::iterator i=commands.begin(); i!=commands.end(); ++i)
{
if (strncmp(buf, (*i).c_str(), (*i).size())==0)
{
slot= *i;
break;
}
}
script[slot].push_back(buf);
}
output.str("");
for (list<string>::iterator i=commands.begin(); i!=commands.end(); ++i)
{
for (list<string>::iterator j=script[*i].begin(); j!=script[*i].end(); ++j)
output << *j;
output << "! \n";
output << "! \n";
}
}
void NATCompiler_pix::epilog()
{
if ( fw->getOptionsObject()->getBool("pix_regroup_commands"))
{
cout << " Regrouping commands \n" << flush;
regroup();
}
}

504
src/pix/NATCompiler_pix.h Normal file
View File

@ -0,0 +1,504 @@
/*
Firewall Builder
Copyright (C) 2002 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: NATCompiler_pix.h,v 1.1 2008/03/06 06:48:59 vkurland Exp $
This program is free software which we release under the GNU General Public
License. You may redistribute and/or modify this program under the terms
of that license as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
To get a copy of the GNU General Public License, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _NATCOMPILER_PIX_HH
#define _NATCOMPILER_PIX_HH
#include "fwcompiler/NATCompiler.h"
#include "Helper.h"
#include <map>
#include <deque>
namespace fwcompiler {
typedef enum { UNKNOWN, INTERFACE, SINGLE_ADDRESS, NETWORK_ADDRESS, ADDRESS_RANGE } global_pool_type;
typedef enum { NONAT_NAT0, NONAT_STATIC } nonat_types;
struct NATCmd {
bool ignore_nat;
bool ignore_nat_and_print_acl;
bool ignore_global;
bool use_nat_0_0;
bool outside;
std::string rule_label;
std::string comment;
libfwbuilder::Address *o_src; // for "nat" command
libfwbuilder::Address *o_dst; // for "nat" command
libfwbuilder::Service *o_srv; // for acl in "nat" command for 6.3
libfwbuilder::Interface *o_iface; // for "nat" command
libfwbuilder::Address *t_addr; // for "global" command
libfwbuilder::Interface *t_iface; // for "global" command
int nat_id;
std::string nat_acl_name;
global_pool_type type;
};
struct StaticCmd {
bool ignore_scmd_and_print_acl;
std::string acl_name;
std::string rule;
libfwbuilder::Address *iaddr;
libfwbuilder::Address *oaddr;
libfwbuilder::Address *osrc;
libfwbuilder::Service *osrv;
libfwbuilder::Service *tsrv;
StaticCmd() { };
};
class NATCompiler_pix : public NATCompiler {
Helper helper;
int global_pool_no;
std::map<int,NATCmd*> nat_commands;
std::map<int,StaticCmd*> static_commands;
struct nonat {
std::string acl_name;
libfwbuilder::Interface *i_iface;
libfwbuilder::Interface *o_iface;
libfwbuilder::Address *src;
libfwbuilder::Address *dst;
bool last;
nonat() { last=false; }
};
// first: rule->getId(), second: nonat object
std::map<std::string, nonat> nonat_rules;
// first: interface->getId(), second: rule->getId()
std::map<std::string,std::string> first_nonat_rule_id;
libfwbuilder::RuleSet *final_ruleset;
std::string debugPrintRule(libfwbuilder::Rule *r);
/* this is a dictionary of all nat acl names and associated boolean
* flag that indicates that corresponding 'clear' command has been
* issued. We use this to keep track of all names that are created to
* make sure they are unique
*/
std::map<std::string,int> nat_acl_names;
std::string getNATACLname(libfwbuilder::Rule *r,int nat_id);
std::string getNATACLname(libfwbuilder::Rule *r,std::string suffix);
/**
* verifies correctness of the NAT rules
*/
DECLARE_NAT_RULE_PROCESSOR(VerifyRules);
friend class NATCompiler_pix::VerifyRules;
/**
* using network zone information determine inside and outside
* interfaces for the NAT rule
*/
DECLARE_NAT_RULE_PROCESSOR( AssignInterface );
friend class NATCompiler_pix::AssignInterface;
/**
* if previous processor assigned the same interface as both
* internal and external one for the NAT operation, drop the rule
*/
DECLARE_NAT_RULE_PROCESSOR( verifyInterfaces );
friend class NATCompiler_pix::verifyInterfaces;
/**
* in case of DNAT both odst and tdst should be of the same size:
* either both hosts, or both networks of the same size and can not
* be address ranges. There are other limitations, too.
*/
DECLARE_NAT_RULE_PROCESSOR( verifyRuleElements );
friend class NATCompiler_pix::verifyRuleElements;
/**
* expands address ranges in OSrc and ODst
*/
DECLARE_NAT_RULE_PROCESSOR( ExpandAddressRanges );
friend class NATCompiler_pix::ExpandAddressRanges;
/**
* in case OSrv is not "any" but TSrv is "original", copy it over
*/
DECLARE_NAT_RULE_PROCESSOR( fillTranslatedSrv );
friend class NATCompiler_pix::fillTranslatedSrv;
/**
* replaces firewall objects in ODst with its external interface(s)
*/
DECLARE_NAT_RULE_PROCESSOR( ReplaceFirewallObjectsODst );
friend class NATCompiler_pix::ReplaceFirewallObjectsODst;
/**
* replaces firewall objects in TSrc with its external interface(s)
*/
DECLARE_NAT_RULE_PROCESSOR( ReplaceFirewallObjectsTSrc );
friend class NATCompiler_pix::ReplaceFirewallObjectsTSrc;
/**
* replace host object with firewall's interace if host object
* has the same address
*/
class UseFirewallInterfaces : public NATRuleProcessor
{
void scanInterfaces(libfwbuilder::RuleElement *rel);
public:
UseFirewallInterfaces(const std::string &name) : NATRuleProcessor(name){}
virtual bool processNext();
};
friend class NATCompiler_pix::UseFirewallInterfaces;
/**
* this processor creates ACL for nat 0 rules
*/
class processNONATRules : public NATRuleProcessor
{
protected:
int nonat_no;
public:
processNONATRules(const std::string &name) : NATRuleProcessor(name){ nonat_no=1; }
virtual bool processNext();
};
friend class NATCompiler_pix::processNONATRules;
/**
* this processor creates object of class NATCmd if rule is of
* type SNAT
*/
class createNATCmd : public NATRuleProcessor
{
protected:
int nat_id_counter;
public:
createNATCmd(const std::string &name) : NATRuleProcessor(name){ nat_id_counter=1; }
virtual bool processNext();
};
friend class NATCompiler_pix::createNATCmd;
/**
* Creates objects of class StaticCmd for all DNAT rules
*/
class createStaticCmd : public NATRuleProcessor
{
protected:
int sc_id_counter;
public:
createStaticCmd(const std::string &name) : NATRuleProcessor(name){ sc_id_counter=1; }
virtual bool processNext();
};
friend class NATCompiler_pix::createStaticCmd;
/**
* this processor manipulates list of NATCmd objects so that
* to reuse identical "nat" and "global" rules. It also
* merges objects of class StaticCmd in DNAT rules to avoid *
* duplicate "static" commands
*/
DECLARE_NAT_RULE_PROCESSOR( mergeNATCmd );
friend class NATCompiler_pix::mergeNATCmd;
/**
* takes ID of the original object used in OSrc that has been
* stored in storeOriginalOSrcID and compares this object with
* network zones of interfaces. If FirewallOption
* "pix_optimize_default_nat" is set and original OSrc is the
* same as network zone of one of the interfaces, replaces
* OSrc in this rule with "Any".
*/
DECLARE_NAT_RULE_PROCESSOR( optimizeDefaultNAT );
friend class NATCompiler_pix::optimizeDefaultNAT;
/**
* this rule processor uses boolean flag "clear_osrc" set by
* optimizeDefaultNAT and removes objects in OSrc if this flag is set.
*/
DECLARE_NAT_RULE_PROCESSOR( clearOSrc );
friend class NATCompiler_pix::clearOSrc;
/**
* eliminates duplicate objects in SRC. Uses default comparison
* in eliminateDuplicatesInRE which compares IDs
*/
class eliminateDuplicatesInOSRC : public eliminateDuplicatesInRE
{
public:
eliminateDuplicatesInOSRC(const std::string &n) :
eliminateDuplicatesInRE(n,libfwbuilder::RuleElementOSrc::TYPENAME) {}
};
/**
* eliminates duplicate objects in DST. Uses default comparison
* in eliminateDuplicatesInRE which compares IDs
*/
class eliminateDuplicatesInODST : public eliminateDuplicatesInRE
{
public:
eliminateDuplicatesInODST(const std::string &n) :
eliminateDuplicatesInRE(n,libfwbuilder::RuleElementODst::TYPENAME) {}
};
/**
* eliminates duplicate objects in SRV. Uses default comparison
* in eliminateDuplicatesInRE which compares IDs
*/
class eliminateDuplicatesInOSRV : public eliminateDuplicatesInRE
{
public:
eliminateDuplicatesInOSRV(const std::string &n) :
eliminateDuplicatesInRE(n,libfwbuilder::RuleElementOSrv::TYPENAME) {}
};
/**
* Placeholder for MultiAddressRunTime objects that are not
* supported for ipf
*/
class processMultiAddressObjectsInRE : public NATRuleProcessor
{
std::string re_type;
public:
processMultiAddressObjectsInRE(const std::string &name,
const std::string &t) : NATRuleProcessor(name) { re_type=t; }
virtual bool processNext();
};
class processMultiAddressObjectsInOSrc : public processMultiAddressObjectsInRE
{
public:
processMultiAddressObjectsInOSrc(const std::string &n) :
processMultiAddressObjectsInRE(n,libfwbuilder::RuleElementOSrc::TYPENAME) {}
};
class processMultiAddressObjectsInODst : public processMultiAddressObjectsInRE
{
public:
processMultiAddressObjectsInODst(const std::string &n) :
processMultiAddressObjectsInRE(n,libfwbuilder::RuleElementODst::TYPENAME) {}
};
/**
* this processor accumulates all rules fed to it by previous
* processors, then prints PIX commands to clear
* access-lists, then feeds all rules to the next
* processor. Usually this processor is in chain right
* before PrintRules.
*
* We use this processor to print "clear" commands because
* they need to be generated when all access lists have been
* created but before they are printed.
*/
class PrintClearCommands : public NATRuleProcessor
{
public:
PrintClearCommands(const std::string &n) : NATRuleProcessor(n) {}
virtual bool processNext();
};
friend class NATCompiler_pix::PrintClearCommands;
/**
* prints single policy rule, assuming all groups have been
* expanded, so source, destination and service hold exactly
* one object each, and this object is not a group. Negation
* should also have been taken care of before this method is
* called.
*/
friend class PrintRule;
class PrintRule : public NATRuleProcessor
{
protected:
bool init;
std::string current_rule_label;
std::string _printSrcService(libfwbuilder::Service *srv);
std::string _printDstService(libfwbuilder::Service *srv);
virtual void _printPort(libfwbuilder::Service *srv);
std::string _printAddress(libfwbuilder::Address *a,bool print_netmask);
void _printNONAT(libfwbuilder::NATRule *rule);
std::string _printConnOptions(libfwbuilder::NATRule *rule);
std::map<int,bool> printed_global_pools;
public:
PrintRule(const std::string &n);
virtual bool processNext();
};
friend class NATCompiler_pix::PrintRule;
/**
* detects duplicate nat
*/
class DetectDuplicateNAT : public NATRuleProcessor
{
public:
DetectDuplicateNAT(const std::string &n) : NATRuleProcessor(n){}
virtual bool processNext();
};
friend class NATCompiler_pix::DetectDuplicateNAT;
/**
* base class that has a method that checks for overlapping addresses
* taking into account address ranges and other situations
*/
friend class DetectOverlap;
class DetectOverlap : public NATRuleProcessor
{
protected:
bool checkOverlapping(const libfwbuilder::Address &a1,
const libfwbuilder::IPAddress &a2);
std::string printGlobalPoolAddress(const libfwbuilder::Address &pool);
public:
DetectOverlap(const std::string &n) : NATRuleProcessor(n){}
virtual ~DetectOverlap();
};
friend class NATCompiler_pix::DetectOverlap;
/**
* detects overlapping and some other problems with global pools
*/
friend class DetectGlobalPoolProblems;
class DetectGlobalPoolProblems : public DetectOverlap
{
public:
DetectGlobalPoolProblems(const std::string &n) : DetectOverlap(n){}
virtual bool processNext();
};
friend class NATCompiler_pix::DetectGlobalPoolProblems;
/**
* detects overlapping global pools and static rules
*/
friend class DetectOverlappingGlobalPoolsAndStaticRules;
class DetectOverlappingGlobalPoolsAndStaticRules : public DetectOverlap
{
public:
DetectOverlappingGlobalPoolsAndStaticRules(const std::string &n) : DetectOverlap(n){}
virtual bool processNext();
};
friend class NATCompiler_pix::DetectOverlappingGlobalPoolsAndStaticRules;
/**
* suppress identical nonat static (this happens in rules
* that request no translation in access from a low security
* zone to a high security zone and have group or multiple
* objects in OSrc).
*/
friend class SuppressDuplicateNONATStatics;
class SuppressDuplicateNONATStatics : public NATRuleProcessor
{
protected:
typedef struct {
std::string iface1, iface2;
libfwbuilder::IPAddress addr;
libfwbuilder::Netmask mask;
} nonat_static_parameters;
std::deque<nonat_static_parameters> all_nonat_statics;
public:
SuppressDuplicateNONATStatics(const std::string &n) : NATRuleProcessor(n){}
virtual bool processNext();
};
friend class NATCompiler_pix::SuppressDuplicateNONATStatics;
/**
* detects overlapping static
*/
friend class DetectOverlappingStatics;
class DetectOverlappingStatics : public NATRuleProcessor
{
protected:
public:
DetectOverlappingStatics(const std::string &n) : NATRuleProcessor(n){}
virtual bool processNext();
};
friend class NATCompiler_pix::DetectOverlappingStatics;
/**
* this processor stores processed NAT rules in final_ruleset
*/
DECLARE_NAT_RULE_PROCESSOR( storeProcessedRules );
friend class NATCompiler_pix::storeProcessedRules;
protected:
virtual std::string myPlatformName();
public:
NATCompiler_pix(libfwbuilder::FWObjectDatabase *_db,
const std::string &fwname,
fwcompiler::OSConfigurator *_oscnf);
virtual int prolog();
virtual void compile();
virtual void epilog();
void regroup();
/**
* scans all rules in combined_ruleset and finds rules (if
* any) that define DNAT translation for a combination of
* src,dst and srv (that is, src is equival OSrc, srv is equal
* OSrv and dst is equal TDst). If such rule could be found,
* returns a list of triplets (src,odst,osrv)
*/
std::list<triplet> findDNATForAddress(
libfwbuilder::Address *src,
libfwbuilder::Address *dst,
libfwbuilder::Service *srv);
// virtual string atomicRuleToString(libfwbuilder::Rule *r);
void registerACL(const std::string& acl_name) {
setACLFlag(acl_name,0);
}
int getACLFlag(const std::string& acl_name) {
if (nat_acl_names.count(acl_name)!=0)
return nat_acl_names[acl_name];
return -1;
}
void setACLFlag(const std::string& acl_name, int f) {
nat_acl_names[acl_name] = f;
}
};
}
#endif

View File

@ -0,0 +1,562 @@
/*
Firewall Builder
Copyright (C) 2002 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: NATCompiler_pix_writers.cpp,v 1.1 2008/03/06 06:48:59 vkurland Exp $
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 "NATCompiler_pix.h"
#include "fwbuilder/FWObjectDatabase.h"
#include "fwbuilder/RuleElement.h"
#include "fwbuilder/NAT.h"
#include "fwbuilder/AddressRange.h"
#include "fwbuilder/ICMPService.h"
#include "fwbuilder/TCPService.h"
#include "fwbuilder/UDPService.h"
#include "fwbuilder/Interface.h"
#include "fwbuilder/IPv4.h"
#include "fwbuilder/Network.h"
#include "fwbuilder/Resources.h"
#include <algorithm>
#include <functional>
#include <assert.h>
using namespace libfwbuilder;
using namespace fwcompiler;
using namespace std;
bool NATCompiler_pix::PrintClearCommands::processNext()
{
NATCompiler_pix *pix_comp=dynamic_cast<NATCompiler_pix*>(compiler);
string version = compiler->fw->getStr("version");
string platform = compiler->fw->getStr("platform");
slurp();
if (tmp_queue.size()==0) return false;
compiler->output << endl;
if ( !compiler->fw->getOptionsObject()->getBool("pix_acl_no_clear") )
{
compiler->output << Resources::platform_res[platform]->getResourceStr(
string("/FWBuilderResources/Target/options/")+
"version_"+version+"/pix_commands/clear_xlate") << endl;
compiler->output << Resources::platform_res[platform]->getResourceStr(
string("/FWBuilderResources/Target/options/")+
"version_"+version+"/pix_commands/clear_static") << endl;
compiler->output << Resources::platform_res[platform]->getResourceStr(
string("/FWBuilderResources/Target/options/")+
"version_"+version+"/pix_commands/clear_global") << endl;
compiler->output << Resources::platform_res[platform]->getResourceStr(
string("/FWBuilderResources/Target/options/")+
"version_"+version+"/pix_commands/clear_nat") << endl;
}
return true;
}
string NATCompiler_pix::PrintRule::_printAddress(Address *a,bool print_netmask)
{
string addr=a->getAddress().toString();
string mask=a->getNetmask().toString();
if (addr=="0.0.0.0" && mask=="0.0.0.0") return "any";
// if (addr=="0.0.0.0") addr="0";
// if (mask=="0.0.0.0") mask="0";
/*
* If the object 'a' is a Host or a IPv4 (that is, it defines only
* a single IP address) but its netmask is not 255.255.255.255, PIX will
* issue an error "address,mask doesn't pair".
*
* I am not sure if it is appropriate to just fix this for the user,
* may be I should issue a warning or even abort.
*/
if (Host::isA(a) || IPv4::isA(a)) mask="255.255.255.255";
if (mask=="255.255.255.255") { addr="host "+addr; mask=""; }
if (print_netmask) return addr+" "+mask;
else return addr;
}
void NATCompiler_pix::PrintRule::_printNONAT(NATRule *rule)
{
Helper helper(compiler);
NATCompiler_pix *pix_comp=dynamic_cast<NATCompiler_pix*>(compiler);
string platform = compiler->fw->getStr("platform");
string version = compiler->fw->getStr("version");
string clearACLcmd = Resources::platform_res[platform]->getResourceStr(
string("/FWBuilderResources/Target/options/")+
"version_"+version+"/pix_commands/clear_acl");
switch (rule->getInt("nonat_type"))
{
case NONAT_NAT0:
{
nonat n0=pix_comp->nonat_rules[rule->getId()];
Interface *iface1=n0.i_iface;
// Interface *iface2=n0.o_iface;
if (rule->getBool("use_nat_0_0"))
{
/* old, < 6.3 */
compiler->output << "nat (" << iface1->getLabel() << ") 0 0 0";
compiler->output << endl;
} else
{
/* new, >=6.3 */
compiler->output << endl;
if (pix_comp->getACLFlag(n0.acl_name)==0 &&
compiler->fw->getOptionsObject()->getBool("pix_acl_substitution"))
{
compiler->output << clearACLcmd <<" " << n0.acl_name << endl;
pix_comp->setACLFlag(n0.acl_name,1);
}
compiler->output << "access-list "
<< n0.acl_name
<< " permit ip "
<< _printAddress(n0.src,true)
<< " "
<< _printAddress(n0.dst,true)
<< endl;
if ( pix_comp->first_nonat_rule_id[iface1->getId()]==rule->getId() )
{
if (compiler->fw->getStr("platform")=="fwsm" &&
compiler->fw->getOptionsObject()->getBool("pix_use_manual_commit") )
{
compiler->output << "access-list commit" << endl;
compiler->output << endl;
}
compiler->output << "nat ("
<< iface1->getLabel()
<< ") 0 access-list "
<< n0.acl_name
<< endl;
}
}
break;
}
case NONAT_STATIC:
{
Address *osrc=compiler->getFirstOSrc(rule); assert(osrc);
Address *odst=compiler->getFirstODst(rule); assert(odst);
Interface *osrc_iface=compiler->getCachedFwInterface( helper.findInterfaceByNetzone(osrc ) );
Interface *odst_iface=compiler->getCachedFwInterface( helper.findInterfaceByNetzone(odst ) );
string addr=odst->getAddress().toString();
string mask;
if (Network::isA(odst)) mask=odst->getNetmask().toString();
else mask="255.255.255.255";
compiler->output << "static ("
<< odst_iface->getLabel() << ","
<< osrc_iface->getLabel() << ") "
<< addr << " " << addr
<< " netmask " << mask
<< endl;
}
break;
}
}
NATCompiler_pix::PrintRule::PrintRule(const std::string &name) : NATRuleProcessor(name)
{
init=true;
}
/*
* we verify that port ranges are not used in verifyRuleElements
*/
void NATCompiler_pix::PrintRule::_printPort(Service *srv)
{
if (TCPService::isA(srv) || UDPService::isA(srv))
{
int drs=srv->getInt("dst_range_start");
if (drs!=0) compiler->output << drs << " ";
}
}
string NATCompiler_pix::PrintRule::_printSrcService(Service *srv)
{
ostringstream str;
if (TCPService::isA(srv) || UDPService::isA(srv))
{
int rs=srv->getInt("src_range_start");
int re=srv->getInt("src_range_end");
if (rs<0) rs=0;
if (re<0) re=0;
if (rs>0 || re>0) {
if (rs==re) str << "eq " << rs;
else
if (rs==0 && re!=0) str << "lt " << re;
else
if (rs!=0 && re==65535) str << "gt " << rs;
else
str << "range " << rs << " " << re;
}
}
return str.str();
}
string NATCompiler_pix::PrintRule::_printDstService(Service *srv)
{
ostringstream str;
if (TCPService::isA(srv) || UDPService::isA(srv)) {
int rs=srv->getInt("dst_range_start");
int re=srv->getInt("dst_range_end");
if (rs<0) rs=0;
if (re<0) re=0;
if (rs>0 || re>0) {
if (rs==re) str << "eq " << rs;
else
if (rs==0 && re!=0) str << "lt " << re;
else
if (rs!=0 && re==65535) str << "gt " << rs;
else
str << "range " << rs << " " << re;
}
}
if (ICMPService::isA(srv) && srv->getInt("type")!=-1)
str << srv->getStr("type") << " ";
return str.str();
}
string NATCompiler_pix::PrintRule::_printConnOptions(NATRule *rule)
{
if (rule==NULL) return "";
ostringstream ostr;
int max_conns=compiler->fw->getOptionsObject()->getInt("pix_max_conns");
int emb_limit=compiler->fw->getOptionsObject()->getInt("pix_emb_limit");
if (max_conns<0) max_conns=0;
if (emb_limit<0) emb_limit=0;
// we only support tcp connection options at this time
// however PIX 7.0 (7.2?) also supports udp conn limit
//
// Note that keyword 'tcp' here is only valid in 7.x
if (libfwbuilder::XMLTools::version_compare(
compiler->fw->getStr("version"),"7.0")>=0) ostr << "tcp ";
ostr << max_conns << " " << emb_limit;
return ostr.str();
}
bool NATCompiler_pix::PrintRule::processNext()
{
NATCompiler_pix *pix_comp=dynamic_cast<NATCompiler_pix*>(compiler);
string platform = compiler->fw->getStr("platform");
string version = compiler->fw->getStr("version");
string clearACLcmd = Resources::platform_res[platform]->getResourceStr(
string("/FWBuilderResources/Target/options/")+
"version_"+version+"/pix_commands/clear_acl");
NATRule *rule=getNext(); if (rule==NULL) return false;
tmp_queue.push_back(rule);
if ( compiler->fw->getOptionsObject()->getBool("pix_include_comments") )
{
string rl=rule->getLabel();
if (rl!=current_rule_label)
{
compiler->output << "! " << endl;
compiler->output << "! Rule " << rl << endl;
string comm=rule->getComment();
string::size_type c1,c2;
c1=0;
while ( (c2=comm.find('\n',c1))!=string::npos ) {
compiler->output << "! " << comm.substr(c1,c2-c1) << endl;
c1=c2+1;
}
compiler->output << "! " << comm.substr(c1) << endl;
compiler->output << "! " << endl;
current_rule_label=rl;
}
}
Address *osrc=compiler->getFirstOSrc(rule); assert(osrc);
Address *odst=compiler->getFirstODst(rule); assert(odst);
Service *osrv=compiler->getFirstOSrv(rule); assert(osrv);
Address *tsrc=compiler->getFirstTSrc(rule); assert(tsrc);
Address *tdst=compiler->getFirstTDst(rule); assert(tdst);
Service *tsrv=compiler->getFirstTSrv(rule); assert(tsrv);
Interface *iface_orig = compiler->getCachedFwInterface( rule->getStr("nat_iface_orig") );
Interface *iface_trn = compiler->getCachedFwInterface( rule->getStr("nat_iface_trn" ) );
switch (rule->getRuleType())
{
case NATRule::NONAT:
_printNONAT(rule);
break;
case NATRule::SNAT:
{
NATCmd *natcmd=pix_comp->nat_commands[ rule->getInt("nat_cmd") ];
if ( ! natcmd->ignore_global)
{
compiler->output <<
"global (" << natcmd->t_iface->getLabel() << ") "
<< natcmd->nat_id;
switch (natcmd->type)
{
case INTERFACE:
compiler->output << " interface" << endl;
break;
case SINGLE_ADDRESS:
compiler->output << " "
<< natcmd->t_addr->getAddress().toString()
<< endl;
break;
case NETWORK_ADDRESS:
compiler->output << " "
<< natcmd->t_addr->getAddress().toString()
<< " netmask "
<< natcmd->t_addr->getNetmask().toString()
<< endl;
break;
case ADDRESS_RANGE:
{
AddressRange *ar=AddressRange::cast(natcmd->t_addr);
compiler->output << " "
<< ar->getRangeStart().toString()
<< "-"
<< ar->getRangeEnd().toString()
<< " netmask "
<< natcmd->t_iface->getNetmask().toString()
<< endl;
}
break;
default: ; // TODO: should actually be always_assert
}
}
if ( natcmd->ignore_nat)
{
compiler->output <<"! " << natcmd->comment << endl;
} else
{
if (rule->getBool("use_nat_0_0") ||
libfwbuilder::XMLTools::version_compare(compiler->fw->getStr("version"),"6.3")<0)
{
/* old, < 6.3 */
compiler->output << "nat (" << natcmd->o_iface->getLabel() << ") "
<< natcmd->nat_id
<< " "
<< natcmd->o_src->getAddress().toString() << " "
<< natcmd->o_src->getNetmask().toString();
if (natcmd->outside) compiler->output << " outside";
else compiler->output << " " << _printConnOptions(rule);
compiler->output << endl;
} else
{
/* new, >=6.3 */
if (pix_comp->getACLFlag(natcmd->nat_acl_name)==0 &&
compiler->fw->getOptionsObject()->getBool("pix_acl_substitution"))
{
compiler->output << clearACLcmd << " "
<< natcmd->nat_acl_name
<< endl;
pix_comp->setACLFlag(natcmd->nat_acl_name,1);
}
compiler->output << "access-list "
<< natcmd->nat_acl_name
<< " permit ";
compiler->output << osrv->getProtocolName();
compiler->output << " ";
compiler->output << _printAddress(osrc,true);
compiler->output << " ";
compiler->output << _printSrcService( osrv );
compiler->output << " ";
compiler->output << _printAddress(odst,true);
compiler->output << " ";
compiler->output << _printDstService( osrv );
compiler->output << endl;
if (!natcmd->ignore_nat_and_print_acl)
{
if (compiler->fw->getStr("platform")=="fwsm" &&
compiler->fw->getOptionsObject()->getBool("pix_use_manual_commit") )
{
compiler->output << "access-list commit" << endl;
compiler->output << endl;
}
compiler->output << "nat (" << natcmd->o_iface->getLabel() << ") "
<< natcmd->nat_id
<< " access-list "
<< natcmd->nat_acl_name;
if (natcmd->outside) compiler->output << " outside";
else compiler->output << " " << _printConnOptions(rule);
compiler->output << endl;
}
}
}
break;
}
case NATRule::DNAT:
{
StaticCmd *scmd=pix_comp->static_commands[ rule->getInt("sc_cmd") ];
IPAddress outa=scmd->oaddr->getAddress();
Netmask outm=scmd->oaddr->getNetmask();
IPAddress insa=scmd->iaddr->getAddress();
/*
* we verify that odst and tdst have the same size in verifyRuleElements,
* so we can rely on that now.
*/
if (libfwbuilder::XMLTools::version_compare(compiler->fw->getStr("version"),"6.3")<0)
{
/* old, < 6.3 */
compiler->output << "static ("
<< iface_trn->getLabel()
<< ","
<< iface_orig->getLabel()
<< ") " ;
bool use_ports=false;
if (TCPService::cast(osrv)) { use_ports=true; compiler->output << "tcp "; }
if (UDPService::cast(osrv)) { use_ports=true; compiler->output << "udp "; }
if (Interface::cast(scmd->oaddr)!=NULL)
{
compiler->output << "interface ";
if (use_ports) _printPort(scmd->osrv);
compiler->output << insa.toString() << " ";
if (use_ports) _printPort(scmd->tsrv);
} else
{
compiler->output << outa.toString() << " ";
if (use_ports) _printPort(scmd->osrv);
compiler->output << insa.toString() << " ";
if (use_ports) _printPort(scmd->tsrv);
compiler->output << " netmask " << outm.toString();
}
compiler->output << " " << _printConnOptions(rule) << endl;
} else
{
/* new, >=6.3 */
if (pix_comp->getACLFlag(scmd->acl_name)==0 &&
compiler->fw->getOptionsObject()->getBool("pix_acl_substitution"))
{
compiler->output << clearACLcmd << " "
<< scmd->acl_name
<< endl;
pix_comp->setACLFlag(scmd->acl_name,1);
}
compiler->output << "access-list "
<< scmd->acl_name
<< " permit ";
/*
* This acl does not make any sense if treated as a regular access
* list. I just follow example from
* http://www.cisco.com/en/US/products/sw/secursw/ps2120/products_configuration_guide_chapter09186a0080172786.html#1113601
*/
compiler->output << scmd->osrv->getProtocolName();
compiler->output << " ";
compiler->output << _printAddress(scmd->iaddr,true);
compiler->output << " ";
compiler->output << _printDstService( scmd->tsrv );
compiler->output << " ";
compiler->output << _printAddress(scmd->osrc,true);
compiler->output << " ";
compiler->output << _printSrcService( scmd->osrv );
compiler->output << endl;
if (!scmd->ignore_scmd_and_print_acl)
{
if (compiler->fw->getStr("platform")=="fwsm" &&
compiler->fw->getOptionsObject()->getBool("pix_use_manual_commit") )
{
compiler->output << "access-list commit" << endl;
compiler->output << endl;
}
compiler->output << "static ("
<< iface_trn->getLabel()
<< ","
<< iface_orig->getLabel()
<< ") " ;
bool use_ports=false;
if (TCPService::cast(scmd->osrv)) { use_ports=true; compiler->output << "tcp "; }
if (UDPService::cast(scmd->osrv)) { use_ports=true; compiler->output << "udp "; }
if (Interface::cast(scmd->oaddr)!=NULL) compiler->output << "interface ";
else compiler->output << outa.toString() << " ";
if (use_ports) _printPort(scmd->osrv);
compiler->output << " ";
compiler->output << "access-list "
<< scmd->acl_name
<< " " << _printConnOptions(rule) << endl;
}
}
break;
}
default: ; // TODO: should actually be always_assert
}
return true;
}

View File

@ -0,0 +1,535 @@
/*
Firewall Builder
Copyright (C) 2002 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: OSConfigurator_pix_os.cpp,v 1.1 2008/03/06 06:49:00 vkurland Exp $
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 "OSConfigurator_pix_os.h"
#include "Helper.h"
#include "fwbuilder/Resources.h"
#include "fwbuilder/Firewall.h"
#include "fwbuilder/FWOptions.h"
#include "fwbuilder/Interface.h"
#include "fwbuilder/Management.h"
#include "fwbuilder/Resources.h"
#include <list>
#include <algorithm>
#include <functional>
#include <assert.h>
#include <iostream>
using namespace libfwbuilder;
using namespace fwcompiler;
using namespace std;
string OSConfigurator_pix_os::myPlatformName() { return "pix_os"; }
int OSConfigurator_pix_os::prolog()
{
string host_os = fw->getStr("host_OS");
if (host_os!="pix_os" && host_os!="fwsm_os")
abort("Unsupported OS " + host_os );
return Compiler::prolog();
}
void OSConfigurator_pix_os::processFirewallOptions()
{
// FWOptions* options=fw->getOptionsObject();
string s;
// int i;
string version = fw->getStr("version");
string platform = fw->getStr("platform");
if ( fw->getOptionsObject()->getBool("pix_set_host_name") )
{
output << "hostname " << fw->getName() << endl;
output << endl;
}
output << _printNameif();
output << endl;
output << _printIPAddress();
output << endl;
output << _printLogging();
output << endl;
output << _printTimeouts();
output << endl;
output << _printSNMP();
output << endl;
output << _printNTP();
output << endl;
output << _printSysopt();
output << endl;
output << getProtocolInspectionCommands();
output << endl;
}
string OSConfigurator_pix_os::_printNameif()
{
ostringstream res;
string version = fw->getStr("version");
string platform = fw->getStr("platform");
string::size_type n;
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);
string nameifCmd = Resources::platform_res[platform]->getResourceStr(
string("/FWBuilderResources/Target/options/version_")+
version+"/pix_commands/nameif");
if ((n = nameifCmd.find("%il"))!=string::npos)
nameifCmd.replace(n,3,iface->getLabel());
if ((n = nameifCmd.find("%in"))!=string::npos)
nameifCmd.replace(n,3,iface->getName());
if ((n = nameifCmd.find("%sl"))!=string::npos)
{
ostringstream sls;
sls << iface->getSecurityLevel();
nameifCmd.replace(n,3,sls.str());
}
res << nameifCmd;
}
res << endl;
return res.str();
}
string OSConfigurator_pix_os::_printIPAddress()
{
ostringstream res;
string version = fw->getStr("version");
string platform = fw->getStr("platform");
string setAddrCmd;
string::size_type n;
if ( fw->getOptionsObject()->getBool("pix_ip_address") )
{
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())
{
setAddrCmd = Resources::platform_res[platform]->getResourceStr(
string("/FWBuilderResources/Target/options/version_")+
version+"/pix_commands/ip_addr_dyn");
} else
{
setAddrCmd = Resources::platform_res[platform]->getResourceStr(
string("/FWBuilderResources/Target/options/version_")+
version+"/pix_commands/ip_addr_static");
}
if ((n = setAddrCmd.find("%il"))!=string::npos)
setAddrCmd.replace(n,3,iface->getLabel());
if ((n = setAddrCmd.find("%in"))!=string::npos)
setAddrCmd.replace(n,3,iface->getName());
if ((n = setAddrCmd.find("%a"))!=string::npos)
setAddrCmd.replace(n,2,iface->getAddress().toString());
if ((n = setAddrCmd.find("%n"))!=string::npos)
setAddrCmd.replace(n,2,iface->getNetmask().toString());
res << setAddrCmd;
}
}
res << endl;
return res.str();
}
string OSConfigurator_pix_os::_printLogging()
{
Helper helper(this);
ostringstream str;
bool logging_on=false;
string syslog_host = fw->getOptionsObject()->getStr("pix_syslog_host");
int syslog_queue_size=fw->getOptionsObject()->getInt("pix_syslog_queue_size");
string syslog_facility= fw->getOptionsObject()->getStr("pix_syslog_facility");
string trap_level= fw->getOptionsObject()->getStr("pix_logging_trap_level");
bool buffered= fw->getOptionsObject()->getBool("pix_logging_buffered");
string buffered_level= fw->getOptionsObject()->getStr("pix_logging_buffered_level");
bool console= fw->getOptionsObject()->getBool("pix_logging_console");
string console_level= fw->getOptionsObject()->getStr("pix_logging_console_level");
bool timestamp= fw->getOptionsObject()->getBool("pix_logging_timestamp");
if ( ! syslog_host.empty() )
{
string iface_id=helper.findInterfaceByNetzone(IPAddress(syslog_host));
if (iface_id.empty()) abort("Log server "+syslog_host+" does not belong to any known network zone");
Interface *syslog_iface = getCachedFwInterface(iface_id);
str << endl;
str << "logging host "
<< syslog_iface->getLabel()
<< " " << syslog_host;
if ( fw->getOptionsObject()->getBool("pix_emblem_log_format") )
str << " format emblem ";
str << endl;
str << "logging queue "
<< syslog_queue_size << endl;
if ( ! syslog_facility.empty() )
str << "logging facility " << syslog_facility << endl;
if ( ! trap_level.empty() )
str << "logging trap " << trap_level << endl;
logging_on=true;
}
if ( ! buffered ) str << "no logging buffered" << endl;
else
{
str << "logging buffered " << buffered_level << endl;
logging_on=true;
}
if ( ! console ) str << "no logging console" << endl;
else
{
str << "logging console " << console_level << endl;
logging_on=true;
}
if ( ! timestamp ) str << "no ";
str << "logging timestamp" << endl;
if ( ! logging_on) str << "no ";
str << "logging on" << endl;
string s=fw->getOptionsObject()->getStr("pix_syslog_device_id_opt");
string v=fw->getOptionsObject()->getStr("pix_syslog_device_id_val");
if (s=="hostname") str << "logging device-id hostname" << endl;
if (s=="interface") str << "logging device-id ipaddress " << v << endl;
if (s=="string") str << "logging device-id string " << v << endl;
str << endl;
return str.str();
}
string OSConfigurator_pix_os::_printSNMPServer(const std::string &srv,int poll_trap)
{
Helper helper(this);
ostringstream str;
string iface_id=helper.findInterfaceByNetzone( IPAddress(srv) );
if (iface_id.empty())
abort(string("SNMP server ")+srv+" does not belong to any known network zone");
Interface *snmp_iface = getCachedFwInterface(iface_id);
str << "snmp-server host " << snmp_iface->getLabel() << " " << srv;
switch (poll_trap) {
case 1: str << " poll" << endl; break;
case 2: str << " trap" << endl; break;
default: str << endl; break;
}
return str.str();
}
string OSConfigurator_pix_os::_printSNMP()
{
ostringstream str;
string version = fw->getStr("version");
string platform = fw->getStr("platform");
bool set_communities=fw->getOptionsObject()->getBool("pix_set_communities_from_object_data");
bool set_sysinfo= fw->getOptionsObject()->getBool("pix_set_sysinfo_from_object_data" );
bool enable_traps= fw->getOptionsObject()->getBool("pix_enable_snmp_traps");
string clearSNMPcmd = Resources::platform_res[platform]->getResourceStr(
string("/FWBuilderResources/Target/options/version_")+
version+"/pix_commands/clear_snmp");
if ( !fw->getOptionsObject()->getBool("pix_acl_no_clear") )
str << clearSNMPcmd << endl;
if ( fw->getOptionsObject()->getBool("pix_disable_snmp_agent") )
{
str << "no snmp-server " << endl;
} else
{
if (set_communities) {
string read_c=fw->getManagementObject()->getSNMPManagement()->getReadCommunity();
str << endl;
str << "snmp-server community " << read_c << endl;
}
if (set_sysinfo) {
string location=fw->getOptionsObject()->getStr("snmp_location");
string contact =fw->getOptionsObject()->getStr("snmp_contact");
str << endl;
if (!location.empty()) str << "snmp-server location " << location << endl;
if (!contact.empty()) str << "snmp-server contact " << contact << endl;
}
if (enable_traps) {
str << endl;
str << "snmp-server enable traps" << endl;
} else {
str << endl;
str << "no snmp-server enable traps" << endl;
}
string snmp_server_1= fw->getOptionsObject()->getStr("pix_snmp_server1");
string snmp_server_2= fw->getOptionsObject()->getStr("pix_snmp_server2");
int snmp_poll_traps_1= fw->getOptionsObject()->getInt("pix_snmp_poll_traps_1");
int snmp_poll_traps_2= fw->getOptionsObject()->getInt("pix_snmp_poll_traps_2");
if (!snmp_server_1.empty())
str << _printSNMPServer(snmp_server_1,snmp_poll_traps_1);
if (!snmp_server_2.empty())
str << _printSNMPServer(snmp_server_2,snmp_poll_traps_2);
}
return str.str();
}
string OSConfigurator_pix_os::_printNTPServer(const std::string &srv,bool pref)
{
Helper helper(this);
ostringstream str;
string iface_id=helper.findInterfaceByNetzone( IPAddress(srv) );
if (iface_id.empty()) abort("NTP server "+srv+" does not belong to any known network zone");
Interface *ntp_iface = getCachedFwInterface(iface_id);
str << "ntp server " << srv << " source " << ntp_iface->getLabel();
if (pref) str << " prefer";
str << endl;
return str.str();
}
string OSConfigurator_pix_os::_printNTP()
{
ostringstream res;
string version = fw->getStr("version");
string platform = fw->getStr("platform");
string clearNTPcmd = Resources::platform_res[platform]->getResourceStr(
string("/FWBuilderResources/Target/options/version_")+
version+"/pix_commands/clear_ntp");
if ( !fw->getOptionsObject()->getBool("pix_acl_no_clear") )
res << clearNTPcmd << endl;
string ntp_server_1=fw->getOptionsObject()->getStr("pix_ntp1");
bool ntp1_pref=fw->getOptionsObject()->getBool("pix_ntp1_pref");
string ntp_server_2=fw->getOptionsObject()->getStr("pix_ntp2");
bool ntp2_pref=fw->getOptionsObject()->getBool("pix_ntp2_pref");
string ntp_server_3=fw->getOptionsObject()->getStr("pix_ntp3");
bool ntp3_pref=fw->getOptionsObject()->getBool("pix_ntp3_pref");
if (!ntp_server_1.empty())
res << _printNTPServer(ntp_server_1,ntp1_pref);
if (!ntp_server_2.empty())
res << _printNTPServer(ntp_server_2,ntp2_pref);
if (!ntp_server_3.empty())
res << _printNTPServer(ntp_server_3,ntp3_pref);
return res.str();
}
string OSConfigurator_pix_os::_printSysopt()
{
ostringstream res;
string platform = fw->getStr("platform");
string version = fw->getStr("version");
FWOptions *options=fw->getOptionsObject();
assert(options!=NULL);
bool tcpmss= fw->getOptionsObject()->getBool("pix_tcpmss");
int tcpmss_val=fw->getOptionsObject()->getInt("pix_tcpmss_value");
res << endl;
if (fw->getOptionsObject()->getBool("pix_resetinbound"))
res << "service resetinbound" << endl;
else
res << "no service resetinbound" << endl;
if (fw->getOptionsObject()->getBool("pix_resetoutside"))
res << "service resetoutside" << endl;
else
res << "no service resetoutside" << endl;
if (tcpmss)
res << "sysopt connection tcpmss " << tcpmss_val << endl;
if (fw->getStr("platform")=="pix")
{
if (fw->getOptionsObject()->getBool("pix_connection_timewait"))
res << "sysopt connection timewait" << endl;
else
res << "no sysopt connection timewait" << endl;
}
if (Resources::platform_res[platform]->getResourceBool(
"/FWBuilderResources/Target/options/version_"+version+
"/pix_security_fragguard_supported") )
{
if ( fw->getOptionsObject()->getBool("pix_fragguard") )
res << "sysopt security fragguard" << endl;
else
res << "no sysopt security fragguard" << endl;
}
if ( fw->getOptionsObject()->getBool("pix_nodnsalias_inbound") )
res << "sysopt nodnsalias inbound" << endl;
else
res << "no sysopt nodnsalias inbound" << endl;
if ( fw->getOptionsObject()->getBool("pix_nodnsalias_outbound") )
res << "sysopt nodnsalias outbound" << endl;
else
res << "no sysopt nodnsalias outbound" << endl;
if (Resources::platform_res[platform]->getResourceBool(
"/FWBuilderResources/Target/options/version_"+version+
"/pix_route_dnat_supported") )
{
if ( fw->getOptionsObject()->getBool("pix_route_dnat") )
res << "sysopt route dnat" << endl;
else
res << "no sysopt route dnat" << endl;
}
if (Resources::platform_res[platform]->getResourceBool(
"/FWBuilderResources/Target/options/version_"+version+
"/pix_floodguard_supported") )
{
if ( fw->getOptionsObject()->getBool("pix_floodguard") )
res << "floodguard enable" << endl;
else
res << "floodguard disable" << endl;
}
res << endl;
return res.str();
}
string OSConfigurator_pix_os::_printServiceTimeout(const std::string &pix_service)
{
ostringstream res;
string hh,mm,ss;
string version = fw->getStr("version");
string platform = fw->getStr("platform");
bool use_sunrpc = Resources::platform_res[platform]->getResourceBool(
"/FWBuilderResources/Target/options/version_"+version+
"/pix_timeout_rpc_is_sunrpc");
hh=fw->getOptionsObject()->getStr(pix_service+"_hh");
mm=fw->getOptionsObject()->getStr(pix_service+"_mm");
ss=fw->getOptionsObject()->getStr(pix_service+"_ss");
if (hh!="" && mm!="" && ss!="")
{
string service_name = pix_service;
if (pix_service=="rpc" && use_sunrpc)
service_name = "sunrpc";
res << "timeout " << service_name
<< " " << hh << ":" << mm << ":" << ss << " ";
if (pix_service=="uauth")
{
bool abs=fw->getOptionsObject()->getBool("uauth_abs");
bool inact=fw->getOptionsObject()->getBool("uauth_inact");
if (abs) res << "absolute";
if (inact) res << "inactivity";
}
res << endl;
}
return res.str();
}
string OSConfigurator_pix_os::_printTimeouts()
{
ostringstream res;
res << _printServiceTimeout("xlate");
res << _printServiceTimeout("conn");
res << _printServiceTimeout("udp");
res << _printServiceTimeout("rpc");
res << _printServiceTimeout("h323");
res << _printServiceTimeout("sip");
res << _printServiceTimeout("sip_media");
res << _printServiceTimeout("half-closed");
res << _printServiceTimeout("uauth");
res << endl;
int to;
to=fw->getOptionsObject()->getInt("pix_telnet_timeout");
if (to>60) abort("Telnet timeout should not exceed 60 minutes");
if (to!=0) res << "telnet timeout " << to << endl;
to=fw->getOptionsObject()->getInt("pix_ssh_timeout");
if (to>60) abort("SSH timeout should not exceed 60 minutes");
if (to!=0) res << "ssh timeout " << to << endl;
return res.str();
}
void OSConfigurator_pix_os::addVirtualAddressForNAT(const Address *addr)
{
if (addr==NULL) ;
}
void OSConfigurator_pix_os::addVirtualAddressForNAT(const Network *nw)
{
if (nw==NULL) ;
}

View File

@ -0,0 +1,77 @@
/*
Firewall Builder
Copyright (C) 2002 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: OSConfigurator_pix_os.h,v 1.1 2008/03/06 06:49:00 vkurland Exp $
This program is free software which we release under the GNU General Public
License. You may redistribute and/or modify this program under the terms
of that license as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
To get a copy of the GNU General Public License, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _OSNETWORKCONFIGURATOR_PIX_OS_HH
#define _OSNETWORKCONFIGURATOR_PIX_OS_HH
#include "config.h"
#include "fwcompiler/OSConfigurator.h"
#include <map>
namespace fwcompiler {
class OSConfigurator_pix_os : public OSConfigurator {
std::string _printNameif();
std::string _printIPAddress();
std::string _printLogging();
std::string _printSNMPServer(const std::string &srv,int poll_trap);
std::string _printSNMP();
std::string _printSysopt();
std::string _printNTPServer(const std::string &srv,bool pref);
std::string _printNTP();
std::string _printServiceTimeout(const std::string &pix_service);
std::string _printTimeouts();
std::string _printFixupCommand(const std::string &fixup_name,
const std::string &sw,
int arg1,
int arg2,
bool ov);
std::string _printFixups();
std::string _printMPF();
public:
virtual ~OSConfigurator_pix_os() {};
OSConfigurator_pix_os(libfwbuilder::FWObjectDatabase *_db,
const std::string &fwname) :
OSConfigurator(_db,fwname) {}
virtual int prolog();
virtual std::string myPlatformName();
virtual void processFirewallOptions();
virtual void addVirtualAddressForNAT(const libfwbuilder::Address *addr);
virtual void addVirtualAddressForNAT(const libfwbuilder::Network *nw);
std::string getProtocolInspectionCommands();
};
};
#endif

View File

@ -0,0 +1,447 @@
/*
Firewall Builder
Copyright (C) 2002 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: OSConfigurator_pix_os_fixups.cpp,v 1.1 2008/03/06 06:49:00 vkurland Exp $
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 "OSConfigurator_pix_os.h"
#include "Helper.h"
#include "fwbuilder/Resources.h"
#include "fwbuilder/Firewall.h"
#include "fwbuilder/FWOptions.h"
#include "fwbuilder/Interface.h"
#include "fwbuilder/Management.h"
#include "fwbuilder/Resources.h"
#include <list>
#include <algorithm>
#include <functional>
#include <assert.h>
#include <iostream>
using namespace libfwbuilder;
using namespace fwcompiler;
using namespace std;
/* ********************************************************************
*
* Generating old school fixup commands for PIX 6.X
* and FWSM 2.3
*
* ********************************************************************/
/*
* Copy this method into class PIXAdvancedFWDialog in fwbuilder/src/pix
*/
string OSConfigurator_pix_os::_printFixupCommand(const string &fixup_name,
const string &sw,
int arg1,
int arg2,
bool ov)
{
ostringstream res;
if (sw=="0")
{
if (fixup_name=="dns")
{
if (arg1)
{
res << "fixup protocol " << fixup_name;
res << " maximum-length " << arg1;
res << endl;
}
} else
{
if (fixup_name=="ftp")
{
if (arg1)
{
res << "fixup protocol " << fixup_name << " ";
if (ov) res << "strict ";
res << arg1;
res << endl;
}
} else
{
if (fixup_name=="mgcp")
{
if (arg1)
{
res << "fixup protocol " << fixup_name << " ";
res << arg1;
res << endl;
}
if (arg2)
{
res << "fixup protocol " << fixup_name << " ";
res << arg2;
res << endl;
}
} else
{
res << "fixup protocol " << fixup_name << " ";
if (arg1) res << arg1;
if (arg2 && arg1!=arg2) res << "-" << arg2;
res << endl;
}
}
}
}
if (sw=="1")
{
res << "no fixup protocol " << fixup_name;
res << endl;
}
return res.str();
}
string OSConfigurator_pix_os::_printFixups()
{
ostringstream res;
string platform=fw->getStr("platform");
string version=fw->getStr("version");
FWOptions *options=fw->getOptionsObject();
assert(options!=NULL);
string lst=Resources::platform_res[platform]->getResourceStr(
"/FWBuilderResources/Target/options/version_"+version+"/fixups/list");
string::size_type i,j, k;
i=0;
while ( i<lst.size() )
{
j=lst.find(",",i);
string fixup_xml_element=lst.substr(i,j-i);
i=j+1;
string f=options->getStr(fixup_xml_element);
if (!f.empty())
{
string fixup_name=fixup_xml_element.substr(0, fixup_xml_element.find("_fixup") );
while ( (k=fixup_name.find("_"))!=string::npos )
fixup_name.replace(k,1,1,' ');
string sw;
int arg1,arg2;
string on;
bool ov;
istringstream str(f);
str >> sw >> arg1 >> arg2 >> on >> ov;
res << _printFixupCommand(fixup_name, sw, arg1, arg2, ov );
}
if (j==string::npos) break;
}
return res.str();
}
/* ********************************************************************
*
* Generating class-map, class and match commands instead of fixups
* for PIX 7.0
*
* ********************************************************************/
class InspectionProtocol;
std::map<std::string,InspectionProtocol*> protocols;
enum { FIXUP_ENABLE=0, FIXUP_DISABLE=1, FIXUP_SKIP=2 } fixupStatus;
/*
* par1 and par2 are parameters for the inspection protocol. These are
* port numbers most of the time, but for some protocols the meaning
* may be different. For example for dns it is "maximum-length".
*/
class InspectionProtocol {
public:
string name;
string printable_name;
string ip_proto;
int par1,par2;
InspectionProtocol(const string &fn,
const string &prn,
const string &pn,
int p1,
int p2)
{
name=fn; printable_name=prn; ip_proto=pn; par1=p1; par2=p2;
if (protocols.count(fn)==0) protocols[fn]=this;
}
};
/*
* Default ports are defined here jsut like they are filled in the
* options by the GUI. If the GUI allows for port range, we specify
* port range here, and vice versa. Some of the cases seem to differ
* from what Cisco doc specify in the table of the default ports here
* http://www.cisco.com/en/US/products/sw/secursw/ps2120/products_upgrade_guides09186a0080369ee2.html
* I suppose this is ok since we always can use port range map with
* "match" command even if they did not intend it to be like that by
* default. However if the GUI returned port numbers that match those
* defined in protocolDefinitions, we do not generate 'match' commands
* at all and put everything in the "inspection_default" class-map
*
* Here is how this works: constructor of the class InspectionProtocols
* adds object to map 'protocols'. Every initialization of an object
* of this class in array protocolDefinitions calls constructor and
* therefore creates an entry in the map 'protocols'. It is done this
* way because we can statically initialize an array but cant initialize
* std::map (at least I do not know how)
*
* Note: in PIX 7.0 inspector that corresponds to fixup 'smtp' is
* called 'esmtp'
*/
InspectionProtocol protocolDefinitions[] =
{
InspectionProtocol("ctiqbe", "ctiqbe", "tcp", 2748, 0 ),
InspectionProtocol("dns", "dns", "udp", 53, 0 ),
InspectionProtocol("ftp", "ftp", "tcp", 21, 0 ),
InspectionProtocol("gtp", "gtp", "udp", 2123, 3386 ),
InspectionProtocol("h323_h225", "h323 h225", "tcp", 1720, 1720 ),
InspectionProtocol("h323_ras", "h323 ras", "udp", 1718, 1719 ),
InspectionProtocol("http", "http", "tcp", 80, 80 ),
InspectionProtocol("icmp_error","icmp", "icmp", 0, 0 ),
InspectionProtocol("ils", "ils", "tcp", 389, 389 ),
InspectionProtocol("mgcp", "mgcp", "udp", 2427, 2727 ),
InspectionProtocol("netbios", "netbios", "udp", 137, 138 ),
InspectionProtocol("rpc", "rpc", "udp", 111, 0 ),
InspectionProtocol("rsh", "rsh", "tcp", 514, 0 ),
InspectionProtocol("rtsp", "rtsp", "tcp", 554, 0 ),
InspectionProtocol("sip", "sip", "tcp", 5060, 5060 ),
InspectionProtocol("sip_udp", "sip", "udp", 5060, 0 ),
InspectionProtocol("skinny", "skinny", "tcp", 2000, 2000 ),
InspectionProtocol("smtp", "esmtp", "tcp", 25, 25 ),
InspectionProtocol("sqlnet", "sqlnet", "tcp", 1521, 1521 ),
InspectionProtocol("tftp", "tftp", "udp", 69, 0 ),
InspectionProtocol("xdmcp", "xdmcp", "udp", 177, 0 ),
};
/*
* status:
* 0: enable
* 1: disable
* 2: skip
*/
class InspectionClassMap {
public:
string class_map_name;
string fixup_name;
string inspect_name;
int status;
int port1,port2;
string arg_name;
int arg_val;
InspectionClassMap(const string &fn,int s,int p1,int p2,const string &a,int v)
{
status=s; port1=p1; port2=p2; arg_name=a; arg_val=v;
string ss = fn;
string::size_type k;
while ( (k=ss.find(" "))!=string::npos )
ss.replace(k,1,1,'_');
inspect_name = ss;
fixup_name = fn;
class_map_name = string("custom_")+ss+string("_inspection");
}
bool isDefault();
string getIPProtocol();
string getPrintableName();
string getMatchCommand();
};
std::list<InspectionClassMap> defaultClassMaps;
std::list<InspectionClassMap> customClassMaps;
std::map<std::string,int> DefaultInspectionInspectStatements;
std::map<std::string,int> CustomInspectionInspectStatements;
bool InspectionClassMap::isDefault()
{
InspectionProtocol *ip = protocols[fixup_name];
if (ip!=NULL) return (ip->par1==port1 && ip->par2==port2);
return false;
}
string InspectionClassMap::getIPProtocol()
{
InspectionProtocol *ip = protocols[fixup_name];
if (ip!=NULL) return ip->ip_proto;
return "";
}
string InspectionClassMap::getPrintableName()
{
InspectionProtocol *ip = protocols[fixup_name];
if (ip!=NULL) return ip->printable_name;
return "";
}
string InspectionClassMap::getMatchCommand()
{
ostringstream res;
res << "match port " << getIPProtocol() << " ";
if (port1!=0 && port2==0)
res << "eq " << port1;
if (port1!=0 && port1==port2)
res << "eq " << port1;
if (port1!=0 && port2!=0 && port1!=port2)
res << "range " << port1 << " " << port2;
res << endl;
return res.str();
}
string OSConfigurator_pix_os::_printMPF()
{
ostringstream res;
string platform=fw->getStr("platform");
string version=fw->getStr("version");
FWOptions *options=fw->getOptionsObject();
assert(options!=NULL);
string lst=Resources::platform_res[platform]->getResourceStr(
"/FWBuilderResources/Target/options/version_"+version+"/fixups/list");
defaultClassMaps.clear();
customClassMaps.clear();
DefaultInspectionInspectStatements.clear();
CustomInspectionInspectStatements.clear();
string::size_type i,j;
i=0;
while ( i<lst.size() )
{
j=lst.find(",",i);
string fixup_xml_element=lst.substr(i,j-i);
i=j+1;
string f=options->getStr(fixup_xml_element);
if (!f.empty())
{
string fixup_name=fixup_xml_element.substr(0, fixup_xml_element.find("_fixup") );
int status;
int p1,p2;
string an;
int av;
istringstream str(f);
str >> status >> p1 >> p2 >> an >> av;
/* We should really fix this in the GUI and pass max length parameter
* as an/av rather than as port p1
*/
if (fixup_name=="dns" && p1!=0) { an="maximum-length"; av=p1; p1=53; }
InspectionClassMap cm(fixup_name,status,p1,p2,an,av);
if (cm.isDefault()) defaultClassMaps.push_back(cm);
else customClassMaps.push_back(cm);
}
if (j==string::npos) break;
}
res << "class-map inspection_default" << endl;
res << " match default-inspection-traffic" << endl;
res << endl;
std::list<InspectionClassMap>::iterator i1;
if (customClassMaps.size()>0)
{
for (i1=customClassMaps.begin(); i1!=customClassMaps.end(); i1++)
{
res << "class-map " << i1->class_map_name << endl;
res << " " << i1->getMatchCommand() << endl;
}
res << endl;
}
res << "policy-map global_policy" << endl;
if (defaultClassMaps.size()>0)
{
res << " class inspection_default" << endl;
for (i1=defaultClassMaps.begin(); i1!=defaultClassMaps.end(); i1++)
{
string pn = i1->getPrintableName();
if (i1->status!=FIXUP_SKIP &&
DefaultInspectionInspectStatements[pn]!=1)
{
res << " ";
if (i1->status==FIXUP_DISABLE) res << "no ";
res << "inspect " << pn << endl;
DefaultInspectionInspectStatements[pn]=1;
}
}
}
if (customClassMaps.size()>0)
{
for (i1=customClassMaps.begin(); i1!=customClassMaps.end(); i1++)
{
string pn = i1->getPrintableName();
if (i1->status!=FIXUP_SKIP &&
CustomInspectionInspectStatements[pn]!=1)
{
res << " class " << i1->class_map_name << endl;
res << " ";
if (i1->status==FIXUP_DISABLE) res << "no ";
res << "inspect " << i1->getPrintableName() << endl;
CustomInspectionInspectStatements[pn]=1;
}
}
}
res << endl;
res << "service-policy global_policy global" << endl;
return res.str();
}
string OSConfigurator_pix_os::getProtocolInspectionCommands()
{
string platform=fw->getStr("platform");
string version=fw->getStr("version");
if (Resources::platform_res[platform]->getResourceBool(
"/FWBuilderResources/Target/options/version_"+version+"/fixups/use_mpf"))
return _printMPF();
return _printFixups();
}

118
src/pix/PIXObjectGroup.cpp Normal file
View File

@ -0,0 +1,118 @@
/*
Firewall Builder
Copyright (C) 2002 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: PIXObjectGroup.cpp,v 1.1 2008/03/06 06:49:00 vkurland Exp $
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 "PIXObjectGroup.h"
#include <iostream>
#include <sstream>
using namespace std;
map<string,int> PIXGroup::nc;
const char *PIXGroup::TYPENAME={"PIXGroup"};
string PIXGroup::registerGroupName(const std::string &prefix)
{
ostringstream str;
str << prefix;
switch (getPIXGroupType())
{
case UNKNOWN: str << ".unknown"; break;
case NETWORK: str << ".net"; break;
case PROTO: str << ".proto"; break;
case ICMP_TYPE: str << ".icmp"; break;
case TCP_SERVICE: str << ".tcp"; break;
case UDP_SERVICE: str << ".udp"; break;
}
int n=nc[str.str()];
nc[str.str()]=n+1;
str << "." << n;
return str.str();
}
void PIXGroup::setName(const std::string &prefix)
{
FWObject::setName( registerGroupName(prefix) );
}
bool PIXGroup::isServiceGroup()
{
switch (getPIXGroupType())
{
case PROTO: return true;
case ICMP_TYPE: return true;
case TCP_SERVICE: return true;
case UDP_SERVICE: return true;
default: return false;
}
return false;
}
bool PIXGroup::isObjectGroup()
{
switch (getPIXGroupType())
{
case UNKNOWN: return true;
case NETWORK: return true;
default: return false;
}
return false;
}
string PIXGroup::getSrvTypeName()
{
switch (getPIXGroupType())
{
case ICMP_TYPE: return "icmp";
case TCP_SERVICE: return "tcp";
case UDP_SERVICE: return "udp";
default: break;
}
return "";
}
#if 0
void PIXServiceGroup::setName(const std::string &prefix)
{
FWObject::setName( registerGroupName(prefix) );
}
const char *PIXObjectGroup::TYPENAME={"PIXObjectGroup"};
PIXObjectGroup::PIXObjectGroup(pix_group_type _gt) :
ObjectGroup(), PIXGroup(_gt) {}
const char *PIXServiceGroup::TYPENAME={"PIXServiceGroup"};
PIXServiceGroup::PIXServiceGroup(pix_group_type _gt) :
ServiceGroup(), PIXGroup(_gt) {}
#endif

94
src/pix/PIXObjectGroup.h Normal file
View File

@ -0,0 +1,94 @@
/*
Firewall Builder
Copyright (C) 2002 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: PIXObjectGroup.h,v 1.1 2008/03/06 06:49:00 vkurland Exp $
This program is free software which we release under the GNU General Public
License. You may redistribute and/or modify this program under the terms
of that license as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
To get a copy of the GNU General Public License, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __PIXOBJECTGROUP_HH
#define __PIXOBJECTGROUP_HH
#include "fwbuilder/FWObject.h"
#include "fwbuilder/ObjectGroup.h"
#include "fwbuilder/ServiceGroup.h"
typedef enum { UNKNOWN,
NETWORK,
PROTO,
ICMP_TYPE,
TCP_SERVICE,
UDP_SERVICE } pix_group_type;
class PIXGroup : public libfwbuilder::Group {
private:
pix_group_type gt;
static std::map<std::string,int> nc;
protected:
std::string registerGroupName(const std::string &prefix);
public:
PIXGroup(pix_group_type _gt=UNKNOWN) : libfwbuilder::Group() { gt=_gt; }
virtual ~PIXGroup() {};
DECLARE_FWOBJECT_SUBTYPE(PIXGroup);
virtual bool validateChild(FWObject *o) { return true; }
void setPIXGroupType(pix_group_type _gt) { gt=_gt; }
pix_group_type getPIXGroupType() { return gt; }
virtual void setName(const std::string &prefix);
bool isServiceGroup();
bool isObjectGroup();
std::string getSrvTypeName();
};
#if 0
class PIXObjectGroup : public libfwbuilder::ObjectGroup
{
private:
pix_group_type gt;
public:
PIXObjectGroup(pix_group_type _gt=NETWORK) : ObjectGroup() { gt=_gt; }
virtual ~PIXObjectGroup() {};
DECLARE_FWOBJECT_SUBTYPE(PIXObjectGroup);
virtual bool validateChild(FWObject *o) { if (o==NULL) ; return true; }
virtual void setName(const std::string &prefix);
};
class PIXServiceGroup : public libfwbuilder::ServiceGroup
{
private:
pix_group_type gt;
public:
PIXServiceGroup(pix_group_type _gt=UNKNOWN) : ServiceGroup() { gt=_gt; }
virtual ~PIXServiceGroup() {};
DECLARE_FWOBJECT_SUBTYPE(PIXServiceGroup);
virtual bool validateChild(FWObject *o) { if (o==NULL) ; return true; }
virtual void setName(const std::string &prefix);
};
#endif
#endif

View File

@ -0,0 +1,845 @@
/*
Firewall Builder
Copyright (C) 2002 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: PolicyCompiler_pix.cpp,v 1.1 2008/03/06 06:49:00 vkurland Exp $
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 "Helper.h"
#include "PolicyCompiler_pix.h"
#include "NATCompiler_pix.h"
#include "PIXObjectGroup.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/Network.h"
#include "fwbuilder/Policy.h"
#include "fwbuilder/Interface.h"
#include "fwbuilder/Management.h"
#include "fwbuilder/Resources.h"
#include "fwbuilder/AddressTable.h"
#include <iostream>
#if __GNUC__ > 3 || \
(__GNUC__ == 3 && (__GNUC_MINOR__ > 2 || (__GNUC_MINOR__ == 2 ) ) ) || \
_MSC_VER
# include <streambuf>
#else
# include <streambuf.h>
#endif
#include <iomanip>
#include <algorithm>
#include <functional>
#include <assert.h>
using namespace libfwbuilder;
using namespace fwcompiler;
using namespace std;
string PolicyCompiler_pix::myPlatformName() { return "pix"; }
PolicyCompiler_pix::PolicyCompiler_pix(FWObjectDatabase *_db,
const std::string &fwname,
OSConfigurator *_oscnf,
NATCompiler_pix *_natcmp) :
PolicyCompiler_cisco(_db,fwname,_oscnf)
{
natcmp=_natcmp;
resetinbound=false;
fragguard=false;
}
int PolicyCompiler_pix::prolog()
{
string version = fw->getStr("version");
string platform = fw->getStr("platform");
string host_os = fw->getStr("host_OS");
if (platform!="pix" && platform!="fwsm")
abort("Unsupported platform " + platform );
object_groups=new Group();
dbcopy->add( object_groups );
output << "!################" << endl;
if (platform=="fwsm")
{
if (fw->getOptionsObject()->getBool("pix_use_manual_commit") )
output << "access-list mode manual" << endl;
else
output << "access-list mode auto" << endl;
}
if ( fw->getOptionsObject()->getBool("pix_acl_substitution") )
{
/* Generate short temporary ACL and assign it to all
* interfaces. This ACL permits IPSEC (IP proto 50 and UDP port 500)
as well as ssh from given subnet to any.
*/
string temp_acl = "tmp_acl";
string temp_acl_addr = fw->getOptionsObject()->getStr("pix_acl_temp_addr");
if (temp_acl_addr.empty())
{
abort("Missing address for management host or subnet for temporary ACL.\nPlease enter it in the tab 'Script options' in 'Firewall Settings' dialog");
}
string::size_type slash_idx = temp_acl_addr.find('/');
string addr = temp_acl_addr;
string netmask = "255.255.255.255";
if (slash_idx!=string::npos)
{
addr = temp_acl_addr.substr(0,slash_idx);
netmask = temp_acl_addr.substr(slash_idx+1);
try
{
if (netmask.find(".")!=string::npos)
{
Netmask nm(netmask);
nm.to32BitInt(); // to avoid warning abt unused var
} else
{
int nm_length;
istringstream str(netmask);
str >> nm_length;
Netmask nm(nm_length);
netmask = nm.toString();
}
} catch(FWException &ex)
{
abort("Invalid netmask for management subnet: '"+netmask+"'");
}
}
try
{
IPAddress a(addr);
a.to32BitInt();
} catch(FWException &ex)
{
abort("Invalid address for management subnet: '"+addr+"'");
}
string clearACLcmd = Resources::platform_res[platform]->getResourceStr(
string("/FWBuilderResources/Target/options/")+
"version_"+version+"/pix_commands/clear_acl");
output << endl;
output << clearACLcmd << " " << temp_acl << endl;
output << "access-list " << temp_acl
<< " permit ip "
<< addr << " " << netmask
<< " any "
<< endl;
output << "access-list " << temp_acl
<< " deny ip any any "
<< endl;
if (platform=="fwsm" &&
fw->getOptionsObject()->getBool("pix_use_manual_commit") )
output << "access-list commit" << endl;
output << endl;
output << "access-group " << temp_acl
<< " in interface outside" << endl;
output << "access-group " << temp_acl
<< " in interface inside" << endl;
output << endl;
}
return PolicyCompiler::prolog();
}
bool PolicyCompiler_pix::checkVersionAndDynamicInterface::findDynamicInterface(
PolicyRule *rule, RuleElement *rel)
{
string vers=compiler->fw->getStr("version");
for (list<FWObject*>::iterator i1=rel->begin(); i1!=rel->end(); ++i1)
{
FWObject *o = *i1;
FWObject *obj = NULL;
if (FWReference::cast(o)!=NULL) obj=FWReference::cast(o)->getPointer();
Interface *iface=Interface::cast(obj);
if (iface!=NULL && iface->isDyn() && (vers=="6.1" || vers=="6.2"))
compiler->abort("Dynamic interface can be used in the policy rule only in v6.3 or later. Rule "+rule->getLabel());
}
return true;
}
bool PolicyCompiler_pix::checkVersionAndDynamicInterface::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
tmp_queue.push_back(rule);
Service *s=compiler->getFirstSrv(rule);
/* if service is ssh, telnet or icmp then we can use dynamic interface
* even in earlier versions */
if (ICMPService::isA(s)) return true;
if (TCPService::isA(s))
{
if ( s->getInt("dst_range_start")==22 &&
s->getInt("dst_range_end")==22) return true;
if ( s->getInt("dst_range_start")==23 &&
s->getInt("dst_range_end")==23) return true;
}
findDynamicInterface(rule,rule->getSrc());
findDynamicInterface(rule,rule->getDst());
return true;
}
bool PolicyCompiler_pix::SpecialServices::processNext()
{
PolicyCompiler_pix *pix_comp=dynamic_cast<PolicyCompiler_pix*>(compiler);
PolicyRule *rule=getNext(); if (rule==NULL) return false;
Service *s=compiler->getFirstSrv(rule);
if (IPService::cast(s)!=NULL) {
if (s->getBool("short_fragm") ||
s->getBool("fragm") ) {
pix_comp->fragguard=true;
return true; // do not copy the rule
}
if (s->getBool("rr") ||
s->getBool("ssrr") ||
s->getBool("ts") )
compiler->abort("PIX does not support checking for IP options in ACLs. Rule: "+rule->getLabel());
}
if (TCPService::cast(s)!=NULL) {
if (s->getBool("ack_flag") ||
s->getBool("fin_flag") ||
s->getBool("rst_flag") ||
s->getBool("syn_flag") )
compiler->abort("PIX does not support checking for TCP options in ACLs. Rule: "+rule->getLabel());
}
tmp_queue.push_back(rule);
return true;
}
/*
* if dst contains firewall, it must be a single object there.
*/
bool PolicyCompiler_pix::PrepareForICMPCmd::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
Address *dst=compiler->getFirstDst(rule);
Service *srv=compiler->getFirstSrv(rule);
if (ICMPService::isA(srv) &&
compiler->complexMatch(dst,compiler->fw))
rule->setBool("icmp_cmd",true);
tmp_queue.push_back(rule);
return true;
}
bool PolicyCompiler_pix::SplitSRCForICMPCmd::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
if (rule->getBool("icmp_cmd"))
{
RuleElementSrc *src=rule->getSrc();
if (src->size()==1)
{
tmp_queue.push_back(rule);
return true;
}
for (FWObject::iterator i=src->begin(); i!=src->end(); ++i)
{
FWObject *o = *i;
FWObject *obj = NULL;
if (FWReference::cast(o)!=NULL) obj=FWReference::cast(o)->getPointer();
Address *a=Address::cast(obj);
assert(a!=NULL);
PolicyRule *new_rule= PolicyRule::cast(compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(new_rule);
new_rule->duplicate(rule);
RuleElementSrc *new_re=new_rule->getSrc();
new_re->clearChildren();
new_re->addRef(a);
tmp_queue.push_back(new_rule);
}
} else
tmp_queue.push_back(rule);
return true;
}
/*
* About "service resetinbound" command:
*
* "The service command works with all inbound TCP connections to
* statics whose access lists or uauth (user authorization) do not
* allow inbound"
*/
bool PolicyCompiler_pix::RejectAction::processNext()
{
PolicyCompiler_pix *pix_comp=dynamic_cast<PolicyCompiler_pix*>(compiler);
PolicyRule *rule=getNext(); if (rule==NULL) return false;
if (rule->getAction()==PolicyRule::Reject)
pix_comp->resetinbound=true;
tmp_queue.push_back(rule);
return true;
}
bool PolicyCompiler_pix::replaceNATtedObjects::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
PolicyCompiler_pix *pix_comp=dynamic_cast<PolicyCompiler_pix*>(compiler);
Interface *rule_iface = compiler->getCachedFwInterface(rule->getInterfaceId());
// string rule_iface_id=rule->getInterfaceId();
// Address *src=compiler->getFirstSrc(rule);
// Service *srv=compiler->getFirstSrv(rule);
RuleElementSrc *srcrel=rule->getSrc();
RuleElementDst *dstrel=rule->getDst();
RuleElementSrv *srvrel=rule->getSrv();
list<PolicyRule*> t_rules;
list<PolicyRule*> transformed_rules;
for (list<FWObject*>::iterator i1=srcrel->begin(); i1!=srcrel->end(); ++i1)
{
for (list<FWObject*>::iterator i2=dstrel->begin(); i2!=dstrel->end(); ++i2)
{
for (list<FWObject*>::iterator i3=srvrel->begin(); i3!=srvrel->end(); ++i3)
{
FWObject *o1 = *i1;
FWObject *o2 = *i2;
FWObject *o3 = *i3;
FWObject *obj1 = NULL;
FWObject *obj2 = NULL;
FWObject *obj3 = NULL;
if (FWReference::cast(o1)!=NULL)
obj1=FWReference::cast(o1)->getPointer();
Address *src=Address::cast(obj1);
assert(src!=NULL);
if (FWReference::cast(o2)!=NULL)
obj2=FWReference::cast(o2)->getPointer();
Address *dst=Address::cast(obj2);
assert(dst!=NULL);
if (FWReference::cast(o3)!=NULL)
obj3=FWReference::cast(o3)->getPointer();
Service *srv=Service::cast(obj3);
assert(srv!=NULL);
list<triplet> tl = pix_comp->natcmp->findDNATForAddress(
src,dst,srv);
for( list<triplet>::iterator t=tl.begin(); t!=tl.end(); ++t)
{
FWObject *p = t->dst->getParent();
if (t->dst->getId()==rule_iface->getId() ||
p->getId()==rule_iface->getId())
{
PolicyRule *r = PolicyRule::cast(
compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
RuleElementSrc *nsrc=r->getSrc();
nsrc->clearChildren();
nsrc->addRef( src );
RuleElementDst *ndst=r->getDst();
ndst->clearChildren();
ndst->addRef( t->dst );
RuleElementSrv *nsrv=r->getSrv();
nsrv->clearChildren();
nsrv->addRef( t->srv );
t_rules.push_back(r);
}
}
}
}
}
/* list t_rules has all the atomic rules that have a
* matching NAT rule, with dst and srv already converted. We just add them to
* the policy on top of the original rule.
*/
for (list<PolicyRule*>::iterator i1=t_rules.begin(); i1!=t_rules.end(); ++i1)
{
PolicyRule *r=PolicyRule::cast( *i1 );
tmp_queue.push_back(r);
}
tmp_queue.push_back(rule);
return true;
}
/*
* processor splitIfDstMatchesFw should have made a firewall a single
* object in dst
*/
bool PolicyCompiler_pix::splitIfTelnetSSHICMPtoFw::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
// PolicyCompiler_pix *pix_comp=dynamic_cast<PolicyCompiler_pix*>(compiler);
Address *dst=compiler->getFirstDst(rule);
RuleElement *re=rule->getSrc();
if (re->size()!=1 && dst->getId()==compiler->getFwId())
{
for (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();
PolicyRule *r= PolicyRule::cast(compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
RuleElementSrc *nsrc=r->getSrc();
nsrc->clearChildren();
nsrc->addRef( obj );
tmp_queue.push_back(r);
}
} else
tmp_queue.push_back(rule);
return true;
}
/*
* this is probably not necessary. PIX prints all acl rules with
* object-groups twice: first time as entered, with object-group, and
* the second time it expands the group (for convenience ?). I thought
* it does not print original rule for icmp but it looks like it it
* does it for icmp just like for other protocols. PIX is ok, I made a
* mistake. I keep with rule processor just in case, but comment out
* the call to it.
*/
bool PolicyCompiler_pix::AvoidObjectGroup::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
// PolicyCompiler_pix *pix_comp=dynamic_cast<PolicyCompiler_pix*>(compiler);
RuleElement *srv=RuleElement::cast(rule->getFirstByType(RuleElementSrv::TYPENAME));
if (srv->size()==1) // no need to create object-group since there is single object in the rule element
{
tmp_queue.push_back(rule);
return true;
}
FWObject *o = srv->front();
if (FWReference::cast(o)!=NULL) o=FWReference::cast(o)->getPointer();
if (ICMPService::isA(o))
{
/* we have a rule with multiple icmp services in Srv. We do not want
* to use object-group for it because PIX 6.3(3) expands them anyway,
* which breaks incremental installer.
*/
for (FWObject::iterator i1=srv->begin(); i1!=srv->end(); ++i1)
{
PolicyRule *r = PolicyRule::cast(
compiler->dbcopy->create(PolicyRule::TYPENAME) );
r->duplicate(rule);
compiler->temp_ruleset->add(r);
FWObject *s;
s=r->getSrv(); assert(s);
s->clearChildren();
s->add( *i1 );
tmp_queue.push_back(r);
}
return true;
}
tmp_queue.push_back(rule);
return true;
}
PIXGroup* PolicyCompiler_pix::CreateObjectGroups::findObjectGroup(RuleElement *re)
{
PolicyCompiler_pix *pix_comp=dynamic_cast<PolicyCompiler_pix*>(compiler);
list<FWObject*> relement;
for (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();
relement.push_back(obj);
}
for (FWObject::iterator i=pix_comp->object_groups->begin();
i!=pix_comp->object_groups->end(); ++i)
{
PIXGroup *og=dynamic_cast<PIXGroup*>(*i);
assert(og!=NULL);
if (og->size()==0 || (og->size()!=re->size()) ) continue;
bool match=true;
for (FWObject::iterator i1=og->begin(); i1!=og->end(); ++i1)
{
FWObject *o = *i1;
FWObject *obj = o;
if (FWReference::cast(o)!=NULL) obj=FWReference::cast(o)->getPointer();
if ( find(relement.begin(), relement.end(), obj)==relement.end() )
{
match=false;
break;
}
}
if (match) return og;
}
return NULL;
}
bool PolicyCompiler_pix::CreateObjectGroups::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
PolicyCompiler_pix *pix_comp=dynamic_cast<PolicyCompiler_pix*>(compiler);
Interface *rule_iface = compiler->getCachedFwInterface(rule->getInterfaceId());
assert(rule_iface);
RuleElement *re=RuleElement::cast(rule->getFirstByType(re_type));
if (re->size()==1) // no need to create object-group since there is single object in the rule element
{
tmp_queue.push_back(rule);
return true;
}
PIXGroup *obj_group=findObjectGroup(re);
if (obj_group==NULL)
{
obj_group= new PIXGroup();
FWObject *o=re->front();
FWObject *obj = o;
if (FWReference::cast(o)!=NULL) obj=FWReference::cast(o)->getPointer();
if (Address::cast(obj)!=NULL) obj_group->setPIXGroupType(NETWORK);
if (IPService::cast(obj)!=NULL) obj_group->setPIXGroupType(PROTO);
if (ICMPService::cast(obj)!=NULL) obj_group->setPIXGroupType(ICMP_TYPE);
if (TCPService::cast(obj)!=NULL) obj_group->setPIXGroupType(TCP_SERVICE);
if (UDPService::cast(obj)!=NULL) obj_group->setPIXGroupType(UDP_SERVICE);
obj_group->setName(
rule_iface->getLabel()+"."+rule->getUniqueId()+"."+name_suffix);
pix_comp->object_groups->add(obj_group);
pix_comp->cacheObj(obj_group);
for (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();
obj_group->addRef( obj );
}
}
re->clearChildren(false); // do not want to destroy children objects
re->addRef(obj_group);
assert(re->size()==1);
tmp_queue.push_back(rule);
return true;
}
void PolicyCompiler_pix::compile()
{
cout << " Compiling policy for " << fw->getName() << " ..." << endl << flush;
try
{
string vers = fw->getStr("version");
string platform = fw->getStr("platform");
bool outbound_acl_supported = Resources::platform_res[platform]->getResourceBool(
string("/FWBuilderResources/Target/options/")+
"version_"+vers+
"/pix_outbound_acl_supported");
bool generate_out_acl = fw->getOptionsObject()->getBool("pix_generate_out_acl");
if (outbound_acl_supported && !generate_out_acl)
{
// behave like if outbound acls are not supported but are emulated
outbound_acl_supported = false;
fw->getOptionsObject()->setBool("pix_emulate_out_acl", true);
}
Compiler::compile();
addDefaultPolicyRule();
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" ));
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 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 (" Start processing rules" ));
add( new printTotalNumberOfRules ( ));
add( new RejectAction ("check for action 'Reject'" ));
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 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 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"));
if ( fwopt->getBool("pix_assume_fw_part_of_any")) {
// add( new splitIfSrcAny( "split rule if src is any" ));
add( new splitIfDstAny( "split rule if dst is any" ));
}
add( new splitIfSrcMatchesFw ("split rule if Src matches FW" ));
add( new splitIfDstMatchesFw ("split rule if Dst matches FW" ));
// if ( !outbound_acl_supported )
// add( new fillDirection_v6 ("determine directions" ));
// if ( fwopt->getBool("pix_replace_natted_objects"))
// add( new replaceNATtedObjects ("replace objects in DST that are TDst in DNAT translations" ));
add( new telnetToFirewall(
"separate rules controlling telnet to firewall"));
add( new sshToFirewall("separate rules controlling ssh to firewall" ));
add( new splitServices("split rules with different protocols" ));
add( new PrepareForICMPCmd("prepare for icmp command" ));
add( new replaceFWinSRCInterfacePolicy(
"replace fw with its interface in SRC in interface policy rules"));
add( new replaceFWinDSTInterfacePolicy(
"replace fw with its interface in DST in interface policy rules"));
add( new ExpandMultipleAddressesInSRC(
"expand objects with multiple addresses in SRC" ));
add( new MACFiltering("check for MAC address filtering" ));
add( new splitByNetworkZonesForSrc(
"split rule if objects in Src belong to different network zones " ));
add( new replaceFWinDSTPolicy(
"replace fw with its interface in DST in global policy rules"));
add( new ExpandMultipleAddressesInDST(
"expand objects with multiple addresses in DST" ));
add( new MACFiltering("check for MAC address filtering" ));
add( new splitByNetworkZonesForDst(
"split rule if objects in Dst belong to different network zones " ));
add( new checkForUnnumbered( "check for unnumbered interfaces" ));
add( new addressRanges("process address ranges" ));
if (outbound_acl_supported )
{
add( new setInterfaceAndDirectionBySrc(
"Set interface and direction for rules with interface 'all' using SRC; v7"));
add( new setInterfaceAndDirectionByDst(
"Set interface and direction for rules with interface 'all' using DST; v7"));
add(new setInterfaceAndDirectionIfInterfaceSet(
"Set direction for rules with interface not 'all'; v7"));
} else
{
add( new SplitDirection_v6("split rules with direction 'both'" ));
// add( new assignRuleToInterface ("assign rules to interfaces" ));
add( new EmulateOutboundACL_v6("emulate outbound ACL" ));
add( new assignRuleToInterface_v6("assign rules to interfaces" ));
add( new InterfaceAndDirection_v6(
"check for combinations of interface and direction"));
}
add( new specialCaseWithDynInterface(
"check for a special cases with dynamic interface" ));
add( new SplitSRCForICMPCmd( "split SRC for icmp commands" ));
if ( fwopt->getBool("pix_replace_natted_objects"))
add( new replaceNATtedObjects(
"replace objects in DST that are TDst in DNAT translations"));
if (outbound_acl_supported )
// first arg is false because we are not using
// "ip access-list" for PIX.
add( new pickACL( false, "assign ACLs for v7" ));
else
add( new pickACL_v6( "assign ACLs for v6" ));
add( new SpecialServices( "check for special services" ));
add( new checkForZeroAddr( "check for zero addresses" ));
add( new checkVersionAndDynamicInterface(
"check for dynamic interfaces in policy rule and verify version of PIX OS"));
add( new splitIfTelnetSSHICMPtoFw(
"split rule if there are multiple objects in src and it controlls access to the firewall"));
/* remove redundant objects only after all splits has been
* done, right before object groups are created
*/
add( new removeRedundantAddressesFromSrc(
"remove redundant addresses from Src"));
add( new removeRedundantAddressesFromDst(
"remove redundant addresses from Dst"));
// add( new AvoidObjectGroup("avoid object groups for certain cases"));
add( new CreateObjectGroupsForSrc("create object groups for Src"));
add( new CreateObjectGroupsForDst("create object groups for Dst"));
add( new CreateObjectGroupsForSrv("create object groups for Srv"));
add( new simplePrintProgress());
add( new createNewCompilerPass("Creating object groups and ACLs ..."));
add( new PrintObjectGroupsAndClearCommands(
"Clear ACLs and generate code for object groups"));
add( new PrintRule("generate code for ACLs"));
add( new simplePrintProgress());
/*
if ( fw->getOptionsObject()->getBool("pix_check_rule_shadowing"))
{
add( new createNewCompilerPass (" Detecting rule shadowing ..." ));
add( new ExpandGroups ("expand groups" ));
add( new ConvertToAtomic ("convert to atomic rules" ));
add( new DetectShadowing ("Detect shadowing" ));
add( new simplePrintProgress ( ));
}
*/
runRuleProcessors();
} catch (FWException &ex) {
error(ex.toString());
exit(1);
}
}
string PolicyCompiler_pix::printAccessGroupCmd(ciscoACL *acl)
{
string dir;
if (acl->direction()=="in" || acl->direction()=="Inbound") dir="in";
if (acl->direction()=="out" || acl->direction()=="Outbound") dir="out";
return string("access-group ") + acl->workName() +
" " + dir +
" interface " + acl->getInterface()->getLabel() + "\n";
}
void PolicyCompiler_pix::epilog()
{
output << endl;
if (resetinbound) output << "service resetinbound" << endl;
output << endl;
if (fw->getStr("platform")=="fwsm" && fw->getOptionsObject()->getBool("pix_use_manual_commit"))
{
output << "access-list commit" << endl;
output << endl;
}
for (map<string,ciscoACL*>::iterator i=acls.begin(); i!=acls.end(); ++i)
{
ciscoACL *acl=(*i).second;
if (acl->size()!=0) output << printAccessGroupCmd(acl);
}
output << endl;
if ( fw->getOptionsObject()->getBool("pix_regroup_commands"))
{
cout << " Regrouping commands \n" << flush;
regroup();
}
}

View File

@ -0,0 +1,327 @@
/*
Firewall Builder
Copyright (C) 2002 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: PolicyCompiler_pix.h,v 1.1 2008/03/06 06:49:00 vkurland Exp $
This program is free software which we release under the GNU General Public
License. You may redistribute and/or modify this program under the terms
of that license as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
To get a copy of the GNU General Public License, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __POLICYCOMPILER_PIX_HH
#define __POLICYCOMPILER_PIX_HH
#include <fwbuilder/libfwbuilder-config.h>
#include "PIXObjectGroup.h"
#include "fwcompiler/PolicyCompiler.h"
#include "fwbuilder/RuleElement.h"
#include "Helper.h"
#include "ACL.h"
#include "PolicyCompiler_cisco.h"
namespace libfwbuilder {
class IPService;
class ICMPService;
class TCPService;
class UDPService;
class RuleElementSrc;
class RuleElementDst;
class RuleElementSrv;
class Group;
};
namespace fwcompiler {
class NATCompiler_pix;
class PolicyCompiler_pix : public PolicyCompiler_cisco {
protected:
/**
* dynamic interfaces can be used in policy rules only in v6.3 and later
*
*/
friend class checkVersionAndDynamicInterface;
class checkVersionAndDynamicInterface : public PolicyRuleProcessor
{
bool findDynamicInterface(libfwbuilder::PolicyRule *rule,
libfwbuilder::RuleElement *re);
public:
checkVersionAndDynamicInterface(const std::string &name) : PolicyRuleProcessor(name) {}
virtual bool processNext();
};
/*
*************************************************************************
*
* the following rule processors are intended for PIX < 7.0
* the code is in the module PolicyCompiler_pix_v6_acls.cpp
*
*************************************************************************
*/
/**
* verifies combination of interface and direction and
* fills interface and direction. After this predicate it
* is guaranteed that both interface and direction have
* some value. In certain situations interface ID may be
* set to "nil" though (e.g. global policy rules).
*/
DECLARE_POLICY_RULE_PROCESSOR( InterfaceAndDirection_v6 );
/**
* if interface has not been defined (this is global policy
* rule), then multiply the rule for each interface and set
* direction to "Inbound"
*/
DECLARE_POLICY_RULE_PROCESSOR( assignRuleToInterface_v6 );
/**
* split rules with direction "both".
* TODO: This is used in OpenBSD pf. Move to class PolicyCompiler
*/
DECLARE_POLICY_RULE_PROCESSOR( SplitDirection_v6 );
/**
* in PIX, ACLs are always applied on interface and direction
* can only be "inbound". We emulate outbound ACLs though.
*/
DECLARE_POLICY_RULE_PROCESSOR( EmulateOutboundACL_v6 );
/**
* determine acl rules should belong to
*/
DECLARE_POLICY_RULE_PROCESSOR( pickACL_v6 );
friend class PolicyCompiler_pix::pickACL_v6;
/*
*************************************************************************
*
* end of module PolicyCompiler_pix_v6_acls.cpp
*
*************************************************************************
*/
/*
*************************************************************************
*
* rule processors intended to manage ACLs for PIX < 7.0 are inherited
* from PolicyCompiler_cisco.
* The code is in the module PolicyCompiler_cisco_acls.cpp
*
* The processors assume that all objects in src and dst
* belong to the same network zone (respectively)
*
* All these rule processors assume outbound ACLs are supported.
* Check corresponding capability flag and do not include these
* processors in the processors chain in pix.cpp if outbound acls
* are not supported.
*
*************************************************************************
*/
/**
* this processor checks for the services which require
* special treatment. Some of these will be checking for
* source or destination object as well because special
* command may need to be generated in case source or
* destination is a firewall itself. Therefore this processor
* should be called after converting to atomic rules, but
* before interface addresses in source and destination are
* expanded.
*/
DECLARE_POLICY_RULE_PROCESSOR( SpecialServices );
friend class PolicyCompiler_pix::SpecialServices;
/**
* sets boolean flag icmp_cmd to be able to generate command
* "icmp" instead of "access-list" later. Call this processor
* after SplitServices and splitIfDstMatchesFw
*/
DECLARE_POLICY_RULE_PROCESSOR( PrepareForICMPCmd );
/**
* splits SRC if this is icmp_cmd rule
*/
DECLARE_POLICY_RULE_PROCESSOR( SplitSRCForICMPCmd );
/**
* to implement action "Reject" add command "service resetinbound"
*/
DECLARE_POLICY_RULE_PROCESSOR( RejectAction );
friend class PolicyCompiler_pix::RejectAction;
/**
* this processor replaces objects in dst for which we have
* DNAT rule in a NAT policy. Call _after_ telnetToFirewall,
* sshToFirewall and PrepareForICMPCmd
*/
class replaceNATtedObjects : public PolicyRuleProcessor
{
public:
replaceNATtedObjects(const std::string &n):PolicyRuleProcessor(n) {}
virtual bool processNext();
};
friend class PolicyCompiler_pix::replaceNATtedObjects;
/**
* can not use object-group in "icmp", "telnet" and "ssh" commands
*/
DECLARE_POLICY_RULE_PROCESSOR( splitIfTelnetSSHICMPtoFw );
/**
* this processor creates PIX-specific object groups
* (PIX CLI command "object-group") for rules with
* more than one object in src or dst or srv
*/
class CreateObjectGroups : public PolicyRuleProcessor
{
std::string re_type;
std::string name_suffix;
PIXGroup* findObjectGroup(libfwbuilder::RuleElement *re);
public:
CreateObjectGroups(const std::string &name,
const std::string &_ns,
const std::string &_type) :
PolicyRuleProcessor(name) {re_type=_type; name_suffix=_ns; }
virtual bool processNext();
};
friend class PolicyCompiler_pix::CreateObjectGroups;
class CreateObjectGroupsForSrc : public CreateObjectGroups
{
public:
CreateObjectGroupsForSrc(const std::string &n):
CreateObjectGroups(n,"src",libfwbuilder::RuleElementSrc::TYPENAME) {}
};
class CreateObjectGroupsForDst : public CreateObjectGroups
{
public:
CreateObjectGroupsForDst(const std::string &n):
CreateObjectGroups(n,"dst",libfwbuilder::RuleElementDst::TYPENAME) {}
};
class CreateObjectGroupsForSrv : public CreateObjectGroups
{
public:
CreateObjectGroupsForSrv(const std::string &n):
CreateObjectGroups(n,"srv",libfwbuilder::RuleElementSrv::TYPENAME) {}
};
/**
* this processor accumulates all rules fed to it by previous
* * processors, then prints PIX commands to clear
* access-lists, object groups, icmp, ssh, telnet and prints
* all object groups, then feeds all rules to the next
* processor. Usually this processor is in chain right
* before PrintRules.
*
* We use this processor to print "clear" commands because
* they need to be generated when all access lists have been
* created but before they are printed.
*/
class PrintObjectGroupsAndClearCommands : public PolicyRuleProcessor
{
public:
PrintObjectGroupsAndClearCommands(const std::string &n) : PolicyRuleProcessor(n) {}
virtual bool processNext();
};
friend class PolicyCompiler_pix::PrintObjectGroupsAndClearCommands;
class AvoidObjectGroup : public PolicyRuleProcessor
{
public:
AvoidObjectGroup(const std::string &n) : PolicyRuleProcessor(n) {}
virtual bool processNext();
};
friend class PolicyCompiler_pix::AvoidObjectGroup;
/**
* this processor prints single policy rule, assuming all
* groups have been expanded, so source, destination and
* service hold exactly one object each, and this object is
* not a group. Negation should also have been taken care of
* before this method is called.
*/
class PrintRule : public PolicyRuleProcessor
{
protected:
std::string current_rule_label1;
std::map<std::string,std::string> current_rule_label2;
std::list<std::string> seen_icmp_commands;
int aclLineCounter;
std::string _printSingleSSHTelnetCommand(int port,
libfwbuilder::Address *a,
const std::string &interfaceLabel);
std::string _printSrcService(libfwbuilder::Service *srv);
std::string _printDstService(libfwbuilder::Service *srv);
std::string _printAddr(libfwbuilder::Address *o);
std::string _printAction(libfwbuilder::PolicyRule *r);
std::string _printACL(libfwbuilder::PolicyRule *r);
std::string _printSSHTelnetCommand(libfwbuilder::PolicyRule *r);
std::string _printICMPCommand(libfwbuilder::PolicyRule *r);
std::string _printLog(libfwbuilder::PolicyRule *r);
bool suppressDuplicateICMPCommands(const std::string &cmd);
public:
PrintRule(const std::string &name) : PolicyRuleProcessor(name) { aclLineCounter=0; }
virtual bool processNext();
};
friend class PolicyCompiler_pix::PrintRule;
bool resetinbound;
bool fragguard;
// storage for object groups created to be used with PIX command object-group
libfwbuilder::Group *object_groups;
NATCompiler_pix *natcmp;
protected:
virtual std::string myPlatformName();
std::string printAccessGroupCmd(ciscoACL *acl);
public:
PolicyCompiler_pix(libfwbuilder::FWObjectDatabase *_db,
const std::string &fwname,
fwcompiler::OSConfigurator *_oscnf,
NATCompiler_pix *_natcmp);
virtual ~PolicyCompiler_pix() {}
virtual int prolog();
virtual void compile();
virtual void epilog();
};
}
#endif

View File

@ -0,0 +1,361 @@
/*
Firewall Builder
Copyright (C) 2002 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: PolicyCompiler_pix_v6_acls.cpp,v 1.1 2008/03/06 06:49:00 vkurland Exp $
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
Rule processors in this module build ACLs for PIX v6
they employ number of assumptions that are only valid for PIX <7.0
*/
#include "config.h"
#include "PolicyCompiler_pix.h"
#include "NATCompiler_pix.h"
#include "PIXObjectGroup.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/Network.h"
#include "fwbuilder/Policy.h"
#include "fwbuilder/Interface.h"
#include "fwbuilder/Management.h"
#include "fwbuilder/Resources.h"
#include "fwbuilder/AddressTable.h"
#include <iostream>
#if __GNUC__ > 3 || \
(__GNUC__ == 3 && (__GNUC_MINOR__ > 2 || (__GNUC_MINOR__ == 2 ) ) ) || \
_MSC_VER
# include <streambuf>
#else
# include <streambuf.h>
#endif
#include <iomanip>
#include <algorithm>
#include <functional>
#include <assert.h>
using namespace libfwbuilder;
using namespace fwcompiler;
using namespace std;
bool PolicyCompiler_pix::InterfaceAndDirection_v6::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
tmp_queue.push_back(rule);
bool icmp_cmd = rule->getBool("icmp_cmd");
bool ssh_telnet_cmd = rule->getBool("ssh_telnet_cmd");
string interface_id = rule->getInterfaceId();
if (rule->getDirection()==PolicyRule::Undefined)
rule->setDirection( PolicyRule::Both );
if (interface_id.empty() && rule->getDirection()==PolicyRule::Both)
return true;
if (interface_id.empty() && !icmp_cmd && !ssh_telnet_cmd && (
rule->getDirection()==PolicyRule::Inbound ||
rule->getDirection()==PolicyRule::Outbound)
) compiler->abort(string("Direction set without interface in rule ")+rule->getLabel());
return true;
}
/*
* rules with direction 'both' associated with an interface are split
* and copies are assigned directions Inbound and Outbound
*
* rules with direction 'both' not associated with any interface are
* simply converted to "Inbound". This is because we only generate
* outbound ACLs for rules that explicitly were defined by the user
* with direction "Outbound"; everything else is implemented using
* inbound ACLs
*
* 04/21/06 --vk
*/
bool PolicyCompiler_pix::SplitDirection_v6::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
Interface *rule_iface = compiler->getCachedFwInterface(rule->getInterfaceId());
if (rule->getDirection()==PolicyRule::Both)
{
if (rule_iface!=NULL)
{
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
{
rule->setDirection(PolicyRule::Inbound);
tmp_queue.push_back(rule);
}
} else
tmp_queue.push_back(rule);
return true;
}
/**
* this processor emulates outbound ACL by splitting a rule onto
* several rules and assigning them to interfaces. This processor
* works only with rules that have direction "Outbound" and have
* interface specified.
*
* Prerequisities:
*
* Rule should have been split before this processor is called if
* objects in src and/or dst belong to different network zones
*
*
* Internet ("any")
* ^
* |
* | i4
* +----------+
* i1| |i3
* ---------------+ PIX +----------------
* host1 | | host3
* +----------+
* |i2
* |
* |host2
*
* src dst interface
*
* h1 h2 i2 change interface to i1
* any h2 i2 split, use all interfaces but i2
* h1 any i2 change interface to i1
* any any i2 split, use all interfaces but i2
*
*
* FWSM v2.3 and beyond, as well as PIX 7.0, support outbound ACLs
* (via "access-group out ..." command) We do not need to do this
* for these platforms.
*/
bool PolicyCompiler_pix::EmulateOutboundACL_v6::processNext()
{
Helper helper(compiler);
PolicyRule *rule=getNext(); if (rule==NULL) return false;
Interface *rule_iface = compiler->getCachedFwInterface(rule->getInterfaceId());
if (rule->getDirection()==PolicyRule::Outbound && rule_iface!=NULL)
{
if ( compiler->fw->getOptionsObject()->getBool("pix_emulate_out_acl") )
{
RuleElementSrc *src=rule->getSrc(); assert(src);
RuleElementDst *dst=rule->getDst(); assert(dst);
try
{
if (!src->isAny())
{
string iface1_id=helper.findInterfaceByNetzone( compiler->getFirstSrc(rule) );
/* special case: interface detected via comparison of src and the
* network zone is the same as the one this rule is assigned to, but
* direction is Outbound - drop this rule
*/
if (iface1_id==rule->getInterfaceId())
{
return true;
}
rule->setInterfaceId(iface1_id);
rule->setDirection(PolicyRule::Inbound);
tmp_queue.push_back(rule);
} else
{
string iface2_id;
iface2_id=helper.findInterfaceByNetzone( compiler->getFirstDst(rule) );
list<FWObject*> l2=compiler->fw->getByType(Interface::TYPENAME);
for (list<FWObject*>::iterator i=l2.begin(); i!=l2.end(); ++i)
{
if ( (*i)->getId()==iface2_id ) continue;
PolicyRule *r= PolicyRule::cast(
compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
r->setInterfaceId((*i)->getId());
rule->setDirection(PolicyRule::Inbound);
tmp_queue.push_back(r);
}
}
} catch (string addr)
{
ostringstream str;
str << "Can not find interface to assign rule "
<< rule->getLabel()
<< ": " << endl
<< "Address " << addr
<< " does not match address or network zone of any interface"
<< endl;
compiler->abort(str.str());
}
} else
compiler->abort("Outbound ACLs are not supported and emulation is not activated: Rule "+rule->getLabel());
} else
tmp_queue.push_back(rule);
return true;
}
/**
* this processor assigns rules to interfaces (since PIX only
* supports ACLs on interfaces and direction can only be "inbound").
*
*
* Internet ("any")
* ^
* |
* | i4
* +----------+
* i1| |i3
* ---------------+ PIX +----------------
* host1 | | host3
* +----------+
* |i2
* |
* |host2
*
* src dst assign to interface
*
* any i1 i1
* any i2 i2
* any i3 i3
* any i4 i4
* any host2 all
* host1 host2 i1
* host1 any i1
* any any all
*/
bool PolicyCompiler_pix::assignRuleToInterface_v6::processNext()
{
PolicyRule *rule=getNext(); if (rule==NULL) return false;
Helper helper(compiler);
RuleElementSrc *src=rule->getSrc(); assert(src);
RuleElementDst *dst=rule->getDst(); assert(dst);
if (rule->getInterfaceId()=="")
{
try
{
if (! src->isAny() )
{
Address *a=compiler->getFirstSrc(rule);
string iface1_id=helper.findInterfaceByNetzone(a);
rule->setInterfaceId(iface1_id);
tmp_queue.push_back(rule);
} else {
Address *a=compiler->getFirstDst(rule);
if ( ! dst->isAny() && compiler->complexMatch(a,compiler->fw))
{
string iface2_id=helper.findInterfaceByNetzone( a );
rule->setInterfaceId(iface2_id);
rule->setStr("direction","Inbound");
tmp_queue.push_back(rule);
return true;
}
list<FWObject*> l2=compiler->fw->getByType(Interface::TYPENAME);
for (list<FWObject*>::iterator i=l2.begin(); i!=l2.end(); ++i)
{
PolicyRule *r= PolicyRule::cast(
compiler->dbcopy->create(PolicyRule::TYPENAME) );
compiler->temp_ruleset->add(r);
r->duplicate(rule);
r->setInterfaceId((*i)->getId());
r->setStr("direction","Inbound");
tmp_queue.push_back(r);
}
}
} catch (string addr)
{
ostringstream str;
str << "Can not find interface to assign rule "
<< rule->getLabel()
<< ": " << endl
<< "Address " << addr
<< " does not match address or network zone of any interface"
<< endl;
compiler->abort(str.str());
}
} else {
tmp_queue.push_back(rule);
}
return true;
}
/*
* This processor is called after emulateOutboundACL
*/
bool PolicyCompiler_pix::pickACL_v6::processNext()
{
PolicyCompiler_pix *pix_comp=dynamic_cast<PolicyCompiler_pix*>(compiler);
PolicyRule *rule=getNext(); if (rule==NULL) return false;
Interface *rule_iface = compiler->getCachedFwInterface(rule->getInterfaceId());
if(rule_iface==NULL)
{
compiler->abort("Missing interface assignment for rule "+rule->getLabel());
}
string acl_name= rule_iface->getLabel() + "_acl_in";
rule->setStr("acl",acl_name);
ciscoACL *acl = new ciscoACL(acl_name,rule_iface, "in");
pix_comp->acls[acl_name] = acl;
acl->setWorkName(acl_name);
tmp_queue.push_back(rule);
return true;
}

View File

@ -0,0 +1,688 @@
/*
Firewall Builder
Copyright (C) 2002 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: PolicyCompiler_pix_writers.cpp,v 1.1 2008/03/06 06:49:00 vkurland Exp $
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 "PolicyCompiler_pix.h"
#include "PIXObjectGroup.h"
#include "fwbuilder/Firewall.h"
#include "fwbuilder/AddressRange.h"
#include "fwbuilder/RuleElement.h"
#include "fwbuilder/IPService.h"
#include "fwbuilder/ICMPService.h"
#include "fwbuilder/TCPService.h"
#include "fwbuilder/UDPService.h"
#include "fwbuilder/CustomService.h"
#include "fwbuilder/Policy.h"
#include "fwbuilder/FWOptions.h"
#include "fwbuilder/FWObjectDatabase.h"
#include "fwbuilder/Interface.h"
#include "fwbuilder/IPv4.h"
#include "fwbuilder/Network.h"
#include "fwbuilder/Management.h"
#include "fwbuilder/Resources.h"
#include <iostream>
#if __GNUC__ > 3 || \
(__GNUC__ == 3 && (__GNUC_MINOR__ > 2 || (__GNUC_MINOR__ == 2 ) ) ) || \
_MSC_VER
# include <streambuf>
#else
# include <streambuf.h>
#endif
#include <iomanip>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <functional>
#include <assert.h>
using namespace libfwbuilder;
using namespace fwcompiler;
using namespace std;
bool PolicyCompiler_pix::PrintObjectGroupsAndClearCommands::processNext()
{
PolicyCompiler_pix *pix_comp=dynamic_cast<PolicyCompiler_pix*>(compiler);
string vers = compiler->fw->getStr("version");
string platform = compiler->fw->getStr("platform");
string clearACLcmd = Resources::platform_res[platform]->getResourceStr(
string("/FWBuilderResources/Target/options/")+
"version_"+vers+"/pix_commands/clear_acl");
string clearOGcmd = Resources::platform_res[platform]->getResourceStr(
string("/FWBuilderResources/Target/options/")+
"version_"+vers+"/pix_commands/clear_og");
string clearICMPcmd = Resources::platform_res[platform]->getResourceStr(
string("/FWBuilderResources/Target/options/")+
"version_"+vers+"/pix_commands/clear_icmp");
string clearTelnetcmd = Resources::platform_res[platform]->getResourceStr(
string("/FWBuilderResources/Target/options/")+
"version_"+vers+"/pix_commands/clear_telnet");
string clearSSHcmd = Resources::platform_res[platform]->getResourceStr(
string("/FWBuilderResources/Target/options/")+
"version_"+vers+"/pix_commands/clear_ssh");
slurp();
if (tmp_queue.size()==0) return false;
if ( compiler->fw->getOptionsObject()->getBool("pix_acl_basic") )
{
compiler->output << clearACLcmd << endl;
compiler->output << clearOGcmd << endl;
}
if (compiler->fw->getOptionsObject()->getBool("pix_acl_substitution"))
{
for (map<string,ciscoACL*>::iterator i=pix_comp->acls.begin();
i!=pix_comp->acls.end(); ++i)
{
ciscoACL *acl=(*i).second;
compiler->output << clearACLcmd << " " << acl->workName() << endl;
}
compiler->output << clearOGcmd << endl;
compiler->output << endl;
}
if ( !compiler->fw->getOptionsObject()->getBool("pix_acl_no_clear") )
{
compiler->output << clearICMPcmd << endl;
compiler->output << clearTelnetcmd << endl;
compiler->output << clearSSHcmd << endl;
}
for (FWObject::iterator i=pix_comp->object_groups->begin();
i!=pix_comp->object_groups->end(); ++i)
{
PIXGroup *og=dynamic_cast<PIXGroup*>(*i);
assert(og!=NULL);
if (og->size()==0) continue;
pix_comp->output << endl;
switch (og->getPIXGroupType())
{
case NETWORK:
pix_comp->output << "object-group network "
<< og->getName() << endl;
break;
case PROTO:
pix_comp->output << "object-group protocol "
<< og->getName() << endl;
break;
case ICMP_TYPE:
pix_comp->output << "object-group icmp-type "
<< og->getName() << endl;
break;
case TCP_SERVICE:
pix_comp->output << "object-group service "
<< og->getName() << " tcp" << endl;
break;
case UDP_SERVICE:
pix_comp->output << "object-group service "
<< og->getName() << " udp" << endl;
break;
default: compiler->abort("Unknown object group");
}
for (FWObject::iterator i1=og->begin(); i1!=og->end(); ++i1)
{
FWObject *o = *i1;
FWObject *obj = o;
if (FWReference::cast(o)!=NULL) obj=FWReference::cast(o)->getPointer();
switch (og->getPIXGroupType())
{
case NETWORK:
{
Address *a=Address::cast(obj);
assert(a!=NULL);
IPAddress addr=a->getAddress();
pix_comp->output << " network-object ";
if (Network::cast(obj)!=NULL) {
Netmask mask=a->getNetmask();
pix_comp->output << addr.toString() << " ";
pix_comp->output << mask.toString() << " ";
} else {
pix_comp->output << " host ";
pix_comp->output << addr.toString() << " ";
}
pix_comp->output << endl;
break;
}
case PROTO:
{
pix_comp->output << " protocol-object ";
Service *s=Service::cast(obj);
assert(s!=NULL);
pix_comp->output << s->getProtocolName();
pix_comp->output << endl;
break;
}
case ICMP_TYPE:
{
pix_comp->output << " icmp-object ";
ICMPService *s=ICMPService::cast(obj);
assert(s!=NULL);
if ( s->getInt("type")== -1)
pix_comp->output << "any";
else
pix_comp->output << s->getInt("type");
pix_comp->output << endl;
break;
}
case TCP_SERVICE:
case UDP_SERVICE:
{
pix_comp->output << " port-object ";
Service *s=Service::cast(obj);
assert(s!=NULL);
int rs=s->getInt("dst_range_start");
int re=s->getInt("dst_range_end");
if (rs<0) rs=0;
if (re<0) re=0;
if (rs>0 || re>0) {
if (rs==re) compiler->output << "eq " << rs;
else compiler->output << "range " << rs << " " << re;
}
else compiler->output << "range 0 65535";
pix_comp->output << endl;
break;
}
default:
compiler->abort("Unknown object group");
}
}
pix_comp->output << " exit" << endl << endl;
}
return true;
}
string PolicyCompiler_pix::PrintRule::_printAction(PolicyRule *rule)
{
ostringstream str;
switch (rule->getAction()) {
case PolicyRule::Accept: str << "permit "; break;
case PolicyRule::Deny: str << "deny "; break;
case PolicyRule::Reject: str << "deny "; break;
default: str << rule->getActionAsString() << " ";
}
return str.str();
}
string PolicyCompiler_pix::PrintRule::_printACL(PolicyRule *rule)
{
// PolicyCompiler_pix *pix_comp=dynamic_cast<PolicyCompiler_pix*>(compiler);
string acl_name=rule->getStr("acl");
assert (acl_name!="");
return acl_name+" ";
}
string PolicyCompiler_pix::PrintRule::_printLog(PolicyRule *rule)
{
string platform=compiler->fw->getStr("platform");
string vers=compiler->fw->getStr("version");
if (platform=="pix" && (vers=="6.1" || vers=="6.2")) return "";
// PolicyCompiler_pix *pix_comp=dynamic_cast<PolicyCompiler_pix*>(compiler);
FWOptions *ruleopt =rule->getOptionsObject();
ostringstream str;
if (ruleopt->getBool("disable_logging_for_this_rule"))
return "log disable ";
if (rule->getLogging())
{
string level=ruleopt->getStr("log_level");
int logint=ruleopt->getInt("log_interval");
/*
* PIX always adds logging interval in "show * access-list" command,
* so we should always add it, too. Otherwise ACL lines look
* different when diff is generated.
*/
if (logint<=0)
logint=Resources::platform_res[platform]->getResourceInt(
string("/FWBuilderResources/Target/options/")+
"version_"+compiler->fw->getStr("version")+
"/pix_default_logint");
if (level.empty()) level= compiler->fw->getOptionsObject()->getStr("pix_logging_trap_level");
if (!level.empty())
{
if (level=="alert") level="1";
if (level=="crit") level="2";
if (level=="error") level="3";
if (level=="warning") level="4";
if (level=="notice") level="5";
if (level=="info") level="6";
if (level=="debug") level="7";
str << "log " << level << " ";
if (logint>0 || platform=="pix") // can't use "interval 0" on fwsm
str << "interval " << logint << " ";
}
}
return str.str();
}
string PolicyCompiler_pix::PrintRule::_printSrcService(libfwbuilder::Service *srv)
{
ostringstream str;
if (TCPService::isA(srv) || UDPService::isA(srv))
{
int rs=srv->getInt("src_range_start");
int re=srv->getInt("src_range_end");
if (rs<0) rs=0;
if (re<0) re=0;
if (rs>0 || re>0) {
if (rs==re) str << "eq " << rs << " ";
else
if (rs==0 && re!=0) str << "lt " << re << " ";
else
if (rs!=0 && re==65535) str << "gt " << rs << " ";
else
str << "range " << rs << " " << re << " ";
}
}
return str.str();
}
string PolicyCompiler_pix::PrintRule::_printDstService(libfwbuilder::Service *srv)
{
ostringstream str;
if (TCPService::isA(srv) || UDPService::isA(srv)) {
int rs=srv->getInt("dst_range_start");
int re=srv->getInt("dst_range_end");
if (rs<0) rs=0;
if (re<0) re=0;
if (rs>0 || re>0) {
if (rs==re) str << "eq " << rs << " ";
else
if (rs==0 && re!=0) str << "lt " << re << " ";
else
if (rs!=0 && re==65535) str << "gt " << rs << " ";
else
str << "range " << rs << " " << re << " ";
}
}
if (ICMPService::isA(srv) && srv->getInt("type")!=-1)
str << srv->getStr("type") << " ";
return str.str();
}
string PolicyCompiler_pix::PrintRule::_printAddr(libfwbuilder::Address *o)
{
ostringstream str;
IPAddress srcaddr=o->getAddress();
Netmask srcmask=o->getNetmask();
if (Interface::cast(o)!=NULL)
{
Interface *interface_=Interface::cast(o);
if (interface_->isDyn())
{
return string("interface ") + interface_->getLabel() + " ";
}
srcmask=Netmask("255.255.255.255");
}
if (IPv4::cast(o)!=NULL)
srcmask=Netmask("255.255.255.255");
if (srcaddr.toString()=="0.0.0.0" && srcmask.toString()=="0.0.0.0")
{
str << "any ";
} else {
if (srcmask.toString()=="255.255.255.255")
{
str << "host " << srcaddr.toString() << " ";
} else
{
str << srcaddr.toString() << " ";
str << srcmask.toString() << " ";
}
}
return str.str();
}
bool PolicyCompiler_pix::PrintRule::suppressDuplicateICMPCommands(const string &cmd)
{
list<string>::iterator i;
i=std::find(seen_icmp_commands.begin(),seen_icmp_commands.end(),cmd);
if (i!=seen_icmp_commands.end()) return true;
seen_icmp_commands.push_back(cmd);
return false;
}
string PolicyCompiler_pix::PrintRule::_printICMPCommand(PolicyRule *rule)
{
ostringstream str;
Address *src =compiler->getFirstSrc(rule);
RuleElementSrv *srvrel=rule->getSrv();
FWObject *srv=srvrel->front();
if (FWReference::cast(srv)!=NULL) srv=FWReference::cast(srv)->getPointer();
Interface *rule_iface = compiler->getCachedFwInterface(rule->getInterfaceId());
assert(rule_iface);
if ( PIXGroup::cast(srv)!=NULL &&
PIXGroup::cast(srv)->getPIXGroupType()==ICMP_TYPE)
{
for (FWObject::iterator i1=srv->begin(); i1!=srv->end(); ++i1)
{
FWObject *o = *i1;
FWObject *obj = o;
if (FWReference::cast(o)!=NULL) obj=FWReference::cast(o)->getPointer();
ICMPService *s=ICMPService::cast(obj);
assert(s!=NULL);
ostringstream str1;
str1 << "icmp ";
str1 << _printAction(rule);
str1 << _printAddr( src );
str1 << s->getStr("type");
str1 << " ";
str1 << rule_iface->getLabel();
str1 << endl;
if ( ! suppressDuplicateICMPCommands(str1.str())) str << str1.str();
}
return str.str();
} else
{
str << "icmp ";
str << _printAction(rule);
str << _printAddr( src );
str << _printDstService( Service::cast(srv) );
str << " ";
str << rule_iface->getLabel();
str << endl;
if ( ! suppressDuplicateICMPCommands(str.str())) return str.str();
}
return "";
}
string PolicyCompiler_pix::PrintRule::_printSSHTelnetCommand(PolicyRule *rule)
{
// Helper helper(this);
ostringstream str;
int port;
RuleElementSrc *rel=rule->getSrc();
Service *srv=compiler->getFirstSrv(rule);
Interface *rule_iface = compiler->getCachedFwInterface(rule->getInterfaceId());
assert(rule_iface);
port=srv->getInt("dst_range_start");
for (FWObject::iterator i=rel->begin(); i!=rel->end(); ++i)
{
FWObject *o = *i;
if (FWReference::cast(o)!=NULL) o=FWReference::cast(o)->getPointer();
// Address *a;
if (dynamic_cast<PIXGroup*>(o)!=NULL)
{
for (FWObject::iterator j=o->begin(); j!=o->end(); ++j)
{
FWObject *o1 = *j;
if (FWReference::cast(o1)!=NULL)
o1=FWReference::cast(o1)->getPointer();
Address *a=Address::cast(o1);
assert(a!=NULL);
str << _printSingleSSHTelnetCommand(port,a,rule_iface->getLabel());
}
} else
{
Address *a=Address::cast(o);
assert(a!=NULL);
str << _printSingleSSHTelnetCommand(port,a,rule_iface->getLabel());
}
}
return str.str();
}
string PolicyCompiler_pix::PrintRule::_printSingleSSHTelnetCommand(int port,
Address *a,
const string &interfaceLabel)
{
string res;
if (port==23)
{
res += "telnet ";
res += a->getAddress().toString() + " "
+ a->getNetmask().toString() + " "
+ interfaceLabel + "\n";
}
if (port==22)
{
res += "ssh ";
res += a->getAddress().toString() + " "
+ a->getNetmask().toString() + " "
+ interfaceLabel + "\n";
}
return res;
}
/*
* the following additional attributes should have been defined by now:
*
* "acl" - string, name of the access list
* choices are: outside-in, outside-out, inside-in, indside-out,
* dmz-in, dmz-out etc.
* General rule for the acl name: "iface_name-{in,out}"
*/
bool PolicyCompiler_pix::PrintRule::processNext()
{
PolicyCompiler_pix *pix_comp=dynamic_cast<PolicyCompiler_pix*>(compiler);
PolicyRule *rule=getNext(); if (rule==NULL) return false;
// FWOptions *ruleopt =rule->getOptionsObject();
bool write_comments= compiler->fw->getOptionsObject()->getBool("pix_include_comments");
tmp_queue.push_back(rule);
ostringstream comment;
string rl=rule->getLabel();
if (write_comments)
{
if (rl!=current_rule_label1)
{
comment << "! " << endl;
comment << "! Rule " << rl << endl;
string comm=rule->getComment();
string::size_type c1,c2;
c1=0;
while ( (c2=comm.find('\n',c1))!=string::npos ) {
comment << "! " << comm.substr(c1,c2-c1) << endl;
c1=c2+1;
}
comment << "! " << comm.substr(c1) << endl;
comment << "! " << endl;
current_rule_label1=rl;
}
}
compiler->output << comment.str();
if (rule->getBool("icmp_cmd"))
{
compiler->output << _printICMPCommand(rule);
// need to generate access list command as well as icmp command
// in order to properly serve icmp through nat
// 04/21/06 --vk
// return true;
}
if (rule->getBool("ssh_telnet_cmd"))
{
compiler->output << _printSSHTelnetCommand(rule);
return true;
}
/*
* all three rule elements contain exactly one object, which can
* be either group (in case processor CreateObjectGroups created
* object group for it) or a regular object
*/
RuleElementSrc *src=rule->getSrc();
RuleElementDst *dst=rule->getDst();
RuleElementSrv *srv=rule->getSrv();
assert(src->size()==1);
assert(dst->size()==1);
assert(srv->size()==1);
FWObject *srcobj=src->front();
FWObject *dstobj=dst->front();
FWObject *srvobj=srv->front();
assert(srcobj);
assert(dstobj);
assert(srvobj);
if (FWReference::cast(srcobj)!=NULL)
{
srcobj=FWReference::cast(srcobj)->getPointer();
assert(srcobj);
}
if (FWReference::cast(dstobj)!=NULL)
{
dstobj=FWReference::cast(dstobj)->getPointer();
assert(dstobj);
}
if (FWReference::cast(srvobj)!=NULL)
{
srvobj=FWReference::cast(srvobj)->getPointer();
assert(srvobj);
}
ostringstream aclstr;
string acl_name=rule->getStr("acl");
assert (acl_name!="");
ciscoACL *acl = pix_comp->acls[acl_name];
assert(acl!=NULL);
if (compiler->fw->getOptionsObject()->getBool("pix_use_acl_remarks"))
{
compiler->output << acl->addRemark( rule->getLabel() );
}
/*
* Assemble ACL command in aclstr
*/
aclstr << _printAction(rule);
/*
* processor splitServices guaranties that rule has services of
* the same type (that is, the same protocol, like all tcp, all
* udp, all icmp or all IP with the same protocol number). PIX can
* use object-group for protocol only if protocol numbers are
* different and these are not icmp/tcp/udp protocols. This means
* that because of processor splitServices we never use
* object-group in protocol part of ACL.
*/
PIXGroup *pgsrv = PIXGroup::cast(srvobj);
PIXGroup *pgsrc = PIXGroup::cast(srcobj);
PIXGroup *pgdst = PIXGroup::cast(dstobj);
if ( pgsrv!=NULL && pgsrv->isServiceGroup())
aclstr << pgsrv->getSrvTypeName();
else
aclstr << Service::cast(srvobj)->getProtocolName();
aclstr << " ";
if ( pgsrc!=NULL && pgsrc->isObjectGroup())
{
aclstr << "object-group " << srcobj->getName();
aclstr << " ";
} else
{
aclstr << _printAddr( compiler->getFirstSrc(rule) );
}
if ( pgsrv==NULL )
aclstr << _printSrcService( compiler->getFirstSrv(rule) );
if ( pgdst!=NULL && pgdst->isObjectGroup())
{
aclstr << "object-group " << dstobj->getName();
aclstr << " ";
} else
aclstr << _printAddr( compiler->getFirstDst(rule) );
if ( pgsrv!=NULL )
{
aclstr << "object-group " << srvobj->getName();
aclstr << " ";
} else
aclstr << _printDstService( compiler->getFirstSrv(rule) );
aclstr << _printLog( rule );
// aclstr << endl;
compiler->output << acl->addLine(aclstr.str());
return true;
}

75
src/pix/globalNATPool.cpp Normal file
View File

@ -0,0 +1,75 @@
/*
Firewall Builder
Copyright (C) 2002 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: globalNATPool.cpp,v 1.1 2008/03/06 06:49:02 vkurland Exp $
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_pix.h"
#include "helpers.h"
#include "fwbuilder/AddressRange.h"
#include "fwbuilder/Interface.h"
using namespace libfwbuilder;
using namespace fwcompiler;
globalNATPool::globalNATPool(int id,Interface *ifs,Address *a)
{
nat_id=id;
iface=ifs;
addr= a;
if (Interface::cast(a)!=NULL || iface->isDyn()) {
type=INTERFACE;
} else {
type= (AddressRange::cast(a)!=NULL)?ADDRESS_RANGE:SINGLE_ADDRESS;
}
}
/*
* global pool prints itself only once
*/
ostream& fwcompiler::operator<<(ostream &s,const globalNATPool &pool)
{
s << "global (" << pool.iface->getLabel() << ") " << pool.pool_no;
switch (pool.type) {
case globalNATPool::INTERFACE:
s << " interface" << endl;
break;
case globalNATPool::SINGLE_ADDRESS:
s << " " << pool.addr->getAddress().toString() << endl;
break;
case globalNATPool::ADDRESS_RANGE:
AddressRange *ar=AddressRange::cast(pool.addr);
s << " "
<< ar->getRangeStart().toString()
<< "-"
<< ar->getRangeEnd().toString()
<< " netmask "
<< pool.iface->getNetmask().toString()
<< endl;
break;
}
return s;
}

643
src/pix/pix.cpp Normal file
View File

@ -0,0 +1,643 @@
/*
Firewall Builder
Copyright (C) 2002 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id: pix.cpp,v 1.2 2008/03/09 05:13:55 vkurland Exp $
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 <qsettings.h>
#include <fstream>
#include <iostream>
#include <sstream>
#include <map>
#include <algorithm>
#include <functional>
#ifdef _WIN32
# include <direct.h>
#else
# include <unistd.h>
#endif
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>
#include <assert.h>
#include "PolicyCompiler_pix.h"
#include "NATCompiler_pix.h"
#include "OSConfigurator_pix_os.h"
#include "fwcompiler/Preprocessor.h"
#include "fwbuilder/Resources.h"
#include "fwbuilder/FWObjectDatabase.h"
#include "fwbuilder/Firewall.h"
#include "fwbuilder/Interface.h"
#include "fwbuilder/IPv4.h"
#include "fwbuilder/XMLTools.h"
#include "fwbuilder/FWException.h"
#include "fwbuilder/Tools.h"
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#else
#ifdef _WIN32
#include <getopt.h>
#else
#include <stdlib.h>
#endif
#endif
#include "../common/init.cpp"
using namespace std;
using namespace libfwbuilder;
using namespace fwcompiler;
static const char *filename = NULL;
static const char *wdir = NULL;
static const char *fwobjectname = NULL;
static string ofname = "";
static int dl = 0;
static int drp = -1;
static int drn = -1;
static int verbose = 0;
static int test_mode = 0;
static int only_print_inspection_code = 0;
FWObjectDatabase *objdb = NULL;
class UpgradePredicate: public XMLTools::UpgradePredicate
{
public:
virtual bool operator()(const string &msg) const
{
msg.size(); // to make compiler happy about unused parameter
cout << "Data file has been created in the old version of Firewall Builder.\nLoad it in the GUI to convert it to the new version." << endl;
return false;
}
};
class sort_by_net_zone {
public:
// explicit sort_by_net_zone();
bool operator()(const FWObject *a, const FWObject *b) {
if (Interface::constcast(a) && Interface::constcast(b)) {
string netzone_a=a->getStr("network_zone");
string netzone_b=b->getStr("network_zone");
if ( netzone_a==FWObjectDatabase::getAnyNetworkId()) return false;
if ( netzone_b==FWObjectDatabase::getAnyNetworkId()) return true;
}
return false;
}
};
void usage(const char *name)
{
cout << "Firewall Builder: policy compiler for Cisco PIX firewall (with support for FWSM)" << endl;
cout << "Copyright 2002-2004 NetCitadel, LLC" << endl;
cout << "Version " << VERSION << "-" << RELEASE_NUM << endl;
cout << "Usage: " << name << " [-tvV] [-f filename.xml] [-d destdir] [-o output.fw] firewall_object_name" << endl;
}
int main(int argc, char * const * argv)
{
if (argc<=1)
{
usage(argv0.c_str());
exit(1);
}
int opt;
while( (opt=getopt(argc,argv,"x:vVf:d:r:tLo:i")) != EOF )
{
switch(opt)
{
case 'i':
only_print_inspection_code++;
break;
case 'd':
wdir = strdup(optarg);
break;
case 'r':
respath = string(optarg);
break;
case 'f':
filename = strdup(optarg);
break;
case 'o':
ofname = string(optarg);
break;
case 'x':
if (*optarg=='p') {
++optarg;
drp = atoi(optarg);
} else {
if (*optarg=='n') {
++optarg;
drn = atoi(optarg);
} else {
if (isdigit(*optarg)) dl=atoi(optarg); // increase debug level
else {
usage(argv[0]);
exit(1);
}
}
}
break;
case 't':
test_mode++;
break;
case 'v':
verbose++;
break;
case 'V':
usage(argv[0]);
exit(1);
case 'h':
usage(argv[0]);
exit(1);
}
}
/* can use init and init2 only after command line option "-r" has been read */
init(argv);
if((argc-1) != optind)
{
usage(argv[0]);
exit(1);
}
fwobjectname = strdup( argv[optind++] );
if (ofname.empty())
{
ofname=string(fwobjectname)+".fw";
}
if (filename==NULL || fwobjectname==NULL)
{
usage(argv[0]);
exit(1);
}
if (wdir==0) wdir="./";
if (
#ifdef _WIN32
_chdir(wdir)
#else
chdir(wdir)
#endif
) {
cerr << "Can't change working directory to: " << wdir << endl;
exit(1);
}
if (test_mode)
cout << "*** Running in test mode, all errors are ignored" << endl << endl;
try
{
new Resources(respath+FS_SEPARATOR+"resources.xml");
/* create database */
objdb = new FWObjectDatabase();
/* load the data file */
UpgradePredicate upgrade_predicate;
if (verbose) cout << " *** Loading data ...";
#if 0
objdb->setReadOnly( false );
objdb->load( sysfname, &upgrade_predicate, librespath);
objdb->setFileName("");
FWObjectDatabase *ndb = new FWObjectDatabase();
ndb->load(filename, &upgrade_predicate, librespath);
objdb->merge(ndb, NULL);
delete ndb;
objdb->setFileName(filename);
#endif
objdb->setReadOnly( false );
objdb->load( filename, &upgrade_predicate, librespath);
objdb->setFileName(filename);
objdb->reIndex();
if (verbose) cout << " done\n";
/* why do I do this ?
FWObject *slib = objdb->findInIndex("syslib000");
if ( slib->isReadOnly()) slib->setReadOnly(false);
*/
/*
* some general sanity checks first
*/
Firewall* fw=objdb->findFirewallByName(fwobjectname);
FWOptions* options=fw->getOptionsObject();
bool pix_acl_basic=options->getBool("pix_acl_basic");
bool pix_acl_no_clear=options->getBool("pix_acl_no_clear");
bool pix_acl_substitution=options->getBool("pix_acl_substitution");
bool pix_add_clear_statements=options->getBool("pix_add_clear_statements");
if ( !pix_acl_basic &&
!pix_acl_no_clear &&
!pix_acl_substitution )
{
if ( pix_add_clear_statements ) options->setBool("pix_acl_basic",true);
else options->setBool("pix_acl_no_clear",true);
}
if (only_print_inspection_code)
{
OSConfigurator_pix_os *oscnf=NULL;
oscnf=new OSConfigurator_pix_os(objdb , fwobjectname);
oscnf->prolog();
cout << oscnf->getProtocolInspectionCommands();
return 0;
}
Helper helper(NULL);
multimap<string, FWObject*> netzone_objects;
std::list<FWObject*> l2=fw->getByType(Interface::TYPENAME);
for (std::list<FWObject*>::iterator i=l2.begin(); i!=l2.end(); ++i)
{
Interface *iface=dynamic_cast<Interface*>(*i);
assert(iface);
/*
* missing labels on interfaces
*/
if (iface->getLabel()=="")
{
string lbl;
if (iface->getSecurityLevel()==0) lbl="outside";
else
{
if (iface->getSecurityLevel()==100) lbl="inside";
else
{
char s[64];
sprintf(s,"dmz%d",iface->getSecurityLevel());
lbl=s;
}
}
iface->setLabel(lbl);
}
if ( iface->isDyn())
{
list<FWObject*> l3=iface->getByType(IPv4::TYPENAME);
if (l3.size()>0)
{
char errstr[256];
for (list<FWObject*>::iterator j=l3.begin(); j!=l3.end(); ++j)
if ( objdb->findAllReferences(*j).size()!=0 )
{
sprintf(errstr,
_("Dynamic interface %s has an IP address that is used in the firewall policy rule.\n"),
iface->getName().c_str() );
throw FWException(errstr);
}
sprintf(errstr,
_("Dynamic interface %s should not have an IP address object attached to it. This IP address object will be ignored.\n"),
iface->getName().c_str() );
cerr << errstr;
for (list<FWObject*>::iterator j=l3.begin(); j!=l3.end(); ++j)
iface->remove(*j);
}
}
/*
* no address
*/
if (iface->isRegular())
{
FWObject *ipv4=iface->getFirstByType(IPv4::TYPENAME);
if (ipv4==NULL)
throw FWException(
"Interface "+
iface->getName()+" ("+iface->getLabel()+") has no address." );
}
/*
* there shouldn't be two interfaces with the same security level
*/
for (std::list<FWObject*>::iterator j=l2.begin(); j!=l2.end(); ++j)
{
Interface *iface2=dynamic_cast<Interface*>(*j);
assert(iface2);
if (iface->getId()==iface2->getId()) continue;
if (iface->getSecurityLevel()==iface2->getSecurityLevel())
throw FWException(
"Security level of each interface should be unique, however interfaces "+
iface->getName()+" ("+iface->getLabel()+")"+
" and "+
iface2->getName()+" ("+iface2->getLabel()+")"+
" have the same security level."
);
}
/*
* in PIX, we need network zones to be defined for all interfaces
*/
string netzone_id=iface->getStr("network_zone");
if (netzone_id=="") {
throw FWException(
"Network zone definition is missing for interface "
+iface->getName()+" ("+iface->getLabel()+")");
}
FWObject *netzone=objdb->findInIndex(netzone_id);
if (netzone==NULL)
{
throw FWException(
"Network zone points at nonexisting object for interface "
+iface->getName()+" ("+iface->getLabel()+")");
}
/*
* netzone may be a group, in which case we need to expand it
* (recursively).
*
* 1. We create new temporary object (type Group).
*
* 2. put it in the database somewhere
*
* 3. add all objects that belong to the network zone to this
* group. We add objects directly, not as a reference.
*
* 4. finally replace reference to the old network zone object in the
* interface with reference to this new group.
*
* 5. we store ID of the original network zone object
* using iface->setStr("orig_netzone_id")
*
* This ensures netzones do not contain other groups and do not
* require any recursive expanding anymore. Since objects were added
* to netzones directly, we do not need to bother with dereferencing,
* too.
*/
list<FWObject*> ol;
helper.expand_group_recursive_no_cache(netzone,ol);
FWObject *nz=objdb->create(ObjectGroup::TYPENAME);
assert(nz!=NULL);
nz->setName("netzone_"+iface->getLabel());
objdb->add(nz);
for (list<FWObject*>::iterator j=ol.begin(); j!=ol.end(); ++j)
{
netzone_objects.insert( pair<string,FWObject*>(iface->getLabel(),*j));
nz->add(*j);
}
iface->setStr("orig_netzone_id", netzone_id );
iface->setStr("network_zone", nz->getId() );
}
/*
* the same object (network or host) can not belong to network zones
* of two different interfaces. Map netzone_objects holds pairs
* interface_id/object. We just make sure the same object does not
* appear in two pairs with different interfaces.
*/
multimap<string,FWObject*>::iterator k;
for (k=netzone_objects.begin(); k!=netzone_objects.end(); ++k)
{
multimap<string,FWObject*>::iterator l;
l=k;
++l;
for ( ; l!=netzone_objects.end(); ++l)
{
if ( l->second->getId() == k->second->getId() )
{
if (k->first==l->first)
throw FWException(
"Object "+l->second->getName()
+" is used more than once in network zone of interface '"
+k->first+"'");
else
throw FWException(
"Object "+l->second->getName()
+" is used more than once in network zones of the following interfaces: '"
+k->first+"' and '"+l->first+"'");
}
}
}
/*
* now sort interfaces by their network zone "width" (that is, more narrow
* network zone should go first, interface with network zone "any" should be
* the last)
*
std::sort(fw->begin(), fw->end(), sort_by_net_zone() );
*/
char timestr[256];
time_t tm;
tm=time(NULL);
strcpy(timestr,ctime(&tm));
timestr[ strlen(timestr)-1 ]='\0';
#ifdef _WIN32
char* user_name=getenv("USERNAME");
#else
char* user_name=getenv("USER");
#endif
if (user_name==NULL)
throw FWException("Can't figure out your user name, aborting");
Preprocessor* prep=new Preprocessor(objdb , fwobjectname);
prep->compile();
/*
* Process firewall options, build OS network configuration script
*/
OSConfigurator *oscnf=NULL;
oscnf=new OSConfigurator_pix_os(objdb , fwobjectname);
oscnf->prolog();
oscnf->processFirewallOptions();
/* create compilers and run the whole thing */
NATCompiler_pix *n=new NATCompiler_pix( objdb ,
fwobjectname, oscnf );
if (test_mode) n->setTestMode();
n->setDebugLevel( dl );
n->setDebugRule( drn );
n->setVerbose( verbose );
if ( n->prolog() > 0 ) {
n->compile();
n->epilog();
} else
cout << " Nothing to compile in NAT \n" << flush;
PolicyCompiler_pix *c=new PolicyCompiler_pix( objdb ,
fwobjectname ,
oscnf , n);
if (test_mode) c->setTestMode();
c->setDebugLevel( dl );
c->setDebugRule( drp );
c->setVerbose( verbose );
if ( c->prolog() > 0 ) {
c->compile();
c->epilog();
} else
cout << " Nothing to compile in Policy \n" << flush;
#ifdef _WIN32
ofstream ofile(ofname.c_str(), ios::out|ios::binary);
#else
ofstream ofile(ofname.c_str());
#endif
ofile << "!\n\
! This is automatically generated file. DO NOT MODIFY !\n\
!\n\
! Firewall Builder fwb_pix v" << VERSION << "-" << RELEASE_NUM << " \n\
!\n\
! Generated " << timestr
<< " "
<< tzname[0]
<< " by "
<< user_name;
ofile << endl;
string vers = fw->getStr("version");
string platform = fw->getStr("platform");
bool outbound_acl_supported = Resources::platform_res[platform]->getResourceBool(
string("/FWBuilderResources/Target/options/")+
"version_"+vers+
"/pix_outbound_acl_supported");
bool afpa = options->getBool("pix_assume_fw_part_of_any");
bool emulate_outb_acls = options->getBool("pix_emulate_out_acl");
bool generate_outb_acls = options->getBool("pix_generate_out_acl");
ofile << "!" << endl;
ofile << "!"
<< " Compiled for " << platform << " " << vers << endl;
ofile << "!"
<< " Outbound ACLs " << string((outbound_acl_supported)?"supported":"not supported")
<< endl;
if (!outbound_acl_supported)
{
ofile << "!"
<< " Emulate outbound ACLs: " << string((emulate_outb_acls)?"yes":"no")
<< endl;
}
ofile << "!"
<< " Generating outbound ACLs: " << string((generate_outb_acls)?"yes":"no")
<< endl;
ofile << "!"
<< " Assume firewall is part of 'any': " << string((afpa)?"yes":"no")
<< endl;
ofile << "!" << endl;
ofile << "!" << MANIFEST_MARKER << "* " << ofname << endl;
ofile << "!" << endl;
ofile << endl;
ofile << "!" << endl;
ofile << "! Prolog script:" << endl;
ofile << "!" << endl;
string pre_hook= fw->getOptionsObject()->getStr("pix_prolog_script");
ofile << pre_hook << endl;
ofile << "!" << endl;
ofile << "! End of prolog script:" << endl;
ofile << "!" << endl;
ofile << oscnf->getCompiledScript();
ofile << endl;
ofile << c->getCompiledScript();
ofile << endl;
ofile << n->getCompiledScript();
ofile << endl;
ofile << "!" << endl;
ofile << "! Epilog script:" << endl;
ofile << "!" << endl;
string post_hook= fw->getOptionsObject()->getStr("pix_epilog_script");
ofile << post_hook << endl;
ofile << endl;
ofile << "! End of epilog script:" << endl;
ofile << "!" << endl;
ofile.close();
cout << _(" Compiled successfully") << endl << flush;
} catch(libfwbuilder::FWException &ex) {
cerr << ex.toString() << endl;
return 1;
} catch (std::string s) {
cerr << s << endl;
return 1;
// } catch (std::exception ex) {
// cerr << "exception: " << ex.what() << endl;
// return 1;
// } catch (...) {
// cerr << "Unsupported exception";
// return 1;
}
return 0;
}

43
src/pix/pix.pro Normal file
View File

@ -0,0 +1,43 @@
#-*- mode: makefile; tab-width: 4; -*-
#
include(../../qmake.inc)
#
#
# PACKAGE = fwbuilder-pix-$$FWB_VERSION
#
# QMAKE_CXXFLAGS_DEBUG += -DPACKAGE="\"$$PACKAGE\""
# QMAKE_CXXFLAGS_RELEASE += -DPACKAGE="\"$$PACKAGE\""
SOURCES = NATCompiler_pix.cpp \
NATCompiler_pix_writers.cpp \
OSConfigurator_pix_os.cpp \
OSConfigurator_pix_os_fixups.cpp \
pix.cpp \
PIXObjectGroup.cpp \
PolicyCompiler_pix.cpp \
PolicyCompiler_pix_writers.cpp \
PolicyCompiler_pix_v6_acls.cpp
HEADERS = ../../config.h \
NATCompiler_pix.h \
OSConfigurator_pix_os.h \
PIXObjectGroup.h \
PolicyCompiler_pix.h \
../cisco_lib/PolicyCompiler_cisco.h \
../cisco_lib/ACL.h \
../cisco_lib/Helper.h
# CONFIG -= qt
QMAKE_COPY = /usr/bin/install -m 0755 -s
win32:CONFIG += console
INCLUDEPATH += ../cisco_lib/
win32:LIBS += $$PREFIX/fwbcisco.lib
!win32:LIBS += ../cisco_lib/libfwbcisco.a
LIBS += $$LIBS_FWCOMPILER
TARGET = fwb_pix

View File

@ -18,5 +18,5 @@ contains( HAVE_ANTLR_RUNTIME, 1 ) {
}
}
SUBDIRS += gui ipt pflib pf ipf ipfw
SUBDIRS += gui ipt pflib pf ipf ipfw cisco_lib iosacl pix

View File

@ -0,0 +1,14 @@
# this is a comment
#
; this should be a comment too
;
192.168.1.1
192.168.1.2/32
192.168.1.3/30
192.168.2.128/25
192.168.1.200/32 # comment again
192.168.1.201/32 # this should work, too

View File

@ -0,0 +1,57 @@
#
# use this table to test run-time AddressTable object
# (this is just a small collection of addresses that sent spam to me
# on Nov 20 2005)
#
151.8.224.178 # this is also a comment
168.156.76.20
193.207.126.36
195.136.186.35
196.15.136.15
201.10.180.138
201.17.93.16
201.36.156.121
202.103.25.253
202.96.112.93
203.162.3.209
203.209.124.144
210.106.193.237
210.222.114.102
211.144.143.143
211.172.218.237
211.250.16.132
212.100.212.100
212.21.241.31
218.104.138.146
218.18.72.252
218.39.114.122
218.55.115.43
219.132.104.160
220.71.17.86
220.81.50.105
220.91.99.46
221.14.249.242
221.166.177.135
221.198.33.38
221.202.160.233
221.205.54.125
221.217.44.248
222.100.212.223
222.121.118.144
222.174.113.2
58.231.13.78
58.33.181.83
58.53.82.190
61.150.47.112
61.184.14.102
64.106.85.186
70.228.60.100
80.243.72.149
80.249.77.34
80.51.236.6
81.196.74.125
81.2.36.254
82.117.221.205
82.143.196.17
82.77.37.174
84.90.8.198

15
test/iosacl/do-diff Executable file
View File

@ -0,0 +1,15 @@
#!/bin/sh
N=$1
if which opendiff > /dev/null; then
TOOL="opendiff"
elif which tkdiff > /dev/null; then
TOOL="tkdiff "
else
TOOL="diff -u -b -B"
fi
$TOOL firewall${N}.fw.orig firewall${N}.fw

2206
test/iosacl/objects.fwb Normal file

File diff suppressed because it is too large Load Diff

15
test/iosacl/quick-cmp.sh Executable file
View File

@ -0,0 +1,15 @@
#!/usr/bin/perl
$XMLFILE=@ARGV[0];
$DIFFCMD="diff -U 0 -u -b -B -I \"! Generated\" ";
while (<>) {
$str=$_;
while ( $str=~ /<Firewall / ) {
$str=~ /<Firewall [^>]+name="([^"]*).*$"/;
$fw=$1;
printf "$DIFFCMD %s.fw.orig %s.fw\n",$fw,$fw;
$str=~ s/^.*<Firewall [^>]+name="$fw"[^>]+>//;
}
}

8
test/iosacl/recycle Executable file
View File

@ -0,0 +1,8 @@
#!/bin/sh
for f in *.fw; do
j=${f}.orig
mv $f $j
done

17
test/iosacl/run.all Executable file
View File

@ -0,0 +1,17 @@
#!/usr/bin/perl
$XMLFILE=@ARGV[0];
while (<>) {
$str=$_;
while ( $str=~ /<Firewall / ) {
$str=~ /<Firewall [^>]+name="([^"]*).*$"/;
$fw=$1;
printf "echo ====================== $fw =========================================\n";
printf "fwb_iosacl -v -f $XMLFILE $fw\n";
$str=~ s/^.*<Firewall [^>]+name="$fw"[^>]+>//;
}
}

14
test/pix/addr-table-1.tbl Normal file
View File

@ -0,0 +1,14 @@
# this is a comment
#
; this should be a comment too
;
192.168.1.1
192.168.1.2/32
192.168.1.3/30
192.168.2.128/25
192.168.1.200/32 # comment again
192.168.1.201/32 # this should work, too

57
test/pix/block-hosts.tbl Normal file
View File

@ -0,0 +1,57 @@
#
# use this table to test run-time AddressTable object
# (this is just a small collection of addresses that sent spam to me
# on Nov 20 2005)
#
151.8.224.178 # this is also a comment
168.156.76.20
193.207.126.36
195.136.186.35
196.15.136.15
201.10.180.138
201.17.93.16
201.36.156.121
202.103.25.253
202.96.112.93
203.162.3.209
203.209.124.144
210.106.193.237
210.222.114.102
211.144.143.143
211.172.218.237
211.250.16.132
212.100.212.100
212.21.241.31
218.104.138.146
218.18.72.252
218.39.114.122
218.55.115.43
219.132.104.160
220.71.17.86
220.81.50.105
220.91.99.46
221.14.249.242
221.166.177.135
221.198.33.38
221.202.160.233
221.205.54.125
221.217.44.248
222.100.212.223
222.121.118.144
222.174.113.2
58.231.13.78
58.33.181.83
58.53.82.190
61.150.47.112
61.184.14.102
64.106.85.186
70.228.60.100
80.243.72.149
80.249.77.34
80.51.236.6
81.196.74.125
81.2.36.254
82.117.221.205
82.143.196.17
82.77.37.174
84.90.8.198

15
test/pix/do-diff Executable file
View File

@ -0,0 +1,15 @@
#!/bin/sh
N=$1
if which opendiff > /dev/null; then
TOOL="opendiff"
elif which tkdiff > /dev/null; then
TOOL="tkdiff "
else
TOOL="diff -u -b -B"
fi
$TOOL firewall${N}.fw.orig firewall${N}.fw

14347
test/pix/objects.fwb Normal file

File diff suppressed because it is too large Load Diff

15
test/pix/quick-cmp.sh Executable file
View File

@ -0,0 +1,15 @@
#!/usr/bin/perl
$XMLFILE=@ARGV[0];
$DIFFCMD="diff -0 -u -b -B -I \"! Generated\" ";
while (<>) {
$str=$_;
while ( $str=~ /<Firewall / ) {
$str=~ /<Firewall [^>]+name="([^"]*).*$"/;
$fw=$1;
printf "$DIFFCMD %s.fw.orig %s.fw\n",$fw,$fw;
$str=~ s/^.*<Firewall [^>]+name="$fw"[^>]+>//;
}
}

8
test/pix/recycle Executable file
View File

@ -0,0 +1,8 @@
#!/bin/sh
for f in *.fw; do
j=${f}.orig
mv $f $j
done

17
test/pix/run.all Executable file
View File

@ -0,0 +1,17 @@
#!/usr/bin/perl
$XMLFILE=@ARGV[0];
while (<>) {
$str=$_;
while ( $str=~ /<Firewall / ) {
$str=~ /<Firewall [^>]+name="([^"]*).*$"/;
$fw=$1;
printf "echo ====================== $fw =========================================\n";
printf "fwb_pix -v -f $XMLFILE $fw\n";
$str=~ s/^.*<Firewall [^>]+name="$fw"[^>]+>//;
}
}