From 6d9f9940673596381d906e494558fb206f4e2aaa Mon Sep 17 00:00:00 2001 From: Vadim Kurland Date: Mon, 16 Nov 2009 23:41:38 +0000 Subject: [PATCH] remove copies of cluster interfaces form the member firewall after all checks are done: fixes #636 ; automatically make vlan parent inetrfaces unprotected and issue warning; check for uniquenness of labels; --- src/cisco_lib/CompilerDriver_pix_run.cpp | 187 +++++++++++++------ src/cisco_lib/PolicyCompiler_pix.cpp | 3 +- src/cisco_lib/PolicyCompiler_pix_v6_acls.cpp | 9 +- 3 files changed, 134 insertions(+), 65 deletions(-) diff --git a/src/cisco_lib/CompilerDriver_pix_run.cpp b/src/cisco_lib/CompilerDriver_pix_run.cpp index 688f16ee8..e384abe5c 100644 --- a/src/cisco_lib/CompilerDriver_pix_run.cpp +++ b/src/cisco_lib/CompilerDriver_pix_run.cpp @@ -80,6 +80,7 @@ #include #include #include +#include using namespace std; @@ -259,71 +260,55 @@ string CompilerDriver_pix::run(const std::string &cluster_id, multimap netzone_objects; - std::list l2=fw->getByType(Interface::TYPENAME); - for (std::list::iterator i=l2.begin(); i!=l2.end(); ++i) + std::list all_interfaces = fw->getByTypeDeep(Interface::TYPENAME); + for (std::list::iterator i=all_interfaces.begin(); i!=all_interfaces.end(); ++i) { Interface *iface = dynamic_cast(*i); assert(iface); + if (iface->getOptionsObject()->getBool("cluster_interface")) continue; + + if ((iface->getOptionsObject()->getStr("type") == "" || + iface->getOptionsObject()->getStr("type") == "ethernet") && + iface->getByType(Interface::TYPENAME).size() > 0) + { + // Parent vlan interface (i.e. trunk) + if (!iface->isUnprotected()) + { + QString err( + "Interface %1 has vlan subinterfaces, it can not " + "be used for ACL. Marking this interface \"unprotected\" " + "to exclude it." + ); + warning(fw, NULL, NULL, + err.arg(iface->getName().c_str()) + .toStdString()); + iface->setUnprotected(true); + } + } + // Tests for label, security level and network zone make sense // only for interfaces that can be used in ACLs or to bind // ACLs to. Unnumbered interfaces can't, so we do not need to // run these checks. One example of unnumbered interface is // parent interface for vlan subinterfaces. if (iface->isUnnumbered()) continue; - - if (iface->getOptionsObject()->getBool("cluster_interface")) continue; + if (iface->isUnprotected()) continue; /* - * missing labels on interfaces + * there shouldn't be two interfaces with the same security level and same label + * */ - if (iface->getLabel()=="") - { - string lbl; - if (iface->isDedicatedFailover()) - { - // dedicated failover interface misses label. This - // interface can be used in failover cluster group - // or state sync group. Assign label depending on - // the function. - FWObjectTypedChildIterator it = - cluster->findByType(StateSyncClusterGroup::TYPENAME); - StateSyncClusterGroup *state_sync_group = - StateSyncClusterGroup::cast(*it); - if (state_sync_group && state_sync_group->hasMember(iface)) - lbl = "state"; - - if (!iface->getOptionsObject()->getStr("failover_group_id").empty()) - lbl = "failover"; - } - - if (lbl.empty()) - { - if (iface->getSecurityLevel()==0) lbl="outside"; - else - { - if (iface->getSecurityLevel()==100) lbl="inside"; - else - { - QString l("dmz%1"); - lbl = l.arg(iface->getSecurityLevel()).toStdString(); - } - } - } - iface->setLabel(lbl); - } - -/* - * there shouldn't be two interfaces with the same security level - */ - for (std::list::iterator j=l2.begin(); j!=l2.end(); ++j) + for (std::list::iterator j=all_interfaces.begin(); j!=all_interfaces.end(); ++j) { Interface *iface2 = dynamic_cast(*j); assert(iface2); if (iface2->isUnnumbered()) continue; + if (iface2->isUnprotected()) continue; if (iface->getId()==iface2->getId()) continue; if (iface->getOptionsObject()->getBool("cluster_interface") || - iface2->getOptionsObject()->getBool("cluster_interface")) continue; + iface2->getOptionsObject()->getBool("cluster_interface")) + continue; if (iface->getSecurityLevel()==iface2->getSecurityLevel()) { @@ -339,6 +324,21 @@ string CompilerDriver_pix::run(const std::string &cluster_id, .arg(iface2->getLabel().c_str()).toStdString()); throw FatalErrorInSingleRuleCompileMode(); } + + if (iface->getLabel()==iface2->getLabel()) + { + QString err( + "Label of each interface should be unique, " + "however interfaces %1 (%2) and %3 (%4)" + " have the same." + ); + abort(fw, NULL, NULL, + err.arg(iface->getName().c_str()) + .arg(iface->getLabel().c_str()) + .arg(iface2->getName().c_str()) + .arg(iface2->getLabel().c_str()).toStdString()); + throw FatalErrorInSingleRuleCompileMode(); + } } // We only do limited checks for dedicated failover @@ -347,11 +347,10 @@ string CompilerDriver_pix::run(const std::string &cluster_id, // commands. if (iface->isDedicatedFailover()) continue; - /* * in PIX, we need network zones to be defined for all interfaces */ - string netzone_id=iface->getStr("network_zone"); + string netzone_id = iface->getStr("network_zone"); if (netzone_id=="") { QString err("Network zone definition is missing for interface %1 (%2)"); @@ -360,7 +359,8 @@ string CompilerDriver_pix::run(const std::string &cluster_id, .arg(iface->getLabel().c_str()).toStdString()); throw FatalErrorInSingleRuleCompileMode(); } - FWObject *netzone=objdb->findInIndex( + + FWObject *netzone = objdb->findInIndex( FWObjectDatabase::getIntId(netzone_id)); if (netzone==NULL) { @@ -447,13 +447,81 @@ string CompilerDriver_pix::run(const std::string &cluster_id, } } + /* Now that all checks are done, we can drop copies of cluster + * interfaces that were added to the firewall by + * CompilerDriver::populateClusterElements() + */ + list copies_of_cluster_interfaces; + for (std::list::iterator i=all_interfaces.begin(); i!=all_interfaces.end(); ++i) + { + Interface *iface = Interface::cast(*i); + assert(iface); + + if (iface->getOptionsObject()->getBool("cluster_interface")) + copies_of_cluster_interfaces.push_back(iface); + } + while (copies_of_cluster_interfaces.size()) + { + fw->remove(copies_of_cluster_interfaces.front()); + copies_of_cluster_interfaces.pop_front(); + } + + all_interfaces = fw->getByTypeDeep(Interface::TYPENAME); + + for (std::list::iterator i=all_interfaces.begin(); i!=all_interfaces.end(); ++i) + { + Interface *iface = dynamic_cast(*i); + assert(iface); /* - * 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) + * missing labels on interfaces * - std::sort(fw->begin(), fw->end(), sort_by_net_zone() ); -*/ + */ + if (iface->getLabel()=="") + { + string lbl; + if (iface->isDedicatedFailover()) + { + // dedicated failover interface misses label. This + // interface can be used in failover cluster group + // or state sync group. Assign label depending on + // the function. + FWObjectTypedChildIterator it = + cluster->findByType(StateSyncClusterGroup::TYPENAME); + StateSyncClusterGroup *state_sync_group = + StateSyncClusterGroup::cast(*it); + if (state_sync_group && state_sync_group->hasMember(iface)) + lbl = "state"; + + if (!iface->getOptionsObject()->getStr("failover_group_id").empty()) + lbl = "failover"; + } + + if (lbl.empty()) + { + if (iface->getSecurityLevel()==0) lbl="outside"; + else + { + if (iface->getSecurityLevel()==100) lbl="inside"; + else + { + QString l("dmz%1"); + lbl = l.arg(iface->getSecurityLevel()).toStdString(); + } + } + } + iface->setLabel(lbl); + } + + + + } + /* + * 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() ); + */ std::auto_ptr prep(new Preprocessor(objdb , fw, false)); prep->compile(); @@ -661,9 +729,10 @@ void CompilerDriver_pix::pixClusterConfigurationChecks(Cluster *cluster, Interface *member_iface = Interface::cast(FWObjectReference::getObject(*it)); assert(member_iface); + pixClusterGroupChecks(failover_group); + if (member_iface->isDedicatedFailover()) { - pixClusterGroupChecks(failover_group); failover_group_inspected = true; } } @@ -709,10 +778,11 @@ void CompilerDriver_pix::pixClusterGroupChecks(ClusterGroup *cluster_group) } } - if (!member_iface->isDedicatedFailover()) + if (StateSyncClusterGroup::isA(cluster_group) && + !member_iface->isDedicatedFailover()) { - QString err("Interface %1 is used in a state synchronization or " - "failover group but is not marked as 'Dedicated Failover' " + QString err("Interface %1 is used in a state synchronization " + "but is not marked as 'Dedicated Failover' " "interface. All interfaces used for the state " "synchronization or failover must be marked " "'Dedicated Failover'. "); @@ -721,6 +791,7 @@ void CompilerDriver_pix::pixClusterGroupChecks(ClusterGroup *cluster_group) err.arg(member_iface->getName().c_str()).toStdString()); throw FatalErrorInSingleRuleCompileMode(); } + if (!member_iface->isRegular() || member_iface->countInetAddresses(true)==0) { QString err("Interface %1 which is used in state synchronization " diff --git a/src/cisco_lib/PolicyCompiler_pix.cpp b/src/cisco_lib/PolicyCompiler_pix.cpp index d8f73e6c9..0a45bb4dd 100644 --- a/src/cisco_lib/PolicyCompiler_pix.cpp +++ b/src/cisco_lib/PolicyCompiler_pix.cpp @@ -696,7 +696,8 @@ void PolicyCompiler_pix::compile() add( new InterfacePolicyRules( "process interface policy rules and store interface ids")); - if ( fwopt->getBool("pix_assume_fw_part_of_any")) { + 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" )); } diff --git a/src/cisco_lib/PolicyCompiler_pix_v6_acls.cpp b/src/cisco_lib/PolicyCompiler_pix_v6_acls.cpp index 4ed392538..e746af0c0 100644 --- a/src/cisco_lib/PolicyCompiler_pix_v6_acls.cpp +++ b/src/cisco_lib/PolicyCompiler_pix_v6_acls.cpp @@ -309,6 +309,7 @@ bool PolicyCompiler_pix::assignRuleToInterface_v6::processNext() { Interface *intf = Interface::cast(*i); if (intf->isUnprotected()) continue; + if (intf->getOptionsObject()->getBool("cluster_interface")) continue; PolicyRule *r = compiler->dbcopy->createPolicyRule(); compiler->temp_ruleset->add(r); @@ -347,14 +348,10 @@ bool PolicyCompiler_pix::pickACL_v6::processNext() 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"); - } + compiler->abort(rule, "Missing interface assignment"); string acl_name= rule_iface->getLabel() + "_acl_in"; - rule->setStr("acl",acl_name); + rule->setStr("acl", acl_name); ciscoACL *acl = new ciscoACL(acl_name, rule_iface, "in"); pix_comp->acls[acl_name] = acl;