/* 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 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 #if __GNUC__ > 3 || \ (__GNUC__ == 3 && (__GNUC_MINOR__ > 2 || (__GNUC_MINOR__ == 2 ) ) ) || \ _MSC_VER # include #else # include #endif #include #include #include #include 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"); int interface_id = rule->getInterfaceId(); if (rule->getDirection()==PolicyRule::Undefined) rule->setDirection( PolicyRule::Both ); if (interface_id==-1 && rule->getDirection()==PolicyRule::Both) return true; if (interface_id==-1 && !icmp_cmd && !ssh_telnet_cmd && ( rule->getDirection()==PolicyRule::Inbound || rule->getDirection()==PolicyRule::Outbound) ) compiler->abort(rule, "Direction set without interface"); 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; FWObject *rule_iface = compiler->dbcopy->findInIndex(rule->getInterfaceId()); if (rule->getDirection()==PolicyRule::Both) { if (rule_iface!=NULL) { PolicyRule *r= compiler->dbcopy->createPolicyRule(); compiler->temp_ruleset->add(r); r->duplicate(rule); r->setDirection(PolicyRule::Inbound); tmp_queue.push_back(r); r= compiler->dbcopy->createPolicyRule(); 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; FWObject *rule_iface = compiler->dbcopy->findInIndex(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()) { int 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 { int iface2_id; iface2_id = helper.findInterfaceByNetzone( compiler->getFirstDst(rule) ); list l2=compiler->fw->getByType(Interface::TYPENAME); for (list::iterator i=l2.begin(); i!=l2.end(); ++i) { if ( (*i)->getId()==iface2_id ) continue; PolicyRule *r= compiler->dbcopy->createPolicyRule(); 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(rule, str.str()); } } else compiler->abort( rule, "Outbound ACLs are not supported and emulation is " "not activated"); } 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()==-1) { try { if (! src->isAny() ) { Address *a=compiler->getFirstSrc(rule); int 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)) { int iface2_id = helper.findInterfaceByNetzone( a ); rule->setInterfaceId(iface2_id); rule->setStr("direction","Inbound"); tmp_queue.push_back(rule); return true; } list l2 = compiler->fw->getByTypeDeep(Interface::TYPENAME); for (list::iterator i=l2.begin(); i!=l2.end(); ++i) { Interface *intf = Interface::cast(*i); if (intf->isUnprotected()) continue; PolicyRule *r = compiler->dbcopy->createPolicyRule(); compiler->temp_ruleset->add(r); r->duplicate(rule); r->setInterfaceId(intf->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(rule, 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(compiler); PolicyRule *rule=getNext(); if (rule==NULL) return false; Interface *rule_iface = Interface::cast(compiler->dbcopy->findInIndex(rule->getInterfaceId())); if(rule_iface==NULL) { compiler->abort( rule, "Missing interface assignment"); } 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; }