diff --git a/build_num b/build_num index 0def9d56f..b3571d687 100644 --- a/build_num +++ b/build_num @@ -1 +1 @@ -#define BUILD_NUM 615 +#define BUILD_NUM 616 diff --git a/doc/ChangeLog b/doc/ChangeLog index 44bb36db2..083d0c5a9 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,17 @@ +2008-10-18 vadim + + * PolicyCompiler_ipt.cpp (singleDstNegation::processNext): fixed + bug (no #): policy compiler for iptables did not handle correctly + rules where a host that has multiple addresses was a single object + in a rule element and had negation. + + * NATCompiler_ipt.cpp (singleObjectNegation::processNext): added + support for single object negation in OSrc and ODst in NAT rules. + This provides for more compact iptables script in the often used + case where single object is used with negation in these elements + of a NAT rule. Other improvements in handling NAT rules with + negation. + 2008-10-15 vadim * ipt.cpp (dumpScript): Explicitly use "\n" instead of endl to diff --git a/src/ipt/NATCompiler_PrintRule.cpp b/src/ipt/NATCompiler_PrintRule.cpp index fa6862f9d..18e75fa89 100644 --- a/src/ipt/NATCompiler_PrintRule.cpp +++ b/src/ipt/NATCompiler_PrintRule.cpp @@ -452,7 +452,7 @@ string NATCompiler_ipt::PrintRule::_printDstService(RuleElementOSrv *rel) // Note print_mask is true by default, print_range is false by default. string NATCompiler_ipt::PrintRule::_printAddr(Address *o, - bool print_mask, + bool , bool print_range) { NATCompiler_ipt *ipt_comp=dynamic_cast(compiler); @@ -525,6 +525,13 @@ string NATCompiler_ipt::PrintRule::_printAddr(Address *o, return ostr.str(); } +string NATCompiler_ipt::PrintRule::_printSingleObjectNegation( + RuleElement *rel) +{ + if (rel->getBool("single_object_negation")) return "! "; + else return ""; +} + NATCompiler_ipt::PrintRule::PrintRule(const std::string &name) : NATRuleProcessor(name) { @@ -554,16 +561,16 @@ bool NATCompiler_ipt::PrintRule::processNext() compiler->output << _createChain(rule->getStr("ipt_target")); -// RuleElementOSrc *osrcrel=rule->getOSrc(); - Address *osrc=compiler->getFirstOSrc(rule); assert(osrc); -// RuleElementODst *odstrel=rule->getODst(); - Address *odst=compiler->getFirstODst(rule); assert(odst); + RuleElementOSrc *osrcrel = rule->getOSrc(); + Address *osrc = compiler->getFirstOSrc(rule); assert(osrc); + RuleElementODst *odstrel = rule->getODst(); + Address *odst = compiler->getFirstODst(rule); assert(odst); RuleElementOSrv *osrvrel=rule->getOSrv(); - Service *osrv=compiler->getFirstOSrv(rule); assert(osrv); + 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); + Address *tsrc = compiler->getFirstTSrc(rule); assert(tsrc); + Address *tdst = compiler->getFirstTDst(rule); assert(tdst); + Service *tsrv = compiler->getFirstTSrv(rule); assert(tsrv); // Interface *iface= // Interface::cast( rule->getRoot()->getById(rule->getInterfaceId() ,true) ); @@ -598,7 +605,9 @@ bool NATCompiler_ipt::PrintRule::processNext() if (osrc_addr==NULL || !osrc_addr->isAny()) { string osrc_out = _printAddr(osrc); - if (!osrc_out.empty()) cmdout << " -s " << osrc_out; + if (!osrc_out.empty()) cmdout << " -s " + << _printSingleObjectNegation(osrcrel) + << osrc_out; } // cmdout << " -s "; @@ -611,8 +620,9 @@ bool NATCompiler_ipt::PrintRule::processNext() } if (!odst->isAny()) { - cmdout << " -d "; - cmdout << _printAddr(odst); + cmdout << " -d " + << _printSingleObjectNegation(odstrel) + << _printAddr(odst); } cmdout << " "; diff --git a/src/ipt/NATCompiler_ipt.cpp b/src/ipt/NATCompiler_ipt.cpp index 319205d70..402866ed4 100644 --- a/src/ipt/NATCompiler_ipt.cpp +++ b/src/ipt/NATCompiler_ipt.cpp @@ -920,25 +920,35 @@ bool NATCompiler_ipt::ReplaceFirewallObjectsTSrc::processNext() if (obj->getId()==compiler->getFwId() ) { - Address *odst=compiler->getFirstODst(rule); + RuleElementODst *odstrel = rule->getODst(); + Address *odst = compiler->getFirstODst(rule); rel->clearChildren(); - Interface *iface=compiler->findInterfaceFor(odst,compiler->fw); + Interface *odst_iface = + compiler->findInterfaceFor(odst, compiler->fw); - if (!odst->isAny() && iface!=NULL) rel->addRef(iface); - else // else use all interfaces except loopback and unnumbered ones + if (!odst->isAny() && odst_iface!=NULL && + !odstrel->getBool("single_object_negation")) + rel->addRef(odst_iface); + else { + // else use all interfaces except loopback and unnumbered ones + // also skip interface connected to ODst if single object + // negation was detected in ODst list l2=compiler->fw->getByType(Interface::TYPENAME); for (list::iterator i=l2.begin(); i!=l2.end(); ++i) { - Interface *iface=Interface::cast(*i); - if (! iface->isLoopback() && - ! iface->isUnnumbered() && - ! iface->isBridgePort() - ) - rel->addRef( *i ); + Interface *iface = Interface::cast(*i); + if (iface->isLoopback() || + iface->isUnnumbered() || + iface->isBridgePort() ) continue; + if (odstrel->getBool("single_object_negation") && + odst_iface->getId()==iface->getId()) continue; + + rel->addRef( *i ); } + for (FWObject::iterator i1=cl.begin(); i1!=cl.end(); ++i1) rel->addRef( *i1 ); @@ -1448,6 +1458,30 @@ bool NATCompiler_ipt::splitMultipleICMP::processNext() return true; } +bool NATCompiler_ipt::singleObjectNegation::processNext() +{ + NATRule *rule=getNext(); if (rule==NULL) return false; + + RuleElement *rel = RuleElement::cast(rule->getFirstByType(re_type)); + assert(rel); + + if (rel->getNeg() && rel->size()==1) + { + FWObject *o = rel->front(); + if (FWReference::cast(o)!=NULL) o=FWReference::cast(o)->getPointer(); + Address *reladdr = Address::cast(o); + if ( reladdr && reladdr->countInetAddresses()==1 && + !compiler->complexMatch(reladdr, compiler->fw)) + { + rel->setNeg(false); + rel->setBool("single_object_negation", true); + } + } + + tmp_queue.push_back(rule); + return true; +} + bool NATCompiler_ipt::doOSrcNegation::processNext() { NATRule *rule=getNext(); if (rule==NULL) return false; @@ -1466,7 +1500,7 @@ bool NATCompiler_ipt::doOSrcNegation::processNext() RuleElementTDst *ntdst; RuleElementTSrv *ntsrv; - string new_chain=NATCompiler_ipt::getNewTmpChainName(rule); + string new_chain = NATCompiler_ipt::getNewTmpChainName(rule); osrcrel->setNeg(false); /* * negation in OSrc : @@ -1728,8 +1762,8 @@ bool NATCompiler_ipt::localNATRule::processNext() // if ( rule->getStr("ipt_chain").empty()) // { - Address *osrc=compiler->getFirstOSrc(rule); - bool osrcfw= compiler->complexMatch(osrc,compiler->fw); + Address *osrc = compiler->getFirstOSrc(rule); + bool osrcfw = compiler->complexMatch(osrc,compiler->fw); switch( rule->getRuleType()) { @@ -1744,7 +1778,7 @@ bool NATCompiler_ipt::localNATRule::processNext() * * Can use OUTPUT chain only for DNAT rules and a like */ - if (osrcfw) rule->setStr("ipt_chain","OUTPUT"); + if (osrcfw) rule->setStr("ipt_chain", "OUTPUT"); if (osrcfw && osrc->getId()==compiler->fw->getId()) { RuleElementOSrc *src; @@ -1778,15 +1812,17 @@ bool NATCompiler_ipt::splitIfOSrcAny::processNext() if (rule->getRuleType()==NATRule::DNAT) { -// RuleElementOSrc *osrcrel=rule->getOSrc(); - Address *osrc=compiler->getFirstOSrc(rule); + RuleElementOSrc *osrcrel = rule->getOSrc(); + Address *osrc = compiler->getFirstOSrc(rule); - if (osrc->isAny()) + // split if osrc is any OR if it has a single object with negation + if (osrc->isAny() || osrcrel->getBool("single_object_negation")) { - NATRule *r= NATRule::cast(compiler->dbcopy->create(NATRule::TYPENAME) ); + NATRule *r = NATRule::cast( + compiler->dbcopy->create(NATRule::TYPENAME) ); compiler->temp_ruleset->add(r); r->duplicate(rule); - RuleElementOSrc *nosrcrel=r->getOSrc(); + RuleElementOSrc *nosrcrel = r->getOSrc(); nosrcrel->addRef(compiler->fw); tmp_queue.push_back(r); } @@ -2220,6 +2256,26 @@ void NATCompiler_ipt::compile() add( new classifyNATRule( "reclassify rules" )); add( new ConvertLoadBalancingRules( "convert load balancing rules")); add( new VerifyRules( "verify rules" )); +#if 0 +// ----------- 10/18/2008 + add( new splitODstForSNAT( + "split rule if objects in ODst belong to different subnets") ); + add( new ReplaceFirewallObjectsODst("replace firewall in ODst" ) ); + add( new ReplaceFirewallObjectsTSrc("replace firewall in TSrc" ) ); + add( new splitOnDynamicInterfaceInODst( + "split rule if ODst is dynamic interface" ) ); + add( new splitOnDynamicInterfaceInTSrc( + "split rule if TSrc is dynamic interface" ) ); + + add( new ExpandMultipleAddresses("expand multiple addresses") ); + add( new dropRuleWithEmptyRE("drop rules with empty rule elements")); +// ----------- +#endif + + add( new singleObjectNegationOSrc( + "negation in OSrc if it holds single object")); + add( new singleObjectNegationODst( + "negation in ODst if it holds single object")); add( new doOSrcNegation( "process negation in OSrc" )); add( new doODstNegation( "process negation in ODst" )); @@ -2245,6 +2301,8 @@ void NATCompiler_ipt::compile() add( new decideOnChain( "decide on chain" ) ); add( new decideOnTarget( "decide on target" ) ); + +// ----------- 10/18/2008 add( new splitODstForSNAT( "split rule if objects in ODst belong to different subnets") ); add( new ReplaceFirewallObjectsODst("replace firewall in ODst" ) ); @@ -2257,6 +2315,7 @@ void NATCompiler_ipt::compile() add( new ExpandMultipleAddresses("expand multiple addresses") ); add( new dropRuleWithEmptyRE("drop rules with empty rule elements")); + if (ipv6) add( new DropIPv4Rules("drop ipv4 rules")); else diff --git a/src/ipt/NATCompiler_ipt.h b/src/ipt/NATCompiler_ipt.h index a4a085d3c..b6d3dfcc4 100644 --- a/src/ipt/NATCompiler_ipt.h +++ b/src/ipt/NATCompiler_ipt.h @@ -304,6 +304,40 @@ namespace fwcompiler { */ DECLARE_NAT_RULE_PROCESSOR(splitMultipleICMP); + /** + * prepare for negation of single objects in rule elements + */ + class singleObjectNegation : public NATRuleProcessor + { + std::string re_type; + public: + singleObjectNegation(const std::string &n,std::string _type): + NATRuleProcessor(n) { re_type=_type; } + virtual bool processNext(); + }; + + /** + * single object negation in OSrc + */ + class singleObjectNegationOSrc : public singleObjectNegation + { + public: + singleObjectNegationOSrc(const std::string &n): + singleObjectNegation(n,libfwbuilder::RuleElementOSrc::TYPENAME) + {} + }; + + /** + * single object negation in ODst + */ + class singleObjectNegationODst : public singleObjectNegation + { + public: + singleObjectNegationODst(const std::string &n): + singleObjectNegation(n,libfwbuilder::RuleElementODst::TYPENAME) + {} + }; + /** * deals with negation in OSrc */ @@ -478,6 +512,7 @@ namespace fwcompiler { bool print_mask=true, bool print_range=false); virtual std::string _printChainDirectionAndInterface(libfwbuilder::NATRule *r); + virtual std::string _printSingleObjectNegation(libfwbuilder::RuleElement *rel); public: PrintRule(const std::string &name); diff --git a/src/ipt/PolicyCompiler_PrintRule.cpp b/src/ipt/PolicyCompiler_PrintRule.cpp index 5fa1335ff..e886ff410 100644 --- a/src/ipt/PolicyCompiler_PrintRule.cpp +++ b/src/ipt/PolicyCompiler_PrintRule.cpp @@ -1104,7 +1104,8 @@ string PolicyCompiler_ipt::PrintRule::_printAddr(Address *o) } -string PolicyCompiler_ipt::PrintRule::_printSingleObjectNegation(RuleElement *rel) +string PolicyCompiler_ipt::PrintRule::_printSingleObjectNegation( + RuleElement *rel) { if (rel->getBool("single_object_negation")) return "! "; else return ""; diff --git a/src/ipt/PolicyCompiler_ipt.cpp b/src/ipt/PolicyCompiler_ipt.cpp index a092477c8..4b93ad7bf 100644 --- a/src/ipt/PolicyCompiler_ipt.cpp +++ b/src/ipt/PolicyCompiler_ipt.cpp @@ -945,16 +945,21 @@ bool PolicyCompiler_ipt::printRuleElements::processNext() bool PolicyCompiler_ipt::singleSrcNegation::processNext() { - PolicyRule *rule=getNext(); if (rule==NULL) return false; + PolicyRule *rule = getNext(); if (rule==NULL) return false; RuleElementSrc *srcrel = rule->getSrc(); - Address *src = compiler->getFirstSrc(rule); /* ! A B C ACTION */ - if (srcrel->getNeg() && srcrel->size()==1 && src!=NULL && - !compiler->complexMatch(src,compiler->fw)) + if (srcrel->getNeg() && srcrel->size()==1) { - srcrel->setNeg(false); - srcrel->setBool("single_object_negation",true); + Address *src = compiler->getFirstSrc(rule); + // note: src can be NULL if object in this rule element is a group + // or MultiAddress + if (src!=NULL && src->countInetAddresses()==1 && + !compiler->complexMatch(src,compiler->fw)) + { + srcrel->setNeg(false); + srcrel->setBool("single_object_negation",true); + } } tmp_queue.push_back(rule); @@ -963,17 +968,19 @@ bool PolicyCompiler_ipt::singleSrcNegation::processNext() bool PolicyCompiler_ipt::singleDstNegation::processNext() { - PolicyRule *rule=getNext(); if (rule==NULL) return false; - - RuleElementDst *dstrel=rule->getDst(); - Address *dst =compiler->getFirstDst(rule); + PolicyRule *rule = getNext(); if (rule==NULL) return false; + RuleElementDst *dstrel = rule->getDst(); /* A ! B C ACTION */ - if (dstrel->getNeg() && dstrel->size()==1 && dst!=NULL && - !compiler->complexMatch(dst,compiler->fw)) + if (dstrel->getNeg() && dstrel->size()==1) { - dstrel->setNeg(false); - dstrel->setBool("single_object_negation",true); + Address *dst = compiler->getFirstDst(rule); + if (dst!=NULL && dst->countInetAddresses()==1 && + !compiler->complexMatch(dst,compiler->fw)) + { + dstrel->setNeg(false); + dstrel->setBool("single_object_negation",true); + } } tmp_queue.push_back(rule); @@ -2596,8 +2603,9 @@ bool PolicyCompiler_ipt::checkForDynamicInterfacesOfOtherObjects::processNext() bool PolicyCompiler_ipt::expandMultipleAddressesIfNotFWinSrc::processNext() { PolicyRule *rule=getNext(); if (rule==NULL) return false; - RuleElementSrc *srcrel=rule->getSrc(); - Address *src =compiler->getFirstSrc(rule); assert(src); + RuleElementSrc *srcrel = rule->getSrc(); + Address *src =compiler->getFirstSrc(rule); + assert(src); if (Firewall::cast(src)==NULL) compiler->_expandAddr(rule, srcrel); tmp_queue.push_back(rule); return true; @@ -3906,13 +3914,11 @@ void PolicyCompiler_ipt::compile() add( new fillActionOnReject("fill in action_on_reject 2" ) ); add( new splitServicesIfRejectWithTCPReset( "split if action on reject is TCP reset 2")); + + add( new singleSrcNegation("negation in Src if it holds single object")); add( new singleDstNegation("negation in Dst if it holds single object")); -/* - * phased out these processors, they are not needed anymore because we use variable - * for dynamic interfaces. - */ add( new splitIfSrcNegAndFw("split rule if src has negation and fw")); add( new splitIfDstNegAndFw("split rule if dst has negation and fw")); @@ -3922,29 +3928,14 @@ void PolicyCompiler_ipt::compile() add( new Logging2("process logging")); -/* this is just a patch for those who do not understand how does +/* + * this is just a patch for those who do not understand how does * "assume firewall is part of any" work. It also eliminates redundant * and useless rules in the FORWARD chain for rules assigned to a * loopback interface. */ // add( new decideOnChainIfLoopback("any-any rule on loopback" ) ); -#if 0 - add( new splitIfSrcAny("split rule if src is any") ); - add( new setChainForMangle("set chain for other rules in mangle")); - add( new setChainPreroutingForTag("chain PREROUTING for Tag")); - add( new splitIfDstAny("split rule if dst is any") ); - add( new setChainPostroutingForTag("chain POSTROUTING for Tag")); - add( new ExpandGroups("expand all groups")); - add( new dropRuleWithEmptyRE("drop rules with empty rule elements")); - add( new eliminateDuplicatesInSRC("eliminate duplicates in SRC" )); - add( new eliminateDuplicatesInDST("eliminate duplicates in DST" )); - add( new eliminateDuplicatesInSRV("eliminate duplicates in SRV" )); - add( new swapMultiAddressObjectsInSrc( - " swap MultiAddress -> MultiAddressRunTime in Src")); - add( new swapMultiAddressObjectsInDst( - " swap MultiAddress -> MultiAddressRunTime in Dst")); -#endif add( new ExpandGroups("expand all groups")); add( new dropRuleWithEmptyRE("drop rules with empty rule elements")); diff --git a/test/ipt/objects-for-regression-tests.fwb b/test/ipt/objects-for-regression-tests.fwb index 0ea35e7ad..86eb970ee 100644 Binary files a/test/ipt/objects-for-regression-tests.fwb and b/test/ipt/objects-for-regression-tests.fwb differ diff --git a/test/ipt/quick-cmp.sh b/test/ipt/quick-cmp.sh index 1f52c681a..486bb4b2b 100755 --- a/test/ipt/quick-cmp.sh +++ b/test/ipt/quick-cmp.sh @@ -1,15 +1,10 @@ -#!/usr/bin/perl +#!/bin/sh -$XMLFILE=@ARGV[0]; -$DIFFCMD="diff -C 1 -c -b -B -I \"# Generated\" -I 'Activating ' -I '# Firewall Builder fwb_ipt v' -I 'Can not find file' -I '====' -I 'log '"; +XMLFILE=$1 +DIFFCMD="diff -C 1 -c -b -B -I \"# Generated\" -I 'Activating ' -I '# Firewall Builder fwb_ipt v' -I 'Can not find file' -I '====' -I 'log '" + +fwbedit list -f $XMLFILE -o /User/Firewalls -c -F%name% | sort | while read fwobj; do + echo "$DIFFCMD ${fwobj}.fw.orig ${fwobj}.fw" +done -while (<>) { - $str=$_; - while ( $str=~ /]+name="([^"]*).*$"/; - $fw=$1; - printf "$DIFFCMD %s.fw.orig %s.fw\n",$fw,$fw; - $str=~ s/^.*]+name="$fw"[^>]+>//; - } -} diff --git a/test/ipt/run.all b/test/ipt/run.all index 3784d86bc..b350edaf8 100755 --- a/test/ipt/run.all +++ b/test/ipt/run.all @@ -1,7 +1,14 @@ -#!/usr/bin/perl +#!/bin/sh -$XMLFILE=@ARGV[0]; +XMLFILE=$1 +fwbedit list -f $XMLFILE -o /User/Firewalls -c -F%name% | sort | while read fwobj; do + echo "echo" + echo "echo \"============================ $fwobj\"" + echo "fwb_ipt -v -f $XMLFILE -xt $fwobj" +done + +exit 0 while (<>) { $str=$_;