bool PolicyCompiler_pf::ProcessScrubOption::processNext() { PolicyRule *rule=getNext(); if (rule==NULL) return false; FWOptions *ruleopt =rule->getOptionsObject(); if ( ruleopt->getBool("scrub") ) { if (rule->getAction()!=PolicyRule::Accept) { ruleopt->setBool("scrub",false); tmp_queue.push_back(rule); compiler->abort(rule, "Rule option 'scrub' is supported only for rules " "with action 'Accept'"); return true; } PolicyRule *r = compiler->dbcopy->createPolicyRule(); compiler->temp_ruleset->add(r); r->duplicate(rule); r->setAction(PolicyRule::Scrub); r->getOptionsObject()->setBool("scrub",false); tmp_queue.push_back(r); ruleopt->setBool("scrub",false); tmp_queue.push_back(rule); return true; } /* if service is ip_fragment and action is 'Deny', then add rule with scrub */ Service *srv=compiler->getFirstSrv(rule); assert(srv); if ( (srv->getBool("short_fragm") || srv->getBool("fragm")) && ( rule->getAction()==PolicyRule::Deny || rule->getAction()==PolicyRule::Reject) ) { PolicyRule *r = compiler->dbcopy->createPolicyRule(); compiler->temp_ruleset->add(r); r->duplicate(rule); r->setAction(PolicyRule::Scrub); r->getOptionsObject()->setBool("scrub",false); tmp_queue.push_back(r); return true; } tmp_queue.push_back(rule); return true; }
void Importer::pushRule() { assert(current_ruleset!=NULL); assert(current_rule!=NULL); // populate all elements of the rule PolicyRule *rule = PolicyRule::cast(current_rule); FWOptions *ropt = current_rule->getOptionsObject(); assert(ropt!=NULL); if (action=="permit") { rule->setAction(PolicyRule::Accept); ropt->setBool("stateless", false); } if (action=="deny") { rule->setAction(PolicyRule::Deny); ropt->setBool("stateless", true); } rule->setDirection(PolicyRule::Both); addSrc(); addDst(); addSrv(); addLogging(); // then add it to the current ruleset current_ruleset->ruleset->add(current_rule); if (error_tracker->hasWarnings()) { QStringList warn = error_tracker->getWarnings(); // parser errors and warnings are added to the log by // PFCfgParser::reportError() and PFCfgParser::reportWarning() // so we dont need to add them again here foreach(QString w, warn) { if (!w.startsWith("Parser warning:")) addMessageToLog("Warning: " + w); } markCurrentRuleBad(); }
void Importer::newPolicyRule() { if (fwbdebug) qDebug() << "Importer::newPolicyRule()"; FWObjectDatabase *dbroot = getFirewallObject()->getRoot(); FWObject *nobj = dbroot->create(PolicyRule::TYPENAME); current_rule = Rule::cast(nobj); // check if all child objects were populated properly FWOptions *ropt = current_rule->getOptionsObject(); assert(ropt!=NULL); ropt->setBool("stateless", true); }
bool PolicyCompiler_ipf::checkForKeepState::processNext() { PolicyRule *rule=getNext(); if (rule==NULL) return false; tmp_queue.push_back(rule); Service *srv=compiler->getFirstSrv(rule); assert(srv); FWOptions *ruleopt =rule->getOptionsObject(); if (! ICMPService::isA(srv) && ! UDPService::isA(srv) && ! TCPService::isA(srv) ) ruleopt->setBool("stateless",true); return true; }
bool PolicyCompiler_ipf::expandAnyService::processNext() { PolicyCompiler_ipf *pcomp=dynamic_cast<PolicyCompiler_ipf*>(compiler); PolicyRule *rule=getNext(); if (rule==NULL) return false; RuleElementSrv *srv=rule->getSrv(); FWOptions *ruleopt =rule->getOptionsObject(); if (srv->isAny() && ! ruleopt->getBool("stateless") && rule->getAction()==PolicyRule::Accept) { PolicyRule *r = compiler->dbcopy->createPolicyRule(); compiler->temp_ruleset->add(r); r->duplicate(rule); RuleElementSrv *nsrv=r->getSrv(); nsrv->clearChildren(); nsrv->addRef(pcomp->anyicmp); //compiler->dbcopy->findInIndex(ANY_ICMP_OBJ_ID)); tmp_queue.push_back(r); r = compiler->dbcopy->createPolicyRule(); compiler->temp_ruleset->add(r); r->duplicate(rule); nsrv=r->getSrv(); nsrv->clearChildren(); nsrv->addRef(pcomp->anytcp); //compiler->dbcopy->findInIndex(ANY_TCP_OBJ_ID)); tmp_queue.push_back(r); r = compiler->dbcopy->createPolicyRule(); compiler->temp_ruleset->add(r); r->duplicate(rule); nsrv=r->getSrv(); nsrv->clearChildren(); nsrv->addRef(pcomp->anyudp); //compiler->dbcopy->findInIndex(ANY_UDP_OBJ_ID)); tmp_queue.push_back(r); r = compiler->dbcopy->createPolicyRule(); compiler->temp_ruleset->add(r); r->duplicate(rule); FWOptions *ruleopt =r->getOptionsObject(); ruleopt->setBool("stateless",true); tmp_queue.push_back(r); } else tmp_queue.push_back(rule); return true; }
bool PolicyCompiler_ipf::doDstNegation::processNext() { PolicyRule *rule=getNext(); if (rule==NULL) return false; RuleElementDst *dst=rule->getDst(); if (dst->getNeg()) { RuleElementDst *ndst; PolicyRule *r; FWOptions *ruleopt; r= compiler->dbcopy->createPolicyRule(); compiler->temp_ruleset->add(r); r->duplicate(rule); r->setAction(PolicyRule::Continue); r->setLogging(false); ndst=r->getDst(); ndst->setNeg(false); r->setBool("quick",false); r->setBool("skip_check_for_duplicates",true); ruleopt = r->getOptionsObject(); ruleopt->setBool("stateless", true); tmp_queue.push_back(r); r= compiler->dbcopy->createPolicyRule(); compiler->temp_ruleset->add(r); r->duplicate(rule); ndst=r->getDst(); ndst->setNeg(false); ndst->clearChildren(); ndst->setAnyElement(); r->setBool("quick",true); r->setBool("skip_check_for_duplicates",true); tmp_queue.push_back(r); return true; } tmp_queue.push_back(rule); return true; }
void PFImporter::addLogging() { PolicyRule *rule = PolicyRule::cast(current_rule); FWOptions *ropt = rule->getOptionsObject(); /* alerts Immediate action needed (severity=1) critical Critical conditions (severity=2) debugging Debugging messages (severity=7) disable Disable log option on this ACL element, (no log at all) emergencies System is unusable (severity=0) errors Error conditions (severity=3) inactive Keyword for disabling an ACL element informational Informational messages (severity=6) interval Configure log interval, default value is 300 sec notifications Normal but significant conditions (severity=5) warnings Warning conditions (severity=4) */ QMap<QString, QString> logging_levels; logging_levels["alerts"] = "alert"; logging_levels["critical"] = "crit"; logging_levels["debugging"] = "debug"; logging_levels["emergencies"] = ""; logging_levels["errors"] = "error"; logging_levels["informational"] = "info"; logging_levels["notifications"] = "notice"; logging_levels["warnings"] = "warning"; logging_levels["0"] = ""; logging_levels["1"] = "alert"; logging_levels["2"] = "crit"; logging_levels["3"] = "error"; logging_levels["4"] = "warning"; logging_levels["5"] = "notice"; logging_levels["6"] = "info"; logging_levels["7"] = "debug"; // QStringList log_levels = getLogLevels("pix"); rule->setLogging(logging); QString log_level_qs = log_level.c_str(); if ( ! log_level_qs.isEmpty()) { if (logging_levels.count(log_level_qs) != 0) ropt->setStr("log_level", logging_levels[log_level_qs].toStdString()); else ropt->setStr("log_level", log_level); if (log_level_qs == "disable" || log_level_qs == "inactive") ropt->setBool("disable_logging_for_this_rule", true); } if ( ! log_interval.empty()) { bool ok = false; int log_interval_int = QString(log_interval.c_str()).toInt(&ok); if (ok) ropt->setInt("log_interval", log_interval_int); } }
QString CompilerDriver_pix::run(const std::string &cluster_id, const std::string &firewall_id, const std::string &single_rule_id) { Cluster *cluster = NULL; Firewall *fw = NULL; getFirewallAndClusterObjects(cluster_id, firewall_id, &cluster, &fw); // Copy rules from the cluster object populateClusterElements(cluster, fw); if (cluster) { // PIX failover is dfferent from VRRP and other failover protocols // in that it does not create new virtual address. Instead, each // unit is configured with two ip addresses, one for the active // unit and another for standby one. When active unit fails, the // other one assumes its address. // // This matters because when we use cluster object or one of its // interfaces in rules, compiler should expand it to the set of // addresses that includes addresses of the corresponding // interface of both member firewalls. Method // CompilerDriver::copyFailoverInterface adds a copy of firewall // interface to the cluster object. This works for all firewalls, // but for PIX we need to add copies of interfaces from both // members. // FWObjectTypedChildIterator cl_iface = cluster->findByType(Interface::TYPENAME); for (; cl_iface != cl_iface.end(); ++cl_iface) { FailoverClusterGroup *failover_group = FailoverClusterGroup::cast( (*cl_iface)->getFirstByType(FailoverClusterGroup::TYPENAME)); if (failover_group) { //FWObject *this_member_interface = NULL; //UNUSED list<FWObject*> other_member_interfaces; for (FWObjectTypedChildIterator it = failover_group->findByType(FWObjectReference::TYPENAME); it != it.end(); ++it) { FWObject *intf = FWObjectReference::getObject(*it); assert(intf); //if (intf->isChildOf(fw)) this_member_interface = intf; //UNUSED //else other_member_interfaces.push_back(intf); if (!intf->isChildOf(fw)) other_member_interfaces.push_back(intf); } if (!other_member_interfaces.empty()) { for (list<FWObject*>::iterator it=other_member_interfaces.begin(); it!=other_member_interfaces.end(); ++it) { cluster->addCopyOf(*it, true); } } } } } #if 0 FWObjectTypedChildIterator iface = fw->findByType(Interface::TYPENAME); for (; iface != iface.end(); ++iface) { (*iface)->dump(true, true); } #endif determineOutputFileNames(cluster, fw, !cluster_id.empty(), QStringList(""), QStringList("fw"), QStringList("")); FWOptions* options = fw->getOptionsObject(); QString script_buffer; std::auto_ptr<NATCompiler_pix> n; std::auto_ptr<PolicyCompiler_pix> c; std::auto_ptr<RoutingCompiler_pix> r; try { clearReadOnly(fw); commonChecks2(cluster, fw); pixClusterConfigurationChecks(cluster, fw); // Note that fwobjectname may be different from the name of the // firewall fw This happens when we compile a member of a cluster current_firewall_name = fw->getName().c_str(); 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); } list<FWObject*> all_interfaces = fw->getByTypeDeep(Interface::TYPENAME); pixSecurityLevelChecks(fw, all_interfaces); pixNetworkZoneChecks(fw, all_interfaces); /* Now that all checks are done, we can drop copies of cluster * interfaces that were added to the firewall by * CompilerDriver::populateClusterElements() */ list<FWObject*> copies_of_cluster_interfaces; for (std::list<FWObject*>::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(); } NamedObjectsManagerPIX named_objects_manager(persistent_objects, fw); all_interfaces = fw->getByTypeDeep(Interface::TYPENAME); for (std::list<FWObject*>::iterator i=all_interfaces.begin(); i!=all_interfaces.end(); ++i) { Interface *iface = Interface::cast(*i); assert(iface); /* * missing labels on interfaces * */ 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() ); */ try { AutomaticRules_cisco auto_rules(fw, persistent_objects); auto_rules.addSshAccessRule(); } catch (FWException &ex) { abort(ex.toString()); } std::auto_ptr<Preprocessor> prep( new Preprocessor(objdb , fw, false)); if (inTestMode()) prep->setTestMode(); if (inEmbeddedMode()) prep->setEmbeddedMode(); prep->compile(); std::auto_ptr<OSConfigurator> oscnf( new OSConfigurator_pix_os(objdb , fw, false)); if (inTestMode()) oscnf->setTestMode(); if (inEmbeddedMode()) oscnf->setEmbeddedMode(); oscnf->prolog(); oscnf->processFirewallOptions(); bool have_named_objects = false; bool have_object_groups = false; /* create compilers and run the whole thing */ string version = fw->getStr("version"); if (XMLTools::version_compare(version, "8.3")>=0) n = std::auto_ptr<NATCompiler_pix>( new NATCompiler_asa8(objdb, fw, false, oscnf.get())); else n = std::auto_ptr<NATCompiler_pix>( new NATCompiler_pix(objdb, fw, false, oscnf.get())); RuleSet *nat = RuleSet::cast(fw->getFirstByType(NAT::TYPENAME)); if (nat) { nat->assignUniqueRuleIds(); n->setNamedObjectsManager(&named_objects_manager); n->setSourceRuleSet(nat); n->setRuleSetName(nat->getName()); n->setPersistentObjects(persistent_objects); if (inTestMode()) n->setTestMode(); if (inEmbeddedMode()) n->setEmbeddedMode(); n->setSingleRuleCompileMode(single_rule_id); n->setDebugLevel( dl ); if (rule_debug_on) n->setDebugRule( drn ); n->setVerbose( verbose ); if ( n->prolog() > 0 ) { n->compile(); n->epilog(); preamble_commands += n->printPreambleCommands(); clear_commands += n->printClearCommands(); have_named_objects = (have_named_objects || named_objects_manager.haveNamedObjects()); have_object_groups = (have_object_groups || named_objects_manager.haveObjectGroups()); //named_objects_manager.saveObjectGroups(); } else info(" Nothing to compile in NAT"); } c = std::auto_ptr<PolicyCompiler_pix>( new PolicyCompiler_pix(objdb, fw, false, oscnf.get() , n.get())); RuleSet *policy = RuleSet::cast(fw->getFirstByType(Policy::TYPENAME)); if (policy) { policy->assignUniqueRuleIds(); c->setNamedObjectsManager(&named_objects_manager); c->setSourceRuleSet(policy); c->setRuleSetName(policy->getName()); c->setPersistentObjects(persistent_objects); if (inTestMode()) c->setTestMode(); if (inEmbeddedMode()) c->setEmbeddedMode(); c->setSingleRuleCompileMode(single_rule_id); c->setDebugLevel( dl ); if (rule_debug_on) c->setDebugRule( drp ); c->setVerbose( verbose ); if ( c->prolog() > 0 ) { c->compile(); c->epilog(); preamble_commands += c->printPreambleCommands(); clear_commands += c->printClearCommands(); have_named_objects = (have_named_objects || named_objects_manager.haveNamedObjects()); have_object_groups = (have_object_groups || named_objects_manager.haveObjectGroups()); //named_objects_manager.saveObjectGroups(); } else info(" Nothing to compile in Policy"); } r = std::auto_ptr<RoutingCompiler_pix>( new RoutingCompiler_pix(objdb, fw, false, oscnf.get())); RuleSet *routing = RuleSet::cast(fw->getFirstByType(Routing::TYPENAME)); if (routing) { routing->assignUniqueRuleIds(); r->setNamedObjectsManager(&named_objects_manager); r->setSourceRuleSet(routing); r->setRuleSetName(routing->getName()); r->setPersistentObjects(persistent_objects); if (inTestMode()) r->setTestMode(); if (inEmbeddedMode()) r->setEmbeddedMode(); r->setSingleRuleCompileMode(single_rule_id); r->setDebugLevel( dl ); if (rule_debug_on) r->setDebugRule( drp ); r->setVerbose( verbose ); if ( r->prolog() > 0 ) { r->compile(); r->epilog(); } else info(" Nothing to compile in Routing"); } /* * compilers detach persistent objects when they finish, this * means at this point library persistent_objects is not part * of any object tree. */ objdb->reparent(persistent_objects); if (haveErrorsAndWarnings()) { all_errors.push_front(getErrors("").c_str()); } policy_script = c->getCompiledScript(); nat_script = n->getCompiledScript(); routing_script = r->getCompiledScript(); named_objects_and_groups = named_objects_manager.getNamedObjectsDefinitions(); if (c->haveErrorsAndWarnings()) all_errors.push_back(c->getErrors("C ").c_str()); if (n->haveErrorsAndWarnings()) all_errors.push_back(n->getErrors("N ").c_str()); if (r->haveErrorsAndWarnings()) all_errors.push_back(r->getErrors("R ").c_str()); if (single_rule_compile_on) { return formSingleRuleCompileOutput( QString::fromUtf8( (named_objects_and_groups + policy_script + nat_script + routing_script).c_str())); } system_configuration_script = oscnf->getCompiledScript(); system_configuration_script += "\n"; clear_commands += named_objects_manager.getClearCommands() + "\n"; // system_configuration_script += preamble_commands; // system_configuration_script += clear_commands; script_buffer = assembleFwScript( cluster, fw, !cluster_id.empty(), oscnf.get()); QString ofname = getAbsOutputFileName(file_names[FW_FILE]); info("Output file name: " + ofname.toStdString()); QFile fw_file(ofname); if (fw_file.open(QIODevice::WriteOnly)) { QTextStream fw_str(&fw_file); fw_str << script_buffer; fw_file.close(); fw_file.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ReadGroup | QFile::ReadOther | QFile::ExeOwner | QFile::ExeGroup | QFile::ExeOther ); info(" Compiled successfully"); } else { QString err(" Failed to open file %1 for writing: %2; Current dir: %3"); abort(err.arg(fw_file.fileName()) .arg(fw_file.error()).arg(QDir::current().path()).toStdString()); } if (!all_errors.isEmpty()) status = BaseCompiler::FWCOMPILER_WARNING; } catch (FWException &ex) { status = BaseCompiler::FWCOMPILER_ERROR; return QString::fromUtf8(ex.toString().c_str()); } return ""; }