1
0
mirror of https://github.com/fwbuilder/fwbuilder synced 2026-03-24 20:27:22 +01:00
fwbuilder/src/cisco_lib/Helper.cpp
Vadim Kurland 4d6302a4cc * CompilerDriver_pix_run.cpp (pixNetworkZoneChecks): see SF bug
3213019 "FWSM Network zone and IPv6". Currently we do not support
ipv6 with PIX/ASA and FWSM. If user creates a group to be used as
network zone object and places ipv6 address in it, this address
should be ignored while compiling the policy but this should not
be an error.
2011-04-07 11:05:46 -07:00

455 lines
15 KiB
C++

/*
Firewall Builder
Copyright (C) 2002 NetCitadel, LLC
Author: Vadim Kurland vadim@vk.crocodile.org
$Id$
This program is free software which we release under the GNU General Public
License. You may redistribute and/or modify this program under the terms
of that license as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
To get a copy of the GNU General Public License, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Helper.h"
#include <fwbuilder/Interface.h>
#include <fwbuilder/ObjectGroup.h>
#include <fwbuilder/InetAddr.h>
#include <fwbuilder/FWObjectDatabase.h>
#include <fwbuilder/RuleElement.h>
#include <fwbuilder/Rule.h>
#include "fwbuilder/Resources.h"
#include <fwbuilder/IPv6.h>
#include <fwbuilder/NetworkIPv6.h>
#include <fwbuilder/Network.h>
#include <fwbuilder/InetAddrMask.h>
#include <assert.h>
#include <limits.h>
#include <iostream>
#include <QObject>
#include <QString>
using namespace libfwbuilder;
using namespace fwcompiler;
using namespace std;
// #define DEBUG_NETZONE_OPS 1
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(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 );
}
}
int Helper::findInterfaceByAddress(Address *obj)
{
return findInterfaceByAddress(obj->getAddressPtr(), obj->getNetmaskPtr());
}
/*
* ticket #1293
* Weird corner case: user made a mistake setting netmask of an
* intrface to 0.0.0.0, which made this interface match any address.
* At the same time, this interface was marked as "unprotected". So,
* if we get an interface from helper.findInterfaceByNetzoneOrAll()
* but this interface is unprotected, issue a warning and use all
* interfaces instead.
*/
int Helper::findInterfaceByAddress(const InetAddr *addr,
const InetAddr *nm)
{
if (addr==NULL) return -1;
#if DEBUG_NETZONE_OPS
cerr << "Helper::findInterfaceByAddress";
cerr << " addr=" << addr->toString();
cerr << " nm=" << nm->toString();
cerr << endl;
#endif
Firewall *fw = compiler->fw;
list<FWObject*> l2 = fw->getByTypeDeep(Interface::TYPENAME);
for (list<FWObject*>::iterator i=l2.begin(); i!=l2.end(); ++i)
{
Interface *iface = Interface::cast(*i);
if (iface->isDedicatedFailover()) continue;
if (iface->isUnprotected()) continue;
#if DEBUG_NETZONE_OPS
cerr << "Helper::findInterfaceByAddress";
cerr << " intf=" << iface->getName();
cerr << endl;
#endif
FWObjectTypedChildIterator j =
iface->findByType((addr->isV4())?IPv4::TYPENAME:IPv6::TYPENAME);
for (; j!=j.end(); ++j)
{
const Address *i_addr = Address::constcast(*j);
#if DEBUG_NETZONE_OPS
cerr << "Helper::findInterfaceByAddress";
cerr << " i_addr=" << i_addr->getName();
cerr << endl;
cerr << " " << i_addr->getAddressPtr()->toString();
cerr << " " << i_addr->getNetmaskPtr()->toString();
cerr << endl;
#endif
if (nm != NULL)
{
InetAddrMask interface_subnet(*(i_addr->getAddressPtr()),
*(i_addr->getNetmaskPtr()));
InetAddrMask other_subnet(*addr, *nm);
#if DEBUG_NETZONE_OPS
cerr << "Helper::findInterfaceByAddress";
cerr << " addr=" << other_subnet.toString();
cerr << " intf=" << iface->getName()
<< " " << interface_subnet.toString();
cerr << endl;
#endif
vector<InetAddrMask> ovr =
libfwbuilder::getOverlap(interface_subnet, other_subnet);
#if DEBUG_NETZONE_OPS
cerr << "Helper::findInterfaceByAddress";
cerr << " overlap:";
cerr << " ovr.size()=" << ovr.size();
if (ovr.size() > 0)
cerr << " ovr.front()=" << ovr.front().toString();
cerr << endl;
#endif
if (ovr.size()==0) continue;
// if interface_subnet is equal or wider than other_subnet,
// getOverlap() returns subnet object equal to other_subnet
// If other_subnet is wider, returned object is equal
// to interface_subnet. If they intersect but one does not fit
// completely in the other, returned object is not equal
// to either.
if (ovr.front() == other_subnet)
{
return iface->getId();
}
} else
{
if ( i_addr->belongs(*addr) ) return iface->getId();
}
}
}
return -1;
}
int Helper::findInterfaceByNetzone(Address *obj)
{
if (IPv4::isA(obj))
{
InetAddr host_netmask("255.255.255.255");
return findInterfaceByNetzone(obj->getAddressPtr(), &host_netmask);
} else
return findInterfaceByNetzone(obj->getAddressPtr(), obj->getNetmaskPtr());
}
/**
* finds interface of the firewall associated with the netzone
* that object 'obj' belongs to. Returns interface ID
*
*/
int Helper::findInterfaceByNetzone(const InetAddr *addr, const InetAddr *nm)
throw(FWException)
{
#if DEBUG_NETZONE_OPS
cerr << "Helper::findInterfaceByNetzone";
cerr << " matching to";
cerr << " addr=" << addr;
if (addr) cerr << " " << addr->toString();
cerr << " nm=" << nm;
if (nm) cerr << " " << nm->toString();
cerr << endl;
#endif
Firewall *fw = compiler->fw;
map<int,FWObject*> zones;
list<FWObject*> l2 = fw->getByTypeDeep(Interface::TYPENAME);
for (list<FWObject*>::iterator i=l2.begin(); i!=l2.end(); ++i)
{
Interface *iface = Interface::cast(*i);
if (iface->isDedicatedFailover()) continue;
if (iface->isUnprotected()) continue;
// NOTE: "network_zone" is globally unique string ID
int netzone_id =
FWObjectDatabase::getIntId(iface->getStr("network_zone"));
if (netzone_id != -1)
{
FWObject *netzone = fw->getRoot()->findInIndex(netzone_id);
list<FWObject*> nz;
expand_group_recursive(netzone, nz);
#if DEBUG_NETZONE_OPS
cerr << "Helper::findInterfaceByNetzone";
cerr << " netzone_id=" << netzone_id
<< " " << iface->getStr("network_zone")
<< " " << netzone->getName()
<< endl;
#endif
for (list<FWObject*>::iterator j=nz.begin(); j!=nz.end(); ++j)
{
Address *netzone_addr = Address::cast(*j);
if (netzone_addr == NULL) continue;
#if DEBUG_NETZONE_OPS
cerr << "Helper::findInterfaceByNetzone";
cerr << " " << netzone_addr->getName()
<< " " << netzone_addr->getAddressPtr()->toString()
<< endl;
#endif
// if addr==NULL, return id of the interfacce that has
// net_zone=="any"
if (addr==NULL)
{
if (netzone_addr->getId()==FWObjectDatabase::ANY_ADDRESS_ID)
return iface->getId(); // id of the interface
} else
{
// see SF bug 3213019
// skip ipv6 addresses in network zone group
if (netzone_addr->getAddressPtr()->addressFamily() !=
addr->addressFamily()) continue;
const InetAddr *nz_addr = netzone_addr->getAddressPtr();
const InetAddr *nz_netm = netzone_addr->getNetmaskPtr();
if (nm != NULL && nz_netm != NULL)
{
InetAddrMask nz_subnet(*nz_addr, *nz_netm);
InetAddrMask other_subnet(*addr, *nm);
vector<InetAddrMask> ovr =
libfwbuilder::getOverlap(nz_subnet,
other_subnet);
#if DEBUG_NETZONE_OPS
cerr << "Helper::findInterfaceByNetzone";
cerr << " addr=" << other_subnet.toString();
cerr << " nz=" << nz_subnet.toString();
cerr << " overlap:";
cerr << " ovr.size()=" << ovr.size();
if (ovr.size() > 0)
cerr << " ovr.front()=" << ovr.front().toString();
cerr << endl;
#endif
if (ovr.size()==0) continue;
// if nz_subnet is equal or wider than other_subnet,
// getOverlap() returns subnet object equal to other_subnet
// If other_subnet is wider, returned object is equal
// to nz_subnet. If they intersect but one does not fit
// completely in the other, returned object is not equal
// to either.
if (ovr.front() == other_subnet)
{
zones[iface->getId()] = netzone_addr;
#if DEBUG_NETZONE_OPS
cerr << "Helper::findInterfaceByNetzone";
cerr << " match" << endl;
#endif
}
} else
{
if (netzone_addr->belongs(*addr))
{
zones[iface->getId()] = netzone_addr;
#if DEBUG_NETZONE_OPS
cerr << "Helper::findInterfaceByNetzone";
cerr << " match" << endl;
#endif
}
}
}
}
}
}
/*
* now compare dimensions of all netzones that contain address obj and
* pick the one with smallest dimension
*/
int res_id = -1;
unsigned long res_dim = LONG_MAX;
for (map<int,FWObject*>::iterator i=zones.begin(); i!=zones.end(); ++i)
{
int iface_id = (*i).first;
FWObject *netzone = (*i).second;
unsigned long dim = calculateDimension(netzone);
#if DEBUG_NETZONE_OPS
cerr << "Helper::findInterfaceByNetzone";
cerr << " netzone=" << netzone->getName()
<< " dim=" << dim
<< " res_dim=" << res_dim
<< endl;
#endif
if (dim<=res_dim)
{
res_id = iface_id;
res_dim = dim;
}
}
#if DEBUG_NETZONE_OPS
cerr << "Helper::findInterfaceByNetzone";
cerr << " Result after scanning network zones: " << res_id << endl;
#endif
/*
* Subnets defined by addresses of interfaces are automatically part
* of the corresponding network zones
*/
if (res_id == -1)
res_id = findInterfaceByAddress(addr, nm);
if (res_id == -1)
{
QString err = QObject::tr("Can not find interface with network zone "
"that includes address '%1%2'");
throw(FWException(err
.arg((addr)?addr->toString().c_str():"NULL")
.arg((nm)?QString("/%1").arg(nm->toString().c_str()):"")
.toStdString()));
}
#if DEBUG_NETZONE_OPS
cerr << "Helper::findInterfaceByNetzone";
cerr << " returning " << res_id << endl;
#endif
return res_id;
}
list<int> Helper::getAllInterfaceIDs()
{
Firewall *fw = compiler->fw;
list<int> 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<int> Helper::findInterfaceByNetzoneOrAll(RuleElement *re)
{
list<int> 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(
re->getParent(),
string("findInterfaceByNetzoneOrAll failed to retrieve first "
"object from the rule element; is argument not of "
"the type RuleElementSrc or RuleElementDst ?"));
return intf_id_list;
}
try
{
int intf_id = findInterfaceByNetzone(a);
intf_id_list.push_back(intf_id);
} catch(FWException &ex)
{
// 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(ex.toString());
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;
}